# HG changeset patch # User Lubomir Nerad # Date 1368028067 -7200 # Node ID d868b5a67b9bf342e017ab04256a23c21d11af58 # Parent 2ac4283ee20931e825f25b7458b641743d308070 Exported annotation needs to be inherited for virtual methods diff -r 2ac4283ee209 -r d868b5a67b9b rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassDataCache.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassDataCache.java Wed May 08 14:54:32 2013 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassDataCache.java Wed May 08 17:47:47 2013 +0200 @@ -67,44 +67,143 @@ return findField(getClassData(startingClass), name, signature); } - MethodData findMethod(ClassData currentClass, + MethodData findMethod(final ClassData startingClass, final String name, final String signature) throws IOException { + final FindFirstTraversalCallback ffTraversalCallback = + new FindFirstTraversalCallback(); + + findMethods(startingClass, name, signature, ffTraversalCallback); + return ffTraversalCallback.getFirst(); + } + + FieldData findField(final ClassData startingClass, + final String name, + final String signature) throws IOException { + final FindFirstTraversalCallback ffTraversalCallback = + new FindFirstTraversalCallback(); + + findFields(startingClass, name, signature, ffTraversalCallback); + return ffTraversalCallback.getFirst(); + } + + void findMethods(final ClassData startingClass, + final String methodName, + final String methodSignature, + final TraversalCallback mdTraversalCallback) + throws IOException { + traverseHierarchy( + startingClass, + new FindMethodsTraversalCallback(methodName, methodSignature, + mdTraversalCallback)); + } + + void findFields(final ClassData startingClass, + final String fieldName, + final String fieldSignature, + final TraversalCallback fdTraversalCallback) + throws IOException { + traverseHierarchy( + startingClass, + new FindFieldsTraversalCallback(fieldName, fieldSignature, + fdTraversalCallback)); + } + + private boolean traverseHierarchy( + ClassData currentClass, + final TraversalCallback cdTraversalCallback) + throws IOException { while (currentClass != null) { - final MethodData methodData = - currentClass.findMethod(name, signature); - if (methodData != null) { - return methodData; + if (!cdTraversalCallback.traverse(currentClass)) { + return false; + } + + for (final String superIfaceName: + currentClass.getSuperInterfaces()) { + if (!traverseHierarchy(getClassData(superIfaceName), + cdTraversalCallback)) { + return false; + } } final String superClassName = currentClass.getSuperClassName(); if (superClassName == null) { break; } + currentClass = getClassData(superClassName); } - return null; + return true; } - FieldData findField(ClassData currentClass, - final String name, - final String signature) throws IOException { - while (currentClass != null) { - final FieldData fieldData = - currentClass.findField(name, signature); - if (fieldData != null) { - return fieldData; - } + interface TraversalCallback { + boolean traverse(T object); + } - final String superClassName = currentClass.getSuperClassName(); - if (superClassName == null) { - break; - } - currentClass = getClassData(superClassName); + private final class FindFirstTraversalCallback + implements TraversalCallback { + private T firstObject; + + @Override + public boolean traverse(final T object) { + firstObject = object; + return false; } - return null; + public T getFirst() { + return firstObject; + } + } + + private final class FindMethodsTraversalCallback + implements TraversalCallback { + private final String methodName; + private final String methodSignature; + private final TraversalCallback mdTraversalCallback; + + public FindMethodsTraversalCallback( + final String methodName, + final String methodSignature, + final TraversalCallback mdTraversalCallback) { + this.methodName = methodName; + this.methodSignature = methodSignature; + this.mdTraversalCallback = mdTraversalCallback; + } + + @Override + public boolean traverse(final ClassData classData) { + final MethodData methodData = + classData.findMethod(methodName, methodSignature); + return (methodData != null) + ? mdTraversalCallback.traverse(methodData) + : true; + } + } + + private final class FindFieldsTraversalCallback + implements TraversalCallback { + private final String fieldName; + private final String fieldSignature; + private final TraversalCallback fdTraversalCallback; + + public FindFieldsTraversalCallback( + final String fieldName, + final String fieldSignature, + final TraversalCallback fdTraversalCallback) { + this.fieldName = fieldName; + this.fieldSignature = fieldSignature; + this.fdTraversalCallback = fdTraversalCallback; + } + + @Override + public boolean traverse(final ClassData classData) { + final FieldData fieldData = + classData.findField(fieldName, fieldSignature); + return (fieldData != null) + ? fdTraversalCallback.traverse(fieldData) + : true; + } } private static InputStream loadClass(Bck2Brwsr.Resources l, String name) diff -r 2ac4283ee209 -r d868b5a67b9b rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Wed May 08 14:54:32 2013 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Wed May 08 17:47:47 2013 +0200 @@ -115,7 +115,7 @@ protected void declaredMethod(MethodData methodData, String destObject, String mangledName) throws IOException { - if (exportedSymbols.isExported(methodData)) { + if (isHierarchyExported(methodData)) { exportMember(destObject, mangledName); } } @@ -317,7 +317,7 @@ && (((method.access & ByteCodeParser.ACC_FINAL) != 0) || ((referencedClass.getAccessFlags() & ByteCodeParser.ACC_FINAL) != 0) - || !exportedSymbols.isExported(method))) { + || !isHierarchyExported(method))) { return object + "." + mangledName; } @@ -331,6 +331,28 @@ return "invoker." + mangledName + '(' + object + ')'; } + private boolean isHierarchyExported(final MethodData methodData) + throws IOException { + if (exportedSymbols.isExported(methodData)) { + return true; + } + if ((methodData.access & (ByteCodeParser.ACC_PRIVATE + | ByteCodeParser.ACC_STATIC)) != 0) { + return false; + } + + final ExportedMethodFinder exportedMethodFinder = + new ExportedMethodFinder(exportedSymbols); + + classDataCache.findMethods( + methodData.cls, + methodData.getName(), + methodData.getInternalSig(), + exportedMethodFinder); + + return (exportedMethodFinder.getFound() != null); + } + private static String accessNonVirtualMember(String object, String mangledName, ClassData declaringClass) { @@ -338,6 +360,33 @@ : object + "['" + mangledName + "']"; } + private static final class ExportedMethodFinder + implements ClassDataCache.TraversalCallback { + private final ExportedSymbols exportedSymbols; + private MethodData found; + + public ExportedMethodFinder(final ExportedSymbols exportedSymbols) { + this.exportedSymbols = exportedSymbols; + } + + @Override + public boolean traverse(final MethodData methodData) { + try { + if (exportedSymbols.isExported(methodData)) { + found = methodData; + return false; + } + } catch (final IOException e) { + } + + return true; + } + + public MethodData getFound() { + return found; + } + } + private static final class Standalone extends VM { private Standalone(Appendable out, Bck2Brwsr.Resources resources) { super(out, resources);