mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Working on dependency checker
This commit is contained in:
parent
93798a335c
commit
7e7cdc5b78
|
@ -51,7 +51,6 @@ public class TObject {
|
||||||
public final void wait0(long timeout, int nanos) throws TInterruptedException {
|
public final void wait0(long timeout, int nanos) throws TInterruptedException {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Rename("wait")
|
@Rename("wait")
|
||||||
public final void wait0() throws TInterruptedException {
|
public final void wait0() throws TInterruptedException {
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,16 +71,16 @@ public class DependencyChecker {
|
||||||
}
|
}
|
||||||
MethodGraph graph = attachMethodGraph(methodRef);
|
MethodGraph graph = attachMethodGraph(methodRef);
|
||||||
DependencyNode[] varNodes = graph.getVariableNodes();
|
DependencyNode[] varNodes = graph.getVariableNodes();
|
||||||
schedulePropagation(varNodes[0], methodRef.getClassName());
|
varNodes[0].propagate(methodRef.getClassName());
|
||||||
for (int i = 0; i < argumentTypes.length; ++i) {
|
for (int i = 0; i < argumentTypes.length; ++i) {
|
||||||
schedulePropagation(varNodes[i + 1], argumentTypes[i]);
|
varNodes[i + 1].propagate(argumentTypes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void schedulePropagation(final DependencyConsumer targetNode, final String type) {
|
public void schedulePropagation(final DependencyConsumer consumer, final String type) {
|
||||||
schedule(new Runnable() {
|
schedule(new Runnable() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
targetNode.propagate(type);
|
consumer.consume(type);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,5 @@ package org.teavm.dependency;
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public interface DependencyConsumer {
|
public interface DependencyConsumer {
|
||||||
void propagate(String type);
|
void consume(String type);
|
||||||
|
|
||||||
boolean hasType(String type);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ class DependencyGraphBuilder {
|
||||||
private DependencyNode resultNode;
|
private DependencyNode resultNode;
|
||||||
private Program program;
|
private Program program;
|
||||||
private ValueType resultType;
|
private ValueType resultType;
|
||||||
private TypeAnalyzer typeAnalyzer;
|
|
||||||
|
|
||||||
public DependencyGraphBuilder(DependencyChecker dependencyChecker) {
|
public DependencyGraphBuilder(DependencyChecker dependencyChecker) {
|
||||||
this.dependencyChecker = dependencyChecker;
|
this.dependencyChecker = dependencyChecker;
|
||||||
|
@ -86,7 +85,7 @@ class DependencyGraphBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void propagate(String className) {
|
public void consume(String className) {
|
||||||
if (DependencyChecker.shouldLog) {
|
if (DependencyChecker.shouldLog) {
|
||||||
System.out.println("Virtual call of " + methodDesc + " detected on " +
|
System.out.println("Virtual call of " + methodDesc + " detected on " +
|
||||||
node.getTag() + ". Target class is " + className);
|
node.getTag() + ". Target class is " + className);
|
||||||
|
@ -100,22 +99,11 @@ class DependencyGraphBuilder {
|
||||||
DependencyNode[] targetParams = targetGraph.getVariableNodes();
|
DependencyNode[] targetParams = targetGraph.getVariableNodes();
|
||||||
for (int i = 0; i < parameters.length; ++i) {
|
for (int i = 0; i < parameters.length; ++i) {
|
||||||
parameters[i].connect(targetParams[i]);
|
parameters[i].connect(targetParams[i]);
|
||||||
if (hasBody(method)) {// && isPossibleArrayPair(paramTypes[i], method.getProgram().variableAt(i))) {
|
|
||||||
targetParams[i].connect(parameters[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (targetGraph.getResultNode() != null) {
|
if (targetGraph.getResultNode() != null) {
|
||||||
targetGraph.getResultNode().connect(result);
|
targetGraph.getResultNode().connect(result);
|
||||||
if (isPossibleArrayPair(method.getResultType(), resultType)) {
|
|
||||||
result.connect(targetGraph.getResultNode());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasType(String type) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodHolder findMethod(MethodReference methodRef, ClassHolderSource classSource) {
|
private static MethodHolder findMethod(MethodReference methodRef, ClassHolderSource classSource) {
|
||||||
|
|
|
@ -17,47 +17,76 @@ package org.teavm.dependency;
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class DependencyNode implements DependencyConsumer {
|
public class DependencyNode {
|
||||||
private DependencyChecker dependencyChecker;
|
private DependencyChecker dependencyChecker;
|
||||||
private static final Object mapValue = new Object();
|
private static final Object mapValue = new Object();
|
||||||
private ConcurrentMap<DependencyConsumer, Object> followers = new ConcurrentHashMap<>();
|
private ConcurrentMap<DependencyConsumer, Object> followers = new ConcurrentHashMap<>();
|
||||||
private ConcurrentMap<String, Object> types = new ConcurrentHashMap<>();
|
private ConcurrentMap<String, Object> types = new ConcurrentHashMap<>();
|
||||||
|
private ConcurrentMap<DependencyNode, DependencyNodeToNodeTransition> transitions = new ConcurrentHashMap<>();
|
||||||
private volatile String tag;
|
private volatile String tag;
|
||||||
|
private final AtomicReference<DependencyNode> arrayItemNode = new AtomicReference<>();
|
||||||
|
private volatile CountDownLatch arrayItemNodeLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
DependencyNode(DependencyChecker dependencyChecker) {
|
DependencyNode(DependencyChecker dependencyChecker) {
|
||||||
this.dependencyChecker = dependencyChecker;
|
this.dependencyChecker = dependencyChecker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void propagate(String type) {
|
public void propagate(String type) {
|
||||||
if (types.putIfAbsent(type, mapValue) == null) {
|
if (types.putIfAbsent(type, mapValue) == null) {
|
||||||
if (DependencyChecker.shouldLog) {
|
if (DependencyChecker.shouldLog) {
|
||||||
System.out.println(tag + " -> " + type);
|
System.out.println(tag + " -> " + type);
|
||||||
}
|
}
|
||||||
for (DependencyConsumer follower : followers.keySet().toArray(new DependencyConsumer[0])) {
|
for (DependencyConsumer consumer : followers.keySet().toArray(new DependencyConsumer[0])) {
|
||||||
if (follower.hasType(type)) {
|
dependencyChecker.schedulePropagation(consumer, type);
|
||||||
dependencyChecker.schedulePropagation(follower, type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(DependencyConsumer follower) {
|
public void addConsumer(DependencyConsumer consumer) {
|
||||||
if (followers.putIfAbsent(follower, mapValue) == null) {
|
if (followers.putIfAbsent(consumer, mapValue) == null) {
|
||||||
for (String type : types.keySet().toArray(new String[0])) {
|
for (String type : types.keySet().toArray(new String[0])) {
|
||||||
if (follower.hasType(type)) {
|
dependencyChecker.schedulePropagation(consumer, type);
|
||||||
dependencyChecker.schedulePropagation(follower, type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void connect(DependencyNode node) {
|
||||||
|
DependencyNodeToNodeTransition transition = new DependencyNodeToNodeTransition(this, node);
|
||||||
|
if (transitions.putIfAbsent(node, transition) == null) {
|
||||||
|
addConsumer(transition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DependencyNode getArrayItemNode() {
|
||||||
|
DependencyNode result = arrayItemNode.get();
|
||||||
|
if (result == null) {
|
||||||
|
result = new DependencyNode(dependencyChecker);
|
||||||
|
if (arrayItemNode.compareAndSet(null, result)) {
|
||||||
|
arrayItemNodeLatch.countDown();
|
||||||
|
arrayItemNodeLatch = null;
|
||||||
|
} else {
|
||||||
|
CountDownLatch latch = arrayItemNodeLatch;
|
||||||
|
if (latch != null) {
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = arrayItemNode.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasType(String type) {
|
public boolean hasType(String type) {
|
||||||
return types.containsKey(type);
|
return types.containsKey(type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.teavm.dependency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
class DependencyNodeToNodeTransition implements DependencyConsumer {
|
||||||
|
private DependencyNode source;
|
||||||
|
private DependencyNode destination;
|
||||||
|
|
||||||
|
public DependencyNodeToNodeTransition(DependencyNode source, DependencyNode destination) {
|
||||||
|
this.source = source;
|
||||||
|
this.destination = destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void consume(String type) {
|
||||||
|
if (!destination.hasType(type)) {
|
||||||
|
destination.propagate(type);
|
||||||
|
if (type.startsWith("[")) {
|
||||||
|
source.getArrayItemNode().connect(destination.getArrayItemNode());
|
||||||
|
destination.getArrayItemNode().connect(destination.getArrayItemNode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,313 +0,0 @@
|
||||||
package org.teavm.dependency;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import org.teavm.model.*;
|
|
||||||
import org.teavm.model.instructions.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
|
||||||
*/
|
|
||||||
class TypeAnalyzer implements InstructionVisitor {
|
|
||||||
private ClassHolderSource classSource;
|
|
||||||
private ValueType[] types;
|
|
||||||
|
|
||||||
public TypeAnalyzer(ClassHolderSource classSource, int variableCount) {
|
|
||||||
this.classSource = classSource;
|
|
||||||
types = new ValueType[variableCount];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(EmptyInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueType typeOf(int variable) {
|
|
||||||
return types[variable];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void define(Variable var, ValueType type) {
|
|
||||||
types[var.getIndex()] = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void merge(Variable var, ValueType type) {
|
|
||||||
if (types[var.getIndex()] == null) {
|
|
||||||
define(var, type);
|
|
||||||
} else {
|
|
||||||
define(var, merge(typeOf(var.getIndex()), type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ValueType merge(ValueType a, ValueType b) {
|
|
||||||
if (a instanceof ValueType.Array && b instanceof ValueType.Array) {
|
|
||||||
return merge(((ValueType.Array)a).getItemType(), ((ValueType.Array)b).getItemType());
|
|
||||||
} else if (a instanceof ValueType.Object && b instanceof ValueType.Object) {
|
|
||||||
String p = ((ValueType.Object)a).getClassName();
|
|
||||||
String q = ((ValueType.Object)b).getClassName();
|
|
||||||
if (p.equals(q)) {
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
ClassHolder firstClass = classSource.getClassHolder(p);
|
|
||||||
ClassHolder secondClass = classSource.getClassHolder(q);
|
|
||||||
if (firstClass.getModifiers().contains(ElementModifier.INTERFACE) ||
|
|
||||||
secondClass.getModifiers().contains(ElementModifier.INTERFACE)) {
|
|
||||||
return ValueType.object("java.lang.Object");
|
|
||||||
}
|
|
||||||
if (isSuper(secondClass, firstClass)) {
|
|
||||||
return ValueType.object(secondClass.getName());
|
|
||||||
}
|
|
||||||
Set<String> path = getPathToRoot(firstClass);
|
|
||||||
return ValueType.object(findAmoungSupertypes(secondClass, path));
|
|
||||||
} else {
|
|
||||||
return ValueType.object("java.lang.Object");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> getPathToRoot(ClassHolder cls) {
|
|
||||||
Set<String> path = new HashSet<>();
|
|
||||||
while (cls != null) {
|
|
||||||
path.add(cls.getName());
|
|
||||||
cls = cls.getParent() != null ? classSource.getClassHolder(cls.getParent()) : null;
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isSuper(ClassHolder cls, ClassHolder superCls) {
|
|
||||||
while (cls != null) {
|
|
||||||
if (cls == superCls) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
cls = cls.getParent() != null ? classSource.getClassHolder(cls.getParent()) : null;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String findAmoungSupertypes(ClassHolder cls, Set<String> supertypes) {
|
|
||||||
while (cls != null) {
|
|
||||||
if (supertypes.contains(cls.getName())) {
|
|
||||||
return cls.getName();
|
|
||||||
}
|
|
||||||
cls = cls.getParent() != null ? classSource.getClassHolder(cls.getParent()) : null;
|
|
||||||
}
|
|
||||||
return "java.lang.Object";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ClassConstantInstruction insn) {
|
|
||||||
define(insn.getReceiver(), ValueType.object("java.lang.Class"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(NullConstantInstruction insn) {
|
|
||||||
define(insn.getReceiver(), ValueType.NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(IntegerConstantInstruction insn) {
|
|
||||||
define(insn.getReceiver(), ValueType.INTEGER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(LongConstantInstruction insn) {
|
|
||||||
define(insn.getReceiver(), ValueType.LONG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(FloatConstantInstruction insn) {
|
|
||||||
define(insn.getReceiver(), ValueType.FLOAT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(DoubleConstantInstruction insn) {
|
|
||||||
define(insn.getReceiver(), ValueType.DOUBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(StringConstantInstruction insn) {
|
|
||||||
define(insn.getReceiver(), ValueType.object("java.lang.String"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(BinaryInstruction insn) {
|
|
||||||
switch (insn.getOperation()) {
|
|
||||||
case ADD:
|
|
||||||
case SUBTRACT:
|
|
||||||
case MULTIPLY:
|
|
||||||
case DIVIDE:
|
|
||||||
case MODULO:
|
|
||||||
case SHIFT_LEFT:
|
|
||||||
case SHIFT_RIGHT:
|
|
||||||
case SHIFT_RIGHT_UNSIGNED:
|
|
||||||
case AND:
|
|
||||||
case OR:
|
|
||||||
case XOR:
|
|
||||||
define(insn.getReceiver(), map(insn.getOperandType()));
|
|
||||||
break;
|
|
||||||
case COMPARE:
|
|
||||||
define(insn.getReceiver(), ValueType.INTEGER);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ValueType map(NumericOperandType type) {
|
|
||||||
switch (type) {
|
|
||||||
case INT:
|
|
||||||
return ValueType.INTEGER;
|
|
||||||
case LONG:
|
|
||||||
return ValueType.LONG;
|
|
||||||
case FLOAT:
|
|
||||||
return ValueType.FLOAT;
|
|
||||||
case DOUBLE:
|
|
||||||
return ValueType.DOUBLE;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Unknown type: " + type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(NegateInstruction insn) {
|
|
||||||
define(insn.getReceiver(), map(insn.getOperandType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(AssignInstruction insn) {
|
|
||||||
define(insn.getReceiver(), types[insn.getAssignee().getIndex()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CastInstruction insn) {
|
|
||||||
define(insn.getReceiver(), insn.getTargetType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CastNumberInstruction insn) {
|
|
||||||
define(insn.getReceiver(), map(insn.getTargetType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(BranchingInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(BinaryBranchingInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(JumpInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(SwitchInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ExitInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(RaiseInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ConstructArrayInstruction insn) {
|
|
||||||
define(insn.getReceiver(), ValueType.arrayOf(insn.getItemType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ConstructInstruction insn) {
|
|
||||||
define(insn.getReceiver(), ValueType.object(insn.getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ConstructMultiArrayInstruction insn) {
|
|
||||||
ValueType type = insn.getItemType();
|
|
||||||
for (int i = 0; i < insn.getDimensions().size(); ++i) {
|
|
||||||
type = ValueType.arrayOf(type);
|
|
||||||
}
|
|
||||||
define(insn.getReceiver(), type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(GetFieldInstruction insn) {
|
|
||||||
FieldHolder field = getRealField(new FieldReference(insn.getClassName(), insn.getField()));
|
|
||||||
if (field == null) {
|
|
||||||
throw new RuntimeException("Field not found: " + insn.getClassName() + "." + insn.getField());
|
|
||||||
}
|
|
||||||
define(insn.getReceiver(), field.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
private FieldHolder getRealField(FieldReference ref) {
|
|
||||||
String className = ref.getClassName();
|
|
||||||
while (className != null) {
|
|
||||||
ClassHolder cls = classSource.getClassHolder(className);
|
|
||||||
if (cls == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
FieldHolder field = cls.getField(ref.getFieldName());
|
|
||||||
if (field.getLevel() == AccessLevel.PRIVATE && !className.equals(ref.getClassName())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MethodHolder getRealMethod(MethodReference ref) {
|
|
||||||
String className = ref.getClassName();
|
|
||||||
while (className != null) {
|
|
||||||
ClassHolder cls = classSource.getClassHolder(className);
|
|
||||||
if (cls == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
MethodHolder method = cls.getMethod(ref.getDescriptor());
|
|
||||||
if (method.getLevel() == AccessLevel.PRIVATE && !className.equals(ref.getClassName())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(PutFieldInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ArrayLengthInstruction insn) {
|
|
||||||
define(insn.getReceiver(), ValueType.INTEGER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CloneArrayInstruction insn) {
|
|
||||||
define(insn.getReceiver(), types[insn.getArray().getIndex()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(GetElementInstruction insn) {
|
|
||||||
ValueType type = types[insn.getArray().getIndex()];
|
|
||||||
if (!(type instanceof ValueType.Array)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ValueType itemType = ((ValueType.Array)type).getItemType();
|
|
||||||
define(insn.getReceiver(), itemType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(PutElementInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(InvokeInstruction insn) {
|
|
||||||
MethodHolder method = getRealMethod(new MethodReference(insn.getClassName(), insn.getMethod()));
|
|
||||||
if (method == null) {
|
|
||||||
throw new RuntimeException("Method not found: " + insn.getMethod());
|
|
||||||
}
|
|
||||||
if (insn.getMethod().getResultType() != ValueType.VOID) {
|
|
||||||
define(insn.getReceiver(), insn.getMethod().getResultType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(IsInstanceInstruction insn) {
|
|
||||||
define(insn.getReceiver(), ValueType.BOOLEAN);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user