[m-rev.] for review: fix bugs with java arrays

Peter Wang novalazy at gmail.com
Thu May 7 12:13:32 AEST 2009


Implementing arrays using reflection seems dodgy but anyway.


Branches: main

Fix two problems implementation of arrays for Java backend:

- array.from_list([1, 2, 3]) didn't work because it would create an Integer[]
  array, but the code generated by the Mercury compiler would try to assign
  it to a int[] variable.  Fix this by special casing the primitive types to
  create arrays with the expected types.

- We used the class of a representative element to determine the type of
  an array to create.  Enumeration types only have the one class
  corresponding to the Mercury type, so the class of the representative
  element is correct.

  However, general d.u. types have subclasses for each functor, so the class
  of a representative element could correspond to a functor.  This meant that
  arrays could only hold more elements with the same functor.  What is needed
  is actually the super class, corresponding to a Mercury type.

  The solution adopted here is to make Java classes corresponding to Mercury
  types implement an interface called `MercuryType'.  Then we can tell
  whether the class or the superclass of the representative element is the
  one needed.


java/runtime/MercuryType.java:
        Add the new interface.

compiler/ml_type_gen.m:
        When the target language is Java, make d.u. parent types implement
        the `MercuryType' interface.

compiler/mlds_to_java.m:
        Make the `MercuryType' interface special so it is printed without an
        arity suffix.

library/array.m:
        Fix the problems with creating/resizing ararys.

diff --git a/compiler/ml_type_gen.m b/compiler/ml_type_gen.m
index 6686661..8b855df 100644
--- a/compiler/ml_type_gen.m
+++ b/compiler/ml_type_gen.m
@@ -97,6 +97,7 @@
 :- import_module mdbcomp.prim_data.
 :- import_module ml_backend.ml_code_util.
 :- import_module ml_backend.ml_util.
+:- import_module parse_tree.java_names.
 :- import_module parse_tree.prog_data.
 :- import_module parse_tree.prog_type.
 :- import_module parse_tree.prog_util.
@@ -403,6 +404,7 @@ ml_gen_du_parent_type(ModuleInfo, TypeCtor,
TypeDefn, Ctors, TagValues,
         BaseClassModuleName, QualKind, Globals,
         BaseClassName, BaseClassArity),

+    globals.get_target(Globals, Target),
     (
         % If none of the constructors for this type need a secondary tag,
         % then we don't need the members for the secondary tag.
@@ -438,7 +440,6 @@ ml_gen_du_parent_type(ModuleInfo, TypeCtor,
TypeDefn, Ctors, TagValues,
             TagMembers = TagMembers0,
             TagClassId = BaseClassId
         ;
-            globals.get_target(Globals, Target),
             ml_gen_secondary_tag_class(MLDS_Context, BaseClassQualifier,
                 BaseClassId, TagMembers0, Target, TagTypeDefn, TagClassId),
             TagMembers = [TagTypeDefn]
@@ -456,7 +457,19 @@ ml_gen_du_parent_type(ModuleInfo, TypeCtor,
TypeDefn, Ctors, TagValues,
     % The base class doesn't import or inherit anything.
     Imports = [],
     Inherits = [],
-    Implements = [],
+
+    % For the implementation of arrays in Java, we need to be able to find out
+    % whether a class corresponds to a Mercury type or functor.  We make
+    % classes corresponding to types implement the MercuryType interface.
+    ( Target = target_java ->
+        InterfaceModuleName = mercury_module_name_to_mlds(
+            java_names.mercury_runtime_package_name),
+        Interface = qual(InterfaceModuleName, module_qual, "MercuryType"),
+        InterfaceDefn = mlds_class_type(Interface, 0, mlds_interface),
+        Implements = [InterfaceDefn]
+    ;
+        Implements = []
+    ),

     % Put it all together.
     Members = MaybeEqualityMembers ++ TagMembers ++ CtorMembers,
diff --git a/compiler/mlds_to_java.m b/compiler/mlds_to_java.m
index 0aa6c45..5808e8d 100644
--- a/compiler/mlds_to_java.m
+++ b/compiler/mlds_to_java.m
@@ -244,6 +244,7 @@ rval_is_enum_object(Rval) :-
     %
 :- pred interface_is_special(string::in) is semidet.

+interface_is_special("MercuryType").
 interface_is_special("MethodPtr").

 %-----------------------------------------------------------------------------%
diff --git a/java/runtime/MercuryType.java b/java/runtime/MercuryType.java
new file mode 100644
index 0000000..3d09237
--- /dev/null
+++ b/java/runtime/MercuryType.java
@@ -0,0 +1,13 @@
+//
+// Copyright (C) 2009 The University of Melbourne.
+// This file may only be copied under the terms of the GNU Library General
+// Public License - see the file COPYING.LIB in the Mercury distribution.
+//
+// This interface is implemented by wrapper classes which are automatically
+// generated by the Java back-end to implement method pointers in Java.
+//
+
+package mercury.runtime;
+
+public interface MercuryType {
+}
diff --git a/library/array.m b/library/array.m
index a88b7d1..5541cbb 100644
--- a/library/array.m
+++ b/library/array.m
@@ -625,6 +625,43 @@ ML_init_array(MR_ArrayPtr array, MR_Integer size,
MR_Word item)
 }
 ").

+:- pragma foreign_code("Java", "
+static Object
+ML_new_array(int Size, Object Item)
+{
+    if (Item instanceof Integer) {
+        return new int[Size];
+    }
+    if (Item instanceof Double) {
+        return new double[Size];
+    }
+    if (Item instanceof Character) {
+        return new char[Size];
+    }
+    if (Item instanceof Boolean) {
+        return new boolean[Size];
+    }
+
+    // We must find the class corresponding to the Mercury type.
+    // For enumerations this is the class of the Item.
+    // For general d.u. types the class of the Item corresponds
+    // to a functor, so we want the enclosing class.
+
+    java.lang.Class itemClass = Item.getClass();
+    boolean found = false;
+    for (java.lang.Class iface : itemClass.getInterfaces()) {
+        if (iface == mercury.runtime.MercuryType.class) {
+            found = true;
+            break;
+        }
+    }
+    if (!found) {
+        itemClass = itemClass.getEnclosingClass();
+    }
+    return java.lang.reflect.Array.newInstance(itemClass, Size);
+}
+").
+
 array.init(Size, Item, Array) :-
     ( Size < 0 ->
         error("array.init: negative size")
@@ -696,9 +733,7 @@ array.init(Size, Item, Array) :-
     array.init_2(Size::in, Item::in, Array::array_uo),
     [will_not_call_mercury, promise_pure, thread_safe],
 "
-    java.lang.Class itemClass = Item.getClass();
-
-    Array = java.lang.reflect.Array.newInstance(itemClass, Size);
+    Array = ML_new_array(Size, Item);
     for (int i = 0; i < Size; i++) {
         java.lang.reflect.Array.set(Array, i, Item);
     }
@@ -1057,19 +1092,17 @@ ML_resize_array(MR_ArrayPtr array, MR_ArrayPtr
old_array,
     array.resize(Array0::array_di, Size::in, Item::in, Array::array_uo),
     [will_not_call_mercury, promise_pure, thread_safe],
 "
-    java.lang.Class itemClass = Item.getClass();
-
     if (Size == 0) {
         Array = null;
     } else if (Array0 == null) {
-        Array = java.lang.reflect.Array.newInstance(itemClass, Size);
+        Array = ML_new_array(Size, Item);
         for (int i = 0; i < Size; i++) {
             java.lang.reflect.Array.set(Array, i, Item);
         }
     } else if (java.lang.reflect.Array.getLength(Array0) == Size) {
         Array = Array0;
     } else {
-        Array = java.lang.reflect.Array.newInstance(itemClass, Size);
+        Array = ML_new_array(Size, Item);

         int i;
         for (i = 0; i < java.lang.reflect.Array.getLength(Array0) &&
--------------------------------------------------------------------------
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