mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -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
|
||||
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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,37 +115,22 @@ class JavascriptNativeProcessor {
|
|||
return null;
|
||||
}
|
||||
Map<MethodDescriptor, MethodReference> 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<String> visited,
|
||||
Map<MethodDescriptor, MethodReference> 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<MethodDescriptor, MethodReference> 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) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ class ResourceProgramTransformer {
|
|||
return Arrays.<Instruction>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.<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) {
|
||||
if (insn.getReceiver() == null) {
|
||||
return Collections.emptyList();
|
||||
|
|
Loading…
Reference in New Issue
Block a user