[m-rev.] diff: don't use reflection for java arrays

Peter Wang novalazy at gmail.com
Tue Jul 20 17:39:15 AEST 2010


Branches: main, 10.04.1

library/array.m:
        Don't use reflection to implement Java versions of array predicates.
        It is faster just to test the array type at runtime, repeating the
        code for each array type we support.

        Fix wrong casts in ML_copy_array for char[] and Object[] arrays.

tests/hard_coded/Mmakefile:
tests/hard_coded/array_test2.exp:
tests/hard_coded/array_test2.m:
        Add test case.

diff --git a/library/array.m b/library/array.m
index 7a75e9a..f3f502b 100644
--- a/library/array.m
+++ b/library/array.m
@@ -702,8 +702,79 @@ ML_array_size(Object Array)
 {
     if (Array == null) {
         return 0;
+    } else if (Array instanceof int[]) {
+        return ((int[]) Array).length;
+    } else if (Array instanceof double[]) {
+        return ((double[]) Array).length;
+    } else if (Array instanceof char[]) {
+        return ((char[]) Array).length;
+    } else if (Array instanceof boolean[]) {
+        return ((boolean[]) Array).length;
     } else {
-        return java.lang.reflect.Array.getLength(Array);
+        return ((Object[]) Array).length;
+    }
+}
+
+public static Object
+ML_array_resize(Object Array0, int Size, Object Item)
+{
+    if (Size == 0) {
+        return null;
+    }
+    if (Array0 == null) {
+        return ML_new_array(Size, Item, true);
+    }
+    if (ML_array_size(Array0) == Size) {
+        return Array0;
+    }
+    if (Array0 instanceof int[]) {
+        int[] arr0 = (int[]) Array0;
+        int[] Array = new int[Size];
+
+        System.arraycopy(arr0, 0, Array, 0, Math.min(arr0.length, Size));
+        for (int i = arr0.length; i < Size; i++) {
+            Array[i] = (Integer) Item;
+        }
+        return Array;
+    }
+    if (Array0 instanceof double[]) {
+        double[] arr0 = (double[]) Array0;
+        double[] Array = new double[Size];
+
+        System.arraycopy(arr0, 0, Array, 0, Math.min(arr0.length, Size));
+        for (int i = arr0.length; i < Size; i++) {
+            Array[i] = (Double) Item;
+        }
+        return Array;
+    }
+    if (Array0 instanceof char[]) {
+        char[] arr0 = (char[]) Array0;
+        char[] Array = new char[Size];
+
+        System.arraycopy(arr0, 0, Array, 0, Math.min(arr0.length, Size));
+        for (int i = arr0.length; i < Size; i++) {
+            Array[i] = (Character) Item;
+        }
+        return Array;
+    }
+    if (Array0 instanceof boolean[]) {
+        boolean[] arr0 = (boolean[]) Array0;
+        boolean[] Array = new boolean[Size];
+
+        System.arraycopy(arr0, 0, Array, 0, Math.min(arr0.length, Size));
+        for (int i = arr0.length; i < Size; i++) {
+            Array[i] = (Boolean) Item;
+        }
+        return Array;
+    } else {
+        Object[] arr0 = (Object[]) Array0;
+        Object[] Array = new Object[Size];
+
+        System.arraycopy(arr0, 0, Array, 0, Math.min(arr0.length, Size));
+        for (int i = arr0.length; i < Size; i++) {
+            Array[i] = Item;
+        }
+        return Array;
     }
 }
 ").
@@ -895,11 +966,7 @@ array.bounds(Array, Min, Max) :-
     array.size(Array::in, Max::out),
     [will_not_call_mercury, promise_pure, thread_safe],
 "
-    if (Array != null) {
-        Max = java.lang.reflect.Array.getLength(Array);
-    } else {
-        Max = 0;
-    }
+    Max = jmercury.array.ML_array_size(Array);
 ").
 
 %-----------------------------------------------------------------------------%
@@ -972,7 +1039,17 @@ array.lookup(Array, Index, Item) :-
     array.unsafe_lookup(Array::in, Index::in, Item::out),
     [will_not_call_mercury, promise_pure, thread_safe],
 "
-    Item = java.lang.reflect.Array.get(Array, Index);
+    if (Array instanceof int[]) {
+        Item = ((int[]) Array)[Index];
+    } else if (Array instanceof double[]) {
+        Item = ((double[]) Array)[Index];
+    } else if (Array instanceof char[]) {
+        Item = ((char[]) Array)[Index];
+    } else if (Array instanceof boolean[]) {
+        Item = ((boolean[]) Array)[Index];
+    } else {
+        Item = ((Object[]) Array)[Index];
+    }
 ").
 
 %-----------------------------------------------------------------------------%
