1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Feb 26 16:54:16 2013 +0100
1.3 @@ -0,0 +1,1859 @@
1.4 +/**
1.5 + * Back 2 Browser Bytecode Translator
1.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
1.7 + *
1.8 + * This program is free software: you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation, version 2 of the License.
1.11 + *
1.12 + * This program is distributed in the hope that it will be useful,
1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.15 + * GNU General Public License for more details.
1.16 + *
1.17 + * You should have received a copy of the GNU General Public License
1.18 + * along with this program. Look for COPYING file in the top folder.
1.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
1.20 + */
1.21 +package org.apidesign.vm4brwsr;
1.22 +
1.23 +import java.io.IOException;
1.24 +import java.io.InputStream;
1.25 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
1.26 +import org.apidesign.javap.AnnotationParser;
1.27 +import org.apidesign.javap.ClassData;
1.28 +import org.apidesign.javap.FieldData;
1.29 +import org.apidesign.javap.MethodData;
1.30 +import org.apidesign.javap.StackMapIterator;
1.31 +import static org.apidesign.javap.RuntimeConstants.*;
1.32 +import org.apidesign.javap.TrapData;
1.33 +import org.apidesign.javap.TrapDataIterator;
1.34 +
1.35 +/** Translator of the code inside class files to JavaScript.
1.36 + *
1.37 + * @author Jaroslav Tulach <jtulach@netbeans.org>
1.38 + */
1.39 +abstract class ByteCodeToJavaScript {
1.40 + private ClassData jc;
1.41 + final Appendable out;
1.42 +
1.43 + protected ByteCodeToJavaScript(Appendable out) {
1.44 + this.out = out;
1.45 + }
1.46 +
1.47 + /* Collects additional required resources.
1.48 + *
1.49 + * @param internalClassName classes that were referenced and should be loaded in order the
1.50 + * generated JavaScript code works properly. The names are in internal
1.51 + * JVM form so String is <code>java/lang/String</code>.
1.52 + */
1.53 + protected abstract boolean requireReference(String internalClassName);
1.54 +
1.55 + /*
1.56 + * @param resourcePath name of resources to read
1.57 + */
1.58 + protected abstract void requireScript(String resourcePath) throws IOException;
1.59 +
1.60 + /** Allows subclasses to redefine what field a function representing a
1.61 + * class gets assigned. By default it returns the suggested name followed
1.62 + * by <code>" = "</code>;
1.63 + *
1.64 + * @param className suggested name of the class
1.65 + */
1.66 + /* protected */ String assignClass(String className) {
1.67 + return className + " = ";
1.68 + }
1.69 + /* protected */ String accessClass(String classOperation) {
1.70 + return classOperation;
1.71 + }
1.72 +
1.73 + /** Prints out a debug message.
1.74 + *
1.75 + * @param msg the message
1.76 + * @return true if the message has been printed
1.77 + * @throws IOException
1.78 + */
1.79 + boolean debug(String msg) throws IOException {
1.80 + out.append(msg);
1.81 + return true;
1.82 + }
1.83 +
1.84 + /**
1.85 + * Converts a given class file to a JavaScript version.
1.86 + *
1.87 + * @param classFile input stream with code of the .class file
1.88 + * @return the initialization code for this class, if any. Otherwise <code>null</code>
1.89 + *
1.90 + * @throws IOException if something goes wrong during read or write or translating
1.91 + */
1.92 +
1.93 + public String compile(InputStream classFile) throws IOException {
1.94 + this.jc = new ClassData(classFile);
1.95 + if (jc.getMajor_version() < 50) {
1.96 + throw new IOException("Can't compile " + jc.getClassName() + ". Class file version " + jc.getMajor_version() + "."
1.97 + + jc.getMinor_version() + " - recompile with -target 1.6 (at least)."
1.98 + );
1.99 + }
1.100 + byte[] arrData = jc.findAnnotationData(true);
1.101 + String[] arr = findAnnotation(arrData, jc,
1.102 + "org.apidesign.bck2brwsr.core.ExtraJavaScript",
1.103 + "resource", "processByteCode"
1.104 + );
1.105 + if (arr != null) {
1.106 + requireScript(arr[0]);
1.107 + if ("0".equals(arr[1])) {
1.108 + return null;
1.109 + }
1.110 + }
1.111 + String[] proto = findAnnotation(arrData, jc,
1.112 + "org.apidesign.bck2brwsr.core.JavaScriptPrototype",
1.113 + "container", "prototype"
1.114 + );
1.115 + StringArray toInitilize = new StringArray();
1.116 + final String className = className(jc);
1.117 + out.append("\n\n").append(assignClass(className));
1.118 + out.append("function CLS() {");
1.119 + out.append("\n if (!CLS.$class) {");
1.120 + if (proto == null) {
1.121 + String sc = jc.getSuperClassName(); // with _
1.122 + out.append("\n var pp = ").
1.123 + append(accessClass(sc.replace('/', '_'))).append("(true);");
1.124 + out.append("\n var p = CLS.prototype = pp;");
1.125 + out.append("\n var c = p;");
1.126 + out.append("\n var sprcls = pp.constructor.$class;");
1.127 + } else {
1.128 + out.append("\n var p = CLS.prototype = ").append(proto[1]).append(";");
1.129 + if (proto[0] == null) {
1.130 + proto[0] = "p";
1.131 + }
1.132 + out.append("\n var c = ").append(proto[0]).append(";");
1.133 + out.append("\n var sprcls = null;");
1.134 + }
1.135 + for (FieldData v : jc.getFields()) {
1.136 + if (v.isStatic()) {
1.137 + out.append("\n CLS.").append(v.getName()).append(initField(v));
1.138 + } else {
1.139 + out.append("\n c._").append(v.getName()).append(" = function (v) {")
1.140 + .append(" if (arguments.length == 1) this.fld_").
1.141 + append(className).append('_').append(v.getName())
1.142 + .append(" = v; return this.fld_").
1.143 + append(className).append('_').append(v.getName())
1.144 + .append("; };");
1.145 + }
1.146 + }
1.147 + for (MethodData m : jc.getMethods()) {
1.148 + byte[] onlyArr = m.findAnnotationData(true);
1.149 + String[] only = findAnnotation(onlyArr, jc,
1.150 + "org.apidesign.bck2brwsr.core.JavaScriptOnly",
1.151 + "name", "value"
1.152 + );
1.153 + if (only != null) {
1.154 + if (only[0] != null && only[1] != null) {
1.155 + out.append("\n p.").append(only[0]).append(" = ")
1.156 + .append(only[1]).append(";");
1.157 + }
1.158 + continue;
1.159 + }
1.160 + String prefix;
1.161 + String mn;
1.162 + if (m.isStatic()) {
1.163 + prefix = "\n c.";
1.164 + mn = generateStaticMethod(prefix, m, toInitilize);
1.165 + } else {
1.166 + if (m.isConstructor()) {
1.167 + prefix = "\n CLS.";
1.168 + mn = generateInstanceMethod(prefix, m);
1.169 + } else {
1.170 + prefix = "\n c.";
1.171 + mn = generateInstanceMethod(prefix, m);
1.172 + }
1.173 + }
1.174 + byte[] runAnno = m.findAnnotationData(false);
1.175 + if (runAnno != null) {
1.176 + out.append(prefix).append(mn).append(".anno = {");
1.177 + generateAnno(jc, out, runAnno);
1.178 + out.append("\n };");
1.179 + }
1.180 + out.append(prefix).append(mn).append(".access = " + m.getAccess()).append(";");
1.181 + out.append(prefix).append(mn).append(".cls = CLS;");
1.182 + }
1.183 + out.append("\n c.constructor = CLS;");
1.184 + out.append("\n c.$instOf_").append(className).append(" = true;");
1.185 + for (String superInterface : jc.getSuperInterfaces()) {
1.186 + out.append("\n c.$instOf_").append(superInterface.replace('/', '_')).append(" = true;");
1.187 + }
1.188 + out.append("\n CLS.$class = 'temp';");
1.189 + out.append("\n CLS.$class = ");
1.190 + out.append(accessClass("java_lang_Class(true);"));
1.191 + out.append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';");
1.192 + out.append("\n CLS.$class.superclass = sprcls;");
1.193 + out.append("\n CLS.$class.access = ").append(jc.getAccessFlags()+";");
1.194 + out.append("\n CLS.$class.cnstr = CLS;");
1.195 + byte[] classAnno = jc.findAnnotationData(false);
1.196 + if (classAnno != null) {
1.197 + out.append("\n CLS.$class.anno = {");
1.198 + generateAnno(jc, out, classAnno);
1.199 + out.append("\n };");
1.200 + }
1.201 + out.append("\n }");
1.202 + out.append("\n if (arguments.length === 0) {");
1.203 + out.append("\n if (!(this instanceof CLS)) {");
1.204 + out.append("\n return new CLS();");
1.205 + out.append("\n }");
1.206 + for (FieldData v : jc.getFields()) {
1.207 + byte[] onlyArr = v.findAnnotationData(true);
1.208 + String[] only = findAnnotation(onlyArr, jc,
1.209 + "org.apidesign.bck2brwsr.core.JavaScriptOnly",
1.210 + "name", "value"
1.211 + );
1.212 + if (only != null) {
1.213 + if (only[0] != null && only[1] != null) {
1.214 + out.append("\n p.").append(only[0]).append(" = ")
1.215 + .append(only[1]).append(";");
1.216 + }
1.217 + continue;
1.218 + }
1.219 + if (!v.isStatic()) {
1.220 + out.append("\n this.fld_").
1.221 + append(className).append('_').
1.222 + append(v.getName()).append(initField(v));
1.223 + }
1.224 + }
1.225 + out.append("\n return this;");
1.226 + out.append("\n }");
1.227 + out.append("\n return arguments[0] ? new CLS() : CLS.prototype;");
1.228 + out.append("\n};");
1.229 + StringBuilder sb = new StringBuilder();
1.230 + for (String init : toInitilize.toArray()) {
1.231 + sb.append("\n").append(init).append("();");
1.232 + }
1.233 + return sb.toString();
1.234 + }
1.235 + private String generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException {
1.236 + String jsb = javaScriptBody(prefix, m, true);
1.237 + if (jsb != null) {
1.238 + return jsb;
1.239 + }
1.240 + final String mn = findMethodName(m, new StringBuilder());
1.241 + if (mn.equals("class__V")) {
1.242 + toInitilize.add(accessClass(className(jc)) + "(false)." + mn);
1.243 + }
1.244 + generateMethod(prefix, mn, m);
1.245 + return mn;
1.246 + }
1.247 +
1.248 + private String generateInstanceMethod(String prefix, MethodData m) throws IOException {
1.249 + String jsb = javaScriptBody(prefix, m, false);
1.250 + if (jsb != null) {
1.251 + return jsb;
1.252 + }
1.253 + final String mn = findMethodName(m, new StringBuilder());
1.254 + generateMethod(prefix, mn, m);
1.255 + return mn;
1.256 + }
1.257 +
1.258 + private void generateMethod(String prefix, String name, MethodData m)
1.259 + throws IOException {
1.260 + final StackMapIterator stackMapIterator = m.createStackMapIterator();
1.261 + TrapDataIterator trap = m.getTrapDataIterator();
1.262 + final LocalsMapper lmapper =
1.263 + new LocalsMapper(stackMapIterator.getArguments());
1.264 +
1.265 + out.append(prefix).append(name).append(" = function(");
1.266 + lmapper.outputArguments(out, m.isStatic());
1.267 + out.append(") {").append("\n");
1.268 +
1.269 + final byte[] byteCodes = m.getCode();
1.270 + if (byteCodes == null) {
1.271 + out.append(" throw 'no code found for ")
1.272 + .append(jc.getClassName()).append('.')
1.273 + .append(m.getName()).append("';\n");
1.274 + out.append("};");
1.275 + return;
1.276 + }
1.277 +
1.278 + final StackMapper smapper = new StackMapper();
1.279 +
1.280 + if (!m.isStatic()) {
1.281 + out.append(" var ").append(" lcA0 = this;\n");
1.282 + }
1.283 +
1.284 + int lastStackFrame = -1;
1.285 + TrapData[] previousTrap = null;
1.286 + boolean wide = false;
1.287 +
1.288 + out.append("\n var gt = 0;\n for(;;) switch(gt) {\n");
1.289 + for (int i = 0; i < byteCodes.length; i++) {
1.290 + int prev = i;
1.291 + stackMapIterator.advanceTo(i);
1.292 + boolean changeInCatch = trap.advanceTo(i);
1.293 + if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) {
1.294 + if (previousTrap != null) {
1.295 + generateCatch(previousTrap);
1.296 + previousTrap = null;
1.297 + }
1.298 + }
1.299 + if (lastStackFrame != stackMapIterator.getFrameIndex()) {
1.300 + lastStackFrame = stackMapIterator.getFrameIndex();
1.301 + lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals());
1.302 + smapper.syncWithFrameStack(stackMapIterator.getFrameStack());
1.303 + out.append(" case " + i).append(": ");
1.304 + changeInCatch = true;
1.305 + } else {
1.306 + debug(" /* " + i + " */ ");
1.307 + }
1.308 + if (changeInCatch && trap.useTry()) {
1.309 + out.append("try {");
1.310 + previousTrap = trap.current();
1.311 + }
1.312 + final int c = readUByte(byteCodes, i);
1.313 + switch (c) {
1.314 + case opc_aload_0:
1.315 + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(0));
1.316 + break;
1.317 + case opc_iload_0:
1.318 + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(0));
1.319 + break;
1.320 + case opc_lload_0:
1.321 + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(0));
1.322 + break;
1.323 + case opc_fload_0:
1.324 + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(0));
1.325 + break;
1.326 + case opc_dload_0:
1.327 + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(0));
1.328 + break;
1.329 + case opc_aload_1:
1.330 + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(1));
1.331 + break;
1.332 + case opc_iload_1:
1.333 + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(1));
1.334 + break;
1.335 + case opc_lload_1:
1.336 + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(1));
1.337 + break;
1.338 + case opc_fload_1:
1.339 + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(1));
1.340 + break;
1.341 + case opc_dload_1:
1.342 + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(1));
1.343 + break;
1.344 + case opc_aload_2:
1.345 + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(2));
1.346 + break;
1.347 + case opc_iload_2:
1.348 + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(2));
1.349 + break;
1.350 + case opc_lload_2:
1.351 + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(2));
1.352 + break;
1.353 + case opc_fload_2:
1.354 + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(2));
1.355 + break;
1.356 + case opc_dload_2:
1.357 + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(2));
1.358 + break;
1.359 + case opc_aload_3:
1.360 + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(3));
1.361 + break;
1.362 + case opc_iload_3:
1.363 + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(3));
1.364 + break;
1.365 + case opc_lload_3:
1.366 + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(3));
1.367 + break;
1.368 + case opc_fload_3:
1.369 + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(3));
1.370 + break;
1.371 + case opc_dload_3:
1.372 + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(3));
1.373 + break;
1.374 + case opc_iload: {
1.375 + ++i;
1.376 + final int indx = wide ? readUShort(byteCodes, i++)
1.377 + : readUByte(byteCodes, i);
1.378 + wide = false;
1.379 + emit(out, "var @1 = @2;",
1.380 + smapper.pushI(), lmapper.getI(indx));
1.381 + break;
1.382 + }
1.383 + case opc_lload: {
1.384 + ++i;
1.385 + final int indx = wide ? readUShort(byteCodes, i++)
1.386 + : readUByte(byteCodes, i);
1.387 + wide = false;
1.388 + emit(out, "var @1 = @2;",
1.389 + smapper.pushL(), lmapper.getL(indx));
1.390 + break;
1.391 + }
1.392 + case opc_fload: {
1.393 + ++i;
1.394 + final int indx = wide ? readUShort(byteCodes, i++)
1.395 + : readUByte(byteCodes, i);
1.396 + wide = false;
1.397 + emit(out, "var @1 = @2;",
1.398 + smapper.pushF(), lmapper.getF(indx));
1.399 + break;
1.400 + }
1.401 + case opc_dload: {
1.402 + ++i;
1.403 + final int indx = wide ? readUShort(byteCodes, i++)
1.404 + : readUByte(byteCodes, i);
1.405 + wide = false;
1.406 + emit(out, "var @1 = @2;",
1.407 + smapper.pushD(), lmapper.getD(indx));
1.408 + break;
1.409 + }
1.410 + case opc_aload: {
1.411 + ++i;
1.412 + final int indx = wide ? readUShort(byteCodes, i++)
1.413 + : readUByte(byteCodes, i);
1.414 + wide = false;
1.415 + emit(out, "var @1 = @2;",
1.416 + smapper.pushA(), lmapper.getA(indx));
1.417 + break;
1.418 + }
1.419 + case opc_istore: {
1.420 + ++i;
1.421 + final int indx = wide ? readUShort(byteCodes, i++)
1.422 + : readUByte(byteCodes, i);
1.423 + wide = false;
1.424 + emit(out, "var @1 = @2;",
1.425 + lmapper.setI(indx), smapper.popI());
1.426 + break;
1.427 + }
1.428 + case opc_lstore: {
1.429 + ++i;
1.430 + final int indx = wide ? readUShort(byteCodes, i++)
1.431 + : readUByte(byteCodes, i);
1.432 + wide = false;
1.433 + emit(out, "var @1 = @2;",
1.434 + lmapper.setL(indx), smapper.popL());
1.435 + break;
1.436 + }
1.437 + case opc_fstore: {
1.438 + ++i;
1.439 + final int indx = wide ? readUShort(byteCodes, i++)
1.440 + : readUByte(byteCodes, i);
1.441 + wide = false;
1.442 + emit(out, "var @1 = @2;",
1.443 + lmapper.setF(indx), smapper.popF());
1.444 + break;
1.445 + }
1.446 + case opc_dstore: {
1.447 + ++i;
1.448 + final int indx = wide ? readUShort(byteCodes, i++)
1.449 + : readUByte(byteCodes, i);
1.450 + wide = false;
1.451 + emit(out, "var @1 = @2;",
1.452 + lmapper.setD(indx), smapper.popD());
1.453 + break;
1.454 + }
1.455 + case opc_astore: {
1.456 + ++i;
1.457 + final int indx = wide ? readUShort(byteCodes, i++)
1.458 + : readUByte(byteCodes, i);
1.459 + wide = false;
1.460 + emit(out, "var @1 = @2;",
1.461 + lmapper.setA(indx), smapper.popA());
1.462 + break;
1.463 + }
1.464 + case opc_astore_0:
1.465 + emit(out, "var @1 = @2;", lmapper.setA(0), smapper.popA());
1.466 + break;
1.467 + case opc_istore_0:
1.468 + emit(out, "var @1 = @2;", lmapper.setI(0), smapper.popI());
1.469 + break;
1.470 + case opc_lstore_0:
1.471 + emit(out, "var @1 = @2;", lmapper.setL(0), smapper.popL());
1.472 + break;
1.473 + case opc_fstore_0:
1.474 + emit(out, "var @1 = @2;", lmapper.setF(0), smapper.popF());
1.475 + break;
1.476 + case opc_dstore_0:
1.477 + emit(out, "var @1 = @2;", lmapper.setD(0), smapper.popD());
1.478 + break;
1.479 + case opc_astore_1:
1.480 + emit(out, "var @1 = @2;", lmapper.setA(1), smapper.popA());
1.481 + break;
1.482 + case opc_istore_1:
1.483 + emit(out, "var @1 = @2;", lmapper.setI(1), smapper.popI());
1.484 + break;
1.485 + case opc_lstore_1:
1.486 + emit(out, "var @1 = @2;", lmapper.setL(1), smapper.popL());
1.487 + break;
1.488 + case opc_fstore_1:
1.489 + emit(out, "var @1 = @2;", lmapper.setF(1), smapper.popF());
1.490 + break;
1.491 + case opc_dstore_1:
1.492 + emit(out, "var @1 = @2;", lmapper.setD(1), smapper.popD());
1.493 + break;
1.494 + case opc_astore_2:
1.495 + emit(out, "var @1 = @2;", lmapper.setA(2), smapper.popA());
1.496 + break;
1.497 + case opc_istore_2:
1.498 + emit(out, "var @1 = @2;", lmapper.setI(2), smapper.popI());
1.499 + break;
1.500 + case opc_lstore_2:
1.501 + emit(out, "var @1 = @2;", lmapper.setL(2), smapper.popL());
1.502 + break;
1.503 + case opc_fstore_2:
1.504 + emit(out, "var @1 = @2;", lmapper.setF(2), smapper.popF());
1.505 + break;
1.506 + case opc_dstore_2:
1.507 + emit(out, "var @1 = @2;", lmapper.setD(2), smapper.popD());
1.508 + break;
1.509 + case opc_astore_3:
1.510 + emit(out, "var @1 = @2;", lmapper.setA(3), smapper.popA());
1.511 + break;
1.512 + case opc_istore_3:
1.513 + emit(out, "var @1 = @2;", lmapper.setI(3), smapper.popI());
1.514 + break;
1.515 + case opc_lstore_3:
1.516 + emit(out, "var @1 = @2;", lmapper.setL(3), smapper.popL());
1.517 + break;
1.518 + case opc_fstore_3:
1.519 + emit(out, "var @1 = @2;", lmapper.setF(3), smapper.popF());
1.520 + break;
1.521 + case opc_dstore_3:
1.522 + emit(out, "var @1 = @2;", lmapper.setD(3), smapper.popD());
1.523 + break;
1.524 + case opc_iadd:
1.525 + emit(out, "@1 = @1.add32(@2);", smapper.getI(1), smapper.popI());
1.526 + break;
1.527 + case opc_ladd:
1.528 + emit(out, "@1 = @1.add64(@2);", smapper.getL(1), smapper.popL());
1.529 + break;
1.530 + case opc_fadd:
1.531 + emit(out, "@1 += @2;", smapper.getF(1), smapper.popF());
1.532 + break;
1.533 + case opc_dadd:
1.534 + emit(out, "@1 += @2;", smapper.getD(1), smapper.popD());
1.535 + break;
1.536 + case opc_isub:
1.537 + emit(out, "@1 = @1.sub32(@2);", smapper.getI(1), smapper.popI());
1.538 + break;
1.539 + case opc_lsub:
1.540 + emit(out, "@1 = @1.sub64(@2);", smapper.getL(1), smapper.popL());
1.541 + break;
1.542 + case opc_fsub:
1.543 + emit(out, "@1 -= @2;", smapper.getF(1), smapper.popF());
1.544 + break;
1.545 + case opc_dsub:
1.546 + emit(out, "@1 -= @2;", smapper.getD(1), smapper.popD());
1.547 + break;
1.548 + case opc_imul:
1.549 + emit(out, "@1 = @1.mul32(@2);", smapper.getI(1), smapper.popI());
1.550 + break;
1.551 + case opc_lmul:
1.552 + emit(out, "@1 = @1.mul64(@2);", smapper.getL(1), smapper.popL());
1.553 + break;
1.554 + case opc_fmul:
1.555 + emit(out, "@1 *= @2;", smapper.getF(1), smapper.popF());
1.556 + break;
1.557 + case opc_dmul:
1.558 + emit(out, "@1 *= @2;", smapper.getD(1), smapper.popD());
1.559 + break;
1.560 + case opc_idiv:
1.561 + emit(out, "@1 = @1.div32(@2);",
1.562 + smapper.getI(1), smapper.popI());
1.563 + break;
1.564 + case opc_ldiv:
1.565 + emit(out, "@1 = @1.div64(@2);",
1.566 + smapper.getL(1), smapper.popL());
1.567 + break;
1.568 + case opc_fdiv:
1.569 + emit(out, "@1 /= @2;", smapper.getF(1), smapper.popF());
1.570 + break;
1.571 + case opc_ddiv:
1.572 + emit(out, "@1 /= @2;", smapper.getD(1), smapper.popD());
1.573 + break;
1.574 + case opc_irem:
1.575 + emit(out, "@1 = @1.mod32(@2);",
1.576 + smapper.getI(1), smapper.popI());
1.577 + break;
1.578 + case opc_lrem:
1.579 + emit(out, "@1 = @1.mod64(@2);",
1.580 + smapper.getL(1), smapper.popL());
1.581 + break;
1.582 + case opc_frem:
1.583 + emit(out, "@1 %= @2;", smapper.getF(1), smapper.popF());
1.584 + break;
1.585 + case opc_drem:
1.586 + emit(out, "@1 %= @2;", smapper.getD(1), smapper.popD());
1.587 + break;
1.588 + case opc_iand:
1.589 + emit(out, "@1 &= @2;", smapper.getI(1), smapper.popI());
1.590 + break;
1.591 + case opc_land:
1.592 + emit(out, "@1 = @1.and64(@2);", smapper.getL(1), smapper.popL());
1.593 + break;
1.594 + case opc_ior:
1.595 + emit(out, "@1 |= @2;", smapper.getI(1), smapper.popI());
1.596 + break;
1.597 + case opc_lor:
1.598 + emit(out, "@1 = @1.or64(@2);", smapper.getL(1), smapper.popL());
1.599 + break;
1.600 + case opc_ixor:
1.601 + emit(out, "@1 ^= @2;", smapper.getI(1), smapper.popI());
1.602 + break;
1.603 + case opc_lxor:
1.604 + emit(out, "@1 = @1.xor64(@2);", smapper.getL(1), smapper.popL());
1.605 + break;
1.606 + case opc_ineg:
1.607 + emit(out, "@1 = @1.neg32();", smapper.getI(0));
1.608 + break;
1.609 + case opc_lneg:
1.610 + emit(out, "@1 = @1.neg64();", smapper.getL(0));
1.611 + break;
1.612 + case opc_fneg:
1.613 + emit(out, "@1 = -@1;", smapper.getF(0));
1.614 + break;
1.615 + case opc_dneg:
1.616 + emit(out, "@1 = -@1;", smapper.getD(0));
1.617 + break;
1.618 + case opc_ishl:
1.619 + emit(out, "@1 <<= @2;", smapper.getI(1), smapper.popI());
1.620 + break;
1.621 + case opc_lshl:
1.622 + emit(out, "@1 = @1.shl64(@2);", smapper.getL(1), smapper.popI());
1.623 + break;
1.624 + case opc_ishr:
1.625 + emit(out, "@1 >>= @2;", smapper.getI(1), smapper.popI());
1.626 + break;
1.627 + case opc_lshr:
1.628 + emit(out, "@1 = @1.shr64(@2);", smapper.getL(1), smapper.popI());
1.629 + break;
1.630 + case opc_iushr:
1.631 + emit(out, "@1 >>>= @2;", smapper.getI(1), smapper.popI());
1.632 + break;
1.633 + case opc_lushr:
1.634 + emit(out, "@1 = @1.ushr64(@2);", smapper.getL(1), smapper.popI());
1.635 + break;
1.636 + case opc_iinc: {
1.637 + ++i;
1.638 + final int varIndx = wide ? readUShort(byteCodes, i++)
1.639 + : readUByte(byteCodes, i);
1.640 + ++i;
1.641 + final int incrBy = wide ? readShort(byteCodes, i++)
1.642 + : byteCodes[i];
1.643 + wide = false;
1.644 + if (incrBy == 1) {
1.645 + emit(out, "@1++;", lmapper.getI(varIndx));
1.646 + } else {
1.647 + emit(out, "@1 += @2;",
1.648 + lmapper.getI(varIndx),
1.649 + Integer.toString(incrBy));
1.650 + }
1.651 + break;
1.652 + }
1.653 + case opc_return:
1.654 + emit(out, "return;");
1.655 + break;
1.656 + case opc_ireturn:
1.657 + emit(out, "return @1;", smapper.popI());
1.658 + break;
1.659 + case opc_lreturn:
1.660 + emit(out, "return @1;", smapper.popL());
1.661 + break;
1.662 + case opc_freturn:
1.663 + emit(out, "return @1;", smapper.popF());
1.664 + break;
1.665 + case opc_dreturn:
1.666 + emit(out, "return @1;", smapper.popD());
1.667 + break;
1.668 + case opc_areturn:
1.669 + emit(out, "return @1;", smapper.popA());
1.670 + break;
1.671 + case opc_i2l:
1.672 + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushL());
1.673 + break;
1.674 + case opc_i2f:
1.675 + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushF());
1.676 + break;
1.677 + case opc_i2d:
1.678 + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushD());
1.679 + break;
1.680 + case opc_l2i:
1.681 + emit(out, "var @2 = @1.toInt32();", smapper.popL(), smapper.pushI());
1.682 + break;
1.683 + // max int check?
1.684 + case opc_l2f:
1.685 + emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushF());
1.686 + break;
1.687 + case opc_l2d:
1.688 + emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushD());
1.689 + break;
1.690 + case opc_f2d:
1.691 + emit(out, "var @2 = @1;", smapper.popF(), smapper.pushD());
1.692 + break;
1.693 + case opc_d2f:
1.694 + emit(out, "var @2 = @1;", smapper.popD(), smapper.pushF());
1.695 + break;
1.696 + case opc_f2i:
1.697 + emit(out, "var @2 = Math.floor(@1).toInt32();",
1.698 + smapper.popF(), smapper.pushI());
1.699 + break;
1.700 + case opc_f2l:
1.701 + emit(out, "var @2 = Math.floor(@1).toLong();",
1.702 + smapper.popF(), smapper.pushL());
1.703 + break;
1.704 + case opc_d2i:
1.705 + emit(out, "var @2 = Math.floor(@1).toInt32();",
1.706 + smapper.popD(), smapper.pushI());
1.707 + break;
1.708 + case opc_d2l:
1.709 + emit(out, "var @2 = Math.floor(@1).toLong();",
1.710 + smapper.popD(), smapper.pushL());
1.711 + break;
1.712 + case opc_i2b:
1.713 + emit(out, "var @1 = @1.toInt8();", smapper.getI(0));
1.714 + break;
1.715 + case opc_i2c:
1.716 + out.append("{ /* number conversion */ }");
1.717 + break;
1.718 + case opc_i2s:
1.719 + emit(out, "var @1 = @1.toInt16();", smapper.getI(0));
1.720 + break;
1.721 + case opc_aconst_null:
1.722 + emit(out, "var @1 = null;", smapper.pushA());
1.723 + break;
1.724 + case opc_iconst_m1:
1.725 + emit(out, "var @1 = -1;", smapper.pushI());
1.726 + break;
1.727 + case opc_iconst_0:
1.728 + emit(out, "var @1 = 0;", smapper.pushI());
1.729 + break;
1.730 + case opc_dconst_0:
1.731 + emit(out, "var @1 = 0;", smapper.pushD());
1.732 + break;
1.733 + case opc_lconst_0:
1.734 + emit(out, "var @1 = 0;", smapper.pushL());
1.735 + break;
1.736 + case opc_fconst_0:
1.737 + emit(out, "var @1 = 0;", smapper.pushF());
1.738 + break;
1.739 + case opc_iconst_1:
1.740 + emit(out, "var @1 = 1;", smapper.pushI());
1.741 + break;
1.742 + case opc_lconst_1:
1.743 + emit(out, "var @1 = 1;", smapper.pushL());
1.744 + break;
1.745 + case opc_fconst_1:
1.746 + emit(out, "var @1 = 1;", smapper.pushF());
1.747 + break;
1.748 + case opc_dconst_1:
1.749 + emit(out, "var @1 = 1;", smapper.pushD());
1.750 + break;
1.751 + case opc_iconst_2:
1.752 + emit(out, "var @1 = 2;", smapper.pushI());
1.753 + break;
1.754 + case opc_fconst_2:
1.755 + emit(out, "var @1 = 2;", smapper.pushF());
1.756 + break;
1.757 + case opc_iconst_3:
1.758 + emit(out, "var @1 = 3;", smapper.pushI());
1.759 + break;
1.760 + case opc_iconst_4:
1.761 + emit(out, "var @1 = 4;", smapper.pushI());
1.762 + break;
1.763 + case opc_iconst_5:
1.764 + emit(out, "var @1 = 5;", smapper.pushI());
1.765 + break;
1.766 + case opc_ldc: {
1.767 + int indx = readUByte(byteCodes, ++i);
1.768 + String v = encodeConstant(indx);
1.769 + int type = VarType.fromConstantType(jc.getTag(indx));
1.770 + emit(out, "var @1 = @2;", smapper.pushT(type), v);
1.771 + break;
1.772 + }
1.773 + case opc_ldc_w:
1.774 + case opc_ldc2_w: {
1.775 + int indx = readIntArg(byteCodes, i);
1.776 + i += 2;
1.777 + String v = encodeConstant(indx);
1.778 + int type = VarType.fromConstantType(jc.getTag(indx));
1.779 + if (type == VarType.LONG) {
1.780 + final Long lv = new Long(v);
1.781 + final int low = (int)(lv.longValue() & 0xFFFFFFFF);
1.782 + final int hi = (int)(lv.longValue() >> 32);
1.783 + emit(out, "var @1 = 0x@3.next32(0x@2);", smapper.pushL(),
1.784 + Integer.toHexString(low), Integer.toHexString(hi));
1.785 + } else {
1.786 + emit(out, "var @1 = @2;", smapper.pushT(type), v);
1.787 + }
1.788 + break;
1.789 + }
1.790 + case opc_lcmp:
1.791 + emit(out, "var @3 = @2.compare64(@1);",
1.792 + smapper.popL(), smapper.popL(), smapper.pushI());
1.793 + break;
1.794 + case opc_fcmpl:
1.795 + case opc_fcmpg:
1.796 + emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
1.797 + smapper.popF(), smapper.popF(), smapper.pushI());
1.798 + break;
1.799 + case opc_dcmpl:
1.800 + case opc_dcmpg:
1.801 + emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
1.802 + smapper.popD(), smapper.popD(), smapper.pushI());
1.803 + break;
1.804 + case opc_if_acmpeq:
1.805 + i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
1.806 + "===");
1.807 + break;
1.808 + case opc_if_acmpne:
1.809 + i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
1.810 + "!=");
1.811 + break;
1.812 + case opc_if_icmpeq:
1.813 + i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.814 + "==");
1.815 + break;
1.816 + case opc_ifeq: {
1.817 + int indx = i + readIntArg(byteCodes, i);
1.818 + emit(out, "if (@1 == 0) { gt = @2; continue; }",
1.819 + smapper.popI(), Integer.toString(indx));
1.820 + i += 2;
1.821 + break;
1.822 + }
1.823 + case opc_ifne: {
1.824 + int indx = i + readIntArg(byteCodes, i);
1.825 + emit(out, "if (@1 != 0) { gt = @2; continue; }",
1.826 + smapper.popI(), Integer.toString(indx));
1.827 + i += 2;
1.828 + break;
1.829 + }
1.830 + case opc_iflt: {
1.831 + int indx = i + readIntArg(byteCodes, i);
1.832 + emit(out, "if (@1 < 0) { gt = @2; continue; }",
1.833 + smapper.popI(), Integer.toString(indx));
1.834 + i += 2;
1.835 + break;
1.836 + }
1.837 + case opc_ifle: {
1.838 + int indx = i + readIntArg(byteCodes, i);
1.839 + emit(out, "if (@1 <= 0) { gt = @2; continue; }",
1.840 + smapper.popI(), Integer.toString(indx));
1.841 + i += 2;
1.842 + break;
1.843 + }
1.844 + case opc_ifgt: {
1.845 + int indx = i + readIntArg(byteCodes, i);
1.846 + emit(out, "if (@1 > 0) { gt = @2; continue; }",
1.847 + smapper.popI(), Integer.toString(indx));
1.848 + i += 2;
1.849 + break;
1.850 + }
1.851 + case opc_ifge: {
1.852 + int indx = i + readIntArg(byteCodes, i);
1.853 + emit(out, "if (@1 >= 0) { gt = @2; continue; }",
1.854 + smapper.popI(), Integer.toString(indx));
1.855 + i += 2;
1.856 + break;
1.857 + }
1.858 + case opc_ifnonnull: {
1.859 + int indx = i + readIntArg(byteCodes, i);
1.860 + emit(out, "if (@1 !== null) { gt = @2; continue; }",
1.861 + smapper.popA(), Integer.toString(indx));
1.862 + i += 2;
1.863 + break;
1.864 + }
1.865 + case opc_ifnull: {
1.866 + int indx = i + readIntArg(byteCodes, i);
1.867 + emit(out, "if (@1 === null) { gt = @2; continue; }",
1.868 + smapper.popA(), Integer.toString(indx));
1.869 + i += 2;
1.870 + break;
1.871 + }
1.872 + case opc_if_icmpne:
1.873 + i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.874 + "!=");
1.875 + break;
1.876 + case opc_if_icmplt:
1.877 + i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.878 + "<");
1.879 + break;
1.880 + case opc_if_icmple:
1.881 + i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.882 + "<=");
1.883 + break;
1.884 + case opc_if_icmpgt:
1.885 + i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.886 + ">");
1.887 + break;
1.888 + case opc_if_icmpge:
1.889 + i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.890 + ">=");
1.891 + break;
1.892 + case opc_goto: {
1.893 + int indx = i + readIntArg(byteCodes, i);
1.894 + emit(out, "gt = @1; continue;", Integer.toString(indx));
1.895 + i += 2;
1.896 + break;
1.897 + }
1.898 + case opc_lookupswitch: {
1.899 + int table = i / 4 * 4 + 4;
1.900 + int dflt = i + readInt4(byteCodes, table);
1.901 + table += 4;
1.902 + int n = readInt4(byteCodes, table);
1.903 + table += 4;
1.904 + out.append("switch (").append(smapper.popI()).append(") {\n");
1.905 + while (n-- > 0) {
1.906 + int cnstnt = readInt4(byteCodes, table);
1.907 + table += 4;
1.908 + int offset = i + readInt4(byteCodes, table);
1.909 + table += 4;
1.910 + out.append(" case " + cnstnt).append(": gt = " + offset).append("; continue;\n");
1.911 + }
1.912 + out.append(" default: gt = " + dflt).append("; continue;\n}");
1.913 + i = table - 1;
1.914 + break;
1.915 + }
1.916 + case opc_tableswitch: {
1.917 + int table = i / 4 * 4 + 4;
1.918 + int dflt = i + readInt4(byteCodes, table);
1.919 + table += 4;
1.920 + int low = readInt4(byteCodes, table);
1.921 + table += 4;
1.922 + int high = readInt4(byteCodes, table);
1.923 + table += 4;
1.924 + out.append("switch (").append(smapper.popI()).append(") {\n");
1.925 + while (low <= high) {
1.926 + int offset = i + readInt4(byteCodes, table);
1.927 + table += 4;
1.928 + out.append(" case " + low).append(": gt = " + offset).append("; continue;\n");
1.929 + low++;
1.930 + }
1.931 + out.append(" default: gt = " + dflt).append("; continue;\n}");
1.932 + i = table - 1;
1.933 + break;
1.934 + }
1.935 + case opc_invokeinterface: {
1.936 + i = invokeVirtualMethod(byteCodes, i, smapper) + 2;
1.937 + break;
1.938 + }
1.939 + case opc_invokevirtual:
1.940 + i = invokeVirtualMethod(byteCodes, i, smapper);
1.941 + break;
1.942 + case opc_invokespecial:
1.943 + i = invokeStaticMethod(byteCodes, i, smapper, false);
1.944 + break;
1.945 + case opc_invokestatic:
1.946 + i = invokeStaticMethod(byteCodes, i, smapper, true);
1.947 + break;
1.948 + case opc_new: {
1.949 + int indx = readIntArg(byteCodes, i);
1.950 + String ci = jc.getClassName(indx);
1.951 + emit(out, "var @1 = new @2;",
1.952 + smapper.pushA(), accessClass(ci.replace('/', '_')));
1.953 + addReference(ci);
1.954 + i += 2;
1.955 + break;
1.956 + }
1.957 + case opc_newarray:
1.958 + int atype = readUByte(byteCodes, ++i);
1.959 + String jvmType;
1.960 + switch (atype) {
1.961 + case 4: jvmType = "[Z"; break;
1.962 + case 5: jvmType = "[C"; break;
1.963 + case 6: jvmType = "[F"; break;
1.964 + case 7: jvmType = "[D"; break;
1.965 + case 8: jvmType = "[B"; break;
1.966 + case 9: jvmType = "[S"; break;
1.967 + case 10: jvmType = "[I"; break;
1.968 + case 11: jvmType = "[J"; break;
1.969 + default: throw new IllegalStateException("Array type: " + atype);
1.970 + }
1.971 + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);",
1.972 + smapper.popI(), smapper.pushA(), jvmType);
1.973 + break;
1.974 + case opc_anewarray: {
1.975 + int type = readIntArg(byteCodes, i);
1.976 + i += 2;
1.977 + String typeName = jc.getClassName(type);
1.978 + if (typeName.startsWith("[")) {
1.979 + typeName = "[" + typeName;
1.980 + } else {
1.981 + typeName = "[L" + typeName + ";";
1.982 + }
1.983 + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);",
1.984 + smapper.popI(), smapper.pushA(), typeName);
1.985 + break;
1.986 + }
1.987 + case opc_multianewarray: {
1.988 + int type = readIntArg(byteCodes, i);
1.989 + i += 2;
1.990 + String typeName = jc.getClassName(type);
1.991 + int dim = readUByte(byteCodes, ++i);
1.992 + StringBuilder dims = new StringBuilder();
1.993 + dims.append('[');
1.994 + for (int d = 0; d < dim; d++) {
1.995 + if (d != 0) {
1.996 + dims.append(",");
1.997 + }
1.998 + dims.append(smapper.popI());
1.999 + }
1.1000 + dims.append(']');
1.1001 + emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);",
1.1002 + dims.toString(), smapper.pushA(), typeName);
1.1003 + break;
1.1004 + }
1.1005 + case opc_arraylength:
1.1006 + emit(out, "var @2 = @1.length;",
1.1007 + smapper.popA(), smapper.pushI());
1.1008 + break;
1.1009 + case opc_lastore:
1.1010 + emit(out, "@3.at(@2, @1);",
1.1011 + smapper.popL(), smapper.popI(), smapper.popA());
1.1012 + break;
1.1013 + case opc_fastore:
1.1014 + emit(out, "@3.at(@2, @1);",
1.1015 + smapper.popF(), smapper.popI(), smapper.popA());
1.1016 + break;
1.1017 + case opc_dastore:
1.1018 + emit(out, "@3.at(@2, @1);",
1.1019 + smapper.popD(), smapper.popI(), smapper.popA());
1.1020 + break;
1.1021 + case opc_aastore:
1.1022 + emit(out, "@3.at(@2, @1);",
1.1023 + smapper.popA(), smapper.popI(), smapper.popA());
1.1024 + break;
1.1025 + case opc_iastore:
1.1026 + case opc_bastore:
1.1027 + case opc_castore:
1.1028 + case opc_sastore:
1.1029 + emit(out, "@3.at(@2, @1);",
1.1030 + smapper.popI(), smapper.popI(), smapper.popA());
1.1031 + break;
1.1032 + case opc_laload:
1.1033 + emit(out, "var @3 = @2.at(@1);",
1.1034 + smapper.popI(), smapper.popA(), smapper.pushL());
1.1035 + break;
1.1036 + case opc_faload:
1.1037 + emit(out, "var @3 = @2.at(@1);",
1.1038 + smapper.popI(), smapper.popA(), smapper.pushF());
1.1039 + break;
1.1040 + case opc_daload:
1.1041 + emit(out, "var @3 = @2.at(@1);",
1.1042 + smapper.popI(), smapper.popA(), smapper.pushD());
1.1043 + break;
1.1044 + case opc_aaload:
1.1045 + emit(out, "var @3 = @2.at(@1);",
1.1046 + smapper.popI(), smapper.popA(), smapper.pushA());
1.1047 + break;
1.1048 + case opc_iaload:
1.1049 + case opc_baload:
1.1050 + case opc_caload:
1.1051 + case opc_saload:
1.1052 + emit(out, "var @3 = @2.at(@1);",
1.1053 + smapper.popI(), smapper.popA(), smapper.pushI());
1.1054 + break;
1.1055 + case opc_pop:
1.1056 + case opc_pop2:
1.1057 + smapper.pop(1);
1.1058 + debug("/* pop */");
1.1059 + break;
1.1060 + case opc_dup: {
1.1061 + final Variable v = smapper.get(0);
1.1062 + emit(out, "var @1 = @2;", smapper.pushT(v.getType()), v);
1.1063 + break;
1.1064 + }
1.1065 + case opc_dup2: {
1.1066 + final Variable vi1 = smapper.get(0);
1.1067 +
1.1068 + if (vi1.isCategory2()) {
1.1069 + emit(out, "var @1 = @2;",
1.1070 + smapper.pushT(vi1.getType()), vi1);
1.1071 + } else {
1.1072 + final Variable vi2 = smapper.get(1);
1.1073 + emit(out, "var @1 = @2, @3 = @4;",
1.1074 + smapper.pushT(vi2.getType()), vi2,
1.1075 + smapper.pushT(vi1.getType()), vi1);
1.1076 + }
1.1077 + break;
1.1078 + }
1.1079 + case opc_dup_x1: {
1.1080 + final Variable vi1 = smapper.pop();
1.1081 + final Variable vi2 = smapper.pop();
1.1082 + final Variable vo3 = smapper.pushT(vi1.getType());
1.1083 + final Variable vo2 = smapper.pushT(vi2.getType());
1.1084 + final Variable vo1 = smapper.pushT(vi1.getType());
1.1085 +
1.1086 + emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
1.1087 + vo1, vi1, vo2, vi2, vo3, vo1);
1.1088 + break;
1.1089 + }
1.1090 + case opc_dup2_x1: {
1.1091 + final Variable vi1 = smapper.pop();
1.1092 + final Variable vi2 = smapper.pop();
1.1093 +
1.1094 + if (vi1.isCategory2()) {
1.1095 + final Variable vo3 = smapper.pushT(vi1.getType());
1.1096 + final Variable vo2 = smapper.pushT(vi2.getType());
1.1097 + final Variable vo1 = smapper.pushT(vi1.getType());
1.1098 +
1.1099 + emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
1.1100 + vo1, vi1, vo2, vi2, vo3, vo1);
1.1101 + } else {
1.1102 + final Variable vi3 = smapper.pop();
1.1103 + final Variable vo5 = smapper.pushT(vi2.getType());
1.1104 + final Variable vo4 = smapper.pushT(vi1.getType());
1.1105 + final Variable vo3 = smapper.pushT(vi3.getType());
1.1106 + final Variable vo2 = smapper.pushT(vi2.getType());
1.1107 + final Variable vo1 = smapper.pushT(vi1.getType());
1.1108 +
1.1109 + emit(out, "var @1 = @2, @3 = @4, @5 = @6,",
1.1110 + vo1, vi1, vo2, vi2, vo3, vi3);
1.1111 + emit(out, " @1 = @2, @3 = @4;",
1.1112 + vo4, vo1, vo5, vo2);
1.1113 + }
1.1114 + break;
1.1115 + }
1.1116 + case opc_dup_x2: {
1.1117 + final Variable vi1 = smapper.pop();
1.1118 + final Variable vi2 = smapper.pop();
1.1119 +
1.1120 + if (vi2.isCategory2()) {
1.1121 + final Variable vo3 = smapper.pushT(vi1.getType());
1.1122 + final Variable vo2 = smapper.pushT(vi2.getType());
1.1123 + final Variable vo1 = smapper.pushT(vi1.getType());
1.1124 +
1.1125 + emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
1.1126 + vo1, vi1, vo2, vi2, vo3, vo1);
1.1127 + } else {
1.1128 + final Variable vi3 = smapper.pop();
1.1129 + final Variable vo4 = smapper.pushT(vi1.getType());
1.1130 + final Variable vo3 = smapper.pushT(vi3.getType());
1.1131 + final Variable vo2 = smapper.pushT(vi2.getType());
1.1132 + final Variable vo1 = smapper.pushT(vi1.getType());
1.1133 +
1.1134 + emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;",
1.1135 + vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1);
1.1136 + }
1.1137 + break;
1.1138 + }
1.1139 + case opc_dup2_x2: {
1.1140 + final Variable vi1 = smapper.pop();
1.1141 + final Variable vi2 = smapper.pop();
1.1142 +
1.1143 + if (vi1.isCategory2()) {
1.1144 + if (vi2.isCategory2()) {
1.1145 + final Variable vo3 = smapper.pushT(vi1.getType());
1.1146 + final Variable vo2 = smapper.pushT(vi2.getType());
1.1147 + final Variable vo1 = smapper.pushT(vi1.getType());
1.1148 +
1.1149 + emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
1.1150 + vo1, vi1, vo2, vi2, vo3, vo1);
1.1151 + } else {
1.1152 + final Variable vi3 = smapper.pop();
1.1153 + final Variable vo4 = smapper.pushT(vi1.getType());
1.1154 + final Variable vo3 = smapper.pushT(vi3.getType());
1.1155 + final Variable vo2 = smapper.pushT(vi2.getType());
1.1156 + final Variable vo1 = smapper.pushT(vi1.getType());
1.1157 +
1.1158 + emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;",
1.1159 + vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1);
1.1160 + }
1.1161 + } else {
1.1162 + final Variable vi3 = smapper.pop();
1.1163 +
1.1164 + if (vi3.isCategory2()) {
1.1165 + final Variable vo5 = smapper.pushT(vi2.getType());
1.1166 + final Variable vo4 = smapper.pushT(vi1.getType());
1.1167 + final Variable vo3 = smapper.pushT(vi3.getType());
1.1168 + final Variable vo2 = smapper.pushT(vi2.getType());
1.1169 + final Variable vo1 = smapper.pushT(vi1.getType());
1.1170 +
1.1171 + emit(out, "var @1 = @2, @3 = @4, @5 = @6,",
1.1172 + vo1, vi1, vo2, vi2, vo3, vi3);
1.1173 + emit(out, " @1 = @2, @3 = @4;",
1.1174 + vo4, vo1, vo5, vo2);
1.1175 + } else {
1.1176 + final Variable vi4 = smapper.pop();
1.1177 + final Variable vo6 = smapper.pushT(vi2.getType());
1.1178 + final Variable vo5 = smapper.pushT(vi1.getType());
1.1179 + final Variable vo4 = smapper.pushT(vi4.getType());
1.1180 + final Variable vo3 = smapper.pushT(vi3.getType());
1.1181 + final Variable vo2 = smapper.pushT(vi2.getType());
1.1182 + final Variable vo1 = smapper.pushT(vi1.getType());
1.1183 +
1.1184 + emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8,",
1.1185 + vo1, vi1, vo2, vi2, vo3, vi3, vo4, vi4);
1.1186 + emit(out, " @1 = @2, @3 = @4;",
1.1187 + vo5, vo1, vo6, vo2);
1.1188 + }
1.1189 + }
1.1190 + break;
1.1191 + }
1.1192 + case opc_swap: {
1.1193 + final Variable vi1 = smapper.get(0);
1.1194 + final Variable vi2 = smapper.get(1);
1.1195 +
1.1196 + if (vi1.getType() == vi2.getType()) {
1.1197 + final Variable tmp = smapper.pushT(vi1.getType());
1.1198 +
1.1199 + emit(out, "var @1 = @2, @2 = @3, @3 = @1;",
1.1200 + tmp, vi1, vi2);
1.1201 + smapper.pop(1);
1.1202 + } else {
1.1203 + smapper.pop(2);
1.1204 + smapper.pushT(vi1.getType());
1.1205 + smapper.pushT(vi2.getType());
1.1206 + }
1.1207 + break;
1.1208 + }
1.1209 + case opc_bipush:
1.1210 + emit(out, "var @1 = @2;",
1.1211 + smapper.pushI(), Integer.toString(byteCodes[++i]));
1.1212 + break;
1.1213 + case opc_sipush:
1.1214 + emit(out, "var @1 = @2;",
1.1215 + smapper.pushI(),
1.1216 + Integer.toString(readIntArg(byteCodes, i)));
1.1217 + i += 2;
1.1218 + break;
1.1219 + case opc_getfield: {
1.1220 + int indx = readIntArg(byteCodes, i);
1.1221 + String[] fi = jc.getFieldInfoName(indx);
1.1222 + final int type = VarType.fromFieldType(fi[2].charAt(0));
1.1223 + final String mangleClass = mangleSig(fi[0]);
1.1224 + final String mangleClassAccess = accessClass(mangleClass);
1.1225 + emit(out, "var @2 = @4(false)._@3.call(@1);",
1.1226 + smapper.popA(),
1.1227 + smapper.pushT(type), fi[1], mangleClassAccess
1.1228 + );
1.1229 + i += 2;
1.1230 + break;
1.1231 + }
1.1232 + case opc_putfield: {
1.1233 + int indx = readIntArg(byteCodes, i);
1.1234 + String[] fi = jc.getFieldInfoName(indx);
1.1235 + final int type = VarType.fromFieldType(fi[2].charAt(0));
1.1236 + final String mangleClass = mangleSig(fi[0]);
1.1237 + final String mangleClassAccess = accessClass(mangleClass);
1.1238 + emit(out, "@4(false)._@3.call(@2, @1);",
1.1239 + smapper.popT(type),
1.1240 + smapper.popA(), fi[1],
1.1241 + mangleClassAccess
1.1242 + );
1.1243 + i += 2;
1.1244 + break;
1.1245 + }
1.1246 + case opc_getstatic: {
1.1247 + int indx = readIntArg(byteCodes, i);
1.1248 + String[] fi = jc.getFieldInfoName(indx);
1.1249 + final int type = VarType.fromFieldType(fi[2].charAt(0));
1.1250 + emit(out, "var @1 = @2(false).constructor.@3;",
1.1251 + smapper.pushT(type),
1.1252 + accessClass(fi[0].replace('/', '_')), fi[1]);
1.1253 + i += 2;
1.1254 + addReference(fi[0]);
1.1255 + break;
1.1256 + }
1.1257 + case opc_putstatic: {
1.1258 + int indx = readIntArg(byteCodes, i);
1.1259 + String[] fi = jc.getFieldInfoName(indx);
1.1260 + final int type = VarType.fromFieldType(fi[2].charAt(0));
1.1261 + emit(out, "@1(false).constructor.@2 = @3;",
1.1262 + accessClass(fi[0].replace('/', '_')), fi[1],
1.1263 + smapper.popT(type));
1.1264 + i += 2;
1.1265 + addReference(fi[0]);
1.1266 + break;
1.1267 + }
1.1268 + case opc_checkcast: {
1.1269 + int indx = readIntArg(byteCodes, i);
1.1270 + final String type = jc.getClassName(indx);
1.1271 + if (!type.startsWith("[")) {
1.1272 + emit(out,
1.1273 + "if (@1 !== null && !@1.$instOf_@2) throw {};",
1.1274 + smapper.getA(0), type.replace('/', '_'));
1.1275 + } else {
1.1276 + emit(out, "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@2').cast__Ljava_lang_Object_2Ljava_lang_Object_2(@1);",
1.1277 + smapper.getA(0), type
1.1278 + );
1.1279 + }
1.1280 + i += 2;
1.1281 + break;
1.1282 + }
1.1283 + case opc_instanceof: {
1.1284 + int indx = readIntArg(byteCodes, i);
1.1285 + final String type = jc.getClassName(indx);
1.1286 + if (!type.startsWith("[")) {
1.1287 + emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;",
1.1288 + smapper.popA(), smapper.pushI(),
1.1289 + type.replace('/', '_'));
1.1290 + } else {
1.1291 + emit(out, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);",
1.1292 + smapper.popA(), smapper.pushI(),
1.1293 + type
1.1294 + );
1.1295 + }
1.1296 + i += 2;
1.1297 + break;
1.1298 + }
1.1299 + case opc_athrow: {
1.1300 + final Variable v = smapper.popA();
1.1301 + smapper.clear();
1.1302 +
1.1303 + emit(out, "{ var @1 = @2; throw @2; }",
1.1304 + smapper.pushA(), v);
1.1305 + break;
1.1306 + }
1.1307 +
1.1308 + case opc_monitorenter: {
1.1309 + out.append("/* monitor enter */");
1.1310 + smapper.popA();
1.1311 + break;
1.1312 + }
1.1313 +
1.1314 + case opc_monitorexit: {
1.1315 + out.append("/* monitor exit */");
1.1316 + smapper.popA();
1.1317 + break;
1.1318 + }
1.1319 +
1.1320 + case opc_wide:
1.1321 + wide = true;
1.1322 + break;
1.1323 +
1.1324 + default: {
1.1325 + wide = false;
1.1326 + emit(out, "throw 'unknown bytecode @1';",
1.1327 + Integer.toString(c));
1.1328 + }
1.1329 + }
1.1330 + if (debug(" //")) {
1.1331 + for (int j = prev; j <= i; j++) {
1.1332 + out.append(" ");
1.1333 + final int cc = readUByte(byteCodes, j);
1.1334 + out.append(Integer.toString(cc));
1.1335 + }
1.1336 + }
1.1337 + out.append("\n");
1.1338 + }
1.1339 + if (previousTrap != null) {
1.1340 + generateCatch(previousTrap);
1.1341 + }
1.1342 + out.append(" }\n");
1.1343 + out.append("};");
1.1344 + }
1.1345 +
1.1346 + private int generateIf(byte[] byteCodes, int i,
1.1347 + final Variable v2, final Variable v1,
1.1348 + final String test) throws IOException {
1.1349 + int indx = i + readIntArg(byteCodes, i);
1.1350 + out.append("if (").append(v1)
1.1351 + .append(' ').append(test).append(' ')
1.1352 + .append(v2).append(") { gt = " + indx)
1.1353 + .append("; continue; }");
1.1354 + return i + 2;
1.1355 + }
1.1356 +
1.1357 + private int readIntArg(byte[] byteCodes, int offsetInstruction) {
1.1358 + final int indxHi = byteCodes[offsetInstruction + 1] << 8;
1.1359 + final int indxLo = byteCodes[offsetInstruction + 2];
1.1360 + return (indxHi & 0xffffff00) | (indxLo & 0xff);
1.1361 + }
1.1362 + private int readInt4(byte[] byteCodes, int offset) {
1.1363 + final int d = byteCodes[offset + 0] << 24;
1.1364 + final int c = byteCodes[offset + 1] << 16;
1.1365 + final int b = byteCodes[offset + 2] << 8;
1.1366 + final int a = byteCodes[offset + 3];
1.1367 + return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff);
1.1368 + }
1.1369 + private int readUByte(byte[] byteCodes, int offset) {
1.1370 + return byteCodes[offset] & 0xff;
1.1371 + }
1.1372 +
1.1373 + private int readUShort(byte[] byteCodes, int offset) {
1.1374 + return ((byteCodes[offset] & 0xff) << 8)
1.1375 + | (byteCodes[offset + 1] & 0xff);
1.1376 + }
1.1377 +
1.1378 + private int readShort(byte[] byteCodes, int offset) {
1.1379 + return (byteCodes[offset] << 8)
1.1380 + | (byteCodes[offset + 1] & 0xff);
1.1381 + }
1.1382 +
1.1383 + private static void countArgs(String descriptor, char[] returnType, StringBuilder sig, StringBuilder cnt) {
1.1384 + int i = 0;
1.1385 + Boolean count = null;
1.1386 + boolean array = false;
1.1387 + sig.append("__");
1.1388 + int firstPos = sig.length();
1.1389 + while (i < descriptor.length()) {
1.1390 + char ch = descriptor.charAt(i++);
1.1391 + switch (ch) {
1.1392 + case '(':
1.1393 + count = true;
1.1394 + continue;
1.1395 + case ')':
1.1396 + count = false;
1.1397 + continue;
1.1398 + case 'B':
1.1399 + case 'C':
1.1400 + case 'D':
1.1401 + case 'F':
1.1402 + case 'I':
1.1403 + case 'J':
1.1404 + case 'S':
1.1405 + case 'Z':
1.1406 + if (count) {
1.1407 + if (array) {
1.1408 + sig.append("_3");
1.1409 + }
1.1410 + sig.append(ch);
1.1411 + if (ch == 'J' || ch == 'D') {
1.1412 + cnt.append('1');
1.1413 + } else {
1.1414 + cnt.append('0');
1.1415 + }
1.1416 + } else {
1.1417 + sig.insert(firstPos, ch);
1.1418 + if (array) {
1.1419 + returnType[0] = '[';
1.1420 + sig.insert(firstPos, "_3");
1.1421 + } else {
1.1422 + returnType[0] = ch;
1.1423 + }
1.1424 + }
1.1425 + array = false;
1.1426 + continue;
1.1427 + case 'V':
1.1428 + assert !count;
1.1429 + returnType[0] = 'V';
1.1430 + sig.insert(firstPos, 'V');
1.1431 + continue;
1.1432 + case 'L':
1.1433 + int next = descriptor.indexOf(';', i);
1.1434 + String realSig = mangleSig(descriptor, i - 1, next + 1);
1.1435 + if (count) {
1.1436 + if (array) {
1.1437 + sig.append("_3");
1.1438 + }
1.1439 + sig.append(realSig);
1.1440 + cnt.append('0');
1.1441 + } else {
1.1442 + sig.insert(firstPos, realSig);
1.1443 + if (array) {
1.1444 + sig.insert(firstPos, "_3");
1.1445 + }
1.1446 + returnType[0] = 'L';
1.1447 + }
1.1448 + i = next + 1;
1.1449 + array = false;
1.1450 + continue;
1.1451 + case '[':
1.1452 + array = true;
1.1453 + continue;
1.1454 + default:
1.1455 + throw new IllegalStateException("Invalid char: " + ch);
1.1456 + }
1.1457 + }
1.1458 + }
1.1459 +
1.1460 + static String mangleSig(String sig) {
1.1461 + return mangleSig(sig, 0, sig.length());
1.1462 + }
1.1463 +
1.1464 + private static String mangleSig(String txt, int first, int last) {
1.1465 + StringBuilder sb = new StringBuilder();
1.1466 + for (int i = first; i < last; i++) {
1.1467 + final char ch = txt.charAt(i);
1.1468 + switch (ch) {
1.1469 + case '/': sb.append('_'); break;
1.1470 + case '_': sb.append("_1"); break;
1.1471 + case ';': sb.append("_2"); break;
1.1472 + case '[': sb.append("_3"); break;
1.1473 + default: sb.append(ch); break;
1.1474 + }
1.1475 + }
1.1476 + return sb.toString();
1.1477 + }
1.1478 +
1.1479 + private static String findMethodName(MethodData m, StringBuilder cnt) {
1.1480 + StringBuilder name = new StringBuilder();
1.1481 + if ("<init>".equals(m.getName())) { // NOI18N
1.1482 + name.append("cons"); // NOI18N
1.1483 + } else if ("<clinit>".equals(m.getName())) { // NOI18N
1.1484 + name.append("class"); // NOI18N
1.1485 + } else {
1.1486 + name.append(m.getName());
1.1487 + }
1.1488 +
1.1489 + countArgs(m.getInternalSig(), new char[1], name, cnt);
1.1490 + return name.toString();
1.1491 + }
1.1492 +
1.1493 + static String findMethodName(String[] mi, StringBuilder cnt, char[] returnType) {
1.1494 + StringBuilder name = new StringBuilder();
1.1495 + String descr = mi[2];//mi.getDescriptor();
1.1496 + String nm= mi[1];
1.1497 + if ("<init>".equals(nm)) { // NOI18N
1.1498 + name.append("cons"); // NOI18N
1.1499 + } else {
1.1500 + name.append(nm);
1.1501 + }
1.1502 + countArgs(descr, returnType, name, cnt);
1.1503 + return name.toString();
1.1504 + }
1.1505 +
1.1506 + private int invokeStaticMethod(byte[] byteCodes, int i, final StackMapper mapper, boolean isStatic)
1.1507 + throws IOException {
1.1508 + int methodIndex = readIntArg(byteCodes, i);
1.1509 + String[] mi = jc.getFieldInfoName(methodIndex);
1.1510 + char[] returnType = { 'V' };
1.1511 + StringBuilder cnt = new StringBuilder();
1.1512 + String mn = findMethodName(mi, cnt, returnType);
1.1513 +
1.1514 + final int numArguments = isStatic ? cnt.length() : cnt.length() + 1;
1.1515 + final Variable[] vars = new Variable[numArguments];
1.1516 +
1.1517 + for (int j = numArguments - 1; j >= 0; --j) {
1.1518 + vars[j] = mapper.pop();
1.1519 + }
1.1520 +
1.1521 + if (returnType[0] != 'V') {
1.1522 + out.append("var ")
1.1523 + .append(mapper.pushT(VarType.fromFieldType(returnType[0])))
1.1524 + .append(" = ");
1.1525 + }
1.1526 +
1.1527 + final String in = mi[0];
1.1528 + out.append(accessClass(in.replace('/', '_')));
1.1529 + out.append("(false).");
1.1530 + if (mn.startsWith("cons_")) {
1.1531 + out.append("constructor.");
1.1532 + }
1.1533 + out.append(mn);
1.1534 + if (isStatic) {
1.1535 + out.append('(');
1.1536 + } else {
1.1537 + out.append(".call(");
1.1538 + }
1.1539 + if (numArguments > 0) {
1.1540 + out.append(vars[0]);
1.1541 + for (int j = 1; j < numArguments; ++j) {
1.1542 + out.append(", ");
1.1543 + out.append(vars[j]);
1.1544 + }
1.1545 + }
1.1546 + out.append(");");
1.1547 + i += 2;
1.1548 + addReference(in);
1.1549 + return i;
1.1550 + }
1.1551 + private int invokeVirtualMethod(byte[] byteCodes, int i, final StackMapper mapper)
1.1552 + throws IOException {
1.1553 + int methodIndex = readIntArg(byteCodes, i);
1.1554 + String[] mi = jc.getFieldInfoName(methodIndex);
1.1555 + char[] returnType = { 'V' };
1.1556 + StringBuilder cnt = new StringBuilder();
1.1557 + String mn = findMethodName(mi, cnt, returnType);
1.1558 +
1.1559 + final int numArguments = cnt.length() + 1;
1.1560 + final Variable[] vars = new Variable[numArguments];
1.1561 +
1.1562 + for (int j = numArguments - 1; j >= 0; --j) {
1.1563 + vars[j] = mapper.pop();
1.1564 + }
1.1565 +
1.1566 + if (returnType[0] != 'V') {
1.1567 + out.append("var ")
1.1568 + .append(mapper.pushT(VarType.fromFieldType(returnType[0])))
1.1569 + .append(" = ");
1.1570 + }
1.1571 +
1.1572 + out.append(vars[0]).append('.');
1.1573 + out.append(mn);
1.1574 + out.append('(');
1.1575 + String sep = "";
1.1576 + for (int j = 1; j < numArguments; ++j) {
1.1577 + out.append(sep);
1.1578 + out.append(vars[j]);
1.1579 + sep = ", ";
1.1580 + }
1.1581 + out.append(");");
1.1582 + i += 2;
1.1583 + return i;
1.1584 + }
1.1585 +
1.1586 + private void addReference(String cn) throws IOException {
1.1587 + if (requireReference(cn)) {
1.1588 + debug(" /* needs " + cn + " */");
1.1589 + }
1.1590 + }
1.1591 +
1.1592 + private void outType(String d, StringBuilder out) {
1.1593 + int arr = 0;
1.1594 + while (d.charAt(0) == '[') {
1.1595 + out.append('A');
1.1596 + d = d.substring(1);
1.1597 + }
1.1598 + if (d.charAt(0) == 'L') {
1.1599 + assert d.charAt(d.length() - 1) == ';';
1.1600 + out.append(d.replace('/', '_').substring(0, d.length() - 1));
1.1601 + } else {
1.1602 + out.append(d);
1.1603 + }
1.1604 + }
1.1605 +
1.1606 + private String encodeConstant(int entryIndex) throws IOException {
1.1607 + String[] classRef = { null };
1.1608 + String s = jc.stringValue(entryIndex, classRef);
1.1609 + if (classRef[0] != null) {
1.1610 + if (classRef[0].startsWith("[")) {
1.1611 + s = accessClass("java_lang_Class") + "(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('" + classRef[0] + "');";
1.1612 + } else {
1.1613 + addReference(classRef[0]);
1.1614 + s = accessClass(s.replace('/', '_')) + "(false).constructor.$class";
1.1615 + }
1.1616 + }
1.1617 + return s;
1.1618 + }
1.1619 +
1.1620 + private String javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException {
1.1621 + byte[] arr = m.findAnnotationData(true);
1.1622 + if (arr == null) {
1.1623 + return null;
1.1624 + }
1.1625 + final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;";
1.1626 + class P extends AnnotationParser {
1.1627 + public P() {
1.1628 + super(false, true);
1.1629 + }
1.1630 +
1.1631 + int cnt;
1.1632 + String[] args = new String[30];
1.1633 + String body;
1.1634 +
1.1635 + @Override
1.1636 + protected void visitAttr(String type, String attr, String at, String value) {
1.1637 + if (type.equals(jvmType)) {
1.1638 + if ("body".equals(attr)) {
1.1639 + body = value;
1.1640 + } else if ("args".equals(attr)) {
1.1641 + args[cnt++] = value;
1.1642 + } else {
1.1643 + throw new IllegalArgumentException(attr);
1.1644 + }
1.1645 + }
1.1646 + }
1.1647 + }
1.1648 + P p = new P();
1.1649 + p.parse(arr, jc);
1.1650 + if (p.body == null) {
1.1651 + return null;
1.1652 + }
1.1653 + StringBuilder cnt = new StringBuilder();
1.1654 + final String mn = findMethodName(m, cnt);
1.1655 + out.append(prefix).append(mn);
1.1656 + out.append(" = function(");
1.1657 + String space = "";
1.1658 + int index = 0;
1.1659 + for (int i = 0; i < cnt.length(); i++) {
1.1660 + out.append(space);
1.1661 + space = outputArg(out, p.args, index);
1.1662 + index++;
1.1663 + }
1.1664 + out.append(") {").append("\n");
1.1665 + out.append(p.body);
1.1666 + out.append("\n}\n");
1.1667 + return mn;
1.1668 + }
1.1669 + private static String className(ClassData jc) {
1.1670 + //return jc.getName().getInternalName().replace('/', '_');
1.1671 + return jc.getClassName().replace('/', '_');
1.1672 + }
1.1673 +
1.1674 + private static String[] findAnnotation(
1.1675 + byte[] arr, ClassData cd, final String className,
1.1676 + final String... attrNames
1.1677 + ) throws IOException {
1.1678 + if (arr == null) {
1.1679 + return null;
1.1680 + }
1.1681 + final String[] values = new String[attrNames.length];
1.1682 + final boolean[] found = { false };
1.1683 + final String jvmType = "L" + className.replace('.', '/') + ";";
1.1684 + AnnotationParser ap = new AnnotationParser(false, true) {
1.1685 + @Override
1.1686 + protected void visitAttr(String type, String attr, String at, String value) {
1.1687 + if (type.equals(jvmType)) {
1.1688 + found[0] = true;
1.1689 + for (int i = 0; i < attrNames.length; i++) {
1.1690 + if (attrNames[i].equals(attr)) {
1.1691 + values[i] = value;
1.1692 + }
1.1693 + }
1.1694 + }
1.1695 + }
1.1696 +
1.1697 + };
1.1698 + ap.parse(arr, cd);
1.1699 + return found[0] ? values : null;
1.1700 + }
1.1701 +
1.1702 + private CharSequence initField(FieldData v) {
1.1703 + final String is = v.getInternalSig();
1.1704 + if (is.length() == 1) {
1.1705 + switch (is.charAt(0)) {
1.1706 + case 'S':
1.1707 + case 'J':
1.1708 + case 'B':
1.1709 + case 'Z':
1.1710 + case 'C':
1.1711 + case 'I': return " = 0;";
1.1712 + case 'F':
1.1713 + case 'D': return " = 0.0;";
1.1714 + default:
1.1715 + throw new IllegalStateException(is);
1.1716 + }
1.1717 + }
1.1718 + return " = null;";
1.1719 + }
1.1720 +
1.1721 + private void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException {
1.1722 + AnnotationParser ap = new AnnotationParser(true, false) {
1.1723 + int[] cnt = new int[32];
1.1724 + int depth;
1.1725 +
1.1726 + @Override
1.1727 + protected void visitAnnotationStart(String attrType, boolean top) throws IOException {
1.1728 + final String slashType = attrType.substring(1, attrType.length() - 1);
1.1729 + requireReference(slashType);
1.1730 +
1.1731 + if (cnt[depth]++ > 0) {
1.1732 + out.append(",");
1.1733 + }
1.1734 + if (top) {
1.1735 + out.append('"').append(attrType).append("\" : ");
1.1736 + }
1.1737 + out.append("{\n");
1.1738 + cnt[++depth] = 0;
1.1739 + }
1.1740 +
1.1741 + @Override
1.1742 + protected void visitAnnotationEnd(String type, boolean top) throws IOException {
1.1743 + out.append("\n}\n");
1.1744 + depth--;
1.1745 + }
1.1746 +
1.1747 + @Override
1.1748 + protected void visitValueStart(String attrName, char type) throws IOException {
1.1749 + if (cnt[depth]++ > 0) {
1.1750 + out.append(",\n");
1.1751 + }
1.1752 + cnt[++depth] = 0;
1.1753 + if (attrName != null) {
1.1754 + out.append(attrName).append(" : ");
1.1755 + }
1.1756 + if (type == '[') {
1.1757 + out.append("[");
1.1758 + }
1.1759 + }
1.1760 +
1.1761 + @Override
1.1762 + protected void visitValueEnd(String attrName, char type) throws IOException {
1.1763 + if (type == '[') {
1.1764 + out.append("]");
1.1765 + }
1.1766 + depth--;
1.1767 + }
1.1768 +
1.1769 + @Override
1.1770 + protected void visitAttr(String type, String attr, String attrType, String value)
1.1771 + throws IOException {
1.1772 + if (attr == null && value == null) {
1.1773 + return;
1.1774 + }
1.1775 + out.append(value);
1.1776 + }
1.1777 +
1.1778 + @Override
1.1779 + protected void visitEnumAttr(String type, String attr, String attrType, String value)
1.1780 + throws IOException {
1.1781 + final String slashType = attrType.substring(1, attrType.length() - 1);
1.1782 + requireReference(slashType);
1.1783 +
1.1784 + out.append(accessClass(slashType.replace('/', '_')))
1.1785 + .append("(false).constructor.").append(value);
1.1786 + }
1.1787 + };
1.1788 + ap.parse(data, cd);
1.1789 + }
1.1790 +
1.1791 + private static String outputArg(Appendable out, String[] args, int indx) throws IOException {
1.1792 + final String name = args[indx];
1.1793 + if (name == null) {
1.1794 + return "";
1.1795 + }
1.1796 + if (name.contains(",")) {
1.1797 + throw new IOException("Wrong parameter with ',': " + name);
1.1798 + }
1.1799 + out.append(name);
1.1800 + return ",";
1.1801 + }
1.1802 +
1.1803 + private static void emit(final Appendable out,
1.1804 + final String format,
1.1805 + final CharSequence... params) throws IOException {
1.1806 + final int length = format.length();
1.1807 +
1.1808 + int processed = 0;
1.1809 + int paramOffset = format.indexOf('@');
1.1810 + while ((paramOffset != -1) && (paramOffset < (length - 1))) {
1.1811 + final char paramChar = format.charAt(paramOffset + 1);
1.1812 + if ((paramChar >= '1') && (paramChar <= '9')) {
1.1813 + final int paramIndex = paramChar - '0' - 1;
1.1814 +
1.1815 + out.append(format, processed, paramOffset);
1.1816 + out.append(params[paramIndex]);
1.1817 +
1.1818 + ++paramOffset;
1.1819 + processed = paramOffset + 1;
1.1820 + }
1.1821 +
1.1822 + paramOffset = format.indexOf('@', paramOffset + 1);
1.1823 + }
1.1824 +
1.1825 + out.append(format, processed, length);
1.1826 + }
1.1827 +
1.1828 + private void generateCatch(TrapData[] traps) throws IOException {
1.1829 + out.append("} catch (e) {\n");
1.1830 + int finallyPC = -1;
1.1831 + for (TrapData e : traps) {
1.1832 + if (e == null) {
1.1833 + break;
1.1834 + }
1.1835 + if (e.catch_cpx != 0) { //not finally
1.1836 + final String classInternalName = jc.getClassName(e.catch_cpx);
1.1837 + addReference(classInternalName);
1.1838 + if ("java/lang/Throwable".equals(classInternalName)) {
1.1839 + out.append("if (e.$instOf_java_lang_Throwable) {");
1.1840 + out.append(" var stA0 = e;");
1.1841 + out.append("} else {");
1.1842 + out.append(" var stA0 = vm.java_lang_Throwable(true);");
1.1843 + out.append(" vm.java_lang_Throwable.cons__VLjava_lang_String_2.call(stA0, e.toString());");
1.1844 + out.append("}");
1.1845 + out.append("gt=" + e.handler_pc + "; continue;");
1.1846 + } else {
1.1847 + out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {");
1.1848 + out.append("gt=" + e.handler_pc + "; var stA0 = e; continue;");
1.1849 + out.append("}\n");
1.1850 + }
1.1851 + } else {
1.1852 + finallyPC = e.handler_pc;
1.1853 + }
1.1854 + }
1.1855 + if (finallyPC == -1) {
1.1856 + out.append("throw e;");
1.1857 + } else {
1.1858 + out.append("gt=" + finallyPC + "; var stA0 = e; continue;");
1.1859 + }
1.1860 + out.append("\n}");
1.1861 + }
1.1862 +}