diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java index 2d27966a1..e9a3dc7a0 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -284,9 +284,10 @@ class DependencyGraphBuilder { @Override public void consume(DependencyType type) { + ClassReaderSource classSource = checker.getClassSource(); for (int i = 0; i < exceptions.length; ++i) { - if (exceptions[i] == null || isAssignableFrom(checker.getClassSource(), exceptions[i].getName(), - type.getName())) { + if (exceptions[i] == null || classSource.isSuperType(exceptions[i].getName(), type.getName()) + .orElse(false)) { if (vars[i] != null) { vars[i].propagate(type); } @@ -334,7 +335,9 @@ class DependencyGraphBuilder { if (className.startsWith("[")) { className = "java.lang.Object"; } - if (!isAssignableFrom(checker.getClassSource(), filterClass.getName(), className)) { + + ClassReaderSource classSource = checker.getClassSource(); + if (classSource.isSuperType(filterClass.getName(), className).orElse(false)) { return; } MethodReference methodRef = new MethodReference(className, methodDesc); @@ -344,8 +347,8 @@ class DependencyGraphBuilder { methodDep.use(); DependencyNode[] targetParams = methodDep.getVariables(); if (parameters[0] != null && targetParams[0] != null) { - parameters[0].connect(targetParams[0], thisType -> isAssignableFrom(checker.getClassSource(), - methodDep.getMethod().getOwnerName(), thisType.getName())); + parameters[0].connect(targetParams[0], thisType -> classSource.isSuperType( + methodDep.getMethod().getOwnerName(), thisType.getName()).orElse(false)); } for (int i = 1; i < parameters.length; ++i) { if (parameters[i] != null && targetParams[i] != null) { @@ -360,23 +363,6 @@ class DependencyGraphBuilder { } } - private static boolean isAssignableFrom(ClassReaderSource classSource, String supertype, String subtypeName) { - if (supertype.equals(subtypeName)) { - return true; - } - ClassReader subtype = classSource.get(subtypeName); - if (subtype == null) { - return false; - } - if (subtype.getParent() != null && isAssignableFrom(classSource, supertype, subtype.getParent())) { - return true; - } - if (subtype.getInterfaces().stream().anyMatch(iface -> isAssignableFrom(classSource, supertype, iface))) { - return true; - } - return false; - } - private InstructionReader reader = new InstructionReader() { @Override public void location(InstructionLocation location) { @@ -455,17 +441,17 @@ class DependencyGraphBuilder { public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { DependencyNode valueNode = nodes[value.getIndex()]; DependencyNode receiverNode = nodes[receiver.getIndex()]; + ClassReaderSource classSource = dependencyChecker.getClassSource(); if (targetType instanceof ValueType.Object) { String targetClsName = ((ValueType.Object) targetType).getClassName(); - final ClassReader targetClass = dependencyChecker.getClassSource().get(targetClsName); + final ClassReader targetClass = classSource.get(targetClsName); if (targetClass != null) { if (valueNode != null && receiverNode != null) { valueNode.connect(receiverNode, type -> { if (targetClass.getName().equals("java.lang.Object")) { return true; } - return isAssignableFrom(dependencyChecker.getClassSource(), targetClass.getName(), - type.getName()); + return classSource.isSuperType(targetClass.getName(), type.getName()).orElse(false); }); } return; diff --git a/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java b/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java index bc4e1684c..02d595e76 100644 --- a/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java +++ b/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java @@ -244,6 +244,10 @@ public final class ProgramEmitter { return this; } + public ProgramEmitter invoke(Class cls, String methodName, ValueEmitter... arguments) { + return invoke(cls.getName(), methodName, arguments); + } + public ValueEmitter construct(String className, ValueEmitter... arguments) { Variable var = program.createVariable(); ConstructInstruction insn = new ConstructInstruction(); diff --git a/teavm-core/src/main/java/org/teavm/optimization/Devirtualization.java b/teavm-core/src/main/java/org/teavm/optimization/Devirtualization.java index eb32ec9ed..82422325c 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/Devirtualization.java +++ b/teavm-core/src/main/java/org/teavm/optimization/Devirtualization.java @@ -71,7 +71,7 @@ public class Devirtualization { className = "java.lang.Object"; } ClassReader cls = classSource.get(className); - if (cls == null || !isAssignable(ref.getClassName(), cls)) { + if (cls == null || !classSource.isSuperType(ref.getClassName(), cls.getName()).orElse(false)) { continue; } MethodDependencyInfo methodDep = dependency.getMethodImplementation(new MethodReference( @@ -82,23 +82,4 @@ public class Devirtualization { } return methods; } - - private boolean isAssignable(String target, ClassReader cls) { - if (cls.getName().equals(target)) { - return true; - } - if (cls.getParent() != null) { - ClassReader parent = classSource.get(cls.getParent()); - if (parent != null && isAssignable(target, parent)) { - return true; - } - } - for (String ifaceName : cls.getInterfaces()) { - ClassReader iface = classSource.get(ifaceName); - if (iface != null && isAssignable(target, iface)) { - return true; - } - } - return false; - } } diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java index ceae44dca..4ac433212 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java @@ -198,7 +198,7 @@ public class JavaScriptBodyDependency extends AbstractDependencyListener { this.superClass = agent.getClassSource().get(superMethod.getOwnerName()); } @Override public void consume(DependencyType type) { - if (!isAssignableFrom(superClass, type.getName())) { + if (!agent.getClassSource().isSuperType(superClass.getName(), type.getName()).orElse(false)) { return; } MethodReference methodRef = new MethodReference(type.getName(), superMethod.getDescriptor()); @@ -208,24 +208,5 @@ public class JavaScriptBodyDependency extends AbstractDependencyListener { allClassesNode.connect(method.getVariable(i)); } } - private boolean isAssignableFrom(ClassReader supertype, String subtypeName) { - ClassReaderSource classSource = agent.getClassSource(); - if (supertype.getName().equals(subtypeName)) { - return true; - } - ClassReader subtype = classSource.get(subtypeName); - if (subtype == null) { - return false; - } - if (subtype.getParent() != null && isAssignableFrom(supertype, subtype.getParent())) { - return true; - } - for (String iface : subtype.getInterfaces()) { - if (isAssignableFrom(supertype, iface)) { - return true; - } - } - return false; - } } } diff --git a/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java b/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java index 719fe156f..85d3a3302 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java +++ b/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java @@ -115,37 +115,22 @@ class JavascriptNativeProcessor { return null; } Map methods = new HashMap<>(); - getFunctorMethods(className, new HashSet<>(), methods); + getFunctorMethods(className, methods); if (methods.size() == 1) { return methods.values().iterator().next(); } return null; } - private void getFunctorMethods(String className, Set visited, - Map methods) { - if (!visited.add(className)) { - return; - } - - ClassReader cls = classSource.get(className); - if (cls == null) { - return; - } - - if (cls.getAnnotations().get(JSFunctor.class.getName()) != null && isProperFunctor(cls)) { - MethodReference method = cls.getMethods().iterator().next().getReference(); - if (!methods.containsKey(method.getDescriptor())) { - methods.put(method.getDescriptor(), method); + private void getFunctorMethods(String className, Map methods) { + classSource.getAncestors(className).forEach(cls -> { + if (cls.getAnnotations().get(JSFunctor.class.getName()) != null && isProperFunctor(cls)) { + MethodReference method = cls.getMethods().iterator().next().getReference(); + if (!methods.containsKey(method.getDescriptor())) { + methods.put(method.getDescriptor(), method); + } } - } - - if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) { - getFunctorMethods(cls.getParent(), visited, methods); - } - for (String iface : cls.getInterfaces()) { - getFunctorMethods(iface, visited, methods); - } + }); } public void processClass(ClassHolder cls) { @@ -223,31 +208,12 @@ class JavascriptNativeProcessor { } private MethodReader findOverridenMethod(String className, MethodReader finalMethod) { - ClassReader cls = classSource.get(className); - if (cls == null) { - return null; - } - - MethodReader method = cls.getMethod(finalMethod.getDescriptor()); - if (method != null && !method.getOwnerName().equals(finalMethod.getOwnerName())) { - return method; - } - - if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) { - method = findOverridenMethod(cls.getParent(), finalMethod); - if (method != null) { - return method; - } - } - - for (String iface : cls.getInterfaces()) { - method = findOverridenMethod(iface, finalMethod); - if (method != null) { - return method; - } - } - - return null; + return classSource.getAncestors(className) + .skip(1) + .map(cls -> cls.getMethod(finalMethod.getDescriptor())) + .filter(method -> method != null) + .findFirst() + .orElse(null); } public void addFunctorField(ClassHolder cls, MethodReference method) { diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java index 4ef89d46f..73768dfce 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java @@ -24,7 +24,6 @@ import org.teavm.javascript.spi.Generator; import org.teavm.javascript.spi.GeneratorContext; import org.teavm.model.CallLocation; import org.teavm.model.ClassReader; -import org.teavm.model.ClassReaderSource; import org.teavm.model.ElementModifier; import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; @@ -100,9 +99,10 @@ public class AsyncMethodGenerator implements Generator, DependencyPlugin { @Override public void methodAchieved(DependencyAgent checker, MethodDependency method, CallLocation location) { - MethodReference asyncRef = getAsyncReference(method.getReference()); + MethodReference ref = method.getReference(); + MethodReference asyncRef = getAsyncReference(ref); MethodDependency asyncMethod = checker.linkMethod(asyncRef, location); - int paramCount = method.getReference().parameterCount(); + int paramCount = ref.parameterCount(); for (int i = 0; i <= paramCount; ++i) { method.getVariable(i).connect(asyncMethod.getVariable(i)); } @@ -111,8 +111,8 @@ public class AsyncMethodGenerator implements Generator, DependencyPlugin { MethodDependency completeMethod = checker.linkMethod( new MethodReference(AsyncCallbackWrapper.class, "complete", Object.class, void.class), null); if (method.getResult() != null) { - completeMethod.getVariable(1).connect(method.getResult(), type -> isSubtype(checker.getClassSource(), - type.getName(), method.getReference().getReturnType())); + completeMethod.getVariable(1).connect(method.getResult(), type -> checker.getClassSource() + .isSuperType(ref.getReturnType(), ValueType.object(type.getName())).orElse(false)); } completeMethod.use(); @@ -126,30 +126,4 @@ public class AsyncMethodGenerator implements Generator, DependencyPlugin { asyncMethod.use(); } - - private boolean isSubtype(ClassReaderSource classSource, String className, ValueType returnType) { - if (returnType instanceof ValueType.Primitive) { - return false; - } else if (returnType instanceof ValueType.Array) { - return className.startsWith("["); - } else { - return isSubclass(classSource, className, ((ValueType.Object) returnType).getClassName()); - } - } - - private boolean isSubclass(ClassReaderSource classSource, String className, String baseClass) { - if (className.equals(baseClass)) { - return true; - } - ClassReader cls = classSource.get(className); - if (cls == null) { - return false; - } - if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) { - if (isSubclass(classSource, cls.getParent(), baseClass)) { - return true; - } - } - return cls.getInterfaces().stream().anyMatch(iface -> isSubclass(classSource, iface, baseClass)); - } } diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java index d723bd195..427221d5f 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java @@ -80,7 +80,7 @@ class ResourceProgramTransformer { return Arrays.asList(accessInsn); } ClassReader iface = innerSource.get(method.getClassName()); - if (iface == null || !isSubclass(iface, Resource.class.getName())) { + if (iface == null || !innerSource.isSuperType(Resource.class.getName(), iface.getName()).orElse(false)) { return null; } if (method.getName().startsWith("get")) { @@ -118,23 +118,6 @@ class ResourceProgramTransformer { return Arrays.asList(keysInsn, transformInsn); } - private boolean isSubclass(ClassReader cls, String superClass) { - if (cls.getName().equals(superClass)) { - return true; - } - ClassReader parent = cls.getParent() != null ? innerSource.get(cls.getParent()) : null; - if (parent != null && isSubclass(parent, superClass)) { - return true; - } - for (String ifaceName : cls.getInterfaces()) { - ClassReader iface = innerSource.get(ifaceName); - if (iface != null) { - return isSubclass(iface, superClass); - } - } - return false; - } - private List transformGetterInvocation(InvokeInstruction insn, String property) { if (insn.getReceiver() == null) { return Collections.emptyList();