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; jtulach@167: import org.apidesign.javap.AnnotationParser; jtulach@167: import org.apidesign.javap.ClassData; jtulach@167: import org.apidesign.javap.FieldData; jtulach@167: import org.apidesign.javap.MethodData; lubomir@221: import org.apidesign.javap.StackMapIterator; jtulach@167: import static org.apidesign.javap.RuntimeConstants.*; tzezula@287: import org.apidesign.javap.TrapData; jaroslav@288: import org.apidesign.javap.TrapDataIterator; jaroslav@0: jaroslav@0: /** Translator of the code inside class files to JavaScript. jaroslav@0: * jaroslav@0: * @author Jaroslav Tulach jaroslav@0: */ jaroslav@298: abstract class ByteCodeToJavaScript { jtulach@162: private ClassData jc; jaroslav@272: final Appendable out; jaroslav@0: jtulach@162: protected ByteCodeToJavaScript(Appendable out) { jaroslav@0: this.out = out; jaroslav@0: } jtulach@162: 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: */ jtulach@162: protected abstract void requireScript(String resourcePath); 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: } jaroslav@399: 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@399: out.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 { jtulach@162: this.jc = new ClassData(classFile); 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@170: String[] arr = findAnnotation(arrData, jc, jaroslav@170: "org.apidesign.bck2brwsr.core.ExtraJavaScript", jaroslav@170: "resource", "processByteCode" jaroslav@170: ); jaroslav@152: if (arr != null) { jtulach@162: requireScript(arr[0]); jaroslav@152: if ("0".equals(arr[1])) { jaroslav@97: return null; 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@213: out.append("\n\n").append(assignClass(className)); jaroslav@213: out.append("function CLS() {"); jaroslav@213: out.append("\n if (!CLS.prototype.$instOf_").append(className).append(") {"); jtulach@191: for (FieldData v : jc.getFields()) { jtulach@191: if (v.isStatic()) { jaroslav@213: out.append("\n CLS.").append(v.getName()).append(initField(v)); jtulach@191: } jtulach@191: } jaroslav@239: if (proto == null) { jaroslav@239: String sc = jc.getSuperClassName(); // with _ jaroslav@230: out.append("\n var pp = "). jaroslav@274: append(accessClass(sc.replace('/', '_'))).append("(true);"); jaroslav@230: out.append("\n var p = CLS.prototype = pp;"); jaroslav@239: out.append("\n var c = p;"); jaroslav@230: out.append("\n var sprcls = pp.constructor.$class;"); jtulach@130: } else { jaroslav@240: out.append("\n var p = CLS.prototype = ").append(proto[1]).append(";"); jaroslav@316: if (proto[0] == null) { jaroslav@316: proto[0] = "p"; jaroslav@316: } jaroslav@239: out.append("\n var c = ").append(proto[0]).append(";"); jaroslav@230: out.append("\n var sprcls = null;"); jaroslav@13: } jaroslav@151: for (MethodData m : jc.getMethods()) { jaroslav@240: byte[] onlyArr = m.findAnnotationData(true); jaroslav@240: String[] only = findAnnotation(onlyArr, jc, jaroslav@240: "org.apidesign.bck2brwsr.core.JavaScriptOnly", jaroslav@240: "name", "value" jaroslav@240: ); jaroslav@240: if (only != null) { jaroslav@240: if (only[0] != null && only[1] != null) { jaroslav@240: out.append("\n p.").append(only[0]).append(" = ") jaroslav@240: .append(only[1]).append(";"); jaroslav@240: } jaroslav@240: continue; jaroslav@240: } jaroslav@397: String prefix; jaroslav@266: String mn; jaroslav@203: if (m.isStatic()) { jaroslav@397: prefix = "\n c."; jaroslav@397: mn = generateStaticMethod(prefix, m, toInitilize); jaroslav@203: } else { jaroslav@397: if (m.isConstructor()) { jaroslav@397: prefix = "\n CLS."; jaroslav@397: mn = generateInstanceMethod(prefix, m); jaroslav@397: } else { jaroslav@397: prefix = "\n c."; jaroslav@397: mn = generateInstanceMethod(prefix, m); jaroslav@397: } jaroslav@266: } jaroslav@266: byte[] runAnno = m.findAnnotationData(false); jaroslav@266: if (runAnno != null) { jaroslav@397: out.append(prefix).append(mn).append(".anno = {"); jaroslav@266: generateAnno(jc, out, runAnno); jaroslav@266: out.append("\n };"); jaroslav@38: } jaroslav@397: out.append(prefix).append(mn).append(".access = " + m.getAccess()).append(";"); jaroslav@38: } jaroslav@239: out.append("\n c.constructor = CLS;"); jaroslav@239: out.append("\n c.$instOf_").append(className).append(" = true;"); jaroslav@151: for (String superInterface : jc.getSuperInterfaces()) { jaroslav@239: out.append("\n c.$instOf_").append(superInterface.replace('/', '_')).append(" = true;"); jaroslav@40: } jaroslav@274: out.append("\n CLS.$class = "); jaroslav@274: out.append(accessClass("java_lang_Class(true);")); jaroslav@225: out.append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';"); jaroslav@230: out.append("\n CLS.$class.superclass = sprcls;"); jaroslav@355: out.append("\n CLS.$class.access = ").append(jc.getAccessFlags()+";"); jaroslav@231: out.append("\n CLS.$class.cnstr = CLS;"); jaroslav@235: byte[] classAnno = jc.findAnnotationData(false); jaroslav@235: if (classAnno != null) { jaroslav@235: out.append("\n CLS.$class.anno = {"); jaroslav@235: generateAnno(jc, out, classAnno); jaroslav@235: out.append("\n };"); jaroslav@235: } jaroslav@204: out.append("\n }"); jaroslav@205: out.append("\n if (arguments.length === 0) {"); jaroslav@226: out.append("\n if (!(this instanceof CLS)) {"); jaroslav@226: out.append("\n return new CLS();"); jaroslav@226: out.append("\n }"); jaroslav@205: for (FieldData v : jc.getFields()) { jaroslav@240: byte[] onlyArr = v.findAnnotationData(true); jaroslav@240: String[] only = findAnnotation(onlyArr, jc, jaroslav@240: "org.apidesign.bck2brwsr.core.JavaScriptOnly", jaroslav@240: "name", "value" jaroslav@240: ); jaroslav@240: if (only != null) { jaroslav@240: if (only[0] != null && only[1] != null) { jaroslav@240: out.append("\n p.").append(only[0]).append(" = ") jaroslav@240: .append(only[1]).append(";"); jaroslav@240: } jaroslav@240: continue; jaroslav@240: } jaroslav@205: if (!v.isStatic()) { jaroslav@205: out.append("\n this.fld_"). jaroslav@205: append(v.getName()).append(initField(v)); jaroslav@205: } jaroslav@205: } jaroslav@205: out.append("\n return this;"); jaroslav@205: out.append("\n }"); jaroslav@224: out.append("\n return arguments[0] ? new CLS() : CLS.prototype;"); jaroslav@98: out.append("\n}"); jaroslav@97: StringBuilder sb = new StringBuilder(); jtulach@162: for (String init : toInitilize.toArray()) { jaroslav@97: sb.append("\n").append(init).append("();"); jaroslav@21: } jaroslav@97: return sb.toString(); jaroslav@0: } jaroslav@266: private String generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException { jaroslav@266: String jsb = javaScriptBody(prefix, 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@307: generateMethod(prefix, mn, m); jaroslav@266: return mn; jaroslav@10: } lubomir@307: jaroslav@266: private String generateInstanceMethod(String prefix, MethodData m) throws IOException { jaroslav@266: String jsb = javaScriptBody(prefix, m, false); jaroslav@266: if (jsb != null) { jaroslav@266: return jsb; jaroslav@94: } lubomir@307: final String mn = findMethodName(m, new StringBuilder()); lubomir@307: generateMethod(prefix, mn, m); jaroslav@266: return mn; jaroslav@0: } jaroslav@0: lubomir@307: private void generateMethod(String prefix, 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: lubomir@307: out.append(prefix).append(name).append(" = function("); jaroslav@442: lmapper.outputArguments(out, m.isStatic()); lubomir@307: out.append(") {").append("\n"); lubomir@307: lubomir@221: final byte[] byteCodes = m.getCode(); lubomir@307: if (byteCodes == null) { lubomir@307: out.append(" throw 'no code found for ") jaroslav@424: .append(jc.getClassName()).append('.') jaroslav@424: .append(m.getName()).append("';\n"); lubomir@307: out.append("};"); lubomir@307: return; lubomir@307: } lubomir@307: lubomir@307: final StackMapper smapper = new StackMapper(); lubomir@307: lubomir@307: final int maxLocals = m.getMaxLocals(); lubomir@307: if (maxLocals > 0) { lubomir@307: // TODO: generate only used local variables lubomir@307: for (int j = 0; j <= VarType.LAST; ++j) { lubomir@307: out.append("\n var ").append(Variable.getLocalVariable(j, 0)); lubomir@307: for (int i = 1; i < maxLocals; ++i) { lubomir@307: out.append(", "); lubomir@307: out.append(Variable.getLocalVariable(j, i)); lubomir@307: } lubomir@307: out.append(';'); lubomir@307: } lubomir@307: } jaroslav@442: if (!m.isStatic()) { jaroslav@442: out.append(" var ").append(" lcA0 = this;\n"); jaroslav@442: } lubomir@221: lubomir@221: // maxStack includes two stack positions for every pushed long / double lubomir@221: // so this might generate more stack variables than we need lubomir@221: final int maxStack = m.getMaxStack(); lubomir@221: if (maxStack > 0) { lubomir@281: // TODO: generate only used stack variables lubomir@307: for (int j = 0; j <= VarType.LAST; ++j) { lubomir@281: out.append("\n var ").append(Variable.getStackVariable(j, 0)); lubomir@281: for (int i = 1; i < maxStack; ++i) { lubomir@281: out.append(", "); lubomir@281: out.append(Variable.getStackVariable(j, i)); lubomir@281: } lubomir@281: out.append(';'); lubomir@221: } lubomir@221: } lubomir@221: lubomir@221: int lastStackFrame = -1; jaroslav@398: TrapData[] previousTrap = null; jaroslav@398: jaroslav@10: out.append("\n var gt = 0;\n for(;;) switch(gt) {\n"); jaroslav@0: for (int i = 0; i < byteCodes.length; i++) { jaroslav@272: int prev = i; 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@398: generateCatch(previousTrap); jaroslav@398: previousTrap = null; jaroslav@398: } jaroslav@398: } lubomir@221: if (lastStackFrame != stackMapIterator.getFrameIndex()) { lubomir@221: lastStackFrame = stackMapIterator.getFrameIndex(); lubomir@307: lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals()); lubomir@307: smapper.syncWithFrameStack(stackMapIterator.getFrameStack()); jaroslav@376: out.append(" case " + i).append(": "); jaroslav@398: changeInCatch = true; lubomir@221: } else { jaroslav@399: debug(" /* " + i + " */ "); lubomir@221: } jaroslav@398: if (changeInCatch && trap.useTry()) { tzezula@285: out.append("try {"); jaroslav@398: previousTrap = trap.current(); tzezula@285: } jtulach@128: final int c = readByte(byteCodes, i); jaroslav@0: switch (c) { jaroslav@151: case opc_aload_0: lubomir@307: emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(0)); lubomir@281: break; jaroslav@151: case opc_iload_0: lubomir@307: emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(0)); lubomir@281: break; jaroslav@151: case opc_lload_0: lubomir@307: emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(0)); lubomir@281: break; jaroslav@151: case opc_fload_0: lubomir@307: emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(0)); lubomir@281: break; jaroslav@151: case opc_dload_0: lubomir@307: emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(0)); jaroslav@0: break; jaroslav@151: case opc_aload_1: lubomir@307: emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(1)); lubomir@281: break; jaroslav@151: case opc_iload_1: lubomir@307: emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(1)); lubomir@281: break; jaroslav@151: case opc_lload_1: lubomir@307: emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(1)); lubomir@281: break; jaroslav@151: case opc_fload_1: lubomir@307: emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(1)); lubomir@281: break; jaroslav@151: case opc_dload_1: lubomir@307: emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(1)); jaroslav@0: break; jaroslav@151: case opc_aload_2: lubomir@307: emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(2)); lubomir@281: break; jaroslav@151: case opc_iload_2: lubomir@307: emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(2)); lubomir@281: break; jaroslav@151: case opc_lload_2: lubomir@307: emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(2)); lubomir@281: break; jaroslav@151: case opc_fload_2: lubomir@307: emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(2)); lubomir@281: break; jaroslav@151: case opc_dload_2: lubomir@307: emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(2)); jaroslav@2: break; jaroslav@151: case opc_aload_3: lubomir@307: emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(3)); lubomir@281: break; jaroslav@151: case opc_iload_3: lubomir@307: emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(3)); lubomir@281: break; jaroslav@151: case opc_lload_3: lubomir@307: emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(3)); lubomir@281: break; jaroslav@151: case opc_fload_3: lubomir@307: emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(3)); lubomir@281: break; jaroslav@151: case opc_dload_3: lubomir@307: emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(3)); jaroslav@3: break; lubomir@281: case opc_iload: { lubomir@281: final int indx = readByte(byteCodes, ++i); lubomir@307: emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(indx)); lubomir@281: break; lubomir@281: } lubomir@281: case opc_lload: { lubomir@281: final int indx = readByte(byteCodes, ++i); lubomir@307: emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(indx)); lubomir@281: break; lubomir@281: } lubomir@281: case opc_fload: { lubomir@281: final int indx = readByte(byteCodes, ++i); lubomir@307: emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(indx)); lubomir@281: break; lubomir@281: } lubomir@281: case opc_dload: { lubomir@281: final int indx = readByte(byteCodes, ++i); lubomir@307: emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(indx)); lubomir@281: break; lubomir@281: } jaroslav@151: case opc_aload: { jtulach@128: final int indx = readByte(byteCodes, ++i); lubomir@307: emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(indx)); jaroslav@3: break; jaroslav@3: } lubomir@281: case opc_istore: { lubomir@281: final int indx = readByte(byteCodes, ++i); lubomir@307: emit(out, "@1 = @2;", lmapper.setI(indx), smapper.popI()); lubomir@281: break; lubomir@281: } lubomir@281: case opc_lstore: { lubomir@281: final int indx = readByte(byteCodes, ++i); lubomir@307: emit(out, "@1 = @2;", lmapper.setL(indx), smapper.popL()); lubomir@281: break; lubomir@281: } lubomir@281: case opc_fstore: { lubomir@281: final int indx = readByte(byteCodes, ++i); lubomir@307: emit(out, "@1 = @2;", lmapper.setF(indx), smapper.popF()); lubomir@281: break; lubomir@281: } lubomir@281: case opc_dstore: { lubomir@281: final int indx = readByte(byteCodes, ++i); lubomir@307: emit(out, "@1 = @2;", lmapper.setD(indx), smapper.popD()); lubomir@281: break; lubomir@281: } jaroslav@151: case opc_astore: { jtulach@128: final int indx = readByte(byteCodes, ++i); lubomir@307: emit(out, "@1 = @2;", lmapper.setA(indx), smapper.popA()); jaroslav@31: break; jaroslav@31: } jaroslav@151: case opc_astore_0: lubomir@307: emit(out, "@1 = @2;", lmapper.setA(0), smapper.popA()); lubomir@281: break; jaroslav@151: case opc_istore_0: lubomir@307: emit(out, "@1 = @2;", lmapper.setI(0), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lstore_0: lubomir@307: emit(out, "@1 = @2;", lmapper.setL(0), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fstore_0: lubomir@307: emit(out, "@1 = @2;", lmapper.setF(0), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dstore_0: lubomir@307: emit(out, "@1 = @2;", lmapper.setD(0), smapper.popD()); jaroslav@5: break; jaroslav@151: case opc_astore_1: lubomir@307: emit(out, "@1 = @2;", lmapper.setA(1), smapper.popA()); lubomir@281: break; jaroslav@151: case opc_istore_1: lubomir@307: emit(out, "@1 = @2;", lmapper.setI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lstore_1: lubomir@307: emit(out, "@1 = @2;", lmapper.setL(1), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fstore_1: lubomir@307: emit(out, "@1 = @2;", lmapper.setF(1), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dstore_1: lubomir@307: emit(out, "@1 = @2;", lmapper.setD(1), smapper.popD()); jaroslav@5: break; jaroslav@151: case opc_astore_2: lubomir@307: emit(out, "@1 = @2;", lmapper.setA(2), smapper.popA()); lubomir@281: break; jaroslav@151: case opc_istore_2: lubomir@307: emit(out, "@1 = @2;", lmapper.setI(2), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lstore_2: lubomir@307: emit(out, "@1 = @2;", lmapper.setL(2), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fstore_2: lubomir@307: emit(out, "@1 = @2;", lmapper.setF(2), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dstore_2: lubomir@307: emit(out, "@1 = @2;", lmapper.setD(2), smapper.popD()); jaroslav@5: break; jaroslav@151: case opc_astore_3: lubomir@307: emit(out, "@1 = @2;", lmapper.setA(3), smapper.popA()); lubomir@281: break; jaroslav@151: case opc_istore_3: lubomir@307: emit(out, "@1 = @2;", lmapper.setI(3), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lstore_3: lubomir@307: emit(out, "@1 = @2;", lmapper.setL(3), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fstore_3: lubomir@307: emit(out, "@1 = @2;", lmapper.setF(3), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dstore_3: lubomir@307: emit(out, "@1 = @2;", lmapper.setD(3), smapper.popD()); jaroslav@5: break; jaroslav@151: case opc_iadd: Martin@351: emit(out, "@1 = (@1 + @2) | 0;", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_ladd: lubomir@307: emit(out, "@1 += @2;", smapper.getL(1), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fadd: lubomir@307: emit(out, "@1 += @2;", smapper.getF(1), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dadd: lubomir@307: emit(out, "@1 += @2;", smapper.getD(1), smapper.popD()); jaroslav@0: break; jaroslav@151: case opc_isub: Martin@351: emit(out, "@1 = (@1 - @2) | 0;", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lsub: lubomir@307: emit(out, "@1 -= @2;", smapper.getL(1), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fsub: lubomir@307: emit(out, "@1 -= @2;", smapper.getF(1), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dsub: lubomir@307: emit(out, "@1 -= @2;", smapper.getD(1), smapper.popD()); jaroslav@2: break; jaroslav@151: case opc_imul: Martin@351: emit(out, "@1 = (((@1 * (@2 >> 16)) << 16) + @1 * (@2 & 0xFFFF)) | 0;", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lmul: lubomir@307: emit(out, "@1 *= @2;", smapper.getL(1), smapper.popL()); lubomir@281: break; jaroslav@151: case opc_fmul: lubomir@307: emit(out, "@1 *= @2;", smapper.getF(1), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dmul: lubomir@307: emit(out, "@1 *= @2;", smapper.getD(1), smapper.popD()); jaroslav@1: break; jaroslav@151: case opc_idiv: lubomir@283: emit(out, "@1 = Math.floor(@1 / @2);", lubomir@307: smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_ldiv: lubomir@283: emit(out, "@1 = Math.floor(@1 / @2);", lubomir@307: smapper.getL(1), smapper.popL()); jaroslav@3: break; jaroslav@151: case opc_fdiv: lubomir@307: emit(out, "@1 /= @2;", smapper.getF(1), smapper.popF()); lubomir@281: break; jaroslav@151: case opc_ddiv: lubomir@307: emit(out, "@1 /= @2;", smapper.getD(1), smapper.popD()); jaroslav@3: break; jaroslav@178: case opc_irem: lubomir@307: emit(out, "@1 %= @2;", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@178: case opc_lrem: lubomir@307: emit(out, "@1 %= @2;", smapper.getL(1), smapper.popL()); lubomir@281: break; jaroslav@178: case opc_frem: lubomir@307: emit(out, "@1 %= @2;", smapper.getF(1), smapper.popF()); lubomir@281: break; jaroslav@178: case opc_drem: lubomir@307: emit(out, "@1 %= @2;", smapper.getD(1), smapper.popD()); jaroslav@178: break; jaroslav@151: case opc_iand: lubomir@307: emit(out, "@1 &= @2;", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_land: lubomir@307: emit(out, "@1 &= @2;", smapper.getL(1), smapper.popL()); jaroslav@7: break; jaroslav@151: case opc_ior: lubomir@307: emit(out, "@1 |= @2;", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lor: lubomir@307: emit(out, "@1 |= @2;", smapper.getL(1), smapper.popL()); jaroslav@7: break; jaroslav@151: case opc_ixor: lubomir@307: emit(out, "@1 ^= @2;", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lxor: lubomir@307: emit(out, "@1 ^= @2;", smapper.getL(1), smapper.popL()); jaroslav@6: break; jaroslav@151: case opc_ineg: lubomir@307: emit(out, "@1 = -@1;", smapper.getI(0)); lubomir@281: break; jaroslav@151: case opc_lneg: lubomir@307: emit(out, "@1 = -@1;", smapper.getL(0)); lubomir@281: break; jaroslav@151: case opc_fneg: lubomir@307: emit(out, "@1 = -@1;", smapper.getF(0)); lubomir@281: break; jaroslav@151: case opc_dneg: lubomir@307: emit(out, "@1 = -@1;", smapper.getD(0)); jaroslav@93: break; jaroslav@151: case opc_ishl: lubomir@307: emit(out, "@1 <<= @2;", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lshl: lubomir@307: emit(out, "@1 <<= @2;", smapper.getL(1), smapper.popI()); jaroslav@93: break; jaroslav@151: case opc_ishr: lubomir@307: emit(out, "@1 >>= @2;", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lshr: lubomir@307: emit(out, "@1 >>= @2;", smapper.getL(1), smapper.popI()); jaroslav@93: break; jaroslav@151: case opc_iushr: lubomir@307: emit(out, "@1 >>>= @2;", smapper.getI(1), smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lushr: lubomir@307: emit(out, "@1 >>>= @2;", smapper.getL(1), smapper.popI()); jaroslav@93: break; jaroslav@151: case opc_iinc: { jtulach@128: final int varIndx = readByte(byteCodes, ++i); jaroslav@104: final int incrBy = byteCodes[++i]; jaroslav@5: if (incrBy == 1) { lubomir@307: emit(out, "@1++;", lmapper.getI(varIndx)); jaroslav@5: } else { lubomir@307: emit(out, "@1 += @2;", lubomir@307: lmapper.getI(varIndx), lubomir@283: Integer.toString(incrBy)); jaroslav@5: } jaroslav@5: break; jaroslav@5: } jaroslav@151: case opc_return: lubomir@283: emit(out, "return;"); jaroslav@10: break; jaroslav@151: case opc_ireturn: lubomir@307: emit(out, "return @1;", smapper.popI()); lubomir@281: break; jaroslav@151: case opc_lreturn: lubomir@307: emit(out, "return @1;", smapper.popL()); lubomir@281: break; jaroslav@151: case opc_freturn: lubomir@307: emit(out, "return @1;", smapper.popF()); lubomir@281: break; jaroslav@151: case opc_dreturn: lubomir@307: emit(out, "return @1;", smapper.popD()); lubomir@281: break; jaroslav@151: case opc_areturn: lubomir@307: emit(out, "return @1;", smapper.popA()); jaroslav@1: break; jaroslav@151: case opc_i2l: lubomir@307: emit(out, "@2 = @1;", smapper.popI(), smapper.pushL()); lubomir@281: break; jaroslav@151: case opc_i2f: lubomir@307: emit(out, "@2 = @1;", smapper.popI(), smapper.pushF()); lubomir@281: break; jaroslav@151: case opc_i2d: lubomir@307: emit(out, "@2 = @1;", smapper.popI(), smapper.pushD()); lubomir@281: break; jaroslav@151: case opc_l2i: lubomir@307: emit(out, "@2 = @1;", smapper.popL(), smapper.pushI()); lubomir@281: break; jaroslav@3: // max int check? jaroslav@151: case opc_l2f: lubomir@307: emit(out, "@2 = @1;", smapper.popL(), smapper.pushF()); jaroslav@272: break; jaroslav@151: case opc_l2d: lubomir@307: emit(out, "@2 = @1;", smapper.popL(), smapper.pushD()); jaroslav@272: break; jaroslav@151: case opc_f2d: lubomir@307: emit(out, "@2 = @1;", smapper.popF(), smapper.pushD()); lubomir@281: break; jaroslav@151: case opc_d2f: lubomir@307: emit(out, "@2 = @1;", smapper.popD(), smapper.pushF()); jaroslav@3: break; jaroslav@151: case opc_f2i: lubomir@283: emit(out, "@2 = Math.floor(@1);", lubomir@307: smapper.popF(), smapper.pushI()); lubomir@281: break; jaroslav@151: case opc_f2l: lubomir@283: emit(out, "@2 = Math.floor(@1);", lubomir@307: smapper.popF(), smapper.pushL()); lubomir@281: break; jaroslav@151: case opc_d2i: lubomir@283: emit(out, "@2 = Math.floor(@1);", lubomir@307: smapper.popD(), smapper.pushI()); lubomir@281: break; jaroslav@151: case opc_d2l: lubomir@283: emit(out, "@2 = Math.floor(@1);", lubomir@307: smapper.popD(), smapper.pushL()); jaroslav@3: break; jaroslav@151: case opc_i2b: jaroslav@151: case opc_i2c: jaroslav@151: case opc_i2s: jaroslav@337: out.append("{ /* number conversion */ }"); jaroslav@2: break; jaroslav@151: case opc_aconst_null: lubomir@307: emit(out, "@1 = null;", smapper.pushA()); jaroslav@46: break; jaroslav@151: case opc_iconst_m1: lubomir@307: emit(out, "@1 = -1;", smapper.pushI()); jaroslav@48: break; jaroslav@151: case opc_iconst_0: lubomir@307: emit(out, "@1 = 0;", smapper.pushI()); lubomir@281: break; jaroslav@151: case opc_dconst_0: lubomir@307: emit(out, "@1 = 0;", smapper.pushD()); lubomir@281: break; jaroslav@151: case opc_lconst_0: lubomir@307: emit(out, "@1 = 0;", smapper.pushL()); lubomir@281: break; jaroslav@151: case opc_fconst_0: lubomir@307: emit(out, "@1 = 0;", smapper.pushF()); jaroslav@4: break; jaroslav@151: case opc_iconst_1: lubomir@307: emit(out, "@1 = 1;", smapper.pushI()); lubomir@281: break; jaroslav@151: case opc_lconst_1: lubomir@307: emit(out, "@1 = 1;", smapper.pushL()); lubomir@281: break; jaroslav@151: case opc_fconst_1: lubomir@307: emit(out, "@1 = 1;", smapper.pushF()); lubomir@281: break; jaroslav@151: case opc_dconst_1: lubomir@307: emit(out, "@1 = 1;", smapper.pushD()); jaroslav@4: break; jaroslav@151: case opc_iconst_2: lubomir@307: emit(out, "@1 = 2;", smapper.pushI()); lubomir@281: break; jaroslav@151: case opc_fconst_2: lubomir@307: emit(out, "@1 = 2;", smapper.pushF()); jaroslav@4: break; jaroslav@151: case opc_iconst_3: lubomir@307: emit(out, "@1 = 3;", smapper.pushI()); jaroslav@4: break; jaroslav@151: case opc_iconst_4: lubomir@307: emit(out, "@1 = 4;", smapper.pushI()); jaroslav@4: break; jaroslav@151: case opc_iconst_5: lubomir@307: emit(out, "@1 = 5;", smapper.pushI()); jaroslav@4: break; jaroslav@151: case opc_ldc: { jtulach@128: int indx = readByte(byteCodes, ++i); jaroslav@151: String v = encodeConstant(indx); lubomir@307: int type = VarType.fromConstantType(jc.getTag(indx)); lubomir@307: emit(out, "@1 = @2;", smapper.pushT(type), v); jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_ldc_w: jaroslav@151: case opc_ldc2_w: { jaroslav@8: int indx = readIntArg(byteCodes, i); jaroslav@8: i += 2; jaroslav@151: String v = encodeConstant(indx); lubomir@307: int type = VarType.fromConstantType(jc.getTag(indx)); lubomir@307: emit(out, "@1 = @2;", smapper.pushT(type), v); jaroslav@8: break; jaroslav@8: } jaroslav@151: case opc_lcmp: lubomir@283: emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", lubomir@307: smapper.popL(), smapper.popL(), smapper.pushI()); lubomir@281: break; jaroslav@151: case opc_fcmpl: jaroslav@151: case opc_fcmpg: lubomir@283: emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", lubomir@307: smapper.popF(), smapper.popF(), smapper.pushI()); lubomir@281: break; jaroslav@151: case opc_dcmpl: lubomir@281: case opc_dcmpg: lubomir@283: emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", lubomir@307: smapper.popD(), smapper.popD(), smapper.pushI()); jaroslav@20: break; jaroslav@151: case opc_if_acmpeq: lubomir@307: i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(), lubomir@281: "==="); jaroslav@104: break; jaroslav@151: case opc_if_acmpne: lubomir@307: i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(), lubomir@281: "!="); jaroslav@104: break; lubomir@283: case opc_if_icmpeq: lubomir@307: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), lubomir@281: "=="); jaroslav@4: break; jaroslav@151: case opc_ifeq: { jaroslav@7: int indx = i + readIntArg(byteCodes, i); lubomir@283: emit(out, "if (@1 == 0) { gt = @2; continue; }", lubomir@307: smapper.popI(), Integer.toString(indx)); jaroslav@7: i += 2; jaroslav@7: break; jaroslav@7: } jaroslav@151: case opc_ifne: { jaroslav@20: int indx = i + readIntArg(byteCodes, i); lubomir@283: emit(out, "if (@1 != 0) { gt = @2; continue; }", lubomir@307: smapper.popI(), Integer.toString(indx)); jaroslav@20: i += 2; jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_iflt: { jaroslav@20: int indx = i + readIntArg(byteCodes, i); lubomir@283: emit(out, "if (@1 < 0) { gt = @2; continue; }", lubomir@307: smapper.popI(), Integer.toString(indx)); jaroslav@20: i += 2; jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_ifle: { jaroslav@20: int indx = i + readIntArg(byteCodes, i); lubomir@283: emit(out, "if (@1 <= 0) { gt = @2; continue; }", lubomir@307: smapper.popI(), Integer.toString(indx)); jaroslav@20: i += 2; jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_ifgt: { jaroslav@20: int indx = i + readIntArg(byteCodes, i); lubomir@283: emit(out, "if (@1 > 0) { gt = @2; continue; }", lubomir@307: smapper.popI(), Integer.toString(indx)); jaroslav@20: i += 2; jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_ifge: { jaroslav@20: int indx = i + readIntArg(byteCodes, i); lubomir@283: emit(out, "if (@1 >= 0) { gt = @2; continue; }", lubomir@307: smapper.popI(), Integer.toString(indx)); jaroslav@20: i += 2; jaroslav@20: break; jaroslav@20: } jaroslav@151: case opc_ifnonnull: { jaroslav@16: int indx = i + readIntArg(byteCodes, i); lubomir@283: emit(out, "if (@1 !== null) { gt = @2; continue; }", lubomir@307: smapper.popA(), Integer.toString(indx)); jaroslav@16: i += 2; jaroslav@16: break; jaroslav@16: } jaroslav@151: case opc_ifnull: { jaroslav@16: int indx = i + readIntArg(byteCodes, i); lubomir@283: emit(out, "if (@1 === null) { gt = @2; continue; }", lubomir@307: smapper.popA(), Integer.toString(indx)); jaroslav@16: i += 2; jaroslav@16: break; jaroslav@16: } jaroslav@151: case opc_if_icmpne: lubomir@307: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), lubomir@281: "!="); jaroslav@4: break; jaroslav@151: case opc_if_icmplt: lubomir@307: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), lubomir@281: "<"); jaroslav@4: break; jaroslav@151: case opc_if_icmple: lubomir@307: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), lubomir@281: "<="); jaroslav@4: break; jaroslav@151: case opc_if_icmpgt: lubomir@307: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), lubomir@281: ">"); jaroslav@4: break; jaroslav@151: case opc_if_icmpge: lubomir@307: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), lubomir@281: ">="); jaroslav@4: break; jaroslav@151: case opc_goto: { jaroslav@5: int indx = i + readIntArg(byteCodes, i); lubomir@283: emit(out, "gt = @1; continue;", Integer.toString(indx)); jaroslav@5: i += 2; jaroslav@5: break; jaroslav@5: } jaroslav@151: case opc_lookupswitch: { jtulach@128: int table = i / 4 * 4 + 4; jaroslav@115: int dflt = i + readInt4(byteCodes, table); jaroslav@115: table += 4; jaroslav@115: int n = readInt4(byteCodes, table); jaroslav@115: table += 4; lubomir@307: out.append("switch (").append(smapper.popI()).append(") {\n"); jaroslav@115: while (n-- > 0) { jaroslav@115: int cnstnt = readInt4(byteCodes, table); jaroslav@115: table += 4; jaroslav@115: int offset = i + readInt4(byteCodes, table); jaroslav@115: table += 4; jaroslav@115: out.append(" case " + cnstnt).append(": gt = " + offset).append("; continue;\n"); jaroslav@115: } jaroslav@115: out.append(" default: gt = " + dflt).append("; continue;\n}"); jaroslav@115: i = table - 1; jaroslav@115: break; jaroslav@115: } jaroslav@151: case opc_tableswitch: { jtulach@128: int table = i / 4 * 4 + 4; jaroslav@115: int dflt = i + readInt4(byteCodes, table); jaroslav@115: table += 4; jaroslav@115: int low = readInt4(byteCodes, table); jaroslav@115: table += 4; jaroslav@115: int high = readInt4(byteCodes, table); jaroslav@115: table += 4; lubomir@307: out.append("switch (").append(smapper.popI()).append(") {\n"); jaroslav@115: while (low <= high) { jaroslav@115: int offset = i + readInt4(byteCodes, table); jaroslav@115: table += 4; jaroslav@115: out.append(" case " + low).append(": gt = " + offset).append("; continue;\n"); jaroslav@115: low++; jaroslav@115: } jaroslav@115: out.append(" default: gt = " + dflt).append("; continue;\n}"); jaroslav@115: i = table - 1; 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@8: int indx = readIntArg(byteCodes, i); jaroslav@151: String ci = jc.getClassName(indx); lubomir@283: emit(out, "@1 = new @2;", lubomir@317: smapper.pushA(), accessClass(ci.replace('/', '_'))); jaroslav@151: addReference(ci); jaroslav@8: i += 2; jaroslav@8: break; jaroslav@8: } lubomir@283: case opc_newarray: jaroslav@448: int atype = readByte(byteCodes, ++i); jaroslav@448: String jvmType; jaroslav@448: switch (atype) { jaroslav@448: case 4: jvmType = "[Z"; break; jaroslav@448: case 5: jvmType = "[C"; break; jaroslav@448: case 6: jvmType = "[F"; break; jaroslav@448: case 7: jvmType = "[D"; break; jaroslav@448: case 8: jvmType = "[B"; break; jaroslav@448: case 9: jvmType = "[S"; break; jaroslav@448: case 10: jvmType = "[I"; break; jaroslav@448: case 11: jvmType = "[J"; break; jaroslav@448: default: throw new IllegalStateException("Array type: " + atype); jaroslav@448: } jaroslav@448: emit(out, "@2 = new Array(@1).fillNulls().arrtype('@3');", jaroslav@448: smapper.popI(), smapper.pushA(), jvmType); jaroslav@21: break; jaroslav@448: case opc_anewarray: { jaroslav@448: int type = readIntArg(byteCodes, i); jaroslav@448: i += 2; jaroslav@448: String typeName = jc.getClassName(type); jaroslav@448: if (typeName.startsWith("[")) { jaroslav@448: typeName = "[" + typeName; jaroslav@448: } else { jaroslav@448: typeName = "[L" + typeName + ";"; jaroslav@448: } jaroslav@448: emit(out, "@2 = new Array(@1).fillNulls().arrtype('@3');", jaroslav@448: smapper.popI(), smapper.pushA(), typeName); jaroslav@21: break; jaroslav@448: } jaroslav@151: case opc_multianewarray: { jaroslav@448: int type = readIntArg(byteCodes, i); jtulach@128: i += 2; jaroslav@448: String typeName = jc.getClassName(type); jtulach@128: int dim = readByte(byteCodes, ++i); lubomir@307: out.append("{ var a0 = new Array(").append(smapper.popI()) jaroslav@448: .append(").fillNulls().arrtype('").append(typeName).append("');"); jtulach@128: for (int d = 1; d < dim; d++) { jaroslav@453: typeName = typeName.substring(1); lubomir@221: out.append("\n var l" + d).append(" = ") lubomir@307: .append(smapper.popI()).append(';'); jtulach@128: out.append("\n for (var i" + d).append (" = 0; i" + d). jtulach@128: append(" < a" + (d - 1)). jtulach@128: append(".length; i" + d).append("++) {"); jtulach@128: out.append("\n var a" + d). jaroslav@453: append (" = new Array(l" + d).append(").fillNulls().arrtype('") jaroslav@453: .append(typeName).append("');"); jtulach@128: out.append("\n a" + (d - 1)).append("[i" + d).append("] = a" + d). jtulach@128: append(";"); jtulach@128: } jtulach@128: for (int d = 1; d < dim; d++) { jtulach@128: out.append("\n }"); jtulach@128: } lubomir@307: out.append("\n").append(smapper.pushA()).append(" = a0; }"); jtulach@128: break; jtulach@128: } jaroslav@151: case opc_arraylength: lubomir@307: emit(out, "@2 = @1.length;", smapper.popA(), smapper.pushI()); jaroslav@272: break; lubomir@283: case opc_lastore: lubomir@283: emit(out, "@3[@2] = @1;", lubomir@307: smapper.popL(), smapper.popI(), smapper.popA()); lubomir@281: break; lubomir@283: case opc_fastore: lubomir@283: emit(out, "@3[@2] = @1;", lubomir@307: smapper.popF(), smapper.popI(), smapper.popA()); lubomir@281: break; lubomir@283: case opc_dastore: lubomir@283: emit(out, "@3[@2] = @1;", lubomir@307: smapper.popD(), smapper.popI(), smapper.popA()); lubomir@281: break; lubomir@283: case opc_aastore: lubomir@283: emit(out, "@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: lubomir@283: emit(out, "@3[@2] = @1;", lubomir@307: smapper.popI(), smapper.popI(), smapper.popA()); jaroslav@240: break; lubomir@283: case opc_laload: lubomir@283: emit(out, "@3 = @2[@1];", lubomir@307: smapper.popI(), smapper.popA(), smapper.pushL()); lubomir@281: break; lubomir@283: case opc_faload: lubomir@283: emit(out, "@3 = @2[@1];", lubomir@307: smapper.popI(), smapper.popA(), smapper.pushF()); lubomir@281: break; lubomir@283: case opc_daload: lubomir@283: emit(out, "@3 = @2[@1];", lubomir@307: smapper.popI(), smapper.popA(), smapper.pushD()); lubomir@281: break; lubomir@283: case opc_aaload: lubomir@283: emit(out, "@3 = @2[@1];", lubomir@307: smapper.popI(), smapper.popA(), smapper.pushA()); jaroslav@272: break; jaroslav@272: case opc_iaload: jaroslav@272: case opc_baload: jaroslav@272: case opc_caload: lubomir@283: case opc_saload: lubomir@283: emit(out, "@3 = @2[@1];", lubomir@307: smapper.popI(), smapper.popA(), smapper.pushI()); 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); lubomir@307: emit(out, "@1 = @2;", smapper.pushT(v.getType()), v); jaroslav@21: break; jaroslav@21: } lubomir@281: case opc_dup2: { lubomir@307: if (smapper.get(0).isCategory2()) { lubomir@307: final Variable v = smapper.get(0); lubomir@307: emit(out, "@1 = @2;", smapper.pushT(v.getType()), v); lubomir@281: } else { lubomir@307: final Variable v1 = smapper.get(0); lubomir@307: final Variable v2 = smapper.get(1); lubomir@283: emit(out, "{ @1 = @2; @3 = @4; }", lubomir@307: smapper.pushT(v2.getType()), v2, lubomir@307: smapper.pushT(v1.getType()), v1); lubomir@281: } jaroslav@21: break; jaroslav@21: } lubomir@281: case opc_dup_x1: { lubomir@307: final Variable vi1 = smapper.pop(); lubomir@307: final Variable vi2 = smapper.pop(); 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: lubomir@283: emit(out, "{ @1 = @2; @3 = @4; @5 = @6; }", lubomir@283: vo1, vi1, vo2, vi2, vo3, vo1); jaroslav@93: break; lubomir@281: } lubomir@281: case opc_dup_x2: { lubomir@307: if (smapper.get(1).isCategory2()) { lubomir@307: final Variable vi1 = smapper.pop(); lubomir@307: final Variable vi2 = smapper.pop(); 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: lubomir@283: emit(out, "{ @1 = @2; @3 = @4; @5 = @6; }", lubomir@283: vo1, vi1, vo2, vi2, vo3, vo1); lubomir@281: } else { lubomir@307: final Variable vi1 = smapper.pop(); lubomir@307: final Variable vi2 = smapper.pop(); lubomir@307: final Variable vi3 = smapper.pop(); 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: lubomir@283: emit(out, "{ @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: } jaroslav@151: case opc_bipush: lubomir@283: emit(out, "@1 = @2;", lubomir@307: smapper.pushI(), Integer.toString(byteCodes[++i])); jaroslav@8: break; jaroslav@151: case opc_sipush: lubomir@283: emit(out, "@1 = @2;", lubomir@307: smapper.pushI(), lubomir@283: Integer.toString(readIntArg(byteCodes, i))); jaroslav@31: i += 2; jaroslav@31: break; jaroslav@151: case opc_getfield: { jaroslav@8: int indx = readIntArg(byteCodes, i); jaroslav@151: String[] fi = jc.getFieldInfoName(indx); lubomir@307: final int type = VarType.fromFieldType(fi[2].charAt(0)); lubomir@283: emit(out, "@2 = @1.fld_@3;", lubomir@307: smapper.popA(), smapper.pushT(type), fi[1]); jaroslav@8: i += 2; jaroslav@8: break; jaroslav@8: } jaroslav@151: case opc_getstatic: { jaroslav@9: int indx = readIntArg(byteCodes, i); jaroslav@151: String[] fi = jc.getFieldInfoName(indx); lubomir@307: final int type = VarType.fromFieldType(fi[2].charAt(0)); jaroslav@358: emit(out, "@1 = @2(false).constructor.@3;", lubomir@317: smapper.pushT(type), lubomir@317: accessClass(fi[0].replace('/', '_')), fi[1]); jaroslav@9: i += 2; jaroslav@151: addReference(fi[0]); jaroslav@9: break; jaroslav@9: } jaroslav@151: case opc_putfield: { jaroslav@10: int indx = readIntArg(byteCodes, i); jaroslav@151: String[] fi = jc.getFieldInfoName(indx); lubomir@307: final int type = VarType.fromFieldType(fi[2].charAt(0)); lubomir@283: emit(out, "@2.fld_@3 = @1;", lubomir@307: smapper.popT(type), smapper.popA(), fi[1]); jaroslav@10: i += 2; jaroslav@10: break; jaroslav@10: } lubomir@281: case opc_putstatic: { lubomir@281: int indx = readIntArg(byteCodes, i); lubomir@281: String[] fi = jc.getFieldInfoName(indx); lubomir@307: final int type = VarType.fromFieldType(fi[2].charAt(0)); jaroslav@358: emit(out, "@1(false).constructor.@2 = @3;", lubomir@317: accessClass(fi[0].replace('/', '_')), 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@30: int indx = readIntArg(byteCodes, i); jaroslav@151: final String type = jc.getClassName(indx); jaroslav@42: if (!type.startsWith("[")) { jaroslav@42: // no way to check arrays right now lubomir@283: // XXX proper exception lubomir@317: emit(out, lubomir@317: "if (@1 !== null && !@1.$instOf_@2) throw {};", lubomir@307: smapper.getA(0), type.replace('/', '_')); jaroslav@42: } jaroslav@30: i += 2; jaroslav@30: break; jaroslav@30: } jaroslav@151: case opc_instanceof: { jaroslav@17: int indx = readIntArg(byteCodes, i); jaroslav@151: final String type = jc.getClassName(indx); lubomir@283: emit(out, "@2 = @1.$instOf_@3 ? 1 : 0;", lubomir@317: smapper.popA(), smapper.pushI(), lubomir@317: type.replace('/', '_')); jaroslav@17: i += 2; jaroslav@30: break; jaroslav@17: } jaroslav@151: case opc_athrow: { lubomir@307: final Variable v = smapper.popA(); lubomir@307: smapper.clear(); lubomir@281: lubomir@283: emit(out, "{ @1 = @2; throw @2; }", lubomir@307: smapper.pushA(), v); jaroslav@104: break; jaroslav@104: } lubomir@221: lubomir@221: case opc_monitorenter: { lubomir@221: out.append("/* monitor enter */"); lubomir@307: smapper.popA(); lubomir@221: break; lubomir@221: } lubomir@221: lubomir@221: case opc_monitorexit: { lubomir@221: out.append("/* monitor exit */"); lubomir@307: smapper.popA(); lubomir@221: break; lubomir@221: } lubomir@221: jaroslav@104: default: { lubomir@283: emit(out, "throw 'unknown bytecode @1';", lubomir@283: Integer.toString(c)); jaroslav@104: } jaroslav@0: } jaroslav@399: if (debug(" //")) { jaroslav@399: for (int j = prev; j <= i; j++) { jaroslav@399: out.append(" "); jaroslav@399: final int cc = readByte(byteCodes, j); jaroslav@399: out.append(Integer.toString(cc)); tzezula@285: } jaroslav@0: } tzezula@285: out.append("\n"); jaroslav@0: } jaroslav@398: if (previousTrap != null) { jaroslav@398: generateCatch(previousTrap); jaroslav@398: } jaroslav@10: out.append(" }\n"); lubomir@307: out.append("};"); jaroslav@4: } jaroslav@4: lubomir@281: private int generateIf(byte[] byteCodes, int i, lubomir@281: final Variable v2, final Variable v1, lubomir@281: final String test) throws IOException { jaroslav@4: int indx = i + readIntArg(byteCodes, i); lubomir@281: out.append("if (").append(v1) lubomir@221: .append(' ').append(test).append(' ') lubomir@281: .append(v2).append(") { gt = " + indx) lubomir@221: .append("; continue; }"); jaroslav@4: return i + 2; jaroslav@4: } jaroslav@4: jaroslav@4: private int readIntArg(byte[] byteCodes, int offsetInstruction) { jaroslav@5: final int indxHi = byteCodes[offsetInstruction + 1] << 8; jaroslav@5: final int indxLo = byteCodes[offsetInstruction + 2]; jaroslav@5: return (indxHi & 0xffffff00) | (indxLo & 0xff); jaroslav@4: } jaroslav@115: private int readInt4(byte[] byteCodes, int offsetInstruction) { jaroslav@115: final int d = byteCodes[offsetInstruction + 0] << 24; jaroslav@115: final int c = byteCodes[offsetInstruction + 1] << 16; jaroslav@115: final int b = byteCodes[offsetInstruction + 2] << 8; jaroslav@115: final int a = byteCodes[offsetInstruction + 3]; jaroslav@115: return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff); jaroslav@115: } jtulach@128: private int readByte(byte[] byteCodes, int offsetInstruction) { lubomir@221: return byteCodes[offsetInstruction] & 0xff; jtulach@128: } jaroslav@4: 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@248: private static String mangleSig(String txt, int first, int last) { jaroslav@248: StringBuilder sb = new StringBuilder(); 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@248: default: sb.append(ch); break; jaroslav@248: } jaroslav@248: } jaroslav@248: return sb.toString(); jaroslav@248: } 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@42: name.append(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@151: name.append(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@10: int methodIndex = readIntArg(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; lubomir@281: final Variable[] vars = new Variable[numArguments]; lubomir@221: lubomir@281: for (int j = numArguments - 1; j >= 0; --j) { lubomir@281: vars[j] = mapper.pop(); jaroslav@11: } lubomir@281: lubomir@281: if (returnType[0] != 'V') { lubomir@307: out.append(mapper.pushT(VarType.fromFieldType(returnType[0]))) lubomir@281: .append(" = "); jaroslav@10: } lubomir@221: jaroslav@151: final String in = mi[0]; jaroslav@274: out.append(accessClass(in.replace('/', '_'))); jaroslav@224: out.append("(false)."); jaroslav@397: if (mn.startsWith("cons_")) { jaroslav@397: out.append("constructor."); jaroslav@397: } jaroslav@10: out.append(mn); jaroslav@442: if (isStatic) { jaroslav@442: out.append('('); jaroslav@442: } else { jaroslav@442: out.append(".call("); jaroslav@442: } lubomir@221: if (numArguments > 0) { lubomir@281: out.append(vars[0]); lubomir@281: for (int j = 1; j < numArguments; ++j) { lubomir@221: out.append(", "); lubomir@281: out.append(vars[j]); lubomir@221: } jaroslav@10: } lubomir@221: out.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@12: int methodIndex = readIntArg(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; lubomir@281: final Variable[] vars = new Variable[numArguments]; lubomir@221: lubomir@281: for (int j = numArguments - 1; j >= 0; --j) { lubomir@281: vars[j] = mapper.pop(); jaroslav@12: } lubomir@221: lubomir@281: if (returnType[0] != 'V') { lubomir@307: out.append(mapper.pushT(VarType.fromFieldType(returnType[0]))) lubomir@281: .append(" = "); jaroslav@12: } lubomir@281: lubomir@281: out.append(vars[0]).append('.'); jaroslav@12: out.append(mn); jaroslav@12: out.append('('); jaroslav@442: String sep = ""; lubomir@281: for (int j = 1; j < numArguments; ++j) { jaroslav@442: out.append(sep); lubomir@281: out.append(vars[j]); jaroslav@442: sep = ", "; jaroslav@12: } lubomir@221: out.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@230: addReference(classRef[0]); jaroslav@274: s = accessClass(s.replace('/', '_')) + "(false).constructor.$class"; jaroslav@230: } jaroslav@151: return s; jaroslav@21: } jaroslav@32: jaroslav@266: private String javaScriptBody(String prefix, 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@152: class P extends AnnotationParser { jaroslav@237: public P() { jaroslav@237: super(false); jaroslav@237: } jaroslav@237: jaroslav@152: int cnt; jaroslav@152: String[] args = new String[30]; jaroslav@152: String body; 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@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@266: out.append(prefix).append(mn); jaroslav@203: out.append(" = function("); jaroslav@442: String space = ""; jaroslav@443: int index = 0; jtulach@156: for (int i = 0; i < cnt.length(); i++) { jaroslav@152: out.append(space); jaroslav@316: space = outputArg(out, p.args, index); jaroslav@152: index++; jaroslav@152: } jaroslav@152: out.append(") {").append("\n"); jaroslav@152: out.append(p.body); jaroslav@152: out.append("\n}\n"); jaroslav@266: return mn; jaroslav@151: } jaroslav@151: private static String className(ClassData jc) { jaroslav@151: //return jc.getName().getInternalName().replace('/', '_'); jaroslav@151: return jc.getClassName().replace('/', '_'); 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@237: AnnotationParser ap = new AnnotationParser(false) { 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@235: private static void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException { jaroslav@237: AnnotationParser ap = new AnnotationParser(true) { jaroslav@237: int anno; jaroslav@235: int cnt; jaroslav@235: jaroslav@235: @Override jaroslav@235: protected void visitAnnotationStart(String type) throws IOException { jaroslav@237: if (anno++ > 0) { jaroslav@237: out.append(","); jaroslav@237: } jaroslav@235: out.append('"').append(type).append("\" : {\n"); jaroslav@235: cnt = 0; jaroslav@235: } jaroslav@235: jaroslav@235: @Override jaroslav@235: protected void visitAnnotationEnd(String type) throws IOException { jaroslav@235: out.append("\n}\n"); 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@266: if (attr == null) { jaroslav@266: return; jaroslav@266: } jaroslav@235: if (cnt++ > 0) { jaroslav@235: out.append(",\n"); jaroslav@235: } jaroslav@250: out.append(attr).append("__").append(attrType).append(" : ").append(value); 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: lubomir@283: private static void emit(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@398: private void generateCatch(TrapData[] traps) throws IOException { jaroslav@400: out.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@423: if ("java/lang/Throwable".equals(classInternalName)) { jaroslav@423: out.append("if (e.$instOf_java_lang_Throwable) {"); jaroslav@423: out.append(" stA0 = e;"); jaroslav@423: out.append("} else {"); jaroslav@423: out.append(" stA0 = vm.java_lang_Throwable(true);"); jaroslav@442: out.append(" vm.java_lang_Throwable.cons__VLjava_lang_String_2.call(stA0, e.toString());"); jaroslav@423: out.append("}"); jaroslav@423: out.append("gt=" + e.handler_pc + "; continue;"); jaroslav@423: } else { jaroslav@423: out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {"); jaroslav@423: out.append("gt=" + e.handler_pc + "; stA0 = e; continue;"); jaroslav@423: out.append("}\n"); jaroslav@423: } jaroslav@398: } else { jaroslav@401: finallyPC = e.handler_pc; jaroslav@398: } jaroslav@398: } jaroslav@401: if (finallyPC == -1) { jaroslav@401: out.append("throw e;"); jaroslav@401: } else { jaroslav@401: out.append("gt=" + finallyPC + "; stA0 = e; continue;"); jaroslav@401: } jaroslav@400: out.append("\n}"); jaroslav@398: } jaroslav@0: }