Fix private method call resolution in Java 11

This commit is contained in:
Alexey Andreev 2022-11-11 10:56:20 +01:00
parent 5fb83ca2ac
commit 1fb70b0903
4 changed files with 50 additions and 6 deletions

View File

@ -22,6 +22,7 @@ import static org.teavm.dependency.AbstractInstructionAnalyzer.MONITOR_EXIT_SYNC
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.teavm.model.AccessLevel;
import org.teavm.model.BasicBlockReader; import org.teavm.model.BasicBlockReader;
import org.teavm.model.CallLocation; import org.teavm.model.CallLocation;
import org.teavm.model.ClassHierarchy; import org.teavm.model.ClassHierarchy;
@ -31,6 +32,7 @@ import org.teavm.model.ElementModifier;
import org.teavm.model.IncomingReader; import org.teavm.model.IncomingReader;
import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodHolder; import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.PhiReader; import org.teavm.model.PhiReader;
import org.teavm.model.Program; import org.teavm.model.Program;
@ -368,6 +370,15 @@ class DependencyGraphBuilder {
@Override @Override
protected void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method, protected void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments) { List<? extends VariableReader> 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)) { if (handleSpecialMethod(receiver, instance, method)) {
return; return;
} }
@ -377,7 +388,7 @@ class DependencyGraphBuilder {
actualArgs[i + 1] = nodes[arguments.get(i).getIndex()]; actualArgs[i + 1] = nodes[arguments.get(i).getIndex()];
} }
actualArgs[0] = getNode(instance); actualArgs[0] = getNode(instance);
DependencyConsumer listener = new VirtualCallConsumer(getNode(instance), DependencyConsumer listener = new VirtualCallConsumer(
method.getClassName(), method.getDescriptor(), dependencyAnalyzer, actualArgs, method.getClassName(), method.getDescriptor(), dependencyAnalyzer, actualArgs,
receiver != null ? getNode(receiver) : null, getCallLocation(), receiver != null ? getNode(receiver) : null, getCallLocation(),
currentExceptionConsumer); currentExceptionConsumer);

View File

@ -16,7 +16,10 @@
package org.teavm.dependency; package org.teavm.dependency;
import java.util.List; import java.util.List;
import org.teavm.model.AccessLevel;
import org.teavm.model.CallLocation; import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.VariableReader; import org.teavm.model.VariableReader;
@ -46,6 +49,14 @@ class FastInstructionAnalyzer extends AbstractInstructionAnalyzer {
@Override @Override
protected void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method, protected void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments) { List<? extends VariableReader> 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); invokeGetClass(method);
FastVirtualCallConsumer consumer = dependencyAnalyzer.getVirtualCallConsumer(method); FastVirtualCallConsumer consumer = dependencyAnalyzer.getVirtualCallConsumer(method);
consumer.addLocation(impreciseLocation); consumer.addLocation(impreciseLocation);

View File

@ -20,7 +20,6 @@ import org.teavm.model.CallLocation;
import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodDescriptor;
class VirtualCallConsumer implements DependencyConsumer { class VirtualCallConsumer implements DependencyConsumer {
private final DependencyNode node;
private final MethodDescriptor methodDesc; private final MethodDescriptor methodDesc;
private final DependencyAnalyzer analyzer; private final DependencyAnalyzer analyzer;
private final DependencyNode[] parameters; private final DependencyNode[] parameters;
@ -32,11 +31,9 @@ class VirtualCallConsumer implements DependencyConsumer {
private boolean isPolymorphic; private boolean isPolymorphic;
private MethodDependency monomorphicCall; private MethodDependency monomorphicCall;
VirtualCallConsumer(DependencyNode node, String filterClass, VirtualCallConsumer(String filterClass, MethodDescriptor methodDesc, DependencyAnalyzer analyzer,
MethodDescriptor methodDesc, DependencyAnalyzer analyzer, DependencyNode[] parameters, DependencyNode[] parameters, DependencyNode result, CallLocation location,
DependencyNode result, CallLocation location,
DependencyGraphBuilder.ExceptionConsumer exceptionConsumer) { DependencyGraphBuilder.ExceptionConsumer exceptionConsumer) {
this.node = node;
this.filter = analyzer.getSuperClassFilter(filterClass); this.filter = analyzer.getSuperClassFilter(filterClass);
this.methodDesc = methodDesc; this.methodDesc = methodDesc;
this.analyzer = analyzer; this.analyzer = analyzer;

View File

@ -634,4 +634,29 @@ public class VMTest {
} }
return result; 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";
}
}
} }