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: