src/main/java/org/apidesign/java4browser/ByteCodeToJavaScript.java
changeset 10 e84d9314f1bc
parent 9 0cab1e07e677
child 11 eca88b77b986
     1.1 --- a/src/main/java/org/apidesign/java4browser/ByteCodeToJavaScript.java	Sun Sep 16 07:28:57 2012 +0200
     1.2 +++ b/src/main/java/org/apidesign/java4browser/ByteCodeToJavaScript.java	Sun Sep 16 18:35:16 2012 +0200
     1.3 @@ -24,7 +24,6 @@
     1.4  import org.netbeans.modules.classfile.CPClassInfo;
     1.5  import org.netbeans.modules.classfile.CPEntry;
     1.6  import org.netbeans.modules.classfile.CPFieldInfo;
     1.7 -import org.netbeans.modules.classfile.CPLongInfo;
     1.8  import org.netbeans.modules.classfile.CPMethodInfo;
     1.9  import org.netbeans.modules.classfile.ClassFile;
    1.10  import org.netbeans.modules.classfile.Code;
    1.11 @@ -57,6 +56,8 @@
    1.12          for (Method m : jc.getMethods()) {
    1.13              if (m.isStatic()) {
    1.14                  compiler.generateStaticMethod(m);
    1.15 +            } else {
    1.16 +                compiler.generateInstanceMethod(m);
    1.17              }
    1.18          }
    1.19          for (Variable v : jc.getVariables()) {
    1.20 @@ -64,20 +65,29 @@
    1.21                  compiler.generateStaticField(v);
    1.22              }
    1.23          }
    1.24 +        out.append("function java_lang_Object_consV(self){}\n"); // XXX temporary
    1.25 +        
    1.26 +        out.append("\nfunction ").append(jc.getName().getExternalName().replace('.', '_'));
    1.27 +        out.append("() {");
    1.28 +        for (Method m : jc.getMethods()) {
    1.29 +            if (!m.isStatic()) {
    1.30 +                
    1.31 +            }
    1.32 +        }
    1.33 +        for (Variable v : jc.getVariables()) {
    1.34 +            if (!v.isStatic()) {
    1.35 +                out.append("\n  this." + v.getName() + " = 0;");
    1.36 +            }
    1.37 +        }
    1.38 +        out.append("\n}");
    1.39      }
    1.40      private void generateStaticMethod(Method m) throws IOException {
    1.41          out.append("\nfunction ").append(
    1.42              jc.getName().getExternalName().replace('.', '_')
    1.43 -        ).append('_').append(
    1.44 -            m.getName()
    1.45 -        );
    1.46 -        out.append(m.getReturnType());
    1.47 -        List<Parameter> args = m.getParameters();
    1.48 -        for (Parameter t : args) {
    1.49 -            out.append(t.getDescriptor());
    1.50 -        }
    1.51 +        ).append('_').append(findMethodName(m));
    1.52          out.append('(');
    1.53          String space = "";
    1.54 +        List<Parameter> args = m.getParameters();
    1.55          for (int index = 0, i = 0; i < args.size(); i++) {
    1.56              out.append(space);
    1.57              out.append("arg").append(String.valueOf(index));
    1.58 @@ -96,6 +106,37 @@
    1.59              out.append("  var ");
    1.60              out.append("arg").append(String.valueOf(i)).append(";\n");
    1.61          }
    1.62 +        out.append("  var stack = new Array(");
    1.63 +        out.append(Integer.toString(code.getMaxStack()));
    1.64 +        out.append(");\n");
    1.65 +        produceCode(code.getByteCodes());
    1.66 +        out.append("}");
    1.67 +    }
    1.68 +    
    1.69 +    private void generateInstanceMethod(Method m) throws IOException {
    1.70 +        out.append("\nfunction ").append(
    1.71 +            jc.getName().getExternalName().replace('.', '_')
    1.72 +        ).append('_').append(findMethodName(m));
    1.73 +        out.append("(arg0");
    1.74 +        String space = ",";
    1.75 +        List<Parameter> args = m.getParameters();
    1.76 +        for (int index = 1, i = 0; i < args.size(); i++) {
    1.77 +            out.append(space);
    1.78 +            out.append("arg").append(String.valueOf(index));
    1.79 +            final String desc = args.get(i).getDescriptor();
    1.80 +            if ("D".equals(desc) || "J".equals(desc)) {
    1.81 +                index += 2;
    1.82 +            } else {
    1.83 +                index++;
    1.84 +            }
    1.85 +        }
    1.86 +        out.append(") {").append("\n");
    1.87 +        final Code code = m.getCode();
    1.88 +        int len = code.getMaxLocals();
    1.89 +        for (int index = args.size(), i = args.size(); i < len; i++) {
    1.90 +            out.append("  var ");
    1.91 +            out.append("arg").append(String.valueOf(i + 1)).append(";\n");
    1.92 +        }
    1.93          out.append(";\n  var stack = new Array(");
    1.94          out.append(Integer.toString(code.getMaxStack()));
    1.95          out.append(");\n");
    1.96 @@ -104,10 +145,10 @@
    1.97      }
    1.98  
    1.99      private void produceCode(byte[] byteCodes) throws IOException {
   1.100 -        out.append("\nvar gt = 0;\nfor(;;) switch(gt) {\n");
   1.101 +        out.append("\n  var gt = 0;\n  for(;;) switch(gt) {\n");
   1.102          for (int i = 0; i < byteCodes.length; i++) {
   1.103              int prev = i;
   1.104 -            out.append("  case " + i).append(": ");
   1.105 +            out.append("    case " + i).append(": ");
   1.106              final int c = (byteCodes[i] + 256) % 256;
   1.107              switch (c) {
   1.108                  case bc_aload_0:
   1.109 @@ -223,10 +264,14 @@
   1.110                      }
   1.111                      break;
   1.112                  }
   1.113 +                case bc_return:
   1.114 +                    out.append("return;");
   1.115 +                    break;
   1.116                  case bc_ireturn:
   1.117                  case bc_lreturn:
   1.118                  case bc_freturn:
   1.119                  case bc_dreturn:
   1.120 +                case bc_areturn:
   1.121                      out.append("return stack.pop();");
   1.122                      break;
   1.123                  case bc_i2l:
   1.124 @@ -316,41 +361,18 @@
   1.125                      i += 2;
   1.126                      break;
   1.127                  }
   1.128 -                case bc_invokestatic: {
   1.129 -                    int methodIndex = readIntArg(byteCodes, i);
   1.130 -                    CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex);
   1.131 -                    boolean[] hasReturn = { false };
   1.132 -                    StringBuilder signature = new StringBuilder();
   1.133 -                    int cnt = countArgs(mi.getDescriptor(), hasReturn, signature);
   1.134 -                    
   1.135 -                    if (hasReturn[0]) {
   1.136 -                        out.append("stack.push(");
   1.137 -                    }
   1.138 -                    out.append(mi.getClassName().getInternalName().replace('/', '_'));
   1.139 -                    out.append('_');
   1.140 -                    out.append(mi.getName());
   1.141 -                    out.append(signature.toString());
   1.142 -                    out.append('(');
   1.143 -                    String sep = "";
   1.144 -                    for (int j = 0; j < cnt; j++) {
   1.145 -                        out.append(sep);
   1.146 -                        out.append("stack.pop()");
   1.147 -                        sep = ", ";
   1.148 -                    }
   1.149 -                    out.append(")");
   1.150 -                    if (hasReturn[0]) {
   1.151 -                        out.append(")");
   1.152 -                    }
   1.153 -                    out.append(";");
   1.154 -                    i += 2;
   1.155 +                case bc_invokespecial:
   1.156 +                    i = invokeStaticMethod(byteCodes, i, false);
   1.157                      break;
   1.158 -                }
   1.159 +                case bc_invokestatic:
   1.160 +                    i = invokeStaticMethod(byteCodes, i, true);
   1.161 +                    break;
   1.162                  case bc_new: {
   1.163                      int indx = readIntArg(byteCodes, i);
   1.164                      CPClassInfo ci = jc.getConstantPool().getClass(indx);
   1.165                      out.append("stack.push(");
   1.166                      out.append("new ").append(ci.getClassName().getExternalName().replace('.','_'));
   1.167 -                    out.append("());");
   1.168 +                    out.append(");");
   1.169                      i += 2;
   1.170                      break;
   1.171                  }
   1.172 @@ -360,14 +382,6 @@
   1.173                  case bc_bipush:
   1.174                      out.append("stack.push(" + byteCodes[++i] + ");");
   1.175                      break;
   1.176 -                case bc_invokevirtual:
   1.177 -                case bc_invokespecial: {
   1.178 -                    int indx = readIntArg(byteCodes, i);
   1.179 -                    CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(indx);
   1.180 -                    out.append("{ var tmp = stack.pop(); tmp." + mi.getMethodName() + "(); }");
   1.181 -                    i += 2;
   1.182 -                    break;
   1.183 -                }
   1.184                  case bc_getfield: {
   1.185                      int indx = readIntArg(byteCodes, i);
   1.186                      CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx);
   1.187 @@ -391,6 +405,14 @@
   1.188                      i += 2;
   1.189                      break;
   1.190                  }
   1.191 +                case bc_putfield: {
   1.192 +                    int indx = readIntArg(byteCodes, i);
   1.193 +                    CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx);
   1.194 +                    out.append("{ var v = stack.pop(); stack.pop().")
   1.195 +                       .append(fi.getFieldName()).append(" = v; }");
   1.196 +                    i += 2;
   1.197 +                    break;
   1.198 +                }
   1.199                      
   1.200              }
   1.201              out.append(" /*");
   1.202 @@ -401,7 +423,7 @@
   1.203              }
   1.204              out.append("*/\n");
   1.205          }
   1.206 -        out.append("}\n");
   1.207 +        out.append("  }\n");
   1.208      }
   1.209  
   1.210      private int generateIf(byte[] byteCodes, int i, final String test) throws IOException {
   1.211 @@ -421,6 +443,7 @@
   1.212          int cnt = 0;
   1.213          int i = 0;
   1.214          Boolean count = null;
   1.215 +        int firstPos = sig.length();
   1.216          while (i < descriptor.length()) {
   1.217              char ch = descriptor.charAt(i++);
   1.218              switch (ch) {
   1.219 @@ -443,13 +466,13 @@
   1.220                          sig.append(ch);
   1.221                      } else {
   1.222                          hasReturnType[0] = true;
   1.223 -                        sig.insert(0, ch);
   1.224 +                        sig.insert(firstPos, ch);
   1.225                      }
   1.226                      continue;
   1.227                  case 'V': 
   1.228                      assert !count;
   1.229                      hasReturnType[0] = false;
   1.230 -                    sig.insert(0, 'V');
   1.231 +                    sig.insert(firstPos, 'V');
   1.232                      continue;
   1.233                  case 'L':
   1.234                      i = descriptor.indexOf(';', i);
   1.235 @@ -474,4 +497,63 @@
   1.236             .append(jc.getName().getExternalName().replace('.', '_'))
   1.237             .append('_').append(v.getName()).append(" = 0;");
   1.238      }
   1.239 +
   1.240 +    private String findMethodName(Method m) {
   1.241 +        StringBuilder out = new StringBuilder();
   1.242 +        if ("<init>".equals(m.getName())) { // NOI18N
   1.243 +            out.append("consV"); // NOI18N
   1.244 +        } else {
   1.245 +            out.append(m.getName());
   1.246 +            out.append(m.getReturnType());
   1.247 +        } 
   1.248 +        List<Parameter> args = m.getParameters();
   1.249 +        for (Parameter t : args) {
   1.250 +            out.append(t.getDescriptor());
   1.251 +        }
   1.252 +        return out.toString();
   1.253 +    }
   1.254 +
   1.255 +    private String findMethodName(CPMethodInfo mi, int[] cnt, boolean[] hasReturn) {
   1.256 +        StringBuilder name = new StringBuilder();
   1.257 +        if ("<init>".equals(mi.getName())) { // NOI18N
   1.258 +            name.append("cons"); // NOI18N
   1.259 +        } else {
   1.260 +            name.append(mi.getName());
   1.261 +        }
   1.262 +        cnt[0] = countArgs(mi.getDescriptor(), hasReturn, name);
   1.263 +        return name.toString();
   1.264 +    }
   1.265 +
   1.266 +    private int invokeStaticMethod(byte[] byteCodes, int i, boolean isStatic)
   1.267 +    throws IOException {
   1.268 +        int methodIndex = readIntArg(byteCodes, i);
   1.269 +        CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex);
   1.270 +        boolean[] hasReturn = { false };
   1.271 +        int[] cnt = { 0 };
   1.272 +        String mn = findMethodName(mi, cnt, hasReturn);
   1.273 +        if (hasReturn[0]) {
   1.274 +            out.append("stack.push(");
   1.275 +        }
   1.276 +        out.append(mi.getClassName().getInternalName().replace('/', '_'));
   1.277 +        out.append('_');
   1.278 +        out.append(mn);
   1.279 +        out.append('(');
   1.280 +        String sep = "";
   1.281 +        if (!isStatic) {
   1.282 +            out.append("stack.pop()");
   1.283 +            sep = ", ";
   1.284 +        }
   1.285 +        for (int j = 0; j < cnt[0]; j++) {
   1.286 +            out.append(sep);
   1.287 +            out.append("stack.pop()");
   1.288 +            sep = ", ";
   1.289 +        }
   1.290 +        out.append(")");
   1.291 +        if (hasReturn[0]) {
   1.292 +            out.append(")");
   1.293 +        }
   1.294 +        out.append(";");
   1.295 +        i += 2;
   1.296 +        return i;
   1.297 +    }
   1.298  }