1st step in eliminating Class.forName when working with array types. Class.getComponentType on directly allocated arrays does not need that. closure
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 06 May 2014 08:36:54 +0200
branchclosure
changeset 153210d26626c426
parent 1531 ce3b83777055
child 1533 9e1af8aae380
1st step in eliminating Class.forName when working with array types. Class.getComponentType on directly allocated arrays does not need that.
rt/emul/mini/src/main/java/java/lang/Class.java
rt/emul/mini/src/main/java/java/lang/reflect/Array.java
rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_String.js
rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
rt/vm/src/test/java/org/apidesign/vm4brwsr/Array.java
rt/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java
     1.1 --- a/rt/emul/mini/src/main/java/java/lang/Class.java	Mon May 05 14:19:25 2014 +0200
     1.2 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java	Tue May 06 08:36:54 2014 +0200
     1.3 @@ -151,7 +151,7 @@
     1.4      public static Class<?> forName(String className)
     1.5      throws ClassNotFoundException {
     1.6          if (className.startsWith("[")) {
     1.7 -            Class<?> arrType = defineArray(className);
     1.8 +            Class<?> arrType = defineArray(className, null);
     1.9              Class<?> c = arrType;
    1.10              while (c != null && c.isArray()) {
    1.11                  c = c.getComponentType0(); // verify component type is sane
    1.12 @@ -1544,13 +1544,24 @@
    1.13      public Class<?> getComponentType() {
    1.14          if (isArray()) {
    1.15              try {
    1.16 -                return getComponentType0();
    1.17 +                Class<?> c = getComponentTypeByFnc();
    1.18 +                return c != null ? c : getComponentType0();
    1.19              } catch (ClassNotFoundException cnfe) {
    1.20                  throw new IllegalStateException(cnfe);
    1.21              }
    1.22          }
    1.23          return null;
    1.24      }
    1.25 +    
    1.26 +    @JavaScriptBody(args = {  }, body = 
    1.27 +        "if (this.fnc) {\n"
    1.28 +      + "  var c = this.fnc(false).constructor.$class;\n"
    1.29 +//      + "  java.lang.System.out.println('will call: ' + (!!this.fnc) + ' res: ' + c.jvmName);\n"
    1.30 +      + "  if (c) return c;\n"
    1.31 +      + "}\n"
    1.32 +      + "return null;"
    1.33 +    )
    1.34 +    private native Class<?> getComponentTypeByFnc();
    1.35  
    1.36      private Class<?> getComponentType0() throws ClassNotFoundException {
    1.37          String n = getName().substring(1);
    1.38 @@ -1577,24 +1588,26 @@
    1.39              case 'C':
    1.40                  return Character.TYPE;
    1.41              case '[':
    1.42 -                return defineArray(n);
    1.43 +                return defineArray(n, null);
    1.44              default:
    1.45                  throw new ClassNotFoundException("Unknown component type of " + getName());
    1.46          }
    1.47      }
    1.48      
    1.49 -    @JavaScriptBody(args = { "sig" }, body = 
    1.50 +    @JavaScriptBody(args = { "sig", "fnc" }, body = 
    1.51          "if (!sig) sig = '[Ljava/lang/Object;';\n" +
    1.52          "var c = Array[sig];\n" +
    1.53 -        "if (c) return c;\n" +
    1.54 -        "c = vm.java_lang_Class(true);\n" +
    1.55 -        "c.jvmName = sig;\n" +
    1.56 -        "c.superclass = vm.java_lang_Object(false).$class;\n" +
    1.57 -        "c.array = true;\n" +
    1.58 -        "Array[sig] = c;\n" +
    1.59 +        "if (!c) {\n" +
    1.60 +        "  c = vm.java_lang_Class(true);\n" +
    1.61 +        "  c.jvmName = sig;\n" +
    1.62 +        "  c.superclass = vm.java_lang_Object(false).$class;\n" +
    1.63 +        "  c.array = true;\n" +
    1.64 +        "  Array[sig] = c;\n" +
    1.65 +        "}\n" +
    1.66 +        "if (!c.fnc) c.fnc = fnc;\n" +
    1.67          "return c;"
    1.68      )
    1.69 -    private static native Class<?> defineArray(String sig);
    1.70 +    private static native Class<?> defineArray(String sig, Object fnc);
    1.71      
    1.72      /**
    1.73       * Returns true if and only if this class was declared as an enum in the
     2.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Array.java	Mon May 05 14:19:25 2014 +0200
     2.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Array.java	Tue May 06 08:36:54 2014 +0200
     2.3 @@ -76,7 +76,7 @@
     2.4              throw new NegativeArraySizeException();
     2.5          }
     2.6          String sig = findSignature(componentType);
     2.7 -        return newArray(componentType.isPrimitive(), sig, length);
     2.8 +        return newArray(componentType.isPrimitive(), sig, null, length);
     2.9      }
    2.10      
    2.11      private static String findSignature(Class<?> type) {
    2.12 @@ -630,24 +630,29 @@
    2.13       * Private
    2.14       */
    2.15  
    2.16 -    @JavaScriptBody(args = { "primitive", "sig", "length" }, body =
    2.17 +    @JavaScriptBody(args = { "primitive", "sig", "fn", "length" }, body =
    2.18            "var arr = new Array(length);\n"
    2.19          + "var value = primitive ? 0 : null;\n"
    2.20          + "for(var i = 0; i < length; i++) arr[i] = value;\n"
    2.21          + "arr.jvmName = sig;\n"
    2.22 +        + "arr.fnc = fn;\n"
    2.23 +//        + "java.lang.System.out.println('Assigned ' + arr.jvmName + ' fn: ' + (!!arr.fnc));\n"
    2.24          + "return arr;"
    2.25      )
    2.26 +    private static native Object newArray0(boolean primitive, String sig, Object fn, int length);
    2.27      @Exported
    2.28 -    private static native Object newArray(boolean primitive, String sig, int length);
    2.29 +    private static Object newArray(boolean primitive, String sig, Object fn, int length) {
    2.30 +        return newArray0(primitive, sig, fn, length);
    2.31 +    }
    2.32  
    2.33  
    2.34      @Exported
    2.35      private static Object multiNewArray(String sig, int[] dims, int index)
    2.36      throws IllegalArgumentException, NegativeArraySizeException {
    2.37          if (dims.length == index + 1) {
    2.38 -            return newArray(sig.length() == 2, sig, dims[index]);
    2.39 +            return newArray(sig.length() == 2, sig, null, dims[index]);
    2.40          }
    2.41 -        Object arr = newArray(false, sig, dims[index]);
    2.42 +        Object arr = newArray(false, sig, null, dims[index]);
    2.43          String compsig = sig.substring(1);
    2.44          int len = getLength(arr);
    2.45          for (int i = 0; i < len; i++) {
     3.1 --- a/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_String.js	Mon May 05 14:19:25 2014 +0200
     3.2 +++ b/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_String.js	Tue May 06 08:36:54 2014 +0200
     3.3 @@ -14,7 +14,7 @@
     3.4    return arr[indx];
     3.5  };
     3.6  Array.prototype.getClass__Ljava_lang_Class_2 = function() {
     3.7 -  return vm.java_lang_Class(false).defineArray__Ljava_lang_Class_2Ljava_lang_String_2(this.jvmName);
     3.8 +  return vm.java_lang_Class(false).defineArray__Ljava_lang_Class_2Ljava_lang_String_2Ljava_lang_Object_2(this.jvmName, this.fnc);
     3.9  };
    3.10  Array.prototype.clone__Ljava_lang_Object_2 = function() {
    3.11    var s = this.length;
    3.12 @@ -23,5 +23,6 @@
    3.13        ret[i] = this[i];
    3.14    }
    3.15    ret.jvmName = this.jvmName;
    3.16 +  ret.fnc = this.fnc;
    3.17    return ret;
    3.18  };
     4.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Mon May 05 14:19:25 2014 +0200
     4.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Tue May 06 08:36:54 2014 +0200
     4.3 @@ -2117,20 +2117,22 @@
     4.4              default: throw new IllegalStateException("Array type: " + atype);
     4.5          }
     4.6          emit(smapper, this, 
     4.7 -            "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](true, '@3', @1);",
     4.8 +            "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2Ljava_lang_Object_2I'](true, '@3', null, @1);",
     4.9               smapper.popI(), smapper.pushA(), jvmType);
    4.10      }
    4.11  
    4.12      private void generateANewArray(int type, final StackMapper smapper) throws IOException {
    4.13          String typeName = jc.getClassName(type);
    4.14 +        String ref = "null";
    4.15          if (typeName.startsWith("[")) {
    4.16 -            typeName = "[" + typeName;
    4.17 +            typeName = "'[" + typeName + "'";
    4.18          } else {
    4.19 -            typeName = "[L" + typeName + ";";
    4.20 +            ref = "vm." + mangleClassName(typeName);
    4.21 +            typeName = "'[L" + typeName + ";'";
    4.22          }
    4.23          emit(smapper, this,
    4.24 -            "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](false, '@3', @1);",
    4.25 -             smapper.popI(), smapper.pushA(), typeName);
    4.26 +            "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2Ljava_lang_Object_2I'](false, @3, @4, @1);",
    4.27 +             smapper.popI(), smapper.pushA(), typeName, ref);
    4.28      }
    4.29  
    4.30      private int generateMultiANewArray(int type, final byte[] byteCodes, int i, final StackMapper smapper) throws IOException {
     5.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Array.java	Mon May 05 14:19:25 2014 +0200
     5.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Array.java	Tue May 06 08:36:54 2014 +0200
     5.3 @@ -17,6 +17,8 @@
     5.4   */
     5.5  package org.apidesign.vm4brwsr;
     5.6  
     5.7 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
     5.8 +
     5.9  /**
    5.10   *
    5.11   * @author Jaroslav Tulach <jtulach@netbeans.org>
    5.12 @@ -133,6 +135,21 @@
    5.13          return arr[0];
    5.14      }
    5.15      
    5.16 +    @JavaScriptBody(args = {  }, body = 
    5.17 +        "if (!vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2) throw 'forName not defined';\n"
    5.18 +      + "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2 = function(s) {\n"
    5.19 +      + "  throw 'Do not call me: ' + s;\n"
    5.20 +      + "};\n")
    5.21 +    private static void disableClassForName() {
    5.22 +    }
    5.23 +    
    5.24 +    public static String nameOfClonedComponent() {
    5.25 +        disableClassForName();
    5.26 +        Object[] intArr = new Integer[10];
    5.27 +        intArr = intArr.clone();
    5.28 +        return intArr.getClass().getComponentType().getName();
    5.29 +    }
    5.30 +    
    5.31      public static int multiLen() {
    5.32          return new int[1][0].length;
    5.33      }
     6.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java	Mon May 05 14:19:25 2014 +0200
     6.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java	Tue May 06 08:36:54 2014 +0200
     6.3 @@ -43,6 +43,13 @@
     6.4              Double.valueOf(15), true
     6.5          );
     6.6      }
     6.7 +
     6.8 +    @Test public void cloneOnArrayAndComponentType() throws Exception {
     6.9 +        String exp = Array.nameOfClonedComponent();
    6.10 +        assertExec("getComponentType on clone", Array.class, "nameOfClonedComponent__Ljava_lang_String_2", 
    6.11 +            exp
    6.12 +        );
    6.13 +    }
    6.14      
    6.15      @Test public void realOperationOnArrays() throws Exception {
    6.16          assertEquals(Array.sum(), 105.0, "Computes to 105");