1.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Dec 18 20:19:11 2012 +0100
1.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Fri Jan 11 16:36:28 2013 +0100
1.3 @@ -25,6 +25,8 @@
1.4 import org.apidesign.javap.MethodData;
1.5 import org.apidesign.javap.StackMapIterator;
1.6 import static org.apidesign.javap.RuntimeConstants.*;
1.7 +import org.apidesign.javap.TrapData;
1.8 +import org.apidesign.javap.TrapDataIterator;
1.9
1.10 /** Translator of the code inside class files to JavaScript.
1.11 *
1.12 @@ -63,6 +65,17 @@
1.13 /* protected */ String accessClass(String classOperation) {
1.14 return classOperation;
1.15 }
1.16 +
1.17 + /** Prints out a debug message.
1.18 + *
1.19 + * @param msg the message
1.20 + * @return true if the message has been printed
1.21 + * @throws IOException
1.22 + */
1.23 + boolean debug(String msg) throws IOException {
1.24 + out.append(msg);
1.25 + return true;
1.26 + }
1.27
1.28 /**
1.29 * Converts a given class file to a JavaScript version.
1.30 @@ -133,18 +146,27 @@
1.31 }
1.32 continue;
1.33 }
1.34 + String prefix;
1.35 String mn;
1.36 if (m.isStatic()) {
1.37 - mn = generateStaticMethod("\n c.", m, toInitilize);
1.38 + prefix = "\n c.";
1.39 + mn = generateStaticMethod(prefix, m, toInitilize);
1.40 } else {
1.41 - mn = generateInstanceMethod("\n c.", m);
1.42 + if (m.isConstructor()) {
1.43 + prefix = "\n CLS.";
1.44 + mn = generateInstanceMethod(prefix, m);
1.45 + } else {
1.46 + prefix = "\n c.";
1.47 + mn = generateInstanceMethod(prefix, m);
1.48 + }
1.49 }
1.50 byte[] runAnno = m.findAnnotationData(false);
1.51 if (runAnno != null) {
1.52 - out.append("\n c.").append(mn).append(".anno = {");
1.53 + out.append(prefix).append(mn).append(".anno = {");
1.54 generateAnno(jc, out, runAnno);
1.55 out.append("\n };");
1.56 }
1.57 + out.append(prefix).append(mn).append(".access = " + m.getAccess()).append(";");
1.58 }
1.59 out.append("\n c.constructor = CLS;");
1.60 out.append("\n c.$instOf_").append(className).append(" = true;");
1.61 @@ -155,6 +177,7 @@
1.62 out.append(accessClass("java_lang_Class(true);"));
1.63 out.append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';");
1.64 out.append("\n CLS.$class.superclass = sprcls;");
1.65 + out.append("\n CLS.$class.access = ").append(jc.getAccessFlags()+";");
1.66 out.append("\n CLS.$class.cnstr = CLS;");
1.67 byte[] classAnno = jc.findAnnotationData(false);
1.68 if (classAnno != null) {
1.69 @@ -221,6 +244,7 @@
1.70 private void generateMethod(String prefix, String name, MethodData m)
1.71 throws IOException {
1.72 final StackMapIterator stackMapIterator = m.createStackMapIterator();
1.73 + TrapDataIterator trap = m.getTrapDataIterator();
1.74 final LocalsMapper lmapper =
1.75 new LocalsMapper(stackMapIterator.getArguments());
1.76
1.77 @@ -231,7 +255,8 @@
1.78 final byte[] byteCodes = m.getCode();
1.79 if (byteCodes == null) {
1.80 out.append(" throw 'no code found for ")
1.81 - .append(m.getInternalSig()).append("';\n");
1.82 + .append(jc.getClassName()).append('.')
1.83 + .append(m.getName()).append("';\n");
1.84 out.append("};");
1.85 return;
1.86 }
1.87 @@ -267,18 +292,31 @@
1.88 }
1.89
1.90 int lastStackFrame = -1;
1.91 -
1.92 + TrapData[] previousTrap = null;
1.93 +
1.94 out.append("\n var gt = 0;\n for(;;) switch(gt) {\n");
1.95 for (int i = 0; i < byteCodes.length; i++) {
1.96 int prev = i;
1.97 stackMapIterator.advanceTo(i);
1.98 + boolean changeInCatch = trap.advanceTo(i);
1.99 + if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) {
1.100 + if (previousTrap != null) {
1.101 + generateCatch(previousTrap);
1.102 + previousTrap = null;
1.103 + }
1.104 + }
1.105 if (lastStackFrame != stackMapIterator.getFrameIndex()) {
1.106 lastStackFrame = stackMapIterator.getFrameIndex();
1.107 lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals());
1.108 smapper.syncWithFrameStack(stackMapIterator.getFrameStack());
1.109 - out.append(" case " + i).append(": ");
1.110 + out.append(" case " + i).append(": ");
1.111 + changeInCatch = true;
1.112 } else {
1.113 - out.append(" /* " + i).append(" */ ");
1.114 + debug(" /* " + i + " */ ");
1.115 + }
1.116 + if (changeInCatch && trap.useTry()) {
1.117 + out.append("try {");
1.118 + previousTrap = trap.current();
1.119 }
1.120 final int c = readByte(byteCodes, i);
1.121 switch (c) {
1.122 @@ -950,7 +988,7 @@
1.123 case opc_pop:
1.124 case opc_pop2:
1.125 smapper.pop(1);
1.126 - out.append("/* pop */");
1.127 + debug("/* pop */");
1.128 break;
1.129 case opc_dup: {
1.130 final Variable v = smapper.get(0);
1.131 @@ -1028,7 +1066,7 @@
1.132 int indx = readIntArg(byteCodes, i);
1.133 String[] fi = jc.getFieldInfoName(indx);
1.134 final int type = VarType.fromFieldType(fi[2].charAt(0));
1.135 - emit(out, "@1 = @2.@3;",
1.136 + emit(out, "@1 = @2(false).constructor.@3;",
1.137 smapper.pushT(type),
1.138 accessClass(fi[0].replace('/', '_')), fi[1]);
1.139 i += 2;
1.140 @@ -1048,7 +1086,7 @@
1.141 int indx = readIntArg(byteCodes, i);
1.142 String[] fi = jc.getFieldInfoName(indx);
1.143 final int type = VarType.fromFieldType(fi[2].charAt(0));
1.144 - emit(out, "@1.@2 = @3;",
1.145 + emit(out, "@1(false).constructor.@2 = @3;",
1.146 accessClass(fi[0].replace('/', '_')), fi[1],
1.147 smapper.popT(type));
1.148 i += 2;
1.149 @@ -1103,13 +1141,17 @@
1.150 Integer.toString(c));
1.151 }
1.152 }
1.153 - out.append(" //");
1.154 - for (int j = prev; j <= i; j++) {
1.155 - out.append(" ");
1.156 - final int cc = readByte(byteCodes, j);
1.157 - out.append(Integer.toString(cc));
1.158 + if (debug(" //")) {
1.159 + for (int j = prev; j <= i; j++) {
1.160 + out.append(" ");
1.161 + final int cc = readByte(byteCodes, j);
1.162 + out.append(Integer.toString(cc));
1.163 + }
1.164 }
1.165 - out.append("\n");
1.166 + out.append("\n");
1.167 + }
1.168 + if (previousTrap != null) {
1.169 + generateCatch(previousTrap);
1.170 }
1.171 out.append(" }\n");
1.172 out.append("};");
1.173 @@ -1208,6 +1250,7 @@
1.174 returnType[0] = 'L';
1.175 }
1.176 i = next + 1;
1.177 + array = false;
1.178 continue;
1.179 case '[':
1.180 array = true;
1.181 @@ -1283,6 +1326,9 @@
1.182 final String in = mi[0];
1.183 out.append(accessClass(in.replace('/', '_')));
1.184 out.append("(false).");
1.185 + if (mn.startsWith("cons_")) {
1.186 + out.append("constructor.");
1.187 + }
1.188 out.append(mn);
1.189 out.append('(');
1.190 if (numArguments > 0) {
1.191 @@ -1332,7 +1378,7 @@
1.192
1.193 private void addReference(String cn) throws IOException {
1.194 if (requireReference(cn)) {
1.195 - out.append(" /* needs ").append(cn).append(" */");
1.196 + debug(" /* needs " + cn + " */");
1.197 }
1.198 }
1.199
1.200 @@ -1538,4 +1584,39 @@
1.201
1.202 out.append(format, processed, length);
1.203 }
1.204 +
1.205 + private void generateCatch(TrapData[] traps) throws IOException {
1.206 + out.append("} catch (e) {\n");
1.207 + int finallyPC = -1;
1.208 + for (TrapData e : traps) {
1.209 + if (e == null) {
1.210 + break;
1.211 + }
1.212 + if (e.catch_cpx != 0) { //not finally
1.213 + final String classInternalName = jc.getClassName(e.catch_cpx);
1.214 + addReference(classInternalName);
1.215 + if ("java/lang/Throwable".equals(classInternalName)) {
1.216 + out.append("if (e.$instOf_java_lang_Throwable) {");
1.217 + out.append(" stA0 = e;");
1.218 + out.append("} else {");
1.219 + out.append(" stA0 = vm.java_lang_Throwable(true);");
1.220 + out.append(" vm.java_lang_Throwable.cons__VLjava_lang_String_2(stA0, e.toString());");
1.221 + out.append("}");
1.222 + out.append("gt=" + e.handler_pc + "; continue;");
1.223 + } else {
1.224 + out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {");
1.225 + out.append("gt=" + e.handler_pc + "; stA0 = e; continue;");
1.226 + out.append("}\n");
1.227 + }
1.228 + } else {
1.229 + finallyPC = e.handler_pc;
1.230 + }
1.231 + }
1.232 + if (finallyPC == -1) {
1.233 + out.append("throw e;");
1.234 + } else {
1.235 + out.append("gt=" + finallyPC + "; stA0 = e; continue;");
1.236 + }
1.237 + out.append("\n}");
1.238 + }
1.239 }