mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Further refactoring of dependency checker
This commit is contained in:
parent
da35fbc2a9
commit
be89d16e88
|
@ -49,10 +49,10 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
|
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||||
switch (graph.getReference().getName()) {
|
switch (method.getReference().getName()) {
|
||||||
case "obtainDigitMapping":
|
case "obtainDigitMapping":
|
||||||
achieveObtainDigitMapping(graph);
|
achieveObtainDigitMapping(method);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
|
||||||
.append("\");").softNewLine();
|
.append("\");").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveObtainDigitMapping(MethodDependency graph) {
|
private void achieveObtainDigitMapping(MethodDependency method) {
|
||||||
graph.getResult().propagate("java.lang.String");
|
method.getResult().propagate("java.lang.String");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,16 +62,16 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
|
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||||
switch (graph.getReference().getName()) {
|
switch (method.getReference().getName()) {
|
||||||
case "clone":
|
case "clone":
|
||||||
achieveClone(graph);
|
achieveClone(method);
|
||||||
break;
|
break;
|
||||||
case "getClass":
|
case "getClass":
|
||||||
achieveGetClass(checker, graph);
|
achieveGetClass(checker, method);
|
||||||
break;
|
break;
|
||||||
case "wrap":
|
case "wrap":
|
||||||
achieveWrap(graph);
|
achieveWrap(method);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,12 +87,12 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
||||||
writer.append(".constructor)");
|
writer.append(".constructor)");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveGetClass(DependencyChecker checker, MethodDependency graph) {
|
private void achieveGetClass(DependencyChecker checker, MethodDependency method) {
|
||||||
String classClass = "java.lang.Class";
|
String classClass = "java.lang.Class";
|
||||||
MethodReference initMethod = new MethodReference(classClass, new MethodDescriptor("createNew",
|
MethodReference initMethod = new MethodReference(classClass, new MethodDescriptor("createNew",
|
||||||
ValueType.object(classClass)));
|
ValueType.object(classClass)));
|
||||||
checker.addEntryPoint(initMethod);
|
checker.addEntryPoint(initMethod);
|
||||||
graph.getResult().propagate("java.lang.Class");
|
method.getResult().propagate("java.lang.Class");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateHashCode(GeneratorContext context, SourceWriter writer) throws IOException {
|
private void generateHashCode(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||||
|
@ -108,8 +108,8 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
||||||
writer.append("return copy;").softNewLine();
|
writer.append("return copy;").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveClone(MethodDependency graph) {
|
private void achieveClone(MethodDependency method) {
|
||||||
graph.getVariable(0).connect(graph.getResult());
|
method.getVariable(0).connect(method.getResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateWrap(InjectorContext context) throws IOException {
|
private void generateWrap(InjectorContext context) throws IOException {
|
||||||
|
|
|
@ -43,10 +43,10 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
|
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||||
switch (graph.getReference().getName()) {
|
switch (method.getReference().getName()) {
|
||||||
case "doArrayCopy":
|
case "doArrayCopy":
|
||||||
achieveArrayCopy(graph);
|
achieveArrayCopy(method);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,9 +66,9 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
||||||
writer.append("return Long_fromNumber(new Date().getTime());").softNewLine();
|
writer.append("return Long_fromNumber(new Date().getTime());").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveArrayCopy(MethodDependency graph) {
|
private void achieveArrayCopy(MethodDependency method) {
|
||||||
DependencyNode src = graph.getVariable(1);
|
DependencyNode src = method.getVariable(1);
|
||||||
DependencyNode dest = graph.getVariable(3);
|
DependencyNode dest = method.getVariable(3);
|
||||||
src.getArrayItem().connect(dest.getArrayItem());
|
src.getArrayItem().connect(dest.getArrayItem());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@ import org.teavm.model.ValueType;
|
||||||
*/
|
*/
|
||||||
public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
|
public void methodAchieved(DependencyChecker checker, MethodDependency method) {
|
||||||
if (graph.getReference().getName().equals("getLength")) {
|
if (method.getReference().getName().equals("getLength")) {
|
||||||
achieveGetLength(checker, graph);
|
achieveGetLength(checker, method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +59,8 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
||||||
writer.append("return " + array + ".data.length;").softNewLine();
|
writer.append("return " + array + ".data.length;").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveGetLength(final DependencyChecker checker, final MethodDependency graph) {
|
private void achieveGetLength(final DependencyChecker checker, final MethodDependency method) {
|
||||||
graph.getVariable(1).addConsumer(new DependencyConsumer() {
|
method.getVariable(1).addConsumer(new DependencyConsumer() {
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(String type) {
|
||||||
if (!type.startsWith("[")) {
|
if (!type.startsWith("[")) {
|
||||||
MethodReference cons = new MethodReference("java.lang.IllegalArgumentException",
|
MethodReference cons = new MethodReference("java.lang.IllegalArgumentException",
|
||||||
|
|
|
@ -26,7 +26,7 @@ import org.teavm.model.*;
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class DependencyChecker implements DependencyInformation {
|
public class DependencyChecker implements DependencyInfo {
|
||||||
private static Object dummyValue = new Object();
|
private static Object dummyValue = new Object();
|
||||||
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
|
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
|
@ -34,12 +34,11 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
private FiniteExecutor executor;
|
private FiniteExecutor executor;
|
||||||
private Mapper<MethodReference, MethodReader> methodReaderCache;
|
private Mapper<MethodReference, MethodReader> methodReaderCache;
|
||||||
private Mapper<FieldReference, FieldReader> fieldReaderCache;
|
private Mapper<FieldReference, FieldReader> fieldReaderCache;
|
||||||
private ConcurrentMap<MethodReference, Object> abstractMethods = new ConcurrentHashMap<>();
|
|
||||||
private ConcurrentMap<MethodReference, DependencyStack> stacks = new ConcurrentHashMap<>();
|
private ConcurrentMap<MethodReference, DependencyStack> stacks = new ConcurrentHashMap<>();
|
||||||
private ConcurrentMap<FieldReference, DependencyStack> fieldStacks = new ConcurrentHashMap<>();
|
private ConcurrentMap<FieldReference, DependencyStack> fieldStacks = new ConcurrentHashMap<>();
|
||||||
private ConcurrentMap<String, DependencyStack> classStacks = new ConcurrentHashMap<>();
|
private ConcurrentMap<String, DependencyStack> classStacks = new ConcurrentHashMap<>();
|
||||||
private ConcurrentCachedMapper<MethodReference, MethodDependency> methodCache;
|
private ConcurrentCachedMapper<MethodReference, MethodDependency> methodCache;
|
||||||
private ConcurrentCachedMapper<FieldReference, DependencyNode> fieldCache;
|
private ConcurrentCachedMapper<FieldReference, FieldDependency> fieldCache;
|
||||||
private ConcurrentMap<String, Object> achievableClasses = new ConcurrentHashMap<>();
|
private ConcurrentMap<String, Object> achievableClasses = new ConcurrentHashMap<>();
|
||||||
private ConcurrentMap<String, Object> initializedClasses = new ConcurrentHashMap<>();
|
private ConcurrentMap<String, Object> initializedClasses = new ConcurrentHashMap<>();
|
||||||
private List<DependencyListener> listeners = new ArrayList<>();
|
private List<DependencyListener> listeners = new ArrayList<>();
|
||||||
|
@ -75,8 +74,8 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
return createMethodDep(preimage, method, stacks.get(preimage));
|
return createMethodDep(preimage, method, stacks.get(preimage));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fieldCache = new ConcurrentCachedMapper<>(new Mapper<FieldReference, DependencyNode>() {
|
fieldCache = new ConcurrentCachedMapper<>(new Mapper<FieldReference, FieldDependency>() {
|
||||||
@Override public DependencyNode map(FieldReference preimage) {
|
@Override public FieldDependency map(FieldReference preimage) {
|
||||||
FieldReader field = fieldReaderCache.map(preimage);
|
FieldReader field = fieldReaderCache.map(preimage);
|
||||||
if (field != null && !field.getReference().equals(preimage)) {
|
if (field != null && !field.getReference().equals(preimage)) {
|
||||||
fieldStacks.put(field.getReference(), fieldStacks.get(preimage));
|
fieldStacks.put(field.getReference(), fieldStacks.get(preimage));
|
||||||
|
@ -98,10 +97,10 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
});
|
});
|
||||||
fieldCache.addKeyListener(new KeyListener<FieldReference>() {
|
fieldCache.addKeyListener(new KeyListener<FieldReference>() {
|
||||||
@Override public void keyAdded(FieldReference key) {
|
@Override public void keyAdded(FieldReference key) {
|
||||||
DependencyNode node = fieldCache.getKnown(key);
|
FieldDependency fieldDep = fieldCache.getKnown(key);
|
||||||
if (!missingFields.containsKey(key)) {
|
if (!fieldDep.isMissing()) {
|
||||||
for (DependencyListener listener : listeners) {
|
for (DependencyListener listener : listeners) {
|
||||||
listener.fieldAchieved(DependencyChecker.this, key, node);
|
listener.fieldAchieved(DependencyChecker.this, fieldDep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,8 +130,9 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
if (parameters.length != argumentTypes.length) {
|
if (parameters.length != argumentTypes.length) {
|
||||||
throw new IllegalArgumentException("argumentTypes length does not match the number of method's arguments");
|
throw new IllegalArgumentException("argumentTypes length does not match the number of method's arguments");
|
||||||
}
|
}
|
||||||
MethodDependency graph = linkMethod(methodRef, DependencyStack.ROOT);
|
MethodDependency method = linkMethod(methodRef, DependencyStack.ROOT);
|
||||||
DependencyNode[] varNodes = graph.getVariables();
|
method.use();
|
||||||
|
DependencyNode[] varNodes = method.getVariables();
|
||||||
varNodes[0].propagate(methodRef.getClassName());
|
varNodes[0].propagate(methodRef.getClassName());
|
||||||
for (int i = 0; i < argumentTypes.length; ++i) {
|
for (int i = 0; i < argumentTypes.length; ++i) {
|
||||||
varNodes[i + 1].propagate(argumentTypes[i]);
|
varNodes[i + 1].propagate(argumentTypes[i]);
|
||||||
|
@ -183,7 +183,7 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
}
|
}
|
||||||
if (cls.getMethod(clinitDesc) != null) {
|
if (cls.getMethod(clinitDesc) != null) {
|
||||||
MethodReference methodRef = new MethodReference(className, clinitDesc);
|
MethodReference methodRef = new MethodReference(className, clinitDesc);
|
||||||
linkMethod(methodRef, new DependencyStack(methodRef, stack));
|
linkMethod(methodRef, new DependencyStack(methodRef, stack)).use();
|
||||||
}
|
}
|
||||||
className = cls.getParent();
|
className = cls.getParent();
|
||||||
}
|
}
|
||||||
|
@ -264,11 +264,10 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
final MethodDependency dep = new MethodDependency(parameterNodes, paramCount, resultNode, stack, method,
|
final MethodDependency dep = new MethodDependency(parameterNodes, paramCount, resultNode, stack, method,
|
||||||
methodRef);
|
methodRef);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
final MethodReader currentMethod = method;
|
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this);
|
DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this);
|
||||||
graphBuilder.buildGraph(currentMethod, dep);
|
graphBuilder.buildGraph(dep);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -284,10 +283,6 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
return methodCache.caches(methodRef);
|
return methodCache.caches(methodRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAbstractMethodAchievable(MethodReference methodRef) {
|
|
||||||
return abstractMethods.containsKey(methodRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MethodReference> getAchievableMethods() {
|
public Collection<MethodReference> getAchievableMethods() {
|
||||||
return methodCache.getCachedPreimages();
|
return methodCache.getCachedPreimages();
|
||||||
|
@ -303,17 +298,17 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
return new HashSet<>(achievableClasses.keySet());
|
return new HashSet<>(achievableClasses.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
public DependencyNode linkField(FieldReference fieldRef, DependencyStack stack) {
|
public FieldDependency linkField(FieldReference fieldRef, DependencyStack stack) {
|
||||||
fieldStacks.putIfAbsent(fieldRef, stack);
|
fieldStacks.putIfAbsent(fieldRef, stack);
|
||||||
return fieldCache.map(fieldRef);
|
return fieldCache.map(fieldRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DependencyNode getField(FieldReference fieldRef) {
|
public FieldDependency getField(FieldReference fieldRef) {
|
||||||
return fieldCache.getKnown(fieldRef);
|
return fieldCache.getKnown(fieldRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DependencyNode createFieldNode(FieldReference fieldRef, FieldReader field, DependencyStack stack) {
|
private FieldDependency createFieldNode(FieldReference fieldRef, FieldReader field, DependencyStack stack) {
|
||||||
DependencyNode node = new DependencyNode(this);
|
DependencyNode node = new DependencyNode(this);
|
||||||
if (field == null) {
|
if (field == null) {
|
||||||
missingFields.putIfAbsent(fieldRef, stack);
|
missingFields.putIfAbsent(fieldRef, stack);
|
||||||
|
@ -324,24 +319,15 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
initClass(fieldRef.getClassName(), stack);
|
initClass(fieldRef.getClassName(), stack);
|
||||||
}
|
}
|
||||||
return node;
|
return new FieldDependency(node, stack, field, fieldRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activateDependencyPlugin(MethodDependency graph) {
|
private void activateDependencyPlugin(MethodDependency methodDep) {
|
||||||
MethodReference methodRef = graph.getReference();
|
AnnotationReader depAnnot = methodDep.getMethod().getAnnotations().get(PluggableDependency.class.getName());
|
||||||
ClassReader cls = classSource.get(methodRef.getClassName());
|
|
||||||
if (cls == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
|
||||||
if (method == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AnnotationHolder depAnnot = method.getAnnotations().get(PluggableDependency.class.getName());
|
|
||||||
if (depAnnot == null) {
|
if (depAnnot == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ValueType depType = depAnnot.getValues().get("value").getJavaClass();
|
ValueType depType = depAnnot.getValue("value").getJavaClass();
|
||||||
String depClassName = ((ValueType.Object)depType).getClassName();
|
String depClassName = ((ValueType.Object)depType).getClassName();
|
||||||
Class<?> depClass;
|
Class<?> depClass;
|
||||||
try {
|
try {
|
||||||
|
@ -355,26 +341,7 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
} catch (IllegalAccessException | InstantiationException e) {
|
} catch (IllegalAccessException | InstantiationException e) {
|
||||||
throw new RuntimeException("Can't instantiate dependency plugin " + depClassName, e);
|
throw new RuntimeException("Can't instantiate dependency plugin " + depClassName, e);
|
||||||
}
|
}
|
||||||
plugin.methodAchieved(this, graph);
|
plugin.methodAchieved(this, methodDep);
|
||||||
}
|
|
||||||
|
|
||||||
public void addAbstractMethod(MethodReference methodRef, DependencyStack stack) {
|
|
||||||
stacks.putIfAbsent(methodRef, stack);
|
|
||||||
if (abstractMethods.putIfAbsent(methodRef, methodRef) == null) {
|
|
||||||
String className = methodRef.getClassName();
|
|
||||||
while (className != null) {
|
|
||||||
ClassReader cls = classSource.get(className);
|
|
||||||
if (cls == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
|
||||||
if (method != null) {
|
|
||||||
abstractMethods.put(methodRef, methodRef);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
className = cls.getParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListableClassHolderSource cutUnachievableClasses(ClassHolderSource classSource) {
|
public ListableClassHolderSource cutUnachievableClasses(ClassHolderSource classSource) {
|
||||||
|
@ -384,13 +351,12 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
cutClasses.putClassHolder(classHolder);
|
cutClasses.putClassHolder(classHolder);
|
||||||
for (MethodHolder method : classHolder.getMethods().toArray(new MethodHolder[0])) {
|
for (MethodHolder method : classHolder.getMethods().toArray(new MethodHolder[0])) {
|
||||||
MethodReference methodRef = new MethodReference(className, method.getDescriptor());
|
MethodReference methodRef = new MethodReference(className, method.getDescriptor());
|
||||||
if (!methodCache.getCachedPreimages().contains(methodRef)) {
|
MethodDependency methodDep = getMethod(methodRef);
|
||||||
if (abstractMethods.containsKey(methodRef)) {
|
if (methodDep == null) {
|
||||||
method.getModifiers().add(ElementModifier.ABSTRACT);
|
classHolder.removeMethod(method);
|
||||||
method.setProgram(null);
|
} else if (!methodDep.isUsed()) {
|
||||||
} else {
|
method.getModifiers().add(ElementModifier.ABSTRACT);
|
||||||
classHolder.removeMethod(method);
|
method.setProgram(null);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (FieldHolder field : classHolder.getFields().toArray(new FieldHolder[0])) {
|
for (FieldHolder field : classHolder.getFields().toArray(new FieldHolder[0])) {
|
||||||
|
@ -404,7 +370,7 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DependencyMethodInformation getMethod(MethodReference methodRef) {
|
public MethodDependency getMethod(MethodReference methodRef) {
|
||||||
return methodCache.getKnown(methodRef);
|
return methodCache.getKnown(methodRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.dependency;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
@ -32,23 +33,25 @@ class DependencyGraphBuilder {
|
||||||
private DependencyNode resultNode;
|
private DependencyNode resultNode;
|
||||||
private ProgramReader program;
|
private ProgramReader program;
|
||||||
private DependencyStack callerStack;
|
private DependencyStack callerStack;
|
||||||
|
private List<Runnable> useRunners = new ArrayList<>();
|
||||||
|
|
||||||
public DependencyGraphBuilder(DependencyChecker dependencyChecker) {
|
public DependencyGraphBuilder(DependencyChecker dependencyChecker) {
|
||||||
this.dependencyChecker = dependencyChecker;
|
this.dependencyChecker = dependencyChecker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void buildGraph(MethodReader method, MethodDependency graph) {
|
public void buildGraph(MethodDependency dep) {
|
||||||
|
MethodReader method = dep.getMethod();
|
||||||
if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) {
|
if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callerStack = graph.getStack();
|
callerStack = dep.getStack();
|
||||||
program = method.getProgram();
|
program = method.getProgram();
|
||||||
if (DependencyChecker.shouldLog) {
|
if (DependencyChecker.shouldLog) {
|
||||||
System.out.println("Method achieved: " + method.getReference());
|
System.out.println("Method achieved: " + method.getReference());
|
||||||
System.out.println(new ListingBuilder().buildListing(program, " "));
|
System.out.println(new ListingBuilder().buildListing(program, " "));
|
||||||
}
|
}
|
||||||
resultNode = graph.getResult();
|
resultNode = dep.getResult();
|
||||||
nodes = graph.getVariables();
|
nodes = dep.getVariables();
|
||||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
BasicBlockReader block = program.basicBlockAt(i);
|
BasicBlockReader block = program.basicBlockAt(i);
|
||||||
block.readAllInstructions(reader);
|
block.readAllInstructions(reader);
|
||||||
|
@ -58,6 +61,7 @@ class DependencyGraphBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dep.setUseRunner(new MultipleRunner(useRunners));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class VirtualCallPropagationListener implements DependencyConsumer {
|
private static class VirtualCallPropagationListener implements DependencyConsumer {
|
||||||
|
@ -92,6 +96,7 @@ class DependencyGraphBuilder {
|
||||||
MethodReference methodRef = new MethodReference(className, methodDesc);
|
MethodReference methodRef = new MethodReference(className, methodDesc);
|
||||||
MethodDependency methodDep = checker.linkMethod(methodRef, stack);
|
MethodDependency methodDep = checker.linkMethod(methodRef, stack);
|
||||||
if (!methodDep.isMissing() && knownMethods.putIfAbsent(methodRef, methodRef) == null) {
|
if (!methodDep.isMissing() && knownMethods.putIfAbsent(methodRef, methodRef) == null) {
|
||||||
|
methodDep.use();
|
||||||
DependencyNode[] targetParams = methodDep.getVariables();
|
DependencyNode[] targetParams = methodDep.getVariables();
|
||||||
for (int i = 0; i < parameters.length; ++i) {
|
for (int i = 0; i < parameters.length; ++i) {
|
||||||
parameters[i].connect(targetParams[i]);
|
parameters[i].connect(targetParams[i]);
|
||||||
|
@ -103,6 +108,30 @@ class DependencyGraphBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class MultipleRunner implements Runnable {
|
||||||
|
private List<Runnable> parts;
|
||||||
|
public MultipleRunner(List<Runnable> parts) {
|
||||||
|
this.parts = parts;
|
||||||
|
}
|
||||||
|
@Override public void run() {
|
||||||
|
for (Runnable part : parts) {
|
||||||
|
part.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TypePropagationRunner implements Runnable {
|
||||||
|
private DependencyNode node;
|
||||||
|
private String type;
|
||||||
|
public TypePropagationRunner(DependencyNode node, String type) {
|
||||||
|
this.node = node;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
@Override public void run() {
|
||||||
|
node.propagate(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private InstructionReader reader = new InstructionReader() {
|
private InstructionReader reader = new InstructionReader() {
|
||||||
@Override
|
@Override
|
||||||
public void nop() {
|
public void nop() {
|
||||||
|
@ -110,7 +139,7 @@ class DependencyGraphBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void classConstant(VariableReader receiver, ValueType cst) {
|
public void classConstant(VariableReader receiver, ValueType cst) {
|
||||||
nodes[receiver.getIndex()].propagate("java.lang.Class");
|
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], "java.lang.Class"));
|
||||||
while (cst instanceof ValueType.Array) {
|
while (cst instanceof ValueType.Array) {
|
||||||
cst = ((ValueType.Array)cst).getItemType();
|
cst = ((ValueType.Array)cst).getItemType();
|
||||||
}
|
}
|
||||||
|
@ -141,9 +170,11 @@ class DependencyGraphBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stringConstant(VariableReader receiver, String cst) {
|
public void stringConstant(VariableReader receiver, String cst) {
|
||||||
nodes[receiver.getIndex()].propagate("java.lang.String");
|
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], "java.lang.String"));
|
||||||
dependencyChecker.linkMethod(new MethodReference("java.lang.String", new MethodDescriptor(
|
MethodDependency method = dependencyChecker.linkMethod(new MethodReference("java.lang.String",
|
||||||
"<init>", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), callerStack);
|
new MethodDescriptor("<init>", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)),
|
||||||
|
callerStack);
|
||||||
|
method.use();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -211,7 +242,7 @@ class DependencyGraphBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
||||||
nodes[receiver.getIndex()].propagate("[" + itemType);
|
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], "[" + itemType));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -222,27 +253,27 @@ class DependencyGraphBuilder {
|
||||||
sb.append('[');
|
sb.append('[');
|
||||||
}
|
}
|
||||||
sb.append(itemType);
|
sb.append(itemType);
|
||||||
nodes[receiver.getIndex()].propagate(sb.toString());
|
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], sb.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void create(VariableReader receiver, String type) {
|
public void create(VariableReader receiver, String type) {
|
||||||
nodes[receiver.getIndex()].propagate(type);
|
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], type));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
|
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
|
||||||
ValueType fieldType) {
|
ValueType fieldType) {
|
||||||
DependencyNode fieldNode = dependencyChecker.linkField(field, callerStack);
|
FieldDependency fieldDep = dependencyChecker.linkField(field, callerStack);
|
||||||
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||||
fieldNode.connect(receiverNode);
|
fieldDep.getValue().connect(receiverNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
|
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
|
||||||
DependencyNode fieldNode = dependencyChecker.linkField(field, callerStack);
|
FieldDependency fieldDep = dependencyChecker.linkField(field, callerStack);
|
||||||
DependencyNode valueNode = nodes[value.getIndex()];
|
DependencyNode valueNode = nodes[value.getIndex()];
|
||||||
valueNode.connect(fieldNode);
|
valueNode.connect(fieldDep.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -305,6 +336,7 @@ class DependencyGraphBuilder {
|
||||||
if (methodDep.isMissing()) {
|
if (methodDep.isMissing()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
methodDep.use();
|
||||||
DependencyNode[] targetParams = methodDep.getVariables();
|
DependencyNode[] targetParams = methodDep.getVariables();
|
||||||
for (int i = 0; i < arguments.size(); ++i) {
|
for (int i = 0; i < arguments.size(); ++i) {
|
||||||
nodes[arguments.get(i).getIndex()].connect(targetParams[i + 1]);
|
nodes[arguments.get(i).getIndex()].connect(targetParams[i + 1]);
|
||||||
|
|
|
@ -23,14 +23,14 @@ import org.teavm.model.MethodReference;
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public interface DependencyInformation {
|
public interface DependencyInfo {
|
||||||
Collection<MethodReference> getAchievableMethods();
|
Collection<MethodReference> getAchievableMethods();
|
||||||
|
|
||||||
Collection<FieldReference> getAchievableFields();
|
Collection<FieldReference> getAchievableFields();
|
||||||
|
|
||||||
Collection<String> getAchievableClasses();
|
Collection<String> getAchievableClasses();
|
||||||
|
|
||||||
DependencyValueInformation getField(FieldReference fieldRef);
|
FieldDependencyInfo getField(FieldReference fieldRef);
|
||||||
|
|
||||||
DependencyMethodInformation getMethod(MethodReference methodRef);
|
MethodDependencyInfo getMethod(MethodReference methodRef);
|
||||||
}
|
}
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.dependency;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
import org.teavm.model.FieldReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
|
@ -28,5 +26,5 @@ public interface DependencyListener {
|
||||||
|
|
||||||
void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method);
|
void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method);
|
||||||
|
|
||||||
void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field, DependencyNode node);
|
void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class DependencyNode implements DependencyValueInformation {
|
public class DependencyNode implements ValueDependencyInfo {
|
||||||
private DependencyChecker dependencyChecker;
|
private DependencyChecker dependencyChecker;
|
||||||
private static final Object mapValue = new Object();
|
private static final Object mapValue = new Object();
|
||||||
private ConcurrentMap<DependencyConsumer, Object> followers = new ConcurrentHashMap<>();
|
private ConcurrentMap<DependencyConsumer, Object> followers = new ConcurrentHashMap<>();
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.dependency;
|
||||||
|
|
||||||
|
import org.teavm.model.FieldReader;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public class FieldDependency implements FieldDependencyInfo {
|
||||||
|
private DependencyNode value;
|
||||||
|
private DependencyStack stack;
|
||||||
|
private FieldReader field;
|
||||||
|
private FieldReference reference;
|
||||||
|
|
||||||
|
FieldDependency(DependencyNode value, DependencyStack stack, FieldReader field, FieldReference reference) {
|
||||||
|
this.value = value;
|
||||||
|
this.stack = stack;
|
||||||
|
this.field = field;
|
||||||
|
this.reference = reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DependencyNode getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DependencyStack getStack() {
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldReader getField() {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldReference getReference() {
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMissing() {
|
||||||
|
return field == null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.dependency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public interface FieldDependencyInfo {
|
||||||
|
ValueDependencyInfo getValue();
|
||||||
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
package org.teavm.dependency;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
|
@ -23,13 +24,15 @@ import org.teavm.model.MethodReference;
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class MethodDependency implements DependencyMethodInformation {
|
public class MethodDependency implements MethodDependencyInfo {
|
||||||
private DependencyNode[] variableNodes;
|
private DependencyNode[] variableNodes;
|
||||||
private int parameterCount;
|
private int parameterCount;
|
||||||
private DependencyNode resultNode;
|
private DependencyNode resultNode;
|
||||||
private DependencyStack stack;
|
private DependencyStack stack;
|
||||||
private MethodReader method;
|
private MethodReader method;
|
||||||
private MethodReference reference;
|
private MethodReference reference;
|
||||||
|
private AtomicBoolean used = new AtomicBoolean();
|
||||||
|
private volatile Runnable useRunner;
|
||||||
|
|
||||||
MethodDependency(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode,
|
MethodDependency(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode,
|
||||||
DependencyStack stack, MethodReader method, MethodReference reference) {
|
DependencyStack stack, MethodReader method, MethodReference reference) {
|
||||||
|
@ -81,4 +84,29 @@ public class MethodDependency implements DependencyMethodInformation {
|
||||||
public boolean isMissing() {
|
public boolean isMissing() {
|
||||||
return method == null;
|
return method == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUsed() {
|
||||||
|
return used.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void use() {
|
||||||
|
if (used.compareAndSet(false, true)) {
|
||||||
|
if (useRunner != null) {
|
||||||
|
useRunner.run();
|
||||||
|
useRunner = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUseRunner(Runnable runner) {
|
||||||
|
if (isUsed()) {
|
||||||
|
runner.run();
|
||||||
|
} else {
|
||||||
|
useRunner = runner;
|
||||||
|
if (isUsed()) {
|
||||||
|
runner.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,14 +19,16 @@ package org.teavm.dependency;
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public interface DependencyMethodInformation {
|
public interface MethodDependencyInfo {
|
||||||
DependencyValueInformation[] getVariables();
|
ValueDependencyInfo[] getVariables();
|
||||||
|
|
||||||
int getVariableCount();
|
int getVariableCount();
|
||||||
|
|
||||||
DependencyValueInformation getVariable(int index);
|
ValueDependencyInfo getVariable(int index);
|
||||||
|
|
||||||
int getParameterCount();
|
int getParameterCount();
|
||||||
|
|
||||||
DependencyNode getResult();
|
DependencyNode getResult();
|
||||||
|
|
||||||
|
boolean isUsed();
|
||||||
}
|
}
|
|
@ -19,7 +19,7 @@ package org.teavm.dependency;
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public interface DependencyValueInformation {
|
public interface ValueDependencyInfo {
|
||||||
String[] getTypes();
|
String[] getTypes();
|
||||||
|
|
||||||
boolean hasType(String type);
|
boolean hasType(String type);
|
|
@ -20,7 +20,7 @@ import java.util.*;
|
||||||
import org.teavm.codegen.*;
|
import org.teavm.codegen.*;
|
||||||
import org.teavm.common.FiniteExecutor;
|
import org.teavm.common.FiniteExecutor;
|
||||||
import org.teavm.dependency.DependencyChecker;
|
import org.teavm.dependency.DependencyChecker;
|
||||||
import org.teavm.dependency.DependencyInformation;
|
import org.teavm.dependency.DependencyInfo;
|
||||||
import org.teavm.dependency.DependencyListener;
|
import org.teavm.dependency.DependencyListener;
|
||||||
import org.teavm.dependency.DependencyStack;
|
import org.teavm.dependency.DependencyStack;
|
||||||
import org.teavm.javascript.ast.ClassNode;
|
import org.teavm.javascript.ast.ClassNode;
|
||||||
|
@ -120,9 +120,9 @@ public class JavascriptBuilder implements JavascriptBuilderHost {
|
||||||
builder.setMinified(minifying);
|
builder.setMinified(minifying);
|
||||||
SourceWriter sourceWriter = builder.build(writer);
|
SourceWriter sourceWriter = builder.build(writer);
|
||||||
dependencyChecker.linkMethod(new MethodReference("java.lang.Class", new MethodDescriptor("createNew",
|
dependencyChecker.linkMethod(new MethodReference("java.lang.Class", new MethodDescriptor("createNew",
|
||||||
ValueType.object("java.lang.Class"))), DependencyStack.ROOT);
|
ValueType.object("java.lang.Class"))), DependencyStack.ROOT).use();
|
||||||
dependencyChecker.linkMethod(new MethodReference("java.lang.String", new MethodDescriptor("<init>",
|
dependencyChecker.linkMethod(new MethodReference("java.lang.String", new MethodDescriptor("<init>",
|
||||||
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), DependencyStack.ROOT);
|
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), DependencyStack.ROOT).use();
|
||||||
executor.complete();
|
executor.complete();
|
||||||
dependencyChecker.checkForMissingItems();
|
dependencyChecker.checkForMissingItems();
|
||||||
ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses(classSource);
|
ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses(classSource);
|
||||||
|
@ -164,16 +164,18 @@ public class JavascriptBuilder implements JavascriptBuilderHost {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void devirtualize(ListableClassHolderSource classes, DependencyInformation dependency) {
|
private void devirtualize(ListableClassHolderSource classes, DependencyInfo dependency) {
|
||||||
final Devirtualization devirtualization = new Devirtualization(dependency, classes);
|
final Devirtualization devirtualization = new Devirtualization(dependency, classes);
|
||||||
for (String className : classes.getClassNames()) {
|
for (String className : classes.getClassNames()) {
|
||||||
ClassHolder cls = classes.get(className);
|
ClassHolder cls = classes.get(className);
|
||||||
for (final MethodHolder method : cls.getMethods()) {
|
for (final MethodHolder method : cls.getMethods()) {
|
||||||
executor.execute(new Runnable() {
|
if (method.getProgram() != null) {
|
||||||
@Override public void run() {
|
executor.execute(new Runnable() {
|
||||||
devirtualization.apply(method);
|
@Override public void run() {
|
||||||
}
|
devirtualization.apply(method);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,13 @@ import org.teavm.model.MethodReference;
|
||||||
public class JavascriptEntryPoint {
|
public class JavascriptEntryPoint {
|
||||||
private String publicName;
|
private String publicName;
|
||||||
MethodReference reference;
|
MethodReference reference;
|
||||||
private MethodDependency graph;
|
private MethodDependency method;
|
||||||
|
|
||||||
JavascriptEntryPoint(String publicName, MethodReference reference, MethodDependency graph) {
|
JavascriptEntryPoint(String publicName, MethodReference reference, MethodDependency method) {
|
||||||
this.publicName = publicName;
|
this.publicName = publicName;
|
||||||
this.reference = reference;
|
this.reference = reference;
|
||||||
this.graph = graph;
|
this.method = method;
|
||||||
|
method.use();
|
||||||
}
|
}
|
||||||
|
|
||||||
String getPublicName() {
|
String getPublicName() {
|
||||||
|
@ -41,7 +42,7 @@ public class JavascriptEntryPoint {
|
||||||
if (argument > reference.parameterCount()) {
|
if (argument > reference.parameterCount()) {
|
||||||
throw new IllegalArgumentException("Illegal argument #" + argument + " of " + reference.parameterCount());
|
throw new IllegalArgumentException("Illegal argument #" + argument + " of " + reference.parameterCount());
|
||||||
}
|
}
|
||||||
graph.getVariable(argument).propagate(type);
|
method.getVariable(argument).propagate(type);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ package org.teavm.model;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public interface AnnotationContainerReader {
|
public interface AnnotationContainerReader {
|
||||||
AnnotationHolder get(String type);
|
AnnotationReader get(String type);
|
||||||
|
|
||||||
Iterable<? extends AnnotationReader> all();
|
Iterable<? extends AnnotationReader> all();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@ package org.teavm.optimization;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.dependency.DependencyInformation;
|
import org.teavm.dependency.DependencyInfo;
|
||||||
import org.teavm.dependency.DependencyMethodInformation;
|
import org.teavm.dependency.MethodDependencyInfo;
|
||||||
import org.teavm.dependency.DependencyValueInformation;
|
import org.teavm.dependency.ValueDependencyInfo;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.*;
|
||||||
import org.teavm.model.instructions.InvocationType;
|
import org.teavm.model.instructions.InvocationType;
|
||||||
import org.teavm.model.instructions.InvokeInstruction;
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
@ -29,16 +29,16 @@ import org.teavm.model.instructions.InvokeInstruction;
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class Devirtualization {
|
public class Devirtualization {
|
||||||
private DependencyInformation dependency;
|
private DependencyInfo dependency;
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
|
|
||||||
public Devirtualization(DependencyInformation dependency, ClassReaderSource classSource) {
|
public Devirtualization(DependencyInfo dependency, ClassReaderSource classSource) {
|
||||||
this.dependency = dependency;
|
this.dependency = dependency;
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply(MethodHolder method) {
|
public void apply(MethodHolder method) {
|
||||||
DependencyMethodInformation methodDep = dependency.getMethod(method.getReference());
|
MethodDependencyInfo methodDep = dependency.getMethod(method.getReference());
|
||||||
if (methodDep == null) {
|
if (methodDep == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ public class Devirtualization {
|
||||||
if (invoke.getType() != InvocationType.VIRTUAL) {
|
if (invoke.getType() != InvocationType.VIRTUAL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DependencyValueInformation var = methodDep.getVariable(invoke.getInstance().getIndex());
|
ValueDependencyInfo var = methodDep.getVariable(invoke.getInstance().getIndex());
|
||||||
Set<MethodReference> implementations = getImplementations(var.getTypes(),
|
Set<MethodReference> implementations = getImplementations(var.getTypes(),
|
||||||
invoke.getMethod().getDescriptor());
|
invoke.getMethod().getDescriptor());
|
||||||
if (implementations.size() == 1) {
|
if (implementations.size() == 1) {
|
||||||
|
|
|
@ -48,44 +48,44 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency graph) {
|
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) {
|
||||||
if (graph.isMissing()) {
|
if (method.isMissing()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AnnotationReader annot = graph.getMethod().getAnnotations().get(JavaScriptBody.class.getName());
|
AnnotationReader annot = method.getMethod().getAnnotations().get(JavaScriptBody.class.getName());
|
||||||
if (annot != null) {
|
if (annot != null) {
|
||||||
includeDefaultDependencies(dependencyChecker);
|
includeDefaultDependencies(dependencyChecker);
|
||||||
AnnotationValue javacall = annot.getValue("javacall");
|
AnnotationValue javacall = annot.getValue("javacall");
|
||||||
if (graph.getResult() != null) {
|
if (method.getResult() != null) {
|
||||||
allClassesNode.connect(graph.getResult());
|
allClassesNode.connect(method.getResult());
|
||||||
allClassesNode.addConsumer(new OneDirectionalConnection(graph.getResult().getArrayItem()));
|
allClassesNode.addConsumer(new OneDirectionalConnection(method.getResult().getArrayItem()));
|
||||||
allClassesNode.addConsumer(new OneDirectionalConnection(graph.getResult().getArrayItem()
|
allClassesNode.addConsumer(new OneDirectionalConnection(method.getResult().getArrayItem()
|
||||||
.getArrayItem()));
|
.getArrayItem()));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < graph.getParameterCount(); ++i) {
|
for (int i = 0; i < method.getParameterCount(); ++i) {
|
||||||
graph.getVariable(i).connect(allClassesNode);
|
method.getVariable(i).connect(allClassesNode);
|
||||||
allClassesNode.addConsumer(new OneDirectionalConnection(graph.getVariable(i).getArrayItem()));
|
allClassesNode.addConsumer(new OneDirectionalConnection(method.getVariable(i).getArrayItem()));
|
||||||
allClassesNode.addConsumer(new OneDirectionalConnection(graph.getVariable(i).getArrayItem()
|
allClassesNode.addConsumer(new OneDirectionalConnection(method.getVariable(i).getArrayItem()
|
||||||
.getArrayItem()));
|
.getArrayItem()));
|
||||||
}
|
}
|
||||||
if (javacall != null && javacall.getBoolean()) {
|
if (javacall != null && javacall.getBoolean()) {
|
||||||
String body = annot.getValue("body").getString();
|
String body = annot.getValue("body").getString();
|
||||||
new GeneratorJsCallback(dependencyChecker.getClassSource(), dependencyChecker, graph).parse(body);
|
new GeneratorJsCallback(dependencyChecker, method).parse(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void includeDefaultDependencies(DependencyChecker dependencyChecker) {
|
private void includeDefaultDependencies(DependencyChecker dependencyChecker) {
|
||||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT).use();
|
||||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT).use();
|
||||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT).use();
|
||||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT).use();
|
||||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT).use();
|
||||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT).use();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field, DependencyNode node) {
|
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency fieldDep) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) {
|
private static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) {
|
||||||
|
@ -113,27 +113,25 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class GeneratorJsCallback extends JsCallback {
|
private class GeneratorJsCallback extends JsCallback {
|
||||||
private ClassReaderSource classSource;
|
|
||||||
private DependencyChecker dependencyChecker;
|
private DependencyChecker dependencyChecker;
|
||||||
private MethodDependency caller;
|
private MethodDependency caller;
|
||||||
public GeneratorJsCallback(ClassReaderSource classSource, DependencyChecker dependencyChecker,
|
public GeneratorJsCallback(DependencyChecker dependencyChecker, MethodDependency caller) {
|
||||||
MethodDependency caller) {
|
|
||||||
this.classSource = classSource;
|
|
||||||
this.dependencyChecker = dependencyChecker;
|
this.dependencyChecker = dependencyChecker;
|
||||||
this.caller = caller;
|
this.caller = caller;
|
||||||
}
|
}
|
||||||
@Override protected CharSequence callMethod(String ident, String fqn, String method, String params) {
|
@Override protected CharSequence callMethod(String ident, String fqn, String method, String params) {
|
||||||
MethodDescriptor desc = MethodDescriptor.parse(method + params + "V");
|
MethodDescriptor desc = MethodDescriptor.parse(method + params + "V");
|
||||||
MethodReader reader = findMethod(classSource, fqn, desc);
|
MethodReader reader = findMethod(dependencyChecker.getClassSource(), params, desc);
|
||||||
if (reader != null) {
|
MethodReference ref = reader != null ? reader.getReference() : new MethodReference(fqn, desc);
|
||||||
|
MethodDependency methodDep = dependencyChecker.linkMethod(ref, caller.getStack());
|
||||||
|
if (!methodDep.isMissing()) {
|
||||||
if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) {
|
if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) {
|
||||||
MethodDependency graph = dependencyChecker.linkMethod(reader.getReference(), caller.getStack());
|
methodDep.use();
|
||||||
for (int i = 0; i <= graph.getParameterCount(); ++i) {
|
for (int i = 0; i <= methodDep.getParameterCount(); ++i) {
|
||||||
allClassesNode.connect(graph.getVariable(i));
|
allClassesNode.connect(methodDep.getVariable(i));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
allClassesNode.addConsumer(new VirtualCallbackConsumer(dependencyChecker,
|
allClassesNode.addConsumer(new VirtualCallbackConsumer(dependencyChecker, reader, caller));
|
||||||
reader.getReference(), caller));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
@ -141,22 +139,46 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class VirtualCallbackConsumer implements DependencyConsumer {
|
private class VirtualCallbackConsumer implements DependencyConsumer {
|
||||||
private String superClass;
|
|
||||||
private DependencyChecker dependencyChecker;
|
private DependencyChecker dependencyChecker;
|
||||||
private MethodReference superMethod;
|
private MethodReader superMethod;
|
||||||
|
private ClassReader superClass;
|
||||||
private MethodDependency caller;
|
private MethodDependency caller;
|
||||||
public VirtualCallbackConsumer(DependencyChecker dependencyChecker, MethodReference superMethod,
|
public VirtualCallbackConsumer(DependencyChecker dependencyChecker, MethodReader superMethod,
|
||||||
MethodDependency caller) {
|
MethodDependency caller) {
|
||||||
this.dependencyChecker = dependencyChecker;
|
this.dependencyChecker = dependencyChecker;
|
||||||
this.superMethod = superMethod;
|
this.superMethod = superMethod;
|
||||||
this.caller = caller;
|
this.caller = caller;
|
||||||
|
this.superClass = dependencyChecker.getClassSource().get(superMethod.getOwnerName());
|
||||||
}
|
}
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(String type) {
|
||||||
MethodReference method = new MethodReference(type, superMethod.getDescriptor());
|
if (!isAssignableFrom(superClass, type)) {
|
||||||
MethodDependency graph = dependencyChecker.linkMethod(method, caller.getStack());
|
return;
|
||||||
for (int i = 0; i < graph.getParameterCount(); ++i) {
|
|
||||||
allClassesNode.connect(graph.getVariable(i));
|
|
||||||
}
|
}
|
||||||
|
MethodReference methodRef = new MethodReference(type, superMethod.getDescriptor());
|
||||||
|
MethodDependency method = dependencyChecker.linkMethod(methodRef, caller.getStack());
|
||||||
|
method.use();
|
||||||
|
for (int i = 0; i < method.getParameterCount(); ++i) {
|
||||||
|
allClassesNode.connect(method.getVariable(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private boolean isAssignableFrom(ClassReader supertype, String subtypeName) {
|
||||||
|
ClassReaderSource classSource = dependencyChecker.getClassSource();
|
||||||
|
if (supertype.getName().equals(subtypeName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ClassReader subtype = classSource.get(subtypeName);
|
||||||
|
if (subtype == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isAssignableFrom(supertype, subtype.getParent())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (String iface : subtype.getInterfaces()) {
|
||||||
|
if (isAssignableFrom(supertype, iface)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,11 +94,11 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(final DependencyChecker checker, final MethodDependency graph) {
|
public void methodAchieved(final DependencyChecker checker, final MethodDependency method) {
|
||||||
for (int i = 0; i < graph.getReference().parameterCount(); ++i) {
|
for (int i = 0; i < method.getReference().parameterCount(); ++i) {
|
||||||
graph.getVariable(i).addConsumer(new DependencyConsumer() {
|
method.getVariable(i).addConsumer(new DependencyConsumer() {
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(String type) {
|
||||||
achieveFunctorMethods(checker, type, graph);
|
achieveFunctorMethods(checker, type, method);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin
|
||||||
ClassReader cls = checker.getClassSource().get(type);
|
ClassReader cls = checker.getClassSource().get(type);
|
||||||
if (cls != null) {
|
if (cls != null) {
|
||||||
for (MethodReader method : cls.getMethods()) {
|
for (MethodReader method : cls.getMethods()) {
|
||||||
checker.linkMethod(method.getReference(), caller.getStack());
|
checker.linkMethod(method.getReference(), caller.getStack()).use();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user