rt/emul/mini/src/main/java/java/lang/reflect/Array.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 07 May 2014 08:49:54 +0200
branchclosure
changeset 1541 3471d74a6b99
parent 1535 c02c6d409461
child 1702 228f26fc1159
permissions -rw-r--r--
Methods in Array are shared between different VMs, but other types like Integer, or Float, aren't. Need to be careful when using equality then
     1 /*
     2  * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 
    26 package java.lang.reflect;
    27 
    28 import org.apidesign.bck2brwsr.core.Exported;
    29 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    30 import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
    31 
    32 /**
    33  * The {@code Array} class provides static methods to dynamically create and
    34  * access Java arrays.
    35  *
    36  * <p>{@code Array} permits widening conversions to occur during a get or set
    37  * operation, but throws an {@code IllegalArgumentException} if a narrowing
    38  * conversion would occur.
    39  *
    40  * @author Nakul Saraiya
    41  */
    42 @JavaScriptPrototype(prototype = "new Array", container = "Array.prototype")
    43 public final
    44 class Array {
    45 
    46     /**
    47      * Constructor.  Class Array is not instantiable.
    48      */
    49     private Array() {}
    50 
    51     /**
    52      * Creates a new array with the specified component type and
    53      * length.
    54      * Invoking this method is equivalent to creating an array
    55      * as follows:
    56      * <blockquote>
    57      * <pre>
    58      * int[] x = {length};
    59      * Array.newInstance(componentType, x);
    60      * </pre>
    61      * </blockquote>
    62      *
    63      * @param componentType the {@code Class} object representing the
    64      * component type of the new array
    65      * @param length the length of the new array
    66      * @return the new array
    67      * @exception NullPointerException if the specified
    68      * {@code componentType} parameter is null
    69      * @exception IllegalArgumentException if componentType is {@link Void#TYPE}
    70      * @exception NegativeArraySizeException if the specified {@code length}
    71      * is negative
    72      */
    73     public static Object newInstance(Class<?> componentType, int length)
    74     throws NegativeArraySizeException {
    75         if (length < 0) {
    76             throw new NegativeArraySizeException();
    77         }
    78         String sig = Method.findArraySignature(componentType);
    79         return newArray(componentType.isPrimitive(), sig, null, length);
    80     }
    81     
    82     /**
    83      * Creates a new array
    84      * with the specified component type and dimensions.
    85      * If {@code componentType}
    86      * represents a non-array class or interface, the new array
    87      * has {@code dimensions.length} dimensions and
    88      * {@code componentType} as its component type. If
    89      * {@code componentType} represents an array class, the
    90      * number of dimensions of the new array is equal to the sum
    91      * of {@code dimensions.length} and the number of
    92      * dimensions of {@code componentType}. In this case, the
    93      * component type of the new array is the component type of
    94      * {@code componentType}.
    95      *
    96      * <p>The number of dimensions of the new array must not
    97      * exceed the number of array dimensions supported by the
    98      * implementation (typically 255).
    99      *
   100      * @param componentType the {@code Class} object representing the component
   101      * type of the new array
   102      * @param dimensions an array of {@code int} representing the dimensions of
   103      * the new array
   104      * @return the new array
   105      * @exception NullPointerException if the specified
   106      * {@code componentType} argument is null
   107      * @exception IllegalArgumentException if the specified {@code dimensions}
   108      * argument is a zero-dimensional array, or if the number of
   109      * requested dimensions exceeds the limit on the number of array dimensions
   110      * supported by the implementation (typically 255), or if componentType
   111      * is {@link Void#TYPE}.
   112      * @exception NegativeArraySizeException if any of the components in
   113      * the specified {@code dimensions} argument is negative.
   114      */
   115     public static Object newInstance(Class<?> componentType, int... dimensions)
   116         throws IllegalArgumentException, NegativeArraySizeException {
   117         StringBuilder sig = new StringBuilder();
   118         for (int i = 1; i < dimensions.length; i++) {
   119             sig.append('[');
   120         }
   121         sig.append(Method.findArraySignature(componentType));
   122         return multiNewArray(sig.toString(), dimensions, 0);
   123     }
   124 
   125     /**
   126      * Returns the length of the specified array object, as an {@code int}.
   127      *
   128      * @param array the array
   129      * @return the length of the array
   130      * @exception IllegalArgumentException if the object argument is not
   131      * an array
   132      */
   133     public static int getLength(Object array)
   134     throws IllegalArgumentException {
   135         if (!array.getClass().isArray()) {
   136             throw new IllegalArgumentException("Argument is not an array");
   137         }
   138         return length(array);
   139     }
   140     
   141     @JavaScriptBody(args = { "arr" }, body = "return arr.length;")
   142     private static native int length(Object arr);
   143 
   144     /**
   145      * Returns the value of the indexed component in the specified
   146      * array object.  The value is automatically wrapped in an object
   147      * if it has a primitive type.
   148      *
   149      * @param array the array
   150      * @param index the index
   151      * @return the (possibly wrapped) value of the indexed component in
   152      * the specified array
   153      * @exception NullPointerException If the specified object is null
   154      * @exception IllegalArgumentException If the specified object is not
   155      * an array
   156      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   157      * argument is negative, or if it is greater than or equal to the
   158      * length of the specified array
   159      */
   160     public static Object get(Object array, int index)
   161     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   162         final Class<?> t = array.getClass().getComponentType();
   163         if (t.isPrimitive()) {
   164             return fromPrimitive(t, array, index);
   165         } else {
   166             return ((Object[])array)[index];
   167         }
   168     }
   169 
   170     /**
   171      * Returns the value of the indexed component in the specified
   172      * array object, as a {@code boolean}.
   173      *
   174      * @param array the array
   175      * @param index the index
   176      * @return the value of the indexed component in the specified array
   177      * @exception NullPointerException If the specified object is null
   178      * @exception IllegalArgumentException If the specified object is not
   179      * an array, or if the indexed element cannot be converted to the
   180      * return type by an identity or widening conversion
   181      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   182      * argument is negative, or if it is greater than or equal to the
   183      * length of the specified array
   184      * @see Array#get
   185      */
   186     public static native boolean getBoolean(Object array, int index)
   187         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
   188 
   189     /**
   190      * Returns the value of the indexed component in the specified
   191      * array object, as a {@code byte}.
   192      *
   193      * @param array the array
   194      * @param index the index
   195      * @return the value of the indexed component in the specified array
   196      * @exception NullPointerException If the specified object is null
   197      * @exception IllegalArgumentException If the specified object is not
   198      * an array, or if the indexed element cannot be converted to the
   199      * return type by an identity or widening conversion
   200      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   201      * argument is negative, or if it is greater than or equal to the
   202      * length of the specified array
   203      * @see Array#get
   204      */
   205     public static byte getByte(Object array, int index)
   206     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   207         if (!Method.samePrimitive(array.getClass().getComponentType(), Byte.TYPE)) {
   208             throw new IllegalArgumentException();
   209         }
   210         byte[] arr = (byte[]) array;
   211         return arr[index];
   212     }
   213 
   214     /**
   215      * Returns the value of the indexed component in the specified
   216      * array object, as a {@code char}.
   217      *
   218      * @param array the array
   219      * @param index the index
   220      * @return the value of the indexed component in the specified array
   221      * @exception NullPointerException If the specified object is null
   222      * @exception IllegalArgumentException If the specified object is not
   223      * an array, or if the indexed element cannot be converted to the
   224      * return type by an identity or widening conversion
   225      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   226      * argument is negative, or if it is greater than or equal to the
   227      * length of the specified array
   228      * @see Array#get
   229      */
   230     public static native char getChar(Object array, int index)
   231         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
   232 
   233     /**
   234      * Returns the value of the indexed component in the specified
   235      * array object, as a {@code short}.
   236      *
   237      * @param array the array
   238      * @param index the index
   239      * @return the value of the indexed component in the specified array
   240      * @exception NullPointerException If the specified object is null
   241      * @exception IllegalArgumentException If the specified object is not
   242      * an array, or if the indexed element cannot be converted to the
   243      * return type by an identity or widening conversion
   244      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   245      * argument is negative, or if it is greater than or equal to the
   246      * length of the specified array
   247      * @see Array#get
   248      */
   249     public static short getShort(Object array, int index)
   250     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   251         final Class<?> t = array.getClass().getComponentType();
   252         if (Method.samePrimitive(t, Short.TYPE)) {
   253             short[] arr = (short[]) array;
   254             return arr[index];
   255         }
   256         return getByte(array, index);
   257     }
   258 
   259     /**
   260      * Returns the value of the indexed component in the specified
   261      * array object, as an {@code int}.
   262      *
   263      * @param array the array
   264      * @param index the index
   265      * @return the value of the indexed component in the specified array
   266      * @exception NullPointerException If the specified object is null
   267      * @exception IllegalArgumentException If the specified object is not
   268      * an array, or if the indexed element cannot be converted to the
   269      * return type by an identity or widening conversion
   270      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   271      * argument is negative, or if it is greater than or equal to the
   272      * length of the specified array
   273      * @see Array#get
   274      */
   275     public static int getInt(Object array, int index) 
   276     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   277         final Class<?> t = array.getClass().getComponentType();
   278         if (Method.samePrimitive(t, Integer.TYPE)) {
   279             int[] arr = (int[]) array;
   280             return arr[index];
   281         }
   282         return getShort(array, index);
   283     }
   284 
   285     /**
   286      * Returns the value of the indexed component in the specified
   287      * array object, as a {@code long}.
   288      *
   289      * @param array the array
   290      * @param index the index
   291      * @return the value of the indexed component in the specified array
   292      * @exception NullPointerException If the specified object is null
   293      * @exception IllegalArgumentException If the specified object is not
   294      * an array, or if the indexed element cannot be converted to the
   295      * return type by an identity or widening conversion
   296      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   297      * argument is negative, or if it is greater than or equal to the
   298      * length of the specified array
   299      * @see Array#get
   300      */
   301     public static long getLong(Object array, int index)
   302     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   303         final Class<?> t = array.getClass().getComponentType();
   304         if (Method.samePrimitive(t, Long.TYPE)) {
   305             long[] arr = (long[]) array;
   306             return arr[index];
   307         }
   308         return getInt(array, index);
   309     }
   310 
   311     /**
   312      * Returns the value of the indexed component in the specified
   313      * array object, as a {@code float}.
   314      *
   315      * @param array the array
   316      * @param index the index
   317      * @return the value of the indexed component in the specified array
   318      * @exception NullPointerException If the specified object is null
   319      * @exception IllegalArgumentException If the specified object is not
   320      * an array, or if the indexed element cannot be converted to the
   321      * return type by an identity or widening conversion
   322      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   323      * argument is negative, or if it is greater than or equal to the
   324      * length of the specified array
   325      * @see Array#get
   326      */
   327     public static float getFloat(Object array, int index)
   328     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   329         final Class<?> t = array.getClass().getComponentType();
   330         if (Method.samePrimitive(t, Float.TYPE)) {
   331             float[] arr = (float[]) array;
   332             return arr[index];
   333         }
   334         return getLong(array, index);
   335     }
   336 
   337     /**
   338      * Returns the value of the indexed component in the specified
   339      * array object, as a {@code double}.
   340      *
   341      * @param array the array
   342      * @param index the index
   343      * @return the value of the indexed component in the specified array
   344      * @exception NullPointerException If the specified object is null
   345      * @exception IllegalArgumentException If the specified object is not
   346      * an array, or if the indexed element cannot be converted to the
   347      * return type by an identity or widening conversion
   348      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   349      * argument is negative, or if it is greater than or equal to the
   350      * length of the specified array
   351      * @see Array#get
   352      */
   353     public static double getDouble(Object array, int index)
   354     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   355         final Class<?> t = array.getClass().getComponentType();
   356         if (Method.samePrimitive(t, Double.TYPE)) {
   357             double[] arr = (double[]) array;
   358             return arr[index];
   359         }
   360         return getFloat(array, index);
   361     }
   362 
   363     /**
   364      * Sets the value of the indexed component of the specified array
   365      * object to the specified new value.  The new value is first
   366      * automatically unwrapped if the array has a primitive component
   367      * type.
   368      * @param array the array
   369      * @param index the index into the array
   370      * @param value the new value of the indexed component
   371      * @exception NullPointerException If the specified object argument
   372      * is null
   373      * @exception IllegalArgumentException If the specified object argument
   374      * is not an array, or if the array component type is primitive and
   375      * an unwrapping conversion fails
   376      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   377      * argument is negative, or if it is greater than or equal to
   378      * the length of the specified array
   379      */
   380     public static void set(Object array, int index, Object value)
   381     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   382         if (array.getClass().getComponentType().isPrimitive()) {
   383             throw new IllegalArgumentException();
   384         } else {
   385             Object[] arr = (Object[])array;
   386             arr[index] = value;
   387         }
   388     }
   389 
   390     /**
   391      * Sets the value of the indexed component of the specified array
   392      * object to the specified {@code boolean} value.
   393      * @param array the array
   394      * @param index the index into the array
   395      * @param z the new value of the indexed component
   396      * @exception NullPointerException If the specified object argument
   397      * is null
   398      * @exception IllegalArgumentException If the specified object argument
   399      * is not an array, or if the specified value cannot be converted
   400      * to the underlying array's component type by an identity or a
   401      * primitive widening conversion
   402      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   403      * argument is negative, or if it is greater than or equal to
   404      * the length of the specified array
   405      * @see Array#set
   406      */
   407     public static native void setBoolean(Object array, int index, boolean z)
   408         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
   409 
   410     /**
   411      * Sets the value of the indexed component of the specified array
   412      * object to the specified {@code byte} value.
   413      * @param array the array
   414      * @param index the index into the array
   415      * @param b the new value of the indexed component
   416      * @exception NullPointerException If the specified object argument
   417      * is null
   418      * @exception IllegalArgumentException If the specified object argument
   419      * is not an array, or if the specified value cannot be converted
   420      * to the underlying array's component type by an identity or a
   421      * primitive widening conversion
   422      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   423      * argument is negative, or if it is greater than or equal to
   424      * the length of the specified array
   425      * @see Array#set
   426      */
   427     public static void setByte(Object array, int index, byte b)
   428     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   429         Class<?> t = array.getClass().getComponentType();
   430         if (Method.samePrimitive(t, Byte.TYPE)) {
   431             byte[] arr = (byte[]) array;
   432             arr[index] = b;
   433         } else {
   434             setShort(array, index, b);
   435         }
   436     }
   437 
   438     /**
   439      * Sets the value of the indexed component of the specified array
   440      * object to the specified {@code char} value.
   441      * @param array the array
   442      * @param index the index into the array
   443      * @param c the new value of the indexed component
   444      * @exception NullPointerException If the specified object argument
   445      * is null
   446      * @exception IllegalArgumentException If the specified object argument
   447      * is not an array, or if the specified value cannot be converted
   448      * to the underlying array's component type by an identity or a
   449      * primitive widening conversion
   450      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   451      * argument is negative, or if it is greater than or equal to
   452      * the length of the specified array
   453      * @see Array#set
   454      */
   455     public static native void setChar(Object array, int index, char c)
   456         throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
   457 
   458     /**
   459      * Sets the value of the indexed component of the specified array
   460      * object to the specified {@code short} value.
   461      * @param array the array
   462      * @param index the index into the array
   463      * @param s the new value of the indexed component
   464      * @exception NullPointerException If the specified object argument
   465      * is null
   466      * @exception IllegalArgumentException If the specified object argument
   467      * is not an array, or if the specified value cannot be converted
   468      * to the underlying array's component type by an identity or a
   469      * primitive widening conversion
   470      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   471      * argument is negative, or if it is greater than or equal to
   472      * the length of the specified array
   473      * @see Array#set
   474      */
   475     public static void setShort(Object array, int index, short s)
   476     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   477         Class<?> t = array.getClass().getComponentType();
   478         if (Method.samePrimitive(t, Short.TYPE)) {
   479             short[] arr = (short[]) array;
   480             arr[index] = s;
   481         } else {
   482             setInt(array, index, s);
   483         }
   484         
   485     }
   486     
   487     /**
   488      * Sets the value of the indexed component of the specified array
   489      * object to the specified {@code int} value.
   490      * @param array the array
   491      * @param index the index into the array
   492      * @param i the new value of the indexed component
   493      * @exception NullPointerException If the specified object argument
   494      * is null
   495      * @exception IllegalArgumentException If the specified object argument
   496      * is not an array, or if the specified value cannot be converted
   497      * to the underlying array's component type by an identity or a
   498      * primitive widening conversion
   499      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   500      * argument is negative, or if it is greater than or equal to
   501      * the length of the specified array
   502      * @see Array#set
   503      */
   504     public static void setInt(Object array, int index, int i)
   505     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   506         Class<?> t = array.getClass().getComponentType();
   507         if (Method.samePrimitive(t, Integer.TYPE)) {
   508             int[] arr = (int[]) array;
   509             arr[index] = i;
   510         } else {
   511             setLong(array, index, i);
   512         }
   513     }
   514 
   515     /**
   516      * Sets the value of the indexed component of the specified array
   517      * object to the specified {@code long} value.
   518      * @param array the array
   519      * @param index the index into the array
   520      * @param l the new value of the indexed component
   521      * @exception NullPointerException If the specified object argument
   522      * is null
   523      * @exception IllegalArgumentException If the specified object argument
   524      * is not an array, or if the specified value cannot be converted
   525      * to the underlying array's component type by an identity or a
   526      * primitive widening conversion
   527      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   528      * argument is negative, or if it is greater than or equal to
   529      * the length of the specified array
   530      * @see Array#set
   531      */
   532     public static void setLong(Object array, int index, long l)
   533     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   534         Class<?> t = array.getClass().getComponentType();
   535         if (Method.samePrimitive(t, Long.TYPE)) {
   536             long[] arr = (long[]) array;
   537             arr[index] = l;
   538         } else {
   539             setFloat(array, index, l);
   540         }
   541     }
   542 
   543     /**
   544      * Sets the value of the indexed component of the specified array
   545      * object to the specified {@code float} value.
   546      * @param array the array
   547      * @param index the index into the array
   548      * @param f the new value of the indexed component
   549      * @exception NullPointerException If the specified object argument
   550      * is null
   551      * @exception IllegalArgumentException If the specified object argument
   552      * is not an array, or if the specified value cannot be converted
   553      * to the underlying array's component type by an identity or a
   554      * primitive widening conversion
   555      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   556      * argument is negative, or if it is greater than or equal to
   557      * the length of the specified array
   558      * @see Array#set
   559      */
   560     public static void setFloat(Object array, int index, float f)
   561     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   562         Class<?> t = array.getClass().getComponentType();
   563         if (Method.samePrimitive(t, Float.TYPE)) {
   564             float[] arr = (float[])array;
   565             arr[index] = f;
   566         } else {
   567             setDouble(array, index, f);
   568         }
   569     }
   570 
   571     /**
   572      * Sets the value of the indexed component of the specified array
   573      * object to the specified {@code double} value.
   574      * @param array the array
   575      * @param index the index into the array
   576      * @param d the new value of the indexed component
   577      * @exception NullPointerException If the specified object argument
   578      * is null
   579      * @exception IllegalArgumentException If the specified object argument
   580      * is not an array, or if the specified value cannot be converted
   581      * to the underlying array's component type by an identity or a
   582      * primitive widening conversion
   583      * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   584      * argument is negative, or if it is greater than or equal to
   585      * the length of the specified array
   586      * @see Array#set
   587      */
   588     public static void setDouble(Object array, int index, double d)
   589     throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   590         Class<?> t = array.getClass().getComponentType();
   591         if (Method.samePrimitive(t, Double.TYPE)) {
   592             double[] arr = (double[])array;
   593             arr[index] = d;
   594         } else {
   595             throw new IllegalArgumentException("argument type mismatch");
   596         }
   597     }
   598 
   599     /*
   600      * Private
   601      */
   602 
   603     @JavaScriptBody(args = { "primitive", "sig", "fn", "length" }, body =
   604           "var arr = new Array(length);\n"
   605         + "var value = primitive ? 0 : null;\n"
   606         + "for(var i = 0; i < length; i++) arr[i] = value;\n"
   607         + "arr.jvmName = sig;\n"
   608         + "arr.fnc = fn;\n"
   609 //        + "java.lang.System.out.println('Assigned ' + arr.jvmName + ' fn: ' + (!!arr.fnc));\n"
   610         + "return arr;"
   611     )
   612     @Exported
   613     private static native Object newArray(boolean primitive, String sig, Object fn, int length);
   614 
   615     @Exported
   616     private static boolean isInstance(Object arr, String sig)  {
   617         if (arr == null) {
   618             return false;
   619         }
   620         return sig.equals(arr.getClass().getName());
   621     }
   622     
   623     @Exported
   624     private static boolean isInstance(Object arr, int dimensions, Object fn) throws ClassNotFoundException {
   625         if (arr == null) {
   626             return false;
   627         }
   628 //        log("isInstance for " + arr + " and " + dimensions);
   629         Class<?> c = arr.getClass();
   630         while (dimensions-- > 0) {
   631 //            log(" class: " + c);
   632             c = c.getComponentType();
   633 //            log(" next class: " + c);
   634             if (c == null) {
   635                 return false;
   636             }
   637         }
   638         Class<?> t = classFromFn(fn);
   639 //        log(" to check: " + t);
   640         return t.isAssignableFrom(c);
   641     }
   642     
   643     @JavaScriptBody(args = { "cntstr" }, body = "return cntstr(false).constructor.$class;")
   644     private static native Class<?> classFromFn(Object cntstr);
   645 
   646 //    @JavaScriptBody(args = { "m" }, body = "java.lang.System.out.println(m.toString().toString());")
   647 //    private static native void log(Object m);
   648     
   649     @Exported
   650     private static Object multiNewArray(String sig, int[] dims, Object fn)
   651     throws IllegalArgumentException, NegativeArraySizeException {
   652         return multiNewArray(sig, dims, 0, fn);
   653     }
   654     private static Object multiNewArray(String sig, int[] dims, int index, Object fn)
   655     throws IllegalArgumentException, NegativeArraySizeException {
   656         if (dims.length == index + 1) {
   657             return newArray(sig.length() == 2, sig, fn, dims[index]);
   658         }
   659         Object arr = newArray(false, sig, null, dims[index]);
   660         String compsig = sig.substring(1);
   661         int len = getLength(arr);
   662         for (int i = 0; i < len; i++) {
   663             setArray(arr, i, multiNewArray(compsig, dims, index + 1, fn));
   664         }
   665         return arr;
   666     }
   667     private static Object fromPrimitive(Class<?> t, Object array, int index) {
   668         return Method.fromPrimitive(t, atArray(array, index));
   669     }
   670     
   671     @JavaScriptBody(args = { "array", "index" }, body = "return array[index];")
   672     private static native Object atArray(Object array, int index);
   673 
   674     @JavaScriptBody(args = { "array", "index", "v" }, body = "array[index] = v;")
   675     private static native Object setArray(Object array, int index, Object v);
   676 }