From 1fb70b0903ec0114bac6ce993fde10ef50e0edef Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 11 Nov 2022 10:56:20 +0100 Subject: [PATCH] Fix private method call resolution in Java 11 --- .../dependency/DependencyGraphBuilder.java | 13 +++++++++- .../dependency/FastInstructionAnalyzer.java | 11 ++++++++ .../teavm/dependency/VirtualCallConsumer.java | 7 ++---- tests/src/test/java/org/teavm/vm/VMTest.java | 25 +++++++++++++++++++ 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java index c36e99213..4b438158d 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -22,6 +22,7 @@ import static org.teavm.dependency.AbstractInstructionAnalyzer.MONITOR_EXIT_SYNC import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.teavm.model.AccessLevel; import org.teavm.model.BasicBlockReader; import org.teavm.model.CallLocation; import org.teavm.model.ClassHierarchy; @@ -31,6 +32,7 @@ import org.teavm.model.ElementModifier; import org.teavm.model.IncomingReader; import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodHolder; +import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; import org.teavm.model.PhiReader; import org.teavm.model.Program; @@ -368,6 +370,15 @@ class DependencyGraphBuilder { @Override protected void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method, List arguments) { + ClassReader cls = dependencyAnalyzer.getClassSource().get(method.getClassName()); + if (cls != null) { + MethodReader methodHolder = cls.getMethod(method.getDescriptor()); + if (methodHolder != null && methodHolder.getLevel() == AccessLevel.PRIVATE) { + invokeSpecial(receiver, instance, method, arguments); + return; + } + } + if (handleSpecialMethod(receiver, instance, method)) { return; } @@ -377,7 +388,7 @@ class DependencyGraphBuilder { actualArgs[i + 1] = nodes[arguments.get(i).getIndex()]; } actualArgs[0] = getNode(instance); - DependencyConsumer listener = new VirtualCallConsumer(getNode(instance), + DependencyConsumer listener = new VirtualCallConsumer( method.getClassName(), method.getDescriptor(), dependencyAnalyzer, actualArgs, receiver != null ? getNode(receiver) : null, getCallLocation(), currentExceptionConsumer); diff --git a/core/src/main/java/org/teavm/dependency/FastInstructionAnalyzer.java b/core/src/main/java/org/teavm/dependency/FastInstructionAnalyzer.java index f3a27616e..3f55d51b0 100644 --- a/core/src/main/java/org/teavm/dependency/FastInstructionAnalyzer.java +++ b/core/src/main/java/org/teavm/dependency/FastInstructionAnalyzer.java @@ -16,7 +16,10 @@ package org.teavm.dependency; import java.util.List; +import org.teavm.model.AccessLevel; import org.teavm.model.CallLocation; +import org.teavm.model.ClassReader; +import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; import org.teavm.model.VariableReader; @@ -46,6 +49,14 @@ class FastInstructionAnalyzer extends AbstractInstructionAnalyzer { @Override protected void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method, List arguments) { + ClassReader cls = dependencyAnalyzer.getClassSource().get(method.getClassName()); + if (cls != null) { + MethodReader methodHolder = cls.getMethod(method.getDescriptor()); + if (methodHolder != null && methodHolder.getLevel() == AccessLevel.PRIVATE) { + invokeSpecial(receiver, instance, method, arguments); + return; + } + } invokeGetClass(method); FastVirtualCallConsumer consumer = dependencyAnalyzer.getVirtualCallConsumer(method); consumer.addLocation(impreciseLocation); diff --git a/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java b/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java index ce0e1a4f2..6b3b2ec7f 100644 --- a/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java +++ b/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java @@ -20,7 +20,6 @@ import org.teavm.model.CallLocation; import org.teavm.model.MethodDescriptor; class VirtualCallConsumer implements DependencyConsumer { - private final DependencyNode node; private final MethodDescriptor methodDesc; private final DependencyAnalyzer analyzer; private final DependencyNode[] parameters; @@ -32,11 +31,9 @@ class VirtualCallConsumer implements DependencyConsumer { private boolean isPolymorphic; private MethodDependency monomorphicCall; - VirtualCallConsumer(DependencyNode node, String filterClass, - MethodDescriptor methodDesc, DependencyAnalyzer analyzer, DependencyNode[] parameters, - DependencyNode result, CallLocation location, + VirtualCallConsumer(String filterClass, MethodDescriptor methodDesc, DependencyAnalyzer analyzer, + DependencyNode[] parameters, DependencyNode result, CallLocation location, DependencyGraphBuilder.ExceptionConsumer exceptionConsumer) { - this.node = node; this.filter = analyzer.getSuperClassFilter(filterClass); this.methodDesc = methodDesc; this.analyzer = analyzer; diff --git a/tests/src/test/java/org/teavm/vm/VMTest.java b/tests/src/test/java/org/teavm/vm/VMTest.java index 8b8c6fdbc..888f5f70f 100644 --- a/tests/src/test/java/org/teavm/vm/VMTest.java +++ b/tests/src/test/java/org/teavm/vm/VMTest.java @@ -634,4 +634,29 @@ public class VMTest { } return result; } + + @Test + public void virtualCallWithPrivateMethods() { + assertEquals("ap", callA(new B())); + } + + private static String callA(A a) { + return a.a(); + } + + static class A { + String a() { + return "a" + p(); + } + + private String p() { + return "p"; + } + } + + static class B extends A { + private String p() { + return "q"; + } + } } \ No newline at end of file