mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-09 00:14:10 -08:00
Improve performance of dependency analysis by filtering out propagated types that don't match types of method parameters and return values
This commit is contained in:
parent
d811e7edbb
commit
edfbe01a7f
|
@ -31,7 +31,6 @@ import java.util.Set;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.teavm.callgraph.CallGraph;
|
import org.teavm.callgraph.CallGraph;
|
||||||
import org.teavm.callgraph.DefaultCallGraph;
|
import org.teavm.callgraph.DefaultCallGraph;
|
||||||
import org.teavm.callgraph.DefaultCallGraphNode;
|
|
||||||
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;
|
||||||
|
@ -52,7 +51,6 @@ import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
import org.teavm.model.ReferenceCache;
|
import org.teavm.model.ReferenceCache;
|
||||||
import org.teavm.model.TextLocation;
|
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.optimization.UnreachableBasicBlockEliminator;
|
import org.teavm.model.optimization.UnreachableBasicBlockEliminator;
|
||||||
import org.teavm.model.util.ModelUtils;
|
import org.teavm.model.util.ModelUtils;
|
||||||
|
@ -62,6 +60,8 @@ import org.teavm.parsing.Parser;
|
||||||
public class DependencyChecker implements DependencyInfo {
|
public class DependencyChecker implements DependencyInfo {
|
||||||
private static final int PROPAGATION_STACK_THRESHOLD = 50;
|
private static final int PROPAGATION_STACK_THRESHOLD = 50;
|
||||||
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
|
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
|
||||||
|
static final boolean shouldTag = System.getProperty("org.teavm.tagDependencies", "false").equals("true")
|
||||||
|
|| shouldLog;
|
||||||
private int classNameSuffix;
|
private int classNameSuffix;
|
||||||
private DependencyClassSource classSource;
|
private DependencyClassSource classSource;
|
||||||
private ClassLoader classLoader;
|
private ClassLoader classLoader;
|
||||||
|
@ -141,7 +141,11 @@ public class DependencyChecker implements DependencyInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DependencyNode createNode() {
|
public DependencyNode createNode() {
|
||||||
return new DependencyNode(this);
|
return createNode(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DependencyNode createNode(ValueType typeFilter) {
|
||||||
|
return new DependencyNode(this, typeFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -322,12 +326,7 @@ public class DependencyChecker implements DependencyInfo {
|
||||||
}
|
}
|
||||||
ClassDependency dep = classCache.map(className);
|
ClassDependency dep = classCache.map(className);
|
||||||
boolean added = true;
|
boolean added = true;
|
||||||
if (callLocation != null && callLocation.getMethod() != null) {
|
if (callLocation == null || callLocation.getMethod() == null) {
|
||||||
DefaultCallGraphNode callGraphNode = callGraph.getNode(callLocation.getMethod());
|
|
||||||
if (!addClassAccess(callGraphNode, className, callLocation.getSourceLocation())) {
|
|
||||||
added = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
added = classesAddedByRoot.add(className);
|
added = classesAddedByRoot.add(className);
|
||||||
}
|
}
|
||||||
if (!dep.isMissing() && added) {
|
if (!dep.isMissing() && added) {
|
||||||
|
@ -336,24 +335,17 @@ public class DependencyChecker implements DependencyInfo {
|
||||||
listener.classReached(agent, className, callLocation);
|
listener.classReached(agent, className, callLocation);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
return dep;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean addClassAccess(DefaultCallGraphNode node, String className, TextLocation loc) {
|
ClassReader cls = dep.getClassReader();
|
||||||
if (!node.addClassAccess(className, loc)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ClassReader cls = classSource.get(className);
|
|
||||||
if (cls != null) {
|
|
||||||
if (cls.getParent() != null) {
|
if (cls.getParent() != null) {
|
||||||
addClassAccess(node, cls.getParent(), loc);
|
linkClass(cls.getParent(), callLocation);
|
||||||
}
|
}
|
||||||
for (String iface : cls.getInterfaces()) {
|
for (String iface : cls.getInterfaces()) {
|
||||||
addClassAccess(node, iface, loc);
|
linkClass(iface, callLocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
return dep;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClassDependency createClassDependency(String className) {
|
private ClassDependency createClassDependency(String className) {
|
||||||
|
@ -414,26 +406,33 @@ public class DependencyChecker implements DependencyInfo {
|
||||||
ValueType[] arguments = methodRef.getParameterTypes();
|
ValueType[] arguments = methodRef.getParameterTypes();
|
||||||
int paramCount = arguments.length + 1;
|
int paramCount = arguments.length + 1;
|
||||||
DependencyNode[] parameterNodes = new DependencyNode[arguments.length + 1];
|
DependencyNode[] parameterNodes = new DependencyNode[arguments.length + 1];
|
||||||
for (int i = 0; i < parameterNodes.length; ++i) {
|
|
||||||
parameterNodes[i] = createNode();
|
parameterNodes[0] = createNode(ValueType.object(methodRef.getClassName()));
|
||||||
parameterNodes[i].method = methodRef;
|
parameterNodes[0].method = methodRef;
|
||||||
if (shouldLog) {
|
if (shouldTag) {
|
||||||
|
parameterNodes[0].setTag(methodRef + ":0");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < arguments.length; ++i) {
|
||||||
|
parameterNodes[i + 1] = createNode(arguments[i]);
|
||||||
|
parameterNodes[i + 1].method = methodRef;
|
||||||
|
if (shouldTag) {
|
||||||
parameterNodes[i].setTag(methodRef + ":" + i);
|
parameterNodes[i].setTag(methodRef + ":" + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DependencyNode resultNode;
|
DependencyNode resultNode;
|
||||||
if (methodRef.getDescriptor().getResultType() == ValueType.VOID) {
|
if (methodRef.getDescriptor().getResultType() == ValueType.VOID) {
|
||||||
resultNode = null;
|
resultNode = null;
|
||||||
} else {
|
} else {
|
||||||
resultNode = createNode();
|
resultNode = createNode();
|
||||||
resultNode.method = methodRef;
|
resultNode.method = methodRef;
|
||||||
if (shouldLog) {
|
if (shouldTag) {
|
||||||
resultNode.setTag(methodRef + ":RESULT");
|
resultNode.setTag(methodRef + ":RESULT");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DependencyNode thrown = createNode();
|
DependencyNode thrown = createNode();
|
||||||
thrown.method = methodRef;
|
thrown.method = methodRef;
|
||||||
if (shouldLog) {
|
if (shouldTag) {
|
||||||
thrown.setTag(methodRef + ":THROWN");
|
thrown.setTag(methodRef + ":THROWN");
|
||||||
}
|
}
|
||||||
MethodDependency dep = new MethodDependency(this, parameterNodes, paramCount, resultNode, thrown,
|
MethodDependency dep = new MethodDependency(this, parameterNodes, paramCount, resultNode, thrown,
|
||||||
|
@ -504,8 +503,8 @@ public class DependencyChecker implements DependencyInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
private FieldDependency createFieldNode(FieldReference fieldRef, FieldReader field) {
|
private FieldDependency createFieldNode(FieldReference fieldRef, FieldReader field) {
|
||||||
DependencyNode node = createNode();
|
DependencyNode node = createNode(field != null ? field.getType() : null);
|
||||||
if (shouldLog) {
|
if (shouldTag) {
|
||||||
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
|
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
|
||||||
}
|
}
|
||||||
FieldDependency dep = new FieldDependency(node, field, fieldRef);
|
FieldDependency dep = new FieldDependency(node, field, fieldRef);
|
||||||
|
|
|
@ -112,7 +112,7 @@ class DependencyGraphBuilder {
|
||||||
for (int i = dep.getVariableCount(); i < nodeClasses.length; ++i) {
|
for (int i = dep.getVariableCount(); i < nodeClasses.length; ++i) {
|
||||||
nodeClasses[i] = dependencyChecker.createNode();
|
nodeClasses[i] = dependencyChecker.createNode();
|
||||||
nodeClasses[i].method = ref;
|
nodeClasses[i].method = ref;
|
||||||
if (DependencyChecker.shouldLog) {
|
if (DependencyChecker.shouldTag) {
|
||||||
nodeClasses[i].setTag(dep.getMethod().getReference() + ":" + i);
|
nodeClasses[i].setTag(dep.getMethod().getReference() + ":" + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,13 +274,13 @@ class DependencyGraphBuilder {
|
||||||
return new ExceptionConsumer(dependencyChecker, exceptions, vars, methodDep);
|
return new ExceptionConsumer(dependencyChecker, exceptions, vars, methodDep);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ExceptionConsumer implements DependencyConsumer {
|
static class ExceptionConsumer implements DependencyConsumer {
|
||||||
private DependencyChecker checker;
|
private DependencyChecker checker;
|
||||||
private ClassReader[] exceptions;
|
private ClassReader[] exceptions;
|
||||||
private DependencyNode[] vars;
|
private DependencyNode[] vars;
|
||||||
private MethodDependency method;
|
private MethodDependency method;
|
||||||
|
|
||||||
public ExceptionConsumer(DependencyChecker checker, ClassReader[] exceptions, DependencyNode[] vars,
|
ExceptionConsumer(DependencyChecker checker, ClassReader[] exceptions, DependencyNode[] vars,
|
||||||
MethodDependency method) {
|
MethodDependency method) {
|
||||||
this.checker = checker;
|
this.checker = checker;
|
||||||
this.exceptions = exceptions;
|
this.exceptions = exceptions;
|
||||||
|
@ -654,6 +654,11 @@ class DependencyGraphBuilder {
|
||||||
receiver != null ? nodes[receiver.getIndex()] : null, caller, currentLocation,
|
receiver != null ? nodes[receiver.getIndex()] : null, caller, currentLocation,
|
||||||
currentExceptionConsumer);
|
currentExceptionConsumer);
|
||||||
nodes[instance.getIndex()].addConsumer(listener);
|
nodes[instance.getIndex()].addConsumer(listener);
|
||||||
|
|
||||||
|
dependencyChecker.getClassSource().overriddenMethods(method).forEach(methodImpl -> {
|
||||||
|
CallLocation callLocation = new CallLocation(caller.getMethod(), currentLocation);
|
||||||
|
dependencyChecker.linkMethod(methodImpl.getReference(), callLocation);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.dependency;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
public class DependencyNode implements ValueDependencyInfo {
|
public class DependencyNode implements ValueDependencyInfo {
|
||||||
private static final int SMALL_TYPES_THRESHOLD = 6;
|
private static final int SMALL_TYPES_THRESHOLD = 6;
|
||||||
|
@ -31,14 +32,17 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
private int degree;
|
private int degree;
|
||||||
boolean locked;
|
boolean locked;
|
||||||
MethodReference method;
|
MethodReference method;
|
||||||
|
private ValueType typeFilter;
|
||||||
|
private SuperClassFilter cachedTypeFilter;
|
||||||
|
|
||||||
DependencyNode(DependencyChecker dependencyChecker) {
|
DependencyNode(DependencyChecker dependencyChecker, ValueType typeFilter) {
|
||||||
this(dependencyChecker, 0);
|
this(dependencyChecker, typeFilter, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DependencyNode(DependencyChecker dependencyChecker, int degree) {
|
private DependencyNode(DependencyChecker dependencyChecker, ValueType typeFilter, int degree) {
|
||||||
this.dependencyChecker = dependencyChecker;
|
this.dependencyChecker = dependencyChecker;
|
||||||
this.degree = degree;
|
this.degree = degree;
|
||||||
|
this.typeFilter = typeFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean addType(DependencyType type) {
|
private boolean addType(DependencyType type) {
|
||||||
|
@ -88,7 +92,7 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
if (degree > 2) {
|
if (degree > 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (addType(type)) {
|
if (addType(type) && filter(type)) {
|
||||||
if (DependencyChecker.shouldLog) {
|
if (DependencyChecker.shouldLog) {
|
||||||
System.out.println(tag + " -> " + type.getName());
|
System.out.println(tag + " -> " + type.getName());
|
||||||
}
|
}
|
||||||
|
@ -118,7 +122,7 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (int i = 0; i < newTypes.length; ++i) {
|
for (int i = 0; i < newTypes.length; ++i) {
|
||||||
DependencyType type = newTypes[i];
|
DependencyType type = newTypes[i];
|
||||||
if (addType(type)) {
|
if (addType(type) && filter(type)) {
|
||||||
newTypes[j++] = type;
|
newTypes[j++] = type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,6 +158,24 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean filter(DependencyType type) {
|
||||||
|
if (typeFilter == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cachedTypeFilter == null) {
|
||||||
|
String superClass;
|
||||||
|
if (typeFilter instanceof ValueType.Object) {
|
||||||
|
superClass = ((ValueType.Object) typeFilter).getClassName();
|
||||||
|
} else {
|
||||||
|
superClass = "java.lang.Object";
|
||||||
|
}
|
||||||
|
cachedTypeFilter = dependencyChecker.getSuperClassFilter(superClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedTypeFilter.match(type);
|
||||||
|
}
|
||||||
|
|
||||||
public void addConsumer(DependencyConsumer consumer) {
|
public void addConsumer(DependencyConsumer consumer) {
|
||||||
if (followers == null) {
|
if (followers == null) {
|
||||||
followers = new ArrayList<>(1);
|
followers = new ArrayList<>(1);
|
||||||
|
@ -163,7 +185,7 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
}
|
}
|
||||||
followers.add(consumer);
|
followers.add(consumer);
|
||||||
|
|
||||||
propagateTypes(consumer, null);
|
propagateTypes(consumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(DependencyNode node, DependencyTypeFilter filter) {
|
public void connect(DependencyNode node, DependencyTypeFilter filter) {
|
||||||
|
@ -190,30 +212,42 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
System.out.println("Connecting " + tag + " to " + node.tag);
|
System.out.println("Connecting " + tag + " to " + node.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
propagateTypes(transition, filter);
|
propagateTypes(transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void propagateTypes(DependencyConsumer transition, DependencyTypeFilter filter) {
|
private void propagateTypes(DependencyConsumer transition) {
|
||||||
if (this.types != null) {
|
if (this.types != null) {
|
||||||
List<DependencyType> types = new ArrayList<>();
|
DependencyType[] types = new DependencyType[this.types.cardinality()];
|
||||||
|
int j = 0;
|
||||||
for (int index = this.types.nextSetBit(0); index >= 0; index = this.types.nextSetBit(index + 1)) {
|
for (int index = this.types.nextSetBit(0); index >= 0; index = this.types.nextSetBit(index + 1)) {
|
||||||
DependencyType type = dependencyChecker.types.get(index);
|
DependencyType type = dependencyChecker.types.get(index);
|
||||||
if (filter == null || filter.match(type)) {
|
types[j++] = type;
|
||||||
types.add(type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dependencyChecker.schedulePropagation(transition, types.toArray(new DependencyType[types.size()]));
|
dependencyChecker.schedulePropagation(transition, types);
|
||||||
} else if (this.smallTypes != null) {
|
} else if (this.smallTypes != null) {
|
||||||
DependencyType[] types = new DependencyType[smallTypes.length];
|
DependencyType[] types = new DependencyType[smallTypes.length];
|
||||||
int j = 0;
|
|
||||||
for (int i = 0; i < types.length; ++i) {
|
for (int i = 0; i < types.length; ++i) {
|
||||||
DependencyType type = dependencyChecker.types.get(smallTypes[i]);
|
DependencyType type = dependencyChecker.types.get(smallTypes[i]);
|
||||||
if (filter == null || filter.match(type)) {
|
types[i] = type;
|
||||||
types[j++] = type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (j < types.length) {
|
dependencyChecker.schedulePropagation(transition, types);
|
||||||
types = Arrays.copyOf(types, j);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void propagateTypes(DependencyNodeToNodeTransition transition) {
|
||||||
|
if (this.types != null) {
|
||||||
|
DependencyType[] types = new DependencyType[this.types.cardinality()];
|
||||||
|
int j = 0;
|
||||||
|
for (int index = this.types.nextSetBit(0); index >= 0; index = this.types.nextSetBit(index + 1)) {
|
||||||
|
DependencyType type = dependencyChecker.types.get(index);
|
||||||
|
types[j++] = type;
|
||||||
|
}
|
||||||
|
dependencyChecker.schedulePropagation(transition, types);
|
||||||
|
} else if (this.smallTypes != null) {
|
||||||
|
DependencyType[] types = new DependencyType[smallTypes.length];
|
||||||
|
for (int i = 0; i < types.length; ++i) {
|
||||||
|
DependencyType type = dependencyChecker.types.get(smallTypes[i]);
|
||||||
|
types[i] = type;
|
||||||
}
|
}
|
||||||
dependencyChecker.schedulePropagation(transition, types);
|
dependencyChecker.schedulePropagation(transition, types);
|
||||||
}
|
}
|
||||||
|
@ -226,8 +260,11 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
@Override
|
@Override
|
||||||
public DependencyNode getArrayItem() {
|
public DependencyNode getArrayItem() {
|
||||||
if (arrayItemNode == null) {
|
if (arrayItemNode == null) {
|
||||||
arrayItemNode = new DependencyNode(dependencyChecker, degree + 1);
|
ValueType itemTypeFilter = typeFilter instanceof ValueType.Array
|
||||||
if (DependencyChecker.shouldLog) {
|
? ((ValueType.Array) typeFilter).getItemType()
|
||||||
|
: null;
|
||||||
|
arrayItemNode = new DependencyNode(dependencyChecker, itemTypeFilter, degree + 1);
|
||||||
|
if (DependencyChecker.shouldTag) {
|
||||||
arrayItemNode.tag = tag + "[";
|
arrayItemNode.tag = tag + "[";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,9 +274,9 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
@Override
|
@Override
|
||||||
public DependencyNode getClassValueNode() {
|
public DependencyNode getClassValueNode() {
|
||||||
if (classValueNode == null) {
|
if (classValueNode == null) {
|
||||||
classValueNode = new DependencyNode(dependencyChecker, degree);
|
classValueNode = new DependencyNode(dependencyChecker, null, degree);
|
||||||
classValueNode.classValueNode = classValueNode;
|
classValueNode.classValueNode = classValueNode;
|
||||||
if (DependencyChecker.shouldLog) {
|
if (DependencyChecker.shouldTag) {
|
||||||
classValueNode.tag = tag + "@";
|
classValueNode.tag = tag + "@";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,19 +309,33 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
public String[] getTypes() {
|
public String[] getTypes() {
|
||||||
if (smallTypes != null) {
|
if (smallTypes != null) {
|
||||||
String[] result = new String[smallTypes.length];
|
String[] result = new String[smallTypes.length];
|
||||||
|
int j = 0;
|
||||||
for (int i = 0; i < result.length; ++i) {
|
for (int i = 0; i < result.length; ++i) {
|
||||||
result[i] = dependencyChecker.types.get(smallTypes[i]).getName();
|
DependencyType type = dependencyChecker.types.get(smallTypes[i]);
|
||||||
|
if (filter(type)) {
|
||||||
|
result[j++] = type.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j < result.length) {
|
||||||
|
result = Arrays.copyOf(result, j);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (types == null) {
|
if (types == null) {
|
||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
List<String> result = new ArrayList<>();
|
String[] result = new String[types.cardinality()];
|
||||||
|
int j = 0;
|
||||||
for (int index = types.nextSetBit(0); index >= 0; index = types.nextSetBit(index + 1)) {
|
for (int index = types.nextSetBit(0); index >= 0; index = types.nextSetBit(index + 1)) {
|
||||||
result.add(dependencyChecker.types.get(index).getName());
|
DependencyType type = dependencyChecker.types.get(index);
|
||||||
|
if (filter(type)) {
|
||||||
|
result[j++] = type.getName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result.toArray(new String[result.size()]);
|
if (j < result.length) {
|
||||||
|
result = Arrays.copyOf(result, j);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTag() {
|
public String getTag() {
|
||||||
|
|
|
@ -15,24 +15,15 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.dependency;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import org.teavm.model.BasicBlock;
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.BasicBlockReader;
|
|
||||||
import org.teavm.model.ClassHolder;
|
import org.teavm.model.ClassHolder;
|
||||||
import org.teavm.model.ClassReader;
|
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
import org.teavm.model.FieldHolder;
|
import org.teavm.model.FieldHolder;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.Instruction;
|
import org.teavm.model.Instruction;
|
||||||
import org.teavm.model.MethodHolder;
|
import org.teavm.model.MethodHolder;
|
||||||
import org.teavm.model.MethodReader;
|
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
import org.teavm.model.ProgramReader;
|
|
||||||
import org.teavm.model.VariableReader;
|
|
||||||
import org.teavm.model.instructions.AbstractInstructionReader;
|
|
||||||
import org.teavm.model.instructions.GetFieldInstruction;
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
import org.teavm.model.instructions.InitClassInstruction;
|
import org.teavm.model.instructions.InitClassInstruction;
|
||||||
import org.teavm.model.instructions.InvocationType;
|
import org.teavm.model.instructions.InvocationType;
|
||||||
|
@ -40,47 +31,12 @@ import org.teavm.model.instructions.InvokeInstruction;
|
||||||
import org.teavm.model.instructions.PutFieldInstruction;
|
import org.teavm.model.instructions.PutFieldInstruction;
|
||||||
|
|
||||||
public class Linker {
|
public class Linker {
|
||||||
private Set<MethodReference> methodsToPreserve = new HashSet<>();
|
|
||||||
private Set<String> additionalClasses = new HashSet<>();
|
|
||||||
|
|
||||||
public void prepare(DependencyInfo dependency, ClassReader cls) {
|
|
||||||
for (MethodReader method : cls.getMethods().toArray(new MethodReader[0])) {
|
|
||||||
MethodReference methodRef = new MethodReference(cls.getName(), method.getDescriptor());
|
|
||||||
MethodDependencyInfo methodDep = dependency.getMethod(methodRef);
|
|
||||||
if (methodDep != null && method.getProgram() != null) {
|
|
||||||
collectMethodsToPreserve(method.getProgram());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void collectMethodsToPreserve(ProgramReader program) {
|
|
||||||
for (BasicBlockReader block : program.getBasicBlocks()) {
|
|
||||||
block.readAllInstructions(new AbstractInstructionReader() {
|
|
||||||
@Override
|
|
||||||
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
|
|
||||||
List<? extends VariableReader> arguments, InvocationType type) {
|
|
||||||
methodsToPreserve.add(method);
|
|
||||||
additionalClasses.add(method.getClassName());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getAdditionalClasses() {
|
|
||||||
return additionalClasses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void link(DependencyInfo dependency, ClassHolder cls) {
|
public void link(DependencyInfo dependency, ClassHolder cls) {
|
||||||
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
|
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
|
||||||
MethodReference methodRef = method.getReference();
|
MethodReference methodRef = method.getReference();
|
||||||
MethodDependencyInfo methodDep = dependency.getMethod(methodRef);
|
MethodDependencyInfo methodDep = dependency.getMethod(methodRef);
|
||||||
if (methodDep == null) {
|
if (methodDep == null) {
|
||||||
if (methodsToPreserve.contains(methodRef)) {
|
cls.removeMethod(method);
|
||||||
method.getModifiers().add(ElementModifier.ABSTRACT);
|
|
||||||
method.setProgram(null);
|
|
||||||
} else {
|
|
||||||
cls.removeMethod(method);
|
|
||||||
}
|
|
||||||
} else if (!methodDep.isUsed()) {
|
} else if (!methodDep.isUsed()) {
|
||||||
method.getModifiers().add(ElementModifier.ABSTRACT);
|
method.getModifiers().add(ElementModifier.ABSTRACT);
|
||||||
method.setProgram(null);
|
method.setProgram(null);
|
||||||
|
|
|
@ -21,9 +21,60 @@ import org.teavm.common.Mapper;
|
||||||
import org.teavm.interop.Remove;
|
import org.teavm.interop.Remove;
|
||||||
import org.teavm.interop.Rename;
|
import org.teavm.interop.Rename;
|
||||||
import org.teavm.interop.Superclass;
|
import org.teavm.interop.Superclass;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.AnnotationContainer;
|
||||||
import org.teavm.model.instructions.*;
|
import org.teavm.model.AnnotationHolder;
|
||||||
import org.teavm.model.util.ModelUtils;
|
import org.teavm.model.AnnotationValue;
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
|
import org.teavm.model.FieldHolder;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.InvokeDynamicInstruction;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
|
import org.teavm.model.MethodHandle;
|
||||||
|
import org.teavm.model.MethodHolder;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.RuntimeConstant;
|
||||||
|
import org.teavm.model.TryCatchBlock;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.instructions.ArrayLengthInstruction;
|
||||||
|
import org.teavm.model.instructions.AssignInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryBranchingInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryInstruction;
|
||||||
|
import org.teavm.model.instructions.BranchingInstruction;
|
||||||
|
import org.teavm.model.instructions.CastInstruction;
|
||||||
|
import org.teavm.model.instructions.CastIntegerInstruction;
|
||||||
|
import org.teavm.model.instructions.CastNumberInstruction;
|
||||||
|
import org.teavm.model.instructions.ClassConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||||
|
import org.teavm.model.instructions.ConstructArrayInstruction;
|
||||||
|
import org.teavm.model.instructions.ConstructInstruction;
|
||||||
|
import org.teavm.model.instructions.ConstructMultiArrayInstruction;
|
||||||
|
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.EmptyInstruction;
|
||||||
|
import org.teavm.model.instructions.ExitInstruction;
|
||||||
|
import org.teavm.model.instructions.FloatConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.GetElementInstruction;
|
||||||
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.InitClassInstruction;
|
||||||
|
import org.teavm.model.instructions.InstructionVisitor;
|
||||||
|
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
import org.teavm.model.instructions.IsInstanceInstruction;
|
||||||
|
import org.teavm.model.instructions.JumpInstruction;
|
||||||
|
import org.teavm.model.instructions.LongConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.MonitorEnterInstruction;
|
||||||
|
import org.teavm.model.instructions.MonitorExitInstruction;
|
||||||
|
import org.teavm.model.instructions.NegateInstruction;
|
||||||
|
import org.teavm.model.instructions.NullCheckInstruction;
|
||||||
|
import org.teavm.model.instructions.NullConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.PutElementInstruction;
|
||||||
|
import org.teavm.model.instructions.PutFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.RaiseInstruction;
|
||||||
|
import org.teavm.model.instructions.StringConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.SwitchInstruction;
|
||||||
|
import org.teavm.model.instructions.UnwrapArrayInstruction;
|
||||||
|
|
||||||
public class ClassRefsRenamer implements InstructionVisitor {
|
public class ClassRefsRenamer implements InstructionVisitor {
|
||||||
private Mapper<String, String> classNameMapper;
|
private Mapper<String, String> classNameMapper;
|
||||||
|
@ -55,7 +106,7 @@ public class ClassRefsRenamer implements InstructionVisitor {
|
||||||
renamedCls.addMethod(rename(method));
|
renamedCls.addMethod(rename(method));
|
||||||
}
|
}
|
||||||
for (FieldHolder field : cls.getFields().toArray(new FieldHolder[0])) {
|
for (FieldHolder field : cls.getFields().toArray(new FieldHolder[0])) {
|
||||||
renamedCls.addField(ModelUtils.copyField(field));
|
renamedCls.addField(rename(field));
|
||||||
}
|
}
|
||||||
if (cls.getOwnerName() != null) {
|
if (cls.getOwnerName() != null) {
|
||||||
renamedCls.setOwnerName(classNameMapper.map(cls.getOwnerName()));
|
renamedCls.setOwnerName(classNameMapper.map(cls.getOwnerName()));
|
||||||
|
@ -89,6 +140,16 @@ public class ClassRefsRenamer implements InstructionVisitor {
|
||||||
return renamedMethod;
|
return renamedMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FieldHolder rename(FieldHolder field) {
|
||||||
|
FieldHolder renamedField = new FieldHolder(field.getName());
|
||||||
|
renamedField.getModifiers().addAll(field.getModifiers());
|
||||||
|
renamedField.setLevel(field.getLevel());
|
||||||
|
renamedField.setType(rename(field.getType()));
|
||||||
|
renamedField.setInitialValue(field.getInitialValue());
|
||||||
|
rename(field.getAnnotations(), renamedField.getAnnotations());
|
||||||
|
return renamedField;
|
||||||
|
}
|
||||||
|
|
||||||
private ValueType rename(ValueType type) {
|
private ValueType rename(ValueType type) {
|
||||||
if (type instanceof ValueType.Array) {
|
if (type instanceof ValueType.Array) {
|
||||||
ValueType itemType = ((ValueType.Array) type).getItemType();
|
ValueType itemType = ((ValueType.Array) type).getItemType();
|
||||||
|
|
|
@ -22,12 +22,10 @@ import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.teavm.cache.NoCache;
|
import org.teavm.cache.NoCache;
|
||||||
import org.teavm.common.ServiceRepository;
|
import org.teavm.common.ServiceRepository;
|
||||||
|
@ -401,20 +399,11 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
}
|
}
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
for (String className : dependency.getReachableClasses()) {
|
|
||||||
ClassReader clsReader = dependency.getClassSource().get(className);
|
|
||||||
if (clsReader != null) {
|
|
||||||
linker.prepare(dependency, clsReader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (wasCancelled()) {
|
if (wasCancelled()) {
|
||||||
return cutClasses;
|
return cutClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> allClasses = new LinkedHashSet<>(dependency.getReachableClasses());
|
for (String className : dependency.getReachableClasses()) {
|
||||||
allClasses.addAll(linker.getAdditionalClasses());
|
|
||||||
|
|
||||||
for (String className : allClasses) {
|
|
||||||
ClassReader clsReader = dependency.getClassSource().get(className);
|
ClassReader clsReader = dependency.getClassSource().get(className);
|
||||||
if (clsReader == null) {
|
if (clsReader == null) {
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user