mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Refactor TeaVM to use new default methods of ClassReaderSource instead
of manual traversing through class hierarchy
This commit is contained in:
parent
57a39a156a
commit
fe940bc084
|
@ -284,9 +284,10 @@ class DependencyGraphBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void consume(DependencyType type) {
|
public void consume(DependencyType type) {
|
||||||
|
ClassReaderSource classSource = checker.getClassSource();
|
||||||
for (int i = 0; i < exceptions.length; ++i) {
|
for (int i = 0; i < exceptions.length; ++i) {
|
||||||
if (exceptions[i] == null || isAssignableFrom(checker.getClassSource(), exceptions[i].getName(),
|
if (exceptions[i] == null || classSource.isSuperType(exceptions[i].getName(), type.getName())
|
||||||
type.getName())) {
|
.orElse(false)) {
|
||||||
if (vars[i] != null) {
|
if (vars[i] != null) {
|
||||||
vars[i].propagate(type);
|
vars[i].propagate(type);
|
||||||
}
|
}
|
||||||
|
@ -334,7 +335,9 @@ class DependencyGraphBuilder {
|
||||||
if (className.startsWith("[")) {
|
if (className.startsWith("[")) {
|
||||||
className = "java.lang.Object";
|
className = "java.lang.Object";
|
||||||
}
|
}
|
||||||
if (!isAssignableFrom(checker.getClassSource(), filterClass.getName(), className)) {
|
|
||||||
|
ClassReaderSource classSource = checker.getClassSource();
|
||||||
|
if (classSource.isSuperType(filterClass.getName(), className).orElse(false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MethodReference methodRef = new MethodReference(className, methodDesc);
|
MethodReference methodRef = new MethodReference(className, methodDesc);
|
||||||
|
@ -344,8 +347,8 @@ class DependencyGraphBuilder {
|
||||||
methodDep.use();
|
methodDep.use();
|
||||||
DependencyNode[] targetParams = methodDep.getVariables();
|
DependencyNode[] targetParams = methodDep.getVariables();
|
||||||
if (parameters[0] != null && targetParams[0] != null) {
|
if (parameters[0] != null && targetParams[0] != null) {
|
||||||
parameters[0].connect(targetParams[0], thisType -> isAssignableFrom(checker.getClassSource(),
|
parameters[0].connect(targetParams[0], thisType -> classSource.isSuperType(
|
||||||
methodDep.getMethod().getOwnerName(), thisType.getName()));
|
methodDep.getMethod().getOwnerName(), thisType.getName()).orElse(false));
|
||||||
}
|
}
|
||||||
for (int i = 1; i < parameters.length; ++i) {
|
for (int i = 1; i < parameters.length; ++i) {
|
||||||
if (parameters[i] != null && targetParams[i] != null) {
|
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() {
|
private InstructionReader reader = new InstructionReader() {
|
||||||
@Override
|
@Override
|
||||||
public void location(InstructionLocation location) {
|
public void location(InstructionLocation location) {
|
||||||
|
@ -455,17 +441,17 @@ class DependencyGraphBuilder {
|
||||||
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
||||||
DependencyNode valueNode = nodes[value.getIndex()];
|
DependencyNode valueNode = nodes[value.getIndex()];
|
||||||
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||||
|
ClassReaderSource classSource = dependencyChecker.getClassSource();
|
||||||
if (targetType instanceof ValueType.Object) {
|
if (targetType instanceof ValueType.Object) {
|
||||||
String targetClsName = ((ValueType.Object) targetType).getClassName();
|
String targetClsName = ((ValueType.Object) targetType).getClassName();
|
||||||
final ClassReader targetClass = dependencyChecker.getClassSource().get(targetClsName);
|
final ClassReader targetClass = classSource.get(targetClsName);
|
||||||
if (targetClass != null) {
|
if (targetClass != null) {
|
||||||
if (valueNode != null && receiverNode != null) {
|
if (valueNode != null && receiverNode != null) {
|
||||||
valueNode.connect(receiverNode, type -> {
|
valueNode.connect(receiverNode, type -> {
|
||||||
if (targetClass.getName().equals("java.lang.Object")) {
|
if (targetClass.getName().equals("java.lang.Object")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return isAssignableFrom(dependencyChecker.getClassSource(), targetClass.getName(),
|
return classSource.isSuperType(targetClass.getName(), type.getName()).orElse(false);
|
||||||
type.getName());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -244,6 +244,10 @@ public final class ProgramEmitter {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ProgramEmitter invoke(Class<?> cls, String methodName, ValueEmitter... arguments) {
|
||||||
|
return invoke(cls.getName(), methodName, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
public ValueEmitter construct(String className, ValueEmitter... arguments) {
|
public ValueEmitter construct(String className, ValueEmitter... arguments) {
|
||||||
Variable var = program.createVariable();
|
Variable var = program.createVariable();
|
||||||
ConstructInstruction insn = new ConstructInstruction();
|
ConstructInstruction insn = new ConstructInstruction();
|
||||||
|
|
|
@ -71,7 +71,7 @@ public class Devirtualization {
|
||||||
className = "java.lang.Object";
|
className = "java.lang.Object";
|
||||||
}
|
}
|
||||||
ClassReader cls = classSource.get(className);
|
ClassReader cls = classSource.get(className);
|
||||||
if (cls == null || !isAssignable(ref.getClassName(), cls)) {
|
if (cls == null || !classSource.isSuperType(ref.getClassName(), cls.getName()).orElse(false)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
MethodDependencyInfo methodDep = dependency.getMethodImplementation(new MethodReference(
|
MethodDependencyInfo methodDep = dependency.getMethodImplementation(new MethodReference(
|
||||||
|
@ -82,23 +82,4 @@ public class Devirtualization {
|
||||||
}
|
}
|
||||||
return methods;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,7 +198,7 @@ public class JavaScriptBodyDependency extends AbstractDependencyListener {
|
||||||
this.superClass = agent.getClassSource().get(superMethod.getOwnerName());
|
this.superClass = agent.getClassSource().get(superMethod.getOwnerName());
|
||||||
}
|
}
|
||||||
@Override public void consume(DependencyType type) {
|
@Override public void consume(DependencyType type) {
|
||||||
if (!isAssignableFrom(superClass, type.getName())) {
|
if (!agent.getClassSource().isSuperType(superClass.getName(), type.getName()).orElse(false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MethodReference methodRef = new MethodReference(type.getName(), superMethod.getDescriptor());
|
MethodReference methodRef = new MethodReference(type.getName(), superMethod.getDescriptor());
|
||||||
|
@ -208,24 +208,5 @@ public class JavaScriptBodyDependency extends AbstractDependencyListener {
|
||||||
allClassesNode.connect(method.getVariable(i));
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,37 +115,22 @@ class JavascriptNativeProcessor {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Map<MethodDescriptor, MethodReference> methods = new HashMap<>();
|
Map<MethodDescriptor, MethodReference> methods = new HashMap<>();
|
||||||
getFunctorMethods(className, new HashSet<>(), methods);
|
getFunctorMethods(className, methods);
|
||||||
if (methods.size() == 1) {
|
if (methods.size() == 1) {
|
||||||
return methods.values().iterator().next();
|
return methods.values().iterator().next();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getFunctorMethods(String className, Set<String> visited,
|
private void getFunctorMethods(String className, Map<MethodDescriptor, MethodReference> methods) {
|
||||||
Map<MethodDescriptor, MethodReference> methods) {
|
classSource.getAncestors(className).forEach(cls -> {
|
||||||
if (!visited.add(className)) {
|
if (cls.getAnnotations().get(JSFunctor.class.getName()) != null && isProperFunctor(cls)) {
|
||||||
return;
|
MethodReference method = cls.getMethods().iterator().next().getReference();
|
||||||
}
|
if (!methods.containsKey(method.getDescriptor())) {
|
||||||
|
methods.put(method.getDescriptor(), method);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
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) {
|
public void processClass(ClassHolder cls) {
|
||||||
|
@ -223,31 +208,12 @@ class JavascriptNativeProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodReader findOverridenMethod(String className, MethodReader finalMethod) {
|
private MethodReader findOverridenMethod(String className, MethodReader finalMethod) {
|
||||||
ClassReader cls = classSource.get(className);
|
return classSource.getAncestors(className)
|
||||||
if (cls == null) {
|
.skip(1)
|
||||||
return null;
|
.map(cls -> cls.getMethod(finalMethod.getDescriptor()))
|
||||||
}
|
.filter(method -> method != null)
|
||||||
|
.findFirst()
|
||||||
MethodReader method = cls.getMethod(finalMethod.getDescriptor());
|
.orElse(null);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addFunctorField(ClassHolder cls, MethodReference method) {
|
public void addFunctorField(ClassHolder cls, MethodReference method) {
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.teavm.javascript.spi.Generator;
|
||||||
import org.teavm.javascript.spi.GeneratorContext;
|
import org.teavm.javascript.spi.GeneratorContext;
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.ClassReader;
|
import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.ClassReaderSource;
|
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -100,9 +99,10 @@ public class AsyncMethodGenerator implements Generator, DependencyPlugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(DependencyAgent checker, MethodDependency method, CallLocation location) {
|
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);
|
MethodDependency asyncMethod = checker.linkMethod(asyncRef, location);
|
||||||
int paramCount = method.getReference().parameterCount();
|
int paramCount = ref.parameterCount();
|
||||||
for (int i = 0; i <= paramCount; ++i) {
|
for (int i = 0; i <= paramCount; ++i) {
|
||||||
method.getVariable(i).connect(asyncMethod.getVariable(i));
|
method.getVariable(i).connect(asyncMethod.getVariable(i));
|
||||||
}
|
}
|
||||||
|
@ -111,8 +111,8 @@ public class AsyncMethodGenerator implements Generator, DependencyPlugin {
|
||||||
MethodDependency completeMethod = checker.linkMethod(
|
MethodDependency completeMethod = checker.linkMethod(
|
||||||
new MethodReference(AsyncCallbackWrapper.class, "complete", Object.class, void.class), null);
|
new MethodReference(AsyncCallbackWrapper.class, "complete", Object.class, void.class), null);
|
||||||
if (method.getResult() != null) {
|
if (method.getResult() != null) {
|
||||||
completeMethod.getVariable(1).connect(method.getResult(), type -> isSubtype(checker.getClassSource(),
|
completeMethod.getVariable(1).connect(method.getResult(), type -> checker.getClassSource()
|
||||||
type.getName(), method.getReference().getReturnType()));
|
.isSuperType(ref.getReturnType(), ValueType.object(type.getName())).orElse(false));
|
||||||
}
|
}
|
||||||
completeMethod.use();
|
completeMethod.use();
|
||||||
|
|
||||||
|
@ -126,30 +126,4 @@ public class AsyncMethodGenerator implements Generator, DependencyPlugin {
|
||||||
|
|
||||||
asyncMethod.use();
|
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ class ResourceProgramTransformer {
|
||||||
return Arrays.<Instruction>asList(accessInsn);
|
return Arrays.<Instruction>asList(accessInsn);
|
||||||
}
|
}
|
||||||
ClassReader iface = innerSource.get(method.getClassName());
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
if (method.getName().startsWith("get")) {
|
if (method.getName().startsWith("get")) {
|
||||||
|
@ -118,23 +118,6 @@ class ResourceProgramTransformer {
|
||||||
return Arrays.<Instruction>asList(keysInsn, transformInsn);
|
return Arrays.<Instruction>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<Instruction> transformGetterInvocation(InvokeInstruction insn, String property) {
|
private List<Instruction> transformGetterInvocation(InvokeInstruction insn, String property) {
|
||||||
if (insn.getReceiver() == null) {
|
if (insn.getReceiver() == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user