@@ -1017,7 +1094,17 @@ array.set(Array0, Index, Item, Array) :-
     array.unsafe_set(Array0::array_di, Index::in, Item::in, Array::array_uo),
     [will_not_call_mercury, promise_pure, thread_safe],
 "
-    java.lang.reflect.Array.set(Array0, Index, Item);
+    if (Array0 instanceof int[]) {
+        ((int[]) Array0)[Index] = (Integer) Item;
+    } else if (Array0 instanceof double[]) {
+        ((double[]) Array0)[Index] = (Double) Item;
+    } else if (Array0 instanceof char[]) {
+        ((char[]) Array0)[Index] = (Character) Item;
+    } else if (Array0 instanceof boolean[]) {
+        ((boolean[]) Array0)[Index] = (Boolean) Item;
+    } else {
+        ((Object[]) Array0)[Index] = Item;
+    }
     Array = Array0;         /* destructive update! */
 ").
 
@@ -1133,26 +1220,9 @@ ML_resize_array(MR_ArrayPtr array, MR_ArrayPtr old_array,
 
 :- pragma foreign_proc("Java",
     array.resize(Array0::array_di, Size::in, Item::in, Array::array_uo),
-    [will_not_call_mercury, promise_pure, thread_safe, may_not_duplicate],
+    [will_not_call_mercury, promise_pure, thread_safe],
 "
-    if (Size == 0) {
-        Array = null;
-    } else if (Array0 == null) {
-        Array = array.ML_new_array(Size, Item, true);
-    } else if (array.ML_array_size(Array0) == Size) {
-        Array = Array0;
-    } else {
-        Array = array.ML_new_array(Size, Item, false);
-
-        int i;
-        for (i = 0; i < array.ML_array_size(Array0) && i < Size; i++) {
-            java.lang.reflect.Array.set(Array, i,
-                java.lang.reflect.Array.get(Array0, i));
-        }
-        for (/*i = Array0.length*/; i < Size; i++) {
-            java.lang.reflect.Array.set(Array, i, Item);
-        }
-    }
+    Array = jmercury.array.ML_array_resize(Array0, Size, Item);
 ").
 
 %-----------------------------------------------------------------------------%
@@ -1331,13 +1401,13 @@ ML_copy_array(MR_ArrayPtr array, MR_ConstArrayPtr old_array)
         Size = ((double[]) Array0).length;
         Array = new double[Size];
     } else if (Array0 instanceof char[]) {
-        Size = ((double[]) Array0).length;
+        Size = ((char[]) Array0).length;
         Array = new char[Size];
     } else if (Array0 instanceof boolean[]) {
         Size = ((boolean[]) Array0).length;
         Array = new boolean[Size];
     } else {
-        Size = ((boolean[]) Array0).length;
+        Size = ((Object[]) Array0).length;
         Array = new Object[Size];
     }
 
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index b3d0c92..5516d35 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -9,6 +9,7 @@ ORDINARY_PROGS=	\
 	address_of_builtins \
 	agg \
 	array_test \
+	array_test2 \
 	backquoted_qualified_ops \
 	bag_various \
 	bidirectional \
diff --git a/tests/hard_coded/array_test2.exp b/tests/hard_coded/array_test2.exp
new file mode 100644
index 0000000..182b391
--- /dev/null
+++ b/tests/hard_coded/array_test2.exp
@@ -0,0 +1,65 @@
+----
+size: 5
+elements: [10, 11, 12, 13, 14]
+good: out of bounds lookup averted
+good: out of bounds lookup averted
+good: out of bounds set averted
+good: out of bounds set averted
+resize without resizing: array([10, 11, 12, 13, 14])
+shrink: array([10, 11, 12])
+enlarge: array([10, 11, 12, 10, 10])
+empty: array([])
+still empty: array([])
+nonempty from empty: array([10, 10, 10])
+----
+size: 5
+elements: [10.0, 11.1, 12.2, 13.3, 14.4]
+good: out of bounds lookup averted
+good: out of bounds lookup averted
+good: out of bounds set averted
+good: out of bounds set averted
+resize without resizing: array([10.0, 11.1, 12.2, 13.3, 14.4])
+shrink: array([10.0, 11.1, 12.2])
+enlarge: array([10.0, 11.1, 12.2, 10.0, 10.0])
+empty: array([])
+still empty: array([])
+nonempty from empty: array([10.0, 10.0, 10.0])
+----
+size: 5
+elements: ['p', 'o', 'k', 'e', 'y']
+good: out of bounds lookup averted
+good: out of bounds lookup averted
+good: out of bounds set averted
+good: out of bounds set averted
+resize without resizing: array(['p', 'o', 'k', 'e', 'y'])
+shrink: array(['p', 'o', 'k'])
+enlarge: array(['p', 'o', 'k', 'p', 'p'])
+empty: array([])
+still empty: array([])
+nonempty from empty: array(['p', 'p', 'p'])
+----
+size: 5
+elements: [yes, no, yes, yes, no]
+good: out of bounds lookup averted
+good: out of bounds lookup averted
+good: out of bounds set averted
+good: out of bounds set averted
+resize without resizing: array([yes, no, yes, yes, no])
+shrink: array([yes, no, yes])
+enlarge: array([yes, no, yes, yes, yes])
+empty: array([])
+still empty: array([])
+nonempty from empty: array([yes, yes, yes])
+----
+size: 5
+elements: ["ten", "eleven", "twelve", "thirteen", "fourteen"]
+good: out of bounds lookup averted
+good: out of bounds lookup averted
+good: out of bounds set averted
+good: out of bounds set averted
+resize without resizing: array(["ten", "eleven", "twelve", "thirteen", "fourteen"])
+shrink: array(["ten", "eleven", "twelve"])
+enlarge: array(["ten", "eleven", "twelve", "ten", "ten"])
+empty: array([])
+still empty: array([])
+nonempty from empty: array(["ten", "ten", "ten"])
diff --git a/tests/hard_coded/array_test2.m b/tests/hard_coded/array_test2.m
new file mode 100644
index 0000000..d4eae4e
--- /dev/null
+++ b/tests/hard_coded/array_test2.m
@@ -0,0 +1,109 @@
+%-----------------------------------------------------------------------------%
+
+:- module array_test2.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module array.
+:- import_module bool.
+:- import_module int.
+:- import_module list.
+
+%-----------------------------------------------------------------------------%
+
+main(!IO) :-
+    % Exercise each of the native types for the Java backend.
+    test([10, 11, 12, 13, 14], !IO),
+    test([10.0, 11.1, 12.2, 13.3, 14.4], !IO),
+    test(['p', 'o', 'k', 'e', 'y'], !IO),
+    test([yes, no, yes, yes, no], !IO),
+    test(["ten", "eleven", "twelve", "thirteen", "fourteen"], !IO).
+
+:- pred test(list(T)::in, io::di, io::uo) is det.
+
+test(List, !IO) :-
+    io.write_string("----\n", !IO),
+
+    % Calls array.init, array.unsafe_insert_items.
+    array.from_list(List, Array),
+
+    % Calls array.bounds, array.fetch_items, array.foldr, array.elem,
+    % array.lookup.
+    array.to_list(Array, Elements),
+
+    io.write_string("size: ", !IO),
+    io.write_int(array.size(Array), !IO),
+    io.nl(!IO),
+
+    io.write_string("elements: ", !IO),
+    io.write(Elements, !IO),
+    io.nl(!IO),
+
+    ( semidet_lookup(Array, -1, _) ->
+        io.write_string("error: out of bounds lookup suceeded\n", !IO)
+    ;
+        io.write_string("good: out of bounds lookup averted\n", !IO)
+    ),
+    ( semidet_lookup(Array, list.length(List), _) ->
+        io.write_string("error: out of bounds lookup suceeded\n", !IO)
+    ;
+        io.write_string("good: out of bounds lookup averted\n", !IO)
+    ),
+
+    Elem = list.det_head(List),
+
+    array.copy(Array, ArrayB),
+    ( semidet_set(Array, -1, Elem, _) ->
+        io.write_string("error: out of bounds set succeeded\n", !IO)
+    ;
+        io.write_string("good: out of bounds set averted\n", !IO)
+    ),
+    ( semidet_set(ArrayB, 5, Elem, _) ->
+        io.write_string("error: out of bounds set succeeded\n", !IO)
+    ;
+        io.write_string("good: out of bounds set averted\n", !IO)
+    ),
+
+    some [!A] (
+        array.from_list(List, !:A),
+        array.resize(!.A, list.length(List), Elem, !:A),
+        io.write_string("resize without resizing: ", !IO),
+        io.write(!.A, !IO),
+        io.nl(!IO),
+
+        array.resize(!.A, 1 + list.length(List)//2, Elem, !:A),
+        io.write_string("shrink: ", !IO),
+        io.write(!.A, !IO),
+        io.nl(!IO),
+
+        array.resize(!.A, list.length(List), Elem, !:A),
+        io.write_string("enlarge: ", !IO), % embiggen
+        io.write(!.A, !IO),
+        io.nl(!IO),
+
+        array.resize(!.A, 0, Elem, !:A),
+        io.write_string("empty: ", !IO),
+        io.write(!.A, !IO),
+        io.nl(!IO),
+
+        array.resize(!.A, 0, Elem, !:A),
+        io.write_string("still empty: ", !IO),
+        io.write(!.A, !IO),
+        io.nl(!IO),
+
+        array.resize(!.A, 3, Elem, !:A),
+        io.write_string("nonempty from empty: ", !IO),
+        io.write(!.A, !IO),
+        io.nl(!IO)
+    ).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et

--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list