1.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Mon May 06 18:06:08 2013 +0200
1.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Tue May 07 19:01:14 2013 +0200
1.3 @@ -2034,6 +2034,30 @@
1.4 return getNameAndType(c2.cpx2, 1, arr);
1.5 }
1.6
1.7 + public MethodData findMethod(String name, String signature) {
1.8 + for (MethodData md: methods) {
1.9 + if (md.getName().equals(name)
1.10 + && md.getInternalSig().equals(signature)) {
1.11 + return md;
1.12 + }
1.13 + }
1.14 +
1.15 + // not found
1.16 + return null;
1.17 + }
1.18 +
1.19 + public FieldData findField(String name, String signature) {
1.20 + for (FieldData fd: fields) {
1.21 + if (fd.getName().equals(name)
1.22 + && fd.getInternalSig().equals(signature)) {
1.23 + return fd;
1.24 + }
1.25 + }
1.26 +
1.27 + // not found
1.28 + return null;
1.29 + }
1.30 +
1.31 static byte[] findAttr(String n, AttrData[] attrs) {
1.32 for (AttrData ad : attrs) {
1.33 if (n.equals(ad.getAttrName())) {
2.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon May 06 18:06:08 2013 +0200
2.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue May 07 19:01:14 2013 +0200
2.3 @@ -59,8 +59,22 @@
2.4 return classOperation;
2.5 }
2.6
2.7 - protected String accessMember(String object, String mangledName,
2.8 - String[] fieldInfoName) throws IOException {
2.9 + protected String accessField(String object, String mangledName,
2.10 + String[] fieldInfoName) throws IOException {
2.11 + return object + "." + mangledName;
2.12 + }
2.13 +
2.14 + protected String accessStaticMethod(
2.15 + String object,
2.16 + String mangledName,
2.17 + String[] fieldInfoName) throws IOException {
2.18 + return object + "." + mangledName;
2.19 + }
2.20 +
2.21 + protected String accessVirtualMethod(
2.22 + String object,
2.23 + String mangledName,
2.24 + String[] fieldInfoName) throws IOException {
2.25 return object + "." + mangledName;
2.26 }
2.27
2.28 @@ -1207,8 +1221,8 @@
2.29 emit(out, "var @2 = @3.call(@1);",
2.30 smapper.popA(),
2.31 smapper.pushT(type),
2.32 - accessMember(mangleClassAccess + "(false)",
2.33 - "_" + fi[1], fi));
2.34 + accessField(mangleClassAccess + "(false)",
2.35 + "_" + fi[1], fi));
2.36 i += 2;
2.37 break;
2.38 }
2.39 @@ -1221,8 +1235,8 @@
2.40 emit(out, "@3.call(@2, @1);",
2.41 smapper.popT(type),
2.42 smapper.popA(),
2.43 - accessMember(mangleClassAccess + "(false)",
2.44 - "_" + fi[1], fi));
2.45 + accessField(mangleClassAccess + "(false)",
2.46 + "_" + fi[1], fi));
2.47 i += 2;
2.48 break;
2.49 }
2.50 @@ -1232,9 +1246,9 @@
2.51 final int type = VarType.fromFieldType(fi[2].charAt(0));
2.52 emit(out, "var @1 = @2();",
2.53 smapper.pushT(type),
2.54 - accessMember(accessClass(fi[0].replace('/', '_'))
2.55 - + "(false)",
2.56 - "_" + fi[1], fi));
2.57 + accessField(accessClass(fi[0].replace('/', '_'))
2.58 + + "(false)",
2.59 + "_" + fi[1], fi));
2.60 i += 2;
2.61 addReference(fi[0]);
2.62 break;
2.63 @@ -1244,9 +1258,9 @@
2.64 String[] fi = jc.getFieldInfoName(indx);
2.65 final int type = VarType.fromFieldType(fi[2].charAt(0));
2.66 emit(out, "@1(@2);",
2.67 - accessMember(accessClass(fi[0].replace('/', '_'))
2.68 - + "(false)",
2.69 - "_" + fi[1], fi),
2.70 + accessField(accessClass(fi[0].replace('/', '_'))
2.71 + + "(false)",
2.72 + "_" + fi[1], fi),
2.73 smapper.popT(type));
2.74 i += 2;
2.75 addReference(fi[0]);
2.76 @@ -1492,7 +1506,7 @@
2.77 }
2.78
2.79 final String in = mi[0];
2.80 - out.append(accessMember(
2.81 + out.append(accessStaticMethod(
2.82 accessClass(in.replace('/', '_')) + "(false)",
2.83 mn.startsWith("cons_")
2.84 ? "constructor." + mn
2.85 @@ -1536,7 +1550,7 @@
2.86 .append(" = ");
2.87 }
2.88
2.89 - out.append(accessMember(vars[0].toString(), mn, mi));
2.90 + out.append(accessVirtualMethod(vars[0].toString(), mn, mi));
2.91 out.append('(');
2.92 String sep = "";
2.93 for (int j = 1; j < numArguments; ++j) {
3.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassDataCache.java Mon May 06 18:06:08 2013 +0200
3.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassDataCache.java Tue May 07 19:01:14 2013 +0200
3.3 @@ -23,6 +23,8 @@
3.4 import java.util.Map;
3.5 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
3.6 import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
3.7 +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
3.8 +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
3.9
3.10 @ExtraJavaScript(processByteCode = false, resource="")
3.11 final class ClassDataCache {
3.12 @@ -37,7 +39,12 @@
3.13 classDataMap = new HashMap<String, Object>();
3.14 }
3.15
3.16 - ClassData getClassData(final String className) throws IOException {
3.17 + ClassData getClassData(String className) throws IOException {
3.18 + if (className.startsWith("[")) {
3.19 + // required for accessVirtualMethod, shouldn't be problematic for
3.20 + // calls from other sources
3.21 + className = "java/lang/Object";
3.22 + }
3.23 Object cacheEntry = classDataMap.get(className);
3.24 if (cacheEntry == null) {
3.25 final InputStream is = loadClass(resources, className);
3.26 @@ -48,6 +55,58 @@
3.27 return (cacheEntry != MISSING_CLASS) ? (ClassData) cacheEntry : null;
3.28 }
3.29
3.30 + MethodData findMethod(final String startingClass,
3.31 + final String name,
3.32 + final String signature) throws IOException {
3.33 + return findMethod(getClassData(startingClass), name, signature);
3.34 + }
3.35 +
3.36 + FieldData findField(final String startingClass,
3.37 + final String name,
3.38 + final String signature) throws IOException {
3.39 + return findField(getClassData(startingClass), name, signature);
3.40 + }
3.41 +
3.42 + MethodData findMethod(ClassData currentClass,
3.43 + final String name,
3.44 + final String signature) throws IOException {
3.45 + while (currentClass != null) {
3.46 + final MethodData methodData =
3.47 + currentClass.findMethod(name, signature);
3.48 + if (methodData != null) {
3.49 + return methodData;
3.50 + }
3.51 +
3.52 + final String superClassName = currentClass.getSuperClassName();
3.53 + if (superClassName == null) {
3.54 + break;
3.55 + }
3.56 + currentClass = getClassData(superClassName);
3.57 + }
3.58 +
3.59 + return null;
3.60 + }
3.61 +
3.62 + FieldData findField(ClassData currentClass,
3.63 + final String name,
3.64 + final String signature) throws IOException {
3.65 + while (currentClass != null) {
3.66 + final FieldData fieldData =
3.67 + currentClass.findField(name, signature);
3.68 + if (fieldData != null) {
3.69 + return fieldData;
3.70 + }
3.71 +
3.72 + final String superClassName = currentClass.getSuperClassName();
3.73 + if (superClassName == null) {
3.74 + break;
3.75 + }
3.76 + currentClass = getClassData(superClassName);
3.77 + }
3.78 +
3.79 + return null;
3.80 + }
3.81 +
3.82 private static InputStream loadClass(Bck2Brwsr.Resources l, String name)
3.83 throws IOException {
3.84 return l.get(name + ".class"); // NOI18N
4.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Mon May 06 18:06:08 2013 +0200
4.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Tue May 07 19:01:14 2013 +0200
4.3 @@ -32,12 +32,14 @@
4.4
4.5 private final Bck2Brwsr.Resources resources;
4.6 private final ExportedSymbols exportedSymbols;
4.7 + private final StringArray invokerMethods;
4.8
4.9 private VM(Appendable out, Bck2Brwsr.Resources resources) {
4.10 super(out);
4.11 this.resources = resources;
4.12 this.classDataCache = new ClassDataCache(resources);
4.13 this.exportedSymbols = new ExportedSymbols(resources);
4.14 + this.invokerMethods = new StringArray();
4.15 }
4.16
4.17 static {
4.18 @@ -67,7 +69,20 @@
4.19
4.20 private void doCompile(StringArray names) throws IOException {
4.21 generatePrologue();
4.22 + out.append(
4.23 + "\n var invoker = function Invoker() {"
4.24 + + "\n return Invoker.target[Invoker.method]"
4.25 + + ".apply(Invoker.target, arguments);"
4.26 + + "\n };");
4.27 generateBody(names);
4.28 + for (String invokerMethod: invokerMethods.toArray()) {
4.29 + out.append("\n invoker." + invokerMethod + " = function(target) {"
4.30 + + "\n invoker.target = target;"
4.31 + + "\n invoker.method = '" + invokerMethod + "';"
4.32 + + "\n return invoker;"
4.33 + + "\n };");
4.34 + }
4.35 + out.append("\n");
4.36 generateEpilogue();
4.37 }
4.38
4.39 @@ -268,16 +283,64 @@
4.40 }
4.41
4.42 @Override
4.43 - protected String accessMember(String object, String mangledName,
4.44 - String[] fieldInfoName) throws IOException {
4.45 - final ClassData declaringClass =
4.46 + protected String accessField(String object, String mangledName,
4.47 + String[] fieldInfoName) throws IOException {
4.48 + final FieldData field =
4.49 + classDataCache.findField(fieldInfoName[0],
4.50 + fieldInfoName[1],
4.51 + fieldInfoName[2]);
4.52 + return accessNonVirtualMember(object, mangledName,
4.53 + (field != null) ? field.cls : null);
4.54 + }
4.55 +
4.56 + @Override
4.57 + protected String accessStaticMethod(
4.58 + String object,
4.59 + String mangledName,
4.60 + String[] fieldInfoName) throws IOException {
4.61 + final MethodData method =
4.62 + classDataCache.findMethod(fieldInfoName[0],
4.63 + fieldInfoName[1],
4.64 + fieldInfoName[2]);
4.65 + return accessNonVirtualMember(object, mangledName,
4.66 + (method != null) ? method.cls : null);
4.67 + }
4.68 +
4.69 + @Override
4.70 + protected String accessVirtualMethod(
4.71 + String object,
4.72 + String mangledName,
4.73 + String[] fieldInfoName) throws IOException {
4.74 + final ClassData referencedClass =
4.75 classDataCache.getClassData(fieldInfoName[0]);
4.76 - if (declaringClass == null) {
4.77 - return object + "['" + mangledName + "']";
4.78 + final MethodData method =
4.79 + classDataCache.findMethod(referencedClass,
4.80 + fieldInfoName[1],
4.81 + fieldInfoName[2]);
4.82 +
4.83 + if ((method != null)
4.84 + && (((method.access & ByteCodeParser.ACC_FINAL) != 0)
4.85 + || ((referencedClass.getAccessFlags()
4.86 + & ByteCodeParser.ACC_FINAL) != 0)
4.87 + || !exportedSymbols.isExported(method))) {
4.88 + return object + "." + mangledName;
4.89 }
4.90
4.91 - // TODO
4.92 - return object + "." + mangledName;
4.93 + return accessThroughInvoker(object, mangledName);
4.94 + }
4.95 +
4.96 + private String accessThroughInvoker(String object, String mangledName) {
4.97 + if (!invokerMethods.contains(mangledName)) {
4.98 + invokerMethods.add(mangledName);
4.99 + }
4.100 + return "invoker." + mangledName + '(' + object + ')';
4.101 + }
4.102 +
4.103 + private static String accessNonVirtualMember(String object,
4.104 + String mangledName,
4.105 + ClassData declaringClass) {
4.106 + return (declaringClass != null) ? object + "." + mangledName
4.107 + : object + "['" + mangledName + "']";
4.108 }
4.109
4.110 private static final class Standalone extends VM {