diff -r 2af07db15110 -r ba912ef24b27 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Apr 24 18:05:21 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Wed Apr 30 15:04:10 2014 +0200 @@ -25,14 +25,36 @@ * * @author Jaroslav Tulach */ -abstract class ByteCodeToJavaScript { +abstract class ByteCodeToJavaScript implements Appendable { private ClassData jc; - final Appendable out; + private final Appendable out; + private boolean outChanged; protected ByteCodeToJavaScript(Appendable out) { this.out = out; } + @Override + public final Appendable append(CharSequence csq) throws IOException { + out.append(csq); + outChanged = true; + return this; + } + + @Override + public final Appendable append(CharSequence csq, int start, int end) throws IOException { + out.append(csq, start, end); + outChanged = true; + return this; + } + + @Override + public final Appendable append(char c) throws IOException { + out.append(c); + outChanged = true; + return this; + } + /* Collects additional required resources. * * @param internalClassName classes that were referenced and should be loaded in order the @@ -99,7 +121,7 @@ * @throws IOException */ boolean debug(String msg) throws IOException { - out.append(msg); + append(msg); return true; } @@ -124,16 +146,34 @@ ); } byte[] arrData = jc.findAnnotationData(true); - String[] arr = findAnnotation(arrData, jc, - "org.apidesign.bck2brwsr.core.ExtraJavaScript", - "resource", "processByteCode" - ); - if (arr != null) { - if (!arr[0].isEmpty()) { - requireScript(arr[0]); + { + String[] arr = findAnnotation(arrData, jc, + "org.apidesign.bck2brwsr.core.ExtraJavaScript", + "resource", "processByteCode" + ); + if (arr != null) { + if (!arr[0].isEmpty()) { + requireScript(arr[0]); + } + if ("0".equals(arr[1])) { + return null; + } } - if ("0".equals(arr[1])) { - return null; + } + { + String[] arr = findAnnotation(arrData, jc, + "net.java.html.js.JavaScriptResource", + "value" + ); + if (arr != null) { + if (arr[0].startsWith("/")) { + requireScript(arr[0]); + } else { + int last = jc.getClassName().lastIndexOf('/'); + requireScript( + jc.getClassName().substring(0, last + 1).replace('.', '/') + arr[0] + ); + } } } String[] proto = findAnnotation(arrData, jc, @@ -142,34 +182,39 @@ ); StringArray toInitilize = new StringArray(); final String className = className(jc); - out.append("\n\n").append(assignClass(className)); - out.append("function ").append(className).append("() {"); - out.append("\n var CLS = ").append(className).append(';'); - out.append("\n if (!CLS.$class) {"); + append("\n\n").append(assignClass(className)); + append("function ").append(className).append("() {"); + append("\n var CLS = ").append(className).append(';'); + append("\n if (!CLS.$class) {"); if (proto == null) { String sc = jc.getSuperClassName(); // with _ - out.append("\n var pp = "). - append(accessClass(sc.replace('/', '_'))).append("(true);"); - out.append("\n var p = CLS.prototype = pp;"); - out.append("\n var c = p;"); - out.append("\n var sprcls = pp.constructor.$class;"); + append("\n var pp = "). + append(accessClass(mangleClassName(sc))).append("(true);"); + append("\n var p = CLS.prototype = pp;"); + append("\n var c = p;"); + append("\n var sprcls = pp.constructor.$class;"); } else { - out.append("\n var p = CLS.prototype = ").append(proto[1]).append(";"); + append("\n var p = CLS.prototype = ").append(proto[1]).append(";"); if (proto[0] == null) { proto[0] = "p"; } - out.append("\n var c = ").append(proto[0]).append(";"); - out.append("\n var sprcls = null;"); + append("\n var c = ").append(proto[0]).append(";"); + append("\n var sprcls = null;"); } for (FieldData v : jc.getFields()) { if (v.isStatic()) { - out.append("\n CLS.").append(v.getName()).append(initField(v)); - out.append("\n c._").append(v.getName()).append(" = function (v) {") - .append(" if (arguments.length == 1) CLS.").append(v.getName()) - .append(" = v; return CLS."). + if ((v.access & ACC_FINAL) != 0 && v.hasConstantValue()) { + if (v.getInternalSig().length() == 1 || v.getInternalSig().equals("Ljava/lang/String;")) { + continue; + } + } + append("\n CLS.fld_").append(v.getName()).append(initField(v)); + append("\n c._").append(v.getName()).append(" = function (v) {") + .append(" if (arguments.length == 1) CLS.fld_").append(v.getName()) + .append(" = v; return CLS.fld_"). append(v.getName()).append("; };"); } else { - out.append("\n c._").append(v.getName()).append(" = function (v) {") + 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_"). @@ -187,14 +232,14 @@ ); if (only != null) { if (only[0] != null && only[1] != null) { - out.append("\n p.").append(only[0]).append(" = ") + append("\n p.").append(only[0]).append(" = ") .append(only[1]).append(";"); } continue; } String destObject; String mn; - out.append("\n "); + append("\n "); if (m.isStatic()) { destObject = "c"; mn = generateStaticMethod(destObject, m, toInitilize); @@ -210,39 +255,47 @@ declaredMethod(m, destObject, mn); byte[] runAnno = m.findAnnotationData(false); if (runAnno != null) { - out.append("\n ").append(destObject).append(".").append(mn).append(".anno = {"); - generateAnno(jc, out, runAnno); - out.append("\n };"); + append("\n ").append(destObject).append(".").append(mn).append(".anno = {"); + generateAnno(jc, runAnno); + append("\n };"); } - out.append("\n ").append(destObject).append(".").append(mn).append(".access = " + m.getAccess()).append(";"); - out.append("\n ").append(destObject).append(".").append(mn).append(".cls = CLS;"); + append("\n ").append(destObject).append(".").append(mn).append(".access = " + m.getAccess()).append(";"); + append("\n ").append(destObject).append(".").append(mn).append(".cls = CLS;"); } - out.append("\n c.constructor = CLS;"); - out.append("\n c['$instOf_").append(className).append("'] = true;"); + append("\n c.constructor = CLS;"); + append("\n function fillInstOf(x) {"); + String instOfName = "$instOf_" + className; + append("\n x['").append(instOfName).append("'] = true;"); for (String superInterface : jc.getSuperInterfaces()) { - out.append("\n c['$instOf_").append(superInterface.replace('/', '_')).append("'] = true;"); + String intrfc = superInterface.replace('/', '_'); + append("\n vm.").append(intrfc).append("(false)['fillInstOf'](x);"); + requireReference(superInterface); } - out.append("\n CLS.$class = 'temp';"); - out.append("\n CLS.$class = "); - out.append(accessClass("java_lang_Class(true);")); - out.append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';"); - out.append("\n CLS.$class.superclass = sprcls;"); - out.append("\n CLS.$class.access = ").append(jc.getAccessFlags()+";"); - out.append("\n CLS.$class.cnstr = CLS;"); + append("\n }"); + append("\n c['fillInstOf'] = fillInstOf;"); + append("\n fillInstOf(c);"); +// obfuscationDelegate.exportJSProperty(this, "c", instOfName); + append("\n CLS.$class = 'temp';"); + append("\n CLS.$class = "); + append(accessClass("java_lang_Class(true);")); + append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';"); + append("\n CLS.$class.superclass = sprcls;"); + append("\n CLS.$class.access = ").append(jc.getAccessFlags()+";"); + append("\n CLS.$class.cnstr = CLS;"); byte[] classAnno = jc.findAnnotationData(false); if (classAnno != null) { - out.append("\n CLS.$class.anno = {"); - generateAnno(jc, out, classAnno); - out.append("\n };"); + append("\n CLS.$class.anno = {"); + generateAnno(jc, classAnno); + append("\n };"); } for (String init : toInitilize.toArray()) { - out.append("\n ").append(init).append("();"); + append("\n ").append(init).append("();"); } - out.append("\n }"); - out.append("\n if (arguments.length === 0) {"); - out.append("\n if (!(this instanceof CLS)) {"); - out.append("\n return new CLS();"); - out.append("\n }"); + append("\n }"); + append("\n if (arguments.length === 0) {"); + append("\n if (!(this instanceof CLS)) {"); + append("\n return new CLS();"); + append("\n }"); for (FieldData v : jc.getFields()) { byte[] onlyArr = v.findAnnotationData(true); String[] only = findAnnotation(onlyArr, jc, @@ -251,21 +304,21 @@ ); if (only != null) { if (only[0] != null && only[1] != null) { - out.append("\n p.").append(only[0]).append(" = ") + append("\n p.").append(only[0]).append(" = ") .append(only[1]).append(";"); } continue; } if (!v.isStatic()) { - out.append("\n this.fld_"). + 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};"); + append("\n return this;"); + append("\n }"); + append("\n return arguments[0] ? new CLS() : CLS.prototype;"); + append("\n};"); declaredClass(jc, className); @@ -305,34 +358,43 @@ final LocalsMapper lmapper = new LocalsMapper(stackMapIterator.getArguments()); - out.append(destObject).append(".").append(name).append(" = function("); - lmapper.outputArguments(out, m.isStatic()); - out.append(") {").append("\n"); + append(destObject).append(".").append(name).append(" = function("); + lmapper.outputArguments(this, m.isStatic()); + append(") {").append("\n"); final byte[] byteCodes = m.getCode(); if (byteCodes == null) { - out.append(" throw 'no code found for ") + append(" throw 'no code found for ") .append(jc.getClassName()).append('.') .append(m.getName()).append("';\n"); - out.append("};"); + append("};"); return; } final StackMapper smapper = new StackMapper(); if (!m.isStatic()) { - out.append(" var ").append(" lcA0 = this;\n"); + append(" var ").append(" lcA0 = this;\n"); } - int lastStackFrame = -1; + int lastStackFrame; TrapData[] previousTrap = null; boolean wide = false; + boolean didBranches; + if (stackMapIterator.isEmpty()) { + didBranches = false; + lastStackFrame = 0; + } else { + didBranches = true; + lastStackFrame = -1; + append("\n var gt = 0;\n"); + } - out.append("\n var gt = 0;\n"); int openBraces = 0; int topMostLabel = 0; for (int i = 0; i < byteCodes.length; i++) { int prev = i; + outChanged = false; stackMapIterator.advanceTo(i); boolean changeInCatch = trap.advanceTo(i); if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) { @@ -342,12 +404,13 @@ } } if (lastStackFrame != stackMapIterator.getFrameIndex()) { + smapper.flush(this); if (i != 0) { - out.append(" }\n"); + append(" }\n"); } if (openBraces > 64) { for (int c = 0; c < 64; c++) { - out.append("break;}\n"); + append("break;}\n"); } openBraces = 1; topMostLabel = i; @@ -356,85 +419,84 @@ lastStackFrame = stackMapIterator.getFrameIndex(); lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals()); smapper.syncWithFrameStack(stackMapIterator.getFrameStack()); - out.append(" X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n"); + append(" X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n"); openBraces++; changeInCatch = true; } else { debug(" /* " + i + " */ "); } if (changeInCatch && trap.useTry()) { - out.append("try {"); + append("try {"); previousTrap = trap.current(); } final int c = readUByte(byteCodes, i); switch (c) { case opc_aload_0: - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(0)); + smapper.assign(this, VarType.REFERENCE, lmapper.getA(0)); break; case opc_iload_0: - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(0)); + smapper.assign(this, VarType.INTEGER, lmapper.getI(0)); break; case opc_lload_0: - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(0)); + smapper.assign(this, VarType.LONG, lmapper.getL(0)); break; case opc_fload_0: - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(0)); + smapper.assign(this, VarType.FLOAT, lmapper.getF(0)); break; case opc_dload_0: - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(0)); + smapper.assign(this, VarType.DOUBLE, lmapper.getD(0)); break; case opc_aload_1: - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(1)); + smapper.assign(this, VarType.REFERENCE, lmapper.getA(1)); break; case opc_iload_1: - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(1)); + smapper.assign(this, VarType.INTEGER, lmapper.getI(1)); break; case opc_lload_1: - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(1)); + smapper.assign(this, VarType.LONG, lmapper.getL(1)); break; case opc_fload_1: - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(1)); + smapper.assign(this, VarType.FLOAT, lmapper.getF(1)); break; case opc_dload_1: - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(1)); + smapper.assign(this, VarType.DOUBLE, lmapper.getD(1)); break; case opc_aload_2: - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(2)); + smapper.assign(this, VarType.REFERENCE, lmapper.getA(2)); break; case opc_iload_2: - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(2)); + smapper.assign(this, VarType.INTEGER, lmapper.getI(2)); break; case opc_lload_2: - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(2)); + smapper.assign(this, VarType.LONG, lmapper.getL(2)); break; case opc_fload_2: - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(2)); + smapper.assign(this, VarType.FLOAT, lmapper.getF(2)); break; case opc_dload_2: - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(2)); + smapper.assign(this, VarType.DOUBLE, lmapper.getD(2)); break; case opc_aload_3: - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(3)); + smapper.assign(this, VarType.REFERENCE, lmapper.getA(3)); break; case opc_iload_3: - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(3)); + smapper.assign(this, VarType.INTEGER, lmapper.getI(3)); break; case opc_lload_3: - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(3)); + smapper.assign(this, VarType.LONG, lmapper.getL(3)); break; case opc_fload_3: - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(3)); + smapper.assign(this, VarType.FLOAT, lmapper.getF(3)); break; case opc_dload_3: - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(3)); + smapper.assign(this, VarType.DOUBLE, lmapper.getD(3)); break; case opc_iload: { ++i; final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", - smapper.pushI(), lmapper.getI(indx)); + smapper.assign(this, VarType.INTEGER, lmapper.getI(indx)); break; } case opc_lload: { @@ -442,8 +504,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", - smapper.pushL(), lmapper.getL(indx)); + smapper.assign(this, VarType.LONG, lmapper.getL(indx)); break; } case opc_fload: { @@ -451,8 +512,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", - smapper.pushF(), lmapper.getF(indx)); + smapper.assign(this, VarType.FLOAT, lmapper.getF(indx)); break; } case opc_dload: { @@ -460,8 +520,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", - smapper.pushD(), lmapper.getD(indx)); + smapper.assign(this, VarType.DOUBLE, lmapper.getD(indx)); break; } case opc_aload: { @@ -469,8 +528,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", - smapper.pushA(), lmapper.getA(indx)); + smapper.assign(this, VarType.REFERENCE, lmapper.getA(indx)); break; } case opc_istore: { @@ -478,7 +536,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", + emit(smapper, this, "var @1 = @2;", lmapper.setI(indx), smapper.popI()); break; } @@ -487,7 +545,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", + emit(smapper, this, "var @1 = @2;", lmapper.setL(indx), smapper.popL()); break; } @@ -496,7 +554,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", + emit(smapper, this, "var @1 = @2;", lmapper.setF(indx), smapper.popF()); break; } @@ -505,7 +563,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", + emit(smapper, this, "var @1 = @2;", lmapper.setD(indx), smapper.popD()); break; } @@ -514,181 +572,181 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", + emit(smapper, this, "var @1 = @2;", lmapper.setA(indx), smapper.popA()); break; } case opc_astore_0: - emit(out, "var @1 = @2;", lmapper.setA(0), smapper.popA()); + emit(smapper, this, "var @1 = @2;", lmapper.setA(0), smapper.popA()); break; case opc_istore_0: - emit(out, "var @1 = @2;", lmapper.setI(0), smapper.popI()); + emit(smapper, this, "var @1 = @2;", lmapper.setI(0), smapper.popI()); break; case opc_lstore_0: - emit(out, "var @1 = @2;", lmapper.setL(0), smapper.popL()); + emit(smapper, this, "var @1 = @2;", lmapper.setL(0), smapper.popL()); break; case opc_fstore_0: - emit(out, "var @1 = @2;", lmapper.setF(0), smapper.popF()); + emit(smapper, this, "var @1 = @2;", lmapper.setF(0), smapper.popF()); break; case opc_dstore_0: - emit(out, "var @1 = @2;", lmapper.setD(0), smapper.popD()); + emit(smapper, this, "var @1 = @2;", lmapper.setD(0), smapper.popD()); break; case opc_astore_1: - emit(out, "var @1 = @2;", lmapper.setA(1), smapper.popA()); + emit(smapper, this, "var @1 = @2;", lmapper.setA(1), smapper.popA()); break; case opc_istore_1: - emit(out, "var @1 = @2;", lmapper.setI(1), smapper.popI()); + emit(smapper, this, "var @1 = @2;", lmapper.setI(1), smapper.popI()); break; case opc_lstore_1: - emit(out, "var @1 = @2;", lmapper.setL(1), smapper.popL()); + emit(smapper, this, "var @1 = @2;", lmapper.setL(1), smapper.popL()); break; case opc_fstore_1: - emit(out, "var @1 = @2;", lmapper.setF(1), smapper.popF()); + emit(smapper, this, "var @1 = @2;", lmapper.setF(1), smapper.popF()); break; case opc_dstore_1: - emit(out, "var @1 = @2;", lmapper.setD(1), smapper.popD()); + emit(smapper, this, "var @1 = @2;", lmapper.setD(1), smapper.popD()); break; case opc_astore_2: - emit(out, "var @1 = @2;", lmapper.setA(2), smapper.popA()); + emit(smapper, this, "var @1 = @2;", lmapper.setA(2), smapper.popA()); break; case opc_istore_2: - emit(out, "var @1 = @2;", lmapper.setI(2), smapper.popI()); + emit(smapper, this, "var @1 = @2;", lmapper.setI(2), smapper.popI()); break; case opc_lstore_2: - emit(out, "var @1 = @2;", lmapper.setL(2), smapper.popL()); + emit(smapper, this, "var @1 = @2;", lmapper.setL(2), smapper.popL()); break; case opc_fstore_2: - emit(out, "var @1 = @2;", lmapper.setF(2), smapper.popF()); + emit(smapper, this, "var @1 = @2;", lmapper.setF(2), smapper.popF()); break; case opc_dstore_2: - emit(out, "var @1 = @2;", lmapper.setD(2), smapper.popD()); + emit(smapper, this, "var @1 = @2;", lmapper.setD(2), smapper.popD()); break; case opc_astore_3: - emit(out, "var @1 = @2;", lmapper.setA(3), smapper.popA()); + emit(smapper, this, "var @1 = @2;", lmapper.setA(3), smapper.popA()); break; case opc_istore_3: - emit(out, "var @1 = @2;", lmapper.setI(3), smapper.popI()); + emit(smapper, this, "var @1 = @2;", lmapper.setI(3), smapper.popI()); break; case opc_lstore_3: - emit(out, "var @1 = @2;", lmapper.setL(3), smapper.popL()); + emit(smapper, this, "var @1 = @2;", lmapper.setL(3), smapper.popL()); break; case opc_fstore_3: - emit(out, "var @1 = @2;", lmapper.setF(3), smapper.popF()); + emit(smapper, this, "var @1 = @2;", lmapper.setF(3), smapper.popF()); break; case opc_dstore_3: - emit(out, "var @1 = @2;", lmapper.setD(3), smapper.popD()); + emit(smapper, this, "var @1 = @2;", lmapper.setD(3), smapper.popD()); break; case opc_iadd: - emit(out, "@1 = @1.add32(@2);", smapper.getI(1), smapper.popI()); + smapper.replace(this, VarType.INTEGER, "(@1).add32(@2)", smapper.getI(1), smapper.popI()); break; case opc_ladd: - emit(out, "@1 = @1.add64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(this, VarType.LONG, "(@1).add64(@2)", smapper.getL(1), smapper.popL()); break; case opc_fadd: - emit(out, "@1 += @2;", smapper.getF(1), smapper.popF()); + smapper.replace(this, VarType.FLOAT, "(@1 + @2)", smapper.getF(1), smapper.popF()); break; case opc_dadd: - emit(out, "@1 += @2;", smapper.getD(1), smapper.popD()); + smapper.replace(this, VarType.DOUBLE, "(@1 + @2)", smapper.getD(1), smapper.popD()); break; case opc_isub: - emit(out, "@1 = @1.sub32(@2);", smapper.getI(1), smapper.popI()); + smapper.replace(this, VarType.INTEGER, "(@1).sub32(@2)", smapper.getI(1), smapper.popI()); break; case opc_lsub: - emit(out, "@1 = @1.sub64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(this, VarType.LONG, "(@1).sub64(@2)", smapper.getL(1), smapper.popL()); break; case opc_fsub: - emit(out, "@1 -= @2;", smapper.getF(1), smapper.popF()); + smapper.replace(this, VarType.FLOAT, "(@1 - @2)", smapper.getF(1), smapper.popF()); break; case opc_dsub: - emit(out, "@1 -= @2;", smapper.getD(1), smapper.popD()); + smapper.replace(this, VarType.DOUBLE, "(@1 - @2)", smapper.getD(1), smapper.popD()); break; case opc_imul: - emit(out, "@1 = @1.mul32(@2);", smapper.getI(1), smapper.popI()); + smapper.replace(this, VarType.INTEGER, "(@1).mul32(@2)", smapper.getI(1), smapper.popI()); break; case opc_lmul: - emit(out, "@1 = @1.mul64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(this, VarType.LONG, "(@1).mul64(@2)", smapper.getL(1), smapper.popL()); break; case opc_fmul: - emit(out, "@1 *= @2;", smapper.getF(1), smapper.popF()); + smapper.replace(this, VarType.FLOAT, "(@1 * @2)", smapper.getF(1), smapper.popF()); break; case opc_dmul: - emit(out, "@1 *= @2;", smapper.getD(1), smapper.popD()); + smapper.replace(this, VarType.DOUBLE, "(@1 * @2)", smapper.getD(1), smapper.popD()); break; case opc_idiv: - emit(out, "@1 = @1.div32(@2);", + smapper.replace(this, VarType.INTEGER, "(@1).div32(@2)", smapper.getI(1), smapper.popI()); break; case opc_ldiv: - emit(out, "@1 = @1.div64(@2);", + smapper.replace(this, VarType.LONG, "(@1).div64(@2)", smapper.getL(1), smapper.popL()); break; case opc_fdiv: - emit(out, "@1 /= @2;", smapper.getF(1), smapper.popF()); + smapper.replace(this, VarType.FLOAT, "(@1 / @2)", smapper.getF(1), smapper.popF()); break; case opc_ddiv: - emit(out, "@1 /= @2;", smapper.getD(1), smapper.popD()); + smapper.replace(this, VarType.DOUBLE, "(@1 / @2)", smapper.getD(1), smapper.popD()); break; case opc_irem: - emit(out, "@1 = @1.mod32(@2);", + smapper.replace(this, VarType.INTEGER, "(@1).mod32(@2)", smapper.getI(1), smapper.popI()); break; case opc_lrem: - emit(out, "@1 = @1.mod64(@2);", + smapper.replace(this, VarType.LONG, "(@1).mod64(@2)", smapper.getL(1), smapper.popL()); break; case opc_frem: - emit(out, "@1 %= @2;", smapper.getF(1), smapper.popF()); + smapper.replace(this, VarType.FLOAT, "(@1 % @2)", smapper.getF(1), smapper.popF()); break; case opc_drem: - emit(out, "@1 %= @2;", smapper.getD(1), smapper.popD()); + smapper.replace(this, VarType.DOUBLE, "(@1 % @2)", smapper.getD(1), smapper.popD()); break; case opc_iand: - emit(out, "@1 &= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(this, VarType.INTEGER, "(@1 & @2)", smapper.getI(1), smapper.popI()); break; case opc_land: - emit(out, "@1 = @1.and64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(this, VarType.LONG, "(@1).and64(@2)", smapper.getL(1), smapper.popL()); break; case opc_ior: - emit(out, "@1 |= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(this, VarType.INTEGER, "(@1 | @2)", smapper.getI(1), smapper.popI()); break; case opc_lor: - emit(out, "@1 = @1.or64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(this, VarType.LONG, "(@1).or64(@2)", smapper.getL(1), smapper.popL()); break; case opc_ixor: - emit(out, "@1 ^= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(this, VarType.INTEGER, "(@1 ^ @2)", smapper.getI(1), smapper.popI()); break; case opc_lxor: - emit(out, "@1 = @1.xor64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(this, VarType.LONG, "(@1).xor64(@2)", smapper.getL(1), smapper.popL()); break; case opc_ineg: - emit(out, "@1 = @1.neg32();", smapper.getI(0)); + smapper.replace(this, VarType.INTEGER, "(@1).neg32()", smapper.getI(0)); break; case opc_lneg: - emit(out, "@1 = @1.neg64();", smapper.getL(0)); + smapper.replace(this, VarType.LONG, "(@1).neg64()", smapper.getL(0)); break; case opc_fneg: - emit(out, "@1 = -@1;", smapper.getF(0)); + smapper.replace(this, VarType.FLOAT, "(-@1)", smapper.getF(0)); break; case opc_dneg: - emit(out, "@1 = -@1;", smapper.getD(0)); + smapper.replace(this, VarType.DOUBLE, "(-@1)", smapper.getD(0)); break; case opc_ishl: - emit(out, "@1 <<= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(this, VarType.INTEGER, "(@1 << @2)", smapper.getI(1), smapper.popI()); break; case opc_lshl: - emit(out, "@1 = @1.shl64(@2);", smapper.getL(1), smapper.popI()); + smapper.replace(this, VarType.LONG, "(@1).shl64(@2)", smapper.getL(1), smapper.popI()); break; case opc_ishr: - emit(out, "@1 >>= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(this, VarType.INTEGER, "(@1 >> @2)", smapper.getI(1), smapper.popI()); break; case opc_lshr: - emit(out, "@1 = @1.shr64(@2);", smapper.getL(1), smapper.popI()); + smapper.replace(this, VarType.LONG, "(@1).shr64(@2)", smapper.getL(1), smapper.popI()); break; case opc_iushr: - emit(out, "@1 >>>= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(this, VarType.INTEGER, "(@1 >>> @2)", smapper.getI(1), smapper.popI()); break; case opc_lushr: - emit(out, "@1 = @1.ushr64(@2);", smapper.getL(1), smapper.popI()); + smapper.replace(this, VarType.LONG, "(@1).ushr64(@2)", smapper.getL(1), smapper.popI()); break; case opc_iinc: { ++i; @@ -699,132 +757,132 @@ : byteCodes[i]; wide = false; if (incrBy == 1) { - emit(out, "@1++;", lmapper.getI(varIndx)); + emit(smapper, this, "@1++;", lmapper.getI(varIndx)); } else { - emit(out, "@1 += @2;", + emit(smapper, this, "@1 += @2;", lmapper.getI(varIndx), Integer.toString(incrBy)); } break; } case opc_return: - emit(out, "return;"); + emit(smapper, this, "return;"); break; case opc_ireturn: - emit(out, "return @1;", smapper.popI()); + emit(smapper, this, "return @1;", smapper.popI()); break; case opc_lreturn: - emit(out, "return @1;", smapper.popL()); + emit(smapper, this, "return @1;", smapper.popL()); break; case opc_freturn: - emit(out, "return @1;", smapper.popF()); + emit(smapper, this, "return @1;", smapper.popF()); break; case opc_dreturn: - emit(out, "return @1;", smapper.popD()); + emit(smapper, this, "return @1;", smapper.popD()); break; case opc_areturn: - emit(out, "return @1;", smapper.popA()); + emit(smapper, this, "return @1;", smapper.popA()); break; case opc_i2l: - emit(out, "var @2 = @1;", smapper.popI(), smapper.pushL()); + smapper.replace(this, VarType.LONG, "@1", smapper.getI(0)); break; case opc_i2f: - emit(out, "var @2 = @1;", smapper.popI(), smapper.pushF()); + smapper.replace(this, VarType.FLOAT, "@1", smapper.getI(0)); break; case opc_i2d: - emit(out, "var @2 = @1;", smapper.popI(), smapper.pushD()); + smapper.replace(this, VarType.DOUBLE, "@1", smapper.getI(0)); break; case opc_l2i: - emit(out, "var @2 = @1.toInt32();", smapper.popL(), smapper.pushI()); + smapper.replace(this, VarType.INTEGER, "(@1).toInt32()", smapper.getL(0)); break; // max int check? case opc_l2f: - emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushF()); + smapper.replace(this, VarType.FLOAT, "(@1).toFP()", smapper.getL(0)); break; case opc_l2d: - emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushD()); + smapper.replace(this, VarType.DOUBLE, "(@1).toFP()", smapper.getL(0)); break; case opc_f2d: - emit(out, "var @2 = @1;", smapper.popF(), smapper.pushD()); + smapper.replace(this, VarType.DOUBLE, "@1", + smapper.getF(0)); break; case opc_d2f: - emit(out, "var @2 = @1;", smapper.popD(), smapper.pushF()); + smapper.replace(this, VarType.FLOAT, "@1", + smapper.getD(0)); break; case opc_f2i: - emit(out, "var @2 = @1.toInt32();", - smapper.popF(), smapper.pushI()); + smapper.replace(this, VarType.INTEGER, "(@1).toInt32()", + smapper.getF(0)); break; case opc_f2l: - emit(out, "var @2 = @1.toLong();", - smapper.popF(), smapper.pushL()); + smapper.replace(this, VarType.LONG, "(@1).toLong()", + smapper.getF(0)); break; case opc_d2i: - emit(out, "var @2 = @1.toInt32();", - smapper.popD(), smapper.pushI()); + smapper.replace(this, VarType.INTEGER, "(@1).toInt32()", + smapper.getD(0)); break; case opc_d2l: - emit(out, "var @2 = @1.toLong();", - smapper.popD(), smapper.pushL()); + smapper.replace(this, VarType.LONG, "(@1).toLong()", smapper.getD(0)); break; case opc_i2b: - emit(out, "var @1 = @1.toInt8();", smapper.getI(0)); + smapper.replace(this, VarType.INTEGER, "(@1).toInt8()", smapper.getI(0)); break; case opc_i2c: - out.append("{ /* number conversion */ }"); break; case opc_i2s: - emit(out, "var @1 = @1.toInt16();", smapper.getI(0)); + smapper.replace(this, VarType.INTEGER, "(@1).toInt16()", smapper.getI(0)); break; case opc_aconst_null: - emit(out, "var @1 = null;", smapper.pushA()); + smapper.assign(this, VarType.REFERENCE, "null"); break; case opc_iconst_m1: - emit(out, "var @1 = -1;", smapper.pushI()); + smapper.assign(this, VarType.INTEGER, "-1"); break; case opc_iconst_0: - emit(out, "var @1 = 0;", smapper.pushI()); + smapper.assign(this, VarType.INTEGER, "0"); break; case opc_dconst_0: - emit(out, "var @1 = 0;", smapper.pushD()); + smapper.assign(this, VarType.DOUBLE, "0"); break; case opc_lconst_0: - emit(out, "var @1 = 0;", smapper.pushL()); + smapper.assign(this, VarType.LONG, "0"); break; case opc_fconst_0: - emit(out, "var @1 = 0;", smapper.pushF()); + smapper.assign(this, VarType.FLOAT, "0"); break; case opc_iconst_1: - emit(out, "var @1 = 1;", smapper.pushI()); + smapper.assign(this, VarType.INTEGER, "1"); break; case opc_lconst_1: - emit(out, "var @1 = 1;", smapper.pushL()); + smapper.assign(this, VarType.LONG, "1"); break; case opc_fconst_1: - emit(out, "var @1 = 1;", smapper.pushF()); + smapper.assign(this, VarType.FLOAT, "1"); break; case opc_dconst_1: - emit(out, "var @1 = 1;", smapper.pushD()); + smapper.assign(this, VarType.DOUBLE, "1"); break; case opc_iconst_2: - emit(out, "var @1 = 2;", smapper.pushI()); + smapper.assign(this, VarType.INTEGER, "2"); break; case opc_fconst_2: - emit(out, "var @1 = 2;", smapper.pushF()); + smapper.assign(this, VarType.FLOAT, "2"); break; case opc_iconst_3: - emit(out, "var @1 = 3;", smapper.pushI()); + smapper.assign(this, VarType.INTEGER, "3"); break; case opc_iconst_4: - emit(out, "var @1 = 4;", smapper.pushI()); + smapper.assign(this, VarType.INTEGER, "4"); break; case opc_iconst_5: - emit(out, "var @1 = 5;", smapper.pushI()); + smapper.assign(this, VarType.INTEGER, "5"); break; case opc_ldc: { 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); + smapper.assign(this, type, v); break; } case opc_ldc_w: @@ -837,118 +895,122 @@ final Long lv = new Long(v); final int low = (int)(lv.longValue() & 0xFFFFFFFF); final int hi = (int)(lv.longValue() >> 32); - emit(out, "var @1 = 0x@3.next32(0x@2);", smapper.pushL(), - Integer.toHexString(low), Integer.toHexString(hi)); + if (hi == 0) { + smapper.assign(this, VarType.LONG, "0x" + Integer.toHexString(low)); + } else { + smapper.assign(this, VarType.LONG, + "0x" + Integer.toHexString(hi) + ".next32(0x" + + Integer.toHexString(low) + ")" + ); + } } else { - emit(out, "var @1 = @2;", smapper.pushT(type), v); + smapper.assign(this, type, v); } break; } case opc_lcmp: - emit(out, "var @3 = @2.compare64(@1);", - smapper.popL(), smapper.popL(), smapper.pushI()); + smapper.replace(this, VarType.INTEGER, "(@2).compare64(@1)", smapper.popL(), smapper.getL(0)); break; case opc_fcmpl: case opc_fcmpg: - emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", - smapper.popF(), smapper.popF(), smapper.pushI()); + smapper.replace(this, VarType.INTEGER, "(@2).compare(@1)", smapper.popF(), smapper.getF(0)); break; case opc_dcmpl: case opc_dcmpg: - emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", - smapper.popD(), smapper.popD(), smapper.pushI()); + smapper.replace(this, VarType.INTEGER, "(@2).compare(@1)", smapper.popD(), smapper.getD(0)); break; case opc_if_acmpeq: - i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(), + i = generateIf(smapper, byteCodes, i, smapper.popA(), smapper.popA(), "===", topMostLabel); break; case opc_if_acmpne: - i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(), + i = generateIf(smapper, byteCodes, i, smapper.popA(), smapper.popA(), "!==", topMostLabel); break; case opc_if_icmpeq: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), "==", topMostLabel); break; case opc_ifeq: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 == 0) ", + emitIf(smapper, this, "if ((@1) == 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifne: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 != 0) ", + emitIf(smapper, this, "if ((@1) != 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_iflt: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 < 0) ", + emitIf(smapper, this, "if ((@1) < 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifle: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 <= 0) ", + emitIf(smapper, this, "if ((@1) <= 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifgt: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 > 0) ", + emitIf(smapper, this, "if ((@1) > 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifge: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 >= 0) ", + emitIf(smapper, this, "if ((@1) >= 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifnonnull: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 !== null) ", + emitIf(smapper, this, "if ((@1) !== null) ", smapper.popA(), i, indx, topMostLabel); i += 2; break; } case opc_ifnull: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 === null) ", + emitIf(smapper, this, "if ((@1) === null) ", smapper.popA(), i, indx, topMostLabel); i += 2; break; } case opc_if_icmpne: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), "!=", topMostLabel); break; case opc_if_icmplt: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), "<", topMostLabel); break; case opc_if_icmple: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), "<=", topMostLabel); break; case opc_if_icmpgt: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), ">", topMostLabel); break; case opc_if_icmpge: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), ">=", topMostLabel); break; case opc_goto: { + smapper.flush(this); int indx = i + readShortArg(byteCodes, i); - goTo(out, i, indx, topMostLabel); + goTo(this, i, indx, topMostLabel); i += 2; break; } @@ -976,8 +1038,8 @@ case opc_new: { int indx = readUShortArg(byteCodes, i); String ci = jc.getClassName(indx); - emit(out, "var @1 = new @2;", - smapper.pushA(), accessClass(ci.replace('/', '_'))); + emit(smapper, this, "var @1 = new @2;", + smapper.pushA(), accessClass(mangleClassName(ci))); addReference(ci); i += 2; break; @@ -999,54 +1061,53 @@ break; } case opc_arraylength: - emit(out, "var @2 = @1.length;", - smapper.popA(), smapper.pushI()); + smapper.replace(this, VarType.INTEGER, "(@1).length", smapper.getA(0)); break; case opc_lastore: - emit(out, "Array.at(@3, @2, @1);", + emit(smapper, this, "Array.at(@3, @2, @1);", smapper.popL(), smapper.popI(), smapper.popA()); break; case opc_fastore: - emit(out, "Array.at(@3, @2, @1);", + emit(smapper, this, "Array.at(@3, @2, @1);", smapper.popF(), smapper.popI(), smapper.popA()); break; case opc_dastore: - emit(out, "Array.at(@3, @2, @1);", + emit(smapper, this, "Array.at(@3, @2, @1);", smapper.popD(), smapper.popI(), smapper.popA()); break; case opc_aastore: - emit(out, "Array.at(@3, @2, @1);", + emit(smapper, this, "Array.at(@3, @2, @1);", smapper.popA(), smapper.popI(), smapper.popA()); break; case opc_iastore: case opc_bastore: case opc_castore: case opc_sastore: - emit(out, "Array.at(@3, @2, @1);", + emit(smapper, this, "Array.at(@3, @2, @1);", smapper.popI(), smapper.popI(), smapper.popA()); break; case opc_laload: - emit(out, "var @3 = Array.at(@2, @1);", - smapper.popI(), smapper.popA(), smapper.pushL()); + smapper.replace(this, VarType.LONG, "Array.at(@2, @1)", + smapper.popI(), smapper.getA(0)); break; case opc_faload: - emit(out, "var @3 = Array.at(@2, @1);", - smapper.popI(), smapper.popA(), smapper.pushF()); + smapper.replace(this, VarType.FLOAT, "Array.at(@2, @1)", + smapper.popI(), smapper.getA(0)); break; case opc_daload: - emit(out, "var @3 = Array.at(@2, @1);", - smapper.popI(), smapper.popA(), smapper.pushD()); + smapper.replace(this, VarType.DOUBLE, "Array.at(@2, @1)", + smapper.popI(), smapper.getA(0)); break; case opc_aaload: - emit(out, "var @3 = Array.at(@2, @1);", - smapper.popI(), smapper.popA(), smapper.pushA()); + smapper.replace(this, VarType.REFERENCE, "Array.at(@2, @1)", + smapper.popI(), smapper.getA(0)); break; case opc_iaload: case opc_baload: case opc_caload: case opc_saload: - emit(out, "var @3 = Array.at(@2, @1);", - smapper.popI(), smapper.popA(), smapper.pushI()); + smapper.replace(this, VarType.INTEGER, "Array.at(@2, @1)", + smapper.popI(), smapper.getA(0)); break; case opc_pop: case opc_pop2: @@ -1055,86 +1116,86 @@ break; case opc_dup: { final Variable v = smapper.get(0); - emit(out, "var @1 = @2;", smapper.pushT(v.getType()), v); + emit(smapper, this, "var @1 = @2;", smapper.pushT(v.getType()), v); break; } case opc_dup2: { final Variable vi1 = smapper.get(0); if (vi1.isCategory2()) { - emit(out, "var @1 = @2;", + emit(smapper, this, "var @1 = @2;", smapper.pushT(vi1.getType()), vi1); } else { final Variable vi2 = smapper.get(1); - emit(out, "var @1 = @2, @3 = @4;", + emit(smapper, this, "var @1 = @2, @3 = @4;", smapper.pushT(vi2.getType()), vi2, smapper.pushT(vi1.getType()), vi1); } break; } case opc_dup_x1: { - final Variable vi1 = smapper.pop(); - final Variable vi2 = smapper.pop(); + final Variable vi1 = smapper.pop(this); + final Variable vi2 = smapper.pop(this); 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;", + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); break; } case opc_dup2_x1: { - final Variable vi1 = smapper.pop(); - final Variable vi2 = smapper.pop(); + final Variable vi1 = smapper.pop(this); + final Variable vi2 = smapper.pop(this); if (vi1.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;", + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); } else { - final Variable vi3 = smapper.pop(); + final Variable vi3 = smapper.pop(this); 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,", + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6,", vo1, vi1, vo2, vi2, vo3, vi3); - emit(out, " @1 = @2, @3 = @4;", + emit(smapper, this, " @1 = @2, @3 = @4;", vo4, vo1, vo5, vo2); } break; } case opc_dup_x2: { - final Variable vi1 = smapper.pop(); - final Variable vi2 = smapper.pop(); + final Variable vi1 = smapper.pop(this); + final Variable vi2 = smapper.pop(this); 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;", + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); } else { - final Variable vi3 = smapper.pop(); + final Variable vi3 = smapper.pop(this); 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;", + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1); } break; } case opc_dup2_x2: { - final Variable vi1 = smapper.pop(); - final Variable vi2 = smapper.pop(); + final Variable vi1 = smapper.pop(this); + final Variable vi2 = smapper.pop(this); if (vi1.isCategory2()) { if (vi2.isCategory2()) { @@ -1142,20 +1203,20 @@ final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @3 = @4, @5 = @6;", + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); } else { - final Variable vi3 = smapper.pop(); + final Variable vi3 = smapper.pop(this); 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;", + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1); } } else { - final Variable vi3 = smapper.pop(); + final Variable vi3 = smapper.pop(this); if (vi3.isCategory2()) { final Variable vo5 = smapper.pushT(vi2.getType()); @@ -1164,12 +1225,12 @@ final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @3 = @4, @5 = @6,", + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6,", vo1, vi1, vo2, vi2, vo3, vi3); - emit(out, " @1 = @2, @3 = @4;", + emit(smapper, this, " @1 = @2, @3 = @4;", vo4, vo1, vo5, vo2); } else { - final Variable vi4 = smapper.pop(); + final Variable vi4 = smapper.pop(this); final Variable vo6 = smapper.pushT(vi2.getType()); final Variable vo5 = smapper.pushT(vi1.getType()); final Variable vo4 = smapper.pushT(vi4.getType()); @@ -1177,9 +1238,9 @@ 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,", + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8,", vo1, vi1, vo2, vi2, vo3, vi3, vo4, vi4); - emit(out, " @1 = @2, @3 = @4;", + emit(smapper, this, " @1 = @2, @3 = @4;", vo5, vo1, vo6, vo2); } } @@ -1192,7 +1253,7 @@ if (vi1.getType() == vi2.getType()) { final Variable tmp = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @2 = @3, @3 = @1;", + emit(smapper, this, "var @1 = @2, @2 = @3, @3 = @1;", tmp, vi1, vi2); smapper.pop(1); } else { @@ -1203,26 +1264,26 @@ break; } case opc_bipush: - emit(out, "var @1 = @2;", - smapper.pushI(), Integer.toString(byteCodes[++i])); + smapper.assign(this, VarType.INTEGER, + "(" + Integer.toString(byteCodes[++i]) + ")"); break; case opc_sipush: - emit(out, "var @1 = @2;", - smapper.pushI(), - Integer.toString(readShortArg(byteCodes, i))); + smapper.assign(this, VarType.INTEGER, + "(" + Integer.toString(readShortArg(byteCodes, i)) + ")" + ); i += 2; break; case opc_getfield: { int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); - final String mangleClass = mangleSig(fi[0]); + final String mangleClass = mangleClassName(fi[0]); final String mangleClassAccess = accessClass(mangleClass); - emit(out, "var @2 = @3.call(@1);", - smapper.popA(), - smapper.pushT(type), + smapper.replace(this, type, "@2.call(@1)", + smapper.getA(0), accessField(mangleClassAccess + "(false)", - "_" + fi[1], fi)); + "_" + fi[1], fi) + ); i += 2; break; } @@ -1230,9 +1291,9 @@ int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); - final String mangleClass = mangleSig(fi[0]); + final String mangleClass = mangleClassName(fi[0]); final String mangleClassAccess = accessClass(mangleClass); - emit(out, "@3.call(@2, @1);", + emit(smapper, this, "@3.call(@2, @1);", smapper.popT(type), smapper.popA(), accessField(mangleClassAccess + "(false)", @@ -1244,11 +1305,8 @@ int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); - emit(out, "var @1 = @2();", - smapper.pushT(type), - accessField(accessClass(fi[0].replace('/', '_')) - + "(false)", - "_" + fi[1], fi)); + String ac = accessClass(mangleClassName(fi[0])); + smapper.assign(this, type, ac + "(false)._" + fi[1] + "()"); i += 2; addReference(fi[0]); break; @@ -1257,10 +1315,8 @@ int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); - emit(out, "@1(@2);", - accessField(accessClass(fi[0].replace('/', '_')) - + "(false)", - "_" + fi[1], fi), + emit(smapper, this, "@1(false)._@2(@3);", + accessClass(mangleClassName(fi[0])), fi[1], smapper.popT(type)); i += 2; addReference(fi[0]); @@ -1279,22 +1335,22 @@ break; } case opc_athrow: { - final Variable v = smapper.popA(); + final CharSequence v = smapper.popA(); smapper.clear(); - emit(out, "{ var @1 = @2; throw @2; }", + emit(smapper, this, "{ var @1 = @2; throw @2; }", smapper.pushA(), v); break; } case opc_monitorenter: { - out.append("/* monitor enter */"); + debug("/* monitor enter */"); smapper.popA(); break; } case opc_monitorexit: { - out.append("/* monitor exit */"); + debug("/* monitor exit */"); smapper.popA(); break; } @@ -1305,31 +1361,39 @@ default: { wide = false; - emit(out, "throw 'unknown bytecode @1';", + emit(smapper, this, "throw 'unknown bytecode @1';", Integer.toString(c)); } } if (debug(" //")) { generateByteCodeComment(prev, i, byteCodes); } - out.append("\n"); + if (outChanged) { + append("\n"); + } } if (previousTrap != null) { generateCatch(previousTrap, byteCodes.length, topMostLabel); } - out.append("\n }\n"); + if (didBranches) { + append("\n }\n"); + } while (openBraces-- > 0) { - out.append('}'); + append('}'); } - out.append("\n};"); + append("\n};"); } - private int generateIf(byte[] byteCodes, int i, final Variable v2, final Variable v1, final String test, int topMostLabel) throws IOException { + private int generateIf(StackMapper mapper, byte[] byteCodes, + int i, final CharSequence v2, final CharSequence v1, + final String test, int topMostLabel + ) throws IOException { + mapper.flush(this); int indx = i + readShortArg(byteCodes, i); - out.append("if (").append(v1) - .append(' ').append(test).append(' ') - .append(v2).append(") "); - goTo(out, i, indx, topMostLabel); + append("if ((").append(v1) + .append(") ").append(test).append(" (") + .append(v2).append(")) "); + goTo(this, i, indx, topMostLabel); return i + 2; } @@ -1442,8 +1506,20 @@ return mangleSig(sig, 0, sig.length()); } + private static String mangleMethodName(String name) { + StringBuilder sb = new StringBuilder(name.length() * 2); + int last = name.length(); + for (int i = 0; i < last; i++) { + final char ch = name.charAt(i); + switch (ch) { + case '_': sb.append("_1"); break; + default: sb.append(ch); break; + } + } + return sb.toString(); + } private static String mangleSig(String txt, int first, int last) { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder((last - first) * 2); for (int i = first; i < last; i++) { final char ch = txt.charAt(i); switch (ch) { @@ -1456,6 +1532,10 @@ } return sb.toString(); } + + private static String mangleClassName(String name) { + return mangleSig(name); + } private static String findMethodName(MethodData m, StringBuilder cnt) { StringBuilder name = new StringBuilder(); @@ -1464,7 +1544,7 @@ } else if ("".equals(m.getName())) { // NOI18N name.append("class"); // NOI18N } else { - name.append(m.getName()); + name.append(mangleMethodName(m.getName())); } countArgs(m.getInternalSig(), new char[1], name, cnt); @@ -1478,7 +1558,7 @@ if ("".equals(nm)) { // NOI18N name.append("cons"); // NOI18N } else { - name.append(nm); + name.append(mangleMethodName(nm)); } countArgs(descr, returnType, name, cnt); return name.toString(); @@ -1493,14 +1573,14 @@ String mn = findMethodName(mi, cnt, returnType); final int numArguments = isStatic ? cnt.length() : cnt.length() + 1; - final Variable[] vars = new Variable[numArguments]; + final CharSequence[] vars = new CharSequence[numArguments]; for (int j = numArguments - 1; j >= 0; --j) { - vars[j] = mapper.pop(); + vars[j] = mapper.popValue(); } if (returnType[0] != 'V') { - out.append("var ") + append("var ") .append(mapper.pushT(VarType.fromFieldType(returnType[0]))) .append(" = "); } @@ -1510,20 +1590,20 @@ if (mn.startsWith("cons_")) { object += ".constructor"; } - out.append(accessStaticMethod(object, mn, mi)); + append(accessStaticMethod(object, mn, mi)); if (isStatic) { - out.append('('); + append('('); } else { - out.append(".call("); + append(".call("); } if (numArguments > 0) { - out.append(vars[0]); + append(vars[0]); for (int j = 1; j < numArguments; ++j) { - out.append(", "); - out.append(vars[j]); + append(", "); + append(vars[j]); } } - out.append(");"); + append(");"); i += 2; addReference(in); return i; @@ -1537,27 +1617,27 @@ String mn = findMethodName(mi, cnt, returnType); final int numArguments = cnt.length() + 1; - final Variable[] vars = new Variable[numArguments]; + final CharSequence[] vars = new CharSequence[numArguments]; for (int j = numArguments - 1; j >= 0; --j) { - vars[j] = mapper.pop(); + vars[j] = mapper.popValue(); } if (returnType[0] != 'V') { - out.append("var ") + append("var ") .append(mapper.pushT(VarType.fromFieldType(returnType[0]))) .append(" = "); } - out.append(accessVirtualMethod(vars[0].toString(), mn, mi)); - out.append('('); + append(accessVirtualMethod(vars[0].toString(), mn, mi)); + append('('); String sep = ""; for (int j = 1; j < numArguments; ++j) { - out.append(sep); - out.append(vars[j]); + append(sep); + append(vars[j]); sep = ", "; } - out.append(");"); + append(");"); i += 2; return i; } @@ -1587,10 +1667,10 @@ String s = jc.stringValue(entryIndex, classRef); if (classRef[0] != null) { if (classRef[0].startsWith("[")) { - s = accessClass("java_lang_Class") + "(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('" + classRef[0] + "');"; + 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"; + s = accessClass(mangleClassName(s)) + "(false).constructor.$class"; } } return s; @@ -1602,6 +1682,7 @@ return null; } final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;"; + final String htmlType = "Lnet/java/html/js/JavaScriptBody;"; class P extends AnnotationParser { public P() { super(false, true); @@ -1610,6 +1691,8 @@ int cnt; String[] args = new String[30]; String body; + boolean javacall; + boolean html4j; @Override protected void visitAttr(String type, String attr, String at, String value) { @@ -1622,6 +1705,18 @@ throw new IllegalArgumentException(attr); } } + if (type.equals(htmlType)) { + html4j = true; + if ("body".equals(attr)) { + body = value; + } else if ("args".equals(attr)) { + args[cnt++] = value; + } else if ("javacall".equals(attr)) { + javacall = "1".equals(value); + } else { + throw new IllegalArgumentException(attr); + } + } } } P p = new P(); @@ -1631,23 +1726,153 @@ } StringBuilder cnt = new StringBuilder(); final String mn = findMethodName(m, cnt); - out.append(destObject).append(".").append(mn); - out.append(" = function("); + append(destObject).append(".").append(mn); + append(" = function("); String space = ""; int index = 0; + StringBuilder toValue = new StringBuilder(); for (int i = 0; i < cnt.length(); i++) { - out.append(space); - space = outputArg(out, p.args, index); + append(space); + space = outputArg(this, p.args, index); + if (p.html4j && space.length() > 0) { + toValue.append("\n ").append(p.args[index]).append(" = vm.org_apidesign_bck2brwsr_emul_lang_System(false).toJS("). + append(p.args[index]).append(");"); + } index++; } - out.append(") {").append("\n"); - out.append(p.body); - out.append("\n}\n"); + append(") {").append("\n"); + append(toValue.toString()); + if (p.javacall) { + int lastSlash = jc.getClassName().lastIndexOf('/'); + final String pkg = jc.getClassName().substring(0, lastSlash); + append(mangleCallbacks(pkg, p.body)); + requireReference(pkg + "/$JsCallbacks$"); + } else { + append(p.body); + } + append("\n}\n"); return mn; } + + private static CharSequence mangleCallbacks(String pkgName, String body) { + StringBuilder sb = new StringBuilder(); + int pos = 0; + for (;;) { + int next = body.indexOf(".@", pos); + if (next == -1) { + sb.append(body.substring(pos)); + body = sb.toString(); + break; + } + int ident = next; + while (ident > 0) { + if (!Character.isJavaIdentifierPart(body.charAt(--ident))) { + ident++; + break; + } + } + String refId = body.substring(ident, next); + + sb.append(body.substring(pos, ident)); + + int sigBeg = body.indexOf('(', next); + int sigEnd = body.indexOf(')', sigBeg); + int colon4 = body.indexOf("::", next); + if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) { + throw new IllegalStateException("Malformed body " + body); + } + String fqn = body.substring(next + 2, colon4); + String method = body.substring(colon4 + 2, sigBeg); + String params = body.substring(sigBeg, sigEnd + 1); + + int paramBeg = body.indexOf('(', sigEnd + 1); + + sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM()."); + sb.append(mangleJsCallbacks(fqn, method, params, false)); + sb.append("(").append(refId); + if (body.charAt(paramBeg + 1) != ')') { + sb.append(","); + } + pos = paramBeg + 1; + } + sb = null; + pos = 0; + for (;;) { + int next = body.indexOf("@", pos); + if (next == -1) { + if (sb == null) { + return body; + } + sb.append(body.substring(pos)); + return sb; + } + if (sb == null) { + sb = new StringBuilder(); + } + + sb.append(body.substring(pos, next)); + + int sigBeg = body.indexOf('(', next); + int sigEnd = body.indexOf(')', sigBeg); + int colon4 = body.indexOf("::", next); + if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) { + throw new IllegalStateException("Malformed body " + body); + } + String fqn = body.substring(next + 1, colon4); + String method = body.substring(colon4 + 2, sigBeg); + String params = body.substring(sigBeg, sigEnd + 1); + + int paramBeg = body.indexOf('(', sigEnd + 1); + + sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM()."); + sb.append(mangleJsCallbacks(fqn, method, params, true)); + sb.append("("); + pos = paramBeg + 1; + } + } + + static String mangleJsCallbacks(String fqn, String method, String params, boolean isStatic) { + if (params.startsWith("(")) { + params = params.substring(1); + } + if (params.endsWith(")")) { + params = params.substring(0, params.length() - 1); + } + StringBuilder sb = new StringBuilder(); + final String fqnu = fqn.replace('.', '_'); + final String rfqn = mangleClassName(fqnu); + final String rm = mangleMethodName(method); + final String srp; + { + StringBuilder pb = new StringBuilder(); + int len = params.length(); + int indx = 0; + while (indx < len) { + char ch = params.charAt(indx); + if (ch == '[' || ch == 'L') { + pb.append("Ljava/lang/Object;"); + indx = params.indexOf(';', indx) + 1; + } else { + pb.append(ch); + indx++; + } + } + srp = mangleSig(pb.toString()); + } + final String rp = mangleSig(params); + final String mrp = mangleMethodName(rp); + sb.append(rfqn).append("$").append(rm). + append('$').append(mrp).append("__Ljava_lang_Object_2"); + if (!isStatic) { + sb.append('L').append(fqnu).append("_2"); + } + sb.append(srp); + return sb.toString(); + } + private static String className(ClassData jc) { //return jc.getName().getInternalName().replace('/', '_'); - return jc.getClassName().replace('/', '_'); + return mangleClassName(jc.getClassName()); } private static String[] findAnnotation( @@ -1697,7 +1922,7 @@ return " = null;"; } - private void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException { + private void generateAnno(ClassData cd, byte[] data) throws IOException { AnnotationParser ap = new AnnotationParser(true, false) { int[] cnt = new int[32]; int depth; @@ -1708,39 +1933,39 @@ requireReference(slashType); if (cnt[depth]++ > 0) { - out.append(","); + append(","); } if (top) { - out.append('"').append(attrType).append("\" : "); + append('"').append(attrType).append("\" : "); } - out.append("{\n"); + append("{\n"); cnt[++depth] = 0; } @Override protected void visitAnnotationEnd(String type, boolean top) throws IOException { - out.append("\n}\n"); + append("\n}\n"); depth--; } @Override protected void visitValueStart(String attrName, char type) throws IOException { if (cnt[depth]++ > 0) { - out.append(",\n"); + append(",\n"); } cnt[++depth] = 0; if (attrName != null) { - out.append(attrName).append(" : "); + append(attrName).append(" : "); } if (type == '[') { - out.append("["); + append("["); } } @Override protected void visitValueEnd(String attrName, char type) throws IOException { if (type == '[') { - out.append("]"); + append("]"); } depth--; } @@ -1751,7 +1976,7 @@ if (attr == null && value == null) { return; } - out.append(value); + append(value); } @Override @@ -1760,8 +1985,8 @@ final String slashType = attrType.substring(1, attrType.length() - 1); requireReference(slashType); - out.append(accessClass(slashType.replace('/', '_'))) - .append("(false).constructor.").append(value); + append(accessClass(mangleClassName(slashType))) + .append("(false).constructor.fld_").append(value); } }; ap.parse(data, cd); @@ -1779,7 +2004,21 @@ return ","; } - private static void emit(final Appendable out, + final void emitNoFlush( + StackMapper sm, + final String format, final CharSequence... params + ) throws IOException { + emitImpl(this, format, params); + } + static final void emit( + StackMapper sm, + final Appendable out, + final String format, final CharSequence... params + ) throws IOException { + sm.flush(out); + emitImpl(out, format, params); + } + static void emitImpl(final Appendable out, final String format, final CharSequence... params) throws IOException { final int length = format.length(); @@ -1805,7 +2044,7 @@ } private void generateCatch(TrapData[] traps, int current, int topMostLabel) throws IOException { - out.append("} catch (e) {\n"); + append("} catch (e) {\n"); int finallyPC = -1; for (TrapData e : traps) { if (e == null) { @@ -1814,22 +2053,22 @@ if (e.catch_cpx != 0) { //not finally final String classInternalName = jc.getClassName(e.catch_cpx); addReference(classInternalName); - out.append("e = vm.java_lang_Throwable(false).bck2BrwsrCnvrt(e);"); - out.append("if (e['$instOf_" + classInternalName.replace('/', '_') + "']) {"); - out.append("var stA0 = e;"); - goTo(out, current, e.handler_pc, topMostLabel); - out.append("}\n"); + append("e = vm.java_lang_Throwable(false).bck2BrwsrCnvrt(e);"); + append("if (e['$instOf_" + classInternalName.replace('/', '_') + "']) {"); + append("var stA0 = e;"); + goTo(this, current, e.handler_pc, topMostLabel); + append("}\n"); } else { finallyPC = e.handler_pc; } } if (finallyPC == -1) { - out.append("throw e;"); + append("throw e;"); } else { - out.append("var stA0 = e;"); - goTo(out, current, finallyPC, topMostLabel); + append("var stA0 = e;"); + goTo(this, current, finallyPC, topMostLabel); } - out.append("\n}"); + append("\n}"); } private static void goTo(Appendable out, int current, int to, int canBack) throws IOException { @@ -1845,10 +2084,13 @@ } private static void emitIf( - Appendable out, String pattern, Variable param, + StackMapper sm, + Appendable out, String pattern, + CharSequence param, int current, int to, int canBack ) throws IOException { - emit(out, pattern, param); + sm.flush(out); + emitImpl(out, pattern, param); goTo(out, current, to, canBack); } @@ -1865,7 +2107,8 @@ case 11: jvmType = "[J"; break; default: throw new IllegalStateException("Array type: " + atype); } - emit(out, "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](true, '@3', @1);", + emit(smapper, this, + "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](true, '@3', @1);", smapper.popI(), smapper.pushA(), jvmType); } @@ -1876,7 +2119,8 @@ } else { typeName = "[L" + typeName + ";"; } - emit(out, "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](false, '@3', @1);", + emit(smapper, this, + "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](false, '@3', @1);", smapper.popI(), smapper.pushA(), typeName); } @@ -1892,7 +2136,8 @@ dims.insert(1, smapper.popI()); } dims.append(']'); - emit(out, "var @2 = Array.prototype['multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II']('@3', @1, 0);", + emit(smapper, this, + "var @2 = Array.prototype['multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II']('@3', @1, 0);", dims.toString(), smapper.pushA(), typeName); return i; } @@ -1905,16 +2150,18 @@ table += 4; int high = readInt4(byteCodes, table); table += 4; - out.append("switch (").append(smapper.popI()).append(") {\n"); + final CharSequence swVar = smapper.popValue(); + smapper.flush(this); + append("switch (").append(swVar).append(") {\n"); while (low <= high) { int offset = i + readInt4(byteCodes, table); table += 4; - out.append(" case " + low).append(":"); goTo(out, i, offset, topMostLabel); out.append('\n'); + append(" case " + low).append(":"); goTo(this, i, offset, topMostLabel); append('\n'); low++; } - out.append(" default: "); - goTo(out, i, dflt, topMostLabel); - out.append("\n}"); + append(" default: "); + goTo(this, i, dflt, topMostLabel); + append("\n}"); i = table - 1; return i; } @@ -1925,17 +2172,19 @@ table += 4; int n = readInt4(byteCodes, table); table += 4; - out.append("switch (").append(smapper.popI()).append(") {\n"); + final CharSequence swVar = smapper.popValue(); + smapper.flush(this); + append("switch (").append(swVar).append(") {\n"); while (n-- > 0) { int cnstnt = readInt4(byteCodes, table); table += 4; int offset = i + readInt4(byteCodes, table); table += 4; - out.append(" case " + cnstnt).append(": "); goTo(out, i, offset, topMostLabel); out.append('\n'); + append(" case " + cnstnt).append(": "); goTo(this, i, offset, topMostLabel); append('\n'); } - out.append(" default: "); - goTo(out, i, dflt, topMostLabel); - out.append("\n}"); + append(" default: "); + goTo(this, i, dflt, topMostLabel); + append("\n}"); i = table - 1; return i; } @@ -1943,11 +2192,13 @@ private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException { final String type = jc.getClassName(indx); if (!type.startsWith("[")) { - emit(out, "var @2 = @1 != null && @1['$instOf_@3'] ? 1 : 0;", + emit(smapper, this, + "var @2 = @1 != null && @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);", + 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 ); @@ -1957,21 +2208,22 @@ private void generateCheckcast(int indx, final StackMapper smapper) throws IOException { final String type = jc.getClassName(indx); if (!type.startsWith("[")) { - emit(out, + emitNoFlush(smapper, "if (@1 !== null && !@1['$instOf_@2']) throw vm.java_lang_ClassCastException(true);", - smapper.getA(0), type.replace('/', '_')); + smapper.getT(0, VarType.REFERENCE, false), 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 + 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 ); } } private void generateByteCodeComment(int prev, int i, final byte[] byteCodes) throws IOException { for (int j = prev; j <= i; j++) { - out.append(" "); + append(" "); final int cc = readUByte(byteCodes, j); - out.append(Integer.toString(cc)); + append(Integer.toString(cc)); } } }