jaroslav@106: /** jaroslav@106: * Back 2 Browser Bytecode Translator jaroslav@106: * Copyright (C) 2012 Jaroslav Tulach jaroslav@106: * jaroslav@106: * This program is free software: you can redistribute it and/or modify jaroslav@106: * it under the terms of the GNU General Public License as published by jaroslav@106: * the Free Software Foundation, version 2 of the License. jaroslav@106: * jaroslav@106: * This program is distributed in the hope that it will be useful, jaroslav@106: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@106: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@106: * GNU General Public License for more details. jaroslav@106: * jaroslav@106: * You should have received a copy of the GNU General Public License jaroslav@106: * along with this program. Look for COPYING file in the top folder. jaroslav@106: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@106: */ jaroslav@22: package org.apidesign.vm4brwsr; jaroslav@0: jaroslav@0: import java.io.IOException; jaroslav@0: import java.io.InputStream; jaroslav@1547: import java.util.Locale; jaroslav@810: import static org.apidesign.vm4brwsr.ByteCodeParser.*; jaroslav@0: jaroslav@0: /** Translator of the code inside class files to JavaScript. jaroslav@0: * jaroslav@0: * @author Jaroslav Tulach jaroslav@0: */ jaroslav@1509: abstract class ByteCodeToJavaScript implements Appendable { jtulach@162: private ClassData jc; jaroslav@1509: private final Appendable out; jaroslav@1509: private boolean outChanged; jaroslav@1515: private boolean callbacks; jaroslav@0: jtulach@162: protected ByteCodeToJavaScript(Appendable out) { jaroslav@0: this.out = out; jaroslav@0: } jtulach@162: jaroslav@1509: @Override jaroslav@1509: public final Appendable append(CharSequence csq) throws IOException { jaroslav@1509: out.append(csq); jaroslav@1509: outChanged = true; jaroslav@1509: return this; jaroslav@1509: } jaroslav@1509: jaroslav@1509: @Override jaroslav@1509: public final Appendable append(CharSequence csq, int start, int end) throws IOException { jaroslav@1509: out.append(csq, start, end); jaroslav@1509: outChanged = true; jaroslav@1509: return this; jaroslav@1509: } jaroslav@1509: jaroslav@1509: @Override jaroslav@1509: public final Appendable append(char c) throws IOException { jaroslav@1509: out.append(c); jaroslav@1509: outChanged = true; jaroslav@1509: return this; jaroslav@1509: } jaroslav@1509: jtulach@162: /* Collects additional required resources. jtulach@162: * jtulach@162: * @param internalClassName classes that were referenced and should be loaded in order the jtulach@162: * generated JavaScript code works properly. The names are in internal jtulach@162: * JVM form so String is java/lang/String. jtulach@162: */ jtulach@162: protected abstract boolean requireReference(String internalClassName); jtulach@162: jtulach@162: /* jtulach@162: * @param resourcePath name of resources to read jtulach@162: */ jaroslav@503: protected abstract void requireScript(String resourcePath) throws IOException; jaroslav@213: jaroslav@213: /** Allows subclasses to redefine what field a function representing a jaroslav@213: * class gets assigned. By default it returns the suggested name followed jaroslav@213: * by " = "; jaroslav@213: * jaroslav@213: * @param className suggested name of the class jaroslav@213: */ jaroslav@274: /* protected */ String assignClass(String className) { jaroslav@213: return className + " = "; jaroslav@213: } jaroslav@274: /* protected */ String accessClass(String classOperation) { jaroslav@274: return classOperation; jaroslav@274: } lubomir@869: lubomir@1085: protected String accessField(String object, String mangledName, lubomir@1085: String[] fieldInfoName) throws IOException { lubomir@1085: return object + "." + mangledName; lubomir@1085: } lubomir@1085: lubomir@1085: protected String accessStaticMethod( lubomir@1085: String object, lubomir@1085: String mangledName, lubomir@1085: String[] fieldInfoName) throws IOException { lubomir@1085: return object + "." + mangledName; lubomir@1085: } lubomir@1085: lubomir@1085: protected String accessVirtualMethod( lubomir@1085: String object, lubomir@1085: String mangledName, lubomir@1085: String[] fieldInfoName) throws IOException { lubomir@1084: return object + "." + mangledName; lubomir@1084: } lubomir@1084: lubomir@1029: protected void declaredClass(ClassData classData, String mangledName) lubomir@1029: throws IOException { lubomir@1029: } jaroslav@962: lubomir@1083: protected void declaredField(FieldData fieldData, lubomir@1083: String destObject, lubomir@1083: String mangledName) throws IOException { lubomir@1083: } lubomir@1083: lubomir@1083: protected void declaredMethod(MethodData methodData, lubomir@1083: String destObject, lubomir@1083: String mangledName) throws IOException { lubomir@1083: } lubomir@869: jaroslav@399: /** Prints out a debug message. jaroslav@399: * jaroslav@399: * @param msg the message jaroslav@399: * @return true if the message has been printed jaroslav@399: * @throws IOException jaroslav@399: */ jaroslav@399: boolean debug(String msg) throws IOException { jaroslav@1509: append(msg); jaroslav@399: return true; jaroslav@399: } jaroslav@18: jaroslav@18: /** jaroslav@18: * Converts a given class file to a JavaScript version. jaroslav@18: * jaroslav@0: * @param classFile input stream with code of the .class file jaroslav@97: * @return the initialization code for this class, if any. Otherwise null jaroslav@91: * jaroslav@0: * @throws IOException if something goes wrong during read or write or translating jaroslav@0: */ jaroslav@18: jtulach@162: public String compile(InputStream classFile) throws IOException { lubomir@1084: return compile(new ClassData(classFile)); lubomir@1084: } lubomir@1084: lubomir@1084: protected String compile(ClassData classData) throws IOException { lubomir@1084: this.jc = classData; jaroslav@1515: this.callbacks = this.jc.getClassName().endsWith("/$JsCallbacks$"); jaroslav@324: if (jc.getMajor_version() < 50) { jaroslav@324: throw new IOException("Can't compile " + jc.getClassName() + ". Class file version " + jc.getMajor_version() + "." jaroslav@324: + jc.getMinor_version() + " - recompile with -target 1.6 (at least)." jaroslav@324: ); jaroslav@324: } jaroslav@152: byte[] arrData = jc.findAnnotationData(true); jaroslav@1239: { jaroslav@1239: String[] arr = findAnnotation(arrData, jc, jaroslav@1239: "org.apidesign.bck2brwsr.core.ExtraJavaScript", jaroslav@1239: "resource", "processByteCode" jaroslav@1239: ); jaroslav@1239: if (arr != null) { jaroslav@1239: if (!arr[0].isEmpty()) { jaroslav@1239: requireScript(arr[0]); jaroslav@1239: } jaroslav@1239: if ("0".equals(arr[1])) { jaroslav@1239: return null; jaroslav@1239: } lubomir@848: } jaroslav@1239: } jaroslav@1239: { jaroslav@1239: String[] arr = findAnnotation(arrData, jc, jaroslav@1239: "net.java.html.js.JavaScriptResource", jaroslav@1239: "value" jaroslav@1239: ); jaroslav@1239: if (arr != null) { jaroslav@1239: if (arr[0].startsWith("/")) { jaroslav@1239: requireScript(arr[0]); jaroslav@1239: } else { jaroslav@1239: int last = jc.getClassName().lastIndexOf('/'); jaroslav@1239: requireScript( jaroslav@1239: jc.getClassName().substring(0, last + 1).replace('.', '/') + arr[0] jaroslav@1239: ); jaroslav@1239: } jaroslav@91: } jaroslav@91: } jaroslav@239: String[] proto = findAnnotation(arrData, jc, jaroslav@239: "org.apidesign.bck2brwsr.core.JavaScriptPrototype", jaroslav@239: "container", "prototype" jaroslav@239: ); jtulach@162: StringArray toInitilize = new StringArray(); jaroslav@151: final String className = className(jc); jaroslav@1509: append("\n\n").append(assignClass(className)); jaroslav@1509: append("function ").append(className).append("() {"); jaroslav@1509: append("\n var CLS = ").append(className).append(';'); jaroslav@1509: append("\n if (!CLS.$class) {"); jaroslav@239: if (proto == null) { jaroslav@239: String sc = jc.getSuperClassName(); // with _ jaroslav@1509: append("\n var pp = "). jaroslav@1409: append(accessClass(mangleClassName(sc))).append("(true);"); jaroslav@1509: append("\n var p = CLS.prototype = pp;"); jaroslav@1509: append("\n var c = p;"); jaroslav@1509: append("\n var sprcls = pp.constructor.$class;"); jtulach@130: } else { jaroslav@1509: append("\n var p = CLS.prototype = ").append(proto[1]).append(";"); jaroslav@316: if (proto[0] == null) { jaroslav@316: proto[0] = "p"; jaroslav@316: } jaroslav@1509: append("\n var c = ").append(proto[0]).append(";"); jaroslav@1509: append("\n var sprcls = null;"); jaroslav@13: } jaroslav@592: for (FieldData v : jc.getFields()) { jaroslav@592: if (v.isStatic()) { jaroslav@1474: if ((v.access & ACC_FINAL) != 0 && v.hasConstantValue()) { jaroslav@1474: if (v.getInternalSig().length() == 1 || v.getInternalSig().equals("Ljava/lang/String;")) { jaroslav@1472: continue; jaroslav@1472: } jaroslav@1472: } jaroslav@1509: append("\n CLS.fld_").append(v.getName()).append(initField(v)); jaroslav@1509: append("\n c._").append(v.getName()).append(" = function (v) {") jaroslav@1353: .append(" if (arguments.length == 1) CLS.fld_").append(v.getName()) jaroslav@1353: .append(" = v; return CLS.fld_"). jaroslav@775: append(v.getName()).append("; };"); jaroslav@592: } else { jaroslav@1509: append("\n c._").append(v.getName()).append(" = function (v) {") jaroslav@592: .append(" if (arguments.length == 1) this.fld_"). jaroslav@592: append(className).append('_').append(v.getName()) jaroslav@592: .append(" = v; return this.fld_"). jaroslav@592: append(className).append('_').append(v.getName()) jaroslav@592: .append("; };"); jaroslav@592: } lubomir@869: lubomir@1083: declaredField(v, "c", "_" + v.getName()); jaroslav@592: } jaroslav@151: for (MethodData m : jc.getMethods()) { jaroslav@240: byte[] onlyArr = m.findAnnotationData(true); jaroslav@1586: if (javaScriptOnly(onlyArr)) continue; lubomir@869: String destObject; jaroslav@266: String mn; jaroslav@1509: append("\n "); jaroslav@203: if (m.isStatic()) { lubomir@869: destObject = "c"; lubomir@869: mn = generateStaticMethod(destObject, m, toInitilize); jaroslav@203: } else { jaroslav@397: if (m.isConstructor()) { lubomir@869: destObject = "CLS"; lubomir@869: mn = generateInstanceMethod(destObject, m); jaroslav@397: } else { lubomir@869: destObject = "c"; lubomir@869: mn = generateInstanceMethod(destObject, m); jaroslav@397: } jaroslav@266: } lubomir@1083: declaredMethod(m, destObject, mn); jaroslav@266: byte[] runAnno = m.findAnnotationData(false); jaroslav@266: if (runAnno != null) { jaroslav@1509: append("\n ").append(destObject).append(".").append(mn).append(".anno = {"); jaroslav@1509: generateAnno(jc, runAnno); jaroslav@1509: append("\n };"); jaroslav@38: } jaroslav@1509: append("\n ").append(destObject).append(".").append(mn).append(".access = " + m.getAccess()).append(";"); jaroslav@1509: append("\n ").append(destObject).append(".").append(mn).append(".cls = CLS;"); jaroslav@38: } jaroslav@1509: append("\n c.constructor = CLS;"); jaroslav@1509: append("\n function fillInstOf(x) {"); lubomir@869: String instOfName = "$instOf_" + className; jaroslav@1513: append("\n x['").append(instOfName).append("'] = true;"); jaroslav@1256: for (String superInterface : jc.getSuperInterfaces()) { jaroslav@1256: String intrfc = superInterface.replace('/', '_'); jaroslav@1513: append("\n vm.").append(intrfc).append("(false)['fillInstOf'](x);"); jaroslav@1256: requireReference(superInterface); jaroslav@1256: } jaroslav@1509: append("\n }"); jaroslav@1513: append("\n c['fillInstOf'] = fillInstOf;"); jaroslav@1509: append("\n fillInstOf(c);"); jaroslav@1513: // obfuscationDelegate.exportJSProperty(this, "c", instOfName); jaroslav@1509: append("\n CLS.$class = 'temp';"); jaroslav@1509: append("\n CLS.$class = "); jaroslav@1509: append(accessClass("java_lang_Class(true);")); jaroslav@1509: append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';"); jaroslav@1509: append("\n CLS.$class.superclass = sprcls;"); jaroslav@1509: append("\n CLS.$class.access = ").append(jc.getAccessFlags()+";"); jaroslav@1509: append("\n CLS.$class.cnstr = CLS;"); jaroslav@235: byte[] classAnno = jc.findAnnotationData(false); jaroslav@235: if (classAnno != null) { jaroslav@1509: append("\n CLS.$class.anno = {"); jaroslav@1509: generateAnno(jc, classAnno); jaroslav@1509: append("\n };"); jaroslav@235: } jaroslav@834: for (String init : toInitilize.toArray()) { jaroslav@1509: append("\n ").append(init).append("();"); jaroslav@834: } jaroslav@1509: append("\n }"); jaroslav@1509: append("\n if (arguments.length === 0) {"); jaroslav@1509: append("\n if (!(this instanceof CLS)) {"); jaroslav@1509: append("\n return new CLS();"); jaroslav@1509: append("\n }"); jaroslav@205: for (FieldData v : jc.getFields()) { jaroslav@240: byte[] onlyArr = v.findAnnotationData(true); jaroslav@1586: if (javaScriptOnly(onlyArr)) continue; jaroslav@205: if (!v.isStatic()) { jaroslav@1509: append("\n this.fld_"). jaroslav@592: append(className).append('_'). jaroslav@205: append(v.getName()).append(initField(v)); jaroslav@205: } jaroslav@205: } jaroslav@1509: append("\n return this;"); jaroslav@1509: append("\n }"); jaroslav@1509: append("\n return arguments[0] ? new CLS() : CLS.prototype;"); jaroslav@1509: append("\n};"); lubomir@869: lubomir@1029: declaredClass(jc, className); lubomir@869: jaroslav@834: // StringBuilder sb = new StringBuilder(); jaroslav@834: // for (String init : toInitilize.toArray()) { jaroslav@834: // sb.append("\n").append(init).append("();"); jaroslav@834: // } jaroslav@834: return ""; jaroslav@0: } jaroslav@1586: jaroslav@1586: private boolean javaScriptOnly(byte[] anno) throws IOException { jaroslav@1586: String[] only = findAnnotation(anno, jc, jaroslav@1586: "org.apidesign.bck2brwsr.core.JavaScriptOnly", jaroslav@1586: "name", "value" jaroslav@1586: ); jaroslav@1586: if (only != null) { jaroslav@1586: if (only[0] != null && only[1] != null) { jaroslav@1586: append("\n p.").append(only[0]).append(" = ") jaroslav@1586: .append(only[1]).append(";"); jaroslav@1586: } jaroslav@1586: if (ExportedSymbols.isMarkedAsExported(anno, jc)) { jaroslav@1586: append("\n p['").append(only[0]).append("'] = p.") jaroslav@1586: .append(only[0]).append(";"); jaroslav@1586: } jaroslav@1586: return true; jaroslav@1586: } jaroslav@1586: return false; jaroslav@1586: } lubomir@869: private String generateStaticMethod(String destObject, MethodData m, StringArray toInitilize) throws IOException { lubomir@869: String jsb = javaScriptBody(destObject, m, true); jaroslav@266: if (jsb != null) { jaroslav@266: return jsb; jaroslav@94: } lubomir@307: final String mn = findMethodName(m, new StringBuilder()); jaroslav@248: if (mn.equals("class__V")) { jaroslav@274: toInitilize.add(accessClass(className(jc)) + "(false)." + mn); jaroslav@21: } lubomir@869: generateMethod(destObject, mn, m); jaroslav@266: return mn; jaroslav@10: } lubomir@307: lubomir@869: private String generateInstanceMethod(String destObject, MethodData m) throws IOException { lubomir@869: String jsb = javaScriptBody(destObject, m, false); jaroslav@266: if (jsb != null) { jaroslav@266: return jsb; jaroslav@94: } lubomir@307: final String mn = findMethodName(m, new StringBuilder()); lubomir@869: generateMethod(destObject, mn, m); jaroslav@266: return mn; jaroslav@0: } jaroslav@0: lubomir@869: private void generateMethod(String destObject, String name, MethodData m) lubomir@307: throws IOException { lubomir@307: final StackMapIterator stackMapIterator = m.createStackMapIterator(); jaroslav@376: TrapDataIterator trap = m.getTrapDataIterator(); lubomir@307: final LocalsMapper lmapper = lubomir@307: new LocalsMapper(stackMapIterator.getArguments()); lubomir@307: jaroslav@1509: append(destObject).append(".").append(name).append(" = function("); jaroslav@1509: lmapper.outputArguments(this, m.isStatic()); jaroslav@1509: append(") {").append("\n"); lubomir@307: lubomir@221: final byte[] byteCodes = m.getCode(); lubomir@307: if (byteCodes == null) { jaroslav@1509: append(" throw 'no code found for ") jaroslav@424: .append(jc.getClassName()).append('.') jaroslav@424: .append(m.getName()).append("';\n"); jaroslav@1509: append("};"); lubomir@307: return; lubomir@307: } lubomir@307: lubomir@307: final StackMapper smapper = new StackMapper(); lubomir@307: jaroslav@442: if (!m.isStatic()) { jaroslav@1509: append(" var ").append(" lcA0 = this;\n"); jaroslav@442: } lubomir@221: jaroslav@1469: int lastStackFrame; jaroslav@398: TrapData[] previousTrap = null; lubomir@585: boolean wide = false; jaroslav@1469: boolean didBranches; jaroslav@1469: if (stackMapIterator.isEmpty()) { jaroslav@1469: didBranches = false; jaroslav@1469: lastStackFrame = 0; jaroslav@1469: } else { jaroslav@1469: didBranches = true; jaroslav@1469: lastStackFrame = -1; jaroslav@1509: append("\n var gt = 0;\n"); jaroslav@1469: } jaroslav@398: jaroslav@839: int openBraces = 0; jaroslav@843: int topMostLabel = 0; jaroslav@0: for (int i = 0; i < byteCodes.length; i++) { jaroslav@272: int prev = i; jaroslav@1510: outChanged = false; lubomir@221: stackMapIterator.advanceTo(i); jaroslav@398: boolean changeInCatch = trap.advanceTo(i); jaroslav@398: if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) { jaroslav@398: if (previousTrap != null) { jaroslav@843: generateCatch(previousTrap, i, topMostLabel); jaroslav@398: previousTrap = null; jaroslav@398: } jaroslav@398: } lubomir@221: if (lastStackFrame != stackMapIterator.getFrameIndex()) { jaroslav@1509: smapper.flush(this); jaroslav@839: if (i != 0) { jaroslav@1509: append(" }\n"); jaroslav@839: } jaroslav@843: if (openBraces > 64) { jaroslav@843: for (int c = 0; c < 64; c++) { jaroslav@1509: append("break;}\n"); jaroslav@843: } jaroslav@843: openBraces = 1; jaroslav@843: topMostLabel = i; jaroslav@843: } jaroslav@839: lubomir@221: lastStackFrame = stackMapIterator.getFrameIndex(); lubomir@307: lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals()); lubomir@307: smapper.syncWithFrameStack(stackMapIterator.getFrameStack()); jaroslav@1509: append(" X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n"); jaroslav@839: openBraces++; jaroslav@398: changeInCatch = true; lubomir@221: } else { jaroslav@399: debug(" /* " + i + " */ "); lubomir@221: } jaroslav@398: if (changeInCatch && trap.useTry()) { jaroslav@1509: append("try {"); jaroslav@398: previousTrap = trap.current(); tzezula@285: } lubomir@585: final int c = readUByte(byteCodes, i); jaroslav@0: switch (c) { jaroslav@151: case opc_aload_0: jaroslav@1509: smapper.assign(this, VarType.REFERENCE, lmapper.getA(0)); lubomir@281: break; jaroslav@151: case opc_iload_0: jaroslav@1509: smapper.assign(this, VarType.INTEGER, lmapper.getI(0)); lubomir@281: break; jaroslav@151: case opc_lload_0: jaroslav@1509: smapper.assign(this, VarType.LONG, lmapper.getL(0)); lubomir@281: break; jaroslav@151: case opc_fload_0: jaroslav@1509: smapper.assign(this, VarType.FLOAT, lmapper.getF(0)); lubomir@281: break; jaroslav@151: case opc_dload_0: jaroslav@1509: smapper.assign(this, VarType.DOUBLE, lmapper.getD(0)); jaroslav@0: break; jaroslav@151: case opc_aload_1: jaroslav@1509: smapper.assign(this, VarType.REFERENCE, lmapper.getA(1)); lubomir@281: break; jaroslav@151: case opc_iload_1: jaroslav@1509: smapper.assign(this, VarType.INTEGER, lmapper.getI(1)); lubomir@281: break; jaroslav@151: case opc_lload_1: jaroslav@1509: smapper.assign(this, VarType.LONG, lmapper.getL(1)); lubomir@281: break; jaroslav@151: case opc_fload_1: jaroslav@1509: smapper.assign(this, VarType.FLOAT, lmapper.getF(1)); lubomir@281: break; jaroslav@151: case opc_dload_1: jaroslav@1509: smapper.assign(this, VarType.DOUBLE, lmapper.getD(1)); jaroslav@0: break; jaroslav@151: case opc_aload_2: jaroslav@1509: smapper.assign(this, VarType.REFERENCE, lmapper.getA(2)); lubomir@281: break; jaroslav@151: case opc_iload_2: jaroslav@1509: smapper.assign(this, VarType.INTEGER, lmapper.getI(2)); lubomir@281: break; jaroslav@151: case opc_lload_2: jaroslav@1509: smapper.assign(this, VarType.LONG, lmapper.getL(2)); lubomir@281: break; jaroslav@151: case opc_fload_2: jaroslav@1509: smapper.assign(this, VarType.FLOAT, lmapper.getF(2)); lubomir@281: break; jaroslav@151: case opc_dload_2: jaroslav@1509: smapper.assign(this, VarType.DOUBLE, lmapper.getD(2)); jaroslav@2: break; jaroslav@151: case opc_aload_3: jaroslav@1509: smapper.assign(this, VarType.REFERENCE, lmapper.getA(3)); lubomir@281: break; jaroslav@151: case opc_iload_3: jaroslav@1509: smapper.assign(this, VarType.INTEGER, lmapper.getI(3)); lubomir@281: break; jaroslav@151: case opc_lload_3: jaroslav@1509: smapper.assign(this, VarType.LONG, lmapper.getL(3)); lubomir@281: break; jaroslav@151: case opc_fload_3: jaroslav@1509: smapper.assign(this, VarType.FLOAT, lmapper.getF(3)); lubomir@281: break; jaroslav@151: case opc_dload_3: jaroslav@1509: smapper.assign(this, VarType.DOUBLE, lmapper.getD(3)); jaroslav@3: break; lubomir@281: case opc_iload: { lubomir@585: ++i; lubomir@585: final int indx = wide ? readUShort(byteCodes, i++) lubomir@585: : readUByte(byteCodes, i); lubomir@585: wide = false; jaroslav@1509: smapper.assign(this, VarType.INTEGER, lmapper.getI(indx)); lubomir@281: break; lubomir@281: } lubomir@281: case opc_lload: { lubomir@585: ++i; lubomir@585: final int indx = wide ? readUShort(byteCodes, i++) lubomir@585: : readUByte(byteCodes, i); lubomir@585: wide = false; jaroslav@1509: smapper.assign(this, VarType.LONG, lmapper.getL(indx)); lubomir@281: break; lubomir@281: } lubomir@281: case opc_fload: { lubomir@585: ++i; lubomir@585: final int indx = wide ? readUShort(byteCodes, i++) lubomir@585: : readUByte(byteCodes, i); lubomir@585: wide = false; jaroslav@1509: smapper.assign(this, VarType.FLOAT, lmapper.getF(indx)); lubomir@281: break; lubomir@281: } lubomir@281: case opc_dload: { lubomir@585: ++i; lubomir@585: final int indx = wide ? readUShort(byteCodes, i++) lubomir@585: : readUByte(byteCodes, i); lubomir@585: wide = false; jaroslav@1509: smapper.assign(this, VarType.DOUBLE, lmapper.getD(indx)); lubomir@281: break; lubomir@281: } jaroslav@151: case opc_aload: { lubomir@585: ++i; lubomir@585: final int indx = wide ? readUShort(byteCodes, i++) lubomir@585: : readUByte(byteCodes, i); lubomir@585: wide = false; jaroslav@1509: smapper.assign(this, VarType.REFERENCE, lmapper.getA(indx)); jaroslav@3: break; jaroslav@3: } lubomir@281: case opc_istore: { lubomir@585: ++i; lubomir@585: final int indx = wide ? readUShort(byteCodes, i++) lubomir@585: : readUByte(byteCodes, i); lubomir@585: wide = false; jaroslav@1509: emit(smapper, this, "var @1 = @2;", lubomir@474: lmapper.setI(indx), smapper.popI()); lubomir@281: break; lubomir@281: } lubomir@281: case opc_lstore: { lubomir@585: ++i; lubomir@585: final int indx = wide ? readUShort(byteCodes, i++) lubomir@585: : readUByte(byteCodes, i); lubomir@585: wide = false; jaroslav@1509: emit(smapper, this, "var @1 = @2;", lubomir@474: lmapper.setL(indx), smapper.popL()); lubomir@281: break; lubomir@281: } lubomir@281: case opc_fstore: { lubomir@585: ++i; lubomir@585: final int indx = wide ? readUShort(byteCodes, i++) lubomir@585: : readUByte(byteCodes, i); lubomir@585: wide = false; jaroslav@1509: emit(smapper, this, "var @1 = @2;", lubomir@474: lmapper.setF(indx), smapper.popF()); lubomir@281: break; lubomir@281: } lubomir@281: case opc_dstore: { lubomir@585: ++i; lubomir@585: final int indx = wide ? readUShort(byteCodes, i++) lubomir@585: : readUByte(byteCodes, i); lubomir@585: wide = false; jaroslav@1509: emit(smapper, this, "var @1 = @2;", lubomir@474: lmapper.setD(indx), smapper.popD()); lubomir@281: break; lubomir@281: } jaroslav@151: case opc_astore: { lubomir@585: ++i; lubomir@585: final int indx = wide ? readUShort(byteCodes, i++) lubomir@585: : readUByte(byteCodes, i); lubomir@585: wide = false; jaroslav@1509: emit(smapper, this, "var @1 = @2;", lubomir@474: lmapper.setA(indx), smapper.popA()); jaroslav@31: break; jaroslav@31: } jaroslav@151: case opc_astore_0: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setA(0), smapper.popA()); lubomir@281: break; jaroslav@151: case opc_istore_0: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setI(0), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lstore_0: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setL(0), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fstore_0: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setF(0), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dstore_0: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setD(0), smapper.popD()); jaroslav@5: break; jaroslav@151: case opc_astore_1: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setA(1), smapper.popA()); lubomir@281: break; jaroslav@151: case opc_istore_1: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lstore_1: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setL(1), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fstore_1: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setF(1), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dstore_1: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setD(1), smapper.popD()); jaroslav@5: break; jaroslav@151: case opc_astore_2: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setA(2), smapper.popA()); lubomir@281: break; jaroslav@151: case opc_istore_2: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setI(2), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lstore_2: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setL(2), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fstore_2: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setF(2), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dstore_2: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setD(2), smapper.popD()); jaroslav@5: break; jaroslav@151: case opc_astore_3: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setA(3), smapper.popA()); lubomir@281: break; jaroslav@151: case opc_istore_3: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setI(3), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lstore_3: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setL(3), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fstore_3: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setF(3), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dstore_3: jaroslav@1509: emit(smapper, this, "var @1 = @2;", lmapper.setD(3), smapper.popD()); jaroslav@5: break; jaroslav@151: case opc_iadd: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).add32(@2)", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_ladd: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).add64(@2)", smapper.getL(1), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fadd: jaroslav@1509: smapper.replace(this, VarType.FLOAT, "(@1 + @2)", smapper.getF(1), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dadd: jaroslav@1509: smapper.replace(this, VarType.DOUBLE, "(@1 + @2)", smapper.getD(1), smapper.popD()); jaroslav@0: break; jaroslav@151: case opc_isub: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).sub32(@2)", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lsub: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).sub64(@2)", smapper.getL(1), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fsub: jaroslav@1509: smapper.replace(this, VarType.FLOAT, "(@1 - @2)", smapper.getF(1), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dsub: jaroslav@1509: smapper.replace(this, VarType.DOUBLE, "(@1 - @2)", smapper.getD(1), smapper.popD()); jaroslav@2: break; jaroslav@151: case opc_imul: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).mul32(@2)", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lmul: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).mul64(@2)", smapper.getL(1), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fmul: jaroslav@1509: smapper.replace(this, VarType.FLOAT, "(@1 * @2)", smapper.getF(1), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dmul: jaroslav@1509: smapper.replace(this, VarType.DOUBLE, "(@1 * @2)", smapper.getD(1), smapper.popD()); jaroslav@1: break; jaroslav@151: case opc_idiv: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).div32(@2)", lubomir@307: smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_ldiv: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).div64(@2)", lubomir@307: smapper.getL(1), smapper.popL()); jaroslav@3: break; jaroslav@151: case opc_fdiv: jaroslav@1509: smapper.replace(this, VarType.FLOAT, "(@1 / @2)", smapper.getF(1), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_ddiv: jaroslav@1509: smapper.replace(this, VarType.DOUBLE, "(@1 / @2)", smapper.getD(1), smapper.popD()); jaroslav@3: break; jaroslav@178: case opc_irem: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).mod32(@2)", lubomir@737: smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@178: case opc_lrem: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).mod64(@2)", lubomir@676: smapper.getL(1), smapper.popL()); lubomir@281: break; jaroslav@178: case opc_frem: jaroslav@1509: smapper.replace(this, VarType.FLOAT, "(@1 % @2)", smapper.getF(1), smapper.popF()); lubomir@281: break; jaroslav@178: case opc_drem: jaroslav@1509: smapper.replace(this, VarType.DOUBLE, "(@1 % @2)", smapper.getD(1), smapper.popD()); jaroslav@178: break; jaroslav@151: case opc_iand: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1 & @2)", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_land: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).and64(@2)", smapper.getL(1), smapper.popL()); jaroslav@7: break; jaroslav@151: case opc_ior: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1 | @2)", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lor: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).or64(@2)", smapper.getL(1), smapper.popL()); jaroslav@7: break; jaroslav@151: case opc_ixor: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1 ^ @2)", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lxor: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).xor64(@2)", smapper.getL(1), smapper.popL()); jaroslav@6: break; jaroslav@151: case opc_ineg: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).neg32()", smapper.getI(0)); lubomir@281: break; jaroslav@151: case opc_lneg: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).neg64()", smapper.getL(0)); lubomir@281: break; jaroslav@151: case opc_fneg: jaroslav@1509: smapper.replace(this, VarType.FLOAT, "(-@1)", smapper.getF(0)); lubomir@281: break; jaroslav@151: case opc_dneg: jaroslav@1509: smapper.replace(this, VarType.DOUBLE, "(-@1)", smapper.getD(0)); jaroslav@93: break; jaroslav@151: case opc_ishl: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1 << @2)", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lshl: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).shl64(@2)", smapper.getL(1), smapper.popI()); jaroslav@93: break; jaroslav@151: case opc_ishr: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1 >> @2)", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lshr: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).shr64(@2)", smapper.getL(1), smapper.popI()); jaroslav@93: break; jaroslav@151: case opc_iushr: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1 >>> @2)", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lushr: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).ushr64(@2)", smapper.getL(1), smapper.popI()); jaroslav@93: break; jaroslav@151: case opc_iinc: { lubomir@585: ++i; lubomir@585: final int varIndx = wide ? readUShort(byteCodes, i++) lubomir@585: : readUByte(byteCodes, i); lubomir@585: ++i; lubomir@697: final int incrBy = wide ? readShort(byteCodes, i++) lubomir@585: : byteCodes[i]; lubomir@585: wide = false; jaroslav@5: if (incrBy == 1) { jaroslav@1509: emit(smapper, this, "@1++;", lmapper.getI(varIndx)); jaroslav@5: } else { jaroslav@1509: emit(smapper, this, "@1 += @2;", lubomir@307: lmapper.getI(varIndx), lubomir@283: Integer.toString(incrBy)); jaroslav@5: } jaroslav@5: break; jaroslav@5: } jaroslav@151: case opc_return: jaroslav@1509: emit(smapper, this, "return;"); jaroslav@10: break; jaroslav@151: case opc_ireturn: jaroslav@1509: emit(smapper, this, "return @1;", smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lreturn: jaroslav@1509: emit(smapper, this, "return @1;", smapper.popL()); lubomir@281: break; jaroslav@151: case opc_freturn: jaroslav@1509: emit(smapper, this, "return @1;", smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dreturn: jaroslav@1509: emit(smapper, this, "return @1;", smapper.popD()); lubomir@281: break; jaroslav@151: case opc_areturn: jaroslav@1509: emit(smapper, this, "return @1;", smapper.popA()); jaroslav@1: break; jaroslav@151: case opc_i2l: jaroslav@1509: smapper.replace(this, VarType.LONG, "@1", smapper.getI(0)); lubomir@281: break; jaroslav@151: case opc_i2f: jaroslav@1509: smapper.replace(this, VarType.FLOAT, "@1", smapper.getI(0)); lubomir@281: break; jaroslav@151: case opc_i2d: jaroslav@1509: smapper.replace(this, VarType.DOUBLE, "@1", smapper.getI(0)); lubomir@281: break; jaroslav@151: case opc_l2i: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).toInt32()", smapper.getL(0)); lubomir@281: break; jaroslav@3: // max int check? jaroslav@151: case opc_l2f: jaroslav@1509: smapper.replace(this, VarType.FLOAT, "(@1).toFP()", smapper.getL(0)); jaroslav@272: break; jaroslav@151: case opc_l2d: jaroslav@1509: smapper.replace(this, VarType.DOUBLE, "(@1).toFP()", smapper.getL(0)); jaroslav@272: break; jaroslav@151: case opc_f2d: jaroslav@1509: smapper.replace(this, VarType.DOUBLE, "@1", jaroslav@1457: smapper.getF(0)); lubomir@281: break; jaroslav@151: case opc_d2f: jaroslav@1509: smapper.replace(this, VarType.FLOAT, "@1", jaroslav@1457: smapper.getD(0)); jaroslav@3: break; jaroslav@151: case opc_f2i: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).toInt32()", jaroslav@1457: smapper.getF(0)); lubomir@281: break; jaroslav@151: case opc_f2l: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).toLong()", jaroslav@1457: smapper.getF(0)); lubomir@281: break; jaroslav@151: case opc_d2i: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).toInt32()", jaroslav@1457: smapper.getD(0)); lubomir@281: break; jaroslav@151: case opc_d2l: jaroslav@1509: smapper.replace(this, VarType.LONG, "(@1).toLong()", smapper.getD(0)); jaroslav@3: break; jaroslav@151: case opc_i2b: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).toInt8()", smapper.getI(0)); Martin@440: break; jaroslav@151: case opc_i2c: Martin@439: break; jaroslav@151: case opc_i2s: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).toInt16()", smapper.getI(0)); jaroslav@2: break; jaroslav@151: case opc_aconst_null: jaroslav@1509: smapper.assign(this, VarType.REFERENCE, "null"); jaroslav@46: break; jaroslav@151: case opc_iconst_m1: jaroslav@1509: smapper.assign(this, VarType.INTEGER, "-1"); jaroslav@48: break; jaroslav@151: case opc_iconst_0: jaroslav@1509: smapper.assign(this, VarType.INTEGER, "0"); lubomir@281: break; jaroslav@151: case opc_dconst_0: jaroslav@1509: smapper.assign(this, VarType.DOUBLE, "0"); lubomir@281: break; jaroslav@151: case opc_lconst_0: jaroslav@1509: smapper.assign(this, VarType.LONG, "0"); lubomir@281: break; jaroslav@151: case opc_fconst_0: jaroslav@1509: smapper.assign(this, VarType.FLOAT, "0"); jaroslav@4: break; jaroslav@151: case opc_iconst_1: jaroslav@1509: smapper.assign(this, VarType.INTEGER, "1"); lubomir@281: break; jaroslav@151: case opc_lconst_1: jaroslav@1509: smapper.assign(this, VarType.LONG, "1"); lubomir@281: break; jaroslav@151: case opc_fconst_1: jaroslav@1509: smapper.assign(this, VarType.FLOAT, "1"); lubomir@281: break; jaroslav@151: case opc_dconst_1: jaroslav@1509: smapper.assign(this, VarType.DOUBLE, "1"); jaroslav@4: break; jaroslav@151: case opc_iconst_2: jaroslav@1509: smapper.assign(this, VarType.INTEGER, "2"); lubomir@281: break; jaroslav@151: case opc_fconst_2: jaroslav@1509: smapper.assign(this, VarType.FLOAT, "2"); jaroslav@4: break; jaroslav@151: case opc_iconst_3: jaroslav@1509: smapper.assign(this, VarType.INTEGER, "3"); jaroslav@4: break; jaroslav@151: case opc_iconst_4: jaroslav@1509: smapper.assign(this, VarType.INTEGER, "4"); jaroslav@4: break; jaroslav@151: case opc_iconst_5: jaroslav@1509: smapper.assign(this, VarType.INTEGER, "5"); jaroslav@4: break; jaroslav@151: case opc_ldc: { lubomir@585: int indx = readUByte(byteCodes, ++i); jaroslav@151: String v = encodeConstant(indx); lubomir@307: int type = VarType.fromConstantType(jc.getTag(indx)); jaroslav@1509: smapper.assign(this, type, v); jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_ldc_w: jaroslav@151: case opc_ldc2_w: { jaroslav@864: int indx = readUShortArg(byteCodes, i); jaroslav@8: i += 2; jaroslav@151: String v = encodeConstant(indx); lubomir@307: int type = VarType.fromConstantType(jc.getTag(indx)); Martin@582: if (type == VarType.LONG) { Martin@582: final Long lv = new Long(v); Martin@582: final int low = (int)(lv.longValue() & 0xFFFFFFFF); Martin@582: final int hi = (int)(lv.longValue() >> 32); jaroslav@1462: if (hi == 0) { jaroslav@1509: smapper.assign(this, VarType.LONG, "0x" + Integer.toHexString(low)); jaroslav@1462: } else { jaroslav@1509: smapper.assign(this, VarType.LONG, jaroslav@1462: "0x" + Integer.toHexString(hi) + ".next32(0x" + jaroslav@1462: Integer.toHexString(low) + ")" jaroslav@1462: ); jaroslav@1462: } Martin@582: } else { jaroslav@1509: smapper.assign(this, type, v); Martin@582: } jaroslav@8: break; jaroslav@8: } jaroslav@151: case opc_lcmp: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@2).compare64(@1)", smapper.popL(), smapper.getL(0)); lubomir@281: break; jaroslav@151: case opc_fcmpl: jaroslav@151: case opc_fcmpg: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@2).compare(@1)", smapper.popF(), smapper.getF(0)); lubomir@281: break; jaroslav@151: case opc_dcmpl: lubomir@281: case opc_dcmpg: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@2).compare(@1)", smapper.popD(), smapper.getD(0)); jaroslav@20: break; jaroslav@151: case opc_if_acmpeq: jaroslav@1468: i = generateIf(smapper, byteCodes, i, smapper.popA(), smapper.popA(), jaroslav@843: "===", topMostLabel); jaroslav@104: break; jaroslav@151: case opc_if_acmpne: jaroslav@1468: i = generateIf(smapper, byteCodes, i, smapper.popA(), smapper.popA(), jaroslav@843: "!==", topMostLabel); jaroslav@104: break; lubomir@283: case opc_if_icmpeq: jaroslav@1468: i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), jaroslav@843: "==", topMostLabel); jaroslav@4: break; jaroslav@151: case opc_ifeq: { jaroslav@864: int indx = i + readShortArg(byteCodes, i); jaroslav@1509: emitIf(smapper, this, "if ((@1) == 0) ", jaroslav@843: smapper.popI(), i, indx, topMostLabel); jaroslav@7: i += 2; jaroslav@7: break; jaroslav@7: } jaroslav@151: case opc_ifne: { jaroslav@864: int indx = i + readShortArg(byteCodes, i); jaroslav@1509: emitIf(smapper, this, "if ((@1) != 0) ", jaroslav@843: smapper.popI(), i, indx, topMostLabel); jaroslav@20: i += 2; jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_iflt: { jaroslav@864: int indx = i + readShortArg(byteCodes, i); jaroslav@1509: emitIf(smapper, this, "if ((@1) < 0) ", jaroslav@843: smapper.popI(), i, indx, topMostLabel); jaroslav@20: i += 2; jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_ifle: { jaroslav@864: int indx = i + readShortArg(byteCodes, i); jaroslav@1509: emitIf(smapper, this, "if ((@1) <= 0) ", jaroslav@843: smapper.popI(), i, indx, topMostLabel); jaroslav@20: i += 2; jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_ifgt: { jaroslav@864: int indx = i + readShortArg(byteCodes, i); jaroslav@1509: emitIf(smapper, this, "if ((@1) > 0) ", jaroslav@843: smapper.popI(), i, indx, topMostLabel); jaroslav@20: i += 2; jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_ifge: { jaroslav@864: int indx = i + readShortArg(byteCodes, i); jaroslav@1509: emitIf(smapper, this, "if ((@1) >= 0) ", jaroslav@843: smapper.popI(), i, indx, topMostLabel); jaroslav@20: i += 2; jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_ifnonnull: { jaroslav@864: int indx = i + readShortArg(byteCodes, i); jaroslav@1509: emitIf(smapper, this, "if ((@1) !== null) ", jaroslav@843: smapper.popA(), i, indx, topMostLabel); jaroslav@16: i += 2; jaroslav@16: break; jaroslav@16: } jaroslav@151: case opc_ifnull: { jaroslav@864: int indx = i + readShortArg(byteCodes, i); jaroslav@1509: emitIf(smapper, this, "if ((@1) === null) ", jaroslav@843: smapper.popA(), i, indx, topMostLabel); jaroslav@16: i += 2; jaroslav@16: break; jaroslav@16: } jaroslav@151: case opc_if_icmpne: jaroslav@1468: i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), jaroslav@843: "!=", topMostLabel); jaroslav@4: break; jaroslav@151: case opc_if_icmplt: jaroslav@1468: i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), jaroslav@843: "<", topMostLabel); jaroslav@4: break; jaroslav@151: case opc_if_icmple: jaroslav@1468: i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), jaroslav@843: "<=", topMostLabel); jaroslav@4: break; jaroslav@151: case opc_if_icmpgt: jaroslav@1468: i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), jaroslav@843: ">", topMostLabel); jaroslav@4: break; jaroslav@151: case opc_if_icmpge: jaroslav@1468: i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), jaroslav@843: ">=", topMostLabel); jaroslav@4: break; jaroslav@151: case opc_goto: { jaroslav@1509: smapper.flush(this); jaroslav@864: int indx = i + readShortArg(byteCodes, i); jaroslav@1509: goTo(this, i, indx, topMostLabel); jaroslav@5: i += 2; jaroslav@5: break; jaroslav@5: } jaroslav@151: case opc_lookupswitch: { jaroslav@843: i = generateLookupSwitch(i, byteCodes, smapper, topMostLabel); jaroslav@115: break; jaroslav@115: } jaroslav@151: case opc_tableswitch: { jaroslav@843: i = generateTableSwitch(i, byteCodes, smapper, topMostLabel); jaroslav@115: break; jaroslav@115: } jaroslav@151: case opc_invokeinterface: { lubomir@307: i = invokeVirtualMethod(byteCodes, i, smapper) + 2; jaroslav@46: break; jaroslav@46: } jaroslav@151: case opc_invokevirtual: lubomir@307: i = invokeVirtualMethod(byteCodes, i, smapper); jaroslav@12: break; jaroslav@151: case opc_invokespecial: lubomir@307: i = invokeStaticMethod(byteCodes, i, smapper, false); jaroslav@4: break; jaroslav@151: case opc_invokestatic: lubomir@307: i = invokeStaticMethod(byteCodes, i, smapper, true); jaroslav@10: break; jaroslav@151: case opc_new: { jaroslav@864: int indx = readUShortArg(byteCodes, i); jaroslav@151: String ci = jc.getClassName(indx); jaroslav@1509: emit(smapper, this, "var @1 = new @2;", jaroslav@1409: smapper.pushA(), accessClass(mangleClassName(ci))); jaroslav@151: addReference(ci); jaroslav@8: i += 2; jaroslav@8: break; jaroslav@8: } lubomir@283: case opc_newarray: lubomir@585: int atype = readUByte(byteCodes, ++i); jaroslav@842: generateNewArray(atype, smapper); jaroslav@21: break; jaroslav@448: case opc_anewarray: { jaroslav@864: int type = readUShortArg(byteCodes, i); jaroslav@448: i += 2; jaroslav@842: generateANewArray(type, smapper); jaroslav@21: break; jaroslav@448: } jaroslav@151: case opc_multianewarray: { jaroslav@864: int type = readUShortArg(byteCodes, i); jtulach@128: i += 2; jaroslav@842: i = generateMultiANewArray(type, byteCodes, i, smapper); jtulach@128: break; jtulach@128: } jaroslav@151: case opc_arraylength: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "(@1).length", smapper.getA(0)); jaroslav@272: break; lubomir@283: case opc_lastore: jaroslav@1509: emit(smapper, this, "Array.at(@3, @2, @1);", lubomir@307: smapper.popL(), smapper.popI(), smapper.popA()); lubomir@281: break; lubomir@283: case opc_fastore: jaroslav@1509: emit(smapper, this, "Array.at(@3, @2, @1);", lubomir@307: smapper.popF(), smapper.popI(), smapper.popA()); lubomir@281: break; lubomir@283: case opc_dastore: jaroslav@1509: emit(smapper, this, "Array.at(@3, @2, @1);", lubomir@307: smapper.popD(), smapper.popI(), smapper.popA()); lubomir@281: break; lubomir@283: case opc_aastore: jaroslav@1509: emit(smapper, this, "Array.at(@3, @2, @1);", lubomir@307: smapper.popA(), smapper.popI(), smapper.popA()); jaroslav@21: break; jaroslav@151: case opc_iastore: jaroslav@151: case opc_bastore: jaroslav@151: case opc_castore: lubomir@283: case opc_sastore: jaroslav@1509: emit(smapper, this, "Array.at(@3, @2, @1);", lubomir@307: smapper.popI(), smapper.popI(), smapper.popA()); jaroslav@240: break; lubomir@283: case opc_laload: jaroslav@1509: smapper.replace(this, VarType.LONG, "Array.at(@2, @1)", jaroslav@1477: smapper.popI(), smapper.getA(0)); lubomir@281: break; lubomir@283: case opc_faload: jaroslav@1509: smapper.replace(this, VarType.FLOAT, "Array.at(@2, @1)", jaroslav@1477: smapper.popI(), smapper.getA(0)); lubomir@281: break; lubomir@283: case opc_daload: jaroslav@1509: smapper.replace(this, VarType.DOUBLE, "Array.at(@2, @1)", jaroslav@1477: smapper.popI(), smapper.getA(0)); lubomir@281: break; lubomir@283: case opc_aaload: jaroslav@1509: smapper.replace(this, VarType.REFERENCE, "Array.at(@2, @1)", jaroslav@1477: smapper.popI(), smapper.getA(0)); jaroslav@272: break; jaroslav@272: case opc_iaload: jaroslav@272: case opc_baload: jaroslav@272: case opc_caload: lubomir@283: case opc_saload: jaroslav@1509: smapper.replace(this, VarType.INTEGER, "Array.at(@2, @1)", jaroslav@1477: smapper.popI(), smapper.getA(0)); jaroslav@272: break; lubomir@221: case opc_pop: jaroslav@272: case opc_pop2: lubomir@307: smapper.pop(1); jaroslav@399: debug("/* pop */"); jaroslav@272: break; lubomir@281: case opc_dup: { lubomir@307: final Variable v = smapper.get(0); jaroslav@1543: if (smapper.isDirty()) { jaroslav@1543: emit(smapper, this, "var @1 = @2;", smapper.pushT(v.getType()), v); jaroslav@1543: } else { jaroslav@1543: smapper.assign(this, v.getType(), v); jaroslav@1543: } jaroslav@21: break; jaroslav@21: } lubomir@281: case opc_dup2: { lubomir@585: final Variable vi1 = smapper.get(0); lubomir@585: lubomir@585: if (vi1.isCategory2()) { jaroslav@1509: emit(smapper, this, "var @1 = @2;", lubomir@585: smapper.pushT(vi1.getType()), vi1); lubomir@281: } else { lubomir@585: final Variable vi2 = smapper.get(1); jaroslav@1509: emit(smapper, this, "var @1 = @2, @3 = @4;", lubomir@585: smapper.pushT(vi2.getType()), vi2, lubomir@585: smapper.pushT(vi1.getType()), vi1); lubomir@281: } jaroslav@21: break; jaroslav@21: } lubomir@281: case opc_dup_x1: { jaroslav@1509: final Variable vi1 = smapper.pop(this); jaroslav@1509: final Variable vi2 = smapper.pop(this); lubomir@307: final Variable vo3 = smapper.pushT(vi1.getType()); lubomir@307: final Variable vo2 = smapper.pushT(vi2.getType()); lubomir@307: final Variable vo1 = smapper.pushT(vi1.getType()); lubomir@281: jaroslav@1509: emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;", lubomir@283: vo1, vi1, vo2, vi2, vo3, vo1); jaroslav@93: break; lubomir@281: } lubomir@585: case opc_dup2_x1: { jaroslav@1509: final Variable vi1 = smapper.pop(this); jaroslav@1509: final Variable vi2 = smapper.pop(this); lubomir@585: lubomir@585: if (vi1.isCategory2()) { lubomir@307: final Variable vo3 = smapper.pushT(vi1.getType()); lubomir@307: final Variable vo2 = smapper.pushT(vi2.getType()); lubomir@307: final Variable vo1 = smapper.pushT(vi1.getType()); lubomir@281: jaroslav@1509: emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;", lubomir@283: vo1, vi1, vo2, vi2, vo3, vo1); lubomir@281: } else { jaroslav@1509: final Variable vi3 = smapper.pop(this); lubomir@585: final Variable vo5 = smapper.pushT(vi2.getType()); lubomir@585: final Variable vo4 = smapper.pushT(vi1.getType()); lubomir@585: final Variable vo3 = smapper.pushT(vi3.getType()); lubomir@585: final Variable vo2 = smapper.pushT(vi2.getType()); lubomir@585: final Variable vo1 = smapper.pushT(vi1.getType()); lubomir@585: jaroslav@1509: emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6,", lubomir@585: vo1, vi1, vo2, vi2, vo3, vi3); jaroslav@1509: emit(smapper, this, " @1 = @2, @3 = @4;", lubomir@585: vo4, vo1, vo5, vo2); lubomir@585: } lubomir@585: break; lubomir@585: } lubomir@585: case opc_dup_x2: { jaroslav@1509: final Variable vi1 = smapper.pop(this); jaroslav@1509: final Variable vi2 = smapper.pop(this); lubomir@585: lubomir@585: if (vi2.isCategory2()) { lubomir@585: final Variable vo3 = smapper.pushT(vi1.getType()); lubomir@585: final Variable vo2 = smapper.pushT(vi2.getType()); lubomir@585: final Variable vo1 = smapper.pushT(vi1.getType()); lubomir@585: jaroslav@1509: emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;", lubomir@585: vo1, vi1, vo2, vi2, vo3, vo1); lubomir@585: } else { jaroslav@1509: final Variable vi3 = smapper.pop(this); lubomir@307: final Variable vo4 = smapper.pushT(vi1.getType()); lubomir@307: final Variable vo3 = smapper.pushT(vi3.getType()); lubomir@307: final Variable vo2 = smapper.pushT(vi2.getType()); lubomir@307: final Variable vo1 = smapper.pushT(vi1.getType()); lubomir@281: jaroslav@1509: emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", lubomir@283: vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1); lubomir@281: } jaroslav@8: break; lubomir@281: } lubomir@585: case opc_dup2_x2: { jaroslav@1509: final Variable vi1 = smapper.pop(this); jaroslav@1509: final Variable vi2 = smapper.pop(this); lubomir@585: lubomir@585: if (vi1.isCategory2()) { lubomir@585: if (vi2.isCategory2()) { lubomir@585: final Variable vo3 = smapper.pushT(vi1.getType()); lubomir@585: final Variable vo2 = smapper.pushT(vi2.getType()); lubomir@585: final Variable vo1 = smapper.pushT(vi1.getType()); lubomir@585: jaroslav@1509: emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;", lubomir@585: vo1, vi1, vo2, vi2, vo3, vo1); lubomir@585: } else { jaroslav@1509: final Variable vi3 = smapper.pop(this); lubomir@585: final Variable vo4 = smapper.pushT(vi1.getType()); lubomir@585: final Variable vo3 = smapper.pushT(vi3.getType()); lubomir@585: final Variable vo2 = smapper.pushT(vi2.getType()); lubomir@585: final Variable vo1 = smapper.pushT(vi1.getType()); lubomir@585: jaroslav@1509: emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", lubomir@585: vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1); lubomir@585: } lubomir@585: } else { jaroslav@1509: final Variable vi3 = smapper.pop(this); lubomir@585: lubomir@585: if (vi3.isCategory2()) { lubomir@585: final Variable vo5 = smapper.pushT(vi2.getType()); lubomir@585: final Variable vo4 = smapper.pushT(vi1.getType()); lubomir@585: final Variable vo3 = smapper.pushT(vi3.getType()); lubomir@585: final Variable vo2 = smapper.pushT(vi2.getType()); lubomir@585: final Variable vo1 = smapper.pushT(vi1.getType()); lubomir@585: jaroslav@1509: emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6,", lubomir@585: vo1, vi1, vo2, vi2, vo3, vi3); jaroslav@1509: emit(smapper, this, " @1 = @2, @3 = @4;", lubomir@585: vo4, vo1, vo5, vo2); lubomir@585: } else { jaroslav@1509: final Variable vi4 = smapper.pop(this); lubomir@585: final Variable vo6 = smapper.pushT(vi2.getType()); lubomir@585: final Variable vo5 = smapper.pushT(vi1.getType()); lubomir@585: final Variable vo4 = smapper.pushT(vi4.getType()); lubomir@585: final Variable vo3 = smapper.pushT(vi3.getType()); lubomir@585: final Variable vo2 = smapper.pushT(vi2.getType()); lubomir@585: final Variable vo1 = smapper.pushT(vi1.getType()); lubomir@585: jaroslav@1509: emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8,", lubomir@585: vo1, vi1, vo2, vi2, vo3, vi3, vo4, vi4); jaroslav@1509: emit(smapper, this, " @1 = @2, @3 = @4;", lubomir@585: vo5, vo1, vo6, vo2); lubomir@585: } lubomir@585: } lubomir@585: break; lubomir@585: } lubomir@585: case opc_swap: { lubomir@585: final Variable vi1 = smapper.get(0); lubomir@585: final Variable vi2 = smapper.get(1); lubomir@585: lubomir@585: if (vi1.getType() == vi2.getType()) { lubomir@585: final Variable tmp = smapper.pushT(vi1.getType()); lubomir@585: jaroslav@1509: emit(smapper, this, "var @1 = @2, @2 = @3, @3 = @1;", lubomir@585: tmp, vi1, vi2); lubomir@585: smapper.pop(1); lubomir@585: } else { lubomir@585: smapper.pop(2); lubomir@585: smapper.pushT(vi1.getType()); lubomir@585: smapper.pushT(vi2.getType()); lubomir@585: } lubomir@585: break; lubomir@585: } jaroslav@151: case opc_bipush: jaroslav@1509: smapper.assign(this, VarType.INTEGER, jaroslav@1462: "(" + Integer.toString(byteCodes[++i]) + ")"); jaroslav@8: break; jaroslav@151: case opc_sipush: jaroslav@1509: smapper.assign(this, VarType.INTEGER, jaroslav@1462: "(" + Integer.toString(readShortArg(byteCodes, i)) + ")" jaroslav@1462: ); jaroslav@31: i += 2; jaroslav@31: break; jaroslav@151: case opc_getfield: { jaroslav@864: int indx = readUShortArg(byteCodes, i); jaroslav@151: String[] fi = jc.getFieldInfoName(indx); lubomir@307: final int type = VarType.fromFieldType(fi[2].charAt(0)); jaroslav@1409: final String mangleClass = mangleClassName(fi[0]); jaroslav@592: final String mangleClassAccess = accessClass(mangleClass); jaroslav@1513: smapper.replace(this, type, "@2.call(@1)", jaroslav@1477: smapper.getA(0), lubomir@1085: accessField(mangleClassAccess + "(false)", jaroslav@1513: "_" + fi[1], fi) jaroslav@592: ); jaroslav@592: i += 2; jaroslav@592: break; jaroslav@592: } jaroslav@592: case opc_putfield: { jaroslav@864: int indx = readUShortArg(byteCodes, i); jaroslav@592: String[] fi = jc.getFieldInfoName(indx); jaroslav@592: final int type = VarType.fromFieldType(fi[2].charAt(0)); jaroslav@1409: final String mangleClass = mangleClassName(fi[0]); jaroslav@592: final String mangleClassAccess = accessClass(mangleClass); jaroslav@1513: emit(smapper, this, "@3.call(@2, @1);", jaroslav@592: smapper.popT(type), lubomir@1084: smapper.popA(), lubomir@1085: accessField(mangleClassAccess + "(false)", lubomir@1085: "_" + fi[1], fi)); jaroslav@8: i += 2; jaroslav@8: break; jaroslav@8: } jaroslav@151: case opc_getstatic: { jaroslav@864: int indx = readUShortArg(byteCodes, i); jaroslav@151: String[] fi = jc.getFieldInfoName(indx); lubomir@307: final int type = VarType.fromFieldType(fi[2].charAt(0)); jaroslav@1477: String ac = accessClass(mangleClassName(fi[0])); jaroslav@1558: String af = accessField(ac + "(false)", "_" + fi[1], fi); jaroslav@1558: smapper.assign(this, type, af + "()"); jaroslav@9: i += 2; jaroslav@151: addReference(fi[0]); jaroslav@9: break; jaroslav@9: } lubomir@281: case opc_putstatic: { jaroslav@864: int indx = readUShortArg(byteCodes, i); lubomir@281: String[] fi = jc.getFieldInfoName(indx); lubomir@307: final int type = VarType.fromFieldType(fi[2].charAt(0)); jaroslav@1509: emit(smapper, this, "@1(false)._@2(@3);", jaroslav@1409: accessClass(mangleClassName(fi[0])), fi[1], lubomir@317: smapper.popT(type)); lubomir@281: i += 2; lubomir@281: addReference(fi[0]); lubomir@281: break; lubomir@281: } jaroslav@151: case opc_checkcast: { jaroslav@864: int indx = readUShortArg(byteCodes, i); jaroslav@842: generateCheckcast(indx, smapper); jaroslav@30: i += 2; jaroslav@30: break; jaroslav@30: } jaroslav@151: case opc_instanceof: { jaroslav@864: int indx = readUShortArg(byteCodes, i); jaroslav@842: generateInstanceOf(indx, smapper); jaroslav@17: i += 2; jaroslav@30: break; jaroslav@17: } jaroslav@151: case opc_athrow: { jaroslav@1457: final CharSequence v = smapper.popA(); lubomir@307: smapper.clear(); lubomir@281: jaroslav@1509: emit(smapper, this, "{ var @1 = @2; throw @2; }", lubomir@307: smapper.pushA(), v); jaroslav@104: break; jaroslav@104: } lubomir@221: lubomir@221: case opc_monitorenter: { jaroslav@1477: debug("/* monitor enter */"); lubomir@307: smapper.popA(); lubomir@221: break; lubomir@221: } lubomir@221: lubomir@221: case opc_monitorexit: { jaroslav@1477: debug("/* monitor exit */"); lubomir@307: smapper.popA(); lubomir@221: break; lubomir@221: } lubomir@221: lubomir@585: case opc_wide: lubomir@585: wide = true; lubomir@585: break; lubomir@585: jaroslav@104: default: { lubomir@585: wide = false; jaroslav@1509: emit(smapper, this, "throw 'unknown bytecode @1';", lubomir@283: Integer.toString(c)); jaroslav@104: } jaroslav@0: } jaroslav@399: if (debug(" //")) { jaroslav@842: generateByteCodeComment(prev, i, byteCodes); jaroslav@0: } jaroslav@1510: if (outChanged) { jaroslav@1510: append("\n"); jaroslav@1510: } jaroslav@0: } jaroslav@398: if (previousTrap != null) { jaroslav@843: generateCatch(previousTrap, byteCodes.length, topMostLabel); jaroslav@398: } jaroslav@1469: if (didBranches) { jaroslav@1509: append("\n }\n"); jaroslav@1469: } jaroslav@839: while (openBraces-- > 0) { jaroslav@1509: append('}'); jaroslav@839: } jaroslav@1509: append("\n};"); jaroslav@4: } jaroslav@4: jaroslav@1468: private int generateIf(StackMapper mapper, byte[] byteCodes, jaroslav@1468: int i, final CharSequence v2, final CharSequence v1, jaroslav@1468: final String test, int topMostLabel jaroslav@1468: ) throws IOException { jaroslav@1509: mapper.flush(this); jaroslav@864: int indx = i + readShortArg(byteCodes, i); jaroslav@1509: append("if ((").append(v1) jaroslav@1477: .append(") ").append(test).append(" (") jaroslav@1477: .append(v2).append(")) "); jaroslav@1509: goTo(this, i, indx, topMostLabel); jaroslav@4: return i + 2; jaroslav@4: } jaroslav@839: lubomir@697: private int readInt4(byte[] byteCodes, int offset) { lubomir@697: final int d = byteCodes[offset + 0] << 24; lubomir@697: final int c = byteCodes[offset + 1] << 16; lubomir@697: final int b = byteCodes[offset + 2] << 8; lubomir@697: final int a = byteCodes[offset + 3]; jaroslav@115: return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff); jaroslav@115: } jaroslav@864: private static int readUByte(byte[] byteCodes, int offset) { lubomir@697: return byteCodes[offset] & 0xff; jtulach@128: } lubomir@585: jaroslav@864: private static int readUShort(byte[] byteCodes, int offset) { lubomir@697: return ((byteCodes[offset] & 0xff) << 8) lubomir@697: | (byteCodes[offset + 1] & 0xff); lubomir@697: } jaroslav@864: private static int readUShortArg(byte[] byteCodes, int offsetInstruction) { jaroslav@864: return readUShort(byteCodes, offsetInstruction + 1); jaroslav@864: } lubomir@697: jaroslav@864: private static int readShort(byte[] byteCodes, int offset) { jaroslav@864: int signed = byteCodes[offset]; jaroslav@864: byte b0 = (byte)signed; jaroslav@864: return (b0 << 8) | (byteCodes[offset + 1] & 0xff); jaroslav@864: } jaroslav@864: private static int readShortArg(byte[] byteCodes, int offsetInstruction) { jaroslav@864: return readShort(byteCodes, offsetInstruction + 1); lubomir@585: } lubomir@585: lubomir@281: private static void countArgs(String descriptor, char[] returnType, StringBuilder sig, StringBuilder cnt) { jaroslav@4: int i = 0; jaroslav@4: Boolean count = null; jaroslav@32: boolean array = false; jaroslav@248: sig.append("__"); jaroslav@10: int firstPos = sig.length(); jaroslav@4: while (i < descriptor.length()) { jaroslav@4: char ch = descriptor.charAt(i++); jaroslav@4: switch (ch) { jaroslav@4: case '(': jaroslav@4: count = true; jaroslav@4: continue; jaroslav@4: case ')': jaroslav@4: count = false; jaroslav@4: continue; jaroslav@4: case 'B': jaroslav@4: case 'C': jaroslav@4: case 'D': jaroslav@4: case 'F': jaroslav@4: case 'I': jaroslav@4: case 'J': jaroslav@4: case 'S': jaroslav@4: case 'Z': jaroslav@4: if (count) { jaroslav@32: if (array) { jaroslav@248: sig.append("_3"); jaroslav@32: } jaroslav@4: sig.append(ch); jtulach@156: if (ch == 'J' || ch == 'D') { jtulach@156: cnt.append('1'); jtulach@156: } else { jtulach@156: cnt.append('0'); jtulach@156: } jaroslav@4: } else { jaroslav@10: sig.insert(firstPos, ch); jaroslav@32: if (array) { lubomir@281: returnType[0] = '['; jaroslav@248: sig.insert(firstPos, "_3"); lubomir@281: } else { lubomir@281: returnType[0] = ch; jaroslav@32: } jaroslav@4: } jaroslav@93: array = false; jaroslav@4: continue; jaroslav@4: case 'V': jaroslav@4: assert !count; lubomir@281: returnType[0] = 'V'; jaroslav@10: sig.insert(firstPos, 'V'); jaroslav@4: continue; jaroslav@4: case 'L': jaroslav@16: int next = descriptor.indexOf(';', i); jaroslav@248: String realSig = mangleSig(descriptor, i - 1, next + 1); jaroslav@4: if (count) { jaroslav@32: if (array) { jaroslav@248: sig.append("_3"); jaroslav@32: } jaroslav@248: sig.append(realSig); jtulach@156: cnt.append('0'); jaroslav@4: } else { jaroslav@248: sig.insert(firstPos, realSig); jaroslav@32: if (array) { jaroslav@248: sig.insert(firstPos, "_3"); jaroslav@32: } lubomir@281: returnType[0] = 'L'; jaroslav@4: } jaroslav@16: i = next + 1; lubomir@407: array = false; jaroslav@4: continue; jaroslav@4: case '[': jaroslav@248: array = true; jaroslav@4: continue; jaroslav@4: default: jaroslav@248: throw new IllegalStateException("Invalid char: " + ch); jaroslav@4: } jaroslav@4: } jaroslav@0: } jaroslav@248: jaroslav@592: static String mangleSig(String sig) { jaroslav@592: return mangleSig(sig, 0, sig.length()); jaroslav@592: } jaroslav@592: jaroslav@1409: private static String mangleMethodName(String name) { jaroslav@1409: StringBuilder sb = new StringBuilder(name.length() * 2); jaroslav@1409: int last = name.length(); jaroslav@1409: for (int i = 0; i < last; i++) { jaroslav@1409: final char ch = name.charAt(i); jaroslav@1409: switch (ch) { jaroslav@1409: case '_': sb.append("_1"); break; jaroslav@1409: default: sb.append(ch); break; jaroslav@1409: } jaroslav@1409: } jaroslav@1409: return sb.toString(); jaroslav@1409: } jaroslav@248: private static String mangleSig(String txt, int first, int last) { jaroslav@1409: StringBuilder sb = new StringBuilder((last - first) * 2); jaroslav@248: for (int i = first; i < last; i++) { jaroslav@248: final char ch = txt.charAt(i); jaroslav@248: switch (ch) { jaroslav@248: case '/': sb.append('_'); break; jaroslav@248: case '_': sb.append("_1"); break; jaroslav@248: case ';': sb.append("_2"); break; jaroslav@248: case '[': sb.append("_3"); break; jaroslav@1547: default: jaroslav@1547: if (Character.isJavaIdentifierPart(ch)) { jaroslav@1547: sb.append(ch); jaroslav@1547: } else { jaroslav@1547: sb.append("_0"); jaroslav@1547: String hex = Integer.toHexString(ch).toLowerCase(Locale.ENGLISH); jaroslav@1547: for (int m = hex.length(); m < 4; m++) { jaroslav@1547: sb.append("0"); jaroslav@1547: } jaroslav@1547: sb.append(hex); jaroslav@1547: } jaroslav@1547: break; jaroslav@248: } jaroslav@248: } jaroslav@248: return sb.toString(); jaroslav@248: } jaroslav@1409: jaroslav@1409: private static String mangleClassName(String name) { jaroslav@1409: return mangleSig(name); jaroslav@1409: } jaroslav@9: jaroslav@248: private static String findMethodName(MethodData m, StringBuilder cnt) { jaroslav@42: StringBuilder name = new StringBuilder(); jaroslav@10: if ("".equals(m.getName())) { // NOI18N jaroslav@42: name.append("cons"); // NOI18N jaroslav@19: } else if ("".equals(m.getName())) { // NOI18N jaroslav@42: name.append("class"); // NOI18N jaroslav@10: } else { jaroslav@1409: name.append(mangleMethodName(m.getName())); jaroslav@10: } jaroslav@42: lubomir@282: countArgs(m.getInternalSig(), new char[1], name, cnt); jaroslav@42: return name.toString(); jaroslav@10: } jaroslav@10: lubomir@282: static String findMethodName(String[] mi, StringBuilder cnt, char[] returnType) { jaroslav@10: StringBuilder name = new StringBuilder(); jaroslav@151: String descr = mi[2];//mi.getDescriptor(); jaroslav@151: String nm= mi[1]; jaroslav@151: if ("".equals(nm)) { // NOI18N jaroslav@10: name.append("cons"); // NOI18N jaroslav@10: } else { jaroslav@1409: name.append(mangleMethodName(nm)); jaroslav@10: } lubomir@282: countArgs(descr, returnType, name, cnt); jaroslav@10: return name.toString(); jaroslav@10: } jaroslav@10: lubomir@307: private int invokeStaticMethod(byte[] byteCodes, int i, final StackMapper mapper, boolean isStatic) jaroslav@10: throws IOException { jaroslav@864: int methodIndex = readUShortArg(byteCodes, i); jaroslav@151: String[] mi = jc.getFieldInfoName(methodIndex); lubomir@281: char[] returnType = { 'V' }; jtulach@156: StringBuilder cnt = new StringBuilder(); lubomir@281: String mn = findMethodName(mi, cnt, returnType); lubomir@221: lubomir@221: final int numArguments = isStatic ? cnt.length() : cnt.length() + 1; jaroslav@1457: final CharSequence[] vars = new CharSequence[numArguments]; lubomir@221: lubomir@281: for (int j = numArguments - 1; j >= 0; --j) { jaroslav@1457: vars[j] = mapper.popValue(); jaroslav@11: } lubomir@281: lubomir@281: if (returnType[0] != 'V') { jaroslav@1595: mapper.flush(this); jaroslav@1509: append("var ") lubomir@474: .append(mapper.pushT(VarType.fromFieldType(returnType[0]))) lubomir@281: .append(" = "); jaroslav@10: } lubomir@221: jaroslav@151: final String in = mi[0]; jaroslav@1515: String mcn; jaroslav@1515: if (callbacks && in.equals("org/apidesign/html/boot/spi/Fn")) { jaroslav@1515: mcn = "java_lang_Class"; jaroslav@1515: } else { jaroslav@1515: mcn = mangleClassName(in); jaroslav@1515: } jaroslav@1515: String object = accessClass(mcn) + "(false)"; jaroslav@397: if (mn.startsWith("cons_")) { lubomir@1094: object += ".constructor"; jaroslav@397: } jaroslav@1513: append(accessStaticMethod(object, mn, mi)); jaroslav@442: if (isStatic) { jaroslav@1509: append('('); jaroslav@442: } else { jaroslav@1509: append(".call("); jaroslav@442: } lubomir@221: if (numArguments > 0) { jaroslav@1509: append(vars[0]); lubomir@281: for (int j = 1; j < numArguments; ++j) { jaroslav@1509: append(", "); jaroslav@1509: append(vars[j]); lubomir@221: } jaroslav@10: } jaroslav@1509: append(");"); jaroslav@10: i += 2; jaroslav@18: addReference(in); jaroslav@10: return i; jaroslav@10: } lubomir@307: private int invokeVirtualMethod(byte[] byteCodes, int i, final StackMapper mapper) jaroslav@12: throws IOException { jaroslav@864: int methodIndex = readUShortArg(byteCodes, i); jaroslav@151: String[] mi = jc.getFieldInfoName(methodIndex); lubomir@281: char[] returnType = { 'V' }; jtulach@156: StringBuilder cnt = new StringBuilder(); lubomir@281: String mn = findMethodName(mi, cnt, returnType); lubomir@221: lubomir@281: final int numArguments = cnt.length() + 1; jaroslav@1458: final CharSequence[] vars = new CharSequence[numArguments]; lubomir@221: lubomir@281: for (int j = numArguments - 1; j >= 0; --j) { jaroslav@1458: vars[j] = mapper.popValue(); jaroslav@12: } lubomir@221: lubomir@281: if (returnType[0] != 'V') { jaroslav@1509: append("var ") lubomir@474: .append(mapper.pushT(VarType.fromFieldType(returnType[0]))) lubomir@281: .append(" = "); jaroslav@12: } lubomir@281: jaroslav@1513: append(accessVirtualMethod(vars[0].toString(), mn, mi)); jaroslav@1509: append('('); jaroslav@442: String sep = ""; lubomir@281: for (int j = 1; j < numArguments; ++j) { jaroslav@1509: append(sep); jaroslav@1509: append(vars[j]); jaroslav@442: sep = ", "; jaroslav@12: } jaroslav@1509: append(");"); jaroslav@12: i += 2; jaroslav@12: return i; jaroslav@12: } lubomir@221: jaroslav@103: private void addReference(String cn) throws IOException { jtulach@162: if (requireReference(cn)) { jaroslav@399: debug(" /* needs " + cn + " */"); jaroslav@18: } jaroslav@18: } jaroslav@16: jaroslav@33: private void outType(String d, StringBuilder out) { jaroslav@33: int arr = 0; jaroslav@33: while (d.charAt(0) == '[') { jaroslav@33: out.append('A'); jaroslav@33: d = d.substring(1); jaroslav@33: } jaroslav@16: if (d.charAt(0) == 'L') { jaroslav@16: assert d.charAt(d.length() - 1) == ';'; jaroslav@16: out.append(d.replace('/', '_').substring(0, d.length() - 1)); jaroslav@16: } else { jaroslav@16: out.append(d); jaroslav@16: } jaroslav@16: } jaroslav@21: jaroslav@230: private String encodeConstant(int entryIndex) throws IOException { jaroslav@230: String[] classRef = { null }; jaroslav@230: String s = jc.stringValue(entryIndex, classRef); jaroslav@230: if (classRef[0] != null) { jaroslav@567: if (classRef[0].startsWith("[")) { jaroslav@1513: s = accessClass("java_lang_Class") + "(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('" + classRef[0] + "')"; jaroslav@567: } else { jaroslav@567: addReference(classRef[0]); jaroslav@1409: s = accessClass(mangleClassName(s)) + "(false).constructor.$class"; jaroslav@567: } jaroslav@230: } jaroslav@151: return s; jaroslav@21: } jaroslav@32: lubomir@869: private String javaScriptBody(String destObject, MethodData m, boolean isStatic) throws IOException { jaroslav@152: byte[] arr = m.findAnnotationData(true); jaroslav@152: if (arr == null) { jaroslav@266: return null; jaroslav@152: } jaroslav@200: final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;"; jaroslav@1239: final String htmlType = "Lnet/java/html/js/JavaScriptBody;"; jaroslav@152: class P extends AnnotationParser { jaroslav@237: public P() { jaroslav@652: super(false, true); jaroslav@237: } jaroslav@237: jaroslav@152: int cnt; jaroslav@152: String[] args = new String[30]; jaroslav@152: String body; jaroslav@1241: boolean javacall; jaroslav@1421: boolean html4j; jaroslav@94: jaroslav@152: @Override jaroslav@236: protected void visitAttr(String type, String attr, String at, String value) { jaroslav@152: if (type.equals(jvmType)) { jaroslav@152: if ("body".equals(attr)) { jaroslav@152: body = value; jaroslav@152: } else if ("args".equals(attr)) { jaroslav@152: args[cnt++] = value; jaroslav@152: } else { jaroslav@152: throw new IllegalArgumentException(attr); jaroslav@152: } jaroslav@152: } jaroslav@1239: if (type.equals(htmlType)) { jaroslav@1421: html4j = true; jaroslav@1239: if ("body".equals(attr)) { jaroslav@1239: body = value; jaroslav@1239: } else if ("args".equals(attr)) { jaroslav@1239: args[cnt++] = value; jaroslav@1241: } else if ("javacall".equals(attr)) { jaroslav@1241: javacall = "1".equals(value); jaroslav@1239: } else { jaroslav@1239: throw new IllegalArgumentException(attr); jaroslav@1239: } jaroslav@1239: } jaroslav@94: } jaroslav@94: } jaroslav@152: P p = new P(); jaroslav@152: p.parse(arr, jc); jaroslav@152: if (p.body == null) { jaroslav@266: return null; jaroslav@152: } jtulach@156: StringBuilder cnt = new StringBuilder(); jaroslav@266: final String mn = findMethodName(m, cnt); jaroslav@1509: append(destObject).append(".").append(mn); jaroslav@1509: append(" = function("); jaroslav@442: String space = ""; jaroslav@443: int index = 0; jaroslav@1421: StringBuilder toValue = new StringBuilder(); jtulach@156: for (int i = 0; i < cnt.length(); i++) { jaroslav@1509: append(space); jaroslav@1509: space = outputArg(this, p.args, index); jaroslav@1421: if (p.html4j && space.length() > 0) { jaroslav@1515: toValue.append("\n ").append(p.args[index]).append(" = ") jaroslav@1515: .append(accessClass("java_lang_Class")).append("(false).toJS("). jaroslav@1421: append(p.args[index]).append(");"); jaroslav@1421: } jaroslav@152: index++; jaroslav@152: } jaroslav@1509: append(") {").append("\n"); jaroslav@1509: append(toValue.toString()); jaroslav@1242: if (p.javacall) { jaroslav@1242: int lastSlash = jc.getClassName().lastIndexOf('/'); jaroslav@1242: final String pkg = jc.getClassName().substring(0, lastSlash); jaroslav@1509: append(mangleCallbacks(pkg, p.body)); jaroslav@1242: requireReference(pkg + "/$JsCallbacks$"); jaroslav@1242: } else { jaroslav@1509: append(p.body); jaroslav@1242: } jaroslav@1509: append("\n}\n"); jaroslav@266: return mn; jaroslav@151: } jaroslav@1242: jaroslav@1242: private static CharSequence mangleCallbacks(String pkgName, String body) { jaroslav@1242: StringBuilder sb = new StringBuilder(); jaroslav@1242: int pos = 0; jaroslav@1242: for (;;) { jaroslav@1242: int next = body.indexOf(".@", pos); jaroslav@1242: if (next == -1) { jaroslav@1242: sb.append(body.substring(pos)); jaroslav@1243: body = sb.toString(); jaroslav@1243: break; jaroslav@1242: } jaroslav@1242: int ident = next; jaroslav@1242: while (ident > 0) { jaroslav@1242: if (!Character.isJavaIdentifierPart(body.charAt(--ident))) { jaroslav@1242: ident++; jaroslav@1242: break; jaroslav@1242: } jaroslav@1242: } jaroslav@1242: String refId = body.substring(ident, next); jaroslav@1242: jaroslav@1242: sb.append(body.substring(pos, ident)); jaroslav@1242: jaroslav@1242: int sigBeg = body.indexOf('(', next); jaroslav@1242: int sigEnd = body.indexOf(')', sigBeg); jaroslav@1242: int colon4 = body.indexOf("::", next); jaroslav@1242: if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) { jaroslav@1242: throw new IllegalStateException("Malformed body " + body); jaroslav@1242: } jaroslav@1242: String fqn = body.substring(next + 2, colon4); jaroslav@1242: String method = body.substring(colon4 + 2, sigBeg); jaroslav@1242: String params = body.substring(sigBeg, sigEnd + 1); jaroslav@1242: jaroslav@1242: int paramBeg = body.indexOf('(', sigEnd + 1); jaroslav@1242: jaroslav@1242: sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM()."); jaroslav@1409: sb.append(mangleJsCallbacks(fqn, method, params, false)); jaroslav@1242: sb.append("(").append(refId); jaroslav@1242: if (body.charAt(paramBeg + 1) != ')') { jaroslav@1242: sb.append(","); jaroslav@1242: } jaroslav@1242: pos = paramBeg + 1; jaroslav@1242: } jaroslav@1243: sb = null; jaroslav@1243: pos = 0; jaroslav@1243: for (;;) { jaroslav@1243: int next = body.indexOf("@", pos); jaroslav@1243: if (next == -1) { jaroslav@1243: if (sb == null) { jaroslav@1243: return body; jaroslav@1243: } jaroslav@1243: sb.append(body.substring(pos)); jaroslav@1243: return sb; jaroslav@1243: } jaroslav@1243: if (sb == null) { jaroslav@1243: sb = new StringBuilder(); jaroslav@1243: } jaroslav@1243: jaroslav@1243: sb.append(body.substring(pos, next)); jaroslav@1243: jaroslav@1243: int sigBeg = body.indexOf('(', next); jaroslav@1243: int sigEnd = body.indexOf(')', sigBeg); jaroslav@1243: int colon4 = body.indexOf("::", next); jaroslav@1243: if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) { jaroslav@1243: throw new IllegalStateException("Malformed body " + body); jaroslav@1243: } jaroslav@1243: String fqn = body.substring(next + 1, colon4); jaroslav@1243: String method = body.substring(colon4 + 2, sigBeg); jaroslav@1243: String params = body.substring(sigBeg, sigEnd + 1); jaroslav@1243: jaroslav@1243: int paramBeg = body.indexOf('(', sigEnd + 1); jaroslav@1243: jaroslav@1243: sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM()."); jaroslav@1409: sb.append(mangleJsCallbacks(fqn, method, params, true)); jaroslav@1243: sb.append("("); jaroslav@1243: pos = paramBeg + 1; jaroslav@1243: } jaroslav@1242: } jaroslav@1409: jaroslav@1409: static String mangleJsCallbacks(String fqn, String method, String params, boolean isStatic) { jaroslav@1242: if (params.startsWith("(")) { jaroslav@1242: params = params.substring(1); jaroslav@1242: } jaroslav@1242: if (params.endsWith(")")) { jaroslav@1242: params = params.substring(0, params.length() - 1); jaroslav@1242: } jaroslav@1243: StringBuilder sb = new StringBuilder(); jaroslav@1409: final String fqnu = fqn.replace('.', '_'); jaroslav@1409: final String rfqn = mangleClassName(fqnu); jaroslav@1409: final String rm = mangleMethodName(method); jaroslav@1427: final String srp; jaroslav@1427: { jaroslav@1427: StringBuilder pb = new StringBuilder(); jaroslav@1427: int len = params.length(); jaroslav@1427: int indx = 0; jaroslav@1427: while (indx < len) { jaroslav@1427: char ch = params.charAt(indx); jaroslav@1427: if (ch == '[' || ch == 'L') { jaroslav@1427: pb.append("Ljava/lang/Object;"); jaroslav@1427: indx = params.indexOf(';', indx) + 1; jaroslav@1427: } else { jaroslav@1427: pb.append(ch); jaroslav@1427: indx++; jaroslav@1427: } jaroslav@1427: } jaroslav@1427: srp = mangleSig(pb.toString()); jaroslav@1427: } jaroslav@1409: final String rp = mangleSig(params); jaroslav@1409: final String mrp = mangleMethodName(rp); jaroslav@1248: sb.append(rfqn).append("$").append(rm). jaroslav@1409: append('$').append(mrp).append("__Ljava_lang_Object_2"); jaroslav@1243: if (!isStatic) { jaroslav@1409: sb.append('L').append(fqnu).append("_2"); jaroslav@1243: } jaroslav@1427: sb.append(srp); jaroslav@1243: return sb.toString(); jaroslav@1242: } jaroslav@1242: jaroslav@151: private static String className(ClassData jc) { jaroslav@151: //return jc.getName().getInternalName().replace('/', '_'); jaroslav@1409: return mangleClassName(jc.getClassName()); jaroslav@94: } jaroslav@152: jaroslav@152: private static String[] findAnnotation( jaroslav@152: byte[] arr, ClassData cd, final String className, jaroslav@152: final String... attrNames jaroslav@152: ) throws IOException { jaroslav@152: if (arr == null) { jaroslav@152: return null; jaroslav@152: } jaroslav@152: final String[] values = new String[attrNames.length]; jaroslav@152: final boolean[] found = { false }; jaroslav@152: final String jvmType = "L" + className.replace('.', '/') + ";"; jaroslav@652: AnnotationParser ap = new AnnotationParser(false, true) { jaroslav@152: @Override jaroslav@236: protected void visitAttr(String type, String attr, String at, String value) { jaroslav@152: if (type.equals(jvmType)) { jaroslav@152: found[0] = true; jaroslav@152: for (int i = 0; i < attrNames.length; i++) { jaroslav@152: if (attrNames[i].equals(attr)) { jaroslav@152: values[i] = value; jaroslav@152: } jaroslav@152: } jaroslav@152: } jaroslav@152: } jaroslav@152: jaroslav@152: }; jaroslav@152: ap.parse(arr, cd); jaroslav@152: return found[0] ? values : null; jaroslav@152: } jaroslav@173: jaroslav@173: private CharSequence initField(FieldData v) { jaroslav@173: final String is = v.getInternalSig(); jaroslav@173: if (is.length() == 1) { jaroslav@173: switch (is.charAt(0)) { jaroslav@173: case 'S': jaroslav@173: case 'J': jaroslav@173: case 'B': jaroslav@173: case 'Z': jaroslav@173: case 'C': jaroslav@173: case 'I': return " = 0;"; jaroslav@173: case 'F': jaroslav@180: case 'D': return " = 0.0;"; jaroslav@173: default: jaroslav@173: throw new IllegalStateException(is); jaroslav@173: } jaroslav@173: } jaroslav@173: return " = null;"; jaroslav@173: } jaroslav@235: jaroslav@1509: private void generateAnno(ClassData cd, byte[] data) throws IOException { jaroslav@652: AnnotationParser ap = new AnnotationParser(true, false) { jaroslav@652: int[] cnt = new int[32]; jaroslav@652: int depth; jaroslav@235: jaroslav@235: @Override jaroslav@659: protected void visitAnnotationStart(String attrType, boolean top) throws IOException { jaroslav@659: final String slashType = attrType.substring(1, attrType.length() - 1); jaroslav@659: requireReference(slashType); jaroslav@659: jaroslav@652: if (cnt[depth]++ > 0) { jaroslav@1509: append(","); jaroslav@237: } jaroslav@659: if (top) { jaroslav@1509: append('"').append(attrType).append("\" : "); jaroslav@659: } jaroslav@1509: append("{\n"); jaroslav@652: cnt[++depth] = 0; jaroslav@235: } jaroslav@235: jaroslav@235: @Override jaroslav@659: protected void visitAnnotationEnd(String type, boolean top) throws IOException { jaroslav@1509: append("\n}\n"); jaroslav@652: depth--; jaroslav@652: } jaroslav@652: jaroslav@652: @Override jaroslav@652: protected void visitValueStart(String attrName, char type) throws IOException { jaroslav@652: if (cnt[depth]++ > 0) { jaroslav@1509: append(",\n"); jaroslav@652: } jaroslav@652: cnt[++depth] = 0; jaroslav@652: if (attrName != null) { jaroslav@1564: append('"').append(attrName).append("\" : "); jaroslav@652: } jaroslav@652: if (type == '[') { jaroslav@1509: append("["); jaroslav@652: } jaroslav@652: } jaroslav@652: jaroslav@652: @Override jaroslav@652: protected void visitValueEnd(String attrName, char type) throws IOException { jaroslav@652: if (type == '[') { jaroslav@1509: append("]"); jaroslav@652: } jaroslav@652: depth--; jaroslav@235: } jaroslav@235: jaroslav@235: @Override jaroslav@236: protected void visitAttr(String type, String attr, String attrType, String value) jaroslav@235: throws IOException { jaroslav@652: if (attr == null && value == null) { jaroslav@266: return; jaroslav@266: } jaroslav@1509: append(value); jaroslav@592: } jaroslav@655: jaroslav@655: @Override jaroslav@655: protected void visitEnumAttr(String type, String attr, String attrType, String value) jaroslav@655: throws IOException { jaroslav@655: final String slashType = attrType.substring(1, attrType.length() - 1); jaroslav@655: requireReference(slashType); jaroslav@655: jaroslav@1564: final String cn = mangleClassName(slashType); jaroslav@1564: append(accessClass(cn)) jaroslav@1564: .append("(false)['valueOf__L"). jaroslav@1564: append(cn). jaroslav@1564: append("_2Ljava_lang_String_2']('"). jaroslav@1564: append(value). jaroslav@1564: append("')"); jaroslav@235: } jaroslav@235: }; jaroslav@235: ap.parse(data, cd); jaroslav@235: } jaroslav@316: jaroslav@316: private static String outputArg(Appendable out, String[] args, int indx) throws IOException { jaroslav@316: final String name = args[indx]; jaroslav@316: if (name == null) { jaroslav@316: return ""; jaroslav@316: } jaroslav@316: if (name.contains(",")) { jaroslav@316: throw new IOException("Wrong parameter with ',': " + name); jaroslav@316: } jaroslav@316: out.append(name); jaroslav@316: return ","; jaroslav@316: } lubomir@317: jaroslav@1466: final void emitNoFlush( jaroslav@1466: StackMapper sm, jaroslav@1466: final String format, final CharSequence... params jaroslav@1466: ) throws IOException { jaroslav@1509: emitImpl(this, format, params); jaroslav@1466: } jaroslav@1509: static final void emit( jaroslav@1455: StackMapper sm, jaroslav@1455: final Appendable out, jaroslav@1455: final String format, final CharSequence... params jaroslav@1455: ) throws IOException { jaroslav@1455: sm.flush(out); jaroslav@1455: emitImpl(out, format, params); jaroslav@1455: } jaroslav@1455: static void emitImpl(final Appendable out, lubomir@283: final String format, lubomir@283: final CharSequence... params) throws IOException { lubomir@283: final int length = format.length(); lubomir@283: lubomir@283: int processed = 0; lubomir@283: int paramOffset = format.indexOf('@'); lubomir@283: while ((paramOffset != -1) && (paramOffset < (length - 1))) { lubomir@283: final char paramChar = format.charAt(paramOffset + 1); lubomir@283: if ((paramChar >= '1') && (paramChar <= '9')) { lubomir@283: final int paramIndex = paramChar - '0' - 1; lubomir@283: lubomir@283: out.append(format, processed, paramOffset); lubomir@283: out.append(params[paramIndex]); lubomir@283: lubomir@283: ++paramOffset; lubomir@283: processed = paramOffset + 1; lubomir@283: } lubomir@283: lubomir@283: paramOffset = format.indexOf('@', paramOffset + 1); lubomir@283: } lubomir@283: lubomir@283: out.append(format, processed, length); lubomir@283: } jaroslav@398: jaroslav@843: private void generateCatch(TrapData[] traps, int current, int topMostLabel) throws IOException { jaroslav@1509: append("} catch (e) {\n"); jaroslav@401: int finallyPC = -1; jaroslav@398: for (TrapData e : traps) { jaroslav@398: if (e == null) { jaroslav@398: break; jaroslav@398: } jaroslav@398: if (e.catch_cpx != 0) { //not finally jaroslav@398: final String classInternalName = jc.getClassName(e.catch_cpx); jaroslav@398: addReference(classInternalName); jaroslav@1522: append("e = vm.java_lang_Class(false).bck2BrwsrThrwrbl(e);"); jaroslav@1513: append("if (e['$instOf_" + classInternalName.replace('/', '_') + "']) {"); jaroslav@1509: append("var stA0 = e;"); jaroslav@1509: goTo(this, current, e.handler_pc, topMostLabel); jaroslav@1509: append("}\n"); jaroslav@398: } else { jaroslav@401: finallyPC = e.handler_pc; jaroslav@398: } jaroslav@398: } jaroslav@401: if (finallyPC == -1) { jaroslav@1509: append("throw e;"); jaroslav@401: } else { jaroslav@1509: append("var stA0 = e;"); jaroslav@1509: goTo(this, current, finallyPC, topMostLabel); jaroslav@401: } jaroslav@1509: append("\n}"); jaroslav@398: } jaroslav@839: jaroslav@843: private static void goTo(Appendable out, int current, int to, int canBack) throws IOException { jaroslav@839: if (to < current) { jaroslav@843: if (canBack < to) { jaroslav@843: out.append("{ gt = 0; continue X_" + to + "; }"); jaroslav@843: } else { jaroslav@843: out.append("{ gt = " + to + "; continue X_0; }"); jaroslav@843: } jaroslav@839: } else { jaroslav@839: out.append("{ gt = " + to + "; break IF; }"); jaroslav@839: } jaroslav@839: } jaroslav@839: jaroslav@843: private static void emitIf( jaroslav@1455: StackMapper sm, jaroslav@1455: Appendable out, String pattern, jaroslav@1457: CharSequence param, jaroslav@843: int current, int to, int canBack jaroslav@843: ) throws IOException { jaroslav@1455: sm.flush(out); jaroslav@1455: emitImpl(out, pattern, param); jaroslav@843: goTo(out, current, to, canBack); jaroslav@839: } jaroslav@842: jaroslav@842: private void generateNewArray(int atype, final StackMapper smapper) throws IOException, IllegalStateException { jaroslav@842: String jvmType; jaroslav@842: switch (atype) { jaroslav@842: case 4: jvmType = "[Z"; break; jaroslav@842: case 5: jvmType = "[C"; break; jaroslav@842: case 6: jvmType = "[F"; break; jaroslav@842: case 7: jvmType = "[D"; break; jaroslav@842: case 8: jvmType = "[B"; break; jaroslav@842: case 9: jvmType = "[S"; break; jaroslav@842: case 10: jvmType = "[I"; break; jaroslav@842: case 11: jvmType = "[J"; break; jaroslav@842: default: throw new IllegalStateException("Array type: " + atype); jaroslav@842: } jaroslav@1513: emit(smapper, this, jaroslav@1532: "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2Ljava_lang_Object_2I'](true, '@3', null, @1);", jaroslav@842: smapper.popI(), smapper.pushA(), jvmType); jaroslav@842: } jaroslav@842: jaroslav@842: private void generateANewArray(int type, final StackMapper smapper) throws IOException { jaroslav@842: String typeName = jc.getClassName(type); jaroslav@1532: String ref = "null"; jaroslav@842: if (typeName.startsWith("[")) { jaroslav@1532: typeName = "'[" + typeName + "'"; jaroslav@842: } else { jaroslav@1532: ref = "vm." + mangleClassName(typeName); jaroslav@1532: typeName = "'[L" + typeName + ";'"; jaroslav@842: } jaroslav@1513: emit(smapper, this, jaroslav@1532: "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2Ljava_lang_Object_2I'](false, @3, @4, @1);", jaroslav@1532: smapper.popI(), smapper.pushA(), typeName, ref); jaroslav@842: } jaroslav@842: jaroslav@842: private int generateMultiANewArray(int type, final byte[] byteCodes, int i, final StackMapper smapper) throws IOException { jaroslav@842: String typeName = jc.getClassName(type); jaroslav@842: int dim = readUByte(byteCodes, ++i); jaroslav@842: StringBuilder dims = new StringBuilder(); jaroslav@842: dims.append('['); jaroslav@842: for (int d = 0; d < dim; d++) { jaroslav@842: if (d != 0) { jaroslav@842: dims.insert(1, ","); jaroslav@842: } jaroslav@842: dims.insert(1, smapper.popI()); jaroslav@842: } jaroslav@842: dims.append(']'); jaroslav@1535: String fn = "null"; jaroslav@1535: if (typeName.charAt(dim) == 'L') { jaroslav@1535: fn = "vm." + mangleClassName(typeName.substring(dim + 1, typeName.length() - 1)); jaroslav@1535: } jaroslav@1513: emit(smapper, this, jaroslav@1535: "var @2 = Array.prototype['multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3ILjava_lang_Object_2']('@3', @1, @4);", jaroslav@1535: dims.toString(), smapper.pushA(), typeName, fn jaroslav@1535: ); jaroslav@842: return i; jaroslav@842: } jaroslav@842: jaroslav@843: private int generateTableSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException { jaroslav@842: int table = i / 4 * 4 + 4; jaroslav@842: int dflt = i + readInt4(byteCodes, table); jaroslav@842: table += 4; jaroslav@842: int low = readInt4(byteCodes, table); jaroslav@842: table += 4; jaroslav@842: int high = readInt4(byteCodes, table); jaroslav@842: table += 4; jaroslav@1477: final CharSequence swVar = smapper.popValue(); jaroslav@1509: smapper.flush(this); jaroslav@1509: append("switch (").append(swVar).append(") {\n"); jaroslav@842: while (low <= high) { jaroslav@842: int offset = i + readInt4(byteCodes, table); jaroslav@842: table += 4; jaroslav@1509: append(" case " + low).append(":"); goTo(this, i, offset, topMostLabel); append('\n'); jaroslav@842: low++; jaroslav@842: } jaroslav@1509: append(" default: "); jaroslav@1509: goTo(this, i, dflt, topMostLabel); jaroslav@1509: append("\n}"); jaroslav@842: i = table - 1; jaroslav@842: return i; jaroslav@842: } jaroslav@842: jaroslav@843: private int generateLookupSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException { jaroslav@842: int table = i / 4 * 4 + 4; jaroslav@842: int dflt = i + readInt4(byteCodes, table); jaroslav@842: table += 4; jaroslav@842: int n = readInt4(byteCodes, table); jaroslav@842: table += 4; jaroslav@1477: final CharSequence swVar = smapper.popValue(); jaroslav@1509: smapper.flush(this); jaroslav@1509: append("switch (").append(swVar).append(") {\n"); jaroslav@842: while (n-- > 0) { jaroslav@842: int cnstnt = readInt4(byteCodes, table); jaroslav@842: table += 4; jaroslav@842: int offset = i + readInt4(byteCodes, table); jaroslav@842: table += 4; jaroslav@1509: append(" case " + cnstnt).append(": "); goTo(this, i, offset, topMostLabel); append('\n'); jaroslav@842: } jaroslav@1509: append(" default: "); jaroslav@1509: goTo(this, i, dflt, topMostLabel); jaroslav@1509: append("\n}"); jaroslav@842: i = table - 1; jaroslav@842: return i; jaroslav@842: } jaroslav@842: jaroslav@842: private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException { jaroslav@1534: String type = jc.getClassName(indx); jaroslav@842: if (!type.startsWith("[")) { jaroslav@1513: emit(smapper, this, jaroslav@1513: "var @2 = @1 != null && @1['$instOf_@3'] ? 1 : 0;", jaroslav@842: smapper.popA(), smapper.pushI(), jaroslav@842: type.replace('/', '_')); jaroslav@842: } else { jaroslav@1534: int cnt = 0; jaroslav@1534: while (type.charAt(cnt) == '[') { jaroslav@1534: cnt++; jaroslav@1534: } jaroslav@1534: if (type.charAt(cnt) == 'L') { jaroslav@1534: type = "vm." + mangleClassName(type.substring(cnt + 1, type.length() - 1)); jaroslav@1534: emit(smapper, this, jaroslav@1534: "var @2 = Array.prototype['isInstance__ZLjava_lang_Object_2ILjava_lang_Object_2'](@1, @4, @3);", jaroslav@1534: smapper.popA(), smapper.pushI(), jaroslav@1534: type, "" + cnt jaroslav@1534: ); jaroslav@1534: } else { jaroslav@1534: emit(smapper, this, jaroslav@1534: "var @2 = Array.prototype['isInstance__ZLjava_lang_Object_2Ljava_lang_String_2'](@1, '@3');", jaroslav@1534: smapper.popA(), smapper.pushI(), type jaroslav@1534: ); jaroslav@1534: } jaroslav@842: } jaroslav@842: } jaroslav@842: jaroslav@842: private void generateCheckcast(int indx, final StackMapper smapper) throws IOException { jaroslav@1534: String type = jc.getClassName(indx); jaroslav@842: if (!type.startsWith("[")) { jaroslav@1509: emitNoFlush(smapper, lubomir@1082: "if (@1 !== null && !@1['$instOf_@2']) throw vm.java_lang_ClassCastException(true);", jaroslav@1466: smapper.getT(0, VarType.REFERENCE, false), type.replace('/', '_')); jaroslav@842: } else { jaroslav@1534: int cnt = 0; jaroslav@1534: while (type.charAt(cnt) == '[') { jaroslav@1534: cnt++; jaroslav@1534: } jaroslav@1534: if (type.charAt(cnt) == 'L') { jaroslav@1534: type = "vm." + mangleClassName(type.substring(cnt + 1, type.length() - 1)); jaroslav@1534: emitNoFlush(smapper, jaroslav@1534: "if (@1 !== null && !Array.prototype['isInstance__ZLjava_lang_Object_2ILjava_lang_Object_2'](@1, @3, @2)) throw vm.java_lang_ClassCastException(true);", jaroslav@1534: smapper.getT(0, VarType.REFERENCE, false), type, "" + cnt jaroslav@1534: ); jaroslav@1534: } else { jaroslav@1534: emitNoFlush(smapper, jaroslav@1534: "if (@1 !== null && !Array.prototype['isInstance__ZLjava_lang_Object_2Ljava_lang_String_2'](@1, '@2')) throw vm.java_lang_ClassCastException(true);", jaroslav@1534: smapper.getT(0, VarType.REFERENCE, false), type jaroslav@1534: ); jaroslav@1534: } jaroslav@842: } jaroslav@842: } jaroslav@842: jaroslav@842: private void generateByteCodeComment(int prev, int i, final byte[] byteCodes) throws IOException { jaroslav@842: for (int j = prev; j <= i; j++) { jaroslav@1509: append(" "); jaroslav@842: final int cc = readUByte(byteCodes, j); jaroslav@1509: append(Integer.toString(cc)); jaroslav@842: } jaroslav@842: } jaroslav@0: }