mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Reduce memory used by call graph in dev server mode
This commit is contained in:
parent
88dca1bd02
commit
fcfa998e1c
|
@ -18,37 +18,13 @@ package org.teavm.callgraph;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import org.teavm.model.MethodReference;
|
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 {
|
public interface CallGraphNode {
|
||||||
/**
|
|
||||||
* Returns reference to entire call graph.
|
|
||||||
*
|
|
||||||
* @return graph
|
|
||||||
*/
|
|
||||||
CallGraph getGraph();
|
CallGraph getGraph();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the method that this node represents.
|
|
||||||
*
|
|
||||||
* @return method
|
|
||||||
*/
|
|
||||||
MethodReference getMethod();
|
MethodReference getMethod();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns immutable collection of all call sites that are in the method.
|
|
||||||
*
|
|
||||||
* @return call site
|
|
||||||
*/
|
|
||||||
Collection<? extends CallSite> getCallSites();
|
Collection<? extends CallSite> getCallSites();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns immutable collection of all call sites that call this method.
|
|
||||||
*
|
|
||||||
* @return call sites
|
|
||||||
*/
|
|
||||||
Collection<? extends CallSite> getCallerCallSites();
|
Collection<? extends CallSite> getCallerCallSites();
|
||||||
|
|
||||||
Collection<? extends FieldAccessSite> getFieldAccessSites();
|
Collection<? extends FieldAccessSite> getFieldAccessSites();
|
||||||
|
|
|
@ -15,31 +15,13 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.callgraph;
|
package org.teavm.callgraph;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import org.teavm.model.TextLocation;
|
import org.teavm.model.TextLocation;
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Call site that represents exact place in the code that calls a method.</p>.
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public interface CallSite {
|
public interface CallSite {
|
||||||
/**
|
Collection<? extends TextLocation> getLocations(CallGraphNode caller);
|
||||||
* <p>Gets location of the call site</p>.
|
|
||||||
*
|
|
||||||
* @return location of the call site or <code>null</code> if no debug information found for this call site.
|
|
||||||
*/
|
|
||||||
TextLocation getLocation();
|
|
||||||
|
|
||||||
/**
|
Collection<? extends CallGraphNode> getCalledMethods();
|
||||||
* <p>Gets a method that this call site invokes.</p>
|
|
||||||
*
|
|
||||||
* @return a node that represent methods being called
|
|
||||||
*/
|
|
||||||
CallGraphNode getCallee();
|
|
||||||
|
|
||||||
/**
|
Collection<? extends CallGraphNode> getCallers();
|
||||||
* <p>Gets a method that contains this call site.</p>
|
|
||||||
*
|
|
||||||
* @return a node that represents methods's caller
|
|
||||||
*/
|
|
||||||
CallGraphNode getCaller();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -294,8 +294,8 @@ public class DebugInformation {
|
||||||
|
|
||||||
private DebuggerCallSite getCallSite(int index) {
|
private DebuggerCallSite getCallSite(int index) {
|
||||||
RecordArray.Record record = callSiteMapping.get(index);
|
RecordArray.Record record = callSiteMapping.get(index);
|
||||||
int type = record.get(2);
|
int type = record.get(0);
|
||||||
int method = record.get(3);
|
int method = record.get(1);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DebuggerCallSite.NONE:
|
case DebuggerCallSite.NONE:
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2014 Alexey Andreev.
|
* Copyright 2019 Alexey Andreev.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.teavm.callgraph;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
import com.carrotsearch.hppc.ObjectIntHashMap;
|
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||||
import com.carrotsearch.hppc.ObjectIntMap;
|
import com.carrotsearch.hppc.ObjectIntMap;
|
||||||
|
@ -30,10 +30,12 @@ import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import org.teavm.callgraph.CallGraph;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.TextLocation;
|
||||||
|
|
||||||
public class DefaultCallGraph implements CallGraph, Serializable {
|
class DefaultCallGraph implements CallGraph, Serializable {
|
||||||
public Map<MethodReference, DefaultCallGraphNode> nodes = new HashMap<>();
|
public Map<MethodReference, DefaultCallGraphNode> nodes = new HashMap<>();
|
||||||
Map<FieldReference, Set<DefaultFieldAccessSite>> fieldAccessSites = new HashMap<>();
|
Map<FieldReference, Set<DefaultFieldAccessSite>> fieldAccessSites = new HashMap<>();
|
||||||
|
|
||||||
|
@ -127,9 +129,19 @@ public class DefaultCallGraph implements CallGraph, Serializable {
|
||||||
for (DefaultCallSite callSite : callSitesToProcess.toArray(new DefaultCallSite[0])) {
|
for (DefaultCallSite callSite : callSitesToProcess.toArray(new DefaultCallSite[0])) {
|
||||||
int index = callSiteToIndex.get(callSite);
|
int index = callSiteToIndex.get(callSite);
|
||||||
SerializableCallGraph.CallSite scs = callSites.get(index);
|
SerializableCallGraph.CallSite scs = callSites.get(index);
|
||||||
scs.location = callSite.getLocation();
|
scs.virtual = callSite.callers != null;
|
||||||
scs.caller = getNode(callSite.getCaller());
|
List<SerializableCallGraph.Location> locations = new ArrayList<>();
|
||||||
scs.callee = getNode(callSite.getCallee());
|
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;
|
hasAny = true;
|
||||||
}
|
}
|
||||||
callSitesToProcess.clear();
|
callSitesToProcess.clear();
|
||||||
|
@ -161,6 +173,15 @@ public class DefaultCallGraph implements CallGraph, Serializable {
|
||||||
return index;
|
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) {
|
private int getCallSite(DefaultCallSite callSite) {
|
||||||
int index = callSiteToIndex.getOrDefault(callSite, -1);
|
int index = callSiteToIndex.getOrDefault(callSite, -1);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
|
@ -194,7 +215,17 @@ public class DefaultCallGraph implements CallGraph, Serializable {
|
||||||
nodes.add(new DefaultCallGraphNode(cg, serializableNode.method));
|
nodes.add(new DefaultCallGraphNode(cg, serializableNode.method));
|
||||||
}
|
}
|
||||||
for (SerializableCallGraph.CallSite scs : scg.callSites) {
|
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) {
|
for (SerializableCallGraph.FieldAccess sfa : scg.fieldAccessList) {
|
||||||
fieldAccessList.add(new DefaultFieldAccessSite(sfa.location, nodes.get(sfa.callee), sfa.field));
|
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));
|
cg.addFieldAccess(fieldAccessList.get(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<DefaultCallGraphNode> mapNodes(int[] nodes) {
|
||||||
|
Set<DefaultCallGraphNode> result = new LinkedHashSet<>();
|
||||||
|
for (int i = 0; i < nodes.length; ++i) {
|
||||||
|
result.add(this.nodes.get(nodes[i]));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2014 Alexey Andreev.
|
* Copyright 2019 Alexey Andreev.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.teavm.callgraph;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import org.teavm.callgraph.CallGraphNode;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.TextLocation;
|
import org.teavm.model.TextLocation;
|
||||||
|
|
||||||
public class DefaultCallGraphNode implements CallGraphNode {
|
class DefaultCallGraphNode implements CallGraphNode {
|
||||||
private DefaultCallGraph graph;
|
private DefaultCallGraph graph;
|
||||||
private MethodReference method;
|
private MethodReference method;
|
||||||
private Set<DefaultCallSite> callSites;
|
private Map<MethodReference, DefaultCallSite> callSiteMap;
|
||||||
|
private List<DefaultCallSite> callSites;
|
||||||
private DefaultCallSite singleCallSite;
|
private DefaultCallSite singleCallSite;
|
||||||
private Set<DefaultCallSite> safeCallSites;
|
private Collection<DefaultCallSite> safeCallSites;
|
||||||
private DefaultCallSite singleCaller;
|
private DefaultCallSite singleCaller;
|
||||||
private List<DefaultCallSite> callerCallSites;
|
private List<DefaultCallSite> callerCallSites;
|
||||||
private List<DefaultCallSite> safeCallersCallSites;
|
private List<DefaultCallSite> safeCallersCallSites;
|
||||||
private Set<DefaultFieldAccessSite> fieldAccessSites = new LinkedHashSet<>();
|
private Set<DefaultFieldAccessSite> fieldAccessSites = new LinkedHashSet<>();
|
||||||
private Set<DefaultFieldAccessSite> safeFieldAccessSites;
|
private Set<DefaultFieldAccessSite> safeFieldAccessSites;
|
||||||
|
private DefaultCallSite virtualCallSite;
|
||||||
|
|
||||||
DefaultCallGraphNode(DefaultCallGraph graph, MethodReference method) {
|
DefaultCallGraphNode(DefaultCallGraph graph, MethodReference method) {
|
||||||
this.graph = graph;
|
this.graph = graph;
|
||||||
|
@ -61,7 +66,7 @@ public class DefaultCallGraphNode implements CallGraphNode {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
if (safeCallSites == null) {
|
if (safeCallSites == null) {
|
||||||
safeCallSites = Collections.unmodifiableSet(callSites);
|
safeCallSites = Collections.unmodifiableCollection(callSites);
|
||||||
}
|
}
|
||||||
return safeCallSites;
|
return safeCallSites;
|
||||||
}
|
}
|
||||||
|
@ -80,28 +85,64 @@ public class DefaultCallGraphNode implements CallGraphNode {
|
||||||
return safeCallersCallSites;
|
return safeCallersCallSites;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addCallSite(MethodReference method, TextLocation location) {
|
DefaultCallSite addCallSite(MethodReference method) {
|
||||||
DefaultCallGraphNode callee = graph.getNode(method);
|
DefaultCallGraphNode callee = graph.getNode(method);
|
||||||
DefaultCallSite callSite = new DefaultCallSite(location, callee, this);
|
|
||||||
if (callSites == null) {
|
if (callSites == null) {
|
||||||
if (singleCallSite == null) {
|
if (singleCallSite == null) {
|
||||||
singleCallSite = callSite;
|
singleCallSite = new DefaultCallSite(callee, this);
|
||||||
callee.addCaller(callSite);
|
callee.addCaller(singleCallSite);
|
||||||
return true;
|
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);
|
callSites.add(singleCallSite);
|
||||||
singleCallSite = null;
|
singleCallSite = null;
|
||||||
}
|
}
|
||||||
if (callSites.add(callSite)) {
|
|
||||||
|
DefaultCallSite callSite = callSiteMap.get(method);
|
||||||
|
if (callSite == null) {
|
||||||
|
callSite = new DefaultCallSite(callee, this);
|
||||||
callee.addCaller(callSite);
|
callee.addCaller(callSite);
|
||||||
return true;
|
callSiteMap.put(method, callSite);
|
||||||
} else {
|
callSites.add(callSite);
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
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 (callerCallSites == null) {
|
||||||
if (singleCaller == null) {
|
if (singleCaller == null) {
|
||||||
singleCaller = caller;
|
singleCaller = caller;
|
||||||
|
@ -114,10 +155,6 @@ public class DefaultCallGraphNode implements CallGraphNode {
|
||||||
callerCallSites.add(caller);
|
callerCallSites.add(caller);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addCallSite(MethodReference method) {
|
|
||||||
return addCallSite(method, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<DefaultFieldAccessSite> getFieldAccessSites() {
|
public Collection<DefaultFieldAccessSite> getFieldAccessSites() {
|
||||||
if (safeFieldAccessSites == null) {
|
if (safeFieldAccessSites == null) {
|
||||||
|
@ -126,7 +163,7 @@ public class DefaultCallGraphNode implements CallGraphNode {
|
||||||
return safeFieldAccessSites;
|
return safeFieldAccessSites;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addFieldAccess(FieldReference field, TextLocation location) {
|
boolean addFieldAccess(FieldReference field, TextLocation location) {
|
||||||
DefaultFieldAccessSite site = new DefaultFieldAccessSite(location, this, field);
|
DefaultFieldAccessSite site = new DefaultFieldAccessSite(location, this, field);
|
||||||
if (fieldAccessSites.add(site)) {
|
if (fieldAccessSites.add(site)) {
|
||||||
graph.addFieldAccess(site);
|
graph.addFieldAccess(site);
|
96
core/src/main/java/org/teavm/dependency/DefaultCallSite.java
Normal file
96
core/src/main/java/org/teavm/dependency/DefaultCallSite.java
Normal file
|
@ -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<CallGraphNode, Set<TextLocation>> locations;
|
||||||
|
private TextLocation singleLocation;
|
||||||
|
MethodReference method;
|
||||||
|
Set<DefaultCallGraphNode> callers;
|
||||||
|
private DefaultCallGraphNode singleCaller;
|
||||||
|
Set<DefaultCallGraphNode> calledMethods;
|
||||||
|
DefaultCallGraphNode singleCalledMethod;
|
||||||
|
Collection<? extends DefaultCallGraphNode> readonlyCalledMethods;
|
||||||
|
|
||||||
|
DefaultCallSite(MethodReference method, Set<DefaultCallGraphNode> 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<TextLocation> 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<TextLocation> 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2014 Alexey Andreev.
|
* Copyright 2019 Alexey Andreev.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.teavm.callgraph;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import org.teavm.callgraph.FieldAccessSite;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.TextLocation;
|
import org.teavm.model.TextLocation;
|
||||||
|
|
||||||
public class DefaultFieldAccessSite implements FieldAccessSite, Serializable {
|
class DefaultFieldAccessSite implements FieldAccessSite, Serializable {
|
||||||
private TextLocation location;
|
private TextLocation location;
|
||||||
private DefaultCallGraphNode callee;
|
private DefaultCallGraphNode callee;
|
||||||
private FieldReference field;
|
private FieldReference field;
|
|
@ -36,7 +36,6 @@ import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.teavm.cache.IncrementalDependencyProvider;
|
import org.teavm.cache.IncrementalDependencyProvider;
|
||||||
import org.teavm.cache.IncrementalDependencyRegistration;
|
import org.teavm.cache.IncrementalDependencyRegistration;
|
||||||
import org.teavm.callgraph.CallGraph;
|
import org.teavm.callgraph.CallGraph;
|
||||||
import org.teavm.callgraph.DefaultCallGraph;
|
|
||||||
import org.teavm.common.CachedMapper;
|
import org.teavm.common.CachedMapper;
|
||||||
import org.teavm.common.Mapper;
|
import org.teavm.common.Mapper;
|
||||||
import org.teavm.common.ServiceRepository;
|
import org.teavm.common.ServiceRepository;
|
||||||
|
|
|
@ -22,7 +22,6 @@ import static org.teavm.dependency.AbstractInstructionAnalyzer.MONITOR_EXIT_SYNC
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.teavm.callgraph.DefaultCallGraphNode;
|
|
||||||
import org.teavm.model.BasicBlockReader;
|
import org.teavm.model.BasicBlockReader;
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.ClassHierarchy;
|
import org.teavm.model.ClassHierarchy;
|
||||||
|
|
|
@ -177,7 +177,7 @@ public class FastDependencyAnalyzer extends DependencyAnalyzer {
|
||||||
|
|
||||||
FastVirtualCallConsumer getVirtualCallConsumer(MethodReference method) {
|
FastVirtualCallConsumer getVirtualCallConsumer(MethodReference method) {
|
||||||
return virtualCallConsumers.computeIfAbsent(method, key -> {
|
return virtualCallConsumers.computeIfAbsent(method, key -> {
|
||||||
FastVirtualCallConsumer consumer = new FastVirtualCallConsumer(instancesNode, key.getDescriptor(), this);
|
FastVirtualCallConsumer consumer = new FastVirtualCallConsumer(instancesNode, key, this);
|
||||||
defer(() -> {
|
defer(() -> {
|
||||||
getSubtypeNode(method.getClassName()).addConsumer(consumer);
|
getSubtypeNode(method.getClassName()).addConsumer(consumer);
|
||||||
});
|
});
|
||||||
|
|
|
@ -47,7 +47,8 @@ class FastInstructionAnalyzer extends AbstractInstructionAnalyzer {
|
||||||
protected void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method,
|
protected void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method,
|
||||||
List<? extends VariableReader> arguments) {
|
List<? extends VariableReader> arguments) {
|
||||||
invokeGetClass(method);
|
invokeGetClass(method);
|
||||||
dependencyAnalyzer.getVirtualCallConsumer(method).addLocation(impreciseLocation);
|
FastVirtualCallConsumer consumer = dependencyAnalyzer.getVirtualCallConsumer(method);
|
||||||
|
consumer.addLocation(impreciseLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invokeGetClass(MethodReference method) {
|
private void invokeGetClass(MethodReference method) {
|
||||||
|
|
|
@ -20,41 +20,45 @@ import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.MethodDescriptor;
|
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
class FastVirtualCallConsumer implements DependencyConsumer {
|
class FastVirtualCallConsumer implements DependencyConsumer {
|
||||||
private final DependencyNode node;
|
private final DependencyNode node;
|
||||||
private final MethodDescriptor methodDesc;
|
private final MethodReference methodRef;
|
||||||
private final DependencyAnalyzer analyzer;
|
private final DependencyAnalyzer analyzer;
|
||||||
private final Map<MethodReference, CallLocation> callLocations = new LinkedHashMap<>();
|
private final Map<MethodReference, CallLocation> callLocations = new LinkedHashMap<>();
|
||||||
private final Set<MethodDependency> methods = new LinkedHashSet<>(100, 0.5f);
|
private final Set<MethodDependency> 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.node = node;
|
||||||
this.methodDesc = methodDesc;
|
this.methodRef = methodRef;
|
||||||
this.analyzer = analyzer;
|
this.analyzer = analyzer;
|
||||||
|
callSite = analyzer.callGraph.getNode(methodRef).getVirtualCallSite();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void consume(DependencyType type) {
|
public void consume(DependencyType type) {
|
||||||
String className = type.getName();
|
String className = type.getName();
|
||||||
if (DependencyAnalyzer.shouldLog) {
|
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);
|
+ "Target class is " + className);
|
||||||
}
|
}
|
||||||
if (className.startsWith("[")) {
|
if (className.startsWith("[")) {
|
||||||
className = "java.lang.Object";
|
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)) {
|
if (!methods.add(methodDep)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefaultCallGraphNode calledMethodNode = analyzer.callGraph.getNode(methodDep.getReference());
|
||||||
|
callSite.calledMethods.add(calledMethodNode);
|
||||||
|
calledMethodNode.addCaller(callSite);
|
||||||
|
|
||||||
for (CallLocation location : callLocations.values()) {
|
for (CallLocation location : callLocations.values()) {
|
||||||
methodDep.addLocation(location);
|
methodDep.addLocation(location, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!methodDep.isMissing()) {
|
if (!methodDep.isMissing()) {
|
||||||
|
@ -64,8 +68,13 @@ class FastVirtualCallConsumer implements DependencyConsumer {
|
||||||
|
|
||||||
void addLocation(CallLocation location) {
|
void addLocation(CallLocation location) {
|
||||||
if (callLocations.putIfAbsent(location.getMethod(), location) == null) {
|
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) {
|
for (MethodDependency method : methods) {
|
||||||
method.addLocation(location);
|
method.addLocation(location, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ import java.util.ArrayList;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.callgraph.DefaultCallGraphNode;
|
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.FieldReader;
|
import org.teavm.model.FieldReader;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
|
|
|
@ -20,7 +20,6 @@ import java.util.Arrays;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.callgraph.DefaultCallGraphNode;
|
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.MethodHolder;
|
import org.teavm.model.MethodHolder;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
|
@ -111,12 +110,21 @@ public class MethodDependency implements MethodDependencyInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodDependency addLocation(CallLocation location) {
|
public MethodDependency addLocation(CallLocation location) {
|
||||||
|
return addLocation(location, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodDependency addLocation(CallLocation location, boolean addCallSite) {
|
||||||
DefaultCallGraphNode node = dependencyAnalyzer.callGraph.getNode(location.getMethod());
|
DefaultCallGraphNode node = dependencyAnalyzer.callGraph.getNode(location.getMethod());
|
||||||
if (locations == null) {
|
if (locations == null) {
|
||||||
locations = new LinkedHashSet<>();
|
locations = new LinkedHashSet<>();
|
||||||
}
|
}
|
||||||
if (locations.add(location)) {
|
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) {
|
if (locationListeners != null) {
|
||||||
for (LocationListener listener : locationListeners.toArray(new LocationListener[0])) {
|
for (LocationListener listener : locationListeners.toArray(new LocationListener[0])) {
|
||||||
listener.locationAdded(location);
|
listener.locationAdded(location);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2017 Alexey Andreev.
|
* Copyright 2019 Alexey Andreev.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.teavm.callgraph;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
|
@ -36,9 +36,11 @@ class SerializableCallGraph implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class CallSite implements Serializable {
|
static class CallSite implements Serializable {
|
||||||
TextLocation location;
|
MethodReference method;
|
||||||
int callee;
|
boolean virtual;
|
||||||
int caller;
|
Location[] locations;
|
||||||
|
int[] calledMethods;
|
||||||
|
int[] callers;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class FieldAccess implements Serializable {
|
static class FieldAccess implements Serializable {
|
||||||
|
@ -46,4 +48,9 @@ class SerializableCallGraph implements Serializable {
|
||||||
int callee;
|
int callee;
|
||||||
FieldReference field;
|
FieldReference field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class Location {
|
||||||
|
TextLocation value;
|
||||||
|
int caller;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -62,7 +62,6 @@ class VirtualCallConsumer implements DependencyConsumer {
|
||||||
}
|
}
|
||||||
if (className.startsWith("[")) {
|
if (className.startsWith("[")) {
|
||||||
className = "java.lang.Object";
|
className = "java.lang.Object";
|
||||||
type = analyzer.getType(className);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodDependency methodDep = analyzer.linkMethod(className, methodDesc);
|
MethodDependency methodDep = analyzer.linkMethod(className, methodDesc);
|
||||||
|
|
|
@ -46,7 +46,6 @@ public class AsyncMethodFinder {
|
||||||
private Map<MethodReference, Boolean> asyncFamilyMethods = new HashMap<>();
|
private Map<MethodReference, Boolean> asyncFamilyMethods = new HashMap<>();
|
||||||
private Set<MethodReference> readonlyAsyncMethods = Collections.unmodifiableSet(asyncMethods);
|
private Set<MethodReference> readonlyAsyncMethods = Collections.unmodifiableSet(asyncMethods);
|
||||||
private Set<MethodReference> readonlyAsyncFamilyMethods = Collections.unmodifiableSet(asyncFamilyMethods.keySet());
|
private Set<MethodReference> readonlyAsyncFamilyMethods = Collections.unmodifiableSet(asyncFamilyMethods.keySet());
|
||||||
private Map<MethodReference, Set<MethodReference>> overiddenMethodsCache = new HashMap<>();
|
|
||||||
private CallGraph callGraph;
|
private CallGraph callGraph;
|
||||||
private Diagnostics diagnostics;
|
private Diagnostics diagnostics;
|
||||||
private ListableClassReaderSource classSource;
|
private ListableClassReaderSource classSource;
|
||||||
|
@ -178,8 +177,9 @@ public class AsyncMethodFinder {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (CallSite callSite : node.getCallerCallSites()) {
|
for (CallSite callSite : node.getCallerCallSites()) {
|
||||||
MethodReference nextMethod = callSite.getCaller().getMethod();
|
for (CallGraphNode caller : callSite.getCallers()) {
|
||||||
add(nextMethod, new CallStack(nextMethod, stack));
|
add(caller.getMethod(), new CallStack(caller.getMethod(), stack));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
private static final MethodDescriptor MAIN_METHOD_DESC = new MethodDescriptor("main",
|
private static final MethodDescriptor MAIN_METHOD_DESC = new MethodDescriptor("main",
|
||||||
ValueType.arrayOf(ValueType.object("java.lang.String")), ValueType.VOID);
|
ValueType.arrayOf(ValueType.object("java.lang.String")), ValueType.VOID);
|
||||||
|
|
||||||
private final ClassReaderSource classSource;
|
|
||||||
private final DependencyAnalyzer dependencyAnalyzer;
|
private final DependencyAnalyzer dependencyAnalyzer;
|
||||||
private final AccumulationDiagnostics diagnostics = new AccumulationDiagnostics();
|
private final AccumulationDiagnostics diagnostics = new AccumulationDiagnostics();
|
||||||
private final ClassLoader classLoader;
|
private final ClassLoader classLoader;
|
||||||
|
@ -155,9 +154,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
|
|
||||||
TeaVM(TeaVMBuilder builder) {
|
TeaVM(TeaVMBuilder builder) {
|
||||||
target = builder.target;
|
target = builder.target;
|
||||||
classSource = builder.classSource;
|
|
||||||
classLoader = builder.classLoader;
|
classLoader = builder.classLoader;
|
||||||
dependencyAnalyzer = builder.dependencyAnalyzerFactory.create(this.classSource, classLoader,
|
dependencyAnalyzer = builder.dependencyAnalyzerFactory.create(builder.classSource, classLoader,
|
||||||
this, diagnostics, builder.referenceCache);
|
this, diagnostics, builder.referenceCache);
|
||||||
progressListener = new TeaVMProgressListener() {
|
progressListener = new TeaVMProgressListener() {
|
||||||
@Override public TeaVMProgressFeedback progressReached(int progress) {
|
@Override public TeaVMProgressFeedback progressReached(int progress) {
|
||||||
|
@ -313,21 +311,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
preservedClasses.add(className);
|
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() {
|
public ClassReaderSource getDependencyClassSource() {
|
||||||
return dependencyAnalyzer.getClassSource();
|
return dependencyAnalyzer.getClassSource();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.tooling;
|
package org.teavm.tooling;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import org.teavm.callgraph.CallGraph;
|
import org.teavm.callgraph.CallGraph;
|
||||||
import org.teavm.callgraph.CallGraphNode;
|
import org.teavm.callgraph.CallGraphNode;
|
||||||
|
@ -70,12 +71,33 @@ public final class TeaVMProblemRenderer {
|
||||||
}
|
}
|
||||||
CallSite callSite = callSites.next();
|
CallSite callSite = callSites.next();
|
||||||
sb.append("\n at ");
|
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) {
|
public static void renderCallLocation(MethodReference method, TextLocation location, StringBuilder sb) {
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
sb.append(method.getClassName() + "." + method.getName());
|
sb.append(method.getClassName() + "." + method.getName());
|
||||||
|
|
Loading…
Reference in New Issue
Block a user