rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
branchclosure
changeset 1513 ba912ef24b27
parent 1485 2af07db15110
parent 1510 b242abb07fbf
child 1514 d2401e2648af
     1.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Thu Apr 24 18:05:21 2014 +0200
     1.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Wed Apr 30 15:04:10 2014 +0200
     1.3 @@ -25,14 +25,36 @@
     1.4   *
     1.5   * @author Jaroslav Tulach <jtulach@netbeans.org>
     1.6   */
     1.7 -abstract class ByteCodeToJavaScript {
     1.8 +abstract class ByteCodeToJavaScript implements Appendable {
     1.9      private ClassData jc;
    1.10 -    final Appendable out;
    1.11 +    private final Appendable out;
    1.12 +    private boolean outChanged;
    1.13  
    1.14      protected ByteCodeToJavaScript(Appendable out) {
    1.15          this.out = out;
    1.16      }
    1.17      
    1.18 +    @Override
    1.19 +    public final Appendable append(CharSequence csq) throws IOException {
    1.20 +        out.append(csq);
    1.21 +        outChanged = true;
    1.22 +        return this;
    1.23 +    }
    1.24 +
    1.25 +    @Override
    1.26 +    public final Appendable append(CharSequence csq, int start, int end) throws IOException {
    1.27 +        out.append(csq, start, end);
    1.28 +        outChanged = true;
    1.29 +        return this;
    1.30 +    }
    1.31 +
    1.32 +    @Override
    1.33 +    public final Appendable append(char c) throws IOException {
    1.34 +        out.append(c);
    1.35 +        outChanged = true;
    1.36 +        return this;
    1.37 +    }
    1.38 +    
    1.39      /* Collects additional required resources.
    1.40       * 
    1.41       * @param internalClassName classes that were referenced and should be loaded in order the
    1.42 @@ -99,7 +121,7 @@
    1.43       * @throws IOException 
    1.44       */
    1.45      boolean debug(String msg) throws IOException {
    1.46 -        out.append(msg);
    1.47 +        append(msg);
    1.48          return true;
    1.49      }
    1.50  
    1.51 @@ -124,16 +146,34 @@
    1.52              );
    1.53          }
    1.54          byte[] arrData = jc.findAnnotationData(true);
    1.55 -        String[] arr = findAnnotation(arrData, jc, 
    1.56 -            "org.apidesign.bck2brwsr.core.ExtraJavaScript", 
    1.57 -            "resource", "processByteCode"
    1.58 -        );
    1.59 -        if (arr != null) {
    1.60 -            if (!arr[0].isEmpty()) {
    1.61 -                requireScript(arr[0]);
    1.62 +        {
    1.63 +            String[] arr = findAnnotation(arrData, jc, 
    1.64 +                "org.apidesign.bck2brwsr.core.ExtraJavaScript", 
    1.65 +                "resource", "processByteCode"
    1.66 +            );
    1.67 +            if (arr != null) {
    1.68 +                if (!arr[0].isEmpty()) {
    1.69 +                    requireScript(arr[0]);
    1.70 +                }
    1.71 +                if ("0".equals(arr[1])) {
    1.72 +                    return null;
    1.73 +                }
    1.74              }
    1.75 -            if ("0".equals(arr[1])) {
    1.76 -                return null;
    1.77 +        }
    1.78 +        {
    1.79 +            String[] arr = findAnnotation(arrData, jc, 
    1.80 +                "net.java.html.js.JavaScriptResource", 
    1.81 +                "value"
    1.82 +            );
    1.83 +            if (arr != null) {
    1.84 +                if (arr[0].startsWith("/")) {
    1.85 +                    requireScript(arr[0]);
    1.86 +                } else {
    1.87 +                    int last = jc.getClassName().lastIndexOf('/');
    1.88 +                    requireScript(
    1.89 +                        jc.getClassName().substring(0, last + 1).replace('.', '/') + arr[0]
    1.90 +                    );
    1.91 +                }
    1.92              }
    1.93          }
    1.94          String[] proto = findAnnotation(arrData, jc, 
    1.95 @@ -142,34 +182,39 @@
    1.96          );
    1.97          StringArray toInitilize = new StringArray();
    1.98          final String className = className(jc);
    1.99 -        out.append("\n\n").append(assignClass(className));
   1.100 -        out.append("function ").append(className).append("() {");
   1.101 -        out.append("\n  var CLS = ").append(className).append(';');
   1.102 -        out.append("\n  if (!CLS.$class) {");
   1.103 +        append("\n\n").append(assignClass(className));
   1.104 +        append("function ").append(className).append("() {");
   1.105 +        append("\n  var CLS = ").append(className).append(';');
   1.106 +        append("\n  if (!CLS.$class) {");
   1.107          if (proto == null) {
   1.108              String sc = jc.getSuperClassName(); // with _
   1.109 -            out.append("\n    var pp = ").
   1.110 -                append(accessClass(sc.replace('/', '_'))).append("(true);");
   1.111 -            out.append("\n    var p = CLS.prototype = pp;");
   1.112 -            out.append("\n    var c = p;");
   1.113 -            out.append("\n    var sprcls = pp.constructor.$class;");
   1.114 +            append("\n    var pp = ").
   1.115 +                append(accessClass(mangleClassName(sc))).append("(true);");
   1.116 +            append("\n    var p = CLS.prototype = pp;");
   1.117 +            append("\n    var c = p;");
   1.118 +            append("\n    var sprcls = pp.constructor.$class;");
   1.119          } else {
   1.120 -            out.append("\n    var p = CLS.prototype = ").append(proto[1]).append(";");
   1.121 +            append("\n    var p = CLS.prototype = ").append(proto[1]).append(";");
   1.122              if (proto[0] == null) {
   1.123                  proto[0] = "p";
   1.124              }
   1.125 -            out.append("\n    var c = ").append(proto[0]).append(";");
   1.126 -            out.append("\n    var sprcls = null;");
   1.127 +            append("\n    var c = ").append(proto[0]).append(";");
   1.128 +            append("\n    var sprcls = null;");
   1.129          }
   1.130          for (FieldData v : jc.getFields()) {
   1.131              if (v.isStatic()) {
   1.132 -                out.append("\n  CLS.").append(v.getName()).append(initField(v));
   1.133 -                out.append("\n  c._").append(v.getName()).append(" = function (v) {")
   1.134 -                   .append("  if (arguments.length == 1) CLS.").append(v.getName())
   1.135 -                   .append(" = v; return CLS.").
   1.136 +                if ((v.access & ACC_FINAL) != 0 && v.hasConstantValue()) {
   1.137 +                    if (v.getInternalSig().length() == 1 || v.getInternalSig().equals("Ljava/lang/String;")) {
   1.138 +                        continue;
   1.139 +                    }
   1.140 +                }
   1.141 +                append("\n  CLS.fld_").append(v.getName()).append(initField(v));
   1.142 +                append("\n  c._").append(v.getName()).append(" = function (v) {")
   1.143 +                   .append("  if (arguments.length == 1) CLS.fld_").append(v.getName())
   1.144 +                   .append(" = v; return CLS.fld_").
   1.145                      append(v.getName()).append("; };");
   1.146              } else {
   1.147 -                out.append("\n  c._").append(v.getName()).append(" = function (v) {")
   1.148 +                append("\n  c._").append(v.getName()).append(" = function (v) {")
   1.149                     .append("  if (arguments.length == 1) this.fld_").
   1.150                      append(className).append('_').append(v.getName())
   1.151                     .append(" = v; return this.fld_").
   1.152 @@ -187,14 +232,14 @@
   1.153              );
   1.154              if (only != null) {
   1.155                  if (only[0] != null && only[1] != null) {
   1.156 -                    out.append("\n    p.").append(only[0]).append(" = ")
   1.157 +                    append("\n    p.").append(only[0]).append(" = ")
   1.158                          .append(only[1]).append(";");
   1.159                  }
   1.160                  continue;
   1.161              }
   1.162              String destObject;
   1.163              String mn;
   1.164 -            out.append("\n    ");
   1.165 +            append("\n    ");
   1.166              if (m.isStatic()) {
   1.167                  destObject = "c";
   1.168                  mn = generateStaticMethod(destObject, m, toInitilize);
   1.169 @@ -210,39 +255,47 @@
   1.170              declaredMethod(m, destObject, mn);
   1.171              byte[] runAnno = m.findAnnotationData(false);
   1.172              if (runAnno != null) {
   1.173 -                out.append("\n    ").append(destObject).append(".").append(mn).append(".anno = {");
   1.174 -                generateAnno(jc, out, runAnno);
   1.175 -                out.append("\n    };");
   1.176 +                append("\n    ").append(destObject).append(".").append(mn).append(".anno = {");
   1.177 +                generateAnno(jc, runAnno);
   1.178 +                append("\n    };");
   1.179              }
   1.180 -            out.append("\n    ").append(destObject).append(".").append(mn).append(".access = " + m.getAccess()).append(";");
   1.181 -            out.append("\n    ").append(destObject).append(".").append(mn).append(".cls = CLS;");
   1.182 +            append("\n    ").append(destObject).append(".").append(mn).append(".access = " + m.getAccess()).append(";");
   1.183 +            append("\n    ").append(destObject).append(".").append(mn).append(".cls = CLS;");
   1.184          }
   1.185 -        out.append("\n    c.constructor = CLS;");
   1.186 -        out.append("\n    c['$instOf_").append(className).append("'] = true;");
   1.187 +        append("\n    c.constructor = CLS;");
   1.188 +        append("\n    function fillInstOf(x) {");
   1.189 +        String instOfName = "$instOf_" + className;
   1.190 +        append("\n        x['").append(instOfName).append("'] = true;");
   1.191          for (String superInterface : jc.getSuperInterfaces()) {
   1.192 -            out.append("\n    c['$instOf_").append(superInterface.replace('/', '_')).append("'] = true;");
   1.193 +            String intrfc = superInterface.replace('/', '_');
   1.194 +            append("\n      vm.").append(intrfc).append("(false)['fillInstOf'](x);");
   1.195 +            requireReference(superInterface);
   1.196          }
   1.197 -        out.append("\n    CLS.$class = 'temp';");
   1.198 -        out.append("\n    CLS.$class = ");
   1.199 -        out.append(accessClass("java_lang_Class(true);"));
   1.200 -        out.append("\n    CLS.$class.jvmName = '").append(jc.getClassName()).append("';");
   1.201 -        out.append("\n    CLS.$class.superclass = sprcls;");
   1.202 -        out.append("\n    CLS.$class.access = ").append(jc.getAccessFlags()+";");
   1.203 -        out.append("\n    CLS.$class.cnstr = CLS;");
   1.204 +        append("\n    }");
   1.205 +        append("\n    c['fillInstOf'] = fillInstOf;");
   1.206 +        append("\n    fillInstOf(c);");
   1.207 +//        obfuscationDelegate.exportJSProperty(this, "c", instOfName);
   1.208 +        append("\n    CLS.$class = 'temp';");
   1.209 +        append("\n    CLS.$class = ");
   1.210 +        append(accessClass("java_lang_Class(true);"));
   1.211 +        append("\n    CLS.$class.jvmName = '").append(jc.getClassName()).append("';");
   1.212 +        append("\n    CLS.$class.superclass = sprcls;");
   1.213 +        append("\n    CLS.$class.access = ").append(jc.getAccessFlags()+";");
   1.214 +        append("\n    CLS.$class.cnstr = CLS;");
   1.215          byte[] classAnno = jc.findAnnotationData(false);
   1.216          if (classAnno != null) {
   1.217 -            out.append("\n    CLS.$class.anno = {");
   1.218 -            generateAnno(jc, out, classAnno);
   1.219 -            out.append("\n    };");
   1.220 +            append("\n    CLS.$class.anno = {");
   1.221 +            generateAnno(jc, classAnno);
   1.222 +            append("\n    };");
   1.223          }
   1.224          for (String init : toInitilize.toArray()) {
   1.225 -            out.append("\n    ").append(init).append("();");
   1.226 +            append("\n    ").append(init).append("();");
   1.227          }
   1.228 -        out.append("\n  }");
   1.229 -        out.append("\n  if (arguments.length === 0) {");
   1.230 -        out.append("\n    if (!(this instanceof CLS)) {");
   1.231 -        out.append("\n      return new CLS();");
   1.232 -        out.append("\n    }");
   1.233 +        append("\n  }");
   1.234 +        append("\n  if (arguments.length === 0) {");
   1.235 +        append("\n    if (!(this instanceof CLS)) {");
   1.236 +        append("\n      return new CLS();");
   1.237 +        append("\n    }");
   1.238          for (FieldData v : jc.getFields()) {
   1.239              byte[] onlyArr = v.findAnnotationData(true);
   1.240              String[] only = findAnnotation(onlyArr, jc, 
   1.241 @@ -251,21 +304,21 @@
   1.242              );
   1.243              if (only != null) {
   1.244                  if (only[0] != null && only[1] != null) {
   1.245 -                    out.append("\n    p.").append(only[0]).append(" = ")
   1.246 +                    append("\n    p.").append(only[0]).append(" = ")
   1.247                          .append(only[1]).append(";");
   1.248                  }
   1.249                  continue;
   1.250              }
   1.251              if (!v.isStatic()) {
   1.252 -                out.append("\n    this.fld_").
   1.253 +                append("\n    this.fld_").
   1.254                      append(className).append('_').
   1.255                      append(v.getName()).append(initField(v));
   1.256              }
   1.257          }
   1.258 -        out.append("\n    return this;");
   1.259 -        out.append("\n  }");
   1.260 -        out.append("\n  return arguments[0] ? new CLS() : CLS.prototype;");
   1.261 -        out.append("\n};");
   1.262 +        append("\n    return this;");
   1.263 +        append("\n  }");
   1.264 +        append("\n  return arguments[0] ? new CLS() : CLS.prototype;");
   1.265 +        append("\n};");
   1.266  
   1.267          declaredClass(jc, className);
   1.268  
   1.269 @@ -305,34 +358,43 @@
   1.270          final LocalsMapper lmapper =
   1.271                  new LocalsMapper(stackMapIterator.getArguments());
   1.272  
   1.273 -        out.append(destObject).append(".").append(name).append(" = function(");
   1.274 -        lmapper.outputArguments(out, m.isStatic());
   1.275 -        out.append(") {").append("\n");
   1.276 +        append(destObject).append(".").append(name).append(" = function(");
   1.277 +        lmapper.outputArguments(this, m.isStatic());
   1.278 +        append(") {").append("\n");
   1.279  
   1.280          final byte[] byteCodes = m.getCode();
   1.281          if (byteCodes == null) {
   1.282 -            out.append("  throw 'no code found for ")
   1.283 +            append("  throw 'no code found for ")
   1.284                 .append(jc.getClassName()).append('.')
   1.285                 .append(m.getName()).append("';\n");
   1.286 -            out.append("};");
   1.287 +            append("};");
   1.288              return;
   1.289          }
   1.290  
   1.291          final StackMapper smapper = new StackMapper();
   1.292  
   1.293          if (!m.isStatic()) {
   1.294 -            out.append("  var ").append(" lcA0 = this;\n");
   1.295 +            append("  var ").append(" lcA0 = this;\n");
   1.296          }
   1.297  
   1.298 -        int lastStackFrame = -1;
   1.299 +        int lastStackFrame;
   1.300          TrapData[] previousTrap = null;
   1.301          boolean wide = false;
   1.302 +        boolean didBranches;
   1.303 +        if (stackMapIterator.isEmpty()) {
   1.304 +            didBranches = false;
   1.305 +            lastStackFrame = 0;
   1.306 +        } else {
   1.307 +            didBranches = true;
   1.308 +            lastStackFrame = -1;
   1.309 +            append("\n  var gt = 0;\n");
   1.310 +        }
   1.311          
   1.312 -        out.append("\n  var gt = 0;\n");
   1.313          int openBraces = 0;
   1.314          int topMostLabel = 0;
   1.315          for (int i = 0; i < byteCodes.length; i++) {
   1.316              int prev = i;
   1.317 +            outChanged = false;
   1.318              stackMapIterator.advanceTo(i);
   1.319              boolean changeInCatch = trap.advanceTo(i);
   1.320              if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) {
   1.321 @@ -342,12 +404,13 @@
   1.322                  }
   1.323              }
   1.324              if (lastStackFrame != stackMapIterator.getFrameIndex()) {
   1.325 +                smapper.flush(this);
   1.326                  if (i != 0) {
   1.327 -                    out.append("    }\n");
   1.328 +                    append("    }\n");
   1.329                  }
   1.330                  if (openBraces > 64) {
   1.331                      for (int c = 0; c < 64; c++) {
   1.332 -                        out.append("break;}\n");
   1.333 +                        append("break;}\n");
   1.334                      }
   1.335                      openBraces = 1;
   1.336                      topMostLabel = i;
   1.337 @@ -356,85 +419,84 @@
   1.338                  lastStackFrame = stackMapIterator.getFrameIndex();
   1.339                  lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals());
   1.340                  smapper.syncWithFrameStack(stackMapIterator.getFrameStack());
   1.341 -                out.append("    X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n");
   1.342 +                append("    X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n");
   1.343                  openBraces++;
   1.344                  changeInCatch = true;
   1.345              } else {
   1.346                  debug("    /* " + i + " */ ");
   1.347              }
   1.348              if (changeInCatch && trap.useTry()) {
   1.349 -                out.append("try {");
   1.350 +                append("try {");
   1.351                  previousTrap = trap.current();
   1.352              }
   1.353              final int c = readUByte(byteCodes, i);
   1.354              switch (c) {
   1.355                  case opc_aload_0:
   1.356 -                    emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(0));
   1.357 +                    smapper.assign(this, VarType.REFERENCE, lmapper.getA(0));
   1.358                      break;
   1.359                  case opc_iload_0:
   1.360 -                    emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(0));
   1.361 +                    smapper.assign(this, VarType.INTEGER, lmapper.getI(0));
   1.362                      break;
   1.363                  case opc_lload_0:
   1.364 -                    emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(0));
   1.365 +                    smapper.assign(this, VarType.LONG, lmapper.getL(0));
   1.366                      break;
   1.367                  case opc_fload_0:
   1.368 -                    emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(0));
   1.369 +                    smapper.assign(this, VarType.FLOAT, lmapper.getF(0));
   1.370                      break;
   1.371                  case opc_dload_0:
   1.372 -                    emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(0));
   1.373 +                    smapper.assign(this, VarType.DOUBLE, lmapper.getD(0));
   1.374                      break;
   1.375                  case opc_aload_1:
   1.376 -                    emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(1));
   1.377 +                    smapper.assign(this, VarType.REFERENCE, lmapper.getA(1));
   1.378                      break;
   1.379                  case opc_iload_1:
   1.380 -                    emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(1));
   1.381 +                    smapper.assign(this, VarType.INTEGER, lmapper.getI(1));
   1.382                      break;
   1.383                  case opc_lload_1:
   1.384 -                    emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(1));
   1.385 +                    smapper.assign(this, VarType.LONG, lmapper.getL(1));
   1.386                      break;
   1.387                  case opc_fload_1:
   1.388 -                    emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(1));
   1.389 +                    smapper.assign(this, VarType.FLOAT, lmapper.getF(1));
   1.390                      break;
   1.391                  case opc_dload_1:
   1.392 -                    emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(1));
   1.393 +                    smapper.assign(this, VarType.DOUBLE, lmapper.getD(1));
   1.394                      break;
   1.395                  case opc_aload_2:
   1.396 -                    emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(2));
   1.397 +                    smapper.assign(this, VarType.REFERENCE, lmapper.getA(2));
   1.398                      break;
   1.399                  case opc_iload_2:
   1.400 -                    emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(2));
   1.401 +                    smapper.assign(this, VarType.INTEGER, lmapper.getI(2));
   1.402                      break;
   1.403                  case opc_lload_2:
   1.404 -                    emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(2));
   1.405 +                    smapper.assign(this, VarType.LONG, lmapper.getL(2));
   1.406                      break;
   1.407                  case opc_fload_2:
   1.408 -                    emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(2));
   1.409 +                    smapper.assign(this, VarType.FLOAT, lmapper.getF(2));
   1.410                      break;
   1.411                  case opc_dload_2:
   1.412 -                    emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(2));
   1.413 +                    smapper.assign(this, VarType.DOUBLE, lmapper.getD(2));
   1.414                      break;
   1.415                  case opc_aload_3:
   1.416 -                    emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(3));
   1.417 +                    smapper.assign(this, VarType.REFERENCE, lmapper.getA(3));
   1.418                      break;
   1.419                  case opc_iload_3:
   1.420 -                    emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(3));
   1.421 +                    smapper.assign(this, VarType.INTEGER, lmapper.getI(3));
   1.422                      break;
   1.423                  case opc_lload_3:
   1.424 -                    emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(3));
   1.425 +                    smapper.assign(this, VarType.LONG, lmapper.getL(3));
   1.426                      break;
   1.427                  case opc_fload_3:
   1.428 -                    emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(3));
   1.429 +                    smapper.assign(this, VarType.FLOAT, lmapper.getF(3));
   1.430                      break;
   1.431                  case opc_dload_3:
   1.432 -                    emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(3));
   1.433 +                    smapper.assign(this, VarType.DOUBLE, lmapper.getD(3));
   1.434                      break;
   1.435                  case opc_iload: {
   1.436                      ++i;
   1.437                      final int indx = wide ? readUShort(byteCodes, i++)
   1.438                                            : readUByte(byteCodes, i);
   1.439                      wide = false;
   1.440 -                    emit(out, "var @1 = @2;",
   1.441 -                         smapper.pushI(), lmapper.getI(indx));
   1.442 +                    smapper.assign(this, VarType.INTEGER, lmapper.getI(indx));
   1.443                      break;
   1.444                  }
   1.445                  case opc_lload: {
   1.446 @@ -442,8 +504,7 @@
   1.447                      final int indx = wide ? readUShort(byteCodes, i++)
   1.448                                            : readUByte(byteCodes, i);
   1.449                      wide = false;
   1.450 -                    emit(out, "var @1 = @2;",
   1.451 -                         smapper.pushL(), lmapper.getL(indx));
   1.452 +                    smapper.assign(this, VarType.LONG, lmapper.getL(indx));
   1.453                      break;
   1.454                  }
   1.455                  case opc_fload: {
   1.456 @@ -451,8 +512,7 @@
   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 -                         smapper.pushF(), lmapper.getF(indx));
   1.462 +                    smapper.assign(this, VarType.FLOAT, lmapper.getF(indx));
   1.463                      break;
   1.464                  }
   1.465                  case opc_dload: {
   1.466 @@ -460,8 +520,7 @@
   1.467                      final int indx = wide ? readUShort(byteCodes, i++)
   1.468                                            : readUByte(byteCodes, i);
   1.469                      wide = false;
   1.470 -                    emit(out, "var @1 = @2;",
   1.471 -                         smapper.pushD(), lmapper.getD(indx));
   1.472 +                    smapper.assign(this, VarType.DOUBLE, lmapper.getD(indx));
   1.473                      break;
   1.474                  }
   1.475                  case opc_aload: {
   1.476 @@ -469,8 +528,7 @@
   1.477                      final int indx = wide ? readUShort(byteCodes, i++)
   1.478                                            : readUByte(byteCodes, i);
   1.479                      wide = false;
   1.480 -                    emit(out, "var @1 = @2;",
   1.481 -                         smapper.pushA(), lmapper.getA(indx));
   1.482 +                    smapper.assign(this, VarType.REFERENCE, lmapper.getA(indx));
   1.483                      break;
   1.484                  }
   1.485                  case opc_istore: {
   1.486 @@ -478,7 +536,7 @@
   1.487                      final int indx = wide ? readUShort(byteCodes, i++)
   1.488                                            : readUByte(byteCodes, i);
   1.489                      wide = false;
   1.490 -                    emit(out, "var @1 = @2;",
   1.491 +                    emit(smapper, this, "var @1 = @2;",
   1.492                           lmapper.setI(indx), smapper.popI());
   1.493                      break;
   1.494                  }
   1.495 @@ -487,7 +545,7 @@
   1.496                      final int indx = wide ? readUShort(byteCodes, i++)
   1.497                                            : readUByte(byteCodes, i);
   1.498                      wide = false;
   1.499 -                    emit(out, "var @1 = @2;",
   1.500 +                    emit(smapper, this, "var @1 = @2;",
   1.501                           lmapper.setL(indx), smapper.popL());
   1.502                      break;
   1.503                  }
   1.504 @@ -496,7 +554,7 @@
   1.505                      final int indx = wide ? readUShort(byteCodes, i++)
   1.506                                            : readUByte(byteCodes, i);
   1.507                      wide = false;
   1.508 -                    emit(out, "var @1 = @2;",
   1.509 +                    emit(smapper, this, "var @1 = @2;",
   1.510                           lmapper.setF(indx), smapper.popF());
   1.511                      break;
   1.512                  }
   1.513 @@ -505,7 +563,7 @@
   1.514                      final int indx = wide ? readUShort(byteCodes, i++)
   1.515                                            : readUByte(byteCodes, i);
   1.516                      wide = false;
   1.517 -                    emit(out, "var @1 = @2;",
   1.518 +                    emit(smapper, this, "var @1 = @2;",
   1.519                           lmapper.setD(indx), smapper.popD());
   1.520                      break;
   1.521                  }
   1.522 @@ -514,181 +572,181 @@
   1.523                      final int indx = wide ? readUShort(byteCodes, i++)
   1.524                                            : readUByte(byteCodes, i);
   1.525                      wide = false;
   1.526 -                    emit(out, "var @1 = @2;",
   1.527 +                    emit(smapper, this, "var @1 = @2;",
   1.528                           lmapper.setA(indx), smapper.popA());
   1.529                      break;
   1.530                  }
   1.531                  case opc_astore_0:
   1.532 -                    emit(out, "var @1 = @2;", lmapper.setA(0), smapper.popA());
   1.533 +                    emit(smapper, this, "var @1 = @2;", lmapper.setA(0), smapper.popA());
   1.534                      break;
   1.535                  case opc_istore_0:
   1.536 -                    emit(out, "var @1 = @2;", lmapper.setI(0), smapper.popI());
   1.537 +                    emit(smapper, this, "var @1 = @2;", lmapper.setI(0), smapper.popI());
   1.538                      break;
   1.539                  case opc_lstore_0:
   1.540 -                    emit(out, "var @1 = @2;", lmapper.setL(0), smapper.popL());
   1.541 +                    emit(smapper, this, "var @1 = @2;", lmapper.setL(0), smapper.popL());
   1.542                      break;
   1.543                  case opc_fstore_0:
   1.544 -                    emit(out, "var @1 = @2;", lmapper.setF(0), smapper.popF());
   1.545 +                    emit(smapper, this, "var @1 = @2;", lmapper.setF(0), smapper.popF());
   1.546                      break;
   1.547                  case opc_dstore_0:
   1.548 -                    emit(out, "var @1 = @2;", lmapper.setD(0), smapper.popD());
   1.549 +                    emit(smapper, this, "var @1 = @2;", lmapper.setD(0), smapper.popD());
   1.550                      break;
   1.551                  case opc_astore_1:
   1.552 -                    emit(out, "var @1 = @2;", lmapper.setA(1), smapper.popA());
   1.553 +                    emit(smapper, this, "var @1 = @2;", lmapper.setA(1), smapper.popA());
   1.554                      break;
   1.555                  case opc_istore_1:
   1.556 -                    emit(out, "var @1 = @2;", lmapper.setI(1), smapper.popI());
   1.557 +                    emit(smapper, this, "var @1 = @2;", lmapper.setI(1), smapper.popI());
   1.558                      break;
   1.559                  case opc_lstore_1:
   1.560 -                    emit(out, "var @1 = @2;", lmapper.setL(1), smapper.popL());
   1.561 +                    emit(smapper, this, "var @1 = @2;", lmapper.setL(1), smapper.popL());
   1.562                      break;
   1.563                  case opc_fstore_1:
   1.564 -                    emit(out, "var @1 = @2;", lmapper.setF(1), smapper.popF());
   1.565 +                    emit(smapper, this, "var @1 = @2;", lmapper.setF(1), smapper.popF());
   1.566                      break;
   1.567                  case opc_dstore_1:
   1.568 -                    emit(out, "var @1 = @2;", lmapper.setD(1), smapper.popD());
   1.569 +                    emit(smapper, this, "var @1 = @2;", lmapper.setD(1), smapper.popD());
   1.570                      break;
   1.571                  case opc_astore_2:
   1.572 -                    emit(out, "var @1 = @2;", lmapper.setA(2), smapper.popA());
   1.573 +                    emit(smapper, this, "var @1 = @2;", lmapper.setA(2), smapper.popA());
   1.574                      break;
   1.575                  case opc_istore_2:
   1.576 -                    emit(out, "var @1 = @2;", lmapper.setI(2), smapper.popI());
   1.577 +                    emit(smapper, this, "var @1 = @2;", lmapper.setI(2), smapper.popI());
   1.578                      break;
   1.579                  case opc_lstore_2:
   1.580 -                    emit(out, "var @1 = @2;", lmapper.setL(2), smapper.popL());
   1.581 +                    emit(smapper, this, "var @1 = @2;", lmapper.setL(2), smapper.popL());
   1.582                      break;
   1.583                  case opc_fstore_2:
   1.584 -                    emit(out, "var @1 = @2;", lmapper.setF(2), smapper.popF());
   1.585 +                    emit(smapper, this, "var @1 = @2;", lmapper.setF(2), smapper.popF());
   1.586                      break;
   1.587                  case opc_dstore_2:
   1.588 -                    emit(out, "var @1 = @2;", lmapper.setD(2), smapper.popD());
   1.589 +                    emit(smapper, this, "var @1 = @2;", lmapper.setD(2), smapper.popD());
   1.590                      break;
   1.591                  case opc_astore_3:
   1.592 -                    emit(out, "var @1 = @2;", lmapper.setA(3), smapper.popA());
   1.593 +                    emit(smapper, this, "var @1 = @2;", lmapper.setA(3), smapper.popA());
   1.594                      break;
   1.595                  case opc_istore_3:
   1.596 -                    emit(out, "var @1 = @2;", lmapper.setI(3), smapper.popI());
   1.597 +                    emit(smapper, this, "var @1 = @2;", lmapper.setI(3), smapper.popI());
   1.598                      break;
   1.599                  case opc_lstore_3:
   1.600 -                    emit(out, "var @1 = @2;", lmapper.setL(3), smapper.popL());
   1.601 +                    emit(smapper, this, "var @1 = @2;", lmapper.setL(3), smapper.popL());
   1.602                      break;
   1.603                  case opc_fstore_3:
   1.604 -                    emit(out, "var @1 = @2;", lmapper.setF(3), smapper.popF());
   1.605 +                    emit(smapper, this, "var @1 = @2;", lmapper.setF(3), smapper.popF());
   1.606                      break;
   1.607                  case opc_dstore_3:
   1.608 -                    emit(out, "var @1 = @2;", lmapper.setD(3), smapper.popD());
   1.609 +                    emit(smapper, this, "var @1 = @2;", lmapper.setD(3), smapper.popD());
   1.610                      break;
   1.611                  case opc_iadd:
   1.612 -                    emit(out, "@1 = @1.add32(@2);", smapper.getI(1), smapper.popI());
   1.613 +                    smapper.replace(this, VarType.INTEGER, "(@1).add32(@2)", smapper.getI(1), smapper.popI());
   1.614                      break;
   1.615                  case opc_ladd:
   1.616 -                    emit(out, "@1 = @1.add64(@2);", smapper.getL(1), smapper.popL());
   1.617 +                    smapper.replace(this, VarType.LONG, "(@1).add64(@2)", smapper.getL(1), smapper.popL());
   1.618                      break;
   1.619                  case opc_fadd:
   1.620 -                    emit(out, "@1 += @2;", smapper.getF(1), smapper.popF());
   1.621 +                    smapper.replace(this, VarType.FLOAT, "(@1 + @2)", smapper.getF(1), smapper.popF());
   1.622                      break;
   1.623                  case opc_dadd:
   1.624 -                    emit(out, "@1 += @2;", smapper.getD(1), smapper.popD());
   1.625 +                    smapper.replace(this, VarType.DOUBLE, "(@1 + @2)", smapper.getD(1), smapper.popD());
   1.626                      break;
   1.627                  case opc_isub:
   1.628 -                    emit(out, "@1 = @1.sub32(@2);", smapper.getI(1), smapper.popI());
   1.629 +                    smapper.replace(this, VarType.INTEGER, "(@1).sub32(@2)", smapper.getI(1), smapper.popI());
   1.630                      break;
   1.631                  case opc_lsub:
   1.632 -                    emit(out, "@1 = @1.sub64(@2);", smapper.getL(1), smapper.popL());
   1.633 +                    smapper.replace(this, VarType.LONG, "(@1).sub64(@2)", smapper.getL(1), smapper.popL());
   1.634                      break;
   1.635                  case opc_fsub:
   1.636 -                    emit(out, "@1 -= @2;", smapper.getF(1), smapper.popF());
   1.637 +                    smapper.replace(this, VarType.FLOAT, "(@1 - @2)", smapper.getF(1), smapper.popF());
   1.638                      break;
   1.639                  case opc_dsub:
   1.640 -                    emit(out, "@1 -= @2;", smapper.getD(1), smapper.popD());
   1.641 +                    smapper.replace(this, VarType.DOUBLE, "(@1 - @2)", smapper.getD(1), smapper.popD());
   1.642                      break;
   1.643                  case opc_imul:
   1.644 -                    emit(out, "@1 = @1.mul32(@2);", smapper.getI(1), smapper.popI());
   1.645 +                    smapper.replace(this, VarType.INTEGER, "(@1).mul32(@2)", smapper.getI(1), smapper.popI());
   1.646                      break;
   1.647                  case opc_lmul:
   1.648 -                    emit(out, "@1 = @1.mul64(@2);", smapper.getL(1), smapper.popL());
   1.649 +                    smapper.replace(this, VarType.LONG, "(@1).mul64(@2)", smapper.getL(1), smapper.popL());
   1.650                      break;
   1.651                  case opc_fmul:
   1.652 -                    emit(out, "@1 *= @2;", smapper.getF(1), smapper.popF());
   1.653 +                    smapper.replace(this, VarType.FLOAT, "(@1 * @2)", smapper.getF(1), smapper.popF());
   1.654                      break;
   1.655                  case opc_dmul:
   1.656 -                    emit(out, "@1 *= @2;", smapper.getD(1), smapper.popD());
   1.657 +                    smapper.replace(this, VarType.DOUBLE, "(@1 * @2)", smapper.getD(1), smapper.popD());
   1.658                      break;
   1.659                  case opc_idiv:
   1.660 -                    emit(out, "@1 = @1.div32(@2);",
   1.661 +                    smapper.replace(this, VarType.INTEGER, "(@1).div32(@2)",
   1.662                           smapper.getI(1), smapper.popI());
   1.663                      break;
   1.664                  case opc_ldiv:
   1.665 -                    emit(out, "@1 = @1.div64(@2);",
   1.666 +                    smapper.replace(this, VarType.LONG, "(@1).div64(@2)",
   1.667                           smapper.getL(1), smapper.popL());
   1.668                      break;
   1.669                  case opc_fdiv:
   1.670 -                    emit(out, "@1 /= @2;", smapper.getF(1), smapper.popF());
   1.671 +                    smapper.replace(this, VarType.FLOAT, "(@1 / @2)", smapper.getF(1), smapper.popF());
   1.672                      break;
   1.673                  case opc_ddiv:
   1.674 -                    emit(out, "@1 /= @2;", smapper.getD(1), smapper.popD());
   1.675 +                    smapper.replace(this, VarType.DOUBLE, "(@1 / @2)", smapper.getD(1), smapper.popD());
   1.676                      break;
   1.677                  case opc_irem:
   1.678 -                    emit(out, "@1 = @1.mod32(@2);",
   1.679 +                    smapper.replace(this, VarType.INTEGER, "(@1).mod32(@2)",
   1.680                           smapper.getI(1), smapper.popI());
   1.681                      break;
   1.682                  case opc_lrem:
   1.683 -                    emit(out, "@1 = @1.mod64(@2);",
   1.684 +                    smapper.replace(this, VarType.LONG, "(@1).mod64(@2)",
   1.685                           smapper.getL(1), smapper.popL());
   1.686                      break;
   1.687                  case opc_frem:
   1.688 -                    emit(out, "@1 %= @2;", smapper.getF(1), smapper.popF());
   1.689 +                    smapper.replace(this, VarType.FLOAT, "(@1 % @2)", smapper.getF(1), smapper.popF());
   1.690                      break;
   1.691                  case opc_drem:
   1.692 -                    emit(out, "@1 %= @2;", smapper.getD(1), smapper.popD());
   1.693 +                    smapper.replace(this, VarType.DOUBLE, "(@1 % @2)", smapper.getD(1), smapper.popD());
   1.694                      break;
   1.695                  case opc_iand:
   1.696 -                    emit(out, "@1 &= @2;", smapper.getI(1), smapper.popI());
   1.697 +                    smapper.replace(this, VarType.INTEGER, "(@1 & @2)", smapper.getI(1), smapper.popI());
   1.698                      break;
   1.699                  case opc_land:
   1.700 -                    emit(out, "@1 = @1.and64(@2);", smapper.getL(1), smapper.popL());
   1.701 +                    smapper.replace(this, VarType.LONG, "(@1).and64(@2)", smapper.getL(1), smapper.popL());
   1.702                      break;
   1.703                  case opc_ior:
   1.704 -                    emit(out, "@1 |= @2;", smapper.getI(1), smapper.popI());
   1.705 +                    smapper.replace(this, VarType.INTEGER, "(@1 | @2)", smapper.getI(1), smapper.popI());
   1.706                      break;
   1.707                  case opc_lor:
   1.708 -                    emit(out, "@1 = @1.or64(@2);", smapper.getL(1), smapper.popL());
   1.709 +                    smapper.replace(this, VarType.LONG, "(@1).or64(@2)", smapper.getL(1), smapper.popL());
   1.710                      break;
   1.711                  case opc_ixor:
   1.712 -                    emit(out, "@1 ^= @2;", smapper.getI(1), smapper.popI());
   1.713 +                    smapper.replace(this, VarType.INTEGER, "(@1 ^ @2)", smapper.getI(1), smapper.popI());
   1.714                      break;
   1.715                  case opc_lxor:
   1.716 -                    emit(out, "@1 = @1.xor64(@2);", smapper.getL(1), smapper.popL());
   1.717 +                    smapper.replace(this, VarType.LONG, "(@1).xor64(@2)", smapper.getL(1), smapper.popL());
   1.718                      break;
   1.719                  case opc_ineg:
   1.720 -                    emit(out, "@1 = @1.neg32();", smapper.getI(0));
   1.721 +                    smapper.replace(this, VarType.INTEGER, "(@1).neg32()", smapper.getI(0));
   1.722                      break;
   1.723                  case opc_lneg:
   1.724 -                    emit(out, "@1 = @1.neg64();", smapper.getL(0));
   1.725 +                    smapper.replace(this, VarType.LONG, "(@1).neg64()", smapper.getL(0));
   1.726                      break;
   1.727                  case opc_fneg:
   1.728 -                    emit(out, "@1 = -@1;", smapper.getF(0));
   1.729 +                    smapper.replace(this, VarType.FLOAT, "(-@1)", smapper.getF(0));
   1.730                      break;
   1.731                  case opc_dneg:
   1.732 -                    emit(out, "@1 = -@1;", smapper.getD(0));
   1.733 +                    smapper.replace(this, VarType.DOUBLE, "(-@1)", smapper.getD(0));
   1.734                      break;
   1.735                  case opc_ishl:
   1.736 -                    emit(out, "@1 <<= @2;", smapper.getI(1), smapper.popI());
   1.737 +                    smapper.replace(this, VarType.INTEGER, "(@1 << @2)", smapper.getI(1), smapper.popI());
   1.738                      break;
   1.739                  case opc_lshl:
   1.740 -                    emit(out, "@1 = @1.shl64(@2);", smapper.getL(1), smapper.popI());
   1.741 +                    smapper.replace(this, VarType.LONG, "(@1).shl64(@2)", smapper.getL(1), smapper.popI());
   1.742                      break;
   1.743                  case opc_ishr:
   1.744 -                    emit(out, "@1 >>= @2;", smapper.getI(1), smapper.popI());
   1.745 +                    smapper.replace(this, VarType.INTEGER, "(@1 >> @2)", smapper.getI(1), smapper.popI());
   1.746                      break;
   1.747                  case opc_lshr:
   1.748 -                    emit(out, "@1 = @1.shr64(@2);", smapper.getL(1), smapper.popI());
   1.749 +                    smapper.replace(this, VarType.LONG, "(@1).shr64(@2)", smapper.getL(1), smapper.popI());
   1.750                      break;
   1.751                  case opc_iushr:
   1.752 -                    emit(out, "@1 >>>= @2;", smapper.getI(1), smapper.popI());
   1.753 +                    smapper.replace(this, VarType.INTEGER, "(@1 >>> @2)", smapper.getI(1), smapper.popI());
   1.754                      break;
   1.755                  case opc_lushr:
   1.756 -                    emit(out, "@1 = @1.ushr64(@2);", smapper.getL(1), smapper.popI());
   1.757 +                    smapper.replace(this, VarType.LONG, "(@1).ushr64(@2)", smapper.getL(1), smapper.popI());
   1.758                      break;
   1.759                  case opc_iinc: {
   1.760                      ++i;
   1.761 @@ -699,132 +757,132 @@
   1.762                                              : byteCodes[i];
   1.763                      wide = false;
   1.764                      if (incrBy == 1) {
   1.765 -                        emit(out, "@1++;", lmapper.getI(varIndx));
   1.766 +                        emit(smapper, this, "@1++;", lmapper.getI(varIndx));
   1.767                      } else {
   1.768 -                        emit(out, "@1 += @2;",
   1.769 +                        emit(smapper, this, "@1 += @2;",
   1.770                               lmapper.getI(varIndx),
   1.771                               Integer.toString(incrBy));
   1.772                      }
   1.773                      break;
   1.774                  }
   1.775                  case opc_return:
   1.776 -                    emit(out, "return;");
   1.777 +                    emit(smapper, this, "return;");
   1.778                      break;
   1.779                  case opc_ireturn:
   1.780 -                    emit(out, "return @1;", smapper.popI());
   1.781 +                    emit(smapper, this, "return @1;", smapper.popI());
   1.782                      break;
   1.783                  case opc_lreturn:
   1.784 -                    emit(out, "return @1;", smapper.popL());
   1.785 +                    emit(smapper, this, "return @1;", smapper.popL());
   1.786                      break;
   1.787                  case opc_freturn:
   1.788 -                    emit(out, "return @1;", smapper.popF());
   1.789 +                    emit(smapper, this, "return @1;", smapper.popF());
   1.790                      break;
   1.791                  case opc_dreturn:
   1.792 -                    emit(out, "return @1;", smapper.popD());
   1.793 +                    emit(smapper, this, "return @1;", smapper.popD());
   1.794                      break;
   1.795                  case opc_areturn:
   1.796 -                    emit(out, "return @1;", smapper.popA());
   1.797 +                    emit(smapper, this, "return @1;", smapper.popA());
   1.798                      break;
   1.799                  case opc_i2l:
   1.800 -                    emit(out, "var @2 = @1;", smapper.popI(), smapper.pushL());
   1.801 +                    smapper.replace(this, VarType.LONG, "@1", smapper.getI(0));
   1.802                      break;
   1.803                  case opc_i2f:
   1.804 -                    emit(out, "var @2 = @1;", smapper.popI(), smapper.pushF());
   1.805 +                    smapper.replace(this, VarType.FLOAT, "@1", smapper.getI(0));
   1.806                      break;
   1.807                  case opc_i2d:
   1.808 -                    emit(out, "var @2 = @1;", smapper.popI(), smapper.pushD());
   1.809 +                    smapper.replace(this, VarType.DOUBLE, "@1", smapper.getI(0));
   1.810                      break;
   1.811                  case opc_l2i:
   1.812 -                    emit(out, "var @2 = @1.toInt32();", smapper.popL(), smapper.pushI());
   1.813 +                    smapper.replace(this, VarType.INTEGER, "(@1).toInt32()", smapper.getL(0));
   1.814                      break;
   1.815                      // max int check?
   1.816                  case opc_l2f:
   1.817 -                    emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushF());
   1.818 +                    smapper.replace(this, VarType.FLOAT, "(@1).toFP()", smapper.getL(0));
   1.819                      break;
   1.820                  case opc_l2d:
   1.821 -                    emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushD());
   1.822 +                    smapper.replace(this, VarType.DOUBLE, "(@1).toFP()", smapper.getL(0));
   1.823                      break;
   1.824                  case opc_f2d:
   1.825 -                    emit(out, "var @2 = @1;", smapper.popF(), smapper.pushD());
   1.826 +                    smapper.replace(this, VarType.DOUBLE, "@1",
   1.827 +                         smapper.getF(0));
   1.828                      break;
   1.829                  case opc_d2f:
   1.830 -                    emit(out, "var @2 = @1;", smapper.popD(), smapper.pushF());
   1.831 +                    smapper.replace(this, VarType.FLOAT, "@1",
   1.832 +                         smapper.getD(0));
   1.833                      break;
   1.834                  case opc_f2i:
   1.835 -                    emit(out, "var @2 = @1.toInt32();",
   1.836 -                         smapper.popF(), smapper.pushI());
   1.837 +                    smapper.replace(this, VarType.INTEGER, "(@1).toInt32()",
   1.838 +                         smapper.getF(0));
   1.839                      break;
   1.840                  case opc_f2l:
   1.841 -                    emit(out, "var @2 = @1.toLong();",
   1.842 -                         smapper.popF(), smapper.pushL());
   1.843 +                    smapper.replace(this, VarType.LONG, "(@1).toLong()",
   1.844 +                         smapper.getF(0));
   1.845                      break;
   1.846                  case opc_d2i:
   1.847 -                    emit(out, "var @2 = @1.toInt32();",
   1.848 -                         smapper.popD(), smapper.pushI());
   1.849 +                    smapper.replace(this, VarType.INTEGER, "(@1).toInt32()",
   1.850 +                         smapper.getD(0));
   1.851                      break;
   1.852                  case opc_d2l:
   1.853 -                    emit(out, "var @2 = @1.toLong();",
   1.854 -                         smapper.popD(), smapper.pushL());
   1.855 +                    smapper.replace(this, VarType.LONG, "(@1).toLong()", smapper.getD(0));
   1.856                      break;
   1.857                  case opc_i2b:
   1.858 -                    emit(out, "var @1 = @1.toInt8();", smapper.getI(0));
   1.859 +                    smapper.replace(this, VarType.INTEGER, "(@1).toInt8()", smapper.getI(0));
   1.860                      break;
   1.861                  case opc_i2c:
   1.862 -                    out.append("{ /* number conversion */ }");
   1.863                      break;
   1.864                  case opc_i2s:
   1.865 -                    emit(out, "var @1 = @1.toInt16();", smapper.getI(0));
   1.866 +                    smapper.replace(this, VarType.INTEGER, "(@1).toInt16()", smapper.getI(0));
   1.867                      break;
   1.868                  case opc_aconst_null:
   1.869 -                    emit(out, "var @1 = null;", smapper.pushA());
   1.870 +                    smapper.assign(this, VarType.REFERENCE, "null");
   1.871                      break;
   1.872                  case opc_iconst_m1:
   1.873 -                    emit(out, "var @1 = -1;", smapper.pushI());
   1.874 +                    smapper.assign(this, VarType.INTEGER, "-1");
   1.875                      break;
   1.876                  case opc_iconst_0:
   1.877 -                    emit(out, "var @1 = 0;", smapper.pushI());
   1.878 +                    smapper.assign(this, VarType.INTEGER, "0");
   1.879                      break;
   1.880                  case opc_dconst_0:
   1.881 -                    emit(out, "var @1 = 0;", smapper.pushD());
   1.882 +                    smapper.assign(this, VarType.DOUBLE, "0");
   1.883                      break;
   1.884                  case opc_lconst_0:
   1.885 -                    emit(out, "var @1 = 0;", smapper.pushL());
   1.886 +                    smapper.assign(this, VarType.LONG, "0");
   1.887                      break;
   1.888                  case opc_fconst_0:
   1.889 -                    emit(out, "var @1 = 0;", smapper.pushF());
   1.890 +                    smapper.assign(this, VarType.FLOAT, "0");
   1.891                      break;
   1.892                  case opc_iconst_1:
   1.893 -                    emit(out, "var @1 = 1;", smapper.pushI());
   1.894 +                    smapper.assign(this, VarType.INTEGER, "1");
   1.895                      break;
   1.896                  case opc_lconst_1:
   1.897 -                    emit(out, "var @1 = 1;", smapper.pushL());
   1.898 +                    smapper.assign(this, VarType.LONG, "1");
   1.899                      break;
   1.900                  case opc_fconst_1:
   1.901 -                    emit(out, "var @1 = 1;", smapper.pushF());
   1.902 +                    smapper.assign(this, VarType.FLOAT, "1");
   1.903                      break;
   1.904                  case opc_dconst_1:
   1.905 -                    emit(out, "var @1 = 1;", smapper.pushD());
   1.906 +                    smapper.assign(this, VarType.DOUBLE, "1");
   1.907                      break;
   1.908                  case opc_iconst_2:
   1.909 -                    emit(out, "var @1 = 2;", smapper.pushI());
   1.910 +                    smapper.assign(this, VarType.INTEGER, "2");
   1.911                      break;
   1.912                  case opc_fconst_2:
   1.913 -                    emit(out, "var @1 = 2;", smapper.pushF());
   1.914 +                    smapper.assign(this, VarType.FLOAT, "2");
   1.915                      break;
   1.916                  case opc_iconst_3:
   1.917 -                    emit(out, "var @1 = 3;", smapper.pushI());
   1.918 +                    smapper.assign(this, VarType.INTEGER, "3");
   1.919                      break;
   1.920                  case opc_iconst_4:
   1.921 -                    emit(out, "var @1 = 4;", smapper.pushI());
   1.922 +                    smapper.assign(this, VarType.INTEGER, "4");
   1.923                      break;
   1.924                  case opc_iconst_5:
   1.925 -                    emit(out, "var @1 = 5;", smapper.pushI());
   1.926 +                    smapper.assign(this, VarType.INTEGER, "5");
   1.927                      break;
   1.928                  case opc_ldc: {
   1.929                      int indx = readUByte(byteCodes, ++i);
   1.930                      String v = encodeConstant(indx);
   1.931                      int type = VarType.fromConstantType(jc.getTag(indx));
   1.932 -                    emit(out, "var @1 = @2;", smapper.pushT(type), v);
   1.933 +                    smapper.assign(this, type, v);
   1.934                      break;
   1.935                  }
   1.936                  case opc_ldc_w:
   1.937 @@ -837,118 +895,122 @@
   1.938                          final Long lv = new Long(v);
   1.939                          final int low = (int)(lv.longValue() & 0xFFFFFFFF);
   1.940                          final int hi = (int)(lv.longValue() >> 32);
   1.941 -                        emit(out, "var @1 = 0x@3.next32(0x@2);", smapper.pushL(), 
   1.942 -                                Integer.toHexString(low), Integer.toHexString(hi));
   1.943 +                        if (hi == 0) {
   1.944 +                            smapper.assign(this, VarType.LONG, "0x" + Integer.toHexString(low));
   1.945 +                        } else {
   1.946 +                            smapper.assign(this, VarType.LONG,
   1.947 +                                "0x" + Integer.toHexString(hi) + ".next32(0x" + 
   1.948 +                                    Integer.toHexString(low) + ")"
   1.949 +                            );
   1.950 +                        }
   1.951                      } else {
   1.952 -                        emit(out, "var @1 = @2;", smapper.pushT(type), v);
   1.953 +                        smapper.assign(this, type, v);
   1.954                      }
   1.955                      break;
   1.956                  }
   1.957                  case opc_lcmp:
   1.958 -                    emit(out, "var @3 = @2.compare64(@1);",
   1.959 -                         smapper.popL(), smapper.popL(), smapper.pushI());
   1.960 +                    smapper.replace(this, VarType.INTEGER, "(@2).compare64(@1)", smapper.popL(), smapper.getL(0));
   1.961                      break;
   1.962                  case opc_fcmpl:
   1.963                  case opc_fcmpg:
   1.964 -                    emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
   1.965 -                         smapper.popF(), smapper.popF(), smapper.pushI());
   1.966 +                    smapper.replace(this, VarType.INTEGER, "(@2).compare(@1)", smapper.popF(), smapper.getF(0));
   1.967                      break;
   1.968                  case opc_dcmpl:
   1.969                  case opc_dcmpg:
   1.970 -                    emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
   1.971 -                         smapper.popD(), smapper.popD(), smapper.pushI());
   1.972 +                    smapper.replace(this, VarType.INTEGER, "(@2).compare(@1)", smapper.popD(), smapper.getD(0));
   1.973                      break;
   1.974                  case opc_if_acmpeq:
   1.975 -                    i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
   1.976 +                    i = generateIf(smapper, byteCodes, i, smapper.popA(), smapper.popA(),
   1.977                                     "===", topMostLabel);
   1.978                      break;
   1.979                  case opc_if_acmpne:
   1.980 -                    i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
   1.981 +                    i = generateIf(smapper, byteCodes, i, smapper.popA(), smapper.popA(),
   1.982                                     "!==", topMostLabel);
   1.983                      break;
   1.984                  case opc_if_icmpeq:
   1.985 -                    i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
   1.986 +                    i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
   1.987                                     "==", topMostLabel);
   1.988                      break;
   1.989                  case opc_ifeq: {
   1.990                      int indx = i + readShortArg(byteCodes, i);
   1.991 -                    emitIf(out, "if (@1 == 0) ",
   1.992 +                    emitIf(smapper, this, "if ((@1) == 0) ",
   1.993                           smapper.popI(), i, indx, topMostLabel);
   1.994                      i += 2;
   1.995                      break;
   1.996                  }
   1.997                  case opc_ifne: {
   1.998                      int indx = i + readShortArg(byteCodes, i);
   1.999 -                    emitIf(out, "if (@1 != 0) ",
  1.1000 +                    emitIf(smapper, this, "if ((@1) != 0) ",
  1.1001                           smapper.popI(), i, indx, topMostLabel);
  1.1002                      i += 2;
  1.1003                      break;
  1.1004                  }
  1.1005                  case opc_iflt: {
  1.1006                      int indx = i + readShortArg(byteCodes, i);
  1.1007 -                    emitIf(out, "if (@1 < 0) ",
  1.1008 +                    emitIf(smapper, this, "if ((@1) < 0) ",
  1.1009                           smapper.popI(), i, indx, topMostLabel);
  1.1010                      i += 2;
  1.1011                      break;
  1.1012                  }
  1.1013                  case opc_ifle: {
  1.1014                      int indx = i + readShortArg(byteCodes, i);
  1.1015 -                    emitIf(out, "if (@1 <= 0) ",
  1.1016 +                    emitIf(smapper, this, "if ((@1) <= 0) ",
  1.1017                           smapper.popI(), i, indx, topMostLabel);
  1.1018                      i += 2;
  1.1019                      break;
  1.1020                  }
  1.1021                  case opc_ifgt: {
  1.1022                      int indx = i + readShortArg(byteCodes, i);
  1.1023 -                    emitIf(out, "if (@1 > 0) ",
  1.1024 +                    emitIf(smapper, this, "if ((@1) > 0) ",
  1.1025                           smapper.popI(), i, indx, topMostLabel);
  1.1026                      i += 2;
  1.1027                      break;
  1.1028                  }
  1.1029                  case opc_ifge: {
  1.1030                      int indx = i + readShortArg(byteCodes, i);
  1.1031 -                    emitIf(out, "if (@1 >= 0) ",
  1.1032 +                    emitIf(smapper, this, "if ((@1) >= 0) ",
  1.1033                           smapper.popI(), i, indx, topMostLabel);
  1.1034                      i += 2;
  1.1035                      break;
  1.1036                  }
  1.1037                  case opc_ifnonnull: {
  1.1038                      int indx = i + readShortArg(byteCodes, i);
  1.1039 -                    emitIf(out, "if (@1 !== null) ",
  1.1040 +                    emitIf(smapper, this, "if ((@1) !== null) ",
  1.1041                           smapper.popA(), i, indx, topMostLabel);
  1.1042                      i += 2;
  1.1043                      break;
  1.1044                  }
  1.1045                  case opc_ifnull: {
  1.1046                      int indx = i + readShortArg(byteCodes, i);
  1.1047 -                    emitIf(out, "if (@1 === null) ",
  1.1048 +                    emitIf(smapper, this, "if ((@1) === null) ",
  1.1049                           smapper.popA(), i, indx, topMostLabel);
  1.1050                      i += 2;
  1.1051                      break;
  1.1052                  }
  1.1053                  case opc_if_icmpne:
  1.1054 -                    i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
  1.1055 +                    i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
  1.1056                                     "!=", topMostLabel);
  1.1057                      break;
  1.1058                  case opc_if_icmplt:
  1.1059 -                    i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
  1.1060 +                    i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
  1.1061                                     "<", topMostLabel);
  1.1062                      break;
  1.1063                  case opc_if_icmple:
  1.1064 -                    i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
  1.1065 +                    i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
  1.1066                                     "<=", topMostLabel);
  1.1067                      break;
  1.1068                  case opc_if_icmpgt:
  1.1069 -                    i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
  1.1070 +                    i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
  1.1071                                     ">", topMostLabel);
  1.1072                      break;
  1.1073                  case opc_if_icmpge:
  1.1074 -                    i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
  1.1075 +                    i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
  1.1076                                     ">=", topMostLabel);
  1.1077                      break;
  1.1078                  case opc_goto: {
  1.1079 +                    smapper.flush(this);
  1.1080                      int indx = i + readShortArg(byteCodes, i);
  1.1081 -                    goTo(out, i, indx, topMostLabel);
  1.1082 +                    goTo(this, i, indx, topMostLabel);
  1.1083                      i += 2;
  1.1084                      break;
  1.1085                  }
  1.1086 @@ -976,8 +1038,8 @@
  1.1087                  case opc_new: {
  1.1088                      int indx = readUShortArg(byteCodes, i);
  1.1089                      String ci = jc.getClassName(indx);
  1.1090 -                    emit(out, "var @1 = new @2;",
  1.1091 -                         smapper.pushA(), accessClass(ci.replace('/', '_')));
  1.1092 +                    emit(smapper, this, "var @1 = new @2;",
  1.1093 +                         smapper.pushA(), accessClass(mangleClassName(ci)));
  1.1094                      addReference(ci);
  1.1095                      i += 2;
  1.1096                      break;
  1.1097 @@ -999,54 +1061,53 @@
  1.1098                      break;
  1.1099                  }
  1.1100                  case opc_arraylength:
  1.1101 -                    emit(out, "var @2 = @1.length;",
  1.1102 -                         smapper.popA(), smapper.pushI());
  1.1103 +                    smapper.replace(this, VarType.INTEGER, "(@1).length", smapper.getA(0));
  1.1104                      break;
  1.1105                  case opc_lastore:
  1.1106 -                    emit(out, "Array.at(@3, @2, @1);",
  1.1107 +                    emit(smapper, this, "Array.at(@3, @2, @1);",
  1.1108                           smapper.popL(), smapper.popI(), smapper.popA());
  1.1109                      break;
  1.1110                  case opc_fastore:
  1.1111 -                    emit(out, "Array.at(@3, @2, @1);",
  1.1112 +                    emit(smapper, this, "Array.at(@3, @2, @1);",
  1.1113                           smapper.popF(), smapper.popI(), smapper.popA());
  1.1114                      break;
  1.1115                  case opc_dastore:
  1.1116 -                    emit(out, "Array.at(@3, @2, @1);",
  1.1117 +                    emit(smapper, this, "Array.at(@3, @2, @1);",
  1.1118                           smapper.popD(), smapper.popI(), smapper.popA());
  1.1119                      break;
  1.1120                  case opc_aastore:
  1.1121 -                    emit(out, "Array.at(@3, @2, @1);",
  1.1122 +                    emit(smapper, this, "Array.at(@3, @2, @1);",
  1.1123                           smapper.popA(), smapper.popI(), smapper.popA());
  1.1124                      break;
  1.1125                  case opc_iastore:
  1.1126                  case opc_bastore:
  1.1127                  case opc_castore:
  1.1128                  case opc_sastore:
  1.1129 -                    emit(out, "Array.at(@3, @2, @1);",
  1.1130 +                    emit(smapper, this, "Array.at(@3, @2, @1);",
  1.1131                           smapper.popI(), smapper.popI(), smapper.popA());
  1.1132                      break;
  1.1133                  case opc_laload:
  1.1134 -                    emit(out, "var @3 = Array.at(@2, @1);",
  1.1135 -                         smapper.popI(), smapper.popA(), smapper.pushL());
  1.1136 +                    smapper.replace(this, VarType.LONG, "Array.at(@2, @1)",
  1.1137 +                         smapper.popI(), smapper.getA(0));
  1.1138                      break;
  1.1139                  case opc_faload:
  1.1140 -                    emit(out, "var @3 = Array.at(@2, @1);",
  1.1141 -                         smapper.popI(), smapper.popA(), smapper.pushF());
  1.1142 +                    smapper.replace(this, VarType.FLOAT, "Array.at(@2, @1)",
  1.1143 +                         smapper.popI(), smapper.getA(0));
  1.1144                      break;
  1.1145                  case opc_daload:
  1.1146 -                    emit(out, "var @3 = Array.at(@2, @1);",
  1.1147 -                         smapper.popI(), smapper.popA(), smapper.pushD());
  1.1148 +                    smapper.replace(this, VarType.DOUBLE, "Array.at(@2, @1)",
  1.1149 +                         smapper.popI(), smapper.getA(0));
  1.1150                      break;
  1.1151                  case opc_aaload:
  1.1152 -                    emit(out, "var @3 = Array.at(@2, @1);",
  1.1153 -                         smapper.popI(), smapper.popA(), smapper.pushA());
  1.1154 +                    smapper.replace(this, VarType.REFERENCE, "Array.at(@2, @1)",
  1.1155 +                         smapper.popI(), smapper.getA(0));
  1.1156                      break;
  1.1157                  case opc_iaload:
  1.1158                  case opc_baload:
  1.1159                  case opc_caload:
  1.1160                  case opc_saload:
  1.1161 -                    emit(out, "var @3 = Array.at(@2, @1);",
  1.1162 -                         smapper.popI(), smapper.popA(), smapper.pushI());
  1.1163 +                    smapper.replace(this, VarType.INTEGER, "Array.at(@2, @1)",
  1.1164 +                         smapper.popI(), smapper.getA(0));
  1.1165                      break;
  1.1166                  case opc_pop:
  1.1167                  case opc_pop2:
  1.1168 @@ -1055,86 +1116,86 @@
  1.1169                      break;
  1.1170                  case opc_dup: {
  1.1171                      final Variable v = smapper.get(0);
  1.1172 -                    emit(out, "var @1 = @2;", smapper.pushT(v.getType()), v);
  1.1173 +                    emit(smapper, this, "var @1 = @2;", smapper.pushT(v.getType()), v);
  1.1174                      break;
  1.1175                  }
  1.1176                  case opc_dup2: {
  1.1177                      final Variable vi1 = smapper.get(0);
  1.1178  
  1.1179                      if (vi1.isCategory2()) {
  1.1180 -                        emit(out, "var @1 = @2;",
  1.1181 +                        emit(smapper, this, "var @1 = @2;",
  1.1182                               smapper.pushT(vi1.getType()), vi1);
  1.1183                      } else {
  1.1184                          final Variable vi2 = smapper.get(1);
  1.1185 -                        emit(out, "var @1 = @2, @3 = @4;",
  1.1186 +                        emit(smapper, this, "var @1 = @2, @3 = @4;",
  1.1187                               smapper.pushT(vi2.getType()), vi2,
  1.1188                               smapper.pushT(vi1.getType()), vi1);
  1.1189                      }
  1.1190                      break;
  1.1191                  }
  1.1192                  case opc_dup_x1: {
  1.1193 -                    final Variable vi1 = smapper.pop();
  1.1194 -                    final Variable vi2 = smapper.pop();
  1.1195 +                    final Variable vi1 = smapper.pop(this);
  1.1196 +                    final Variable vi2 = smapper.pop(this);
  1.1197                      final Variable vo3 = smapper.pushT(vi1.getType());
  1.1198                      final Variable vo2 = smapper.pushT(vi2.getType());
  1.1199                      final Variable vo1 = smapper.pushT(vi1.getType());
  1.1200  
  1.1201 -                    emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
  1.1202 +                    emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;",
  1.1203                           vo1, vi1, vo2, vi2, vo3, vo1);
  1.1204                      break;
  1.1205                  }
  1.1206                  case opc_dup2_x1: {
  1.1207 -                    final Variable vi1 = smapper.pop();
  1.1208 -                    final Variable vi2 = smapper.pop();
  1.1209 +                    final Variable vi1 = smapper.pop(this);
  1.1210 +                    final Variable vi2 = smapper.pop(this);
  1.1211  
  1.1212                      if (vi1.isCategory2()) {
  1.1213                          final Variable vo3 = smapper.pushT(vi1.getType());
  1.1214                          final Variable vo2 = smapper.pushT(vi2.getType());
  1.1215                          final Variable vo1 = smapper.pushT(vi1.getType());
  1.1216  
  1.1217 -                        emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
  1.1218 +                        emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;",
  1.1219                               vo1, vi1, vo2, vi2, vo3, vo1);
  1.1220                      } else {
  1.1221 -                        final Variable vi3 = smapper.pop();
  1.1222 +                        final Variable vi3 = smapper.pop(this);
  1.1223                          final Variable vo5 = smapper.pushT(vi2.getType());
  1.1224                          final Variable vo4 = smapper.pushT(vi1.getType());
  1.1225                          final Variable vo3 = smapper.pushT(vi3.getType());
  1.1226                          final Variable vo2 = smapper.pushT(vi2.getType());
  1.1227                          final Variable vo1 = smapper.pushT(vi1.getType());
  1.1228  
  1.1229 -                        emit(out, "var @1 = @2, @3 = @4, @5 = @6,",
  1.1230 +                        emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6,",
  1.1231                               vo1, vi1, vo2, vi2, vo3, vi3);
  1.1232 -                        emit(out, " @1 = @2, @3 = @4;",
  1.1233 +                        emit(smapper, this, " @1 = @2, @3 = @4;",
  1.1234                               vo4, vo1, vo5, vo2);
  1.1235                      }
  1.1236                      break;
  1.1237                  }
  1.1238                  case opc_dup_x2: {
  1.1239 -                    final Variable vi1 = smapper.pop();
  1.1240 -                    final Variable vi2 = smapper.pop();
  1.1241 +                    final Variable vi1 = smapper.pop(this);
  1.1242 +                    final Variable vi2 = smapper.pop(this);
  1.1243  
  1.1244                      if (vi2.isCategory2()) {
  1.1245                          final Variable vo3 = smapper.pushT(vi1.getType());
  1.1246                          final Variable vo2 = smapper.pushT(vi2.getType());
  1.1247                          final Variable vo1 = smapper.pushT(vi1.getType());
  1.1248  
  1.1249 -                        emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
  1.1250 +                        emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;",
  1.1251                               vo1, vi1, vo2, vi2, vo3, vo1);
  1.1252                      } else {
  1.1253 -                        final Variable vi3 = smapper.pop();
  1.1254 +                        final Variable vi3 = smapper.pop(this);
  1.1255                          final Variable vo4 = smapper.pushT(vi1.getType());
  1.1256                          final Variable vo3 = smapper.pushT(vi3.getType());
  1.1257                          final Variable vo2 = smapper.pushT(vi2.getType());
  1.1258                          final Variable vo1 = smapper.pushT(vi1.getType());
  1.1259  
  1.1260 -                        emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;",
  1.1261 +                        emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;",
  1.1262                               vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1);
  1.1263                      }
  1.1264                      break;
  1.1265                  }
  1.1266                  case opc_dup2_x2: {
  1.1267 -                    final Variable vi1 = smapper.pop();
  1.1268 -                    final Variable vi2 = smapper.pop();
  1.1269 +                    final Variable vi1 = smapper.pop(this);
  1.1270 +                    final Variable vi2 = smapper.pop(this);
  1.1271  
  1.1272                      if (vi1.isCategory2()) {
  1.1273                          if (vi2.isCategory2()) {
  1.1274 @@ -1142,20 +1203,20 @@
  1.1275                              final Variable vo2 = smapper.pushT(vi2.getType());
  1.1276                              final Variable vo1 = smapper.pushT(vi1.getType());
  1.1277  
  1.1278 -                            emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
  1.1279 +                            emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;",
  1.1280                                   vo1, vi1, vo2, vi2, vo3, vo1);
  1.1281                          } else {
  1.1282 -                            final Variable vi3 = smapper.pop();
  1.1283 +                            final Variable vi3 = smapper.pop(this);
  1.1284                              final Variable vo4 = smapper.pushT(vi1.getType());
  1.1285                              final Variable vo3 = smapper.pushT(vi3.getType());
  1.1286                              final Variable vo2 = smapper.pushT(vi2.getType());
  1.1287                              final Variable vo1 = smapper.pushT(vi1.getType());
  1.1288  
  1.1289 -                            emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;",
  1.1290 +                            emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;",
  1.1291                                   vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1);
  1.1292                          }
  1.1293                      } else {
  1.1294 -                        final Variable vi3 = smapper.pop();
  1.1295 +                        final Variable vi3 = smapper.pop(this);
  1.1296  
  1.1297                          if (vi3.isCategory2()) {
  1.1298                              final Variable vo5 = smapper.pushT(vi2.getType());
  1.1299 @@ -1164,12 +1225,12 @@
  1.1300                              final Variable vo2 = smapper.pushT(vi2.getType());
  1.1301                              final Variable vo1 = smapper.pushT(vi1.getType());
  1.1302  
  1.1303 -                            emit(out, "var @1 = @2, @3 = @4, @5 = @6,",
  1.1304 +                            emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6,",
  1.1305                                   vo1, vi1, vo2, vi2, vo3, vi3);
  1.1306 -                            emit(out, " @1 = @2, @3 = @4;",
  1.1307 +                            emit(smapper, this, " @1 = @2, @3 = @4;",
  1.1308                                   vo4, vo1, vo5, vo2);
  1.1309                          } else {
  1.1310 -                            final Variable vi4 = smapper.pop();
  1.1311 +                            final Variable vi4 = smapper.pop(this);
  1.1312                              final Variable vo6 = smapper.pushT(vi2.getType());
  1.1313                              final Variable vo5 = smapper.pushT(vi1.getType());
  1.1314                              final Variable vo4 = smapper.pushT(vi4.getType());
  1.1315 @@ -1177,9 +1238,9 @@
  1.1316                              final Variable vo2 = smapper.pushT(vi2.getType());
  1.1317                              final Variable vo1 = smapper.pushT(vi1.getType());
  1.1318                              
  1.1319 -                            emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8,",
  1.1320 +                            emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8,",
  1.1321                                   vo1, vi1, vo2, vi2, vo3, vi3, vo4, vi4);
  1.1322 -                            emit(out, " @1 = @2, @3 = @4;",
  1.1323 +                            emit(smapper, this, " @1 = @2, @3 = @4;",
  1.1324                                   vo5, vo1, vo6, vo2);
  1.1325                          }
  1.1326                      }
  1.1327 @@ -1192,7 +1253,7 @@
  1.1328                      if (vi1.getType() == vi2.getType()) {
  1.1329                          final Variable tmp = smapper.pushT(vi1.getType());
  1.1330  
  1.1331 -                        emit(out, "var @1 = @2, @2 = @3, @3 = @1;",
  1.1332 +                        emit(smapper, this, "var @1 = @2, @2 = @3, @3 = @1;",
  1.1333                               tmp, vi1, vi2);
  1.1334                          smapper.pop(1);
  1.1335                      } else {
  1.1336 @@ -1203,26 +1264,26 @@
  1.1337                      break;
  1.1338                  }
  1.1339                  case opc_bipush:
  1.1340 -                    emit(out, "var @1 = @2;",
  1.1341 -                         smapper.pushI(), Integer.toString(byteCodes[++i]));
  1.1342 +                    smapper.assign(this, VarType.INTEGER, 
  1.1343 +                        "(" + Integer.toString(byteCodes[++i]) + ")");
  1.1344                      break;
  1.1345                  case opc_sipush:
  1.1346 -                    emit(out, "var @1 = @2;",
  1.1347 -                         smapper.pushI(),
  1.1348 -                         Integer.toString(readShortArg(byteCodes, i)));
  1.1349 +                    smapper.assign(this, VarType.INTEGER, 
  1.1350 +                        "(" + Integer.toString(readShortArg(byteCodes, i)) + ")"
  1.1351 +                    );
  1.1352                      i += 2;
  1.1353                      break;
  1.1354                  case opc_getfield: {
  1.1355                      int indx = readUShortArg(byteCodes, i);
  1.1356                      String[] fi = jc.getFieldInfoName(indx);
  1.1357                      final int type = VarType.fromFieldType(fi[2].charAt(0));
  1.1358 -                    final String mangleClass = mangleSig(fi[0]);
  1.1359 +                    final String mangleClass = mangleClassName(fi[0]);
  1.1360                      final String mangleClassAccess = accessClass(mangleClass);
  1.1361 -                    emit(out, "var @2 = @3.call(@1);",
  1.1362 -                         smapper.popA(),
  1.1363 -                         smapper.pushT(type),
  1.1364 +                    smapper.replace(this, type, "@2.call(@1)",
  1.1365 +                         smapper.getA(0),
  1.1366                           accessField(mangleClassAccess + "(false)",
  1.1367 -                                     "_" + fi[1], fi));
  1.1368 +                                     "_" + fi[1], fi)
  1.1369 +                    );
  1.1370                      i += 2;
  1.1371                      break;
  1.1372                  }
  1.1373 @@ -1230,9 +1291,9 @@
  1.1374                      int indx = readUShortArg(byteCodes, i);
  1.1375                      String[] fi = jc.getFieldInfoName(indx);
  1.1376                      final int type = VarType.fromFieldType(fi[2].charAt(0));
  1.1377 -                    final String mangleClass = mangleSig(fi[0]);
  1.1378 +                    final String mangleClass = mangleClassName(fi[0]);
  1.1379                      final String mangleClassAccess = accessClass(mangleClass);
  1.1380 -                    emit(out, "@3.call(@2, @1);",
  1.1381 +                    emit(smapper, this, "@3.call(@2, @1);",
  1.1382                           smapper.popT(type),
  1.1383                           smapper.popA(),
  1.1384                           accessField(mangleClassAccess + "(false)",
  1.1385 @@ -1244,11 +1305,8 @@
  1.1386                      int indx = readUShortArg(byteCodes, i);
  1.1387                      String[] fi = jc.getFieldInfoName(indx);
  1.1388                      final int type = VarType.fromFieldType(fi[2].charAt(0));
  1.1389 -                    emit(out, "var @1 = @2();",
  1.1390 -                         smapper.pushT(type),
  1.1391 -                         accessField(accessClass(fi[0].replace('/', '_'))
  1.1392 -                                         + "(false)",
  1.1393 -                                     "_" + fi[1], fi));
  1.1394 +                    String ac = accessClass(mangleClassName(fi[0]));
  1.1395 +                    smapper.assign(this, type, ac + "(false)._" + fi[1] + "()");
  1.1396                      i += 2;
  1.1397                      addReference(fi[0]);
  1.1398                      break;
  1.1399 @@ -1257,10 +1315,8 @@
  1.1400                      int indx = readUShortArg(byteCodes, i);
  1.1401                      String[] fi = jc.getFieldInfoName(indx);
  1.1402                      final int type = VarType.fromFieldType(fi[2].charAt(0));
  1.1403 -                    emit(out, "@1(@2);",
  1.1404 -                         accessField(accessClass(fi[0].replace('/', '_'))
  1.1405 -                                         + "(false)",
  1.1406 -                                     "_" + fi[1], fi),
  1.1407 +                    emit(smapper, this, "@1(false)._@2(@3);",
  1.1408 +                         accessClass(mangleClassName(fi[0])), fi[1],
  1.1409                           smapper.popT(type));
  1.1410                      i += 2;
  1.1411                      addReference(fi[0]);
  1.1412 @@ -1279,22 +1335,22 @@
  1.1413                      break;
  1.1414                  }
  1.1415                  case opc_athrow: {
  1.1416 -                    final Variable v = smapper.popA();
  1.1417 +                    final CharSequence v = smapper.popA();
  1.1418                      smapper.clear();
  1.1419  
  1.1420 -                    emit(out, "{ var @1 = @2; throw @2; }",
  1.1421 +                    emit(smapper, this, "{ var @1 = @2; throw @2; }",
  1.1422                           smapper.pushA(), v);
  1.1423                      break;
  1.1424                  }
  1.1425  
  1.1426                  case opc_monitorenter: {
  1.1427 -                    out.append("/* monitor enter */");
  1.1428 +                    debug("/* monitor enter */");
  1.1429                      smapper.popA();
  1.1430                      break;
  1.1431                  }
  1.1432  
  1.1433                  case opc_monitorexit: {
  1.1434 -                    out.append("/* monitor exit */");
  1.1435 +                    debug("/* monitor exit */");
  1.1436                      smapper.popA();
  1.1437                      break;
  1.1438                  }
  1.1439 @@ -1305,31 +1361,39 @@
  1.1440  
  1.1441                  default: {
  1.1442                      wide = false;
  1.1443 -                    emit(out, "throw 'unknown bytecode @1';",
  1.1444 +                    emit(smapper, this, "throw 'unknown bytecode @1';",
  1.1445                           Integer.toString(c));
  1.1446                  }
  1.1447              }
  1.1448              if (debug(" //")) {
  1.1449                  generateByteCodeComment(prev, i, byteCodes);
  1.1450              }
  1.1451 -            out.append("\n");            
  1.1452 +            if (outChanged) {
  1.1453 +                append("\n");
  1.1454 +            }
  1.1455          }
  1.1456          if (previousTrap != null) {
  1.1457              generateCatch(previousTrap, byteCodes.length, topMostLabel);
  1.1458          }
  1.1459 -        out.append("\n    }\n");
  1.1460 +        if (didBranches) {
  1.1461 +            append("\n    }\n");
  1.1462 +        }
  1.1463          while (openBraces-- > 0) {
  1.1464 -            out.append('}');
  1.1465 +            append('}');
  1.1466          }
  1.1467 -        out.append("\n};");
  1.1468 +        append("\n};");
  1.1469      }
  1.1470  
  1.1471 -    private int generateIf(byte[] byteCodes, int i, final Variable v2, final Variable v1, final String test, int topMostLabel) throws IOException {
  1.1472 +    private int generateIf(StackMapper mapper, byte[] byteCodes, 
  1.1473 +        int i, final CharSequence v2, final CharSequence v1, 
  1.1474 +        final String test, int topMostLabel
  1.1475 +    ) throws IOException {
  1.1476 +        mapper.flush(this);
  1.1477          int indx = i + readShortArg(byteCodes, i);
  1.1478 -        out.append("if (").append(v1)
  1.1479 -           .append(' ').append(test).append(' ')
  1.1480 -           .append(v2).append(") ");
  1.1481 -        goTo(out, i, indx, topMostLabel);
  1.1482 +        append("if ((").append(v1)
  1.1483 +           .append(") ").append(test).append(" (")
  1.1484 +           .append(v2).append(")) ");
  1.1485 +        goTo(this, i, indx, topMostLabel);
  1.1486          return i + 2;
  1.1487      }
  1.1488      
  1.1489 @@ -1442,8 +1506,20 @@
  1.1490          return mangleSig(sig, 0, sig.length());
  1.1491      }
  1.1492      
  1.1493 +    private static String mangleMethodName(String name) {
  1.1494 +        StringBuilder sb = new StringBuilder(name.length() * 2);
  1.1495 +        int last = name.length();
  1.1496 +        for (int i = 0; i < last; i++) {
  1.1497 +            final char ch = name.charAt(i);
  1.1498 +            switch (ch) {
  1.1499 +                case '_': sb.append("_1"); break;
  1.1500 +                default: sb.append(ch); break;
  1.1501 +            }
  1.1502 +        }
  1.1503 +        return sb.toString();
  1.1504 +    }
  1.1505      private static String mangleSig(String txt, int first, int last) {
  1.1506 -        StringBuilder sb = new StringBuilder();
  1.1507 +        StringBuilder sb = new StringBuilder((last - first) * 2);
  1.1508          for (int i = first; i < last; i++) {
  1.1509              final char ch = txt.charAt(i);
  1.1510              switch (ch) {
  1.1511 @@ -1456,6 +1532,10 @@
  1.1512          }
  1.1513          return sb.toString();
  1.1514      }
  1.1515 +    
  1.1516 +    private static String mangleClassName(String name) {
  1.1517 +        return mangleSig(name);
  1.1518 +    }
  1.1519  
  1.1520      private static String findMethodName(MethodData m, StringBuilder cnt) {
  1.1521          StringBuilder name = new StringBuilder();
  1.1522 @@ -1464,7 +1544,7 @@
  1.1523          } else if ("<clinit>".equals(m.getName())) { // NOI18N
  1.1524              name.append("class"); // NOI18N
  1.1525          } else {
  1.1526 -            name.append(m.getName());
  1.1527 +            name.append(mangleMethodName(m.getName()));
  1.1528          } 
  1.1529          
  1.1530          countArgs(m.getInternalSig(), new char[1], name, cnt);
  1.1531 @@ -1478,7 +1558,7 @@
  1.1532          if ("<init>".equals(nm)) { // NOI18N
  1.1533              name.append("cons"); // NOI18N
  1.1534          } else {
  1.1535 -            name.append(nm);
  1.1536 +            name.append(mangleMethodName(nm));
  1.1537          }
  1.1538          countArgs(descr, returnType, name, cnt);
  1.1539          return name.toString();
  1.1540 @@ -1493,14 +1573,14 @@
  1.1541          String mn = findMethodName(mi, cnt, returnType);
  1.1542  
  1.1543          final int numArguments = isStatic ? cnt.length() : cnt.length() + 1;
  1.1544 -        final Variable[] vars = new Variable[numArguments];
  1.1545 +        final CharSequence[] vars = new CharSequence[numArguments];
  1.1546  
  1.1547          for (int j = numArguments - 1; j >= 0; --j) {
  1.1548 -            vars[j] = mapper.pop();
  1.1549 +            vars[j] = mapper.popValue();
  1.1550          }
  1.1551  
  1.1552          if (returnType[0] != 'V') {
  1.1553 -            out.append("var ")
  1.1554 +            append("var ")
  1.1555                 .append(mapper.pushT(VarType.fromFieldType(returnType[0])))
  1.1556                 .append(" = ");
  1.1557          }
  1.1558 @@ -1510,20 +1590,20 @@
  1.1559          if (mn.startsWith("cons_")) {
  1.1560              object += ".constructor";
  1.1561          }
  1.1562 -        out.append(accessStaticMethod(object, mn, mi));
  1.1563 +        append(accessStaticMethod(object, mn, mi));
  1.1564          if (isStatic) {
  1.1565 -            out.append('(');
  1.1566 +            append('(');
  1.1567          } else {
  1.1568 -            out.append(".call(");
  1.1569 +            append(".call(");
  1.1570          }
  1.1571          if (numArguments > 0) {
  1.1572 -            out.append(vars[0]);
  1.1573 +            append(vars[0]);
  1.1574              for (int j = 1; j < numArguments; ++j) {
  1.1575 -                out.append(", ");
  1.1576 -                out.append(vars[j]);
  1.1577 +                append(", ");
  1.1578 +                append(vars[j]);
  1.1579              }
  1.1580          }
  1.1581 -        out.append(");");
  1.1582 +        append(");");
  1.1583          i += 2;
  1.1584          addReference(in);
  1.1585          return i;
  1.1586 @@ -1537,27 +1617,27 @@
  1.1587          String mn = findMethodName(mi, cnt, returnType);
  1.1588  
  1.1589          final int numArguments = cnt.length() + 1;
  1.1590 -        final Variable[] vars = new Variable[numArguments];
  1.1591 +        final CharSequence[] vars = new CharSequence[numArguments];
  1.1592  
  1.1593          for (int j = numArguments - 1; j >= 0; --j) {
  1.1594 -            vars[j] = mapper.pop();
  1.1595 +            vars[j] = mapper.popValue();
  1.1596          }
  1.1597  
  1.1598          if (returnType[0] != 'V') {
  1.1599 -            out.append("var ")
  1.1600 +            append("var ")
  1.1601                 .append(mapper.pushT(VarType.fromFieldType(returnType[0])))
  1.1602                 .append(" = ");
  1.1603          }
  1.1604  
  1.1605 -        out.append(accessVirtualMethod(vars[0].toString(), mn, mi));
  1.1606 -        out.append('(');
  1.1607 +        append(accessVirtualMethod(vars[0].toString(), mn, mi));
  1.1608 +        append('(');
  1.1609          String sep = "";
  1.1610          for (int j = 1; j < numArguments; ++j) {
  1.1611 -            out.append(sep);
  1.1612 -            out.append(vars[j]);
  1.1613 +            append(sep);
  1.1614 +            append(vars[j]);
  1.1615              sep = ", ";
  1.1616          }
  1.1617 -        out.append(");");
  1.1618 +        append(");");
  1.1619          i += 2;
  1.1620          return i;
  1.1621      }
  1.1622 @@ -1587,10 +1667,10 @@
  1.1623          String s = jc.stringValue(entryIndex, classRef);
  1.1624          if (classRef[0] != null) {
  1.1625              if (classRef[0].startsWith("[")) {
  1.1626 -                s = accessClass("java_lang_Class") + "(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('" + classRef[0] + "');";
  1.1627 +                s = accessClass("java_lang_Class") + "(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('" + classRef[0] + "')";
  1.1628              } else {
  1.1629                  addReference(classRef[0]);
  1.1630 -                s = accessClass(s.replace('/', '_')) + "(false).constructor.$class";
  1.1631 +                s = accessClass(mangleClassName(s)) + "(false).constructor.$class";
  1.1632              }
  1.1633          }
  1.1634          return s;
  1.1635 @@ -1602,6 +1682,7 @@
  1.1636              return null;
  1.1637          }
  1.1638          final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;";
  1.1639 +        final String htmlType = "Lnet/java/html/js/JavaScriptBody;";
  1.1640          class P extends AnnotationParser {
  1.1641              public P() {
  1.1642                  super(false, true);
  1.1643 @@ -1610,6 +1691,8 @@
  1.1644              int cnt;
  1.1645              String[] args = new String[30];
  1.1646              String body;
  1.1647 +            boolean javacall;
  1.1648 +            boolean html4j;
  1.1649              
  1.1650              @Override
  1.1651              protected void visitAttr(String type, String attr, String at, String value) {
  1.1652 @@ -1622,6 +1705,18 @@
  1.1653                          throw new IllegalArgumentException(attr);
  1.1654                      }
  1.1655                  }
  1.1656 +                if (type.equals(htmlType)) {
  1.1657 +                    html4j = true;
  1.1658 +                    if ("body".equals(attr)) {
  1.1659 +                        body = value;
  1.1660 +                    } else if ("args".equals(attr)) {
  1.1661 +                        args[cnt++] = value;
  1.1662 +                    } else if ("javacall".equals(attr)) {
  1.1663 +                        javacall = "1".equals(value);
  1.1664 +                    } else {
  1.1665 +                        throw new IllegalArgumentException(attr);
  1.1666 +                    }
  1.1667 +                }
  1.1668              }
  1.1669          }
  1.1670          P p = new P();
  1.1671 @@ -1631,23 +1726,153 @@
  1.1672          }
  1.1673          StringBuilder cnt = new StringBuilder();
  1.1674          final String mn = findMethodName(m, cnt);
  1.1675 -        out.append(destObject).append(".").append(mn);
  1.1676 -        out.append(" = function(");
  1.1677 +        append(destObject).append(".").append(mn);
  1.1678 +        append(" = function(");
  1.1679          String space = "";
  1.1680          int index = 0;
  1.1681 +        StringBuilder toValue = new StringBuilder();
  1.1682          for (int i = 0; i < cnt.length(); i++) {
  1.1683 -            out.append(space);
  1.1684 -            space = outputArg(out, p.args, index);
  1.1685 +            append(space);
  1.1686 +            space = outputArg(this, p.args, index);
  1.1687 +            if (p.html4j && space.length() > 0) {
  1.1688 +                toValue.append("\n  ").append(p.args[index]).append(" = vm.org_apidesign_bck2brwsr_emul_lang_System(false).toJS(").
  1.1689 +                    append(p.args[index]).append(");");
  1.1690 +            }
  1.1691              index++;
  1.1692          }
  1.1693 -        out.append(") {").append("\n");
  1.1694 -        out.append(p.body);
  1.1695 -        out.append("\n}\n");
  1.1696 +        append(") {").append("\n");
  1.1697 +        append(toValue.toString());
  1.1698 +        if (p.javacall) {
  1.1699 +            int lastSlash = jc.getClassName().lastIndexOf('/');
  1.1700 +            final String pkg = jc.getClassName().substring(0, lastSlash);
  1.1701 +            append(mangleCallbacks(pkg, p.body));
  1.1702 +            requireReference(pkg + "/$JsCallbacks$");
  1.1703 +        } else {
  1.1704 +            append(p.body);
  1.1705 +        }
  1.1706 +        append("\n}\n");
  1.1707          return mn;
  1.1708      }
  1.1709 +    
  1.1710 +    private static CharSequence mangleCallbacks(String pkgName, String body) {
  1.1711 +        StringBuilder sb = new StringBuilder();
  1.1712 +        int pos = 0;
  1.1713 +        for (;;) {
  1.1714 +            int next = body.indexOf(".@", pos);
  1.1715 +            if (next == -1) {
  1.1716 +                sb.append(body.substring(pos));
  1.1717 +                body = sb.toString();
  1.1718 +                break;
  1.1719 +            }
  1.1720 +            int ident = next;
  1.1721 +            while (ident > 0) {
  1.1722 +                if (!Character.isJavaIdentifierPart(body.charAt(--ident))) {
  1.1723 +                    ident++;
  1.1724 +                    break;
  1.1725 +                }
  1.1726 +            }
  1.1727 +            String refId = body.substring(ident, next);
  1.1728 +
  1.1729 +            sb.append(body.substring(pos, ident));
  1.1730 +
  1.1731 +            int sigBeg = body.indexOf('(', next);
  1.1732 +            int sigEnd = body.indexOf(')', sigBeg);
  1.1733 +            int colon4 = body.indexOf("::", next);
  1.1734 +            if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
  1.1735 +                throw new IllegalStateException("Malformed body " + body);
  1.1736 +            }
  1.1737 +            String fqn = body.substring(next + 2, colon4);
  1.1738 +            String method = body.substring(colon4 + 2, sigBeg);
  1.1739 +            String params = body.substring(sigBeg, sigEnd + 1);
  1.1740 +
  1.1741 +            int paramBeg = body.indexOf('(', sigEnd + 1);
  1.1742 +            
  1.1743 +            sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM().");
  1.1744 +            sb.append(mangleJsCallbacks(fqn, method, params, false));
  1.1745 +            sb.append("(").append(refId);
  1.1746 +            if (body.charAt(paramBeg + 1) != ')') {
  1.1747 +                sb.append(",");
  1.1748 +            }
  1.1749 +            pos = paramBeg + 1;
  1.1750 +        }
  1.1751 +        sb = null;
  1.1752 +        pos = 0;
  1.1753 +        for (;;) {
  1.1754 +            int next = body.indexOf("@", pos);
  1.1755 +            if (next == -1) {
  1.1756 +                if (sb == null) {
  1.1757 +                    return body;
  1.1758 +                }
  1.1759 +                sb.append(body.substring(pos));
  1.1760 +                return sb;
  1.1761 +            }
  1.1762 +            if (sb == null) {
  1.1763 +                sb = new StringBuilder();
  1.1764 +            }
  1.1765 +
  1.1766 +            sb.append(body.substring(pos, next));
  1.1767 +
  1.1768 +            int sigBeg = body.indexOf('(', next);
  1.1769 +            int sigEnd = body.indexOf(')', sigBeg);
  1.1770 +            int colon4 = body.indexOf("::", next);
  1.1771 +            if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
  1.1772 +                throw new IllegalStateException("Malformed body " + body);
  1.1773 +            }
  1.1774 +            String fqn = body.substring(next + 1, colon4);
  1.1775 +            String method = body.substring(colon4 + 2, sigBeg);
  1.1776 +            String params = body.substring(sigBeg, sigEnd + 1);
  1.1777 +
  1.1778 +            int paramBeg = body.indexOf('(', sigEnd + 1);
  1.1779 +            
  1.1780 +            sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM().");
  1.1781 +            sb.append(mangleJsCallbacks(fqn, method, params, true));
  1.1782 +            sb.append("(");
  1.1783 +            pos = paramBeg + 1;
  1.1784 +        }
  1.1785 +    }
  1.1786 +
  1.1787 +    static String mangleJsCallbacks(String fqn, String method, String params, boolean isStatic) {
  1.1788 +        if (params.startsWith("(")) {
  1.1789 +            params = params.substring(1);
  1.1790 +        }
  1.1791 +        if (params.endsWith(")")) {
  1.1792 +            params = params.substring(0, params.length() - 1);
  1.1793 +        }
  1.1794 +        StringBuilder sb = new StringBuilder();
  1.1795 +        final String fqnu = fqn.replace('.', '_');
  1.1796 +        final String rfqn = mangleClassName(fqnu);
  1.1797 +        final String rm = mangleMethodName(method);
  1.1798 +        final String srp;
  1.1799 +        {
  1.1800 +            StringBuilder pb = new StringBuilder();
  1.1801 +            int len = params.length();
  1.1802 +            int indx = 0;
  1.1803 +            while (indx < len) {
  1.1804 +                char ch = params.charAt(indx);
  1.1805 +                if (ch == '[' || ch == 'L') {
  1.1806 +                    pb.append("Ljava/lang/Object;");
  1.1807 +                    indx = params.indexOf(';', indx) + 1;
  1.1808 +                } else {
  1.1809 +                    pb.append(ch);
  1.1810 +                    indx++;
  1.1811 +                }
  1.1812 +            }
  1.1813 +            srp = mangleSig(pb.toString());
  1.1814 +        }
  1.1815 +        final String rp = mangleSig(params);
  1.1816 +        final String mrp = mangleMethodName(rp);
  1.1817 +        sb.append(rfqn).append("$").append(rm).
  1.1818 +            append('$').append(mrp).append("__Ljava_lang_Object_2");
  1.1819 +        if (!isStatic) {
  1.1820 +            sb.append('L').append(fqnu).append("_2");
  1.1821 +        }
  1.1822 +        sb.append(srp);
  1.1823 +        return sb.toString();
  1.1824 +    }
  1.1825 +
  1.1826      private static String className(ClassData jc) {
  1.1827          //return jc.getName().getInternalName().replace('/', '_');
  1.1828 -        return jc.getClassName().replace('/', '_');
  1.1829 +        return mangleClassName(jc.getClassName());
  1.1830      }
  1.1831      
  1.1832      private static String[] findAnnotation(
  1.1833 @@ -1697,7 +1922,7 @@
  1.1834          return " = null;";
  1.1835      }
  1.1836  
  1.1837 -    private void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException {
  1.1838 +    private void generateAnno(ClassData cd, byte[] data) throws IOException {
  1.1839          AnnotationParser ap = new AnnotationParser(true, false) {
  1.1840              int[] cnt = new int[32];
  1.1841              int depth;
  1.1842 @@ -1708,39 +1933,39 @@
  1.1843                  requireReference(slashType);
  1.1844                  
  1.1845                  if (cnt[depth]++ > 0) {
  1.1846 -                    out.append(",");
  1.1847 +                    append(",");
  1.1848                  }
  1.1849                  if (top) {
  1.1850 -                    out.append('"').append(attrType).append("\" : ");
  1.1851 +                    append('"').append(attrType).append("\" : ");
  1.1852                  }
  1.1853 -                out.append("{\n");
  1.1854 +                append("{\n");
  1.1855                  cnt[++depth] = 0;
  1.1856              }
  1.1857  
  1.1858              @Override
  1.1859              protected void visitAnnotationEnd(String type, boolean top) throws IOException {
  1.1860 -                out.append("\n}\n");
  1.1861 +                append("\n}\n");
  1.1862                  depth--;
  1.1863              }
  1.1864  
  1.1865              @Override
  1.1866              protected void visitValueStart(String attrName, char type) throws IOException {
  1.1867                  if (cnt[depth]++ > 0) {
  1.1868 -                    out.append(",\n");
  1.1869 +                    append(",\n");
  1.1870                  }
  1.1871                  cnt[++depth] = 0;
  1.1872                  if (attrName != null) {
  1.1873 -                    out.append(attrName).append(" : ");
  1.1874 +                    append(attrName).append(" : ");
  1.1875                  }
  1.1876                  if (type == '[') {
  1.1877 -                    out.append("[");
  1.1878 +                    append("[");
  1.1879                  }
  1.1880              }
  1.1881  
  1.1882              @Override
  1.1883              protected void visitValueEnd(String attrName, char type) throws IOException {
  1.1884                  if (type == '[') {
  1.1885 -                    out.append("]");
  1.1886 +                    append("]");
  1.1887                  }
  1.1888                  depth--;
  1.1889              }
  1.1890 @@ -1751,7 +1976,7 @@
  1.1891                  if (attr == null && value == null) {
  1.1892                      return;
  1.1893                  }
  1.1894 -                out.append(value);
  1.1895 +                append(value);
  1.1896              }
  1.1897  
  1.1898              @Override
  1.1899 @@ -1760,8 +1985,8 @@
  1.1900                  final String slashType = attrType.substring(1, attrType.length() - 1);
  1.1901                  requireReference(slashType);
  1.1902                  
  1.1903 -                out.append(accessClass(slashType.replace('/', '_')))
  1.1904 -                   .append("(false).constructor.").append(value);
  1.1905 +                append(accessClass(mangleClassName(slashType)))
  1.1906 +                   .append("(false).constructor.fld_").append(value);
  1.1907              }
  1.1908          };
  1.1909          ap.parse(data, cd);
  1.1910 @@ -1779,7 +2004,21 @@
  1.1911          return ",";
  1.1912      }
  1.1913  
  1.1914 -    private static void emit(final Appendable out,
  1.1915 +    final void emitNoFlush(
  1.1916 +        StackMapper sm, 
  1.1917 +        final String format, final CharSequence... params
  1.1918 +    ) throws IOException {
  1.1919 +        emitImpl(this, format, params);
  1.1920 +    }
  1.1921 +    static final void emit(
  1.1922 +        StackMapper sm, 
  1.1923 +        final Appendable out, 
  1.1924 +        final String format, final CharSequence... params
  1.1925 +    ) throws IOException {
  1.1926 +        sm.flush(out);
  1.1927 +        emitImpl(out, format, params);
  1.1928 +    }
  1.1929 +    static void emitImpl(final Appendable out,
  1.1930                               final String format,
  1.1931                               final CharSequence... params) throws IOException {
  1.1932          final int length = format.length();
  1.1933 @@ -1805,7 +2044,7 @@
  1.1934      }
  1.1935  
  1.1936      private void generateCatch(TrapData[] traps, int current, int topMostLabel) throws IOException {
  1.1937 -        out.append("} catch (e) {\n");
  1.1938 +        append("} catch (e) {\n");
  1.1939          int finallyPC = -1;
  1.1940          for (TrapData e : traps) {
  1.1941              if (e == null) {
  1.1942 @@ -1814,22 +2053,22 @@
  1.1943              if (e.catch_cpx != 0) { //not finally
  1.1944                  final String classInternalName = jc.getClassName(e.catch_cpx);
  1.1945                  addReference(classInternalName);
  1.1946 -                out.append("e = vm.java_lang_Throwable(false).bck2BrwsrCnvrt(e);");
  1.1947 -                out.append("if (e['$instOf_" + classInternalName.replace('/', '_') + "']) {");
  1.1948 -                out.append("var stA0 = e;");
  1.1949 -                goTo(out, current, e.handler_pc, topMostLabel);
  1.1950 -                out.append("}\n");
  1.1951 +                append("e = vm.java_lang_Throwable(false).bck2BrwsrCnvrt(e);");
  1.1952 +                append("if (e['$instOf_" + classInternalName.replace('/', '_') + "']) {");
  1.1953 +                append("var stA0 = e;");
  1.1954 +                goTo(this, current, e.handler_pc, topMostLabel);
  1.1955 +                append("}\n");
  1.1956              } else {
  1.1957                  finallyPC = e.handler_pc;
  1.1958              }
  1.1959          }
  1.1960          if (finallyPC == -1) {
  1.1961 -            out.append("throw e;");
  1.1962 +            append("throw e;");
  1.1963          } else {
  1.1964 -            out.append("var stA0 = e;");
  1.1965 -            goTo(out, current, finallyPC, topMostLabel);
  1.1966 +            append("var stA0 = e;");
  1.1967 +            goTo(this, current, finallyPC, topMostLabel);
  1.1968          }
  1.1969 -        out.append("\n}");
  1.1970 +        append("\n}");
  1.1971      }
  1.1972  
  1.1973      private static void goTo(Appendable out, int current, int to, int canBack) throws IOException {
  1.1974 @@ -1845,10 +2084,13 @@
  1.1975      }
  1.1976  
  1.1977      private static void emitIf(
  1.1978 -        Appendable out, String pattern, Variable param, 
  1.1979 +        StackMapper sm, 
  1.1980 +        Appendable out, String pattern, 
  1.1981 +        CharSequence param, 
  1.1982          int current, int to, int canBack
  1.1983      ) throws IOException {
  1.1984 -        emit(out, pattern, param);
  1.1985 +        sm.flush(out);
  1.1986 +        emitImpl(out, pattern, param);
  1.1987          goTo(out, current, to, canBack);
  1.1988      }
  1.1989  
  1.1990 @@ -1865,7 +2107,8 @@
  1.1991              case 11: jvmType = "[J"; break;
  1.1992              default: throw new IllegalStateException("Array type: " + atype);
  1.1993          }
  1.1994 -        emit(out, "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](true, '@3', @1);",
  1.1995 +        emit(smapper, this, 
  1.1996 +            "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](true, '@3', @1);",
  1.1997               smapper.popI(), smapper.pushA(), jvmType);
  1.1998      }
  1.1999  
  1.2000 @@ -1876,7 +2119,8 @@
  1.2001          } else {
  1.2002              typeName = "[L" + typeName + ";";
  1.2003          }
  1.2004 -        emit(out, "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](false, '@3', @1);",
  1.2005 +        emit(smapper, this,
  1.2006 +            "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](false, '@3', @1);",
  1.2007               smapper.popI(), smapper.pushA(), typeName);
  1.2008      }
  1.2009  
  1.2010 @@ -1892,7 +2136,8 @@
  1.2011              dims.insert(1, smapper.popI());
  1.2012          }
  1.2013          dims.append(']');
  1.2014 -        emit(out, "var @2 = Array.prototype['multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II']('@3', @1, 0);",
  1.2015 +        emit(smapper, this, 
  1.2016 +            "var @2 = Array.prototype['multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II']('@3', @1, 0);",
  1.2017               dims.toString(), smapper.pushA(), typeName);
  1.2018          return i;
  1.2019      }
  1.2020 @@ -1905,16 +2150,18 @@
  1.2021          table += 4;
  1.2022          int high = readInt4(byteCodes, table);
  1.2023          table += 4;
  1.2024 -        out.append("switch (").append(smapper.popI()).append(") {\n");
  1.2025 +        final CharSequence swVar = smapper.popValue();
  1.2026 +        smapper.flush(this);
  1.2027 +        append("switch (").append(swVar).append(") {\n");
  1.2028          while (low <= high) {
  1.2029              int offset = i + readInt4(byteCodes, table);
  1.2030              table += 4;
  1.2031 -            out.append("  case " + low).append(":"); goTo(out, i, offset, topMostLabel); out.append('\n');
  1.2032 +            append("  case " + low).append(":"); goTo(this, i, offset, topMostLabel); append('\n');
  1.2033              low++;
  1.2034          }
  1.2035 -        out.append("  default: ");
  1.2036 -        goTo(out, i, dflt, topMostLabel);
  1.2037 -        out.append("\n}");
  1.2038 +        append("  default: ");
  1.2039 +        goTo(this, i, dflt, topMostLabel);
  1.2040 +        append("\n}");
  1.2041          i = table - 1;
  1.2042          return i;
  1.2043      }
  1.2044 @@ -1925,17 +2172,19 @@
  1.2045          table += 4;
  1.2046          int n = readInt4(byteCodes, table);
  1.2047          table += 4;
  1.2048 -        out.append("switch (").append(smapper.popI()).append(") {\n");
  1.2049 +        final CharSequence swVar = smapper.popValue();
  1.2050 +        smapper.flush(this);
  1.2051 +        append("switch (").append(swVar).append(") {\n");
  1.2052          while (n-- > 0) {
  1.2053              int cnstnt = readInt4(byteCodes, table);
  1.2054              table += 4;
  1.2055              int offset = i + readInt4(byteCodes, table);
  1.2056              table += 4;
  1.2057 -            out.append("  case " + cnstnt).append(": "); goTo(out, i, offset, topMostLabel); out.append('\n');
  1.2058 +            append("  case " + cnstnt).append(": "); goTo(this, i, offset, topMostLabel); append('\n');
  1.2059          }
  1.2060 -        out.append("  default: ");
  1.2061 -        goTo(out, i, dflt, topMostLabel);
  1.2062 -        out.append("\n}");
  1.2063 +        append("  default: ");
  1.2064 +        goTo(this, i, dflt, topMostLabel);
  1.2065 +        append("\n}");
  1.2066          i = table - 1;
  1.2067          return i;
  1.2068      }
  1.2069 @@ -1943,11 +2192,13 @@
  1.2070      private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException {
  1.2071          final String type = jc.getClassName(indx);
  1.2072          if (!type.startsWith("[")) {
  1.2073 -            emit(out, "var @2 = @1 != null && @1['$instOf_@3'] ? 1 : 0;",
  1.2074 +            emit(smapper, this, 
  1.2075 +                    "var @2 = @1 != null && @1['$instOf_@3'] ? 1 : 0;",
  1.2076                   smapper.popA(), smapper.pushI(),
  1.2077                   type.replace('/', '_'));
  1.2078          } else {
  1.2079 -            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.2080 +            emit(smapper, this, 
  1.2081 +                "var @2 = vm.java_lang_Class(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('@3')['isInstance__ZLjava_lang_Object_2'](@1);",
  1.2082                  smapper.popA(), smapper.pushI(),
  1.2083                  type
  1.2084              );
  1.2085 @@ -1957,21 +2208,22 @@
  1.2086      private void generateCheckcast(int indx, final StackMapper smapper) throws IOException {
  1.2087          final String type = jc.getClassName(indx);
  1.2088          if (!type.startsWith("[")) {
  1.2089 -            emit(out,
  1.2090 +            emitNoFlush(smapper, 
  1.2091                   "if (@1 !== null && !@1['$instOf_@2']) throw vm.java_lang_ClassCastException(true);",
  1.2092 -                 smapper.getA(0), type.replace('/', '_'));
  1.2093 +                 smapper.getT(0, VarType.REFERENCE, false), type.replace('/', '_'));
  1.2094          } else {
  1.2095 -            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.2096 -                 smapper.getA(0), type
  1.2097 +            emitNoFlush(smapper, 
  1.2098 +                "vm.java_lang_Class(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('@2')['cast__Ljava_lang_Object_2Ljava_lang_Object_2'](@1);",
  1.2099 +                 smapper.getT(0, VarType.REFERENCE, false), type
  1.2100              );
  1.2101          }
  1.2102      }
  1.2103  
  1.2104      private void generateByteCodeComment(int prev, int i, final byte[] byteCodes) throws IOException {
  1.2105          for (int j = prev; j <= i; j++) {
  1.2106 -            out.append(" ");
  1.2107 +            append(" ");
  1.2108              final int cc = readUByte(byteCodes, j);
  1.2109 -            out.append(Integer.toString(cc));
  1.2110 +            append(Integer.toString(cc));
  1.2111          }
  1.2112      }
  1.2113  }