# HG changeset patch # User Jaroslav Tulach # Date 1399363722 -7200 # Node ID ca538fb33f48d627bbbd70c6c2ea515b6e21a1da # Parent 9e1af8aae38053bb7b75ad5cceb6e57daf8ede98 2nd step in eliminating need for Class.forName when dealing with arrays diff -r 9e1af8aae380 -r ca538fb33f48 rt/emul/mini/src/main/java/java/lang/reflect/Array.java --- a/rt/emul/mini/src/main/java/java/lang/reflect/Array.java Tue May 06 08:38:34 2014 +0200 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Array.java Tue May 06 10:08:42 2014 +0200 @@ -642,7 +642,40 @@ @Exported private static native Object newArray(boolean primitive, String sig, Object fn, int length); + @Exported + private static boolean isInstance(Object arr, String sig) { + if (arr == null) { + return false; + } + return sig.equals(arr.getClass().getName()); + } + + @Exported + private static boolean isInstance(Object arr, int dimensions, Object fn) throws ClassNotFoundException { + if (arr == null) { + return false; + } +// log("isInstance for " + arr + " and " + dimensions); + Class c = arr.getClass(); + while (dimensions-- > 0) { +// log(" class: " + c); + c = c.getComponentType(); +// log(" next class: " + c); + if (c == null) { + return false; + } + } + Class t = classFromFn(fn); +// log(" to check: " + t); + return t.isAssignableFrom(c); + } + + @JavaScriptBody(args = { "cntstr" }, body = "return cntstr(false).constructor.$class;") + private static native Class classFromFn(Object cntstr); +// @JavaScriptBody(args = { "m" }, body = "java.lang.System.out.println(m.toString().toString());") +// private static native void log(Object m); + @Exported private static Object multiNewArray(String sig, int[] dims, int index) throws IllegalArgumentException, NegativeArraySizeException { diff -r 9e1af8aae380 -r ca538fb33f48 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue May 06 08:38:34 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue May 06 10:08:42 2014 +0200 @@ -2201,32 +2201,56 @@ } private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException { - final String type = jc.getClassName(indx); + String type = jc.getClassName(indx); if (!type.startsWith("[")) { emit(smapper, this, "var @2 = @1 != null && @1['$instOf_@3'] ? 1 : 0;", smapper.popA(), smapper.pushI(), type.replace('/', '_')); } else { - emit(smapper, this, - "var @2 = vm.java_lang_Class(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('@3')['isInstance__ZLjava_lang_Object_2'](@1);", - smapper.popA(), smapper.pushI(), - type - ); + int cnt = 0; + while (type.charAt(cnt) == '[') { + cnt++; + } + if (type.charAt(cnt) == 'L') { + type = "vm." + mangleClassName(type.substring(cnt + 1, type.length() - 1)); + emit(smapper, this, + "var @2 = Array.prototype['isInstance__ZLjava_lang_Object_2ILjava_lang_Object_2'](@1, @4, @3);", + smapper.popA(), smapper.pushI(), + type, "" + cnt + ); + } else { + emit(smapper, this, + "var @2 = Array.prototype['isInstance__ZLjava_lang_Object_2Ljava_lang_String_2'](@1, '@3');", + smapper.popA(), smapper.pushI(), type + ); + } } } private void generateCheckcast(int indx, final StackMapper smapper) throws IOException { - final String type = jc.getClassName(indx); + String type = jc.getClassName(indx); if (!type.startsWith("[")) { emitNoFlush(smapper, "if (@1 !== null && !@1['$instOf_@2']) throw vm.java_lang_ClassCastException(true);", smapper.getT(0, VarType.REFERENCE, false), type.replace('/', '_')); } else { - emitNoFlush(smapper, - "vm.java_lang_Class(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('@2')['cast__Ljava_lang_Object_2Ljava_lang_Object_2'](@1);", - smapper.getT(0, VarType.REFERENCE, false), type - ); + int cnt = 0; + while (type.charAt(cnt) == '[') { + cnt++; + } + if (type.charAt(cnt) == 'L') { + type = "vm." + mangleClassName(type.substring(cnt + 1, type.length() - 1)); + emitNoFlush(smapper, + "if (@1 !== null && !Array.prototype['isInstance__ZLjava_lang_Object_2ILjava_lang_Object_2'](@1, @3, @2)) throw vm.java_lang_ClassCastException(true);", + smapper.getT(0, VarType.REFERENCE, false), type, "" + cnt + ); + } else { + emitNoFlush(smapper, + "if (@1 !== null && !Array.prototype['isInstance__ZLjava_lang_Object_2Ljava_lang_String_2'](@1, '@2')) throw vm.java_lang_ClassCastException(true);", + smapper.getT(0, VarType.REFERENCE, false), type + ); + } } } diff -r 9e1af8aae380 -r ca538fb33f48 rt/vm/src/test/java/org/apidesign/vm4brwsr/Array.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Array.java Tue May 06 08:38:34 2014 +0200 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Array.java Tue May 06 10:08:42 2014 +0200 @@ -115,9 +115,42 @@ } public static boolean instanceOfArray(Object obj) { + if ("string-array".equals(obj)) { + obj = new String[] { "Ahoj" }; + } return obj instanceof Object[]; } + public static boolean castArray(int type) { + try { + Object orig = new Object(); + Object res = orig; + if (type == 0) { + Object[] arr = new Integer[1]; + String[] str = (String[]) arr; + res = str; + } + if (type == 1) { + Object[] arr = null; + String[] str = (String[]) arr; + res = str; + } + if (type == 2) { + Object[] arr = new String[1]; + String[] str = (String[]) arr; + res = str; + } + if (type == 3) { + Object[] arr = new String[1]; + CharSequence[] str = (CharSequence[]) arr; + res = str; + } + return res != orig; + } catch (ClassCastException ex) { + return false; + } + } + public static int sum(int size) { int[] arr = new int[size]; return arr[0] + arr[1]; diff -r 9e1af8aae380 -r ca538fb33f48 rt/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java Tue May 06 08:38:34 2014 +0200 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java Tue May 06 10:08:42 2014 +0200 @@ -82,9 +82,28 @@ @Test public void verifyInstanceOfArray() throws Exception { assertExec("Returns 'false'", Array.class, "instanceOfArray__ZLjava_lang_Object_2", Double.valueOf(0), "non-array"); } + @Test public void verifyInstanceOfArrayOnNull() throws Exception { + assertFalse(Array.instanceOfArray(null), "Null is not an instance of array"); + assertExec("Returns 'false'", Array.class, "instanceOfArray__ZLjava_lang_Object_2", Double.valueOf(0), (Object) null); + } + @Test public void verifyInstanceOfArrayStrings() throws Exception { + assertExec("Returns 'false'", Array.class, "instanceOfArray__ZLjava_lang_Object_2", Double.valueOf(1), "string-array"); + } @Test public void verifyMultiLen() throws Exception { assertExec("Multi len is one", Array.class, "multiLen__I", Double.valueOf(1)); } + @Test public void upCastAnArray() throws Exception { + assertExec("Cannot cast int to string array", Array.class, "castArray__ZI", Double.valueOf(0), Double.valueOf(0)); + } + @Test public void upCastANullArray() throws Exception { + assertExec("Can cast null to string array", Array.class, "castArray__ZI", Double.valueOf(1), Double.valueOf(1)); + } + @Test public void upCastOK() throws Exception { + assertExec("Can cast string to string array", Array.class, "castArray__ZI", Double.valueOf(1), Double.valueOf(2)); + } + @Test public void upCastOK2() throws Exception { + assertExec("Can cast string to char sequence array", Array.class, "castArray__ZI", Double.valueOf(1), Double.valueOf(3)); + } private static TestVM code;