Giving everyone the benefits of java.lang.reflect.Array
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Fri, 18 Jan 2013 22:17:01 +0100
changeset 487ec5db7539219
parent 459 a2871a3fd4c5
parent 486 947269b26dc0
child 488 9288ecf9657c
Giving everyone the benefits of java.lang.reflect.Array
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/emul/src/main/java/java/lang/NegativeArraySizeException.java	Fri Jan 18 22:17:01 2013 +0100
     1.3 @@ -0,0 +1,55 @@
     1.4 +/*
     1.5 + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package java.lang;
    1.30 +
    1.31 +/**
    1.32 + * Thrown if an application tries to create an array with negative size.
    1.33 + *
    1.34 + * @author  unascribed
    1.35 + * @since   JDK1.0
    1.36 + */
    1.37 +public
    1.38 +class NegativeArraySizeException extends RuntimeException {
    1.39 +    private static final long serialVersionUID = -8960118058596991861L;
    1.40 +
    1.41 +    /**
    1.42 +     * Constructs a <code>NegativeArraySizeException</code> with no
    1.43 +     * detail message.
    1.44 +     */
    1.45 +    public NegativeArraySizeException() {
    1.46 +        super();
    1.47 +    }
    1.48 +
    1.49 +    /**
    1.50 +     * Constructs a <code>NegativeArraySizeException</code> with the
    1.51 +     * specified detail message.
    1.52 +     *
    1.53 +     * @param   s   the detail message.
    1.54 +     */
    1.55 +    public NegativeArraySizeException(String s) {
    1.56 +        super(s);
    1.57 +    }
    1.58 +}
     2.1 --- a/emul/src/main/java/java/lang/Object.java	Tue Jan 15 12:44:33 2013 +0100
     2.2 +++ b/emul/src/main/java/java/lang/Object.java	Fri Jan 18 22:17:01 2013 +0100
     2.3 @@ -25,6 +25,7 @@
     2.4  
     2.5  package java.lang;
     2.6  
     2.7 +import java.lang.reflect.Array;
     2.8  import org.apidesign.bck2brwsr.core.JavaScriptBody;
     2.9  import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
    2.10  
    2.11 @@ -40,8 +41,13 @@
    2.12  @JavaScriptPrototype(container = "Object.prototype", prototype = "new Object")
    2.13  public class Object {
    2.14  
    2.15 -    @JavaScriptBody(args = {}, body = "")
    2.16 -    private static native void registerNatives();
    2.17 +    private static void registerNatives() {
    2.18 +        try {
    2.19 +            Array.get(null, 0);
    2.20 +        } catch (Throwable ex) {
    2.21 +            // ignore
    2.22 +        }
    2.23 +    }
    2.24      static {
    2.25          registerNatives();
    2.26      }
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/emul/src/main/java/java/lang/reflect/Array.java	Fri Jan 18 22:17:01 2013 +0100
     3.3 @@ -0,0 +1,659 @@
     3.4 +/*
     3.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.  Oracle designates this
    3.11 + * particular file as subject to the "Classpath" exception as provided
    3.12 + * by Oracle in the LICENSE file that accompanied this code.
    3.13 + *
    3.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.17 + * version 2 for more details (a copy is included in the LICENSE file that
    3.18 + * accompanied this code).
    3.19 + *
    3.20 + * You should have received a copy of the GNU General Public License version
    3.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.23 + *
    3.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    3.25 + * or visit www.oracle.com if you need additional information or have any
    3.26 + * questions.
    3.27 + */
    3.28 +
    3.29 +package java.lang.reflect;
    3.30 +
    3.31 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
    3.32 +import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
    3.33 +
    3.34 +/**
    3.35 + * The {@code Array} class provides static methods to dynamically create and
    3.36 + * access Java arrays.
    3.37 + *
    3.38 + * <p>{@code Array} permits widening conversions to occur during a get or set
    3.39 + * operation, but throws an {@code IllegalArgumentException} if a narrowing
    3.40 + * conversion would occur.
    3.41 + *
    3.42 + * @author Nakul Saraiya
    3.43 + */
    3.44 +@JavaScriptPrototype(prototype = "new Array", container = "Array.prototype")
    3.45 +public final
    3.46 +class Array {
    3.47 +
    3.48 +    /**
    3.49 +     * Constructor.  Class Array is not instantiable.
    3.50 +     */
    3.51 +    private Array() {}
    3.52 +
    3.53 +    /**
    3.54 +     * Creates a new array with the specified component type and
    3.55 +     * length.
    3.56 +     * Invoking this method is equivalent to creating an array
    3.57 +     * as follows:
    3.58 +     * <blockquote>
    3.59 +     * <pre>
    3.60 +     * int[] x = {length};
    3.61 +     * Array.newInstance(componentType, x);
    3.62 +     * </pre>
    3.63 +     * </blockquote>
    3.64 +     *
    3.65 +     * @param componentType the {@code Class} object representing the
    3.66 +     * component type of the new array
    3.67 +     * @param length the length of the new array
    3.68 +     * @return the new array
    3.69 +     * @exception NullPointerException if the specified
    3.70 +     * {@code componentType} parameter is null
    3.71 +     * @exception IllegalArgumentException if componentType is {@link Void#TYPE}
    3.72 +     * @exception NegativeArraySizeException if the specified {@code length}
    3.73 +     * is negative
    3.74 +     */
    3.75 +    public static Object newInstance(Class<?> componentType, int length)
    3.76 +    throws NegativeArraySizeException {
    3.77 +        if (length < 0) {
    3.78 +            throw new NegativeArraySizeException();
    3.79 +        }
    3.80 +        String sig = findSignature(componentType);
    3.81 +        return newArray(componentType.isPrimitive(), sig, length);
    3.82 +    }
    3.83 +    
    3.84 +    private static String findSignature(Class<?> type) {
    3.85 +        if (type == Integer.TYPE) {
    3.86 +            return "[I";
    3.87 +        }
    3.88 +        if (type == Long.TYPE) {
    3.89 +            return "[J";
    3.90 +        }
    3.91 +        if (type == Double.TYPE) {
    3.92 +            return "[D";
    3.93 +        }
    3.94 +        if (type == Float.TYPE) {
    3.95 +            return "[F";
    3.96 +        }
    3.97 +        if (type == Byte.TYPE) {
    3.98 +            return "[B";
    3.99 +        }
   3.100 +        if (type == Boolean.TYPE) {
   3.101 +            return "[Z";
   3.102 +        }
   3.103 +        if (type == Short.TYPE) {
   3.104 +            return "[S";
   3.105 +        }
   3.106 +        if (type == Character.TYPE) {
   3.107 +            return "[C";
   3.108 +        }
   3.109 +        if (type.getName().equals("void")) {
   3.110 +            throw new IllegalStateException("Can't create array for " + type);
   3.111 +        }
   3.112 +        return "[L" + type.getName() + ";";
   3.113 +    }
   3.114 +    /**
   3.115 +     * Creates a new array
   3.116 +     * with the specified component type and dimensions.
   3.117 +     * If {@code componentType}
   3.118 +     * represents a non-array class or interface, the new array
   3.119 +     * has {@code dimensions.length} dimensions and
   3.120 +     * {@code componentType} as its component type. If
   3.121 +     * {@code componentType} represents an array class, the
   3.122 +     * number of dimensions of the new array is equal to the sum
   3.123 +     * of {@code dimensions.length} and the number of
   3.124 +     * dimensions of {@code componentType}. In this case, the
   3.125 +     * component type of the new array is the component type of
   3.126 +     * {@code componentType}.
   3.127 +     *
   3.128 +     * <p>The number of dimensions of the new array must not
   3.129 +     * exceed the number of array dimensions supported by the
   3.130 +     * implementation (typically 255).
   3.131 +     *
   3.132 +     * @param componentType the {@code Class} object representing the component
   3.133 +     * type of the new array
   3.134 +     * @param dimensions an array of {@code int} representing the dimensions of
   3.135 +     * the new array
   3.136 +     * @return the new array
   3.137 +     * @exception NullPointerException if the specified
   3.138 +     * {@code componentType} argument is null
   3.139 +     * @exception IllegalArgumentException if the specified {@code dimensions}
   3.140 +     * argument is a zero-dimensional array, or if the number of
   3.141 +     * requested dimensions exceeds the limit on the number of array dimensions
   3.142 +     * supported by the implementation (typically 255), or if componentType
   3.143 +     * is {@link Void#TYPE}.
   3.144 +     * @exception NegativeArraySizeException if any of the components in
   3.145 +     * the specified {@code dimensions} argument is negative.
   3.146 +     */
   3.147 +    public static Object newInstance(Class<?> componentType, int... dimensions)
   3.148 +        throws IllegalArgumentException, NegativeArraySizeException {
   3.149 +        StringBuilder sig = new StringBuilder();
   3.150 +        for (int i = 1; i < dimensions.length; i++) {
   3.151 +            sig.append('[');
   3.152 +        }
   3.153 +        sig.append(findSignature(componentType));
   3.154 +        return multiNewArray(sig.toString(), dimensions, 0);
   3.155 +    }
   3.156 +
   3.157 +    /**
   3.158 +     * Returns the length of the specified array object, as an {@code int}.
   3.159 +     *
   3.160 +     * @param array the array
   3.161 +     * @return the length of the array
   3.162 +     * @exception IllegalArgumentException if the object argument is not
   3.163 +     * an array
   3.164 +     */
   3.165 +    public static int getLength(Object array)
   3.166 +    throws IllegalArgumentException {
   3.167 +        if (!array.getClass().isArray()) {
   3.168 +            throw new IllegalArgumentException("Argument is not an array");
   3.169 +        }
   3.170 +        return length(array);
   3.171 +    }
   3.172 +    
   3.173 +    @JavaScriptBody(args = { "arr" }, body = "return arr.length;")
   3.174 +    private static native int length(Object arr);
   3.175 +
   3.176 +    /**
   3.177 +     * Returns the value of the indexed component in the specified
   3.178 +     * array object.  The value is automatically wrapped in an object
   3.179 +     * if it has a primitive type.
   3.180 +     *
   3.181 +     * @param array the array
   3.182 +     * @param index the index
   3.183 +     * @return the (possibly wrapped) value of the indexed component in
   3.184 +     * the specified array
   3.185 +     * @exception NullPointerException If the specified object is null
   3.186 +     * @exception IllegalArgumentException If the specified object is not
   3.187 +     * an array
   3.188 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.189 +     * argument is negative, or if it is greater than or equal to the
   3.190 +     * length of the specified array
   3.191 +     */
   3.192 +    public static Object get(Object array, int index)
   3.193 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.194 +        final Class<?> t = array.getClass().getComponentType();
   3.195 +        if (t.isPrimitive()) {
   3.196 +            return Array.fromPrimitive(t, array, index);
   3.197 +        } else {
   3.198 +            return ((Object[])array)[index];
   3.199 +        }
   3.200 +    }
   3.201 +
   3.202 +    /**
   3.203 +     * Returns the value of the indexed component in the specified
   3.204 +     * array object, as a {@code boolean}.
   3.205 +     *
   3.206 +     * @param array the array
   3.207 +     * @param index the index
   3.208 +     * @return the value of the indexed component in the specified array
   3.209 +     * @exception NullPointerException If the specified object is null
   3.210 +     * @exception IllegalArgumentException If the specified object is not
   3.211 +     * an array, or if the indexed element cannot be converted to the
   3.212 +     * return type by an identity or widening conversion
   3.213 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.214 +     * argument is negative, or if it is greater than or equal to the
   3.215 +     * length of the specified array
   3.216 +     * @see Array#get
   3.217 +     */
   3.218 +    public static native boolean getBoolean(Object array, int index)
   3.219 +        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
   3.220 +
   3.221 +    /**
   3.222 +     * Returns the value of the indexed component in the specified
   3.223 +     * array object, as a {@code byte}.
   3.224 +     *
   3.225 +     * @param array the array
   3.226 +     * @param index the index
   3.227 +     * @return the value of the indexed component in the specified array
   3.228 +     * @exception NullPointerException If the specified object is null
   3.229 +     * @exception IllegalArgumentException If the specified object is not
   3.230 +     * an array, or if the indexed element cannot be converted to the
   3.231 +     * return type by an identity or widening conversion
   3.232 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.233 +     * argument is negative, or if it is greater than or equal to the
   3.234 +     * length of the specified array
   3.235 +     * @see Array#get
   3.236 +     */
   3.237 +    public static byte getByte(Object array, int index)
   3.238 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.239 +        if (array.getClass().getComponentType() != Byte.TYPE) {
   3.240 +            throw new IllegalArgumentException();
   3.241 +        }
   3.242 +        byte[] arr = (byte[]) array;
   3.243 +        return arr[index];
   3.244 +    }
   3.245 +
   3.246 +    /**
   3.247 +     * Returns the value of the indexed component in the specified
   3.248 +     * array object, as a {@code char}.
   3.249 +     *
   3.250 +     * @param array the array
   3.251 +     * @param index the index
   3.252 +     * @return the value of the indexed component in the specified array
   3.253 +     * @exception NullPointerException If the specified object is null
   3.254 +     * @exception IllegalArgumentException If the specified object is not
   3.255 +     * an array, or if the indexed element cannot be converted to the
   3.256 +     * return type by an identity or widening conversion
   3.257 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.258 +     * argument is negative, or if it is greater than or equal to the
   3.259 +     * length of the specified array
   3.260 +     * @see Array#get
   3.261 +     */
   3.262 +    public static native char getChar(Object array, int index)
   3.263 +        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
   3.264 +
   3.265 +    /**
   3.266 +     * Returns the value of the indexed component in the specified
   3.267 +     * array object, as a {@code short}.
   3.268 +     *
   3.269 +     * @param array the array
   3.270 +     * @param index the index
   3.271 +     * @return the value of the indexed component in the specified array
   3.272 +     * @exception NullPointerException If the specified object is null
   3.273 +     * @exception IllegalArgumentException If the specified object is not
   3.274 +     * an array, or if the indexed element cannot be converted to the
   3.275 +     * return type by an identity or widening conversion
   3.276 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.277 +     * argument is negative, or if it is greater than or equal to the
   3.278 +     * length of the specified array
   3.279 +     * @see Array#get
   3.280 +     */
   3.281 +    public static short getShort(Object array, int index)
   3.282 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.283 +        final Class<?> t = array.getClass().getComponentType();
   3.284 +        if (t == Short.TYPE) {
   3.285 +            short[] arr = (short[]) array;
   3.286 +            return arr[index];
   3.287 +        }
   3.288 +        return getByte(array, index);
   3.289 +    }
   3.290 +
   3.291 +    /**
   3.292 +     * Returns the value of the indexed component in the specified
   3.293 +     * array object, as an {@code int}.
   3.294 +     *
   3.295 +     * @param array the array
   3.296 +     * @param index the index
   3.297 +     * @return the value of the indexed component in the specified array
   3.298 +     * @exception NullPointerException If the specified object is null
   3.299 +     * @exception IllegalArgumentException If the specified object is not
   3.300 +     * an array, or if the indexed element cannot be converted to the
   3.301 +     * return type by an identity or widening conversion
   3.302 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.303 +     * argument is negative, or if it is greater than or equal to the
   3.304 +     * length of the specified array
   3.305 +     * @see Array#get
   3.306 +     */
   3.307 +    public static int getInt(Object array, int index) 
   3.308 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.309 +        final Class<?> t = array.getClass().getComponentType();
   3.310 +        if (t == Integer.TYPE) {
   3.311 +            int[] arr = (int[]) array;
   3.312 +            return arr[index];
   3.313 +        }
   3.314 +        return getShort(array, index);
   3.315 +    }
   3.316 +
   3.317 +    /**
   3.318 +     * Returns the value of the indexed component in the specified
   3.319 +     * array object, as a {@code long}.
   3.320 +     *
   3.321 +     * @param array the array
   3.322 +     * @param index the index
   3.323 +     * @return the value of the indexed component in the specified array
   3.324 +     * @exception NullPointerException If the specified object is null
   3.325 +     * @exception IllegalArgumentException If the specified object is not
   3.326 +     * an array, or if the indexed element cannot be converted to the
   3.327 +     * return type by an identity or widening conversion
   3.328 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.329 +     * argument is negative, or if it is greater than or equal to the
   3.330 +     * length of the specified array
   3.331 +     * @see Array#get
   3.332 +     */
   3.333 +    public static long getLong(Object array, int index)
   3.334 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.335 +        final Class<?> t = array.getClass().getComponentType();
   3.336 +        if (t == Long.TYPE) {
   3.337 +            long[] arr = (long[]) array;
   3.338 +            return arr[index];
   3.339 +        }
   3.340 +        return getInt(array, index);
   3.341 +    }
   3.342 +
   3.343 +    /**
   3.344 +     * Returns the value of the indexed component in the specified
   3.345 +     * array object, as a {@code float}.
   3.346 +     *
   3.347 +     * @param array the array
   3.348 +     * @param index the index
   3.349 +     * @return the value of the indexed component in the specified array
   3.350 +     * @exception NullPointerException If the specified object is null
   3.351 +     * @exception IllegalArgumentException If the specified object is not
   3.352 +     * an array, or if the indexed element cannot be converted to the
   3.353 +     * return type by an identity or widening conversion
   3.354 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.355 +     * argument is negative, or if it is greater than or equal to the
   3.356 +     * length of the specified array
   3.357 +     * @see Array#get
   3.358 +     */
   3.359 +    public static float getFloat(Object array, int index)
   3.360 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.361 +        final Class<?> t = array.getClass().getComponentType();
   3.362 +        if (t == Float.TYPE) {
   3.363 +            float[] arr = (float[]) array;
   3.364 +            return arr[index];
   3.365 +        }
   3.366 +        return getLong(array, index);
   3.367 +    }
   3.368 +
   3.369 +    /**
   3.370 +     * Returns the value of the indexed component in the specified
   3.371 +     * array object, as a {@code double}.
   3.372 +     *
   3.373 +     * @param array the array
   3.374 +     * @param index the index
   3.375 +     * @return the value of the indexed component in the specified array
   3.376 +     * @exception NullPointerException If the specified object is null
   3.377 +     * @exception IllegalArgumentException If the specified object is not
   3.378 +     * an array, or if the indexed element cannot be converted to the
   3.379 +     * return type by an identity or widening conversion
   3.380 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.381 +     * argument is negative, or if it is greater than or equal to the
   3.382 +     * length of the specified array
   3.383 +     * @see Array#get
   3.384 +     */
   3.385 +    public static double getDouble(Object array, int index)
   3.386 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.387 +        final Class<?> t = array.getClass().getComponentType();
   3.388 +        if (t == Double.TYPE) {
   3.389 +            double[] arr = (double[]) array;
   3.390 +            return arr[index];
   3.391 +        }
   3.392 +        return getFloat(array, index);
   3.393 +    }
   3.394 +
   3.395 +    /**
   3.396 +     * Sets the value of the indexed component of the specified array
   3.397 +     * object to the specified new value.  The new value is first
   3.398 +     * automatically unwrapped if the array has a primitive component
   3.399 +     * type.
   3.400 +     * @param array the array
   3.401 +     * @param index the index into the array
   3.402 +     * @param value the new value of the indexed component
   3.403 +     * @exception NullPointerException If the specified object argument
   3.404 +     * is null
   3.405 +     * @exception IllegalArgumentException If the specified object argument
   3.406 +     * is not an array, or if the array component type is primitive and
   3.407 +     * an unwrapping conversion fails
   3.408 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.409 +     * argument is negative, or if it is greater than or equal to
   3.410 +     * the length of the specified array
   3.411 +     */
   3.412 +    public static void set(Object array, int index, Object value)
   3.413 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.414 +        if (array.getClass().getComponentType().isPrimitive()) {
   3.415 +            throw new IllegalArgumentException();
   3.416 +        } else {
   3.417 +            Object[] arr = (Object[])array;
   3.418 +            arr[index] = value;
   3.419 +        }
   3.420 +    }
   3.421 +
   3.422 +    /**
   3.423 +     * Sets the value of the indexed component of the specified array
   3.424 +     * object to the specified {@code boolean} value.
   3.425 +     * @param array the array
   3.426 +     * @param index the index into the array
   3.427 +     * @param z the new value of the indexed component
   3.428 +     * @exception NullPointerException If the specified object argument
   3.429 +     * is null
   3.430 +     * @exception IllegalArgumentException If the specified object argument
   3.431 +     * is not an array, or if the specified value cannot be converted
   3.432 +     * to the underlying array's component type by an identity or a
   3.433 +     * primitive widening conversion
   3.434 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.435 +     * argument is negative, or if it is greater than or equal to
   3.436 +     * the length of the specified array
   3.437 +     * @see Array#set
   3.438 +     */
   3.439 +    public static native void setBoolean(Object array, int index, boolean z)
   3.440 +        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
   3.441 +
   3.442 +    /**
   3.443 +     * Sets the value of the indexed component of the specified array
   3.444 +     * object to the specified {@code byte} value.
   3.445 +     * @param array the array
   3.446 +     * @param index the index into the array
   3.447 +     * @param b the new value of the indexed component
   3.448 +     * @exception NullPointerException If the specified object argument
   3.449 +     * is null
   3.450 +     * @exception IllegalArgumentException If the specified object argument
   3.451 +     * is not an array, or if the specified value cannot be converted
   3.452 +     * to the underlying array's component type by an identity or a
   3.453 +     * primitive widening conversion
   3.454 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.455 +     * argument is negative, or if it is greater than or equal to
   3.456 +     * the length of the specified array
   3.457 +     * @see Array#set
   3.458 +     */
   3.459 +    public static void setByte(Object array, int index, byte b)
   3.460 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.461 +        Class<?> t = array.getClass().getComponentType();
   3.462 +        if (t == Byte.TYPE) {
   3.463 +            byte[] arr = (byte[]) array;
   3.464 +            arr[index] = b;
   3.465 +        } else {
   3.466 +            setShort(array, index, b);
   3.467 +        }
   3.468 +    }
   3.469 +
   3.470 +    /**
   3.471 +     * Sets the value of the indexed component of the specified array
   3.472 +     * object to the specified {@code char} value.
   3.473 +     * @param array the array
   3.474 +     * @param index the index into the array
   3.475 +     * @param c the new value of the indexed component
   3.476 +     * @exception NullPointerException If the specified object argument
   3.477 +     * is null
   3.478 +     * @exception IllegalArgumentException If the specified object argument
   3.479 +     * is not an array, or if the specified value cannot be converted
   3.480 +     * to the underlying array's component type by an identity or a
   3.481 +     * primitive widening conversion
   3.482 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.483 +     * argument is negative, or if it is greater than or equal to
   3.484 +     * the length of the specified array
   3.485 +     * @see Array#set
   3.486 +     */
   3.487 +    public static native void setChar(Object array, int index, char c)
   3.488 +        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
   3.489 +
   3.490 +    /**
   3.491 +     * Sets the value of the indexed component of the specified array
   3.492 +     * object to the specified {@code short} value.
   3.493 +     * @param array the array
   3.494 +     * @param index the index into the array
   3.495 +     * @param s the new value of the indexed component
   3.496 +     * @exception NullPointerException If the specified object argument
   3.497 +     * is null
   3.498 +     * @exception IllegalArgumentException If the specified object argument
   3.499 +     * is not an array, or if the specified value cannot be converted
   3.500 +     * to the underlying array's component type by an identity or a
   3.501 +     * primitive widening conversion
   3.502 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.503 +     * argument is negative, or if it is greater than or equal to
   3.504 +     * the length of the specified array
   3.505 +     * @see Array#set
   3.506 +     */
   3.507 +    public static void setShort(Object array, int index, short s)
   3.508 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.509 +        Class<?> t = array.getClass().getComponentType();
   3.510 +        if (t == Short.TYPE) {
   3.511 +            short[] arr = (short[]) array;
   3.512 +            arr[index] = s;
   3.513 +        } else {
   3.514 +            setInt(array, index, s);
   3.515 +        }
   3.516 +        
   3.517 +    }
   3.518 +
   3.519 +    /**
   3.520 +     * Sets the value of the indexed component of the specified array
   3.521 +     * object to the specified {@code int} value.
   3.522 +     * @param array the array
   3.523 +     * @param index the index into the array
   3.524 +     * @param i the new value of the indexed component
   3.525 +     * @exception NullPointerException If the specified object argument
   3.526 +     * is null
   3.527 +     * @exception IllegalArgumentException If the specified object argument
   3.528 +     * is not an array, or if the specified value cannot be converted
   3.529 +     * to the underlying array's component type by an identity or a
   3.530 +     * primitive widening conversion
   3.531 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.532 +     * argument is negative, or if it is greater than or equal to
   3.533 +     * the length of the specified array
   3.534 +     * @see Array#set
   3.535 +     */
   3.536 +    public static void setInt(Object array, int index, int i)
   3.537 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.538 +        Class<?> t = array.getClass().getComponentType();
   3.539 +        if (t == Integer.TYPE) {
   3.540 +            long[] arr = (long[]) array;
   3.541 +            arr[index] = i;
   3.542 +        } else {
   3.543 +            setLong(array, index, i);
   3.544 +        }
   3.545 +    }
   3.546 +
   3.547 +    /**
   3.548 +     * Sets the value of the indexed component of the specified array
   3.549 +     * object to the specified {@code long} value.
   3.550 +     * @param array the array
   3.551 +     * @param index the index into the array
   3.552 +     * @param l the new value of the indexed component
   3.553 +     * @exception NullPointerException If the specified object argument
   3.554 +     * is null
   3.555 +     * @exception IllegalArgumentException If the specified object argument
   3.556 +     * is not an array, or if the specified value cannot be converted
   3.557 +     * to the underlying array's component type by an identity or a
   3.558 +     * primitive widening conversion
   3.559 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.560 +     * argument is negative, or if it is greater than or equal to
   3.561 +     * the length of the specified array
   3.562 +     * @see Array#set
   3.563 +     */
   3.564 +    public static void setLong(Object array, int index, long l)
   3.565 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.566 +        Class<?> t = array.getClass().getComponentType();
   3.567 +        if (t == Long.TYPE) {
   3.568 +            long[] arr = (long[]) array;
   3.569 +            arr[index] = l;
   3.570 +        } else {
   3.571 +            setFloat(array, index, l);
   3.572 +        }
   3.573 +    }
   3.574 +
   3.575 +    /**
   3.576 +     * Sets the value of the indexed component of the specified array
   3.577 +     * object to the specified {@code float} value.
   3.578 +     * @param array the array
   3.579 +     * @param index the index into the array
   3.580 +     * @param f the new value of the indexed component
   3.581 +     * @exception NullPointerException If the specified object argument
   3.582 +     * is null
   3.583 +     * @exception IllegalArgumentException If the specified object argument
   3.584 +     * is not an array, or if the specified value cannot be converted
   3.585 +     * to the underlying array's component type by an identity or a
   3.586 +     * primitive widening conversion
   3.587 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.588 +     * argument is negative, or if it is greater than or equal to
   3.589 +     * the length of the specified array
   3.590 +     * @see Array#set
   3.591 +     */
   3.592 +    public static void setFloat(Object array, int index, float f)
   3.593 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.594 +        Class<?> t = array.getClass().getComponentType();
   3.595 +        if (t == Float.TYPE) {
   3.596 +            float[] arr = (float[])array;
   3.597 +            arr[index] = f;
   3.598 +        } else {
   3.599 +            setDouble(array, index, f);
   3.600 +        }
   3.601 +    }
   3.602 +
   3.603 +    /**
   3.604 +     * Sets the value of the indexed component of the specified array
   3.605 +     * object to the specified {@code double} value.
   3.606 +     * @param array the array
   3.607 +     * @param index the index into the array
   3.608 +     * @param d the new value of the indexed component
   3.609 +     * @exception NullPointerException If the specified object argument
   3.610 +     * is null
   3.611 +     * @exception IllegalArgumentException If the specified object argument
   3.612 +     * is not an array, or if the specified value cannot be converted
   3.613 +     * to the underlying array's component type by an identity or a
   3.614 +     * primitive widening conversion
   3.615 +     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
   3.616 +     * argument is negative, or if it is greater than or equal to
   3.617 +     * the length of the specified array
   3.618 +     * @see Array#set
   3.619 +     */
   3.620 +    public static void setDouble(Object array, int index, double d)
   3.621 +    throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
   3.622 +        Class<?> t = array.getClass().getComponentType();
   3.623 +        if (t == Double.TYPE) {
   3.624 +            double[] arr = (double[])array;
   3.625 +            arr[index] = d;
   3.626 +        } else {
   3.627 +            throw new IllegalArgumentException("argument type mismatch");
   3.628 +        }
   3.629 +    }
   3.630 +
   3.631 +    /*
   3.632 +     * Private
   3.633 +     */
   3.634 +
   3.635 +    @JavaScriptBody(args = { "primitive", "sig", "length" }, body =
   3.636 +          "var arr = new Array(length);\n"
   3.637 +        + "var value = primitive ? 0 : null;\n"
   3.638 +        + "for(var i = 0; i < length; i++) arr[i] = value;\n"
   3.639 +        + "arr.jvmName = sig;\n"
   3.640 +        + "return arr;"
   3.641 +    )
   3.642 +    private static native Object newArray(boolean primitive, String sig, int length);
   3.643 +
   3.644 +    private static Object multiNewArray(String sig, int[] dims, int index)
   3.645 +    throws IllegalArgumentException, NegativeArraySizeException {
   3.646 +        if (dims.length == index + 1) {
   3.647 +            return newArray(sig.length() == 2, sig, dims[index]);
   3.648 +        }
   3.649 +        Object[] arr = (Object[]) newArray(false, sig, dims[index]);
   3.650 +        String compsig = sig.substring(1);
   3.651 +        for (int i = 0; i < arr.length; i++) {
   3.652 +            arr[i] = multiNewArray(compsig, dims, index + 1);
   3.653 +        }
   3.654 +        return arr;
   3.655 +    }
   3.656 +    private static Object fromPrimitive(Class<?> t, Object array, int index) {
   3.657 +        return Method.fromPrimitive(t, atArray(array, index));
   3.658 +    }
   3.659 +    
   3.660 +    @JavaScriptBody(args = { "array", "index" }, body = "return array[index]")
   3.661 +    private static native Object atArray(Object array, int index);
   3.662 +}
     4.1 --- a/emul/src/main/java/java/lang/reflect/Method.java	Tue Jan 15 12:44:33 2013 +0100
     4.2 +++ b/emul/src/main/java/java/lang/reflect/Method.java	Fri Jan 18 22:17:01 2013 +0100
     4.3 @@ -537,7 +537,7 @@
     4.4      )
     4.5      private static native Object invoke0(boolean isStatic, Method m, Object self, Object[] args);
     4.6  
     4.7 -    private static Object fromPrimitive(Class<?> type, Object o) {
     4.8 +    static Object fromPrimitive(Class<?> type, Object o) {
     4.9          if (type == Integer.TYPE) {
    4.10              return fromRaw(Integer.class, "valueOf__Ljava_lang_Integer_2I", o);
    4.11          }
     5.1 --- a/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js	Tue Jan 15 12:44:33 2013 +0100
     5.2 +++ b/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js	Fri Jan 18 22:17:01 2013 +0100
     5.3 @@ -1,12 +1,7 @@
     5.4 -// initialize methods on String constants
     5.5 +// initialize methods on arrays and String constants
     5.6 +vm.java_lang_reflect_Array(false);
     5.7  vm.java_lang_String(false);
     5.8  
     5.9 -// we need initialized arrays
    5.10 -Array.prototype.initWith = function(sig, value) {
    5.11 -  for(var i = 0; i < this.length; i++) this[i] = value;
    5.12 -  this.jvmName = sig;
    5.13 -  return this;
    5.14 -};
    5.15  Array.prototype.at = function(indx, value) {
    5.16    if (indx < 0 || indx > this.length) {
    5.17        var e = vm.java_lang_ArrayIndexOutOfBoundsException(true);
     6.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Tue Jan 15 12:44:33 2013 +0100
     6.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Fri Jan 18 22:17:01 2013 +0100
     6.3 @@ -926,7 +926,7 @@
     6.4                          case 11: jvmType = "[J"; break;
     6.5                          default: throw new IllegalStateException("Array type: " + atype);
     6.6                      }
     6.7 -                    emit(out, "@2 = new Array(@1).initWith('@3', 0);",
     6.8 +                    emit(out, "@2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);",
     6.9                           smapper.popI(), smapper.pushA(), jvmType);
    6.10                      break;
    6.11                  case opc_anewarray: {
    6.12 @@ -938,7 +938,7 @@
    6.13                      } else {
    6.14                          typeName = "[L" + typeName + ";";
    6.15                      }
    6.16 -                    emit(out, "@2 = new Array(@1).initWith('@3', null);",
    6.17 +                    emit(out, "@2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);",
    6.18                           smapper.popI(), smapper.pushA(), typeName);
    6.19                      break;
    6.20                  }
    6.21 @@ -947,26 +947,17 @@
    6.22                      i += 2;
    6.23                      String typeName = jc.getClassName(type);
    6.24                      int dim = readByte(byteCodes, ++i);
    6.25 -                    out.append("{ var a0 = new Array(").append(smapper.popI())
    6.26 -                       .append(").initWith('").append(typeName).append("', null);");
    6.27 -                    for (int d = 1; d < dim; d++) {
    6.28 -                        typeName = typeName.substring(1);
    6.29 -                        out.append("\n  var l" + d).append(" = ")
    6.30 -                           .append(smapper.popI()).append(';');
    6.31 -                        out.append("\n  for (var i" + d).append (" = 0; i" + d).
    6.32 -                            append(" < a" + (d - 1)).
    6.33 -                            append(".length; i" + d).append("++) {");
    6.34 -                        out.append("\n    var a" + d).
    6.35 -                            append (" = new Array(l" + d).append(").initWith('")
    6.36 -                            .append(typeName).append("', ")
    6.37 -                            .append(typeName.length() == 2 ? "0" : "null").append(");");
    6.38 -                        out.append("\n    a" + (d - 1)).append("[i" + d).append("] = a" + d).
    6.39 -                            append(";");
    6.40 +                    StringBuilder dims = new StringBuilder();
    6.41 +                    dims.append('[');
    6.42 +                    for (int d = 0; d < dim; d++) {
    6.43 +                        if (d != 0) {
    6.44 +                            dims.append(",");
    6.45 +                        }
    6.46 +                        dims.append(smapper.popI());
    6.47                      }
    6.48 -                    for (int d = 1; d < dim; d++) {
    6.49 -                        out.append("\n  }");
    6.50 -                    }
    6.51 -                    out.append("\n").append(smapper.pushA()).append(" = a0; }");
    6.52 +                    dims.append(']');
    6.53 +                    emit(out, "@2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);",
    6.54 +                         dims.toString(), smapper.pushA(), typeName);
    6.55                      break;
    6.56                  }
    6.57                  case opc_arraylength:
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java	Fri Jan 18 22:17:01 2013 +0100
     7.3 @@ -0,0 +1,135 @@
     7.4 +/**
     7.5 + * Back 2 Browser Bytecode Translator
     7.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     7.7 + *
     7.8 + * This program is free software: you can redistribute it and/or modify
     7.9 + * it under the terms of the GNU General Public License as published by
    7.10 + * the Free Software Foundation, version 2 of the License.
    7.11 + *
    7.12 + * This program is distributed in the hope that it will be useful,
    7.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    7.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    7.15 + * GNU General Public License for more details.
    7.16 + *
    7.17 + * You should have received a copy of the GNU General Public License
    7.18 + * along with this program. Look for COPYING file in the top folder.
    7.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    7.20 + */
    7.21 +package org.apidesign.bck2brwsr.tck;
    7.22 +
    7.23 +import java.lang.reflect.Array;
    7.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
    7.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
    7.26 +import org.testng.annotations.Factory;
    7.27 +
    7.28 +/**
    7.29 + *
    7.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    7.31 + */
    7.32 +public class ReflectionArrayTest {
    7.33 +    @Compare public int lengthOfStringArray() {
    7.34 +        String[] arr = (String[]) Array.newInstance(String.class, 10);
    7.35 +        return arr.length;
    7.36 +    }
    7.37 +    
    7.38 +    @Compare public int reflectiveLengthOfStringArray() {
    7.39 +        Object arr = Array.newInstance(String.class, 10);
    7.40 +        return Array.getLength(arr);
    7.41 +    }
    7.42 +
    7.43 +    @Compare public int reflectiveLengthOneNonArray() {
    7.44 +        Object arr = "non-array";
    7.45 +        return Array.getLength(arr);
    7.46 +    }
    7.47 +
    7.48 +    @Compare public String compTypeOfStringArray() {
    7.49 +        String[] arr = (String[]) Array.newInstance(String.class, 10);
    7.50 +        return arr.getClass().getComponentType().getName();
    7.51 +    }
    7.52 +
    7.53 +    @Compare public Object negativeArrayExcp() {
    7.54 +        return Array.newInstance(String.class, -5);
    7.55 +    }
    7.56 +    
    7.57 +    @Compare public int lengthOfIntArray() {
    7.58 +        int[] arr = (int[]) Array.newInstance(Integer.TYPE, 10);
    7.59 +        return arr.length;
    7.60 +    }
    7.61 +
    7.62 +    @Compare public int reflectiveLengthOfIntArray() {
    7.63 +        Object arr = Array.newInstance(Integer.TYPE, 10);
    7.64 +        return Array.getLength(arr);
    7.65 +    }
    7.66 +
    7.67 +    @Compare public String compTypeOfIntArray() {
    7.68 +        int[] arr = (int[]) Array.newInstance(int.class, 10);
    7.69 +        return arr.getClass().getComponentType().getName();
    7.70 +    }
    7.71 +
    7.72 +    @Compare public Object intNegativeArrayExcp() {
    7.73 +        return Array.newInstance(int.class, -5);
    7.74 +    }
    7.75 +
    7.76 +    @Compare public Integer verifyAutobox() {
    7.77 +        int[] arr = (int[]) Array.newInstance(int.class, 5);
    7.78 +        return (Integer) Array.get(arr, 0);
    7.79 +    }
    7.80 +    @Compare public String verifyObjectArray() {
    7.81 +        String[] arr = (String[]) Array.newInstance(String.class, 5);
    7.82 +        Array.set(arr, 0, "Hello");
    7.83 +        return (String) Array.get(arr, 0);
    7.84 +    }
    7.85 +    @Compare public int verifyInt() {
    7.86 +        int[] arr = (int[]) Array.newInstance(int.class, 5);
    7.87 +        return Array.getInt(arr, 0);
    7.88 +    }
    7.89 +    @Compare public long verifyConvertToLong() {
    7.90 +        int[] arr = (int[]) Array.newInstance(int.class, 5);
    7.91 +        return Array.getLong(arr, 0);
    7.92 +    }
    7.93 +
    7.94 +    @Compare public Object verifySetIntToObject() {
    7.95 +        try {
    7.96 +            Object[] arr = (Object[]) Array.newInstance(Object.class, 5);
    7.97 +            Array.setInt(arr, 0, 10);
    7.98 +            return Array.get(arr, 0);
    7.99 +        } catch (Exception exception) {
   7.100 +            return exception.getClass().getName();
   7.101 +        }
   7.102 +    }
   7.103 +    @Compare public long verifySetShort() {
   7.104 +        int[] arr = (int[]) Array.newInstance(int.class, 5);
   7.105 +        Array.setShort(arr, 0, (short)10);
   7.106 +        return Array.getLong(arr, 0);
   7.107 +    }
   7.108 +    @Compare public long verifyCantSetLong() {
   7.109 +        int[] arr = (int[]) Array.newInstance(int.class, 5);
   7.110 +        Array.setLong(arr, 0, 10);
   7.111 +        return Array.getLong(arr, 0);
   7.112 +    }
   7.113 +    @Compare public float verifyLongToFloat() {
   7.114 +        Object arr = Array.newInstance(float.class, 5);
   7.115 +        Array.setLong(arr, 0, 10);
   7.116 +        return Array.getFloat(arr, 0);
   7.117 +    }
   7.118 +
   7.119 +    @Compare public double verifyConvertToDouble() {
   7.120 +        int[] arr = (int[]) Array.newInstance(int.class, 5);
   7.121 +        return Array.getDouble(arr, 0);
   7.122 +    }
   7.123 +    
   7.124 +    @Compare public int multiIntArray() {
   7.125 +        int[][][] arr = (int[][][]) Array.newInstance(int.class, 3, 3, 3);
   7.126 +        return arr[0][1][2] + 5 + arr[2][2][0];
   7.127 +    }
   7.128 +
   7.129 +    @Compare public String multiIntArrayCompType() {
   7.130 +        return Array.newInstance(int.class, 3, 3, 3).getClass().getName();
   7.131 +    }
   7.132 +    
   7.133 +    
   7.134 +    @Factory
   7.135 +    public static Object[] create() {
   7.136 +        return VMTest.create(ReflectionArrayTest.class);
   7.137 +    }
   7.138 +}