1.1 --- a/src/main/java/org/apidesign/java4browser/ByteCodeToJavaScript.java Mon Sep 24 09:35:00 2012 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,793 +0,0 @@
1.4 -/*
1.5 -Java 4 Browser Bytecode Translator
1.6 -Copyright (C) 2012-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.java4browser;
1.22 -
1.23 -import java.io.IOException;
1.24 -import java.io.InputStream;
1.25 -import java.util.ArrayList;
1.26 -import java.util.Collection;
1.27 -import java.util.List;
1.28 -import static org.netbeans.modules.classfile.ByteCodes.*;
1.29 -import org.netbeans.modules.classfile.CPClassInfo;
1.30 -import org.netbeans.modules.classfile.CPEntry;
1.31 -import org.netbeans.modules.classfile.CPFieldInfo;
1.32 -import org.netbeans.modules.classfile.CPMethodInfo;
1.33 -import org.netbeans.modules.classfile.CPStringInfo;
1.34 -import org.netbeans.modules.classfile.ClassFile;
1.35 -import org.netbeans.modules.classfile.ClassName;
1.36 -import org.netbeans.modules.classfile.Code;
1.37 -import org.netbeans.modules.classfile.Method;
1.38 -import org.netbeans.modules.classfile.Parameter;
1.39 -import org.netbeans.modules.classfile.Variable;
1.40 -
1.41 -/** Translator of the code inside class files to JavaScript.
1.42 - *
1.43 - * @author Jaroslav Tulach <jtulach@netbeans.org>
1.44 - */
1.45 -public final class ByteCodeToJavaScript {
1.46 - private final ClassFile jc;
1.47 - private final Appendable out;
1.48 - private final Collection<? super String> references;
1.49 -
1.50 - private ByteCodeToJavaScript(
1.51 - ClassFile jc, Appendable out, Collection<? super String> references
1.52 - ) {
1.53 - this.jc = jc;
1.54 - this.out = out;
1.55 - this.references = references;
1.56 - }
1.57 -
1.58 - /**
1.59 - * Converts a given class file to a JavaScript version.
1.60 - *
1.61 - * @param classFile input stream with code of the .class file
1.62 - * @param out a {@link StringBuilder} or similar to generate the output to
1.63 - * @param references a write only collection where the system adds list of
1.64 - * other classes that were referenced and should be loaded in order the
1.65 - * generated JavaScript code works properly. The names are in internal
1.66 - * JVM form so String is <code>java/lang/String</code>. Can be <code>null</code>
1.67 - * if one is not interested in knowing references
1.68 - * @throws IOException if something goes wrong during read or write or translating
1.69 - */
1.70 -
1.71 - public static void compile(
1.72 - InputStream classFile, Appendable out,
1.73 - Collection<? super String> references
1.74 - ) throws IOException {
1.75 - ClassFile jc = new ClassFile(classFile, true);
1.76 - ByteCodeToJavaScript compiler = new ByteCodeToJavaScript(
1.77 - jc, out, references
1.78 - );
1.79 - List<String> toInitilize = new ArrayList<String>();
1.80 - for (Method m : jc.getMethods()) {
1.81 - if (m.isStatic()) {
1.82 - compiler.generateStaticMethod(m, toInitilize);
1.83 - } else {
1.84 - compiler.generateInstanceMethod(m);
1.85 - }
1.86 - }
1.87 - for (Variable v : jc.getVariables()) {
1.88 - if (v.isStatic()) {
1.89 - compiler.generateStaticField(v);
1.90 - }
1.91 - }
1.92 -
1.93 - final String className = jc.getName().getInternalName().replace('/', '_');
1.94 - out.append("\nfunction ").append(className);
1.95 - out.append("() {");
1.96 - for (Method m : jc.getMethods()) {
1.97 - if (!m.isStatic()) {
1.98 - compiler.generateMethodReference(m);
1.99 - }
1.100 - }
1.101 - for (Variable v : jc.getVariables()) {
1.102 - if (!v.isStatic()) {
1.103 - out.append("\n this." + v.getName() + " = 0;");
1.104 - }
1.105 - }
1.106 - out.append("\n this.$instOf_").append(className).append(" = true;");
1.107 - out.append("\n}");
1.108 - ClassName sc = jc.getSuperClass();
1.109 - if (sc != null) {
1.110 - out.append("\n").append(className)
1.111 - .append(".prototype = new ").append(sc.getInternalName().replace('/', '_'));
1.112 - }
1.113 - for (String init : toInitilize) {
1.114 - out.append("\n").append(init).append("();");
1.115 - }
1.116 - }
1.117 - private void generateStaticMethod(Method m, List<String> toInitilize) throws IOException {
1.118 - final String mn = findMethodName(m);
1.119 - out.append("\nfunction ").append(
1.120 - jc.getName().getInternalName().replace('/', '_')
1.121 - ).append('_').append(mn);
1.122 - if (mn.equals("classV")) {
1.123 - toInitilize.add(jc.getName().getInternalName().replace('/', '_') + '_' + mn);
1.124 - }
1.125 - out.append('(');
1.126 - String space = "";
1.127 - List<Parameter> args = m.getParameters();
1.128 - for (int index = 0, i = 0; i < args.size(); i++) {
1.129 - out.append(space);
1.130 - out.append("arg").append(String.valueOf(index));
1.131 - space = ",";
1.132 - final String desc = args.get(i).getDescriptor();
1.133 - if ("D".equals(desc) || "J".equals(desc)) {
1.134 - index += 2;
1.135 - } else {
1.136 - index++;
1.137 - }
1.138 - }
1.139 - out.append(") {").append("\n");
1.140 - final Code code = m.getCode();
1.141 - if (code != null) {
1.142 - int len = code.getMaxLocals();
1.143 - for (int index = args.size(), i = args.size(); i < len; i++) {
1.144 - out.append(" var ");
1.145 - out.append("arg").append(String.valueOf(i)).append(";\n");
1.146 - }
1.147 - out.append(" var stack = new Array();\n");
1.148 - produceCode(code.getByteCodes());
1.149 - } else {
1.150 - out.append(" /* no code found for ").append(m.getTypeSignature()).append(" */\n");
1.151 - }
1.152 - out.append("}");
1.153 - }
1.154 -
1.155 - private void generateMethodReference(Method m) throws IOException {
1.156 - final String name = findMethodName(m);
1.157 - out.append("\n this.").append(name).append(" = ")
1.158 - .append(jc.getName().getInternalName().replace('/', '_'))
1.159 - .append('_').append(name).append(";");
1.160 - }
1.161 -
1.162 - private void generateInstanceMethod(Method m) throws IOException {
1.163 - out.append("\nfunction ").append(
1.164 - jc.getName().getInternalName().replace('/', '_')
1.165 - ).append('_').append(findMethodName(m));
1.166 - out.append("(arg0");
1.167 - String space = ",";
1.168 - List<Parameter> args = m.getParameters();
1.169 - for (int index = 1, i = 0; i < args.size(); i++) {
1.170 - out.append(space);
1.171 - out.append("arg").append(String.valueOf(index));
1.172 - final String desc = args.get(i).getDescriptor();
1.173 - if ("D".equals(desc) || "J".equals(desc)) {
1.174 - index += 2;
1.175 - } else {
1.176 - index++;
1.177 - }
1.178 - }
1.179 - out.append(") {").append("\n");
1.180 - final Code code = m.getCode();
1.181 - if (code != null) {
1.182 - int len = code.getMaxLocals();
1.183 - for (int index = args.size(), i = args.size(); i < len; i++) {
1.184 - out.append(" var ");
1.185 - out.append("arg").append(String.valueOf(i + 1)).append(";\n");
1.186 - }
1.187 - out.append(";\n var stack = new Array(");
1.188 - out.append(Integer.toString(code.getMaxStack()));
1.189 - out.append(");\n");
1.190 - produceCode(code.getByteCodes());
1.191 - } else {
1.192 - out.append(" /* no code found for ").append(m.getTypeSignature()).append(" */\n");
1.193 - }
1.194 - out.append("}");
1.195 - }
1.196 -
1.197 - private void produceCode(byte[] byteCodes) throws IOException {
1.198 - out.append("\n var gt = 0;\n for(;;) switch(gt) {\n");
1.199 - for (int i = 0; i < byteCodes.length; i++) {
1.200 - int prev = i;
1.201 - out.append(" case " + i).append(": ");
1.202 - final int c = (byteCodes[i] + 256) % 256;
1.203 - switch (c) {
1.204 - case bc_aload_0:
1.205 - case bc_iload_0:
1.206 - case bc_lload_0:
1.207 - case bc_fload_0:
1.208 - case bc_dload_0:
1.209 - out.append("stack.push(arg0);");
1.210 - break;
1.211 - case bc_aload_1:
1.212 - case bc_iload_1:
1.213 - case bc_lload_1:
1.214 - case bc_fload_1:
1.215 - case bc_dload_1:
1.216 - out.append("stack.push(arg1);");
1.217 - break;
1.218 - case bc_aload_2:
1.219 - case bc_iload_2:
1.220 - case bc_lload_2:
1.221 - case bc_fload_2:
1.222 - case bc_dload_2:
1.223 - out.append("stack.push(arg2);");
1.224 - break;
1.225 - case bc_aload_3:
1.226 - case bc_iload_3:
1.227 - case bc_lload_3:
1.228 - case bc_fload_3:
1.229 - case bc_dload_3:
1.230 - out.append("stack.push(arg3);");
1.231 - break;
1.232 - case bc_iload:
1.233 - case bc_lload:
1.234 - case bc_fload:
1.235 - case bc_dload:
1.236 - case bc_aload: {
1.237 - final int indx = (byteCodes[++i] + 256) % 256;
1.238 - out.append("stack.push(arg").append(indx + ");");
1.239 - break;
1.240 - }
1.241 - case bc_astore_0:
1.242 - case bc_istore_0:
1.243 - case bc_lstore_0:
1.244 - case bc_fstore_0:
1.245 - case bc_dstore_0:
1.246 - out.append("arg0 = stack.pop();");
1.247 - break;
1.248 - case bc_astore_1:
1.249 - case bc_istore_1:
1.250 - case bc_lstore_1:
1.251 - case bc_fstore_1:
1.252 - case bc_dstore_1:
1.253 - out.append("arg1 = stack.pop();");
1.254 - break;
1.255 - case bc_astore_2:
1.256 - case bc_istore_2:
1.257 - case bc_lstore_2:
1.258 - case bc_fstore_2:
1.259 - case bc_dstore_2:
1.260 - out.append("arg2 = stack.pop();");
1.261 - break;
1.262 - case bc_astore_3:
1.263 - case bc_istore_3:
1.264 - case bc_lstore_3:
1.265 - case bc_fstore_3:
1.266 - case bc_dstore_3:
1.267 - out.append("arg3 = stack.pop();");
1.268 - break;
1.269 - case bc_iadd:
1.270 - case bc_ladd:
1.271 - case bc_fadd:
1.272 - case bc_dadd:
1.273 - out.append("stack.push(stack.pop() + stack.pop());");
1.274 - break;
1.275 - case bc_isub:
1.276 - case bc_lsub:
1.277 - case bc_fsub:
1.278 - case bc_dsub:
1.279 - out.append("{ var tmp = stack.pop(); stack.push(stack.pop() - tmp); }");
1.280 - break;
1.281 - case bc_imul:
1.282 - case bc_lmul:
1.283 - case bc_fmul:
1.284 - case bc_dmul:
1.285 - out.append("stack.push(stack.pop() * stack.pop());");
1.286 - break;
1.287 - case bc_idiv:
1.288 - case bc_ldiv:
1.289 - out.append("{ var tmp = stack.pop(); stack.push(Math.floor(stack.pop() / tmp)); }");
1.290 - break;
1.291 - case bc_fdiv:
1.292 - case bc_ddiv:
1.293 - out.append("{ var tmp = stack.pop(); stack.push(stack.pop() / tmp); }");
1.294 - break;
1.295 - case bc_iand:
1.296 - case bc_land:
1.297 - out.append("stack.push(stack.pop() & stack.pop());");
1.298 - break;
1.299 - case bc_ior:
1.300 - case bc_lor:
1.301 - out.append("stack.push(stack.pop() | stack.pop());");
1.302 - break;
1.303 - case bc_ixor:
1.304 - case bc_lxor:
1.305 - out.append("stack.push(stack.pop() ^ stack.pop());");
1.306 - break;
1.307 - case bc_iinc: {
1.308 - final int varIndx = (byteCodes[++i] + 256) % 256;
1.309 - final int incrBy = (byteCodes[++i] + 256) % 256;
1.310 - if (incrBy == 1) {
1.311 - out.append("arg" + varIndx).append("++;");
1.312 - } else {
1.313 - out.append("arg" + varIndx).append(" += " + incrBy).append(";");
1.314 - }
1.315 - break;
1.316 - }
1.317 - case bc_return:
1.318 - out.append("return;");
1.319 - break;
1.320 - case bc_ireturn:
1.321 - case bc_lreturn:
1.322 - case bc_freturn:
1.323 - case bc_dreturn:
1.324 - case bc_areturn:
1.325 - out.append("return stack.pop();");
1.326 - break;
1.327 - case bc_i2l:
1.328 - case bc_i2f:
1.329 - case bc_i2d:
1.330 - case bc_l2i:
1.331 - // max int check?
1.332 - case bc_l2f:
1.333 - case bc_l2d:
1.334 - case bc_f2d:
1.335 - case bc_d2f:
1.336 - out.append("/* number conversion */");
1.337 - break;
1.338 - case bc_f2i:
1.339 - case bc_f2l:
1.340 - case bc_d2i:
1.341 - case bc_d2l:
1.342 - out.append("stack.push(Math.floor(stack.pop()));");
1.343 - break;
1.344 - case bc_i2b:
1.345 - case bc_i2c:
1.346 - case bc_i2s:
1.347 - out.append("/* number conversion */");
1.348 - break;
1.349 - case bc_iconst_0:
1.350 - case bc_dconst_0:
1.351 - case bc_lconst_0:
1.352 - case bc_fconst_0:
1.353 - out.append("stack.push(0);");
1.354 - break;
1.355 - case bc_iconst_1:
1.356 - case bc_lconst_1:
1.357 - case bc_fconst_1:
1.358 - case bc_dconst_1:
1.359 - out.append("stack.push(1);");
1.360 - break;
1.361 - case bc_iconst_2:
1.362 - case bc_fconst_2:
1.363 - out.append("stack.push(2);");
1.364 - break;
1.365 - case bc_iconst_3:
1.366 - out.append("stack.push(3);");
1.367 - break;
1.368 - case bc_iconst_4:
1.369 - out.append("stack.push(4);");
1.370 - break;
1.371 - case bc_iconst_5:
1.372 - out.append("stack.push(5);");
1.373 - break;
1.374 - case bc_ldc: {
1.375 - int indx = byteCodes[++i];
1.376 - CPEntry entry = jc.getConstantPool().get(indx);
1.377 - String v = encodeConstant(entry);
1.378 - out.append("stack.push(").append(v).append(");");
1.379 - break;
1.380 - }
1.381 - case bc_ldc_w:
1.382 - case bc_ldc2_w: {
1.383 - int indx = readIntArg(byteCodes, i);
1.384 - CPEntry entry = jc.getConstantPool().get(indx);
1.385 - i += 2;
1.386 - String v = encodeConstant(entry);
1.387 - out.append("stack.push(").append(v).append(");");
1.388 - break;
1.389 - }
1.390 - case bc_lcmp:
1.391 - case bc_fcmpl:
1.392 - case bc_fcmpg:
1.393 - case bc_dcmpl:
1.394 - case bc_dcmpg: {
1.395 - out.append("{ var delta = stack.pop() - stack.pop(); stack.push(delta < 0 ?-1 : (delta == 0 ? 0 : 1)); }");
1.396 - break;
1.397 - }
1.398 - case bc_if_icmpeq: {
1.399 - i = generateIf(byteCodes, i, "==");
1.400 - break;
1.401 - }
1.402 - case bc_ifeq: {
1.403 - int indx = i + readIntArg(byteCodes, i);
1.404 - out.append("if (stack.pop() == 0) { gt = " + indx);
1.405 - out.append("; continue; }");
1.406 - i += 2;
1.407 - break;
1.408 - }
1.409 - case bc_ifne: {
1.410 - int indx = i + readIntArg(byteCodes, i);
1.411 - out.append("if (stack.pop() != 0) { gt = " + indx);
1.412 - out.append("; continue; }");
1.413 - i += 2;
1.414 - break;
1.415 - }
1.416 - case bc_iflt: {
1.417 - int indx = i + readIntArg(byteCodes, i);
1.418 - out.append("if (stack.pop() < 0) { gt = " + indx);
1.419 - out.append("; continue; }");
1.420 - i += 2;
1.421 - break;
1.422 - }
1.423 - case bc_ifle: {
1.424 - int indx = i + readIntArg(byteCodes, i);
1.425 - out.append("if (stack.pop() <= 0) { gt = " + indx);
1.426 - out.append("; continue; }");
1.427 - i += 2;
1.428 - break;
1.429 - }
1.430 - case bc_ifgt: {
1.431 - int indx = i + readIntArg(byteCodes, i);
1.432 - out.append("if (stack.pop() > 0) { gt = " + indx);
1.433 - out.append("; continue; }");
1.434 - i += 2;
1.435 - break;
1.436 - }
1.437 - case bc_ifge: {
1.438 - int indx = i + readIntArg(byteCodes, i);
1.439 - out.append("if (stack.pop() >= 0) { gt = " + indx);
1.440 - out.append("; continue; }");
1.441 - i += 2;
1.442 - break;
1.443 - }
1.444 - case bc_ifnonnull: {
1.445 - int indx = i + readIntArg(byteCodes, i);
1.446 - out.append("if (stack.pop()) { gt = " + indx);
1.447 - out.append("; continue; }");
1.448 - i += 2;
1.449 - break;
1.450 - }
1.451 - case bc_ifnull: {
1.452 - int indx = i + readIntArg(byteCodes, i);
1.453 - out.append("if (!stack.pop()) { gt = " + indx);
1.454 - out.append("; continue; }");
1.455 - i += 2;
1.456 - break;
1.457 - }
1.458 - case bc_if_icmpne:
1.459 - i = generateIf(byteCodes, i, "!=");
1.460 - break;
1.461 - case bc_if_icmplt:
1.462 - i = generateIf(byteCodes, i, ">");
1.463 - break;
1.464 - case bc_if_icmple:
1.465 - i = generateIf(byteCodes, i, ">=");
1.466 - break;
1.467 - case bc_if_icmpgt:
1.468 - i = generateIf(byteCodes, i, "<");
1.469 - break;
1.470 - case bc_if_icmpge:
1.471 - i = generateIf(byteCodes, i, "<=");
1.472 - break;
1.473 - case bc_goto: {
1.474 - int indx = i + readIntArg(byteCodes, i);
1.475 - out.append("gt = " + indx).append("; continue;");
1.476 - i += 2;
1.477 - break;
1.478 - }
1.479 - case bc_invokeinterface:
1.480 - case bc_invokevirtual:
1.481 - i = invokeVirtualMethod(byteCodes, i);
1.482 - break;
1.483 - case bc_invokespecial:
1.484 - i = invokeStaticMethod(byteCodes, i, false);
1.485 - break;
1.486 - case bc_invokestatic:
1.487 - i = invokeStaticMethod(byteCodes, i, true);
1.488 - break;
1.489 - case bc_new: {
1.490 - int indx = readIntArg(byteCodes, i);
1.491 - CPClassInfo ci = jc.getConstantPool().getClass(indx);
1.492 - out.append("stack.push(");
1.493 - out.append("new ").append(ci.getClassName().getInternalName().replace('/','_'));
1.494 - out.append(");");
1.495 - addReference(ci.getClassName().getInternalName());
1.496 - i += 2;
1.497 - break;
1.498 - }
1.499 - case bc_newarray: {
1.500 - int type = byteCodes[i++];
1.501 - out.append("stack.push(new Array(stack.pop()));");
1.502 - break;
1.503 - }
1.504 - case bc_anewarray: {
1.505 - i += 2; // skip type of array
1.506 - out.append("stack.push(new Array(stack.pop()));");
1.507 - break;
1.508 - }
1.509 - case bc_arraylength:
1.510 - out.append("stack.push(stack.pop().length);");
1.511 - break;
1.512 - case bc_iastore:
1.513 - case bc_lastore:
1.514 - case bc_fastore:
1.515 - case bc_dastore:
1.516 - case bc_aastore:
1.517 - case bc_bastore:
1.518 - case bc_castore:
1.519 - case bc_sastore: {
1.520 - out.append("{ var value = stack.pop(); var indx = stack.pop(); stack.pop()[indx] = value; }");
1.521 - break;
1.522 - }
1.523 - case bc_iaload:
1.524 - case bc_laload:
1.525 - case bc_faload:
1.526 - case bc_daload:
1.527 - case bc_aaload:
1.528 - case bc_baload:
1.529 - case bc_caload:
1.530 - case bc_saload: {
1.531 - out.append("{ var indx = stack.pop(); stack.push(stack.pop()[indx]); }");
1.532 - break;
1.533 - }
1.534 - case bc_dup:
1.535 - out.append("stack.push(stack[stack.length - 1]);");
1.536 - break;
1.537 - case bc_bipush:
1.538 - out.append("stack.push(" + byteCodes[++i] + ");");
1.539 - break;
1.540 - case bc_getfield: {
1.541 - int indx = readIntArg(byteCodes, i);
1.542 - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx);
1.543 - out.append("stack.push(stack.pop().").append(fi.getFieldName()).append(");");
1.544 - i += 2;
1.545 - break;
1.546 - }
1.547 - case bc_getstatic: {
1.548 - int indx = readIntArg(byteCodes, i);
1.549 - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx);
1.550 - final String in = fi.getClassName().getInternalName();
1.551 - out.append("stack.push(").append(in.replace('/', '_'));
1.552 - out.append('_').append(fi.getFieldName()).append(");");
1.553 - i += 2;
1.554 - addReference(in);
1.555 - break;
1.556 - }
1.557 - case bc_putstatic: {
1.558 - int indx = readIntArg(byteCodes, i);
1.559 - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx);
1.560 - final String in = fi.getClassName().getInternalName();
1.561 - out.append(in.replace('/', '_'));
1.562 - out.append('_').append(fi.getFieldName()).append(" = stack.pop();");
1.563 - i += 2;
1.564 - addReference(in);
1.565 - break;
1.566 - }
1.567 - case bc_putfield: {
1.568 - int indx = readIntArg(byteCodes, i);
1.569 - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx);
1.570 - out.append("{ var v = stack.pop(); stack.pop().")
1.571 - .append(fi.getFieldName()).append(" = v; }");
1.572 - i += 2;
1.573 - break;
1.574 - }
1.575 - case bc_instanceof: {
1.576 - int indx = readIntArg(byteCodes, i);
1.577 - CPClassInfo ci = jc.getConstantPool().getClass(indx);
1.578 - out.append("stack.push(stack.pop().$instOf_")
1.579 - .append(ci.getClassName().getInternalName().replace('/', '_'))
1.580 - .append(" ? 1 : 0);");
1.581 - i += 2;
1.582 - }
1.583 -
1.584 - }
1.585 - out.append(" /*");
1.586 - for (int j = prev; j <= i; j++) {
1.587 - out.append(" ");
1.588 - final int cc = (byteCodes[j] + 256) % 256;
1.589 - out.append(Integer.toString(cc));
1.590 - }
1.591 - out.append("*/\n");
1.592 - }
1.593 - out.append(" }\n");
1.594 - }
1.595 -
1.596 - private int generateIf(byte[] byteCodes, int i, final String test) throws IOException {
1.597 - int indx = i + readIntArg(byteCodes, i);
1.598 - out.append("if (stack.pop() ").append(test).append(" stack.pop()) { gt = " + indx);
1.599 - out.append("; continue; }");
1.600 - return i + 2;
1.601 - }
1.602 -
1.603 - private int readIntArg(byte[] byteCodes, int offsetInstruction) {
1.604 - final int indxHi = byteCodes[offsetInstruction + 1] << 8;
1.605 - final int indxLo = byteCodes[offsetInstruction + 2];
1.606 - return (indxHi & 0xffffff00) | (indxLo & 0xff);
1.607 - }
1.608 -
1.609 - private static int countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig) {
1.610 - int cnt = 0;
1.611 - int i = 0;
1.612 - Boolean count = null;
1.613 - int firstPos = sig.length();
1.614 - while (i < descriptor.length()) {
1.615 - char ch = descriptor.charAt(i++);
1.616 - switch (ch) {
1.617 - case '(':
1.618 - count = true;
1.619 - continue;
1.620 - case ')':
1.621 - count = false;
1.622 - continue;
1.623 - case 'B':
1.624 - case 'C':
1.625 - case 'D':
1.626 - case 'F':
1.627 - case 'I':
1.628 - case 'J':
1.629 - case 'S':
1.630 - case 'Z':
1.631 - if (count) {
1.632 - cnt++;
1.633 - sig.append(ch);
1.634 - } else {
1.635 - hasReturnType[0] = true;
1.636 - sig.insert(firstPos, ch);
1.637 - }
1.638 - continue;
1.639 - case 'V':
1.640 - assert !count;
1.641 - hasReturnType[0] = false;
1.642 - sig.insert(firstPos, 'V');
1.643 - continue;
1.644 - case 'L':
1.645 - int next = descriptor.indexOf(';', i);
1.646 - if (count) {
1.647 - cnt++;
1.648 - sig.append(ch);
1.649 - sig.append(descriptor.substring(i, next).replace('/', '_'));
1.650 - } else {
1.651 - sig.insert(firstPos, descriptor.substring(i, next).replace('/', '_'));
1.652 - sig.insert(firstPos, ch);
1.653 - hasReturnType[0] = true;
1.654 - }
1.655 - i = next + 1;
1.656 - continue;
1.657 - case '[':
1.658 - //arrays++;
1.659 - continue;
1.660 - default:
1.661 - break; // invalid character
1.662 - }
1.663 - }
1.664 - return cnt;
1.665 - }
1.666 -
1.667 - private void generateStaticField(Variable v) throws IOException {
1.668 - out.append("\nvar ")
1.669 - .append(jc.getName().getInternalName().replace('/', '_'))
1.670 - .append('_').append(v.getName()).append(" = 0;");
1.671 - }
1.672 -
1.673 - private String findMethodName(Method m) {
1.674 - StringBuilder tmp = new StringBuilder();
1.675 - if ("<init>".equals(m.getName())) { // NOI18N
1.676 - tmp.append("consV"); // NOI18N
1.677 - } else if ("<clinit>".equals(m.getName())) { // NOI18N
1.678 - tmp.append("classV"); // NOI18N
1.679 - } else {
1.680 - tmp.append(m.getName());
1.681 - outType(m.getReturnType(), tmp);
1.682 - }
1.683 - List<Parameter> args = m.getParameters();
1.684 - for (Parameter t : args) {
1.685 - outType(t.getDescriptor(), tmp);
1.686 - }
1.687 - return tmp.toString();
1.688 - }
1.689 -
1.690 - private String findMethodName(CPMethodInfo mi, int[] cnt, boolean[] hasReturn) {
1.691 - StringBuilder name = new StringBuilder();
1.692 - if ("<init>".equals(mi.getName())) { // NOI18N
1.693 - name.append("cons"); // NOI18N
1.694 - } else {
1.695 - name.append(mi.getName());
1.696 - }
1.697 - cnt[0] = countArgs(mi.getDescriptor(), hasReturn, name);
1.698 - return name.toString();
1.699 - }
1.700 -
1.701 - private int invokeStaticMethod(byte[] byteCodes, int i, boolean isStatic)
1.702 - throws IOException {
1.703 - int methodIndex = readIntArg(byteCodes, i);
1.704 - CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex);
1.705 - boolean[] hasReturn = { false };
1.706 - int[] cnt = { 0 };
1.707 - String mn = findMethodName(mi, cnt, hasReturn);
1.708 - out.append("{ ");
1.709 - for (int j = cnt[0] - 1; j >= 0; j--) {
1.710 - out.append("var v" + j).append(" = stack.pop(); ");
1.711 - }
1.712 -
1.713 - if (hasReturn[0]) {
1.714 - out.append("stack.push(");
1.715 - }
1.716 - final String in = mi.getClassName().getInternalName();
1.717 - out.append(in.replace('/', '_'));
1.718 - out.append('_');
1.719 - out.append(mn);
1.720 - out.append('(');
1.721 - String sep = "";
1.722 - if (!isStatic) {
1.723 - out.append("stack.pop()");
1.724 - sep = ", ";
1.725 - }
1.726 - for (int j = 0; j < cnt[0]; j++) {
1.727 - out.append(sep);
1.728 - out.append("v" + j);
1.729 - sep = ", ";
1.730 - }
1.731 - out.append(")");
1.732 - if (hasReturn[0]) {
1.733 - out.append(")");
1.734 - }
1.735 - out.append("; }");
1.736 - i += 2;
1.737 - addReference(in);
1.738 - return i;
1.739 - }
1.740 - private int invokeVirtualMethod(byte[] byteCodes, int i)
1.741 - throws IOException {
1.742 - int methodIndex = readIntArg(byteCodes, i);
1.743 - CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex);
1.744 - boolean[] hasReturn = { false };
1.745 - int[] cnt = { 0 };
1.746 - String mn = findMethodName(mi, cnt, hasReturn);
1.747 - out.append("{ ");
1.748 - for (int j = cnt[0] - 1; j >= 0; j--) {
1.749 - out.append("var v" + j).append(" = stack.pop(); ");
1.750 - }
1.751 - out.append("var self = stack.pop(); ");
1.752 - if (hasReturn[0]) {
1.753 - out.append("stack.push(");
1.754 - }
1.755 - out.append("self.");
1.756 - out.append(mn);
1.757 - out.append('(');
1.758 - out.append("self");
1.759 - for (int j = 0; j < cnt[0]; j++) {
1.760 - out.append(", ");
1.761 - out.append("v" + j);
1.762 - }
1.763 - out.append(")");
1.764 - if (hasReturn[0]) {
1.765 - out.append(")");
1.766 - }
1.767 - out.append("; }");
1.768 - i += 2;
1.769 - return i;
1.770 - }
1.771 -
1.772 - private void addReference(String cn) {
1.773 - if (references != null) {
1.774 - references.add(cn);
1.775 - }
1.776 - }
1.777 -
1.778 - private void outType(final String d, StringBuilder out) {
1.779 - if (d.charAt(0) == 'L') {
1.780 - assert d.charAt(d.length() - 1) == ';';
1.781 - out.append(d.replace('/', '_').substring(0, d.length() - 1));
1.782 - } else {
1.783 - out.append(d);
1.784 - }
1.785 - }
1.786 -
1.787 - private String encodeConstant(CPEntry entry) {
1.788 - final String v;
1.789 - if (entry instanceof CPStringInfo) {
1.790 - v = "\"" + entry.getValue().toString().replace("\"", "\\\"") + "\"";
1.791 - } else {
1.792 - v = entry.getValue().toString();
1.793 - }
1.794 - return v;
1.795 - }
1.796 -}