mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-08 07:54:11 -08:00
Speed up TeaVM compiler
This commit is contained in:
parent
fe2adc4675
commit
824cc79901
|
@ -600,7 +600,6 @@ public class ProgramIO {
|
||||||
try {
|
try {
|
||||||
output.writeByte(39);
|
output.writeByte(39);
|
||||||
output.writeShort(insn.getObjectRef().getIndex());
|
output.writeShort(insn.getObjectRef().getIndex());
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IOExceptionWrapper(e);
|
throw new IOExceptionWrapper(e);
|
||||||
}
|
}
|
||||||
|
@ -611,7 +610,6 @@ public class ProgramIO {
|
||||||
try {
|
try {
|
||||||
output.writeByte(40);
|
output.writeByte(40);
|
||||||
output.writeShort(insn.getObjectRef().getIndex());
|
output.writeShort(insn.getObjectRef().getIndex());
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IOExceptionWrapper(e);
|
throw new IOExceptionWrapper(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,14 @@ public final class GraphUtils {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int[][] findStronglyConnectedComponents(Graph graph, int[] start) {
|
||||||
|
return findStronglyConnectedComponents(graph, start, new GraphNodeFilter() {
|
||||||
|
@Override public boolean match(int node) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tarjan's algorithm
|
* Tarjan's algorithm
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,290 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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 com.carrotsearch.hppc.IntOpenHashSet;
|
||||||
|
import com.carrotsearch.hppc.IntSet;
|
||||||
|
import com.carrotsearch.hppc.ObjectIntMap;
|
||||||
|
import com.carrotsearch.hppc.ObjectIntOpenHashMap;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import org.teavm.common.*;
|
||||||
|
import org.teavm.model.*;
|
||||||
|
import org.teavm.model.instructions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public class DataFlowGraphBuilder implements InstructionReader {
|
||||||
|
private int lastIndex;
|
||||||
|
private GraphBuilder builder = new GraphBuilder();
|
||||||
|
private IntSet importantNodes = new IntOpenHashSet();
|
||||||
|
private ObjectIntMap<MethodReference> methodNodes = new ObjectIntOpenHashMap<>();
|
||||||
|
private ObjectIntMap<FieldReference> fieldNodes = new ObjectIntOpenHashMap<>();
|
||||||
|
private int[] arrayNodes;
|
||||||
|
|
||||||
|
public void important(int node) {
|
||||||
|
importantNodes.add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] buildMapping(ProgramReader program, int paramCount) {
|
||||||
|
lastIndex = program.variableCount();
|
||||||
|
arrayNodes = new int[lastIndex];
|
||||||
|
Arrays.fill(arrayNodes, -1);
|
||||||
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
|
BasicBlockReader block = program.basicBlockAt(i);
|
||||||
|
for (PhiReader phi : block.readPhis()) {
|
||||||
|
for (IncomingReader incoming : phi.readIncomings()) {
|
||||||
|
builder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block.readAllInstructions(this);
|
||||||
|
}
|
||||||
|
Graph graph = builder.build();
|
||||||
|
|
||||||
|
DisjointSet classes = new DisjointSet();
|
||||||
|
for (int i = 0; i < lastIndex; ++i) {
|
||||||
|
classes.create();
|
||||||
|
}
|
||||||
|
IntegerArray startNodes = new IntegerArray(graph.size());
|
||||||
|
for (int i = paramCount; i < graph.size(); ++i) {
|
||||||
|
if (!importantNodes.contains(i) && graph.incomingEdgesCount(i) == 1) {
|
||||||
|
classes.union(graph.incomingEdges(i)[0], i);
|
||||||
|
}
|
||||||
|
if (graph.incomingEdgesCount(i) == 0) {
|
||||||
|
startNodes.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int[][] sccs = GraphUtils.findStronglyConnectedComponents(graph, startNodes.getAll());
|
||||||
|
for (int[] scc : sccs) {
|
||||||
|
int first = scc[0];
|
||||||
|
for (int i = 1; i < scc.length; ++i) {
|
||||||
|
classes.union(first, scc[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return classes.pack(program.variableCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void location(InstructionLocation location) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void classConstant(VariableReader receiver, ValueType cst) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullConstant(VariableReader receiver) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void integerConstant(VariableReader receiver, int cst) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void longConstant(VariableReader receiver, long cst) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void floatConstant(VariableReader receiver, float cst) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doubleConstant(VariableReader receiver, double cst) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stringConstant(VariableReader receiver, String cst) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
|
||||||
|
NumericOperandType type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assign(VariableReader receiver, VariableReader assignee) {
|
||||||
|
builder.addEdge(assignee.getIndex(), receiver.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
||||||
|
builder.addEdge(value.getIndex(), receiver.getIndex());
|
||||||
|
important(receiver.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
|
||||||
|
NumericOperandType targetType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
|
||||||
|
CastIntegerDirection targetType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
|
||||||
|
BasicBlockReader alternative) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
|
||||||
|
BasicBlockReader consequent, BasicBlockReader alternative) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void jump(BasicBlockReader target) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
|
||||||
|
BasicBlockReader defaultTarget) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exit(VariableReader valueToReturn) {
|
||||||
|
if (valueToReturn != null) {
|
||||||
|
important(valueToReturn.getIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void raise(VariableReader exception) {
|
||||||
|
important(exception.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createArray(VariableReader receiver, ValueType itemType, List<? extends VariableReader> dimensions) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void create(VariableReader receiver, String type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getFieldNode(FieldReference field) {
|
||||||
|
int fieldNode = fieldNodes.getOrDefault(field, -1);
|
||||||
|
if (fieldNode < 0) {
|
||||||
|
fieldNode = lastIndex++;
|
||||||
|
fieldNodes.put(field, fieldNode);
|
||||||
|
}
|
||||||
|
important(fieldNode);
|
||||||
|
return fieldNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType) {
|
||||||
|
int fieldNode = getFieldNode(field);
|
||||||
|
builder.addEdge(fieldNode, receiver.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
|
||||||
|
int fieldNode = getFieldNode(field);
|
||||||
|
builder.addEdge(value.getIndex(), fieldNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void arrayLength(VariableReader receiver, VariableReader array) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneArray(VariableReader receiver, VariableReader array) {
|
||||||
|
important(receiver.getIndex());
|
||||||
|
builder.addEdge(array.getIndex(), receiver.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
|
||||||
|
if (elementType == ArrayElementType.OBJECT) {
|
||||||
|
builder.addEdge(array.getIndex(), receiver.getIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getArrayElementNode(int array) {
|
||||||
|
int node = arrayNodes[array];
|
||||||
|
if (node < 0) {
|
||||||
|
node = lastIndex++;
|
||||||
|
arrayNodes[array] = node;
|
||||||
|
}
|
||||||
|
important(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
|
||||||
|
builder.addEdge(getArrayElementNode(array.getIndex()), receiver.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
|
||||||
|
builder.addEdge(value.getIndex(), getArrayElementNode(array.getIndex()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMethodNode(MethodReference method) {
|
||||||
|
int methodNode = methodNodes.getOrDefault(method, -1);
|
||||||
|
if (methodNode < 0) {
|
||||||
|
methodNode = lastIndex++;
|
||||||
|
methodNodes.put(method, methodNode);
|
||||||
|
}
|
||||||
|
important(methodNode);
|
||||||
|
return methodNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
|
||||||
|
List<? extends VariableReader> arguments, InvocationType type) {
|
||||||
|
if (receiver != null) {
|
||||||
|
builder.addEdge(getMethodNode(method), receiver.getIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initClass(String className) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullCheck(VariableReader receiver, VariableReader value) {
|
||||||
|
builder.addEdge(value.getIndex(), receiver.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void monitorEnter(VariableReader objectRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void monitorExit(VariableReader objectRef) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,13 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.dependency;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.*;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Queue;
|
|
||||||
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.callgraph.DefaultCallGraphNode;
|
||||||
|
@ -202,6 +196,8 @@ public class DependencyChecker implements DependencyInfo {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<String> classesAddedByRoot = new HashSet<>();
|
||||||
|
|
||||||
public ClassDependency linkClass(String className, CallLocation callLocation) {
|
public ClassDependency linkClass(String className, CallLocation callLocation) {
|
||||||
ClassDependency dep = classCache.map(className);
|
ClassDependency dep = classCache.map(className);
|
||||||
boolean added = true;
|
boolean added = true;
|
||||||
|
@ -210,6 +206,8 @@ public class DependencyChecker implements DependencyInfo {
|
||||||
if (!addClassAccess(callGraphNode, className, callLocation.getSourceLocation())) {
|
if (!addClassAccess(callGraphNode, className, callLocation.getSourceLocation())) {
|
||||||
added = false;
|
added = false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
added = classesAddedByRoot.add(className);
|
||||||
}
|
}
|
||||||
if (!dep.isMissing() && added) {
|
if (!dep.isMissing() && added) {
|
||||||
for (DependencyListener listener : listeners) {
|
for (DependencyListener listener : listeners) {
|
||||||
|
@ -249,6 +247,8 @@ public class DependencyChecker implements DependencyInfo {
|
||||||
return dependency;
|
return dependency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<MethodReference> methodsAddedByRoot = new HashSet<>();
|
||||||
|
|
||||||
public MethodDependency linkMethod(MethodReference methodRef, CallLocation callLocation) {
|
public MethodDependency linkMethod(MethodReference methodRef, CallLocation callLocation) {
|
||||||
if (methodRef == null) {
|
if (methodRef == null) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
|
@ -262,6 +262,8 @@ public class DependencyChecker implements DependencyInfo {
|
||||||
if (callLocation != null && callLocation.getMethod() != null) {
|
if (callLocation != null && callLocation.getMethod() != null) {
|
||||||
added = callGraph.getNode(callLocation.getMethod()).addCallSite(methodRef,
|
added = callGraph.getNode(callLocation.getMethod()).addCallSite(methodRef,
|
||||||
callLocation.getSourceLocation());
|
callLocation.getSourceLocation());
|
||||||
|
} else {
|
||||||
|
added = methodsAddedByRoot.add(methodRef);
|
||||||
}
|
}
|
||||||
MethodDependency graph = methodCache.map(methodRef);
|
MethodDependency graph = methodCache.map(methodRef);
|
||||||
if (!graph.isMissing() && added) {
|
if (!graph.isMissing() && added) {
|
||||||
|
@ -393,10 +395,14 @@ public class DependencyChecker implements DependencyInfo {
|
||||||
return classCache.getCachedPreimages();
|
return classCache.getCachedPreimages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<FieldReference> fieldsAddedByRoot = new HashSet<>();
|
||||||
|
|
||||||
public FieldDependency linkField(final FieldReference fieldRef, final CallLocation location) {
|
public FieldDependency linkField(final FieldReference fieldRef, final CallLocation location) {
|
||||||
boolean added = true;
|
boolean added = true;
|
||||||
if (location != null) {
|
if (location != null) {
|
||||||
added = callGraph.getNode(location.getMethod()).addFieldAccess(fieldRef, location.getSourceLocation());
|
added = callGraph.getNode(location.getMethod()).addFieldAccess(fieldRef, location.getSourceLocation());
|
||||||
|
} else {
|
||||||
|
added = fieldsAddedByRoot.add(fieldRef);
|
||||||
}
|
}
|
||||||
FieldDependency dep = fieldCache.map(fieldRef);
|
FieldDependency dep = fieldCache.map(fieldRef);
|
||||||
if (!dep.isMissing()) {
|
if (!dep.isMissing()) {
|
||||||
|
|
|
@ -52,7 +52,15 @@ class DependencyGraphBuilder {
|
||||||
System.out.println(new ListingBuilder().buildListing(program, " "));
|
System.out.println(new ListingBuilder().buildListing(program, " "));
|
||||||
}
|
}
|
||||||
resultNode = dep.getResult();
|
resultNode = dep.getResult();
|
||||||
nodes = dep.getVariables();
|
|
||||||
|
DependencyNode[] origNodes = dep.getVariables();
|
||||||
|
int[] nodeMapping = new DataFlowGraphBuilder().buildMapping(program, dep.getParameterCount());
|
||||||
|
nodes = new DependencyNode[origNodes.length];
|
||||||
|
for (int i = 0; i < nodes.length; ++i) {
|
||||||
|
nodes[i] = origNodes[nodeMapping[i]];
|
||||||
|
}
|
||||||
|
dep.setVariables(nodes);
|
||||||
|
|
||||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
BasicBlockReader block = program.basicBlockAt(i);
|
BasicBlockReader block = program.basicBlockAt(i);
|
||||||
currentExceptionConsumer = createExceptionConsumer(dep, block);
|
currentExceptionConsumer = createExceptionConsumer(dep, block);
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.util.*;
|
||||||
public class DependencyNode implements ValueDependencyInfo {
|
public class DependencyNode implements ValueDependencyInfo {
|
||||||
private DependencyChecker dependencyChecker;
|
private DependencyChecker dependencyChecker;
|
||||||
private Set<DependencyConsumer> followers = new HashSet<>();
|
private Set<DependencyConsumer> followers = new HashSet<>();
|
||||||
private BitSet types = new BitSet();
|
private BitSet types;
|
||||||
private Map<DependencyNode, DependencyNodeToNodeTransition> transitions = new HashMap<>();
|
private Map<DependencyNode, DependencyNodeToNodeTransition> transitions = new HashMap<>();
|
||||||
private volatile String tag;
|
private volatile String tag;
|
||||||
private DependencyNode arrayItemNode;
|
private DependencyNode arrayItemNode;
|
||||||
|
@ -46,6 +46,9 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
if (degree > 2) {
|
if (degree > 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (types == null) {
|
||||||
|
types = new BitSet();
|
||||||
|
}
|
||||||
if (!types.get(type.index)) {
|
if (!types.get(type.index)) {
|
||||||
types.set(type.index);
|
types.set(type.index);
|
||||||
if (DependencyChecker.shouldLog) {
|
if (DependencyChecker.shouldLog) {
|
||||||
|
@ -65,10 +68,13 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
if (type.getDependencyChecker() != dependencyChecker) {
|
if (type.getDependencyChecker() != dependencyChecker) {
|
||||||
throw new IllegalArgumentException("The given type does not belong to the same dependency checker");
|
throw new IllegalArgumentException("The given type does not belong to the same dependency checker");
|
||||||
}
|
}
|
||||||
if (!this.types.get(type.index)) {
|
if (this.types == null || !this.types.get(type.index)) {
|
||||||
types[j++] = type;
|
types[j++] = type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.types == null) {
|
||||||
|
this.types = new BitSet();
|
||||||
|
}
|
||||||
for (int i = 0; i < j; ++i) {
|
for (int i = 0; i < j; ++i) {
|
||||||
this.types.set(types[i].index);
|
this.types.set(types[i].index);
|
||||||
if (DependencyChecker.shouldLog) {
|
if (DependencyChecker.shouldLog) {
|
||||||
|
@ -81,7 +87,7 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConsumer(DependencyConsumer consumer) {
|
public void addConsumer(DependencyConsumer consumer) {
|
||||||
if (followers.add(consumer)) {
|
if (followers.add(consumer) && this.types != null) {
|
||||||
List<DependencyType> types = new ArrayList<>();
|
List<DependencyType> types = new ArrayList<>();
|
||||||
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)) {
|
||||||
types.add(dependencyChecker.types.get(index));
|
types.add(dependencyChecker.types.get(index));
|
||||||
|
@ -91,6 +97,9 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(DependencyNode node, DependencyTypeFilter filter) {
|
public void connect(DependencyNode node, DependencyTypeFilter filter) {
|
||||||
|
if (this == node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
DependencyNodeToNodeTransition transition = new DependencyNodeToNodeTransition(this, node, filter);
|
DependencyNodeToNodeTransition transition = new DependencyNodeToNodeTransition(this, node, filter);
|
||||||
if (!transitions.containsKey(node)) {
|
if (!transitions.containsKey(node)) {
|
||||||
transitions.put(node, transition);
|
transitions.put(node, transition);
|
||||||
|
@ -123,11 +132,11 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasArrayType() {
|
public boolean hasArrayType() {
|
||||||
return arrayItemNode != null && arrayItemNode.types.isEmpty();
|
return arrayItemNode != null && arrayItemNode.types != null && !arrayItemNode.types.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasType(DependencyType type) {
|
public boolean hasType(DependencyType type) {
|
||||||
return type.getDependencyChecker() == dependencyChecker && types.get(type.index);
|
return types != null && type.getDependencyChecker() == dependencyChecker && types.get(type.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -137,6 +146,9 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getTypes() {
|
public String[] getTypes() {
|
||||||
|
if (types == null) {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
List<String> result = new ArrayList<>();
|
List<String> result = new ArrayList<>();
|
||||||
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());
|
result.add(dependencyChecker.types.get(index).getName());
|
||||||
|
|
|
@ -55,6 +55,10 @@ public class MethodDependency implements MethodDependencyInfo {
|
||||||
return Arrays.copyOf(variableNodes, variableNodes.length);
|
return Arrays.copyOf(variableNodes, variableNodes.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setVariables(DependencyNode[] variables) {
|
||||||
|
this.variableNodes = variables;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getVariableCount() {
|
public int getVariableCount() {
|
||||||
return variableNodes.length;
|
return variableNodes.length;
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.model;
|
package org.teavm.model;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Specifies a fully qualified name of a method, including its name, class name, parameter types
|
* <p>Specifies a fully qualified name of a method, including its name, class name, parameter types
|
||||||
* and return value type. This class overloads <code>equals</code> and <code>hashCode</code>
|
* and return value type. This class overloads <code>equals</code> and <code>hashCode</code>
|
||||||
|
@ -28,11 +30,16 @@ package org.teavm.model;
|
||||||
*/
|
*/
|
||||||
public class MethodReference {
|
public class MethodReference {
|
||||||
private String className;
|
private String className;
|
||||||
private MethodDescriptor descriptor;
|
private String name;
|
||||||
|
private ValueType[] signature;
|
||||||
|
private transient MethodDescriptor descriptor;
|
||||||
|
private transient String reprCache;
|
||||||
|
|
||||||
public MethodReference(String className, MethodDescriptor descriptor) {
|
public MethodReference(String className, MethodDescriptor descriptor) {
|
||||||
this.className = className;
|
this.className = className;
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
|
this.name = descriptor.getName();
|
||||||
|
this.signature = descriptor.getSignature();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,11 +59,21 @@ public class MethodReference {
|
||||||
* a type of a returning value, and all the remaining elements are types of arguments.
|
* a type of a returning value, and all the remaining elements are types of arguments.
|
||||||
*/
|
*/
|
||||||
public MethodReference(String className, String name, ValueType... signature) {
|
public MethodReference(String className, String name, ValueType... signature) {
|
||||||
this(className, new MethodDescriptor(name, signature));
|
this.className = className;
|
||||||
|
this.name = name;
|
||||||
|
this.signature = Arrays.copyOf(signature, signature.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodReference(Class<?> cls, String name, Class<?>... signature) {
|
public MethodReference(Class<?> cls, String name, Class<?>... signature) {
|
||||||
this(cls.getName(), new MethodDescriptor(name, signature));
|
this(cls.getName(), name, convertSignature(signature));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ValueType[] convertSignature(Class<?>... signature) {
|
||||||
|
ValueType[] types = new ValueType[signature.length];
|
||||||
|
for (int i = 0; i < types.length; ++i) {
|
||||||
|
types[i] = ValueType.parse(signature[i]);
|
||||||
|
}
|
||||||
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getClassName() {
|
public String getClassName() {
|
||||||
|
@ -64,44 +81,61 @@ public class MethodReference {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodDescriptor getDescriptor() {
|
public MethodDescriptor getDescriptor() {
|
||||||
|
if (descriptor == null) {
|
||||||
|
descriptor = new MethodDescriptor(name, signature);
|
||||||
|
}
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int parameterCount() {
|
public int parameterCount() {
|
||||||
return descriptor.parameterCount();
|
return signature.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueType[] getParameterTypes() {
|
public ValueType[] getParameterTypes() {
|
||||||
return descriptor.getParameterTypes();
|
return Arrays.copyOf(signature, signature.length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueType[] getSignature() {
|
public ValueType[] getSignature() {
|
||||||
return descriptor.getSignature();
|
return Arrays.copyOf(signature, signature.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return descriptor.getName();
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return className.hashCode() ^ descriptor.hashCode();
|
return toString().hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
if (!(obj instanceof MethodReference)) {
|
if (!(obj instanceof MethodReference)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MethodReference other = (MethodReference)obj;
|
MethodReference other = (MethodReference)obj;
|
||||||
return className.equals(other.className) && descriptor.equals(other.descriptor);
|
return toString().equals(other.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return className + "." + descriptor;
|
if (reprCache == null) {
|
||||||
|
reprCache = className + "." + name + signatureToString();
|
||||||
|
}
|
||||||
|
return reprCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String signatureToString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append('(');
|
||||||
|
for (int i = 0; i < signature.length - 1; ++i) {
|
||||||
|
sb.append(signature[i].toString());
|
||||||
|
}
|
||||||
|
sb.append(')');
|
||||||
|
sb.append(signature[signature.length - 1]);
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user