Dependency API supports multiple occurence of reaching events for

different location
This commit is contained in:
Alexey Andreev 2014-12-29 19:16:29 +04:00
parent cd0664d695
commit 1fff443c36
23 changed files with 182 additions and 117 deletions

View File

@ -31,12 +31,12 @@ public class ClassLookupDependencySupport implements DependencyListener {
}
@Override
public void classAchieved(DependencyAgent agent, String className) {
public void classAchieved(DependencyAgent agent, String className, CallLocation location) {
allClasses.propagate(agent.getType(className));
}
@Override
public void methodAchieved(final DependencyAgent agent, MethodDependency method) {
public void methodAchieved(final DependencyAgent agent, MethodDependency method, final CallLocation location) {
MethodReference ref = method.getReference();
if (ref.getClassName().equals("java.lang.Class") && ref.getName().equals("forNameImpl")) {
allClasses.addConsumer(new DependencyConsumer() {
@ -47,7 +47,7 @@ public class ClassLookupDependencySupport implements DependencyListener {
}
MethodReader initMethod = cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID));
if (initMethod != null) {
agent.linkMethod(initMethod.getReference(), null).use();
agent.linkMethod(initMethod.getReference(), location).use();
}
}
});
@ -55,6 +55,6 @@ public class ClassLookupDependencySupport implements DependencyListener {
}
@Override
public void fieldAchieved(DependencyAgent dependencyChecker, FieldDependency field) {
public void fieldAchieved(DependencyAgent dependencyChecker, FieldDependency field, CallLocation location) {
}
}

View File

@ -16,6 +16,7 @@
package org.teavm.classlib.impl;
import org.teavm.dependency.*;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReader;
@ -35,7 +36,7 @@ public class EnumDependencySupport implements DependencyListener {
}
@Override
public void classAchieved(DependencyAgent agent, String className) {
public void classAchieved(DependencyAgent agent, String className, CallLocation location) {
ClassReader cls = agent.getClassSource().get(className);
if (cls == null || cls.getParent() == null || !cls.getParent().equals("java.lang.Enum")) {
return;
@ -45,25 +46,25 @@ public class EnumDependencySupport implements DependencyListener {
MethodReader method = cls.getMethod(new MethodDescriptor("values",
ValueType.arrayOf(ValueType.object(cls.getName()))));
if (method != null) {
agent.linkMethod(method.getReference(), null).use();
agent.linkMethod(method.getReference(), location).use();
}
}
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
if (method.getReference().getClassName().equals("java.lang.Class") &&
method.getReference().getName().equals("getEnumConstantsImpl")) {
unlocked = true;
allEnums.connect(method.getResult().getArrayItem());
method.getResult().propagate(agent.getType("[java.lang.Enum"));
for (String cls : agent.getAchievableClasses()) {
classAchieved(agent, cls);
classAchieved(agent, cls, location);
}
}
}
@Override
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
public void fieldAchieved(DependencyAgent agent, FieldDependency field, CallLocation location) {
}
}

View File

@ -31,7 +31,7 @@ public class NewInstanceDependencySupport implements DependencyListener {
}
@Override
public void classAchieved(DependencyAgent agent, String className) {
public void classAchieved(DependencyAgent agent, String className, CallLocation location) {
ClassReader cls = agent.getClassSource().get(className);
if (cls == null) {
return;
@ -46,24 +46,24 @@ public class NewInstanceDependencySupport implements DependencyListener {
}
@Override
public void methodAchieved(final DependencyAgent agent, MethodDependency method) {
public void methodAchieved(final DependencyAgent agent, MethodDependency method, final CallLocation location) {
MethodReader reader = method.getMethod();
if (reader.getOwnerName().equals("java.lang.Class") && reader.getName().equals("newInstance")) {
allClassesNode.connect(method.getResult());
method.getResult().addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
attachConstructor(agent, type.getName());
attachConstructor(agent, type.getName(), location);
}
});
}
}
private void attachConstructor(DependencyAgent checker, String type) {
private void attachConstructor(DependencyAgent checker, String type, CallLocation location) {
MethodReference ref = new MethodReference(type, new MethodDescriptor("<init>", ValueType.VOID));
checker.linkMethod(ref, null).use();
checker.linkMethod(ref, location).use();
}
@Override
public void fieldAchieved(DependencyAgent dependencyAgent, FieldDependency field) {
public void fieldAchieved(DependencyAgent dependencyAgent, FieldDependency field, CallLocation location) {
}
}

View File

@ -25,6 +25,7 @@ import org.teavm.codegen.SourceWriter;
import org.teavm.dependency.*;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
@ -34,6 +35,7 @@ import org.teavm.model.ValueType;
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ServiceLoaderSupport implements Generator, DependencyListener {
private Set<String> achievedClasses;
private Map<String, List<String>> serviceMap = new HashMap<>();
private DependencyNode allClassesNode;
private ClassLoader classLoader;
@ -82,7 +84,10 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
}
@Override
public void classAchieved(DependencyAgent agent, String className) {
public void classAchieved(DependencyAgent agent, String className, CallLocation location) {
if (!achievedClasses.add(className)) {
return;
}
try {
Enumeration<URL> resources = classLoader.getResources("META-INF/services/" + className);
while (resources.hasMoreElements()) {
@ -118,25 +123,25 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
}
@Override
public void methodAchieved(final DependencyAgent agent, MethodDependency method) {
public void methodAchieved(final DependencyAgent agent, MethodDependency method, final CallLocation location) {
MethodReference ref = method.getReference();
if (ref.getClassName().equals("java.util.ServiceLoader") && ref.getName().equals("loadServices")) {
method.getResult().propagate(agent.getType("[java.lang.Object"));
allClassesNode.connect(method.getResult().getArrayItem());
method.getResult().getArrayItem().addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
initConstructor(agent, type.getName());
initConstructor(agent, type.getName(), location);
}
});
}
}
private void initConstructor(DependencyAgent agent, String type) {
private void initConstructor(DependencyAgent agent, String type, CallLocation location) {
MethodReference ctor = new MethodReference(type, new MethodDescriptor("<init>", ValueType.VOID));
agent.linkMethod(ctor, null).use();
agent.linkMethod(ctor, location).use();
}
@Override
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
public void fieldAchieved(DependencyAgent agent, FieldDependency field, CallLocation location) {
}
}

View File

@ -24,6 +24,7 @@ import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
/**
@ -52,7 +53,7 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
switch (method.getReference().getName()) {
case "obtainDigitMapping":
case "obtainClasses":

View File

@ -186,7 +186,7 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency graph) {
public void methodAchieved(DependencyAgent agent, MethodDependency graph, CallLocation location) {
switch (graph.getReference().getName()) {
case "voidClass":
case "booleanClass":
@ -205,8 +205,8 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
graph.getResult().propagate(agent.getType("java.lang.Class"));
break;
case "newInstance":
agent.linkMethod(new MethodReference(InstantiationException.class.getName(), "<init>",
ValueType.VOID), null).use();
agent.linkMethod(new MethodReference(InstantiationException.class, "<init>", void.class),
location).use();
break;
}
}

View File

@ -22,6 +22,7 @@ import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.ni.Injector;
import org.teavm.javascript.ni.InjectorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
/**
@ -58,7 +59,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
switch (method.getReference().getName()) {
case "clone":
method.getVariable(0).connect(method.getResult());

View File

@ -21,6 +21,7 @@ import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.ni.Injector;
import org.teavm.javascript.ni.InjectorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
/**
@ -29,7 +30,7 @@ import org.teavm.model.MethodReference;
*/
public class StringNativeGenerator implements Injector, DependencyPlugin {
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
switch (method.getReference().getName()) {
case "wrap":
method.getVariable(1).connect(method.getResult());

View File

@ -20,6 +20,7 @@ import org.teavm.codegen.SourceWriter;
import org.teavm.dependency.*;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference;
@ -54,7 +55,7 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
switch (method.getReference().getName()) {
case "doArrayCopy":
achieveArrayCopy(method);

View File

@ -20,6 +20,7 @@ import org.teavm.codegen.SourceWriter;
import org.teavm.dependency.*;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
@ -38,7 +39,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
ValueType.INTEGER, ValueType.LONG, ValueType.FLOAT, ValueType.DOUBLE, ValueType.BOOLEAN };
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
switch (method.getReference().getName()) {
case "getLength":
achieveGetLength(agent, method);

View File

@ -22,6 +22,7 @@ import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
/**
@ -70,7 +71,7 @@ public class DateNativeGenerator implements Generator, DependencyPlugin {
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
switch (method.getMethod().getName()) {
case "toString":
case "toLocaleFormat":

View File

@ -23,6 +23,7 @@ import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
/**
@ -34,7 +35,7 @@ public class TimerNativeGenerator implements Generator, DependencyPlugin {
"performOnce", void.class);
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
switch (method.getReference().getName()) {
case "scheduleOnce": {
MethodDependency performMethod = agent.linkMethod(performOnceRef, null);

View File

@ -69,16 +69,19 @@ public class DefaultCallGraphNode implements CallGraphNode {
return safeCallersCallSites;
}
public void addCallSite(MethodReference method, InstructionLocation location) {
public boolean addCallSite(MethodReference method, InstructionLocation location) {
DefaultCallGraphNode callee = graph.getNode(method);
DefaultCallSite callSite = new DefaultCallSite(location, callee, this);
if (callSites.add(callSite)) {
callee.callerCallSites.add(callSite);
return true;
} else {
return false;
}
}
public void addCallSite(MethodReference method) {
addCallSite(method, null);
public boolean addCallSite(MethodReference method) {
return addCallSite(method, null);
}
@Override

View File

@ -16,6 +16,7 @@
package org.teavm.callgraph;
import java.util.Objects;
import org.teavm.model.CallLocation;
import org.teavm.model.InstructionLocation;
/**
@ -26,11 +27,15 @@ public class DefaultCallSite implements CallSite {
private InstructionLocation location;
private DefaultCallGraphNode callee;
private DefaultCallGraphNode caller;
private CallLocation exactLocation;
DefaultCallSite(InstructionLocation location, DefaultCallGraphNode callee, DefaultCallGraphNode caller) {
this.location = location;
this.callee = callee;
this.caller = caller;
if (caller != null) {
exactLocation = new CallLocation(caller.getMethod(), location);
}
}
@Override
@ -38,6 +43,10 @@ public class DefaultCallSite implements CallSite {
return location;
}
public CallLocation getExactLocation() {
return exactLocation;
}
@Override
public DefaultCallGraphNode getCallee() {
return callee;

View File

@ -26,7 +26,6 @@ import org.teavm.callgraph.CallGraph;
import org.teavm.callgraph.DefaultCallGraph;
import org.teavm.callgraph.DefaultCallGraphNode;
import org.teavm.common.CachedMapper;
import org.teavm.common.CachedMapper.KeyListener;
import org.teavm.common.Mapper;
import org.teavm.common.ServiceRepository;
import org.teavm.diagnostics.Diagnostics;
@ -109,37 +108,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return createClassDependency(preimage);
}
});
methodCache.addKeyListener(new KeyListener<MethodReference>() {
@Override public void keyAdded(MethodReference key) {
MethodDependency graph = methodCache.getKnown(key);
if (!graph.isMissing()) {
for (DependencyListener listener : listeners) {
listener.methodAchieved(DependencyChecker.this, graph);
}
activateDependencyPlugin(graph);
}
}
});
fieldCache.addKeyListener(new KeyListener<FieldReference>() {
@Override public void keyAdded(FieldReference key) {
FieldDependency fieldDep = fieldCache.getKnown(key);
if (!fieldDep.isMissing()) {
for (DependencyListener listener : listeners) {
listener.fieldAchieved(DependencyChecker.this, fieldDep);
}
}
}
});
classCache.addKeyListener(new KeyListener<String>() {
@Override public void keyAdded(String key) {
ClassDependency classDep = classCache.getKnown(key);
if (!classDep.isMissing()) {
for (DependencyListener listener : listeners) {
listener.classAchieved(DependencyChecker.this, key);
}
}
}
});
}
public DependencyCheckerInterruptor getInterruptor() {
@ -234,26 +202,33 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
@Override
public ClassDependency linkClass(String className, CallLocation callLocation) {
ClassDependency dep = classCache.map(className);
boolean added = true;
if (callLocation != null && callLocation.getMethod() != null) {
DefaultCallGraphNode callGraphNode = callGraph.getNode(callLocation.getMethod());
addClassAccess(callGraphNode, className, callLocation.getSourceLocation());
added = addClassAccess(callGraphNode, className, callLocation.getSourceLocation());
}
if (!dep.isMissing() && added) {
for (DependencyListener listener : listeners) {
listener.classAchieved(DependencyChecker.this, className, callLocation);
}
}
return dep;
}
private void addClassAccess(DefaultCallGraphNode node, String className, InstructionLocation loc) {
private boolean addClassAccess(DefaultCallGraphNode node, String className, InstructionLocation loc) {
if (!node.addClassAccess(className, loc)) {
return;
return false;
}
ClassReader cls = classSource.get(className);
if (cls != null) {
if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) {
addClassAccess(node, cls.getParent(), loc);
return addClassAccess(node, cls.getParent(), loc);
}
for (String iface : cls.getInterfaces()) {
addClassAccess(node, iface, loc);
return addClassAccess(node, iface, loc);
}
}
return false;
}
private ClassDependency createClassDependency(String className) {
@ -276,10 +251,19 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
throw new IllegalArgumentException();
}
callGraph.getNode(methodRef);
boolean added = true;
if (callLocation != null && callLocation.getMethod() != null) {
callGraph.getNode(callLocation.getMethod()).addCallSite(methodRef, callLocation.getSourceLocation());
added = callGraph.getNode(callLocation.getMethod()).addCallSite(methodRef,
callLocation.getSourceLocation());
}
return methodCache.map(methodRef);
MethodDependency graph = methodCache.map(methodRef);
if (!graph.isMissing() && added) {
for (DependencyListener listener : listeners) {
listener.methodAchieved(this, graph, callLocation);
}
activateDependencyPlugin(graph, callLocation);
}
return graph;
}
void initClass(ClassDependency cls, final CallLocation callLocation) {
@ -404,8 +388,9 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
@Override
public FieldDependency linkField(final FieldReference fieldRef, final CallLocation location) {
boolean added = true;
if (location != null) {
callGraph.getNode(location.getMethod()).addFieldAccess(fieldRef, location.getSourceLocation());
added = callGraph.getNode(location.getMethod()).addFieldAccess(fieldRef, location.getSourceLocation());
}
FieldDependency dep = fieldCache.map(fieldRef);
if (!dep.isMissing()) {
@ -415,6 +400,11 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
}
});
}
if (!dep.isMissing() && added) {
for (DependencyListener listener : listeners) {
listener.fieldAchieved(DependencyChecker.this, dep, location);
}
}
return dep;
}
@ -444,7 +434,18 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return dep;
}
private void activateDependencyPlugin(MethodDependency methodDep) {
private void activateDependencyPlugin(MethodDependency methodDep, CallLocation location) {
attachDependencyPlugin(methodDep);
if (methodDep.dependencyPlugin != null) {
methodDep.dependencyPlugin.methodAchieved(this, methodDep, location);
}
}
private void attachDependencyPlugin(MethodDependency methodDep) {
if (methodDep.dependencyPluginAttached) {
return;
}
methodDep.dependencyPluginAttached = true;
AnnotationReader depAnnot = methodDep.getMethod().getAnnotations().get(PluggableDependency.class.getName());
if (depAnnot == null) {
return;
@ -457,13 +458,11 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
} catch (ClassNotFoundException e) {
throw new RuntimeException("Dependency plugin not found: " + depClassName, e);
}
DependencyPlugin plugin;
try {
plugin = (DependencyPlugin)depClass.newInstance();
methodDep.dependencyPlugin = (DependencyPlugin)depClass.newInstance();
} catch (IllegalAccessException | InstantiationException e) {
throw new RuntimeException("Can't instantiate dependency plugin " + depClassName, e);
}
plugin.methodAchieved(this, methodDep);
}
@Override

View File

@ -15,6 +15,8 @@
*/
package org.teavm.dependency;
import org.teavm.model.CallLocation;
/**
*
* @author Alexey Andreev
@ -22,9 +24,9 @@ package org.teavm.dependency;
public interface DependencyListener {
void started(DependencyAgent agent);
void classAchieved(DependencyAgent agent, String className);
void classAchieved(DependencyAgent agent, String className, CallLocation location);
void methodAchieved(DependencyAgent agent, MethodDependency method);
void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location);
void fieldAchieved(DependencyAgent agent, FieldDependency field);
void fieldAchieved(DependencyAgent agent, FieldDependency field, CallLocation location);
}

View File

@ -15,10 +15,12 @@
*/
package org.teavm.dependency;
import org.teavm.model.CallLocation;
/**
*
* @author Alexey Andreev
*/
public interface DependencyPlugin {
void methodAchieved(DependencyAgent checker, MethodDependency method);
void methodAchieved(DependencyAgent checker, MethodDependency method, CallLocation location);
}

View File

@ -32,6 +32,8 @@ public class MethodDependency implements MethodDependencyInfo {
private MethodReader method;
private MethodReference reference;
private boolean used;
DependencyPlugin dependencyPlugin;
boolean dependencyPluginAttached;
MethodDependency(DependencyChecker dependencyChecker, DependencyNode[] variableNodes, int parameterCount,
DependencyNode resultNode, DependencyNode thrown, MethodReader method, MethodReference reference) {

View File

@ -16,6 +16,7 @@
package org.teavm.tooling;
import org.teavm.dependency.*;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReference;
@ -35,7 +36,7 @@ class TestExceptionDependency implements DependencyListener {
}
@Override
public void classAchieved(DependencyAgent agent, String className) {
public void classAchieved(DependencyAgent agent, String className, CallLocation location) {
if (isException(agent.getClassSource(), className)) {
allClasses.propagate(agent.getType(className));
}
@ -56,13 +57,13 @@ class TestExceptionDependency implements DependencyListener {
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
if (method.getReference().equals(getMessageRef)) {
allClasses.connect(method.getVariable(1));
}
}
@Override
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
public void fieldAchieved(DependencyAgent agent, FieldDependency field, CallLocation location) {
}
}

View File

@ -22,6 +22,7 @@ import org.teavm.codegen.SourceWriter;
import org.teavm.dependency.*;
import org.teavm.javascript.Renderer;
import org.teavm.javascript.RenderingContext;
import org.teavm.model.CallLocation;
import org.teavm.vm.BuildTarget;
import org.teavm.vm.spi.AbstractRendererListener;
@ -74,14 +75,14 @@ public class EntryPointGenerator extends AbstractRendererListener implements Dep
}
@Override
public void classAchieved(DependencyAgent agent, String className) {
public void classAchieved(DependencyAgent agent, String className, CallLocation location) {
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
}
@Override
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
public void fieldAchieved(DependencyAgent agent, FieldDependency field, CallLocation location) {
}
}

View File

@ -15,9 +15,27 @@
*/
package org.teavm.html4j;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.java.html.js.JavaScriptBody;
import org.teavm.dependency.*;
import org.teavm.model.*;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyAgentType;
import org.teavm.dependency.DependencyConsumer;
import org.teavm.dependency.DependencyListener;
import org.teavm.dependency.DependencyNode;
import org.teavm.dependency.FieldDependency;
import org.teavm.dependency.MethodDependency;
import org.teavm.model.AnnotationReader;
import org.teavm.model.AnnotationValue;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
/**
*
@ -25,6 +43,7 @@ import org.teavm.model.*;
*/
public class JavaScriptBodyDependency implements DependencyListener {
private DependencyNode allClassesNode;
private Map<MethodReference, Set<MethodReference>> achievedMethods = new HashMap<>();
@Override
public void started(DependencyAgent agent) {
@ -43,7 +62,7 @@ public class JavaScriptBodyDependency implements DependencyListener {
}
@Override
public void classAchieved(DependencyAgent agent, String className) {
public void classAchieved(DependencyAgent agent, String className, CallLocation location) {
ClassReader cls = agent.getClassSource().get(className);
if (cls != null && !cls.hasModifier(ElementModifier.ABSTRACT) &&
!cls.hasModifier(ElementModifier.INTERFACE)) {
@ -52,13 +71,21 @@ public class JavaScriptBodyDependency implements DependencyListener {
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
Set<MethodReference> methodsToAchieve = achievedMethods.get(method.getReference());
if (methodsToAchieve != null) {
for (MethodReference methodToAchieve : methodsToAchieve) {
agent.linkMethod(methodToAchieve, location);
}
return;
}
achievedMethods.put(method.getReference(), new HashSet<MethodReference>());
if (method.isMissing()) {
return;
}
AnnotationReader annot = method.getMethod().getAnnotations().get(JavaScriptBody.class.getName());
if (annot != null) {
includeDefaultDependencies(agent);
includeDefaultDependencies(agent, location);
AnnotationValue javacall = annot.getValue("javacall");
if (method.getResult() != null) {
allClassesNode.connect(method.getResult());
@ -74,26 +101,26 @@ public class JavaScriptBodyDependency implements DependencyListener {
}
if (javacall != null && javacall.getBoolean()) {
String body = annot.getValue("body").getString();
new GeneratorJsCallback(agent, method).parse(body);
new GeneratorJsCallback(agent, method, location).parse(body);
}
}
}
private void includeDefaultDependencies(DependencyAgent agent) {
agent.linkMethod(JavaScriptConvGenerator.fromJsMethod, null).use();
agent.linkMethod(JavaScriptConvGenerator.toJsMethod, null).use();
agent.linkMethod(JavaScriptConvGenerator.intValueMethod, null).use();
agent.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, null).use();
agent.linkMethod(JavaScriptConvGenerator.booleanValueMethod, null).use();
agent.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, null).use();
agent.linkMethod(JavaScriptConvGenerator.doubleValueMethod, null).use();
agent.linkMethod(JavaScriptConvGenerator.valueOfDoubleMethod, null).use();
agent.linkMethod(JavaScriptConvGenerator.charValueMethod, null).use();
agent.linkMethod(JavaScriptConvGenerator.valueOfCharMethod, null).use();
private void includeDefaultDependencies(DependencyAgent agent, CallLocation location) {
agent.linkMethod(JavaScriptConvGenerator.fromJsMethod, location).use();
agent.linkMethod(JavaScriptConvGenerator.toJsMethod, location).use();
agent.linkMethod(JavaScriptConvGenerator.intValueMethod, location).use();
agent.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, location).use();
agent.linkMethod(JavaScriptConvGenerator.booleanValueMethod, location).use();
agent.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, location).use();
agent.linkMethod(JavaScriptConvGenerator.doubleValueMethod, location).use();
agent.linkMethod(JavaScriptConvGenerator.valueOfDoubleMethod, location).use();
agent.linkMethod(JavaScriptConvGenerator.charValueMethod, location).use();
agent.linkMethod(JavaScriptConvGenerator.valueOfCharMethod, location).use();
}
@Override
public void fieldAchieved(DependencyAgent agent, FieldDependency fieldDep) {
public void fieldAchieved(DependencyAgent agent, FieldDependency fieldDep, CallLocation location) {
}
private static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) {
@ -126,15 +153,18 @@ public class JavaScriptBodyDependency implements DependencyListener {
private class GeneratorJsCallback extends JsCallback {
private DependencyAgent agent;
private MethodDependency caller;
public GeneratorJsCallback(DependencyAgent agent, MethodDependency caller) {
private CallLocation location;
public GeneratorJsCallback(DependencyAgent agent, MethodDependency caller, CallLocation location) {
this.agent = agent;
this.caller = caller;
this.location = location;
}
@Override protected CharSequence callMethod(String ident, String fqn, String method, String params) {
MethodDescriptor desc = MethodDescriptor.parse(method + params + "V");
MethodReader reader = findMethod(agent.getClassSource(), fqn, desc);
MethodReference ref = reader != null ? reader.getReference() : new MethodReference(fqn, desc);
MethodDependency methodDep = agent.linkMethod(ref, null);
MethodDependency methodDep = agent.linkMethod(ref, location);
achievedMethods.get(caller.getReference()).add(ref);
if (!methodDep.isMissing()) {
if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) {
methodDep.use();
@ -154,8 +184,7 @@ public class JavaScriptBodyDependency implements DependencyListener {
private MethodReader superMethod;
private ClassReader superClass;
private MethodDependency caller;
public VirtualCallbackConsumer(DependencyAgent agent, MethodReader superMethod,
MethodDependency caller) {
public VirtualCallbackConsumer(DependencyAgent agent, MethodReader superMethod, MethodDependency caller) {
this.agent = agent;
this.superMethod = superMethod;
this.caller = caller;

View File

@ -23,6 +23,7 @@ import org.teavm.javascript.ast.Expr;
import org.teavm.javascript.ast.InvocationExpr;
import org.teavm.javascript.ni.Injector;
import org.teavm.javascript.ni.InjectorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
@ -112,7 +113,8 @@ public class JSNativeGenerator implements Injector, DependencyPlugin {
}
@Override
public void methodAchieved(final DependencyAgent agent, final MethodDependency method) {
public void methodAchieved(final DependencyAgent agent, final MethodDependency method,
final CallLocation location) {
switch (method.getReference().getName()) {
case "invoke":
case "instantiate":
@ -120,7 +122,7 @@ public class JSNativeGenerator implements Injector, DependencyPlugin {
for (int i = 0; i < method.getReference().parameterCount(); ++i) {
method.getVariable(i).addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
achieveFunctorMethods(agent, type.getName(), method);
achieveFunctorMethods(agent, type.getName(), method, location);
}
});
}
@ -131,14 +133,15 @@ public class JSNativeGenerator implements Injector, DependencyPlugin {
}
}
private void achieveFunctorMethods(DependencyAgent agent, String type, MethodDependency caller) {
private void achieveFunctorMethods(DependencyAgent agent, String type, MethodDependency caller,
CallLocation location) {
if (caller.isMissing()) {
return;
}
ClassReader cls = agent.getClassSource().get(type);
if (cls != null) {
for (MethodReader method : cls.getMethods()) {
agent.linkMethod(method.getReference(), null).use();
agent.linkMethod(method.getReference(), location).use();
}
}
}

View File

@ -19,6 +19,7 @@ import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyListener;
import org.teavm.dependency.FieldDependency;
import org.teavm.dependency.MethodDependency;
import org.teavm.model.CallLocation;
/**
*
@ -30,11 +31,11 @@ class ResourceAccessorDependencyListener implements DependencyListener {
}
@Override
public void classAchieved(DependencyAgent agent, String className) {
public void classAchieved(DependencyAgent agent, String className, CallLocation location) {
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
switch (method.getReference().getName()) {
case "castToString":
method.getResult().propagate(agent.getType("java.lang.String"));
@ -43,6 +44,6 @@ class ResourceAccessorDependencyListener implements DependencyListener {
}
@Override
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
public void fieldAchieved(DependencyAgent agent, FieldDependency field, CallLocation location) {
}
}