diff -r 8e546d108658 -r b42911b78a16 vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Fri Jan 25 11:00:52 2013 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sun Jan 27 10:19:02 2013 +0100 @@ -114,11 +114,6 @@ out.append("\n\n").append(assignClass(className)); out.append("function CLS() {"); out.append("\n if (!CLS.prototype.$instOf_").append(className).append(") {"); - for (FieldData v : jc.getFields()) { - if (v.isStatic()) { - out.append("\n CLS.").append(v.getName()).append(initField(v)); - } - } if (proto == null) { String sc = jc.getSuperClassName(); // with _ out.append("\n var pp = "). @@ -134,6 +129,18 @@ out.append("\n var c = ").append(proto[0]).append(";"); out.append("\n var sprcls = null;"); } + for (FieldData v : jc.getFields()) { + if (v.isStatic()) { + out.append("\n CLS.").append(v.getName()).append(initField(v)); + } else { + out.append("\n c._").append(v.getName()).append(" = function (v) {") + .append(" if (arguments.length == 1) this.fld_"). + append(className).append('_').append(v.getName()) + .append(" = v; return this.fld_"). + append(className).append('_').append(v.getName()) + .append("; };"); + } + } for (MethodData m : jc.getMethods()) { byte[] onlyArr = m.findAnnotationData(true); String[] only = findAnnotation(onlyArr, jc, @@ -206,13 +213,14 @@ } if (!v.isStatic()) { out.append("\n this.fld_"). + append(className).append('_'). append(v.getName()).append(initField(v)); } } out.append("\n return this;"); out.append("\n }"); out.append("\n return arguments[0] ? new CLS() : CLS.prototype;"); - out.append("\n}"); + out.append("\n};"); StringBuilder sb = new StringBuilder(); for (String init : toInitilize.toArray()) { sb.append("\n").append(init).append("();"); @@ -270,6 +278,7 @@ int lastStackFrame = -1; TrapData[] previousTrap = null; + boolean wide = false; out.append("\n var gt = 0;\n for(;;) switch(gt) {\n"); for (int i = 0; i < byteCodes.length; i++) { @@ -295,7 +304,7 @@ out.append("try {"); previousTrap = trap.current(); } - final int c = readByte(byteCodes, i); + final int c = readUByte(byteCodes, i); switch (c) { case opc_aload_0: emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(0)); @@ -358,61 +367,91 @@ emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(3)); break; case opc_iload: { - final int indx = readByte(byteCodes, ++i); + ++i; + final int indx = wide ? readUShort(byteCodes, i++) + : readUByte(byteCodes, i); + wide = false; emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(indx)); break; } case opc_lload: { - final int indx = readByte(byteCodes, ++i); + ++i; + final int indx = wide ? readUShort(byteCodes, i++) + : readUByte(byteCodes, i); + wide = false; emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(indx)); break; } case opc_fload: { - final int indx = readByte(byteCodes, ++i); + ++i; + final int indx = wide ? readUShort(byteCodes, i++) + : readUByte(byteCodes, i); + wide = false; emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(indx)); break; } case opc_dload: { - final int indx = readByte(byteCodes, ++i); + ++i; + final int indx = wide ? readUShort(byteCodes, i++) + : readUByte(byteCodes, i); + wide = false; emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(indx)); break; } case opc_aload: { - final int indx = readByte(byteCodes, ++i); + ++i; + final int indx = wide ? readUShort(byteCodes, i++) + : readUByte(byteCodes, i); + wide = false; emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(indx)); break; } case opc_istore: { - final int indx = readByte(byteCodes, ++i); + ++i; + final int indx = wide ? readUShort(byteCodes, i++) + : readUByte(byteCodes, i); + wide = false; emit(out, "var @1 = @2;", lmapper.setI(indx), smapper.popI()); break; } case opc_lstore: { - final int indx = readByte(byteCodes, ++i); + ++i; + final int indx = wide ? readUShort(byteCodes, i++) + : readUByte(byteCodes, i); + wide = false; emit(out, "var @1 = @2;", lmapper.setL(indx), smapper.popL()); break; } case opc_fstore: { - final int indx = readByte(byteCodes, ++i); + ++i; + final int indx = wide ? readUShort(byteCodes, i++) + : readUByte(byteCodes, i); + wide = false; emit(out, "var @1 = @2;", lmapper.setF(indx), smapper.popF()); break; } case opc_dstore: { - final int indx = readByte(byteCodes, ++i); + ++i; + final int indx = wide ? readUShort(byteCodes, i++) + : readUByte(byteCodes, i); + wide = false; emit(out, "var @1 = @2;", lmapper.setD(indx), smapper.popD()); break; } case opc_astore: { - final int indx = readByte(byteCodes, ++i); + ++i; + final int indx = wide ? readUShort(byteCodes, i++) + : readUByte(byteCodes, i); + wide = false; emit(out, "var @1 = @2;", lmapper.setA(indx), smapper.popA()); break; @@ -588,8 +627,13 @@ emit(out, "@1 >>>= @2;", smapper.getL(1), smapper.popI()); break; case opc_iinc: { - final int varIndx = readByte(byteCodes, ++i); - final int incrBy = byteCodes[++i]; + ++i; + final int varIndx = wide ? readUShort(byteCodes, i++) + : readUByte(byteCodes, i); + ++i; + final int incrBy = wide ? readIntArg(byteCodes, i++) + : byteCodes[i]; + wide = false; if (incrBy == 1) { emit(out, "@1++;", lmapper.getI(varIndx)); } else { @@ -713,7 +757,7 @@ emit(out, "var @1 = 5;", smapper.pushI()); break; case opc_ldc: { - int indx = readByte(byteCodes, ++i); + int indx = readUByte(byteCodes, ++i); String v = encodeConstant(indx); int type = VarType.fromConstantType(jc.getTag(indx)); emit(out, "var @1 = @2;", smapper.pushT(type), v); @@ -904,7 +948,7 @@ break; } case opc_newarray: - int atype = readByte(byteCodes, ++i); + int atype = readUByte(byteCodes, ++i); String jvmType; switch (atype) { case 4: jvmType = "[Z"; break; @@ -937,7 +981,7 @@ int type = readIntArg(byteCodes, i); i += 2; String typeName = jc.getClassName(type); - int dim = readByte(byteCodes, ++i); + int dim = readUByte(byteCodes, ++i); StringBuilder dims = new StringBuilder(); dims.append('['); for (int d = 0; d < dim; d++) { @@ -1012,16 +1056,16 @@ break; } case opc_dup2: { - if (smapper.get(0).isCategory2()) { - final Variable v = smapper.get(0); + final Variable vi1 = smapper.get(0); + + if (vi1.isCategory2()) { emit(out, "var @1 = @2;", - smapper.pushT(v.getType()), v); + smapper.pushT(vi1.getType()), vi1); } else { - final Variable v1 = smapper.get(0); - final Variable v2 = smapper.get(1); + final Variable vi2 = smapper.get(1); emit(out, "var @1 = @2, @3 = @4;", - smapper.pushT(v2.getType()), v2, - smapper.pushT(v1.getType()), v1); + smapper.pushT(vi2.getType()), vi2, + smapper.pushT(vi1.getType()), vi1); } break; } @@ -1036,10 +1080,11 @@ vo1, vi1, vo2, vi2, vo3, vo1); break; } - case opc_dup_x2: { - if (smapper.get(1).isCategory2()) { - final Variable vi1 = smapper.pop(); - final Variable vi2 = smapper.pop(); + case opc_dup2_x1: { + final Variable vi1 = smapper.pop(); + final Variable vi2 = smapper.pop(); + + if (vi1.isCategory2()) { final Variable vo3 = smapper.pushT(vi1.getType()); final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); @@ -1047,8 +1092,32 @@ emit(out, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); } else { - final Variable vi1 = smapper.pop(); - final Variable vi2 = smapper.pop(); + final Variable vi3 = smapper.pop(); + final Variable vo5 = smapper.pushT(vi2.getType()); + final Variable vo4 = smapper.pushT(vi1.getType()); + final Variable vo3 = smapper.pushT(vi3.getType()); + final Variable vo2 = smapper.pushT(vi2.getType()); + final Variable vo1 = smapper.pushT(vi1.getType()); + + emit(out, "var @1 = @2, @3 = @4, @5 = @6,", + vo1, vi1, vo2, vi2, vo3, vi3); + emit(out, " @1 = @2, @3 = @4;", + vo4, vo1, vo5, vo2); + } + break; + } + case opc_dup_x2: { + final Variable vi1 = smapper.pop(); + final Variable vi2 = smapper.pop(); + + if (vi2.isCategory2()) { + final Variable vo3 = smapper.pushT(vi1.getType()); + final Variable vo2 = smapper.pushT(vi2.getType()); + final Variable vo1 = smapper.pushT(vi1.getType()); + + emit(out, "var @1 = @2, @3 = @4, @5 = @6;", + vo1, vi1, vo2, vi2, vo3, vo1); + } else { final Variable vi3 = smapper.pop(); final Variable vo4 = smapper.pushT(vi1.getType()); final Variable vo3 = smapper.pushT(vi3.getType()); @@ -1060,6 +1129,76 @@ } break; } + case opc_dup2_x2: { + final Variable vi1 = smapper.pop(); + final Variable vi2 = smapper.pop(); + + if (vi1.isCategory2()) { + if (vi2.isCategory2()) { + final Variable vo3 = smapper.pushT(vi1.getType()); + final Variable vo2 = smapper.pushT(vi2.getType()); + final Variable vo1 = smapper.pushT(vi1.getType()); + + emit(out, "var @1 = @2, @3 = @4, @5 = @6;", + vo1, vi1, vo2, vi2, vo3, vo1); + } else { + final Variable vi3 = smapper.pop(); + final Variable vo4 = smapper.pushT(vi1.getType()); + final Variable vo3 = smapper.pushT(vi3.getType()); + final Variable vo2 = smapper.pushT(vi2.getType()); + final Variable vo1 = smapper.pushT(vi1.getType()); + + emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", + vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1); + } + } else { + final Variable vi3 = smapper.pop(); + + if (vi3.isCategory2()) { + final Variable vo5 = smapper.pushT(vi2.getType()); + final Variable vo4 = smapper.pushT(vi1.getType()); + final Variable vo3 = smapper.pushT(vi3.getType()); + final Variable vo2 = smapper.pushT(vi2.getType()); + final Variable vo1 = smapper.pushT(vi1.getType()); + + emit(out, "var @1 = @2, @3 = @4, @5 = @6,", + vo1, vi1, vo2, vi2, vo3, vi3); + emit(out, " @1 = @2, @3 = @4;", + vo4, vo1, vo5, vo2); + } else { + final Variable vi4 = smapper.pop(); + final Variable vo6 = smapper.pushT(vi2.getType()); + final Variable vo5 = smapper.pushT(vi1.getType()); + final Variable vo4 = smapper.pushT(vi4.getType()); + final Variable vo3 = smapper.pushT(vi3.getType()); + final Variable vo2 = smapper.pushT(vi2.getType()); + final Variable vo1 = smapper.pushT(vi1.getType()); + + emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8,", + vo1, vi1, vo2, vi2, vo3, vi3, vo4, vi4); + emit(out, " @1 = @2, @3 = @4;", + vo5, vo1, vo6, vo2); + } + } + break; + } + case opc_swap: { + final Variable vi1 = smapper.get(0); + final Variable vi2 = smapper.get(1); + + if (vi1.getType() == vi2.getType()) { + final Variable tmp = smapper.pushT(vi1.getType()); + + emit(out, "var @1 = @2, @2 = @3, @3 = @1;", + tmp, vi1, vi2); + smapper.pop(1); + } else { + smapper.pop(2); + smapper.pushT(vi1.getType()); + smapper.pushT(vi2.getType()); + } + break; + } case opc_bipush: emit(out, "var @1 = @2;", smapper.pushI(), Integer.toString(byteCodes[++i])); @@ -1074,8 +1213,26 @@ int indx = readIntArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); - emit(out, "var @2 = @1.fld_@3;", - smapper.popA(), smapper.pushT(type), fi[1]); + final String mangleClass = mangleSig(fi[0]); + final String mangleClassAccess = accessClass(mangleClass); + emit(out, "var @2 = @4(false)._@3.call(@1);", + smapper.popA(), + smapper.pushT(type), fi[1], mangleClassAccess + ); + i += 2; + break; + } + case opc_putfield: { + int indx = readIntArg(byteCodes, i); + String[] fi = jc.getFieldInfoName(indx); + final int type = VarType.fromFieldType(fi[2].charAt(0)); + final String mangleClass = mangleSig(fi[0]); + final String mangleClassAccess = accessClass(mangleClass); + emit(out, "@4(false)._@3.call(@2, @1);", + smapper.popT(type), + smapper.popA(), fi[1], + mangleClassAccess + ); i += 2; break; } @@ -1090,15 +1247,6 @@ addReference(fi[0]); break; } - case opc_putfield: { - int indx = readIntArg(byteCodes, i); - String[] fi = jc.getFieldInfoName(indx); - final int type = VarType.fromFieldType(fi[2].charAt(0)); - emit(out, "@2.fld_@3 = @1;", - smapper.popT(type), smapper.popA(), fi[1]); - i += 2; - break; - } case opc_putstatic: { int indx = readIntArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); @@ -1114,11 +1262,13 @@ int indx = readIntArg(byteCodes, i); final String type = jc.getClassName(indx); if (!type.startsWith("[")) { - // no way to check arrays right now - // XXX proper exception emit(out, "if (@1 !== null && !@1.$instOf_@2) throw {};", smapper.getA(0), type.replace('/', '_')); + } else { + emit(out, "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@2').cast__Ljava_lang_Object_2Ljava_lang_Object_2(@1);", + smapper.getA(0), type + ); } i += 2; break; @@ -1126,9 +1276,16 @@ case opc_instanceof: { int indx = readIntArg(byteCodes, i); final String type = jc.getClassName(indx); - emit(out, "var @2 = @1.$instOf_@3 ? 1 : 0;", - smapper.popA(), smapper.pushI(), - type.replace('/', '_')); + if (!type.startsWith("[")) { + emit(out, "var @2 = @1.$instOf_@3 ? 1 : 0;", + smapper.popA(), smapper.pushI(), + type.replace('/', '_')); + } else { + emit(out, "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 + ); + } i += 2; break; } @@ -1153,7 +1310,12 @@ break; } + case opc_wide: + wide = true; + break; + default: { + wide = false; emit(out, "throw 'unknown bytecode @1';", Integer.toString(c)); } @@ -1161,7 +1323,7 @@ if (debug(" //")) { for (int j = prev; j <= i; j++) { out.append(" "); - final int cc = readByte(byteCodes, j); + final int cc = readUByte(byteCodes, j); out.append(Integer.toString(cc)); } } @@ -1197,10 +1359,15 @@ final int a = byteCodes[offsetInstruction + 3]; return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff); } - private int readByte(byte[] byteCodes, int offsetInstruction) { + private int readUByte(byte[] byteCodes, int offsetInstruction) { return byteCodes[offsetInstruction] & 0xff; } - + + private int readUShort(byte[] byteCodes, int offsetInstruction) { + return ((byteCodes[offsetInstruction] & 0xff) << 8) + | (byteCodes[offsetInstruction + 1] & 0xff); + } + private static void countArgs(String descriptor, char[] returnType, StringBuilder sig, StringBuilder cnt) { int i = 0; Boolean count = null; @@ -1278,6 +1445,10 @@ } } + static String mangleSig(String sig) { + return mangleSig(sig, 0, sig.length()); + } + private static String mangleSig(String txt, int first, int last) { StringBuilder sb = new StringBuilder(); for (int i = first; i < last; i++) { @@ -1424,8 +1595,12 @@ String[] classRef = { null }; String s = jc.stringValue(entryIndex, classRef); if (classRef[0] != null) { - addReference(classRef[0]); - s = accessClass(s.replace('/', '_')) + "(false).constructor.$class"; + if (classRef[0].startsWith("[")) { + s = accessClass("java_lang_Class") + "(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('" + classRef[0] + "');"; + } else { + addReference(classRef[0]); + s = accessClass(s.replace('/', '_')) + "(false).constructor.$class"; + } } return s; }