vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
brancharithmetic
changeset 427 12e866a32b40
parent 351 b7459b10d581
parent 424 aef4fd91e99c
child 438 7df624c2a0a1
child 442 b107ed66f2e7
     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  }