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