vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
branchregisters
changeset 282 a98d6c5a545e
parent 281 f2352e0b713e
parent 272 a6a23aa7a546
child 283 51043a802035
     1.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Fri Dec 07 15:02:35 2012 +0100
     1.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Fri Dec 07 15:57:14 2012 +0100
     1.3 @@ -32,7 +32,7 @@
     1.4   */
     1.5  public abstract class ByteCodeToJavaScript {
     1.6      private ClassData jc;
     1.7 -    private final Appendable out;
     1.8 +    final Appendable out;
     1.9  
    1.10      protected ByteCodeToJavaScript(Appendable out) {
    1.11          this.out = out;
    1.12 @@ -99,12 +99,15 @@
    1.13          }
    1.14          if (proto == null) {
    1.15              String sc = jc.getSuperClassName(); // with _
    1.16 -            out.append("\n    var p = CLS.prototype = ").
    1.17 +            out.append("\n    var pp = ").
    1.18                  append(sc.replace('/', '_')).append("(true);");
    1.19 +            out.append("\n    var p = CLS.prototype = pp;");
    1.20              out.append("\n    var c = p;");
    1.21 +            out.append("\n    var sprcls = pp.constructor.$class;");
    1.22          } else {
    1.23              out.append("\n    var p = CLS.prototype = ").append(proto[1]).append(";");
    1.24              out.append("\n    var c = ").append(proto[0]).append(";");
    1.25 +            out.append("\n    var sprcls = null;");
    1.26          }
    1.27          for (MethodData m : jc.getMethods()) {
    1.28              byte[] onlyArr = m.findAnnotationData(true);
    1.29 @@ -119,10 +122,17 @@
    1.30                  }
    1.31                  continue;
    1.32              }
    1.33 +            String mn;
    1.34              if (m.isStatic()) {
    1.35 -                generateStaticMethod("\n    c.", m, toInitilize);
    1.36 +                mn = generateStaticMethod("\n    c.", m, toInitilize);
    1.37              } else {
    1.38 -                generateInstanceMethod("\n    c.", m);
    1.39 +                mn = generateInstanceMethod("\n    c.", m);
    1.40 +            }
    1.41 +            byte[] runAnno = m.findAnnotationData(false);
    1.42 +            if (runAnno != null) {
    1.43 +                out.append("\n    c.").append(mn).append(".anno = {");
    1.44 +                generateAnno(jc, out, runAnno);
    1.45 +                out.append("\n    };");
    1.46              }
    1.47          }
    1.48          out.append("\n    c.constructor = CLS;");
    1.49 @@ -130,6 +140,16 @@
    1.50          for (String superInterface : jc.getSuperInterfaces()) {
    1.51              out.append("\n    c.$instOf_").append(superInterface.replace('/', '_')).append(" = true;");
    1.52          }
    1.53 +        out.append("\n    CLS.$class = java_lang_Class(true);");
    1.54 +        out.append("\n    CLS.$class.jvmName = '").append(jc.getClassName()).append("';");
    1.55 +        out.append("\n    CLS.$class.superclass = sprcls;");
    1.56 +        out.append("\n    CLS.$class.cnstr = CLS;");
    1.57 +        byte[] classAnno = jc.findAnnotationData(false);
    1.58 +        if (classAnno != null) {
    1.59 +            out.append("\n    CLS.$class.anno = {");
    1.60 +            generateAnno(jc, out, classAnno);
    1.61 +            out.append("\n    };");
    1.62 +        }
    1.63          out.append("\n  }");
    1.64          out.append("\n  if (arguments.length === 0) {");
    1.65          out.append("\n    if (!(this instanceof CLS)) {");
    1.66 @@ -163,14 +183,15 @@
    1.67          }
    1.68          return sb.toString();
    1.69      }
    1.70 -    private void generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException {
    1.71 -        if (javaScriptBody(prefix, m, true)) {
    1.72 -            return;
    1.73 +    private String generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException {
    1.74 +        String jsb = javaScriptBody(prefix, m, true);
    1.75 +        if (jsb != null) {
    1.76 +            return jsb;
    1.77          }
    1.78          StringBuilder argsCnt = new StringBuilder();
    1.79          final String mn = findMethodName(m, argsCnt);
    1.80          out.append(prefix).append(mn).append(" = function");
    1.81 -        if (mn.equals("classV")) {
    1.82 +        if (mn.equals("class__V")) {
    1.83              toInitilize.add(className(jc) + "(false)." + mn);
    1.84          }
    1.85          out.append('(');
    1.86 @@ -198,11 +219,13 @@
    1.87              out.append("  throw 'no code found for ").append(m.getInternalSig()).append("';\n");
    1.88          }
    1.89          out.append("};");
    1.90 +        return mn;
    1.91      }
    1.92      
    1.93 -    private void generateInstanceMethod(String prefix, MethodData m) throws IOException {
    1.94 -        if (javaScriptBody(prefix, m, false)) {
    1.95 -            return;
    1.96 +    private String generateInstanceMethod(String prefix, MethodData m) throws IOException {
    1.97 +        String jsb = javaScriptBody(prefix, m, false);
    1.98 +        if (jsb != null) {
    1.99 +            return jsb;
   1.100          }
   1.101          StringBuilder argsCnt = new StringBuilder();
   1.102          final String mn = findMethodName(m, argsCnt);
   1.103 @@ -230,6 +253,7 @@
   1.104              out.append("  throw 'no code found for ").append(m.getInternalSig()).append("';\n");
   1.105          }
   1.106          out.append("};");
   1.107 +        return mn;
   1.108      }
   1.109  
   1.110      private void produceCode(MethodData m) throws IOException {
   1.111 @@ -1288,6 +1312,7 @@
   1.112          int i = 0;
   1.113          Boolean count = null;
   1.114          boolean array = false;
   1.115 +        sig.append("__");
   1.116          int firstPos = sig.length();
   1.117          while (i < descriptor.length()) {
   1.118              char ch = descriptor.charAt(i++);
   1.119 @@ -1298,9 +1323,6 @@
   1.120                  case ')':
   1.121                      count = false;
   1.122                      continue;
   1.123 -                case 'A':
   1.124 -                    array = true;
   1.125 -                    break;
   1.126                  case 'B': 
   1.127                  case 'C': 
   1.128                  case 'D': 
   1.129 @@ -1311,7 +1333,7 @@
   1.130                  case 'Z': 
   1.131                      if (count) {
   1.132                          if (array) {
   1.133 -                            sig.append('A');
   1.134 +                            sig.append("_3");
   1.135                          }
   1.136                          sig.append(ch);
   1.137                          if (ch == 'J' || ch == 'D') {
   1.138 @@ -1323,7 +1345,7 @@
   1.139                          sig.insert(firstPos, ch);
   1.140                          if (array) {
   1.141                              returnType[0] = '[';
   1.142 -                            sig.insert(firstPos, 'A');
   1.143 +                            sig.insert(firstPos, "_3");
   1.144                          } else {
   1.145                              returnType[0] = ch;
   1.146                          }
   1.147 @@ -1337,33 +1359,47 @@
   1.148                      continue;
   1.149                  case 'L':
   1.150                      int next = descriptor.indexOf(';', i);
   1.151 +                    String realSig = mangleSig(descriptor, i - 1, next + 1);
   1.152                      if (count) {
   1.153                          if (array) {
   1.154 -                            sig.append('A');
   1.155 +                            sig.append("_3");
   1.156                          }
   1.157 -                        sig.append(ch);
   1.158 -                        sig.append(descriptor.substring(i, next).replace('/', '_'));
   1.159 +                        sig.append(realSig);
   1.160                          cnt.append('0');
   1.161                      } else {
   1.162 -                        sig.insert(firstPos, descriptor.substring(i, next).replace('/', '_'));
   1.163 -                        sig.insert(firstPos, ch);
   1.164 +                        sig.insert(firstPos, realSig);
   1.165                          if (array) {
   1.166 -                            sig.insert(firstPos, 'A');
   1.167 +                            sig.insert(firstPos, "_3");
   1.168                          }
   1.169                          returnType[0] = 'L';
   1.170                      }
   1.171                      i = next + 1;
   1.172                      continue;
   1.173                  case '[':
   1.174 -                    //arrays++;
   1.175 +                    array = true;
   1.176                      continue;
   1.177                  default:
   1.178 -                    break; // invalid character
   1.179 +                    throw new IllegalStateException("Invalid char: " + ch);
   1.180              }
   1.181          }
   1.182      }
   1.183 +    
   1.184 +    private static String mangleSig(String txt, int first, int last) {
   1.185 +        StringBuilder sb = new StringBuilder();
   1.186 +        for (int i = first; i < last; i++) {
   1.187 +            final char ch = txt.charAt(i);
   1.188 +            switch (ch) {
   1.189 +                case '/': sb.append('_'); break;
   1.190 +                case '_': sb.append("_1"); break;
   1.191 +                case ';': sb.append("_2"); break;
   1.192 +                case '[': sb.append("_3"); break;
   1.193 +                default: sb.append(ch); break;
   1.194 +            }
   1.195 +        }
   1.196 +        return sb.toString();
   1.197 +    }
   1.198  
   1.199 -    private String findMethodName(MethodData m, StringBuilder cnt) {
   1.200 +    private static String findMethodName(MethodData m, StringBuilder cnt) {
   1.201          StringBuilder name = new StringBuilder();
   1.202          if ("<init>".equals(m.getName())) { // NOI18N
   1.203              name.append("cons"); // NOI18N
   1.204 @@ -1373,11 +1409,11 @@
   1.205              name.append(m.getName());
   1.206          } 
   1.207          
   1.208 -        countArgs(findDescriptor(m.getInternalSig()), new char[1], name, cnt);
   1.209 +        countArgs(m.getInternalSig(), new char[1], name, cnt);
   1.210          return name.toString();
   1.211      }
   1.212  
   1.213 -    private String findMethodName(String[] mi, StringBuilder cnt, char[] returnType) {
   1.214 +    static String findMethodName(String[] mi, StringBuilder cnt, char[] returnType) {
   1.215          StringBuilder name = new StringBuilder();
   1.216          String descr = mi[2];//mi.getDescriptor();
   1.217          String nm= mi[1];
   1.218 @@ -1386,7 +1422,7 @@
   1.219          } else {
   1.220              name.append(nm);
   1.221          }
   1.222 -        countArgs(findDescriptor(descr), returnType, name, cnt);
   1.223 +        countArgs(descr, returnType, name, cnt);
   1.224          return name.toString();
   1.225      }
   1.226  
   1.227 @@ -1480,28 +1516,32 @@
   1.228          }
   1.229      }
   1.230  
   1.231 -    private String encodeConstant(int entryIndex) {
   1.232 -        String s = jc.stringValue(entryIndex, true);
   1.233 +    private String encodeConstant(int entryIndex) throws IOException {
   1.234 +        String[] classRef = { null };
   1.235 +        String s = jc.stringValue(entryIndex, classRef);
   1.236 +        if (classRef[0] != null) {
   1.237 +            addReference(classRef[0]);
   1.238 +        }
   1.239          return s;
   1.240      }
   1.241  
   1.242 -    private String findDescriptor(String d) {
   1.243 -        return d.replace('[', 'A');
   1.244 -    }
   1.245 -
   1.246 -    private boolean javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException {
   1.247 +    private String javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException {
   1.248          byte[] arr = m.findAnnotationData(true);
   1.249          if (arr == null) {
   1.250 -            return false;
   1.251 +            return null;
   1.252          }
   1.253          final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;";
   1.254          class P extends AnnotationParser {
   1.255 +            public P() {
   1.256 +                super(false);
   1.257 +            }
   1.258 +            
   1.259              int cnt;
   1.260              String[] args = new String[30];
   1.261              String body;
   1.262              
   1.263              @Override
   1.264 -            protected void visitAttr(String type, String attr, String value) {
   1.265 +            protected void visitAttr(String type, String attr, String at, String value) {
   1.266                  if (type.equals(jvmType)) {
   1.267                      if ("body".equals(attr)) {
   1.268                          body = value;
   1.269 @@ -1516,10 +1556,11 @@
   1.270          P p = new P();
   1.271          p.parse(arr, jc);
   1.272          if (p.body == null) {
   1.273 -            return false;
   1.274 +            return null;
   1.275          }
   1.276          StringBuilder cnt = new StringBuilder();
   1.277 -        out.append(prefix).append(findMethodName(m, cnt));
   1.278 +        final String mn = findMethodName(m, cnt);
   1.279 +        out.append(prefix).append(mn);
   1.280          out.append(" = function(");
   1.281          String space;
   1.282          int index;
   1.283 @@ -1540,7 +1581,7 @@
   1.284          out.append(") {").append("\n");
   1.285          out.append(p.body);
   1.286          out.append("\n}\n");
   1.287 -        return true;
   1.288 +        return mn;
   1.289      }
   1.290      private static String className(ClassData jc) {
   1.291          //return jc.getName().getInternalName().replace('/', '_');
   1.292 @@ -1557,9 +1598,9 @@
   1.293          final String[] values = new String[attrNames.length];
   1.294          final boolean[] found = { false };
   1.295          final String jvmType = "L" + className.replace('.', '/') + ";";
   1.296 -        AnnotationParser ap = new AnnotationParser() {
   1.297 +        AnnotationParser ap = new AnnotationParser(false) {
   1.298              @Override
   1.299 -            protected void visitAttr(String type, String attr, String value) {
   1.300 +            protected void visitAttr(String type, String attr, String at, String value) {
   1.301                  if (type.equals(jvmType)) {
   1.302                      found[0] = true;
   1.303                      for (int i = 0; i < attrNames.length; i++) {
   1.304 @@ -1594,6 +1635,40 @@
   1.305          return " = null;";
   1.306      }
   1.307  
   1.308 +    private static void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException {
   1.309 +        AnnotationParser ap = new AnnotationParser(true) {
   1.310 +            int anno;
   1.311 +            int cnt;
   1.312 +            
   1.313 +            @Override
   1.314 +            protected void visitAnnotationStart(String type) throws IOException {
   1.315 +                if (anno++ > 0) {
   1.316 +                    out.append(",");
   1.317 +                }
   1.318 +                out.append('"').append(type).append("\" : {\n");
   1.319 +                cnt = 0;
   1.320 +            }
   1.321 +
   1.322 +            @Override
   1.323 +            protected void visitAnnotationEnd(String type) throws IOException {
   1.324 +                out.append("\n}\n");
   1.325 +            }
   1.326 +            
   1.327 +            @Override
   1.328 +            protected void visitAttr(String type, String attr, String attrType, String value) 
   1.329 +            throws IOException {
   1.330 +                if (attr == null) {
   1.331 +                    return;
   1.332 +                }
   1.333 +                if (cnt++ > 0) {
   1.334 +                    out.append(",\n");
   1.335 +                }
   1.336 +                out.append(attr).append("__").append(attrType).append(" : ").append(value);
   1.337 +            }
   1.338 +        };
   1.339 +        ap.parse(data, cd);
   1.340 +    }
   1.341 +
   1.342      private static int constantToVariableType(final byte constantTag) {
   1.343          switch (constantTag) {
   1.344              case CONSTANT_INTEGER: