Eliminates use of stack in empty super constructor call ReducedStack
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 15 Feb 2014 20:18:26 +0100
branchReducedStack
changeset 1457b9386cc3ff7b
parent 1456 6212993ac686
child 1458 5c8caf0ba8b8
Eliminates use of stack in empty super constructor call
rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java
rt/vm/src/test/java/org/apidesign/vm4brwsr/SizeOfAMethodTest.java
     1.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Sat Feb 15 17:30:47 2014 +0100
     1.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Sat Feb 15 20:18:26 2014 +0100
     1.3 @@ -572,116 +572,116 @@
     1.4                      emit(smapper, out, "var @1 = @2;", lmapper.setD(3), smapper.popD());
     1.5                      break;
     1.6                  case opc_iadd:
     1.7 -                    emit(smapper, out, "@1 = @1.add32(@2);", smapper.getI(1), smapper.popI());
     1.8 +                    smapper.replace(out, VarType.INTEGER, "@1.add32(@2)", smapper.getI(1), smapper.popI());
     1.9                      break;
    1.10                  case opc_ladd:
    1.11 -                    emit(smapper, out, "@1 = @1.add64(@2);", smapper.getL(1), smapper.popL());
    1.12 +                    smapper.replace(out, VarType.LONG, "@1.add64(@2)", smapper.getL(1), smapper.popL());
    1.13                      break;
    1.14                  case opc_fadd:
    1.15 -                    emit(smapper, out, "@1 += @2;", smapper.getF(1), smapper.popF());
    1.16 +                    smapper.replace(out, VarType.FLOAT, "(@1 + @2)", smapper.getF(1), smapper.popF());
    1.17                      break;
    1.18                  case opc_dadd:
    1.19 -                    emit(smapper, out, "@1 += @2;", smapper.getD(1), smapper.popD());
    1.20 +                    smapper.replace(out, VarType.DOUBLE, "(@1 + @2)", smapper.getD(1), smapper.popD());
    1.21                      break;
    1.22                  case opc_isub:
    1.23 -                    emit(smapper, out, "@1 = @1.sub32(@2);", smapper.getI(1), smapper.popI());
    1.24 +                    smapper.replace(out, VarType.INTEGER, "@1.sub32(@2)", smapper.getI(1), smapper.popI());
    1.25                      break;
    1.26                  case opc_lsub:
    1.27 -                    emit(smapper, out, "@1 = @1.sub64(@2);", smapper.getL(1), smapper.popL());
    1.28 +                    smapper.replace(out, VarType.LONG, "@1.sub64(@2)", smapper.getL(1), smapper.popL());
    1.29                      break;
    1.30                  case opc_fsub:
    1.31 -                    emit(smapper, out, "@1 -= @2;", smapper.getF(1), smapper.popF());
    1.32 +                    smapper.replace(out, VarType.FLOAT, "(@1 - @2)", smapper.getF(1), smapper.popF());
    1.33                      break;
    1.34                  case opc_dsub:
    1.35 -                    emit(smapper, out, "@1 -= @2;", smapper.getD(1), smapper.popD());
    1.36 +                    smapper.replace(out, VarType.DOUBLE, "(@1 - @2)", smapper.getD(1), smapper.popD());
    1.37                      break;
    1.38                  case opc_imul:
    1.39 -                    emit(smapper, out, "@1 = @1.mul32(@2);", smapper.getI(1), smapper.popI());
    1.40 +                    smapper.replace(out, VarType.INTEGER, "@1.mul32(@2)", smapper.getI(1), smapper.popI());
    1.41                      break;
    1.42                  case opc_lmul:
    1.43 -                    emit(smapper, out, "@1 = @1.mul64(@2);", smapper.getL(1), smapper.popL());
    1.44 +                    smapper.replace(out, VarType.LONG, "@1.mul64(@2)", smapper.getL(1), smapper.popL());
    1.45                      break;
    1.46                  case opc_fmul:
    1.47 -                    emit(smapper, out, "@1 *= @2;", smapper.getF(1), smapper.popF());
    1.48 +                    smapper.replace(out, VarType.FLOAT, "(@1 * @2)", smapper.getF(1), smapper.popF());
    1.49                      break;
    1.50                  case opc_dmul:
    1.51 -                    emit(smapper, out, "@1 *= @2;", smapper.getD(1), smapper.popD());
    1.52 +                    smapper.replace(out, VarType.DOUBLE, "(@1 * @2)", smapper.getD(1), smapper.popD());
    1.53                      break;
    1.54                  case opc_idiv:
    1.55 -                    emit(smapper, out, "@1 = @1.div32(@2);",
    1.56 +                    smapper.replace(out, VarType.INTEGER, "@1.div32(@2)",
    1.57                           smapper.getI(1), smapper.popI());
    1.58                      break;
    1.59                  case opc_ldiv:
    1.60 -                    emit(smapper, out, "@1 = @1.div64(@2);",
    1.61 +                    smapper.replace(out, VarType.LONG, "@1.div64(@2)",
    1.62                           smapper.getL(1), smapper.popL());
    1.63                      break;
    1.64                  case opc_fdiv:
    1.65 -                    emit(smapper, out, "@1 /= @2;", smapper.getF(1), smapper.popF());
    1.66 +                    smapper.replace(out, VarType.FLOAT, "(@1 / @2)", smapper.getF(1), smapper.popF());
    1.67                      break;
    1.68                  case opc_ddiv:
    1.69 -                    emit(smapper, out, "@1 /= @2;", smapper.getD(1), smapper.popD());
    1.70 +                    smapper.replace(out, VarType.DOUBLE, "(@1 / @2)", smapper.getD(1), smapper.popD());
    1.71                      break;
    1.72                  case opc_irem:
    1.73 -                    emit(smapper, out, "@1 = @1.mod32(@2);",
    1.74 +                    smapper.replace(out, VarType.INTEGER, "@1.mod32(@2)",
    1.75                           smapper.getI(1), smapper.popI());
    1.76                      break;
    1.77                  case opc_lrem:
    1.78 -                    emit(smapper, out, "@1 = @1.mod64(@2);",
    1.79 +                    smapper.replace(out, VarType.LONG, "@1.mod64(@2)",
    1.80                           smapper.getL(1), smapper.popL());
    1.81                      break;
    1.82                  case opc_frem:
    1.83 -                    emit(smapper, out, "@1 %= @2;", smapper.getF(1), smapper.popF());
    1.84 +                    smapper.replace(out, VarType.FLOAT, "(@1 % @2)", smapper.getF(1), smapper.popF());
    1.85                      break;
    1.86                  case opc_drem:
    1.87 -                    emit(smapper, out, "@1 %= @2;", smapper.getD(1), smapper.popD());
    1.88 +                    smapper.replace(out, VarType.DOUBLE, "(@1 % @2)", smapper.getD(1), smapper.popD());
    1.89                      break;
    1.90                  case opc_iand:
    1.91 -                    emit(smapper, out, "@1 &= @2;", smapper.getI(1), smapper.popI());
    1.92 +                    smapper.replace(out, VarType.INTEGER, "(@1 & @2)", smapper.getI(1), smapper.popI());
    1.93                      break;
    1.94                  case opc_land:
    1.95 -                    emit(smapper, out, "@1 = @1.and64(@2);", smapper.getL(1), smapper.popL());
    1.96 +                    smapper.replace(out, VarType.LONG, "@1.and64(@2)", smapper.getL(1), smapper.popL());
    1.97                      break;
    1.98                  case opc_ior:
    1.99 -                    emit(smapper, out, "@1 |= @2;", smapper.getI(1), smapper.popI());
   1.100 +                    smapper.replace(out, VarType.INTEGER, "(@1 | @2)", smapper.getI(1), smapper.popI());
   1.101                      break;
   1.102                  case opc_lor:
   1.103 -                    emit(smapper, out, "@1 = @1.or64(@2);", smapper.getL(1), smapper.popL());
   1.104 +                    smapper.replace(out, VarType.LONG, "@1.or64(@2)", smapper.getL(1), smapper.popL());
   1.105                      break;
   1.106                  case opc_ixor:
   1.107 -                    emit(smapper, out, "@1 ^= @2;", smapper.getI(1), smapper.popI());
   1.108 +                    smapper.replace(out, VarType.INTEGER, "(@1 ^ @2)", smapper.getI(1), smapper.popI());
   1.109                      break;
   1.110                  case opc_lxor:
   1.111 -                    emit(smapper, out, "@1 = @1.xor64(@2);", smapper.getL(1), smapper.popL());
   1.112 +                    smapper.replace(out, VarType.LONG, "@1.xor64(@2)", smapper.getL(1), smapper.popL());
   1.113                      break;
   1.114                  case opc_ineg:
   1.115 -                    emit(smapper, out, "@1 = @1.neg32();", smapper.getI(0));
   1.116 +                    smapper.replace(out, VarType.INTEGER, "@1.neg32()", smapper.getI(0));
   1.117                      break;
   1.118                  case opc_lneg:
   1.119 -                    emit(smapper, out, "@1 = @1.neg64();", smapper.getL(0));
   1.120 +                    smapper.replace(out, VarType.LONG, "@1.neg64()", smapper.getL(0));
   1.121                      break;
   1.122                  case opc_fneg:
   1.123 -                    emit(smapper, out, "@1 = -@1;", smapper.getF(0));
   1.124 +                    smapper.replace(out, VarType.FLOAT, "(-@1)", smapper.getF(0));
   1.125                      break;
   1.126                  case opc_dneg:
   1.127 -                    emit(smapper, out, "@1 = -@1;", smapper.getD(0));
   1.128 +                    smapper.replace(out, VarType.DOUBLE, "(-@1)", smapper.getD(0));
   1.129                      break;
   1.130                  case opc_ishl:
   1.131 -                    emit(smapper, out, "@1 <<= @2;", smapper.getI(1), smapper.popI());
   1.132 +                    smapper.replace(out, VarType.INTEGER, "(@1 << @2)", smapper.getI(1), smapper.popI());
   1.133                      break;
   1.134                  case opc_lshl:
   1.135 -                    emit(smapper, out, "@1 = @1.shl64(@2);", smapper.getL(1), smapper.popI());
   1.136 +                    smapper.replace(out, VarType.LONG, "@1.shl64(@2)", smapper.getL(1), smapper.popI());
   1.137                      break;
   1.138                  case opc_ishr:
   1.139 -                    emit(smapper, out, "@1 >>= @2;", smapper.getI(1), smapper.popI());
   1.140 +                    smapper.replace(out, VarType.INTEGER, "(@1 >> @2)", smapper.getI(1), smapper.popI());
   1.141                      break;
   1.142                  case opc_lshr:
   1.143 -                    emit(smapper, out, "@1 = @1.shr64(@2);", smapper.getL(1), smapper.popI());
   1.144 +                    smapper.replace(out, VarType.LONG, "@1.shr64(@2)", smapper.getL(1), smapper.popI());
   1.145                      break;
   1.146                  case opc_iushr:
   1.147 -                    emit(smapper, out, "@1 >>>= @2;", smapper.getI(1), smapper.popI());
   1.148 +                    smapper.replace(out, VarType.INTEGER, "(@1 >>> @2)", smapper.getI(1), smapper.popI());
   1.149                      break;
   1.150                  case opc_lushr:
   1.151 -                    emit(smapper, out, "@1 = @1.ushr64(@2);", smapper.getL(1), smapper.popI());
   1.152 +                    smapper.replace(out, VarType.LONG, "@1.ushr64(@2)", smapper.getL(1), smapper.popI());
   1.153                      break;
   1.154                  case opc_iinc: {
   1.155                      ++i;
   1.156 @@ -719,99 +719,99 @@
   1.157                      emit(smapper, out, "return @1;", smapper.popA());
   1.158                      break;
   1.159                  case opc_i2l:
   1.160 -                    emit(smapper, out, "var @2 = @1;", smapper.popI(), smapper.pushL());
   1.161 +                    smapper.replace(out, VarType.LONG, "@1", smapper.getI(0));
   1.162                      break;
   1.163                  case opc_i2f:
   1.164 -                    emit(smapper, out, "var @2 = @1;", smapper.popI(), smapper.pushF());
   1.165 +                    smapper.replace(out, VarType.FLOAT, "@1", smapper.getI(0));
   1.166                      break;
   1.167                  case opc_i2d:
   1.168 -                    emit(smapper, out, "var @2 = @1;", smapper.popI(), smapper.pushD());
   1.169 +                    smapper.replace(out, VarType.DOUBLE, "@1", smapper.getI(0));
   1.170                      break;
   1.171                  case opc_l2i:
   1.172 -                    emit(smapper, out, "var @2 = @1.toInt32();", smapper.popL(), smapper.pushI());
   1.173 +                    smapper.replace(out, VarType.INTEGER, "@1.toInt32()", smapper.getL(0));
   1.174                      break;
   1.175                      // max int check?
   1.176                  case opc_l2f:
   1.177 -                    emit(smapper, out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushF());
   1.178 +                    smapper.replace(out, VarType.FLOAT, "@1.toFP()", smapper.getL(0));
   1.179                      break;
   1.180                  case opc_l2d:
   1.181 -                    emit(smapper, out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushD());
   1.182 +                    smapper.replace(out, VarType.DOUBLE, "@1.toFP()", smapper.getL(0));
   1.183                      break;
   1.184                  case opc_f2d:
   1.185 -                    emit(smapper, out, "var @2 = @1;", smapper.popF(), smapper.pushD());
   1.186 +                    smapper.replace(out, VarType.DOUBLE, "@1",
   1.187 +                         smapper.getF(0));
   1.188                      break;
   1.189                  case opc_d2f:
   1.190 -                    emit(smapper, out, "var @2 = @1;", smapper.popD(), smapper.pushF());
   1.191 +                    smapper.replace(out, VarType.FLOAT, "@1",
   1.192 +                         smapper.getD(0));
   1.193                      break;
   1.194                  case opc_f2i:
   1.195 -                    emit(smapper, out, "var @2 = @1.toInt32();",
   1.196 -                         smapper.popF(), smapper.pushI());
   1.197 +                    smapper.replace(out, VarType.INTEGER, "@1.toInt32()",
   1.198 +                         smapper.getF(0));
   1.199                      break;
   1.200                  case opc_f2l:
   1.201 -                    emit(smapper, out, "var @2 = @1.toLong();",
   1.202 -                         smapper.popF(), smapper.pushL());
   1.203 +                    smapper.replace(out, VarType.LONG, "@1.toLong()",
   1.204 +                         smapper.getF(0));
   1.205                      break;
   1.206                  case opc_d2i:
   1.207 -                    emit(smapper, out, "var @2 = @1.toInt32();",
   1.208 -                         smapper.popD(), smapper.pushI());
   1.209 +                    smapper.replace(out, VarType.INTEGER, "@1.toInt32()",
   1.210 +                         smapper.getD(0));
   1.211                      break;
   1.212                  case opc_d2l:
   1.213 -                    emit(smapper, out, "var @2 = @1.toLong();",
   1.214 -                         smapper.popD(), smapper.pushL());
   1.215 +                    smapper.replace(out, VarType.LONG, "@1.toLong()", smapper.getD(0));
   1.216                      break;
   1.217                  case opc_i2b:
   1.218 -                    emit(smapper, out, "var @1 = @1.toInt8();", smapper.getI(0));
   1.219 +                    smapper.replace(out, VarType.INTEGER, "@1.toInt8()", smapper.getI(0));
   1.220                      break;
   1.221                  case opc_i2c:
   1.222 -                    out.append("{ /* number conversion */ }");
   1.223                      break;
   1.224                  case opc_i2s:
   1.225 -                    emit(smapper, out, "var @1 = @1.toInt16();", smapper.getI(0));
   1.226 +                    smapper.replace(out, VarType.INTEGER, "@1.toInt16()", smapper.getI(0));
   1.227                      break;
   1.228                  case opc_aconst_null:
   1.229 -                    emit(smapper, out, "var @1 = null;", smapper.pushA());
   1.230 +                    smapper.assign(out, VarType.REFERENCE, "null");
   1.231                      break;
   1.232                  case opc_iconst_m1:
   1.233 -                    emit(smapper, out, "var @1 = -1;", smapper.pushI());
   1.234 +                    smapper.assign(out, VarType.INTEGER, "-1");
   1.235                      break;
   1.236                  case opc_iconst_0:
   1.237 -                    emit(smapper, out, "var @1 = 0;", smapper.pushI());
   1.238 +                    smapper.assign(out, VarType.INTEGER, "0");
   1.239                      break;
   1.240                  case opc_dconst_0:
   1.241 -                    emit(smapper, out, "var @1 = 0;", smapper.pushD());
   1.242 +                    smapper.assign(out, VarType.DOUBLE, "0");
   1.243                      break;
   1.244                  case opc_lconst_0:
   1.245 -                    emit(smapper, out, "var @1 = 0;", smapper.pushL());
   1.246 +                    smapper.assign(out, VarType.LONG, "0");
   1.247                      break;
   1.248                  case opc_fconst_0:
   1.249 -                    emit(smapper, out, "var @1 = 0;", smapper.pushF());
   1.250 +                    smapper.assign(out, VarType.FLOAT, "0");
   1.251                      break;
   1.252                  case opc_iconst_1:
   1.253 -                    emit(smapper, out, "var @1 = 1;", smapper.pushI());
   1.254 +                    smapper.assign(out, VarType.INTEGER, "1");
   1.255                      break;
   1.256                  case opc_lconst_1:
   1.257 -                    emit(smapper, out, "var @1 = 1;", smapper.pushL());
   1.258 +                    smapper.assign(out, VarType.LONG, "1");
   1.259                      break;
   1.260                  case opc_fconst_1:
   1.261 -                    emit(smapper, out, "var @1 = 1;", smapper.pushF());
   1.262 +                    smapper.assign(out, VarType.FLOAT, "1");
   1.263                      break;
   1.264                  case opc_dconst_1:
   1.265 -                    emit(smapper, out, "var @1 = 1;", smapper.pushD());
   1.266 +                    smapper.assign(out, VarType.DOUBLE, "1");
   1.267                      break;
   1.268                  case opc_iconst_2:
   1.269 -                    emit(smapper, out, "var @1 = 2;", smapper.pushI());
   1.270 +                    smapper.assign(out, VarType.INTEGER, "2");
   1.271                      break;
   1.272                  case opc_fconst_2:
   1.273 -                    emit(smapper, out, "var @1 = 2;", smapper.pushF());
   1.274 +                    smapper.assign(out, VarType.FLOAT, "2");
   1.275                      break;
   1.276                  case opc_iconst_3:
   1.277 -                    emit(smapper, out, "var @1 = 3;", smapper.pushI());
   1.278 +                    smapper.assign(out, VarType.INTEGER, "3");
   1.279                      break;
   1.280                  case opc_iconst_4:
   1.281 -                    emit(smapper, out, "var @1 = 4;", smapper.pushI());
   1.282 +                    smapper.assign(out, VarType.INTEGER, "4");
   1.283                      break;
   1.284                  case opc_iconst_5:
   1.285 -                    emit(smapper, out, "var @1 = 5;", smapper.pushI());
   1.286 +                    smapper.assign(out, VarType.INTEGER, "5");
   1.287                      break;
   1.288                  case opc_ldc: {
   1.289                      int indx = readUByte(byteCodes, ++i);
   1.290 @@ -1066,8 +1066,8 @@
   1.291                      break;
   1.292                  }
   1.293                  case opc_dup_x1: {
   1.294 -                    final Variable vi1 = smapper.pop();
   1.295 -                    final Variable vi2 = smapper.pop();
   1.296 +                    final Variable vi1 = smapper.pop(out);
   1.297 +                    final Variable vi2 = smapper.pop(out);
   1.298                      final Variable vo3 = smapper.pushT(vi1.getType());
   1.299                      final Variable vo2 = smapper.pushT(vi2.getType());
   1.300                      final Variable vo1 = smapper.pushT(vi1.getType());
   1.301 @@ -1077,8 +1077,8 @@
   1.302                      break;
   1.303                  }
   1.304                  case opc_dup2_x1: {
   1.305 -                    final Variable vi1 = smapper.pop();
   1.306 -                    final Variable vi2 = smapper.pop();
   1.307 +                    final Variable vi1 = smapper.pop(out);
   1.308 +                    final Variable vi2 = smapper.pop(out);
   1.309  
   1.310                      if (vi1.isCategory2()) {
   1.311                          final Variable vo3 = smapper.pushT(vi1.getType());
   1.312 @@ -1088,7 +1088,7 @@
   1.313                          emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6;",
   1.314                               vo1, vi1, vo2, vi2, vo3, vo1);
   1.315                      } else {
   1.316 -                        final Variable vi3 = smapper.pop();
   1.317 +                        final Variable vi3 = smapper.pop(out);
   1.318                          final Variable vo5 = smapper.pushT(vi2.getType());
   1.319                          final Variable vo4 = smapper.pushT(vi1.getType());
   1.320                          final Variable vo3 = smapper.pushT(vi3.getType());
   1.321 @@ -1103,8 +1103,8 @@
   1.322                      break;
   1.323                  }
   1.324                  case opc_dup_x2: {
   1.325 -                    final Variable vi1 = smapper.pop();
   1.326 -                    final Variable vi2 = smapper.pop();
   1.327 +                    final Variable vi1 = smapper.pop(out);
   1.328 +                    final Variable vi2 = smapper.pop(out);
   1.329  
   1.330                      if (vi2.isCategory2()) {
   1.331                          final Variable vo3 = smapper.pushT(vi1.getType());
   1.332 @@ -1114,7 +1114,7 @@
   1.333                          emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6;",
   1.334                               vo1, vi1, vo2, vi2, vo3, vo1);
   1.335                      } else {
   1.336 -                        final Variable vi3 = smapper.pop();
   1.337 +                        final Variable vi3 = smapper.pop(out);
   1.338                          final Variable vo4 = smapper.pushT(vi1.getType());
   1.339                          final Variable vo3 = smapper.pushT(vi3.getType());
   1.340                          final Variable vo2 = smapper.pushT(vi2.getType());
   1.341 @@ -1126,8 +1126,8 @@
   1.342                      break;
   1.343                  }
   1.344                  case opc_dup2_x2: {
   1.345 -                    final Variable vi1 = smapper.pop();
   1.346 -                    final Variable vi2 = smapper.pop();
   1.347 +                    final Variable vi1 = smapper.pop(out);
   1.348 +                    final Variable vi2 = smapper.pop(out);
   1.349  
   1.350                      if (vi1.isCategory2()) {
   1.351                          if (vi2.isCategory2()) {
   1.352 @@ -1138,7 +1138,7 @@
   1.353                              emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6;",
   1.354                                   vo1, vi1, vo2, vi2, vo3, vo1);
   1.355                          } else {
   1.356 -                            final Variable vi3 = smapper.pop();
   1.357 +                            final Variable vi3 = smapper.pop(out);
   1.358                              final Variable vo4 = smapper.pushT(vi1.getType());
   1.359                              final Variable vo3 = smapper.pushT(vi3.getType());
   1.360                              final Variable vo2 = smapper.pushT(vi2.getType());
   1.361 @@ -1148,7 +1148,7 @@
   1.362                                   vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1);
   1.363                          }
   1.364                      } else {
   1.365 -                        final Variable vi3 = smapper.pop();
   1.366 +                        final Variable vi3 = smapper.pop(out);
   1.367  
   1.368                          if (vi3.isCategory2()) {
   1.369                              final Variable vo5 = smapper.pushT(vi2.getType());
   1.370 @@ -1162,7 +1162,7 @@
   1.371                              emit(smapper, out, " @1 = @2, @3 = @4;",
   1.372                                   vo4, vo1, vo5, vo2);
   1.373                          } else {
   1.374 -                            final Variable vi4 = smapper.pop();
   1.375 +                            final Variable vi4 = smapper.pop(out);
   1.376                              final Variable vo6 = smapper.pushT(vi2.getType());
   1.377                              final Variable vo5 = smapper.pushT(vi1.getType());
   1.378                              final Variable vo4 = smapper.pushT(vi4.getType());
   1.379 @@ -1267,7 +1267,7 @@
   1.380                      break;
   1.381                  }
   1.382                  case opc_athrow: {
   1.383 -                    final Variable v = smapper.popA();
   1.384 +                    final CharSequence v = smapper.popA();
   1.385                      smapper.clear();
   1.386  
   1.387                      emit(smapper, out, "{ var @1 = @2; throw @2; }",
   1.388 @@ -1312,7 +1312,7 @@
   1.389          out.append("\n};");
   1.390      }
   1.391  
   1.392 -    private int generateIf(byte[] byteCodes, int i, final Variable v2, final Variable v1, final String test, int topMostLabel) throws IOException {
   1.393 +    private int generateIf(byte[] byteCodes, int i, final CharSequence v2, final CharSequence v1, final String test, int topMostLabel) throws IOException {
   1.394          int indx = i + readShortArg(byteCodes, i);
   1.395          out.append("if (").append(v1)
   1.396             .append(' ').append(test).append(' ')
   1.397 @@ -1497,10 +1497,10 @@
   1.398          String mn = findMethodName(mi, cnt, returnType);
   1.399  
   1.400          final int numArguments = isStatic ? cnt.length() : cnt.length() + 1;
   1.401 -        final Variable[] vars = new Variable[numArguments];
   1.402 +        final CharSequence[] vars = new CharSequence[numArguments];
   1.403  
   1.404          for (int j = numArguments - 1; j >= 0; --j) {
   1.405 -            vars[j] = mapper.pop();
   1.406 +            vars[j] = mapper.popValue();
   1.407          }
   1.408  
   1.409          if (returnType[0] != 'V') {
   1.410 @@ -1545,7 +1545,7 @@
   1.411          final Variable[] vars = new Variable[numArguments];
   1.412  
   1.413          for (int j = numArguments - 1; j >= 0; --j) {
   1.414 -            vars[j] = mapper.pop();
   1.415 +            vars[j] = mapper.pop(out);
   1.416          }
   1.417  
   1.418          if (returnType[0] != 'V') {
   1.419 @@ -2006,7 +2006,7 @@
   1.420      private static void emitIf(
   1.421          StackMapper sm, 
   1.422          Appendable out, String pattern, 
   1.423 -        Variable param, 
   1.424 +        CharSequence param, 
   1.425          int current, int to, int canBack
   1.426      ) throws IOException {
   1.427          sm.flush(out);
     2.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java	Sat Feb 15 17:30:47 2014 +0100
     2.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java	Sat Feb 15 20:18:26 2014 +0100
     2.3 @@ -69,7 +69,16 @@
     2.4  
     2.5      void assign(Appendable out, int varType, CharSequence s) throws IOException {
     2.6          pushTypeAndValue(varType, s);
     2.7 -        flush(out);
     2.8 +    }
     2.9 +
    2.10 +    void replace(Appendable out, int varType, String format, CharSequence... arr) 
    2.11 +    throws IOException {
    2.12 +        StringBuilder sb = new StringBuilder();
    2.13 +        ByteCodeToJavaScript.emitImpl(sb, format, arr);
    2.14 +        String[] values = stackValues.toArray();
    2.15 +        final int last = stackTypeIndexPairs.getSize() - 1;
    2.16 +        values[last] = sb.toString();
    2.17 +        stackTypeIndexPairs.set(last, varType);
    2.18      }
    2.19      
    2.20      void flush(Appendable out) throws IOException {
    2.21 @@ -84,33 +93,39 @@
    2.22          }
    2.23      }
    2.24      
    2.25 -    public Variable popI() {
    2.26 +    public CharSequence popI() {
    2.27          return popT(VarType.INTEGER);
    2.28      }
    2.29  
    2.30 -    public Variable popL() {
    2.31 +    public CharSequence popL() {
    2.32          return popT(VarType.LONG);
    2.33      }
    2.34  
    2.35 -    public Variable popF() {
    2.36 +    public CharSequence popF() {
    2.37          return popT(VarType.FLOAT);
    2.38      }
    2.39  
    2.40 -    public Variable popD() {
    2.41 +    public CharSequence popD() {
    2.42          return popT(VarType.DOUBLE);
    2.43      }
    2.44  
    2.45 -    public Variable popA() {
    2.46 +    public CharSequence popA() {
    2.47          return popT(VarType.REFERENCE);
    2.48      }
    2.49  
    2.50 -    public Variable popT(final int type) {
    2.51 -        final Variable variable = getT(0, type);
    2.52 +    public CharSequence popT(final int type) {
    2.53 +        final CharSequence variable = getT(0, type);
    2.54          popImpl(1);
    2.55          return variable;
    2.56      }
    2.57  
    2.58 -    public Variable pop() {
    2.59 +    public CharSequence popValue() {
    2.60 +        final CharSequence variable = getT(0, -1);
    2.61 +        popImpl(1);
    2.62 +        return variable;
    2.63 +    }
    2.64 +    public Variable pop(Appendable out) throws IOException {
    2.65 +        flush(out);
    2.66          final Variable variable = get(0);
    2.67          popImpl(1);
    2.68          return variable;
    2.69 @@ -124,37 +139,41 @@
    2.70          popImpl(count);
    2.71      }
    2.72  
    2.73 -    public Variable getI(final int indexFromTop) {
    2.74 +    public CharSequence getI(final int indexFromTop) {
    2.75          return getT(indexFromTop, VarType.INTEGER);
    2.76      }
    2.77  
    2.78 -    public Variable getL(final int indexFromTop) {
    2.79 +    public CharSequence getL(final int indexFromTop) {
    2.80          return getT(indexFromTop, VarType.LONG);
    2.81      }
    2.82  
    2.83 -    public Variable getF(final int indexFromTop) {
    2.84 +    public CharSequence getF(final int indexFromTop) {
    2.85          return getT(indexFromTop, VarType.FLOAT);
    2.86      }
    2.87  
    2.88 -    public Variable getD(final int indexFromTop) {
    2.89 +    public CharSequence getD(final int indexFromTop) {
    2.90          return getT(indexFromTop, VarType.DOUBLE);
    2.91      }
    2.92  
    2.93 -    public Variable getA(final int indexFromTop) {
    2.94 +    public CharSequence getA(final int indexFromTop) {
    2.95          return getT(indexFromTop, VarType.REFERENCE);
    2.96      }
    2.97  
    2.98 -    public Variable getT(final int indexFromTop, final int type) {
    2.99 +    public CharSequence getT(final int indexFromTop, final int type) {
   2.100          final int stackSize = stackTypeIndexPairs.getSize();
   2.101          if (indexFromTop >= stackSize) {
   2.102              throw new IllegalStateException("Stack underflow");
   2.103          }
   2.104          final int stackValue =
   2.105                  stackTypeIndexPairs.get(stackSize - indexFromTop - 1);
   2.106 -        if ((stackValue & 0xff) != type) {
   2.107 +        if (type != -1 && (stackValue & 0xff) != type) {
   2.108              throw new IllegalStateException("Type mismatch");
   2.109          }
   2.110 -
   2.111 +        String value =
   2.112 +                stackValues.getAndClear(stackSize - indexFromTop - 1);
   2.113 +        if (value != null) {
   2.114 +            return value;
   2.115 +        }
   2.116          return getVariable(stackValue);
   2.117      }
   2.118  
     3.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java	Sat Feb 15 17:30:47 2014 +0100
     3.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java	Sat Feb 15 20:18:26 2014 +0100
     3.3 @@ -105,7 +105,7 @@
     3.4      }
     3.5  
     3.6      int indexOf(String ic) {
     3.7 -        for (int i = 0; i < arr.length; i++) {
     3.8 +        if (arr != null) for (int i = 0; i < arr.length; i++) {
     3.9              if (ic.equals(arr[i])) {
    3.10                  return i;
    3.11              }
     4.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/SizeOfAMethodTest.java	Sat Feb 15 17:30:47 2014 +0100
     4.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/SizeOfAMethodTest.java	Sat Feb 15 20:18:26 2014 +0100
     4.3 @@ -23,6 +23,8 @@
     4.4  
     4.5  package org.apidesign.vm4brwsr;
     4.6  
     4.7 +import java.io.IOException;
     4.8 +import java.io.InputStream;
     4.9  import static org.testng.Assert.assertEquals;
    4.10  import static org.testng.Assert.assertTrue;
    4.11  import org.testng.annotations.AfterClass;
    4.12 @@ -34,26 +36,53 @@
    4.13   * @author Jaroslav Tulach <jtulach@netbeans.org>
    4.14   */
    4.15  public class SizeOfAMethodTest {
    4.16 -    private static TestVM code;
    4.17 +    private static String code;
    4.18  
    4.19      @Test public void sumXYShouldBeSmall() {
    4.20 -        String s = code.codeSeq().toString();
    4.21 +        String s = code;
    4.22          int beg = s.indexOf("c.sum__III");
    4.23          int end = s.indexOf("c.sum__III.access");
    4.24          
    4.25 -        assertTrue(beg > 0, "Found sum method in " + code.toString());
    4.26 -        assertTrue(beg < end, "Found end of sum method in " + code.toString());
    4.27 +        assertTrue(beg > 0, "Found sum method in " + code);
    4.28 +        assertTrue(beg < end, "Found end of sum method in " + code);
    4.29          
    4.30          String method = s.substring(beg, end);
    4.31          
    4.32 +        
    4.33 +        assertEquals(method.indexOf("st"), -1, "There should be no stack operations:\n" + method);
    4.34 +    }
    4.35 +
    4.36 +    @Test public void emptyConstructorRequiresNoStack() {
    4.37 +        String s = code;
    4.38 +        int beg = s.indexOf("CLS.cons__V");
    4.39 +        int end = s.indexOf("CLS.cons__V.access");
    4.40 +        
    4.41 +        assertTrue(beg > 0, "Found constructor in " + code);
    4.42 +        assertTrue(beg < end, "Found end of constructor in " + code);
    4.43 +        
    4.44 +        String method = s.substring(beg, end);
    4.45 +        method = method.replace("constructor", "CNSTR");
    4.46 +        
    4.47          assertEquals(method.indexOf("st"), -1, "There should be no stack operations:\n" + method);
    4.48      }
    4.49      
    4.50      
    4.51      @BeforeClass 
    4.52      public static void compileTheCode() throws Exception {
    4.53 +        final String res = "org/apidesign/vm4brwsr/StaticMethod";
    4.54          StringBuilder sb = new StringBuilder();
    4.55 -        code = TestVM.compileClass(sb, "org/apidesign/vm4brwsr/StaticMethod");
    4.56 +        class JustStaticMethod implements Bck2Brwsr.Resources {
    4.57 +            @Override
    4.58 +            public InputStream get(String resource) throws IOException {
    4.59 +                final String cn = res + ".class";
    4.60 +                if (resource.equals(cn)) {
    4.61 +                    return getClass().getClassLoader().getResourceAsStream(cn);
    4.62 +                }
    4.63 +                return null;
    4.64 +            }
    4.65 +        }
    4.66 +        Bck2Brwsr.generate(sb, new JustStaticMethod(), res);
    4.67 +        code = sb.toString();
    4.68      }
    4.69      @AfterClass
    4.70      public static void releaseTheCode() {