mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Dependency checker refactoring
This commit is contained in:
parent
5b76001a34
commit
da35fbc2a9
|
@ -21,7 +21,7 @@ import org.teavm.classlib.impl.unicode.UnicodeSupport;
|
||||||
import org.teavm.codegen.SourceWriter;
|
import org.teavm.codegen.SourceWriter;
|
||||||
import org.teavm.dependency.DependencyChecker;
|
import org.teavm.dependency.DependencyChecker;
|
||||||
import org.teavm.dependency.DependencyPlugin;
|
import org.teavm.dependency.DependencyPlugin;
|
||||||
import org.teavm.dependency.MethodGraph;
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.javascript.ni.Generator;
|
import org.teavm.javascript.ni.Generator;
|
||||||
import org.teavm.javascript.ni.GeneratorContext;
|
import org.teavm.javascript.ni.GeneratorContext;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -49,7 +49,7 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(DependencyChecker checker, MethodGraph graph) {
|
public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
|
||||||
switch (graph.getReference().getName()) {
|
switch (graph.getReference().getName()) {
|
||||||
case "obtainDigitMapping":
|
case "obtainDigitMapping":
|
||||||
achieveObtainDigitMapping(graph);
|
achieveObtainDigitMapping(graph);
|
||||||
|
@ -72,7 +72,7 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
|
||||||
.append("\");").softNewLine();
|
.append("\");").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveObtainDigitMapping(MethodGraph graph) {
|
private void achieveObtainDigitMapping(MethodDependency graph) {
|
||||||
graph.getResult().propagate("java.lang.String");
|
graph.getResult().propagate("java.lang.String");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import java.io.IOException;
|
||||||
import org.teavm.codegen.SourceWriter;
|
import org.teavm.codegen.SourceWriter;
|
||||||
import org.teavm.dependency.DependencyChecker;
|
import org.teavm.dependency.DependencyChecker;
|
||||||
import org.teavm.dependency.DependencyPlugin;
|
import org.teavm.dependency.DependencyPlugin;
|
||||||
import org.teavm.dependency.MethodGraph;
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.javascript.ni.Generator;
|
import org.teavm.javascript.ni.Generator;
|
||||||
import org.teavm.javascript.ni.GeneratorContext;
|
import org.teavm.javascript.ni.GeneratorContext;
|
||||||
import org.teavm.javascript.ni.Injector;
|
import org.teavm.javascript.ni.Injector;
|
||||||
|
@ -40,6 +40,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
||||||
generateInit(context, writer);
|
generateInit(context, writer);
|
||||||
break;
|
break;
|
||||||
case "hashCode":
|
case "hashCode":
|
||||||
|
case "identity":
|
||||||
generateHashCode(context, writer);
|
generateHashCode(context, writer);
|
||||||
break;
|
break;
|
||||||
case "clone":
|
case "clone":
|
||||||
|
@ -61,7 +62,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(DependencyChecker checker, MethodGraph graph) {
|
public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
|
||||||
switch (graph.getReference().getName()) {
|
switch (graph.getReference().getName()) {
|
||||||
case "clone":
|
case "clone":
|
||||||
achieveClone(graph);
|
achieveClone(graph);
|
||||||
|
@ -86,7 +87,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
||||||
writer.append(".constructor)");
|
writer.append(".constructor)");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveGetClass(DependencyChecker checker, MethodGraph graph) {
|
private void achieveGetClass(DependencyChecker checker, MethodDependency graph) {
|
||||||
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)));
|
||||||
|
@ -107,7 +108,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
||||||
writer.append("return copy;").softNewLine();
|
writer.append("return copy;").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveClone(MethodGraph graph) {
|
private void achieveClone(MethodDependency graph) {
|
||||||
graph.getVariable(0).connect(graph.getResult());
|
graph.getVariable(0).connect(graph.getResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +116,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
||||||
context.writeExpr(context.getArgument(0));
|
context.writeExpr(context.getArgument(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveWrap(MethodGraph graph) {
|
private void achieveWrap(MethodDependency graph) {
|
||||||
graph.getVariable(1).connect(graph.getResult());
|
graph.getVariable(1).connect(graph.getResult());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import org.teavm.codegen.SourceWriter;
|
||||||
import org.teavm.dependency.DependencyChecker;
|
import org.teavm.dependency.DependencyChecker;
|
||||||
import org.teavm.dependency.DependencyNode;
|
import org.teavm.dependency.DependencyNode;
|
||||||
import org.teavm.dependency.DependencyPlugin;
|
import org.teavm.dependency.DependencyPlugin;
|
||||||
import org.teavm.dependency.MethodGraph;
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.javascript.ni.Generator;
|
import org.teavm.javascript.ni.Generator;
|
||||||
import org.teavm.javascript.ni.GeneratorContext;
|
import org.teavm.javascript.ni.GeneratorContext;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -43,7 +43,7 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(DependencyChecker checker, MethodGraph graph) {
|
public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
|
||||||
switch (graph.getReference().getName()) {
|
switch (graph.getReference().getName()) {
|
||||||
case "doArrayCopy":
|
case "doArrayCopy":
|
||||||
achieveArrayCopy(graph);
|
achieveArrayCopy(graph);
|
||||||
|
@ -66,7 +66,7 @@ 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(MethodGraph graph) {
|
private void achieveArrayCopy(MethodDependency graph) {
|
||||||
DependencyNode src = graph.getVariable(1);
|
DependencyNode src = graph.getVariable(1);
|
||||||
DependencyNode dest = graph.getVariable(3);
|
DependencyNode dest = graph.getVariable(3);
|
||||||
src.getArrayItem().connect(dest.getArrayItem());
|
src.getArrayItem().connect(dest.getArrayItem());
|
||||||
|
|
|
@ -23,7 +23,7 @@ import org.teavm.javascript.ni.InjectedBy;
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class TClass<T> extends TObject {
|
public class TClass<T> extends TObject {
|
||||||
String name;
|
TString name;
|
||||||
boolean primitive;
|
boolean primitive;
|
||||||
boolean array;
|
boolean array;
|
||||||
private TClass<?> componentType;
|
private TClass<?> componentType;
|
||||||
|
@ -39,7 +39,7 @@ public class TClass<T> extends TObject {
|
||||||
@InjectedBy(ClassNativeGenerator.class)
|
@InjectedBy(ClassNativeGenerator.class)
|
||||||
public native boolean isAssignableFrom(TClass<?> obj);
|
public native boolean isAssignableFrom(TClass<?> obj);
|
||||||
|
|
||||||
public String getName() {
|
public TString getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,12 @@ public class TObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Rename("toString")
|
@Rename("toString")
|
||||||
public native TString toString0();
|
public TString toString0() {
|
||||||
|
return TString.wrap(getClass().getName() + "@" + identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GeneratedBy(ObjectNativeGenerator.class)
|
||||||
|
native int identity();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@GeneratedBy(ObjectNativeGenerator.class)
|
@GeneratedBy(ObjectNativeGenerator.class)
|
||||||
|
|
|
@ -20,7 +20,7 @@ import org.teavm.codegen.SourceWriter;
|
||||||
import org.teavm.dependency.DependencyChecker;
|
import org.teavm.dependency.DependencyChecker;
|
||||||
import org.teavm.dependency.DependencyConsumer;
|
import org.teavm.dependency.DependencyConsumer;
|
||||||
import org.teavm.dependency.DependencyPlugin;
|
import org.teavm.dependency.DependencyPlugin;
|
||||||
import org.teavm.dependency.MethodGraph;
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.javascript.ni.Generator;
|
import org.teavm.javascript.ni.Generator;
|
||||||
import org.teavm.javascript.ni.GeneratorContext;
|
import org.teavm.javascript.ni.GeneratorContext;
|
||||||
import org.teavm.model.MethodDescriptor;
|
import org.teavm.model.MethodDescriptor;
|
||||||
|
@ -33,7 +33,7 @@ import org.teavm.model.ValueType;
|
||||||
*/
|
*/
|
||||||
public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(DependencyChecker checker, MethodGraph graph) {
|
public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
|
||||||
if (graph.getReference().getName().equals("getLength")) {
|
if (graph.getReference().getName().equals("getLength")) {
|
||||||
achieveGetLength(checker, graph);
|
achieveGetLength(checker, graph);
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ 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 MethodGraph graph) {
|
private void achieveGetLength(final DependencyChecker checker, final MethodDependency graph) {
|
||||||
graph.getVariable(1).addConsumer(new DependencyConsumer() {
|
graph.getVariable(1).addConsumer(new DependencyConsumer() {
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(String type) {
|
||||||
if (!type.startsWith("[")) {
|
if (!type.startsWith("[")) {
|
||||||
|
|
|
@ -29,14 +29,16 @@ import org.teavm.model.*;
|
||||||
public class DependencyChecker implements DependencyInformation {
|
public class DependencyChecker implements DependencyInformation {
|
||||||
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 ClassHolderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
private ClassLoader classLoader;
|
private ClassLoader classLoader;
|
||||||
private FiniteExecutor executor;
|
private FiniteExecutor executor;
|
||||||
|
private Mapper<MethodReference, MethodReader> methodReaderCache;
|
||||||
|
private Mapper<FieldReference, FieldReader> fieldReaderCache;
|
||||||
private ConcurrentMap<MethodReference, Object> abstractMethods = new ConcurrentHashMap<>();
|
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, MethodGraph> methodCache;
|
private ConcurrentCachedMapper<MethodReference, MethodDependency> methodCache;
|
||||||
private ConcurrentCachedMapper<FieldReference, DependencyNode> fieldCache;
|
private ConcurrentCachedMapper<FieldReference, DependencyNode> 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<>();
|
||||||
|
@ -45,28 +47,48 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
ConcurrentMap<String, DependencyStack> missingClasses = new ConcurrentHashMap<>();
|
ConcurrentMap<String, DependencyStack> missingClasses = new ConcurrentHashMap<>();
|
||||||
ConcurrentMap<FieldReference, DependencyStack> missingFields = new ConcurrentHashMap<>();
|
ConcurrentMap<FieldReference, DependencyStack> missingFields = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader) {
|
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader) {
|
||||||
this(classSource, classLoader, new SimpleFiniteExecutor());
|
this(classSource, classLoader, new SimpleFiniteExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
|
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
methodCache = new ConcurrentCachedMapper<>(new Mapper<MethodReference, MethodGraph>() {
|
methodReaderCache = new ConcurrentCachedMapper<>(new Mapper<MethodReference, MethodReader>() {
|
||||||
@Override public MethodGraph map(MethodReference preimage) {
|
@Override public MethodReader map(MethodReference preimage) {
|
||||||
return createMethodGraph(preimage, stacks.get(preimage));
|
return findMethodReader(preimage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fieldReaderCache = new ConcurrentCachedMapper<>(new Mapper<FieldReference, FieldReader>() {
|
||||||
|
@Override public FieldReader map(FieldReference preimage) {
|
||||||
|
return findFieldReader(preimage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
methodCache = new ConcurrentCachedMapper<>(new Mapper<MethodReference, MethodDependency>() {
|
||||||
|
@Override public MethodDependency map(MethodReference preimage) {
|
||||||
|
MethodReader method = methodReaderCache.map(preimage);
|
||||||
|
if (method != null && !method.getReference().equals(preimage)) {
|
||||||
|
stacks.put(method.getReference(), stacks.get(preimage));
|
||||||
|
return methodCache.map(method.getReference());
|
||||||
|
}
|
||||||
|
return createMethodDep(preimage, method, stacks.get(preimage));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fieldCache = new ConcurrentCachedMapper<>(new Mapper<FieldReference, DependencyNode>() {
|
fieldCache = new ConcurrentCachedMapper<>(new Mapper<FieldReference, DependencyNode>() {
|
||||||
@Override public DependencyNode map(FieldReference preimage) {
|
@Override public DependencyNode map(FieldReference preimage) {
|
||||||
return createFieldNode(preimage, fieldStacks.get(preimage));
|
FieldReader field = fieldReaderCache.map(preimage);
|
||||||
|
if (field != null && !field.getReference().equals(preimage)) {
|
||||||
|
fieldStacks.put(field.getReference(), fieldStacks.get(preimage));
|
||||||
|
return fieldCache.map(field.getReference());
|
||||||
|
}
|
||||||
|
return createFieldNode(preimage, field, fieldStacks.get(preimage));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
methodCache.addKeyListener(new KeyListener<MethodReference>() {
|
methodCache.addKeyListener(new KeyListener<MethodReference>() {
|
||||||
@Override public void keyAdded(MethodReference key) {
|
@Override public void keyAdded(MethodReference key) {
|
||||||
MethodGraph graph = methodCache.getKnown(key);
|
MethodDependency graph = methodCache.getKnown(key);
|
||||||
if (!missingMethods.containsKey(key) && !missingClasses.containsKey(key.getClassName())) {
|
if (!graph.isMissing()) {
|
||||||
for (DependencyListener listener : listeners) {
|
for (DependencyListener listener : listeners) {
|
||||||
listener.methodAchieved(DependencyChecker.this, graph);
|
listener.methodAchieved(DependencyChecker.this, graph);
|
||||||
}
|
}
|
||||||
|
@ -90,7 +112,7 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
return new DependencyNode(this);
|
return new DependencyNode(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassHolderSource getClassSource() {
|
public ClassReaderSource getClassSource() {
|
||||||
return classSource;
|
return classSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +131,7 @@ 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");
|
||||||
}
|
}
|
||||||
MethodGraph graph = attachMethodGraph(methodRef, DependencyStack.ROOT);
|
MethodDependency graph = linkMethod(methodRef, DependencyStack.ROOT);
|
||||||
DependencyNode[] varNodes = graph.getVariables();
|
DependencyNode[] varNodes = graph.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) {
|
||||||
|
@ -140,7 +162,7 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodGraph attachMethodGraph(MethodReference methodRef, DependencyStack stack) {
|
public MethodDependency linkMethod(MethodReference methodRef, DependencyStack stack) {
|
||||||
stacks.putIfAbsent(methodRef, stack);
|
stacks.putIfAbsent(methodRef, stack);
|
||||||
return methodCache.map(methodRef);
|
return methodCache.map(methodRef);
|
||||||
}
|
}
|
||||||
|
@ -154,14 +176,14 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
}
|
}
|
||||||
achieveClass(className, stack);
|
achieveClass(className, stack);
|
||||||
achieveInterfaces(className, stack);
|
achieveInterfaces(className, stack);
|
||||||
ClassHolder cls = classSource.get(className);
|
ClassReader cls = classSource.get(className);
|
||||||
if (cls == null) {
|
if (cls == null) {
|
||||||
missingClasses.put(className, stack);
|
missingClasses.put(className, stack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cls.getMethod(clinitDesc) != null) {
|
if (cls.getMethod(clinitDesc) != null) {
|
||||||
MethodReference methodRef = new MethodReference(className, clinitDesc);
|
MethodReference methodRef = new MethodReference(className, clinitDesc);
|
||||||
attachMethodGraph(methodRef, new DependencyStack(methodRef, stack));
|
linkMethod(methodRef, new DependencyStack(methodRef, stack));
|
||||||
}
|
}
|
||||||
className = cls.getParent();
|
className = cls.getParent();
|
||||||
}
|
}
|
||||||
|
@ -169,7 +191,7 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
|
|
||||||
private void achieveInterfaces(String className, DependencyStack stack) {
|
private void achieveInterfaces(String className, DependencyStack stack) {
|
||||||
classStacks.putIfAbsent(className, stack);
|
classStacks.putIfAbsent(className, stack);
|
||||||
ClassHolder cls = classSource.get(className);
|
ClassReader cls = classSource.get(className);
|
||||||
if (cls == null) {
|
if (cls == null) {
|
||||||
missingClasses.put(className, stack);
|
missingClasses.put(className, stack);
|
||||||
return;
|
return;
|
||||||
|
@ -181,29 +203,44 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodGraph createMethodGraph(final MethodReference methodRef, DependencyStack stack) {
|
private MethodReader findMethodReader(MethodReference methodRef) {
|
||||||
|
String clsName = methodRef.getClassName();
|
||||||
|
MethodDescriptor desc = methodRef.getDescriptor();
|
||||||
|
while (clsName != null) {
|
||||||
|
ClassReader cls = classSource.get(clsName);
|
||||||
|
if (cls == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
MethodReader method = cls.getMethod(desc);
|
||||||
|
if (method != null) {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
clsName = cls.getParent();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldReader findFieldReader(FieldReference fieldRef) {
|
||||||
|
String clsName = fieldRef.getClassName();
|
||||||
|
String name = fieldRef.getFieldName();
|
||||||
|
while (clsName != null) {
|
||||||
|
ClassReader cls = classSource.get(clsName);
|
||||||
|
if (cls == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
FieldReader field = cls.getField(name);
|
||||||
|
if (field != null) {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
clsName = cls.getParent();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodDependency createMethodDep(MethodReference methodRef, MethodReader method, DependencyStack stack) {
|
||||||
if (stack == null) {
|
if (stack == null) {
|
||||||
stack = DependencyStack.ROOT;
|
stack = DependencyStack.ROOT;
|
||||||
}
|
}
|
||||||
initClass(methodRef.getClassName(), stack);
|
|
||||||
ClassHolder cls = classSource.get(methodRef.getClassName());
|
|
||||||
MethodHolder method;
|
|
||||||
if (cls == null) {
|
|
||||||
missingClasses.put(methodRef.getClassName(), stack);
|
|
||||||
method = null;
|
|
||||||
} else {
|
|
||||||
method = cls.getMethod(methodRef.getDescriptor());
|
|
||||||
if (method == null) {
|
|
||||||
while (cls != null) {
|
|
||||||
method = cls.getMethod(methodRef.getDescriptor());
|
|
||||||
if (method != null) {
|
|
||||||
return attachMethodGraph(method.getReference(), stack);
|
|
||||||
}
|
|
||||||
cls = cls.getParent() != null ? classSource.get(cls.getParent()) : null;
|
|
||||||
}
|
|
||||||
missingMethods.put(methodRef, stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ValueType[] arguments = methodRef.getParameterTypes();
|
ValueType[] arguments = methodRef.getParameterTypes();
|
||||||
int paramCount = arguments.length + 1;
|
int paramCount = arguments.length + 1;
|
||||||
int varCount = Math.max(paramCount, method != null ? method.getProgram().variableCount() : 0);
|
int varCount = Math.max(paramCount, method != null ? method.getProgram().variableCount() : 0);
|
||||||
|
@ -224,17 +261,23 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack = new DependencyStack(methodRef, stack);
|
stack = new DependencyStack(methodRef, stack);
|
||||||
final MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode, stack, methodRef);
|
final MethodDependency dep = new MethodDependency(parameterNodes, paramCount, resultNode, stack, method,
|
||||||
|
methodRef);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
final MethodHolder currentMethod = method;
|
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, graph);
|
graphBuilder.buildGraph(currentMethod, dep);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
missingMethods.putIfAbsent(methodRef, stack);
|
||||||
}
|
}
|
||||||
return graph;
|
if (method != null) {
|
||||||
|
initClass(methodRef.getClassName(), stack);
|
||||||
|
}
|
||||||
|
return dep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMethodAchievable(MethodReference methodRef) {
|
public boolean isMethodAchievable(MethodReference methodRef) {
|
||||||
|
@ -260,7 +303,7 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
return new HashSet<>(achievableClasses.keySet());
|
return new HashSet<>(achievableClasses.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
public DependencyNode attachFieldNode(FieldReference fieldRef, DependencyStack stack) {
|
public DependencyNode linkField(FieldReference fieldRef, DependencyStack stack) {
|
||||||
fieldStacks.putIfAbsent(fieldRef, stack);
|
fieldStacks.putIfAbsent(fieldRef, stack);
|
||||||
return fieldCache.map(fieldRef);
|
return fieldCache.map(fieldRef);
|
||||||
}
|
}
|
||||||
|
@ -270,38 +313,27 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
return fieldCache.getKnown(fieldRef);
|
return fieldCache.getKnown(fieldRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DependencyNode createFieldNode(FieldReference fieldRef, DependencyStack stack) {
|
private DependencyNode createFieldNode(FieldReference fieldRef, FieldReader field, DependencyStack stack) {
|
||||||
initClass(fieldRef.getClassName(), stack);
|
|
||||||
ClassHolder cls = classSource.get(fieldRef.getClassName());
|
|
||||||
if (cls == null) {
|
|
||||||
missingClasses.put(fieldRef.getClassName(), stack);
|
|
||||||
} else {
|
|
||||||
FieldHolder field = cls.getField(fieldRef.getFieldName());
|
|
||||||
if (field == null) {
|
|
||||||
while (cls != null) {
|
|
||||||
field = cls.getField(fieldRef.getFieldName());
|
|
||||||
if (field != null) {
|
|
||||||
return attachFieldNode(new FieldReference(cls.getName(), fieldRef.getFieldName()), stack);
|
|
||||||
}
|
|
||||||
cls = cls.getParent() != null ? classSource.get(cls.getParent()) : null;
|
|
||||||
}
|
|
||||||
missingFields.put(fieldRef, stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DependencyNode node = new DependencyNode(this);
|
DependencyNode node = new DependencyNode(this);
|
||||||
|
if (field == null) {
|
||||||
|
missingFields.putIfAbsent(fieldRef, stack);
|
||||||
|
}
|
||||||
if (shouldLog) {
|
if (shouldLog) {
|
||||||
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
|
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
|
||||||
}
|
}
|
||||||
|
if (field != null) {
|
||||||
|
initClass(fieldRef.getClassName(), stack);
|
||||||
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activateDependencyPlugin(MethodGraph graph) {
|
private void activateDependencyPlugin(MethodDependency graph) {
|
||||||
MethodReference methodRef = graph.getReference();
|
MethodReference methodRef = graph.getReference();
|
||||||
ClassHolder cls = classSource.get(methodRef.getClassName());
|
ClassReader cls = classSource.get(methodRef.getClassName());
|
||||||
if (cls == null) {
|
if (cls == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MethodHolder method = cls.getMethod(methodRef.getDescriptor());
|
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -331,11 +363,11 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
if (abstractMethods.putIfAbsent(methodRef, methodRef) == null) {
|
if (abstractMethods.putIfAbsent(methodRef, methodRef) == null) {
|
||||||
String className = methodRef.getClassName();
|
String className = methodRef.getClassName();
|
||||||
while (className != null) {
|
while (className != null) {
|
||||||
ClassHolder cls = classSource.get(className);
|
ClassReader cls = classSource.get(className);
|
||||||
if (cls == null) {
|
if (cls == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MethodHolder method = cls.getMethod(methodRef.getDescriptor());
|
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
abstractMethods.put(methodRef, methodRef);
|
abstractMethods.put(methodRef, methodRef);
|
||||||
return;
|
return;
|
||||||
|
@ -345,7 +377,7 @@ public class DependencyChecker implements DependencyInformation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListableClassHolderSource cutUnachievableClasses() {
|
public ListableClassHolderSource cutUnachievableClasses(ClassHolderSource classSource) {
|
||||||
MutableClassHolderSource cutClasses = new MutableClassHolderSource();
|
MutableClassHolderSource cutClasses = new MutableClassHolderSource();
|
||||||
for (String className : achievableClasses.keySet()) {
|
for (String className : achievableClasses.keySet()) {
|
||||||
ClassHolder classHolder = classSource.get(className);
|
ClassHolder classHolder = classSource.get(className);
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
package org.teavm.dependency;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.*;
|
||||||
import org.teavm.model.instructions.*;
|
import org.teavm.model.instructions.*;
|
||||||
import org.teavm.model.util.ListingBuilder;
|
import org.teavm.model.util.ListingBuilder;
|
||||||
|
@ -28,15 +30,15 @@ class DependencyGraphBuilder {
|
||||||
private DependencyChecker dependencyChecker;
|
private DependencyChecker dependencyChecker;
|
||||||
private DependencyNode[] nodes;
|
private DependencyNode[] nodes;
|
||||||
private DependencyNode resultNode;
|
private DependencyNode resultNode;
|
||||||
private Program program;
|
private ProgramReader program;
|
||||||
private DependencyStack callerStack;
|
private DependencyStack callerStack;
|
||||||
|
|
||||||
public DependencyGraphBuilder(DependencyChecker dependencyChecker) {
|
public DependencyGraphBuilder(DependencyChecker dependencyChecker) {
|
||||||
this.dependencyChecker = dependencyChecker;
|
this.dependencyChecker = dependencyChecker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void buildGraph(MethodHolder method, MethodGraph graph) {
|
public void buildGraph(MethodReader method, MethodDependency graph) {
|
||||||
if (method.getProgram().basicBlockCount() == 0) {
|
if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callerStack = graph.getStack();
|
callerStack = graph.getStack();
|
||||||
|
@ -48,12 +50,10 @@ class DependencyGraphBuilder {
|
||||||
resultNode = graph.getResult();
|
resultNode = graph.getResult();
|
||||||
nodes = graph.getVariables();
|
nodes = graph.getVariables();
|
||||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
BasicBlock block = program.basicBlockAt(i);
|
BasicBlockReader block = program.basicBlockAt(i);
|
||||||
for (Instruction insn : block.getInstructions()) {
|
block.readAllInstructions(reader);
|
||||||
insn.acceptVisitor(visitor);
|
for (PhiReader phi : block.readPhis()) {
|
||||||
}
|
for (IncomingReader incoming : phi.readIncomings()) {
|
||||||
for (Phi phi : block.getPhis()) {
|
|
||||||
for (Incoming incoming : phi.getIncomings()) {
|
|
||||||
nodes[incoming.getValue().getIndex()].connect(nodes[phi.getReceiver().getIndex()]);
|
nodes[incoming.getValue().getIndex()].connect(nodes[phi.getReceiver().getIndex()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,7 @@ class DependencyGraphBuilder {
|
||||||
private final DependencyNode[] parameters;
|
private final DependencyNode[] parameters;
|
||||||
private final DependencyNode result;
|
private final DependencyNode result;
|
||||||
private final DependencyStack stack;
|
private final DependencyStack stack;
|
||||||
|
private final ConcurrentMap<MethodReference, MethodReference> knownMethods = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public VirtualCallPropagationListener(DependencyNode node, MethodDescriptor methodDesc,
|
public VirtualCallPropagationListener(DependencyNode node, MethodDescriptor methodDesc,
|
||||||
DependencyChecker checker, DependencyNode[] parameters, DependencyNode result,
|
DependencyChecker checker, DependencyNode[] parameters, DependencyNode result,
|
||||||
|
@ -89,262 +90,256 @@ class DependencyGraphBuilder {
|
||||||
className = "java.lang.Object";
|
className = "java.lang.Object";
|
||||||
}
|
}
|
||||||
MethodReference methodRef = new MethodReference(className, methodDesc);
|
MethodReference methodRef = new MethodReference(className, methodDesc);
|
||||||
MethodHolder method = findMethod(methodRef, checker.getClassSource());
|
MethodDependency methodDep = checker.linkMethod(methodRef, stack);
|
||||||
if (method == null) {
|
if (!methodDep.isMissing() && knownMethods.putIfAbsent(methodRef, methodRef) == null) {
|
||||||
return;
|
DependencyNode[] targetParams = methodDep.getVariables();
|
||||||
}
|
|
||||||
MethodGraph targetGraph = checker.attachMethodGraph(methodRef, stack);
|
|
||||||
DependencyNode[] targetParams = targetGraph.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]);
|
||||||
}
|
}
|
||||||
if (targetGraph.getResult() != null) {
|
if (methodDep.getResult() != null) {
|
||||||
targetGraph.getResult().connect(result);
|
methodDep.getResult().connect(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodHolder findMethod(MethodReference methodRef, ClassHolderSource classSource) {
|
private InstructionReader reader = new InstructionReader() {
|
||||||
String className = methodRef.getClassName();
|
|
||||||
while (className != null) {
|
|
||||||
ClassHolder cls = classSource.get(className);
|
|
||||||
if (cls == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
MethodHolder method = cls.getMethod(methodRef.getDescriptor());
|
|
||||||
if (method != null) {
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
className = cls.getParent();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private InstructionVisitor visitor = new InstructionVisitor() {
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(IsInstanceInstruction insn) {
|
public void nop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InvokeInstruction insn) {
|
public void classConstant(VariableReader receiver, ValueType cst) {
|
||||||
if (insn.getInstance() == null) {
|
nodes[receiver.getIndex()].propagate("java.lang.Class");
|
||||||
invokeSpecial(insn);
|
while (cst instanceof ValueType.Array) {
|
||||||
} else {
|
cst = ((ValueType.Array)cst).getItemType();
|
||||||
switch (insn.getType()) {
|
|
||||||
case SPECIAL:
|
|
||||||
invokeSpecial(insn);
|
|
||||||
break;
|
|
||||||
case VIRTUAL:
|
|
||||||
invokeVirtual(insn);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if (cst instanceof ValueType.Object) {
|
||||||
|
dependencyChecker.achieveClass(((ValueType.Object)cst).getClassName(), callerStack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invokeSpecial(InvokeInstruction insn) {
|
|
||||||
MethodGraph targetGraph = dependencyChecker.attachMethodGraph(insn.getMethod(), callerStack);
|
|
||||||
DependencyNode[] targetParams = targetGraph.getVariables();
|
|
||||||
List<Variable> arguments = insn.getArguments();
|
|
||||||
for (int i = 0; i < arguments.size(); ++i) {
|
|
||||||
nodes[arguments.get(i).getIndex()].connect(targetParams[i + 1]);
|
|
||||||
}
|
|
||||||
if (insn.getInstance() != null) {
|
|
||||||
nodes[insn.getInstance().getIndex()].connect(targetParams[0]);
|
|
||||||
}
|
|
||||||
if (targetGraph.getResult() != null && insn.getReceiver() != null) {
|
|
||||||
targetGraph.getResult().connect(nodes[insn.getReceiver().getIndex()]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void invokeVirtual(InvokeInstruction insn) {
|
|
||||||
List<Variable> arguments = insn.getArguments();
|
|
||||||
DependencyNode[] actualArgs = new DependencyNode[arguments.size() + 1];
|
|
||||||
for (int i = 0; i < arguments.size(); ++i) {
|
|
||||||
actualArgs[i + 1] = nodes[arguments.get(i).getIndex()];
|
|
||||||
}
|
|
||||||
actualArgs[0] = nodes[insn.getInstance().getIndex()];
|
|
||||||
DependencyConsumer listener = new VirtualCallPropagationListener(nodes[insn.getInstance().getIndex()],
|
|
||||||
insn.getMethod().getDescriptor(), dependencyChecker, actualArgs,
|
|
||||||
insn.getReceiver() != null ? nodes[insn.getReceiver().getIndex()] : null, callerStack);
|
|
||||||
dependencyChecker.addAbstractMethod(insn.getMethod(), callerStack);
|
|
||||||
nodes[insn.getInstance().getIndex()].addConsumer(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(PutElementInstruction insn) {
|
public void nullConstant(VariableReader receiver) {
|
||||||
DependencyNode valueNode = nodes[insn.getValue().getIndex()];
|
|
||||||
DependencyNode arrayNode = nodes[insn.getArray().getIndex()];
|
|
||||||
valueNode.connect(arrayNode.getArrayItem());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(GetElementInstruction insn) {
|
public void integerConstant(VariableReader receiver, int cst) {
|
||||||
DependencyNode arrayNode = nodes[insn.getArray().getIndex()];
|
|
||||||
DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()];
|
|
||||||
arrayNode.getArrayItem().connect(receiverNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(UnwrapArrayInstruction insn) {
|
public void longConstant(VariableReader receiver, long cst) {
|
||||||
DependencyNode arrayNode = nodes[insn.getArray().getIndex()];
|
|
||||||
DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()];
|
|
||||||
arrayNode.connect(receiverNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(CloneArrayInstruction insn) {
|
public void floatConstant(VariableReader receiver, float cst) {
|
||||||
DependencyNode arrayNode = nodes[insn.getArray().getIndex()];
|
}
|
||||||
final DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()];
|
|
||||||
|
@Override
|
||||||
|
public void doubleConstant(VariableReader receiver, double cst) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stringConstant(VariableReader receiver, String cst) {
|
||||||
|
nodes[receiver.getIndex()].propagate("java.lang.String");
|
||||||
|
dependencyChecker.linkMethod(new MethodReference("java.lang.String", new MethodDescriptor(
|
||||||
|
"<init>", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), callerStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
|
||||||
|
NumericOperandType type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assign(VariableReader receiver, VariableReader assignee) {
|
||||||
|
DependencyNode valueNode = nodes[assignee.getIndex()];
|
||||||
|
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||||
|
valueNode.connect(receiverNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
||||||
|
DependencyNode valueNode = nodes[value.getIndex()];
|
||||||
|
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||||
|
valueNode.connect(receiverNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
|
||||||
|
NumericOperandType targetType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
|
||||||
|
CastIntegerDirection targetType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
|
||||||
|
BasicBlockReader alternative) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
|
||||||
|
BasicBlockReader consequent, BasicBlockReader alternative) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jump(BasicBlockReader target) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
|
||||||
|
BasicBlockReader defaultTarget) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exit(VariableReader valueToReturn) {
|
||||||
|
if (valueToReturn != null) {
|
||||||
|
nodes[valueToReturn.getIndex()].connect(resultNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void raise(VariableReader exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
||||||
|
nodes[receiver.getIndex()].propagate("[" + itemType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createArray(VariableReader receiver, ValueType itemType,
|
||||||
|
List<? extends VariableReader> dimensions) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < dimensions.size(); ++i) {
|
||||||
|
sb.append('[');
|
||||||
|
}
|
||||||
|
sb.append(itemType);
|
||||||
|
nodes[receiver.getIndex()].propagate(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void create(VariableReader receiver, String type) {
|
||||||
|
nodes[receiver.getIndex()].propagate(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
|
||||||
|
ValueType fieldType) {
|
||||||
|
DependencyNode fieldNode = dependencyChecker.linkField(field, callerStack);
|
||||||
|
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||||
|
fieldNode.connect(receiverNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
|
||||||
|
DependencyNode fieldNode = dependencyChecker.linkField(field, callerStack);
|
||||||
|
DependencyNode valueNode = nodes[value.getIndex()];
|
||||||
|
valueNode.connect(fieldNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void arrayLength(VariableReader receiver, VariableReader array) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneArray(VariableReader receiver, VariableReader array) {
|
||||||
|
DependencyNode arrayNode = nodes[array.getIndex()];
|
||||||
|
final DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||||
arrayNode.addConsumer(new DependencyConsumer() {
|
arrayNode.addConsumer(new DependencyConsumer() {
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(String type) {
|
||||||
receiverNode.propagate(type);
|
receiverNode.propagate(type);
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
arrayNode.getArrayItem().connect(receiverNode.getArrayItem());
|
arrayNode.getArrayItem().connect(receiverNode.getArrayItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ArrayLengthInstruction insn) {
|
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
|
||||||
|
DependencyNode arrayNode = nodes[array.getIndex()];
|
||||||
|
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||||
|
arrayNode.connect(receiverNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(PutFieldInstruction insn) {
|
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
|
||||||
DependencyNode fieldNode = dependencyChecker.attachFieldNode(insn.getField(), callerStack);
|
DependencyNode arrayNode = nodes[array.getIndex()];
|
||||||
DependencyNode valueNode = nodes[insn.getValue().getIndex()];
|
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||||
valueNode.connect(fieldNode);
|
arrayNode.getArrayItem().connect(receiverNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(GetFieldInstruction insn) {
|
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
|
||||||
DependencyNode fieldNode = dependencyChecker.attachFieldNode(insn.getField(), callerStack);
|
DependencyNode valueNode = nodes[value.getIndex()];
|
||||||
DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()];
|
DependencyNode arrayNode = nodes[array.getIndex()];
|
||||||
fieldNode.connect(receiverNode);
|
valueNode.connect(arrayNode.getArrayItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConstructMultiArrayInstruction insn) {
|
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
|
||||||
StringBuilder sb = new StringBuilder();
|
List<? extends VariableReader> arguments, InvocationType type) {
|
||||||
for (int i = 0; i < insn.getDimensions().size(); ++i) {
|
if (instance == null) {
|
||||||
sb.append('[');
|
invokeSpecial(receiver, instance, method, arguments);
|
||||||
|
} else {
|
||||||
|
switch (type) {
|
||||||
|
case SPECIAL:
|
||||||
|
invokeSpecial(receiver, instance, method, arguments);
|
||||||
|
break;
|
||||||
|
case VIRTUAL:
|
||||||
|
invokeVirtual(receiver, instance, method, arguments);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
sb.append(insn.getItemType());
|
|
||||||
nodes[insn.getReceiver().getIndex()].propagate(sb.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ConstructInstruction insn) {
|
|
||||||
nodes[insn.getReceiver().getIndex()].propagate(insn.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ConstructArrayInstruction insn) {
|
|
||||||
nodes[insn.getReceiver().getIndex()].propagate("[" + insn.getItemType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(RaiseInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ExitInstruction insn) {
|
|
||||||
if (insn.getValueToReturn() != null) {
|
|
||||||
nodes[insn.getValueToReturn().getIndex()].connect(resultNode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void invokeSpecial(VariableReader receiver, VariableReader instance, MethodReference method,
|
||||||
public void visit(SwitchInstruction insn) {
|
List<? extends VariableReader> arguments) {
|
||||||
|
MethodDependency methodDep = dependencyChecker.linkMethod(method, callerStack);
|
||||||
|
if (methodDep.isMissing()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
DependencyNode[] targetParams = methodDep.getVariables();
|
||||||
@Override
|
for (int i = 0; i < arguments.size(); ++i) {
|
||||||
public void visit(JumpInstruction insn) {
|
nodes[arguments.get(i).getIndex()].connect(targetParams[i + 1]);
|
||||||
}
|
}
|
||||||
|
if (instance != null) {
|
||||||
@Override
|
nodes[instance.getIndex()].connect(targetParams[0]);
|
||||||
public void visit(BinaryBranchingInstruction insn) {
|
|
||||||
}
|
}
|
||||||
|
if (methodDep.getResult() != null && receiver != null) {
|
||||||
@Override
|
methodDep.getResult().connect(nodes[receiver.getIndex()]);
|
||||||
public void visit(BranchingInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CastNumberInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CastInstruction insn) {
|
|
||||||
DependencyNode valueNode = nodes[insn.getValue().getIndex()];
|
|
||||||
DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()];
|
|
||||||
valueNode.connect(receiverNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CastIntegerInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(AssignInstruction insn) {
|
|
||||||
DependencyNode valueNode = nodes[insn.getAssignee().getIndex()];
|
|
||||||
DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()];
|
|
||||||
valueNode.connect(receiverNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(NegateInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(BinaryInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(StringConstantInstruction insn) {
|
|
||||||
nodes[insn.getReceiver().getIndex()].propagate("java.lang.String");
|
|
||||||
dependencyChecker.attachMethodGraph(new MethodReference("java.lang.String", new MethodDescriptor(
|
|
||||||
"<init>", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), callerStack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(DoubleConstantInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(FloatConstantInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(LongConstantInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(IntegerConstantInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(NullConstantInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ClassConstantInstruction insn) {
|
|
||||||
nodes[insn.getReceiver().getIndex()].propagate("java.lang.Class");
|
|
||||||
ValueType type = insn.getConstant();
|
|
||||||
while (type instanceof ValueType.Array) {
|
|
||||||
type = ((ValueType.Array)type).getItemType();
|
|
||||||
}
|
|
||||||
if (type instanceof ValueType.Object) {
|
|
||||||
dependencyChecker.achieveClass(((ValueType.Object)type).getClassName(), callerStack);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method,
|
||||||
public void visit(EmptyInstruction insn) {
|
List<? extends VariableReader> arguments) {
|
||||||
|
if (dependencyChecker.linkMethod(method, callerStack).isMissing()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DependencyNode[] actualArgs = new DependencyNode[arguments.size() + 1];
|
||||||
|
for (int i = 0; i < arguments.size(); ++i) {
|
||||||
|
actualArgs[i + 1] = nodes[arguments.get(i).getIndex()];
|
||||||
|
}
|
||||||
|
actualArgs[0] = nodes[instance.getIndex()];
|
||||||
|
DependencyConsumer listener = new VirtualCallPropagationListener(nodes[instance.getIndex()],
|
||||||
|
method.getDescriptor(), dependencyChecker, actualArgs,
|
||||||
|
receiver != null ? nodes[receiver.getIndex()] : null, callerStack);
|
||||||
|
nodes[instance.getIndex()].addConsumer(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InitClassInstruction insn) {
|
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
|
||||||
dependencyChecker.initClass(insn.getClassName(), callerStack);
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initClass(String className) {
|
||||||
|
dependencyChecker.initClass(className, callerStack);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ public interface DependencyListener {
|
||||||
|
|
||||||
void classAchieved(DependencyChecker dependencyChecker, String className);
|
void classAchieved(DependencyChecker dependencyChecker, String className);
|
||||||
|
|
||||||
void methodAchieved(DependencyChecker dependencyChecker, MethodGraph method);
|
void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method);
|
||||||
|
|
||||||
void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field, DependencyNode node);
|
void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field, DependencyNode node);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,5 +20,5 @@ package org.teavm.dependency;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public interface DependencyPlugin {
|
public interface DependencyPlugin {
|
||||||
void methodAchieved(DependencyChecker checker, MethodGraph graph);
|
void methodAchieved(DependencyChecker checker, MethodDependency graph);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,25 +16,28 @@
|
||||||
package org.teavm.dependency;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class MethodGraph implements DependencyMethodInformation {
|
public class MethodDependency implements DependencyMethodInformation {
|
||||||
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 MethodReference reference;
|
private MethodReference reference;
|
||||||
|
|
||||||
MethodGraph(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode,
|
MethodDependency(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode,
|
||||||
DependencyStack stack, MethodReference reference) {
|
DependencyStack stack, MethodReader method, MethodReference reference) {
|
||||||
this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length);
|
this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length);
|
||||||
this.parameterCount = parameterCount;
|
this.parameterCount = parameterCount;
|
||||||
this.resultNode = resultNode;
|
this.resultNode = resultNode;
|
||||||
this.stack = stack;
|
this.stack = stack;
|
||||||
|
this.method = method;
|
||||||
this.reference = reference;
|
this.reference = reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,4 +73,12 @@ public class MethodGraph implements DependencyMethodInformation {
|
||||||
public MethodReference getReference() {
|
public MethodReference getReference() {
|
||||||
return reference;
|
return reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MethodReader getMethod() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMissing() {
|
||||||
|
return method == null;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -91,7 +91,7 @@ public class JavascriptBuilder implements JavascriptBuilderHost {
|
||||||
"for method " + ref);
|
"for method " + ref);
|
||||||
}
|
}
|
||||||
JavascriptEntryPoint entryPoint = new JavascriptEntryPoint(name, ref,
|
JavascriptEntryPoint entryPoint = new JavascriptEntryPoint(name, ref,
|
||||||
dependencyChecker.attachMethodGraph(ref, DependencyStack.ROOT));
|
dependencyChecker.linkMethod(ref, DependencyStack.ROOT));
|
||||||
entryPoints.put(name, entryPoint);
|
entryPoints.put(name, entryPoint);
|
||||||
return entryPoint;
|
return entryPoint;
|
||||||
}
|
}
|
||||||
|
@ -119,13 +119,13 @@ public class JavascriptBuilder implements JavascriptBuilderHost {
|
||||||
SourceWriterBuilder builder = new SourceWriterBuilder(naming);
|
SourceWriterBuilder builder = new SourceWriterBuilder(naming);
|
||||||
builder.setMinified(minifying);
|
builder.setMinified(minifying);
|
||||||
SourceWriter sourceWriter = builder.build(writer);
|
SourceWriter sourceWriter = builder.build(writer);
|
||||||
dependencyChecker.attachMethodGraph(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);
|
||||||
dependencyChecker.attachMethodGraph(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);
|
||||||
executor.complete();
|
executor.complete();
|
||||||
dependencyChecker.checkForMissingItems();
|
dependencyChecker.checkForMissingItems();
|
||||||
ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses();
|
ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses(classSource);
|
||||||
Decompiler decompiler = new Decompiler(classSet, classLoader, executor);
|
Decompiler decompiler = new Decompiler(classSet, classLoader, executor);
|
||||||
devirtualize(classSet, dependencyChecker);
|
devirtualize(classSet, dependencyChecker);
|
||||||
executor.complete();
|
executor.complete();
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.javascript;
|
package org.teavm.javascript;
|
||||||
|
|
||||||
import org.teavm.dependency.MethodGraph;
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,9 +25,9 @@ import org.teavm.model.MethodReference;
|
||||||
public class JavascriptEntryPoint {
|
public class JavascriptEntryPoint {
|
||||||
private String publicName;
|
private String publicName;
|
||||||
MethodReference reference;
|
MethodReference reference;
|
||||||
private MethodGraph graph;
|
private MethodDependency graph;
|
||||||
|
|
||||||
JavascriptEntryPoint(String publicName, MethodReference reference, MethodGraph graph) {
|
JavascriptEntryPoint(String publicName, MethodReference reference, MethodDependency graph) {
|
||||||
this.publicName = publicName;
|
this.publicName = publicName;
|
||||||
this.reference = reference;
|
this.reference = reference;
|
||||||
this.graph = graph;
|
this.graph = graph;
|
||||||
|
|
|
@ -59,4 +59,9 @@ public class FieldHolder extends MemberHolder implements FieldReader {
|
||||||
public String getOwnerName() {
|
public String getOwnerName() {
|
||||||
return owner != null ? owner.getName() : null;
|
return owner != null ? owner.getName() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FieldReference getReference() {
|
||||||
|
return new FieldReference(getOwnerName(), getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,4 +23,6 @@ public interface FieldReader extends MemberReader {
|
||||||
ValueType getType();
|
ValueType getType();
|
||||||
|
|
||||||
Object getInitialValue();
|
Object getInitialValue();
|
||||||
|
|
||||||
|
FieldReference getReference();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,14 @@
|
||||||
package org.teavm.model.util;
|
package org.teavm.model.util;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.teavm.model.Variable;
|
import org.teavm.model.*;
|
||||||
import org.teavm.model.instructions.*;
|
import org.teavm.model.instructions.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class InstructionStringifier implements InstructionVisitor {
|
public class InstructionStringifier implements InstructionReader {
|
||||||
private StringBuilder sb;
|
private StringBuilder sb;
|
||||||
|
|
||||||
public InstructionStringifier(StringBuilder sb) {
|
public InstructionStringifier(StringBuilder sb) {
|
||||||
|
@ -31,56 +31,50 @@ public class InstructionStringifier implements InstructionVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(EmptyInstruction insn) {
|
public void nop() {
|
||||||
sb.append("nop");
|
sb.append("nop");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ClassConstantInstruction insn) {
|
public void classConstant(VariableReader receiver, ValueType cst) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := classOf ")
|
sb.append("@").append(receiver.getIndex()).append(" := classOf ").append(cst);
|
||||||
.append(insn.getConstant());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(NullConstantInstruction insn) {
|
public void nullConstant(VariableReader receiver) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := null");
|
sb.append("@").append(receiver.getIndex()).append(" := null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(IntegerConstantInstruction insn) {
|
public void integerConstant(VariableReader receiver, int cst) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := ")
|
sb.append("@").append(receiver.getIndex()).append(" := ").append(cst);
|
||||||
.append(insn.getConstant());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(LongConstantInstruction insn) {
|
public void longConstant(VariableReader receiver, long cst) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := ")
|
sb.append("@").append(receiver.getIndex()).append(" := ").append(cst);
|
||||||
.append(insn.getConstant());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(FloatConstantInstruction insn) {
|
public void floatConstant(VariableReader receiver, float cst) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := ")
|
sb.append("@").append(receiver.getIndex()).append(" := ").append(cst);
|
||||||
.append(insn.getConstant());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(DoubleConstantInstruction insn) {
|
public void doubleConstant(VariableReader receiver, double cst) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := ")
|
sb.append("@").append(receiver.getIndex()).append(" := ").append(cst);
|
||||||
.append(insn.getConstant());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(StringConstantInstruction insn) {
|
public void stringConstant(VariableReader receiver, String cst) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := '")
|
sb.append("@").append(receiver.getIndex()).append(" := '").append(cst).append("'");
|
||||||
.append(insn.getConstant()).append("'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BinaryInstruction insn) {
|
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := @")
|
NumericOperandType type) {
|
||||||
.append(insn.getFirstOperand().getIndex()).append(" ");
|
sb.append("@").append(receiver.getIndex()).append(" := @").append(first.getIndex()).append(" ");
|
||||||
switch (insn.getOperation()) {
|
switch (op) {
|
||||||
case ADD:
|
case ADD:
|
||||||
sb.append("+");
|
sb.append("+");
|
||||||
break;
|
break;
|
||||||
|
@ -118,25 +112,51 @@ public class InstructionStringifier implements InstructionVisitor {
|
||||||
sb.append("^");
|
sb.append("^");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sb.append(" @").append(insn.getSecondOperand().getIndex());
|
sb.append(" @").append(second.getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(NegateInstruction insn) {
|
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := -")
|
sb.append("@").append(receiver.getIndex()).append(" := -").append(" @").append(operand.getIndex());
|
||||||
.append(" @").append(insn.getOperand().getIndex());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(AssignInstruction insn) {
|
public void assign(VariableReader receiver, VariableReader assignee) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := @")
|
sb.append("@").append(receiver.getIndex()).append(" := @").append(assignee.getIndex());
|
||||||
.append(insn.getAssignee().getIndex());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BranchingInstruction insn) {
|
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
||||||
sb.append("if @").append(insn.getOperand().getIndex()).append(" ");
|
sb.append("@").append(receiver.getIndex()).append(" := cast @").append(value.getIndex())
|
||||||
switch (insn.getCondition()) {
|
.append(" to ").append(targetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
|
||||||
|
NumericOperandType targetType) {
|
||||||
|
sb.append("@").append(receiver.getIndex()).append(" := cast @").append(value.getIndex())
|
||||||
|
.append(" from ").append(sourceType).append(" to ").append(targetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
|
||||||
|
CastIntegerDirection direction) {
|
||||||
|
sb.append("@").append(receiver.getIndex()).append(" := cast @").append(value.getIndex());
|
||||||
|
switch (direction) {
|
||||||
|
case FROM_INTEGER:
|
||||||
|
sb.append(" from INT to ").append(type);
|
||||||
|
break;
|
||||||
|
case TO_INTEGER:
|
||||||
|
sb.append(" from ").append(type).append(" to INT");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
|
||||||
|
BasicBlockReader alternative) {
|
||||||
|
sb.append("if @").append(operand.getIndex()).append(" ");
|
||||||
|
switch (cond) {
|
||||||
case EQUAL:
|
case EQUAL:
|
||||||
sb.append("== 0");
|
sb.append("== 0");
|
||||||
break;
|
break;
|
||||||
|
@ -162,14 +182,14 @@ public class InstructionStringifier implements InstructionVisitor {
|
||||||
sb.append("== null");
|
sb.append("== null");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sb.append(" then goto $").append(insn.getConsequent().getIndex()).append(" else goto $")
|
sb.append(" then goto $").append(consequent.getIndex()).append(" else goto $").append(alternative.getIndex());
|
||||||
.append(insn.getAlternative().getIndex());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BinaryBranchingInstruction insn) {
|
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
|
||||||
sb.append("if @").append(insn.getFirstOperand().getIndex()).append(" ");
|
BasicBlockReader consequent, BasicBlockReader alternative) {
|
||||||
switch (insn.getCondition()) {
|
sb.append("if @").append(first.getIndex()).append(" ");
|
||||||
|
switch (cond) {
|
||||||
case EQUAL:
|
case EQUAL:
|
||||||
case REFERENCE_EQUAL:
|
case REFERENCE_EQUAL:
|
||||||
sb.append("==");
|
sb.append("==");
|
||||||
|
@ -179,119 +199,125 @@ public class InstructionStringifier implements InstructionVisitor {
|
||||||
sb.append("!=");
|
sb.append("!=");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sb.append("@").append(insn.getSecondOperand().getIndex())
|
sb.append("@").append(second.getIndex()).append(" then goto $").append(consequent.getIndex())
|
||||||
.append(" then goto $").append(insn.getConsequent().getIndex())
|
.append(" else goto $").append(alternative.getIndex());
|
||||||
.append(" else goto $").append(insn.getAlternative().getIndex());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(JumpInstruction insn) {
|
public void jump(BasicBlockReader target) {
|
||||||
sb.append("goto $").append(insn.getTarget().getIndex());
|
sb.append("goto $").append(target.getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SwitchInstruction insn) {
|
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
|
||||||
sb.append("switch @").append(insn.getCondition().getIndex()).append(" ");
|
BasicBlockReader defaultTarget) {
|
||||||
List<SwitchTableEntry> entries = insn.getEntries();
|
sb.append("switch @").append(condition.getIndex()).append(" ");
|
||||||
for (int i = 0; i < entries.size(); ++i) {
|
for (int i = 0; i < table.size(); ++i) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
sb.append("; ");
|
sb.append("; ");
|
||||||
}
|
}
|
||||||
SwitchTableEntry entry = entries.get(i);
|
SwitchTableEntryReader entry = table.get(i);
|
||||||
sb.append("case ").append(entry.getCondition()).append(": goto $")
|
sb.append("case ").append(entry.getCondition()).append(": goto $").append(entry.getTarget());
|
||||||
.append(entry.getTarget());
|
|
||||||
}
|
}
|
||||||
sb.append(", default: goto $").append(insn.getDefaultTarget());
|
sb.append(", default: goto $").append(defaultTarget.getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ExitInstruction insn) {
|
public void exit(VariableReader valueToReturn) {
|
||||||
sb.append("return");
|
sb.append("return");
|
||||||
if (insn.getValueToReturn() != null) {
|
if (valueToReturn != null) {
|
||||||
sb.append(" @").append(insn.getValueToReturn().getIndex());
|
sb.append(" @").append(valueToReturn.getIndex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(RaiseInstruction insn) {
|
public void raise(VariableReader exception) {
|
||||||
sb.append("throw @").append(insn.getException().getIndex());
|
sb.append("throw @").append(exception.getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConstructArrayInstruction insn) {
|
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" = new ")
|
sb.append("@").append(receiver.getIndex()).append(" = new ").append(itemType).append("[@")
|
||||||
.append(insn.getItemType()).append("[@").append(insn.getSize().getIndex())
|
.append(size.getIndex()).append(']');
|
||||||
.append(']');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConstructInstruction insn) {
|
public void createArray(VariableReader receiver, ValueType itemType, List<? extends VariableReader> dimensions) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" = new ")
|
sb.append("@").append(receiver.getIndex()).append(" = new ").append(itemType).append("[");
|
||||||
.append(insn.getType()).append("()");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ConstructMultiArrayInstruction insn) {
|
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" = new ")
|
|
||||||
.append(insn.getItemType()).append("[");
|
|
||||||
List<Variable> dimensions = insn.getDimensions();
|
|
||||||
for (int i = 0; i < dimensions.size(); ++i) {
|
for (int i = 0; i < dimensions.size(); ++i) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
sb.append(", ");
|
sb.append(", ");
|
||||||
}
|
}
|
||||||
Variable dimension = dimensions.get(i);
|
sb.append("@").append(dimensions.get(i).getIndex());
|
||||||
sb.append("@").append(dimension.getIndex());
|
|
||||||
}
|
}
|
||||||
sb.append("]");
|
sb.append("]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(GetFieldInstruction insn) {
|
public void create(VariableReader receiver, String type) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := ");
|
sb.append("@").append(receiver.getIndex()).append(" = new ").append(type).append("()");
|
||||||
if (insn.getInstance() != null) {
|
}
|
||||||
sb.append("@").append(insn.getInstance().getIndex());
|
|
||||||
|
@Override
|
||||||
|
public void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType) {
|
||||||
|
sb.append("@").append(receiver.getIndex()).append(" := ");
|
||||||
|
if (instance != null) {
|
||||||
|
sb.append("@").append(instance.getIndex());
|
||||||
} else {
|
} else {
|
||||||
sb.append(insn.getField().getClassName());
|
sb.append(field.getClassName());
|
||||||
}
|
}
|
||||||
sb.append(".").append(insn.getField().getFieldName());
|
sb.append(".").append(field.getFieldName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(PutFieldInstruction insn) {
|
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
|
||||||
if (insn.getInstance() != null) {
|
if (instance != null) {
|
||||||
sb.append("@").append(insn.getInstance().getIndex());
|
sb.append("@").append(instance.getIndex());
|
||||||
} else {
|
} else {
|
||||||
sb.append(insn.getField().getClassName());
|
sb.append(field.getClassName());
|
||||||
}
|
}
|
||||||
sb.append(".").append(insn.getField().getFieldName()).append(" := @").append(insn.getValue().getIndex());
|
sb.append(".").append(field.getFieldName()).append(" := @").append(value.getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(GetElementInstruction insn) {
|
public void arrayLength(VariableReader receiver, VariableReader array) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := @")
|
sb.append("@").append(receiver.getIndex()).append(" := @").append(array.getIndex()).append(".length");
|
||||||
.append(insn.getArray().getIndex()).append("[@")
|
|
||||||
.append(insn.getIndex().getIndex()).append("]");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(PutElementInstruction insn) {
|
public void cloneArray(VariableReader receiver, VariableReader array) {
|
||||||
sb.append("@").append(insn.getArray().getIndex()).append("[@")
|
sb.append("@").append(receiver.getIndex()).append("@").append(array.getIndex()).append(".clone()");
|
||||||
.append(insn.getIndex().getIndex()).append("] := @")
|
|
||||||
.append(insn.getValue().getIndex());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InvokeInstruction insn) {
|
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
|
||||||
if (insn.getReceiver() != null) {
|
sb.append("@").append(receiver.getIndex()).append(" := @").append(array.getIndex()).append(".data");
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := ");
|
|
||||||
}
|
}
|
||||||
if (insn.getInstance() != null) {
|
|
||||||
sb.append("@").append(insn.getInstance().getIndex());
|
@Override
|
||||||
|
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
|
||||||
|
sb.append("@").append(receiver.getIndex()).append(" := @").append(array.getIndex()).append("[@")
|
||||||
|
.append(index.getIndex()).append("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
|
||||||
|
sb.append("@").append(array.getIndex()).append("[@").append(index.getIndex()).append("] := @")
|
||||||
|
.append(value.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
|
||||||
|
List<? extends VariableReader> arguments, InvocationType type) {
|
||||||
|
if (receiver != null) {
|
||||||
|
sb.append("@").append(receiver.getIndex()).append(" := ");
|
||||||
|
}
|
||||||
|
if (instance != null) {
|
||||||
|
sb.append("@").append(instance.getIndex());
|
||||||
} else {
|
} else {
|
||||||
sb.append(insn.getMethod().getClassName());
|
sb.append(method.getClassName());
|
||||||
}
|
}
|
||||||
sb.append(".").append(insn.getMethod().getName()).append("(");
|
sb.append(".").append(method.getName()).append("(");
|
||||||
List<Variable> arguments = insn.getArguments();
|
|
||||||
for (int i = 0; i < arguments.size(); ++i) {
|
for (int i = 0; i < arguments.size(); ++i) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
sb.append(", ");
|
sb.append(", ");
|
||||||
|
@ -302,53 +328,13 @@ public class InstructionStringifier implements InstructionVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(IsInstanceInstruction insn) {
|
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := @")
|
sb.append("@").append(receiver.getIndex()).append(" := @").append(value.getIndex())
|
||||||
.append(insn.getValue().getIndex()).append(" instanceof ").append(insn.getType());
|
.append(" instanceof ").append(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(CastInstruction insn) {
|
public void initClass(String className) {
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := cast @")
|
sb.append("initclass ").append(className);
|
||||||
.append(insn.getValue().getIndex()).append(" to ")
|
|
||||||
.append(insn.getTargetType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CastNumberInstruction insn) {
|
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := cast @")
|
|
||||||
.append(insn.getValue().getIndex())
|
|
||||||
.append(" from ").append(insn.getSourceType())
|
|
||||||
.append(" to ").append(insn.getTargetType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CastIntegerInstruction insn) {
|
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := cast @")
|
|
||||||
.append(insn.getValue().getIndex())
|
|
||||||
.append(" from INT to ").append(insn.getTargetType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(UnwrapArrayInstruction insn) {
|
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := @")
|
|
||||||
.append(insn.getArray().getIndex()).append(".data");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ArrayLengthInstruction insn) {
|
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append(" := @")
|
|
||||||
.append(insn.getArray().getIndex()).append(".length");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CloneArrayInstruction insn) {
|
|
||||||
sb.append("@").append(insn.getReceiver().getIndex()).append("@")
|
|
||||||
.append(insn.getArray().getIndex()).append(".clone()");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(InitClassInstruction insn) {
|
|
||||||
sb.append("initclass ").append(insn.getClassName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,29 +23,29 @@ import org.teavm.model.*;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class ListingBuilder {
|
public class ListingBuilder {
|
||||||
public String buildListing(Program program, String prefix) {
|
public String buildListing(ProgramReader program, String prefix) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
InstructionStringifier stringifier = new InstructionStringifier(sb);
|
InstructionStringifier stringifier = new InstructionStringifier(sb);
|
||||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
BasicBlock block = program.basicBlockAt(i);
|
BasicBlockReader block = program.basicBlockAt(i);
|
||||||
sb.append(prefix).append("$").append(i).append(":\n");
|
sb.append(prefix).append("$").append(i).append(":\n");
|
||||||
for (Phi phi : block.getPhis()) {
|
for (PhiReader phi : block.readPhis()) {
|
||||||
sb.append(prefix).append(" ");
|
sb.append(prefix).append(" ");
|
||||||
sb.append("@").append(phi.getReceiver().getIndex()).append(" := ");
|
sb.append("@").append(phi.getReceiver().getIndex()).append(" := ");
|
||||||
List<Incoming> incomings = phi.getIncomings();
|
List<? extends IncomingReader> incomings = phi.readIncomings();
|
||||||
for (int j = 0; j < incomings.size(); ++j) {
|
for (int j = 0; j < incomings.size(); ++j) {
|
||||||
if (j > 0) {
|
if (j > 0) {
|
||||||
sb.append(", ");
|
sb.append(", ");
|
||||||
}
|
}
|
||||||
Incoming incoming = incomings.get(j);
|
IncomingReader incoming = incomings.get(j);
|
||||||
sb.append("@").append(incoming.getValue().getIndex()).append(" from ")
|
sb.append("@").append(incoming.getValue().getIndex()).append(" from ")
|
||||||
.append("$").append(incoming.getSource().getIndex());
|
.append("$").append(incoming.getSource().getIndex());
|
||||||
}
|
}
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
}
|
}
|
||||||
for (Instruction insn : block.getInstructions()) {
|
for (int j = 0; j < block.instructionCount(); ++j) {
|
||||||
sb.append(prefix).append(" ");
|
sb.append(prefix).append(" ");
|
||||||
insn.acceptVisitor(stringifier);
|
block.readInstruction(j, stringifier);
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,11 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(DependencyChecker dependencyChecker, MethodGraph graph) {
|
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency graph) {
|
||||||
ClassHolder cls = dependencyChecker.getClassSource().get(graph.getReference().getClassName());
|
if (graph.isMissing()) {
|
||||||
MethodHolder method = cls.getMethod(graph.getReference().getDescriptor());
|
return;
|
||||||
AnnotationReader annot = method.getAnnotations().get(JavaScriptBody.class.getName());
|
}
|
||||||
|
AnnotationReader annot = graph.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");
|
||||||
|
@ -75,12 +76,12 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void includeDefaultDependencies(DependencyChecker dependencyChecker) {
|
private void includeDefaultDependencies(DependencyChecker dependencyChecker) {
|
||||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT);
|
||||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT);
|
||||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT);
|
||||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT);
|
||||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT);
|
||||||
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT);
|
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -114,9 +115,9 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
||||||
private class GeneratorJsCallback extends JsCallback {
|
private class GeneratorJsCallback extends JsCallback {
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
private DependencyChecker dependencyChecker;
|
private DependencyChecker dependencyChecker;
|
||||||
private MethodGraph caller;
|
private MethodDependency caller;
|
||||||
public GeneratorJsCallback(ClassReaderSource classSource, DependencyChecker dependencyChecker,
|
public GeneratorJsCallback(ClassReaderSource classSource, DependencyChecker dependencyChecker,
|
||||||
MethodGraph caller) {
|
MethodDependency caller) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.dependencyChecker = dependencyChecker;
|
this.dependencyChecker = dependencyChecker;
|
||||||
this.caller = caller;
|
this.caller = caller;
|
||||||
|
@ -126,13 +127,13 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
||||||
MethodReader reader = findMethod(classSource, fqn, desc);
|
MethodReader reader = findMethod(classSource, fqn, desc);
|
||||||
if (reader != null) {
|
if (reader != null) {
|
||||||
if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) {
|
if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) {
|
||||||
MethodGraph graph = dependencyChecker.attachMethodGraph(reader.getReference(), caller.getStack());
|
MethodDependency graph = dependencyChecker.linkMethod(reader.getReference(), caller.getStack());
|
||||||
for (int i = 0; i <= graph.getParameterCount(); ++i) {
|
for (int i = 0; i <= graph.getParameterCount(); ++i) {
|
||||||
allClassesNode.connect(graph.getVariable(i));
|
allClassesNode.connect(graph.getVariable(i));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
allClassesNode.addConsumer(new VirtualCallbackConsumer(classSource, dependencyChecker, desc,
|
allClassesNode.addConsumer(new VirtualCallbackConsumer(dependencyChecker,
|
||||||
caller));
|
reader.getReference(), caller));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
@ -140,25 +141,22 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class VirtualCallbackConsumer implements DependencyConsumer {
|
private class VirtualCallbackConsumer implements DependencyConsumer {
|
||||||
private ClassReaderSource classSource;
|
private String superClass;
|
||||||
private DependencyChecker dependencyChecker;
|
private DependencyChecker dependencyChecker;
|
||||||
private MethodDescriptor desc;
|
private MethodReference superMethod;
|
||||||
private MethodGraph caller;
|
private MethodDependency caller;
|
||||||
public VirtualCallbackConsumer(ClassReaderSource classSource, DependencyChecker dependencyChecker,
|
public VirtualCallbackConsumer(DependencyChecker dependencyChecker, MethodReference superMethod,
|
||||||
MethodDescriptor desc, MethodGraph caller) {
|
MethodDependency caller) {
|
||||||
this.classSource = classSource;
|
|
||||||
this.dependencyChecker = dependencyChecker;
|
this.dependencyChecker = dependencyChecker;
|
||||||
this.desc = desc;
|
this.superMethod = superMethod;
|
||||||
this.caller = caller;
|
this.caller = caller;
|
||||||
}
|
}
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(String type) {
|
||||||
MethodReader reader = findMethod(classSource, type, desc);
|
MethodReference method = new MethodReference(type, superMethod.getDescriptor());
|
||||||
if (reader != null) {
|
MethodDependency graph = dependencyChecker.linkMethod(method, caller.getStack());
|
||||||
MethodGraph graph = dependencyChecker.attachMethodGraph(reader.getReference(), caller.getStack());
|
|
||||||
for (int i = 0; i < graph.getParameterCount(); ++i) {
|
for (int i = 0; i < graph.getParameterCount(); ++i) {
|
||||||
allClassesNode.connect(graph.getVariable(i));
|
allClassesNode.connect(graph.getVariable(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -317,15 +317,15 @@ public class JavaScriptBodyTests {
|
||||||
|
|
||||||
private static class R implements Runnable {
|
private static class R implements Runnable {
|
||||||
int cnt;
|
int cnt;
|
||||||
//private final Thread initThread;
|
private final Thread initThread;
|
||||||
|
|
||||||
public R() {
|
public R() {
|
||||||
//initThread = Thread.currentThread();
|
initThread = Thread.currentThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
//assert initThread == Thread.currentThread() : "Expecting to run in " + initThread + " but running in " + Thread.currentThread();
|
assert initThread == Thread.currentThread() : "Expecting to run in " + initThread + " but running in " + Thread.currentThread();
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,14 +20,11 @@ import org.teavm.codegen.SourceWriter;
|
||||||
import org.teavm.dependency.DependencyChecker;
|
import org.teavm.dependency.DependencyChecker;
|
||||||
import org.teavm.dependency.DependencyConsumer;
|
import org.teavm.dependency.DependencyConsumer;
|
||||||
import org.teavm.dependency.DependencyPlugin;
|
import org.teavm.dependency.DependencyPlugin;
|
||||||
import org.teavm.dependency.MethodGraph;
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.javascript.ast.ConstantExpr;
|
import org.teavm.javascript.ast.ConstantExpr;
|
||||||
import org.teavm.javascript.ast.Expr;
|
import org.teavm.javascript.ast.Expr;
|
||||||
import org.teavm.javascript.ast.InvocationExpr;
|
import org.teavm.javascript.ast.InvocationExpr;
|
||||||
import org.teavm.model.ClassHolder;
|
import org.teavm.model.*;
|
||||||
import org.teavm.model.FieldReference;
|
|
||||||
import org.teavm.model.MethodHolder;
|
|
||||||
import org.teavm.model.MethodReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -97,7 +94,7 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodAchieved(final DependencyChecker checker, final MethodGraph graph) {
|
public void methodAchieved(final DependencyChecker checker, final MethodDependency graph) {
|
||||||
for (int i = 0; i < graph.getReference().parameterCount(); ++i) {
|
for (int i = 0; i < graph.getReference().parameterCount(); ++i) {
|
||||||
graph.getVariable(i).addConsumer(new DependencyConsumer() {
|
graph.getVariable(i).addConsumer(new DependencyConsumer() {
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(String type) {
|
||||||
|
@ -107,11 +104,14 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveFunctorMethods(DependencyChecker checker, String type, MethodGraph caller) {
|
private void achieveFunctorMethods(DependencyChecker checker, String type, MethodDependency caller) {
|
||||||
ClassHolder cls = checker.getClassSource().get(type);
|
if (caller.isMissing()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ClassReader cls = checker.getClassSource().get(type);
|
||||||
if (cls != null) {
|
if (cls != null) {
|
||||||
for (MethodHolder method : cls.getMethods()) {
|
for (MethodReader method : cls.getMethods()) {
|
||||||
checker.attachMethodGraph(method.getReference(), caller.getStack());
|
checker.linkMethod(method.getReference(), caller.getStack());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user