diff --git a/core/src/main/java/org/teavm/callgraph/CallGraphNode.java b/core/src/main/java/org/teavm/callgraph/CallGraphNode.java
index eba99593a..15a92f48a 100644
--- a/core/src/main/java/org/teavm/callgraph/CallGraphNode.java
+++ b/core/src/main/java/org/teavm/callgraph/CallGraphNode.java
@@ -18,37 +18,13 @@ package org.teavm.callgraph;
import java.util.Collection;
import org.teavm.model.MethodReference;
-/**
- * Represents a method with information about what methods does it call and what method do call the method.
- * @author Alexey Andreev
- */
public interface CallGraphNode {
- /**
- * Returns reference to entire call graph.
- *
- * @return graph
- */
CallGraph getGraph();
- /**
- * Returns the method that this node represents.
- *
- * @return method
- */
MethodReference getMethod();
- /**
- * Returns immutable collection of all call sites that are in the method.
- *
- * @return call site
- */
Collection extends CallSite> getCallSites();
- /**
- * Returns immutable collection of all call sites that call this method.
- *
- * @return call sites
- */
Collection extends CallSite> getCallerCallSites();
Collection extends FieldAccessSite> getFieldAccessSites();
diff --git a/core/src/main/java/org/teavm/callgraph/CallSite.java b/core/src/main/java/org/teavm/callgraph/CallSite.java
index bcf942681..7f5fafc9f 100644
--- a/core/src/main/java/org/teavm/callgraph/CallSite.java
+++ b/core/src/main/java/org/teavm/callgraph/CallSite.java
@@ -15,31 +15,13 @@
*/
package org.teavm.callgraph;
+import java.util.Collection;
import org.teavm.model.TextLocation;
-/**
- *
Call site that represents exact place in the code that calls a method.
.
- * @author Alexey Andreev
- */
public interface CallSite {
- /**
- * Gets location of the call site
.
- *
- * @return location of the call site or null
if no debug information found for this call site.
- */
- TextLocation getLocation();
+ Collection extends TextLocation> getLocations(CallGraphNode caller);
- /**
- * Gets a method that this call site invokes.
- *
- * @return a node that represent methods being called
- */
- CallGraphNode getCallee();
+ Collection extends CallGraphNode> getCalledMethods();
- /**
- * Gets a method that contains this call site.
- *
- * @return a node that represents methods's caller
- */
- CallGraphNode getCaller();
+ Collection extends CallGraphNode> getCallers();
}
diff --git a/core/src/main/java/org/teavm/callgraph/DefaultCallSite.java b/core/src/main/java/org/teavm/callgraph/DefaultCallSite.java
deleted file mode 100644
index 1e22993c7..000000000
--- a/core/src/main/java/org/teavm/callgraph/DefaultCallSite.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2014 Alexey Andreev.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.teavm.callgraph;
-
-import java.io.Serializable;
-import java.util.Objects;
-import org.teavm.model.TextLocation;
-
-public class DefaultCallSite implements CallSite, Serializable {
- private TextLocation location;
- private DefaultCallGraphNode callee;
- private DefaultCallGraphNode caller;
-
- DefaultCallSite(TextLocation location, DefaultCallGraphNode callee, DefaultCallGraphNode caller) {
- this.location = location;
- this.callee = callee;
- this.caller = caller;
- }
-
- @Override
- public TextLocation getLocation() {
- return location;
- }
-
- @Override
- public DefaultCallGraphNode getCallee() {
- return callee;
- }
-
- @Override
- public DefaultCallGraphNode getCaller() {
- return caller;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
- if (!(obj instanceof DefaultCallSite)) {
- return false;
- }
- DefaultCallSite other = (DefaultCallSite) obj;
- return Objects.equals(callee.getMethod(), other.callee.getMethod())
- && Objects.equals(location, other.location);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(callee.getMethod(), location);
- }
-}
diff --git a/core/src/main/java/org/teavm/debugging/information/DebugInformation.java b/core/src/main/java/org/teavm/debugging/information/DebugInformation.java
index 6e6592169..12a485cc4 100644
--- a/core/src/main/java/org/teavm/debugging/information/DebugInformation.java
+++ b/core/src/main/java/org/teavm/debugging/information/DebugInformation.java
@@ -294,8 +294,8 @@ public class DebugInformation {
private DebuggerCallSite getCallSite(int index) {
RecordArray.Record record = callSiteMapping.get(index);
- int type = record.get(2);
- int method = record.get(3);
+ int type = record.get(0);
+ int method = record.get(1);
switch (type) {
case DebuggerCallSite.NONE:
return null;
diff --git a/core/src/main/java/org/teavm/callgraph/DefaultCallGraph.java b/core/src/main/java/org/teavm/dependency/DefaultCallGraph.java
similarity index 79%
rename from core/src/main/java/org/teavm/callgraph/DefaultCallGraph.java
rename to core/src/main/java/org/teavm/dependency/DefaultCallGraph.java
index f6df3ea07..f0e0d2195 100644
--- a/core/src/main/java/org/teavm/callgraph/DefaultCallGraph.java
+++ b/core/src/main/java/org/teavm/dependency/DefaultCallGraph.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Alexey Andreev.
+ * Copyright 2019 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.teavm.callgraph;
+package org.teavm.dependency;
import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap;
@@ -30,10 +30,12 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import org.teavm.callgraph.CallGraph;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference;
+import org.teavm.model.TextLocation;
-public class DefaultCallGraph implements CallGraph, Serializable {
+class DefaultCallGraph implements CallGraph, Serializable {
public Map nodes = new HashMap<>();
Map> fieldAccessSites = new HashMap<>();
@@ -127,9 +129,19 @@ public class DefaultCallGraph implements CallGraph, Serializable {
for (DefaultCallSite callSite : callSitesToProcess.toArray(new DefaultCallSite[0])) {
int index = callSiteToIndex.get(callSite);
SerializableCallGraph.CallSite scs = callSites.get(index);
- scs.location = callSite.getLocation();
- scs.caller = getNode(callSite.getCaller());
- scs.callee = getNode(callSite.getCallee());
+ scs.virtual = callSite.callers != null;
+ List locations = new ArrayList<>();
+ for (DefaultCallGraphNode caller : callSite.getCallers()) {
+ for (TextLocation textLocation : callSite.getLocations(caller)) {
+ SerializableCallGraph.Location location = new SerializableCallGraph.Location();
+ location.caller = getNode(caller);
+ location.value = textLocation;
+ locations.add(location);
+ }
+ }
+ scs.locations = locations.toArray(new SerializableCallGraph.Location[0]);
+ scs.callers = getNodes(callSite.getCallers());
+ scs.calledMethods = getNodes(callSite.getCalledMethods());
hasAny = true;
}
callSitesToProcess.clear();
@@ -161,6 +173,15 @@ public class DefaultCallGraph implements CallGraph, Serializable {
return index;
}
+ private int[] getNodes(Collection extends DefaultCallGraphNode> nodes) {
+ int[] result = new int[nodes.size()];
+ int index = 0;
+ for (DefaultCallGraphNode node : nodes) {
+ result[index++] = getNode(node);
+ }
+ return result;
+ }
+
private int getCallSite(DefaultCallSite callSite) {
int index = callSiteToIndex.getOrDefault(callSite, -1);
if (index < 0) {
@@ -194,7 +215,17 @@ public class DefaultCallGraph implements CallGraph, Serializable {
nodes.add(new DefaultCallGraphNode(cg, serializableNode.method));
}
for (SerializableCallGraph.CallSite scs : scg.callSites) {
- callSites.add(new DefaultCallSite(scs.location, nodes.get(scs.callee), nodes.get(scs.caller)));
+ DefaultCallSite callSite;
+ if (scs.virtual) {
+ callSite = new DefaultCallSite(scs.method, mapNodes(scs.callers));
+ callSite.calledMethods.addAll(mapNodes(scs.calledMethods));
+ } else {
+ callSite = new DefaultCallSite(nodes.get(scs.calledMethods[0]), nodes.get(scs.callers[0]));
+ }
+ for (SerializableCallGraph.Location location : scs.locations) {
+ callSite.addLocation(nodes.get(location.caller), location.value);
+ }
+ callSites.add(callSite);
}
for (SerializableCallGraph.FieldAccess sfa : scg.fieldAccessList) {
fieldAccessList.add(new DefaultFieldAccessSite(sfa.location, nodes.get(sfa.callee), sfa.field));
@@ -208,5 +239,13 @@ public class DefaultCallGraph implements CallGraph, Serializable {
cg.addFieldAccess(fieldAccessList.get(index));
}
}
+
+ private Set mapNodes(int[] nodes) {
+ Set result = new LinkedHashSet<>();
+ for (int i = 0; i < nodes.length; ++i) {
+ result.add(this.nodes.get(nodes[i]));
+ }
+ return result;
+ }
}
}
diff --git a/core/src/main/java/org/teavm/callgraph/DefaultCallGraphNode.java b/core/src/main/java/org/teavm/dependency/DefaultCallGraphNode.java
similarity index 60%
rename from core/src/main/java/org/teavm/callgraph/DefaultCallGraphNode.java
rename to core/src/main/java/org/teavm/dependency/DefaultCallGraphNode.java
index f150a8149..209c70bc2 100644
--- a/core/src/main/java/org/teavm/callgraph/DefaultCallGraphNode.java
+++ b/core/src/main/java/org/teavm/dependency/DefaultCallGraphNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Alexey Andreev.
+ * Copyright 2019 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,29 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.teavm.callgraph;
+package org.teavm.dependency;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import org.teavm.callgraph.CallGraphNode;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference;
import org.teavm.model.TextLocation;
-public class DefaultCallGraphNode implements CallGraphNode {
+class DefaultCallGraphNode implements CallGraphNode {
private DefaultCallGraph graph;
private MethodReference method;
- private Set callSites;
+ private Map callSiteMap;
+ private List callSites;
private DefaultCallSite singleCallSite;
- private Set safeCallSites;
+ private Collection safeCallSites;
private DefaultCallSite singleCaller;
private List callerCallSites;
private List safeCallersCallSites;
private Set fieldAccessSites = new LinkedHashSet<>();
private Set safeFieldAccessSites;
+ private DefaultCallSite virtualCallSite;
DefaultCallGraphNode(DefaultCallGraph graph, MethodReference method) {
this.graph = graph;
@@ -61,7 +66,7 @@ public class DefaultCallGraphNode implements CallGraphNode {
return Collections.emptyList();
}
if (safeCallSites == null) {
- safeCallSites = Collections.unmodifiableSet(callSites);
+ safeCallSites = Collections.unmodifiableCollection(callSites);
}
return safeCallSites;
}
@@ -80,28 +85,64 @@ public class DefaultCallGraphNode implements CallGraphNode {
return safeCallersCallSites;
}
- public boolean addCallSite(MethodReference method, TextLocation location) {
+ DefaultCallSite addCallSite(MethodReference method) {
DefaultCallGraphNode callee = graph.getNode(method);
- DefaultCallSite callSite = new DefaultCallSite(location, callee, this);
+
if (callSites == null) {
if (singleCallSite == null) {
- singleCallSite = callSite;
- callee.addCaller(callSite);
- return true;
+ singleCallSite = new DefaultCallSite(callee, this);
+ callee.addCaller(singleCallSite);
+ return singleCallSite;
}
- callSites = new LinkedHashSet<>();
+ if (singleCallSite != null) {
+ if (singleCallSite.singleCalledMethod.getMethod().equals(method)) {
+ return singleCallSite;
+ }
+ }
+ callSiteMap = new LinkedHashMap<>();
+ callSites = new ArrayList<>();
+ callSiteMap.put(singleCallSite.singleCalledMethod.getMethod(), singleCallSite);
callSites.add(singleCallSite);
singleCallSite = null;
}
- if (callSites.add(callSite)) {
+
+ DefaultCallSite callSite = callSiteMap.get(method);
+ if (callSite == null) {
+ callSite = new DefaultCallSite(callee, this);
callee.addCaller(callSite);
- return true;
- } else {
- return false;
+ callSiteMap.put(method, callSite);
+ callSites.add(callSite);
+ }
+
+ return callSite;
+ }
+
+ DefaultCallSite getVirtualCallSite() {
+ if (virtualCallSite == null) {
+ virtualCallSite = new DefaultCallSite(method, new LinkedHashSet<>());
+ }
+ return virtualCallSite;
+ }
+
+ void addVirtualCallSite(DefaultCallSite callSite) {
+ if (callSite.callers == null) {
+ throw new IllegalArgumentException("Call site is not virtual");
+ }
+ if (callSite.callers.add(this)) {
+ if (callSites == null) {
+ callSites = new ArrayList<>();
+ callSiteMap = new LinkedHashMap<>();
+ if (singleCallSite != null) {
+ callSites.add(singleCallSite);
+ callSiteMap.put(singleCallSite.method, singleCallSite);
+ singleCallSite = null;
+ }
+ }
+ callSites.add(callSite);
}
}
- private void addCaller(DefaultCallSite caller) {
+ void addCaller(DefaultCallSite caller) {
if (callerCallSites == null) {
if (singleCaller == null) {
singleCaller = caller;
@@ -114,10 +155,6 @@ public class DefaultCallGraphNode implements CallGraphNode {
callerCallSites.add(caller);
}
- public boolean addCallSite(MethodReference method) {
- return addCallSite(method, null);
- }
-
@Override
public Collection getFieldAccessSites() {
if (safeFieldAccessSites == null) {
@@ -126,7 +163,7 @@ public class DefaultCallGraphNode implements CallGraphNode {
return safeFieldAccessSites;
}
- public boolean addFieldAccess(FieldReference field, TextLocation location) {
+ boolean addFieldAccess(FieldReference field, TextLocation location) {
DefaultFieldAccessSite site = new DefaultFieldAccessSite(location, this, field);
if (fieldAccessSites.add(site)) {
graph.addFieldAccess(site);
diff --git a/core/src/main/java/org/teavm/dependency/DefaultCallSite.java b/core/src/main/java/org/teavm/dependency/DefaultCallSite.java
new file mode 100644
index 000000000..e82381ccc
--- /dev/null
+++ b/core/src/main/java/org/teavm/dependency/DefaultCallSite.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.dependency;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import org.teavm.callgraph.CallGraphNode;
+import org.teavm.callgraph.CallSite;
+import org.teavm.model.MethodReference;
+import org.teavm.model.TextLocation;
+
+public class DefaultCallSite implements CallSite, Serializable {
+ private Map> locations;
+ private TextLocation singleLocation;
+ MethodReference method;
+ Set callers;
+ private DefaultCallGraphNode singleCaller;
+ Set calledMethods;
+ DefaultCallGraphNode singleCalledMethod;
+ Collection extends DefaultCallGraphNode> readonlyCalledMethods;
+
+ DefaultCallSite(MethodReference method, Set callers) {
+ this.method = method;
+ this.callers = callers;
+ locations = new HashMap<>();
+ calledMethods = new LinkedHashSet<>();
+ }
+
+ DefaultCallSite(DefaultCallGraphNode callee, DefaultCallGraphNode caller) {
+ this.singleCalledMethod = callee;
+ this.singleCaller = caller;
+ }
+
+ @Override
+ public Collection extends TextLocation> getLocations(CallGraphNode caller) {
+ if (singleLocation != null) {
+ return caller == this.singleCaller ? Collections.singleton(singleLocation) : Collections.emptySet();
+ }
+ if (locations == null) {
+ return Collections.emptyList();
+ }
+ Set result = locations.get(caller);
+ return result != null ? Collections.unmodifiableSet(result) : Collections.emptySet();
+ }
+
+ public void addLocation(DefaultCallGraphNode caller, TextLocation location) {
+ if (locations == null) {
+ if (singleLocation == null && callers == null) {
+ singleLocation = location;
+ return;
+ }
+ locations = new LinkedHashMap<>();
+ if (singleLocation != null) {
+ Set singleLocations = new LinkedHashSet<>();
+ singleLocations.add(singleLocation);
+ locations.put(singleCaller, singleLocations);
+ }
+ }
+ locations.computeIfAbsent(caller, k -> new LinkedHashSet<>()).add(location);
+ }
+
+ @Override
+ public Collection extends DefaultCallGraphNode> getCalledMethods() {
+ if (singleCalledMethod == null) {
+ return Collections.singletonList(singleCalledMethod);
+ }
+ if (readonlyCalledMethods == null) {
+ readonlyCalledMethods = Collections.unmodifiableCollection(calledMethods);
+ }
+ return readonlyCalledMethods;
+ }
+
+ @Override
+ public Collection extends DefaultCallGraphNode> getCallers() {
+ return callers != null ? callers : Collections.singletonList(singleCaller);
+ }
+}
diff --git a/core/src/main/java/org/teavm/callgraph/DefaultFieldAccessSite.java b/core/src/main/java/org/teavm/dependency/DefaultFieldAccessSite.java
similarity index 90%
rename from core/src/main/java/org/teavm/callgraph/DefaultFieldAccessSite.java
rename to core/src/main/java/org/teavm/dependency/DefaultFieldAccessSite.java
index a7621719a..ac55e91a4 100644
--- a/core/src/main/java/org/teavm/callgraph/DefaultFieldAccessSite.java
+++ b/core/src/main/java/org/teavm/dependency/DefaultFieldAccessSite.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Alexey Andreev.
+ * Copyright 2019 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.teavm.callgraph;
+package org.teavm.dependency;
import java.io.Serializable;
import java.util.Objects;
+import org.teavm.callgraph.FieldAccessSite;
import org.teavm.model.FieldReference;
import org.teavm.model.TextLocation;
-public class DefaultFieldAccessSite implements FieldAccessSite, Serializable {
+class DefaultFieldAccessSite implements FieldAccessSite, Serializable {
private TextLocation location;
private DefaultCallGraphNode callee;
private FieldReference field;
diff --git a/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java b/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java
index dfa133ed8..cdf13778f 100644
--- a/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java
+++ b/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java
@@ -36,7 +36,6 @@ import org.objectweb.asm.tree.ClassNode;
import org.teavm.cache.IncrementalDependencyProvider;
import org.teavm.cache.IncrementalDependencyRegistration;
import org.teavm.callgraph.CallGraph;
-import org.teavm.callgraph.DefaultCallGraph;
import org.teavm.common.CachedMapper;
import org.teavm.common.Mapper;
import org.teavm.common.ServiceRepository;
diff --git a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java
index ae176ff44..0cb0b09ee 100644
--- a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java
+++ b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java
@@ -22,7 +22,6 @@ import static org.teavm.dependency.AbstractInstructionAnalyzer.MONITOR_EXIT_SYNC
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import org.teavm.callgraph.DefaultCallGraphNode;
import org.teavm.model.BasicBlockReader;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassHierarchy;
diff --git a/core/src/main/java/org/teavm/dependency/FastDependencyAnalyzer.java b/core/src/main/java/org/teavm/dependency/FastDependencyAnalyzer.java
index cadd1c614..38b051d40 100644
--- a/core/src/main/java/org/teavm/dependency/FastDependencyAnalyzer.java
+++ b/core/src/main/java/org/teavm/dependency/FastDependencyAnalyzer.java
@@ -177,7 +177,7 @@ public class FastDependencyAnalyzer extends DependencyAnalyzer {
FastVirtualCallConsumer getVirtualCallConsumer(MethodReference method) {
return virtualCallConsumers.computeIfAbsent(method, key -> {
- FastVirtualCallConsumer consumer = new FastVirtualCallConsumer(instancesNode, key.getDescriptor(), this);
+ FastVirtualCallConsumer consumer = new FastVirtualCallConsumer(instancesNode, key, this);
defer(() -> {
getSubtypeNode(method.getClassName()).addConsumer(consumer);
});
diff --git a/core/src/main/java/org/teavm/dependency/FastInstructionAnalyzer.java b/core/src/main/java/org/teavm/dependency/FastInstructionAnalyzer.java
index c6ace2756..f3a27616e 100644
--- a/core/src/main/java/org/teavm/dependency/FastInstructionAnalyzer.java
+++ b/core/src/main/java/org/teavm/dependency/FastInstructionAnalyzer.java
@@ -47,7 +47,8 @@ class FastInstructionAnalyzer extends AbstractInstructionAnalyzer {
protected void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method,
List extends VariableReader> arguments) {
invokeGetClass(method);
- dependencyAnalyzer.getVirtualCallConsumer(method).addLocation(impreciseLocation);
+ FastVirtualCallConsumer consumer = dependencyAnalyzer.getVirtualCallConsumer(method);
+ consumer.addLocation(impreciseLocation);
}
private void invokeGetClass(MethodReference method) {
diff --git a/core/src/main/java/org/teavm/dependency/FastVirtualCallConsumer.java b/core/src/main/java/org/teavm/dependency/FastVirtualCallConsumer.java
index 124227fa1..31f5fe4c7 100644
--- a/core/src/main/java/org/teavm/dependency/FastVirtualCallConsumer.java
+++ b/core/src/main/java/org/teavm/dependency/FastVirtualCallConsumer.java
@@ -20,41 +20,45 @@ import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.teavm.model.CallLocation;
-import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
class FastVirtualCallConsumer implements DependencyConsumer {
private final DependencyNode node;
- private final MethodDescriptor methodDesc;
+ private final MethodReference methodRef;
private final DependencyAnalyzer analyzer;
private final Map callLocations = new LinkedHashMap<>();
private final Set methods = new LinkedHashSet<>(100, 0.5f);
+ final DefaultCallSite callSite;
- FastVirtualCallConsumer(DependencyNode node, MethodDescriptor methodDesc, DependencyAnalyzer analyzer) {
+ FastVirtualCallConsumer(DependencyNode node, MethodReference methodRef, DependencyAnalyzer analyzer) {
this.node = node;
- this.methodDesc = methodDesc;
+ this.methodRef = methodRef;
this.analyzer = analyzer;
+ callSite = analyzer.callGraph.getNode(methodRef).getVirtualCallSite();
}
@Override
public void consume(DependencyType type) {
String className = type.getName();
if (DependencyAnalyzer.shouldLog) {
- System.out.println("Virtual call of " + methodDesc + " detected on " + node.getTag() + ". "
+ System.out.println("Virtual call of " + methodRef + " detected on " + node.getTag() + ". "
+ "Target class is " + className);
}
if (className.startsWith("[")) {
className = "java.lang.Object";
- type = analyzer.getType(className);
}
- MethodDependency methodDep = analyzer.linkMethod(className, methodDesc);
+ MethodDependency methodDep = analyzer.linkMethod(className, methodRef.getDescriptor());
if (!methods.add(methodDep)) {
return;
}
+ DefaultCallGraphNode calledMethodNode = analyzer.callGraph.getNode(methodDep.getReference());
+ callSite.calledMethods.add(calledMethodNode);
+ calledMethodNode.addCaller(callSite);
+
for (CallLocation location : callLocations.values()) {
- methodDep.addLocation(location);
+ methodDep.addLocation(location, false);
}
if (!methodDep.isMissing()) {
@@ -64,8 +68,13 @@ class FastVirtualCallConsumer implements DependencyConsumer {
void addLocation(CallLocation location) {
if (callLocations.putIfAbsent(location.getMethod(), location) == null) {
+ DefaultCallGraphNode caller = analyzer.callGraph.getNode(location.getMethod());
+ caller.addVirtualCallSite(callSite);
+ if (location.getSourceLocation() != null) {
+ callSite.addLocation(caller, location.getSourceLocation());
+ }
for (MethodDependency method : methods) {
- method.addLocation(location);
+ method.addLocation(location, false);
}
}
}
diff --git a/core/src/main/java/org/teavm/dependency/FieldDependency.java b/core/src/main/java/org/teavm/dependency/FieldDependency.java
index 5df70a43a..27ea3c7ad 100644
--- a/core/src/main/java/org/teavm/dependency/FieldDependency.java
+++ b/core/src/main/java/org/teavm/dependency/FieldDependency.java
@@ -19,7 +19,6 @@ import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
-import org.teavm.callgraph.DefaultCallGraphNode;
import org.teavm.model.CallLocation;
import org.teavm.model.FieldReader;
import org.teavm.model.FieldReference;
diff --git a/core/src/main/java/org/teavm/dependency/MethodDependency.java b/core/src/main/java/org/teavm/dependency/MethodDependency.java
index db0a60806..a32b0311f 100644
--- a/core/src/main/java/org/teavm/dependency/MethodDependency.java
+++ b/core/src/main/java/org/teavm/dependency/MethodDependency.java
@@ -20,7 +20,6 @@ import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
-import org.teavm.callgraph.DefaultCallGraphNode;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReader;
@@ -111,12 +110,21 @@ public class MethodDependency implements MethodDependencyInfo {
}
public MethodDependency addLocation(CallLocation location) {
+ return addLocation(location, true);
+ }
+
+ MethodDependency addLocation(CallLocation location, boolean addCallSite) {
DefaultCallGraphNode node = dependencyAnalyzer.callGraph.getNode(location.getMethod());
if (locations == null) {
locations = new LinkedHashSet<>();
}
if (locations.add(location)) {
- node.addCallSite(reference, location.getSourceLocation());
+ if (addCallSite) {
+ DefaultCallSite callSite = node.addCallSite(reference);
+ if (location.getSourceLocation() != null) {
+ callSite.addLocation(node, location.getSourceLocation());
+ }
+ }
if (locationListeners != null) {
for (LocationListener listener : locationListeners.toArray(new LocationListener[0])) {
listener.locationAdded(location);
diff --git a/core/src/main/java/org/teavm/callgraph/SerializableCallGraph.java b/core/src/main/java/org/teavm/dependency/SerializableCallGraph.java
similarity index 76%
rename from core/src/main/java/org/teavm/callgraph/SerializableCallGraph.java
rename to core/src/main/java/org/teavm/dependency/SerializableCallGraph.java
index d44c1aab6..558105af8 100644
--- a/core/src/main/java/org/teavm/callgraph/SerializableCallGraph.java
+++ b/core/src/main/java/org/teavm/dependency/SerializableCallGraph.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Alexey Andreev.
+ * Copyright 2019 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.teavm.callgraph;
+package org.teavm.dependency;
import java.io.Serializable;
import org.teavm.model.FieldReference;
@@ -35,15 +35,22 @@ class SerializableCallGraph implements Serializable {
int[] fieldAccessSites;
}
- static class CallSite implements Serializable {
- TextLocation location;
- int callee;
- int caller;
+ static class CallSite implements Serializable {
+ MethodReference method;
+ boolean virtual;
+ Location[] locations;
+ int[] calledMethods;
+ int[] callers;
}
- static class FieldAccess implements Serializable {
+ static class FieldAccess implements Serializable {
TextLocation location;
int callee;
FieldReference field;
}
+
+ static class Location {
+ TextLocation value;
+ int caller;
+ }
}
diff --git a/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java b/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java
index 07f8f8316..e71fdbeee 100644
--- a/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java
+++ b/core/src/main/java/org/teavm/dependency/VirtualCallConsumer.java
@@ -62,7 +62,6 @@ class VirtualCallConsumer implements DependencyConsumer {
}
if (className.startsWith("[")) {
className = "java.lang.Object";
- type = analyzer.getType(className);
}
MethodDependency methodDep = analyzer.linkMethod(className, methodDesc);
diff --git a/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java b/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java
index 5f5d3a47d..fe15aa7d3 100644
--- a/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java
+++ b/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java
@@ -46,7 +46,6 @@ public class AsyncMethodFinder {
private Map asyncFamilyMethods = new HashMap<>();
private Set readonlyAsyncMethods = Collections.unmodifiableSet(asyncMethods);
private Set readonlyAsyncFamilyMethods = Collections.unmodifiableSet(asyncFamilyMethods.keySet());
- private Map> overiddenMethodsCache = new HashMap<>();
private CallGraph callGraph;
private Diagnostics diagnostics;
private ListableClassReaderSource classSource;
@@ -178,8 +177,9 @@ public class AsyncMethodFinder {
return;
}
for (CallSite callSite : node.getCallerCallSites()) {
- MethodReference nextMethod = callSite.getCaller().getMethod();
- add(nextMethod, new CallStack(nextMethod, stack));
+ for (CallGraphNode caller : callSite.getCallers()) {
+ add(caller.getMethod(), new CallStack(caller.getMethod(), stack));
+ }
}
}
diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java
index 1acb76054..65dce0550 100644
--- a/core/src/main/java/org/teavm/vm/TeaVM.java
+++ b/core/src/main/java/org/teavm/vm/TeaVM.java
@@ -125,7 +125,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
private static final MethodDescriptor MAIN_METHOD_DESC = new MethodDescriptor("main",
ValueType.arrayOf(ValueType.object("java.lang.String")), ValueType.VOID);
- private final ClassReaderSource classSource;
private final DependencyAnalyzer dependencyAnalyzer;
private final AccumulationDiagnostics diagnostics = new AccumulationDiagnostics();
private final ClassLoader classLoader;
@@ -155,9 +154,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
TeaVM(TeaVMBuilder builder) {
target = builder.target;
- classSource = builder.classSource;
classLoader = builder.classLoader;
- dependencyAnalyzer = builder.dependencyAnalyzerFactory.create(this.classSource, classLoader,
+ dependencyAnalyzer = builder.dependencyAnalyzerFactory.create(builder.classSource, classLoader,
this, diagnostics, builder.referenceCache);
progressListener = new TeaVMProgressListener() {
@Override public TeaVMProgressFeedback progressReached(int progress) {
@@ -313,21 +311,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
preservedClasses.add(className);
}
- /**
- * Gets a {@link ClassReaderSource} which is used by this TeaVM instance. It is exactly what was
- * passed to {@link TeaVMBuilder#setClassSource(ClassReaderSource)}.
- *
- * @return class source.
- */
- public ClassReaderSource getClassSource() {
- return classSource;
- }
-
- /**
- * Gets a {@link ClassReaderSource} which is similar to that of {@link #getClassSource()},
- * except that it also contains classes with applied transformations together with
- * classes, generated via {@link org.teavm.dependency.DependencyAgent#submitClass(ClassHolder)}.
- */
public ClassReaderSource getDependencyClassSource() {
return dependencyAnalyzer.getClassSource();
}
diff --git a/tools/core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java
index e3285d7a9..eee637578 100644
--- a/tools/core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java
+++ b/tools/core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java
@@ -15,6 +15,7 @@
*/
package org.teavm.tooling;
+import java.util.Collection;
import java.util.Iterator;
import org.teavm.callgraph.CallGraph;
import org.teavm.callgraph.CallGraphNode;
@@ -70,12 +71,33 @@ public final class TeaVMProblemRenderer {
}
CallSite callSite = callSites.next();
sb.append("\n at ");
- renderCallLocation(callSite.getCaller().getMethod(), callSite.getLocation(), sb);
- node = callSite.getCaller();
+
+ CallGraphNode caller = getCaller(callSite);
+ renderCallLocation(caller.getMethod(), getLocation(callSite, caller), sb);
+ node = caller;
}
}
}
+ private static CallGraphNode getCaller(CallSite callSite) {
+ Collection extends CallGraphNode> callers = callSite.getCallers();
+ if (callers.isEmpty()) {
+ return null;
+ }
+ return callers.iterator().next();
+ }
+
+ private static TextLocation getLocation(CallSite callSite, CallGraphNode caller) {
+ if (caller == null) {
+ return null;
+ }
+ Collection extends TextLocation> locations = callSite.getLocations(caller);
+ if (locations.isEmpty()) {
+ return null;
+ }
+ return locations.iterator().next();
+ }
+
public static void renderCallLocation(MethodReference method, TextLocation location, StringBuilder sb) {
if (method != null) {
sb.append(method.getClassName() + "." + method.getName());