Initial optimization of dependency checker

This commit is contained in:
konsoletyper 2015-03-13 22:09:28 +03:00
parent 1380e7dbf4
commit 2745f1c7f5
14 changed files with 249 additions and 80 deletions

View File

@ -36,14 +36,20 @@ public class DataFlowGraphBuilder implements InstructionReader {
private ObjectIntMap<MethodReference> methodNodes = new ObjectIntOpenHashMap<>();
private ObjectIntMap<FieldReference> fieldNodes = new ObjectIntOpenHashMap<>();
private int[] arrayNodes;
private int returnIndex = -1;
private int exceptionIndex;
public void important(int node) {
importantNodes.add(node);
}
public int[] buildMapping(ProgramReader program, int paramCount) {
public int[] buildMapping(ProgramReader program, int paramCount, boolean needsReturn) {
lastIndex = program.variableCount();
arrayNodes = new int[lastIndex];
if (needsReturn) {
returnIndex = lastIndex++;
}
exceptionIndex = lastIndex++;
Arrays.fill(arrayNodes, -1);
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlockReader block = program.basicBlockAt(i);
@ -52,6 +58,11 @@ public class DataFlowGraphBuilder implements InstructionReader {
builder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
}
}
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
if (tryCatch.getExceptionVariable() != null) {
important(tryCatch.getExceptionVariable().getIndex());
}
}
block.readAllInstructions(this);
}
Graph graph = builder.build();
@ -76,6 +87,17 @@ public class DataFlowGraphBuilder implements InstructionReader {
importantNodes.add(newCls);
}
}
for (int succ : graph.outgoingEdges(i)) {
boolean succImportant = importantNodes.contains(classes.find(succ));
boolean nodeImportant = importantNodes.contains(classes.find(i));
if (succImportant && nodeImportant) {
continue;
}
int newCls = classes.union(succ, i);
if (nodeImportant || succImportant) {
importantNodes.add(newCls);
}
}
}
int[][] sccs = GraphUtils.findStronglyConnectedComponents(graph, startNodes.getAll());
@ -88,7 +110,25 @@ public class DataFlowGraphBuilder implements InstructionReader {
last = last < 0 ? node : classes.union(node, last);
}
}
return classes.pack(program.variableCount());
int[] classMap = new int[classes.size()];
Arrays.fill(classMap, -1);
int[] result = new int[program.variableCount()];
int classCount = 0;
for (int i = 0; i < program.variableCount(); ++i) {
int cls = classes.find(i);
if (!importantNodes.contains(cls)) {
result[i] = -1;
continue;
}
int packedCls = classMap[cls];
if (packedCls < 0) {
packedCls = classCount++;
classMap[cls] = packedCls;
}
result[i] = packedCls;
}
return result;
}
@Override
@ -178,14 +218,16 @@ public class DataFlowGraphBuilder implements InstructionReader {
@Override
public void exit(VariableReader valueToReturn) {
if (valueToReturn != null) {
important(valueToReturn.getIndex());
if (valueToReturn != null && returnIndex >= 0) {
important(returnIndex);
builder.addEdge(valueToReturn.getIndex(), returnIndex);
}
}
@Override
public void raise(VariableReader exception) {
important(exception.getIndex());
builder.addEdge(exception.getIndex(), exceptionIndex);
important(exceptionIndex);
}
@Override
@ -212,13 +254,18 @@ public class DataFlowGraphBuilder implements InstructionReader {
@Override
public void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType) {
if (fieldType instanceof ValueType.Primitive) {
return;
}
int fieldNode = getFieldNode(field);
builder.addEdge(fieldNode, receiver.getIndex());
}
@Override
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
public void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType) {
if (fieldType instanceof ValueType.Primitive) {
return;
}
int fieldNode = getFieldNode(field);
builder.addEdge(value.getIndex(), fieldNode);
}
@ -274,9 +321,20 @@ public class DataFlowGraphBuilder implements InstructionReader {
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) {
if (receiver != null) {
if (!(method.getReturnType() instanceof ValueType.Primitive)) {
builder.addEdge(getMethodNode(method), receiver.getIndex());
}
}
ValueType[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; ++i) {
if (!(paramTypes[i] instanceof ValueType.Primitive)) {
important(arguments.get(i).getIndex());
}
}
if (instance != null) {
important(instance.getIndex());
}
}
@Override
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
@ -293,9 +351,11 @@ public class DataFlowGraphBuilder implements InstructionReader {
@Override
public void monitorEnter(VariableReader objectRef) {
important(objectRef.getIndex());
}
@Override
public void monitorExit(VariableReader objectRef) {
important(objectRef.getIndex());
}
}

View File

@ -62,6 +62,8 @@ public class DependencyChecker implements DependencyInfo {
private Diagnostics diagnostics;
DefaultCallGraph callGraph = new DefaultCallGraph();
private DependencyAgent agent;
List<DependencyNode> nodes = new ArrayList<>();
List<BitSet> typeBitSets = new ArrayList<>();
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services,
Diagnostics diagnostics) {
@ -128,13 +130,16 @@ public class DependencyChecker implements DependencyInfo {
if (type == null) {
type = new DependencyType(this, name, types.size());
types.add(type);
typeBitSets.add(new BitSet(nodes.size()));
typeMap.put(name, type);
}
return type;
}
public DependencyNode createNode() {
return new DependencyNode(this);
DependencyNode node = new DependencyNode(this, nodes.size());
nodes.add(node);
return node;
}
@Override
@ -336,11 +341,9 @@ public class DependencyChecker implements DependencyInfo {
private MethodDependency createMethodDep(MethodReference methodRef, MethodReader method) {
ValueType[] arguments = methodRef.getParameterTypes();
int paramCount = arguments.length + 1;
int varCount = Math.max(paramCount, method != null && method.getProgram() != null ?
method.getProgram().variableCount() : 0);
DependencyNode[] parameterNodes = new DependencyNode[varCount];
for (int i = 0; i < varCount; ++i) {
parameterNodes[i] = new DependencyNode(this);
DependencyNode[] parameterNodes = new DependencyNode[arguments.length + 1];
for (int i = 0; i < parameterNodes.length; ++i) {
parameterNodes[i] = createNode();
if (shouldLog) {
parameterNodes[i].setTag(methodRef + ":" + i);
}
@ -349,7 +352,7 @@ public class DependencyChecker implements DependencyInfo {
if (methodRef.getDescriptor().getResultType() == ValueType.VOID) {
resultNode = null;
} else {
resultNode = new DependencyNode(this);
resultNode = createNode();
if (shouldLog) {
resultNode.setTag(methodRef + ":RESULT");
}
@ -431,7 +434,7 @@ public class DependencyChecker implements DependencyInfo {
}
private FieldDependency createFieldNode(final FieldReference fieldRef, FieldReader field) {
DependencyNode node = new DependencyNode(this);
DependencyNode node = createNode();
if (shouldLog) {
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
}
@ -501,6 +504,7 @@ public class DependencyChecker implements DependencyInfo {
index = 0;
}
}
return;
}
public <T> T getService(Class<T> type) {

View File

@ -15,6 +15,7 @@
*/
package org.teavm.dependency;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -48,20 +49,29 @@ class DependencyGraphBuilder {
}
program = method.getProgram();
if (DependencyChecker.shouldLog) {
System.out.println("Method achieved: " + method.getReference());
System.out.println("Method reached: " + method.getReference());
System.out.println(new ListingBuilder().buildListing(program, " "));
}
resultNode = dep.getResult();
DependencyNode[] origNodes = dep.getVariables();
DataFlowGraphBuilder dfgBuilder = new DataFlowGraphBuilder();
for (int i = 0; i < dep.getParameterCount(); ++i) {
dfgBuilder.important(i);
}
int[] nodeMapping = dfgBuilder.buildMapping(program, dep.getParameterCount());
nodes = new DependencyNode[origNodes.length];
int[] nodeMapping = dfgBuilder.buildMapping(program, dep.getParameterCount(),
!(method.getResultType() instanceof ValueType.Primitive) && method.getResultType() != ValueType.VOID);
int nodeClassCount = 0;
for (int i = 0; i < nodeMapping.length; ++i) {
nodeClassCount = Math.max(nodeClassCount, nodeMapping[i] + 1);
}
DependencyNode[] nodeClasses = Arrays.copyOf(dep.getVariables(), nodeClassCount);
for (int i = dep.getVariableCount(); i < nodeClasses.length; ++i) {
nodeClasses[i] = dependencyChecker.createNode();
}
nodes = new DependencyNode[dep.getMethod().getProgram().variableCount()];
for (int i = 0; i < nodes.length; ++i) {
nodes[i] = origNodes[nodeMapping[i]];
int mappedNode = nodeMapping[i];
nodes[i] = mappedNode >= 0 ? nodeClasses[mappedNode] : null;
}
dep.setVariables(nodes);
@ -71,9 +81,13 @@ class DependencyGraphBuilder {
block.readAllInstructions(reader);
for (PhiReader phi : block.readPhis()) {
for (IncomingReader incoming : phi.readIncomings()) {
DependencyNode incomingNode = nodes[incoming.getValue().getIndex()];
DependencyNode receiverNode = nodes[phi.getReceiver().getIndex()];
if (incomingNode != null || receiverNode != null) {
nodes[incoming.getValue().getIndex()].connect(nodes[phi.getReceiver().getIndex()]);
}
}
}
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
if (tryCatch.getExceptionType() != null) {
dependencyChecker.linkClass(tryCatch.getExceptionType(), new CallLocation(caller.getMethod()));
@ -169,8 +183,10 @@ class DependencyGraphBuilder {
methodDep.use();
DependencyNode[] targetParams = methodDep.getVariables();
for (int i = 0; i < parameters.length; ++i) {
if (parameters[i] != null) {
parameters[i].connect(targetParams[i]);
}
}
if (result != null && methodDep.getResult() != null) {
methodDep.getResult().connect(result);
}
@ -211,7 +227,10 @@ class DependencyGraphBuilder {
@Override
public void classConstant(VariableReader receiver, ValueType cst) {
nodes[receiver.getIndex()].propagate(dependencyChecker.getType("java.lang.Class"));
DependencyNode node = nodes[receiver.getIndex()];
if (node != null) {
node.propagate(dependencyChecker.getType("java.lang.Class"));
}
while (cst instanceof ValueType.Array) {
cst = ((ValueType.Array)cst).getItemType();
}
@ -243,7 +262,10 @@ class DependencyGraphBuilder {
@Override
public void stringConstant(VariableReader receiver, String cst) {
nodes[receiver.getIndex()].propagate(dependencyChecker.getType("java.lang.String"));
DependencyNode node = nodes[receiver.getIndex()];
if (node != null) {
node.propagate(dependencyChecker.getType("java.lang.String"));
}
MethodDependency method = dependencyChecker.linkMethod(new MethodReference(String.class,
"<init>", char[].class, void.class), new CallLocation(caller.getMethod(), currentLocation));
method.use();
@ -262,8 +284,10 @@ class DependencyGraphBuilder {
public void assign(VariableReader receiver, VariableReader assignee) {
DependencyNode valueNode = nodes[assignee.getIndex()];
DependencyNode receiverNode = nodes[receiver.getIndex()];
if (valueNode != null && receiverNode != null) {
valueNode.connect(receiverNode);
}
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
@ -319,7 +343,10 @@ class DependencyGraphBuilder {
@Override
public void exit(VariableReader valueToReturn) {
if (valueToReturn != null) {
nodes[valueToReturn.getIndex()].connect(resultNode);
DependencyNode node = nodes[valueToReturn.getIndex()];
if (node != null) {
node.connect(resultNode);
}
}
}
@ -330,7 +357,10 @@ class DependencyGraphBuilder {
@Override
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
nodes[receiver.getIndex()].propagate(dependencyChecker.getType("[" + itemType));
DependencyNode node = nodes[receiver.getIndex()];
if (node != null) {
node.propagate(dependencyChecker.getType("[" + itemType));
}
String className = extractClassName(itemType);
if (className != null) {
dependencyChecker.linkClass(className, new CallLocation(caller.getMethod(), currentLocation));
@ -361,6 +391,9 @@ class DependencyGraphBuilder {
sb.append(itemTypeStr);
DependencyNode node = nodes[receiver.getIndex()];
for (int i = 0; i < dimensions.size(); ++i) {
if (node == null) {
break;
}
node.propagate(dependencyChecker.getType(sb.substring(i, sb.length())));
node = node.getArrayItem();
}
@ -373,25 +406,37 @@ class DependencyGraphBuilder {
@Override
public void create(VariableReader receiver, String type) {
dependencyChecker.linkClass(type, new CallLocation(caller.getMethod(), currentLocation));
nodes[receiver.getIndex()].propagate(dependencyChecker.getType(type));
DependencyNode node = nodes[receiver.getIndex()];
if (node != null) {
node.propagate(dependencyChecker.getType(type));
}
}
@Override
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
ValueType fieldType) {
if (!(fieldType instanceof ValueType.Primitive)) {
FieldDependency fieldDep = dependencyChecker.linkField(field,
new CallLocation(caller.getMethod(), currentLocation));
DependencyNode receiverNode = nodes[receiver.getIndex()];
if (receiverNode != null) {
fieldDep.getValue().connect(receiverNode);
}
}
initClass(field.getClassName());
}
@Override
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) {
if (!(fieldType instanceof ValueType.Primitive)) {
FieldDependency fieldDep = dependencyChecker.linkField(field,
new CallLocation(caller.getMethod(), currentLocation));
DependencyNode valueNode = nodes[value.getIndex()];
if (valueNode != null) {
valueNode.connect(fieldDep.getValue());
}
}
initClass(field.getClassName());
}
@ -403,6 +448,7 @@ class DependencyGraphBuilder {
public void cloneArray(VariableReader receiver, VariableReader array) {
DependencyNode arrayNode = nodes[array.getIndex()];
final DependencyNode receiverNode = nodes[receiver.getIndex()];
if (arrayNode != null && receiverNode != null) {
arrayNode.addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyType type) {
receiverNode.propagate(type);
@ -410,27 +456,34 @@ class DependencyGraphBuilder {
});
arrayNode.getArrayItem().connect(receiverNode.getArrayItem());
}
}
@Override
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
DependencyNode arrayNode = nodes[array.getIndex()];
DependencyNode receiverNode = nodes[receiver.getIndex()];
if (arrayNode != null && receiverNode != null) {
arrayNode.connect(receiverNode);
}
}
@Override
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
DependencyNode arrayNode = nodes[array.getIndex()];
DependencyNode receiverNode = nodes[receiver.getIndex()];
if (arrayNode != null && receiverNode != null) {
arrayNode.getArrayItem().connect(receiverNode);
}
}
@Override
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
DependencyNode valueNode = nodes[value.getIndex()];
DependencyNode arrayNode = nodes[array.getIndex()];
if (valueNode != null && arrayNode != null) {
valueNode.connect(arrayNode.getArrayItem());
}
}
@Override
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
@ -460,13 +513,20 @@ class DependencyGraphBuilder {
methodDep.use();
DependencyNode[] targetParams = methodDep.getVariables();
for (int i = 0; i < arguments.size(); ++i) {
nodes[arguments.get(i).getIndex()].connect(targetParams[i + 1]);
DependencyNode value = nodes[arguments.get(i).getIndex()];
DependencyNode param = targetParams[i + 1];
if (value != null && param != null) {
value.connect(param);
}
}
if (instance != null) {
nodes[instance.getIndex()].connect(targetParams[0]);
}
if (methodDep.getResult() != null && receiver != null) {
methodDep.getResult().connect(nodes[receiver.getIndex()]);
DependencyNode receiverNode = nodes[receiver.getIndex()];
if (methodDep.getResult() != null && receiverNode != null) {
methodDep.getResult().connect(receiverNode);
}
}
methodDep.getThrown().addConsumer(currentExceptionConsumer);
initClass(method.getClassName());

View File

@ -23,19 +23,21 @@ import java.util.*;
*/
public class DependencyNode implements ValueDependencyInfo {
private DependencyChecker dependencyChecker;
private Set<DependencyConsumer> followers = new HashSet<>();
private List<DependencyConsumer> followers;
private BitSet types;
private Map<DependencyNode, DependencyNodeToNodeTransition> transitions = new HashMap<>();
private List<DependencyNodeToNodeTransition> transitions;
private volatile String tag;
private DependencyNode arrayItemNode;
private int degree;
int index;
DependencyNode(DependencyChecker dependencyChecker) {
this(dependencyChecker, 0);
DependencyNode(DependencyChecker dependencyChecker, int index) {
this(dependencyChecker, index, 0);
}
DependencyNode(DependencyChecker dependencyChecker, int degree) {
DependencyNode(DependencyChecker dependencyChecker, int index, int degree) {
this.dependencyChecker = dependencyChecker;
this.index = index;
this.degree = degree;
}
@ -54,11 +56,13 @@ public class DependencyNode implements ValueDependencyInfo {
if (DependencyChecker.shouldLog) {
System.out.println(tag + " -> " + type.getName());
}
if (followers != null) {
for (DependencyConsumer consumer : followers.toArray(new DependencyConsumer[followers.size()])) {
dependencyChecker.schedulePropagation(consumer, type);
}
}
}
}
public void propagate(DependencyType[] agentTypes) {
DependencyType[] types = new DependencyType[agentTypes.length];
@ -81,13 +85,22 @@ public class DependencyNode implements ValueDependencyInfo {
System.out.println(tag + " -> " + types[i].getName());
}
}
if (followers != null) {
for (DependencyConsumer consumer : followers.toArray(new DependencyConsumer[followers.size()])) {
dependencyChecker.schedulePropagation(consumer, Arrays.copyOf(types, j));
}
}
}
public void addConsumer(DependencyConsumer consumer) {
if (followers.add(consumer) && this.types != null) {
if (followers == null) {
followers = new ArrayList<>();
}
if (followers.contains(consumer)) {
return;
}
followers.add(consumer);
if (this.types != null) {
List<DependencyType> types = new ArrayList<>();
for (int index = this.types.nextSetBit(0); index >= 0; index = this.types.nextSetBit(index + 1)) {
types.add(dependencyChecker.types.get(index));
@ -100,15 +113,27 @@ public class DependencyNode implements ValueDependencyInfo {
if (this == node) {
return;
}
if (node == null) {
throw new IllegalArgumentException("Node must not be null");
}
if (transitions != null) {
for (DependencyNodeToNodeTransition transition : transitions) {
if (transition.destination == node) {
return;
}
}
}
DependencyNodeToNodeTransition transition = new DependencyNodeToNodeTransition(this, node, filter);
if (!transitions.containsKey(node)) {
transitions.put(node, transition);
if (transitions == null) {
transitions = new ArrayList<>();
}
transitions.add(transition);
if (DependencyChecker.shouldLog) {
System.out.println("Connecting " + tag + " to " + node.tag);
}
addConsumer(transition);
}
}
public void connect(DependencyNode node) {
connect(node, null);
@ -117,7 +142,8 @@ public class DependencyNode implements ValueDependencyInfo {
@Override
public DependencyNode getArrayItem() {
if (arrayItemNode == null) {
arrayItemNode = new DependencyNode(dependencyChecker, degree + 1);
arrayItemNode = new DependencyNode(dependencyChecker, dependencyChecker.nodes.size(), degree + 1);
dependencyChecker.nodes.add(arrayItemNode);
if (DependencyChecker.shouldLog) {
arrayItemNode.tag = tag + "[";
}

View File

@ -20,8 +20,8 @@ package org.teavm.dependency;
* @author Alexey Andreev
*/
class DependencyNodeToNodeTransition implements DependencyConsumer {
private DependencyNode source;
private DependencyNode destination;
DependencyNode source;
DependencyNode destination;
private DependencyTypeFilter filter;
public DependencyNodeToNodeTransition(DependencyNode source, DependencyNode destination,

View File

@ -153,7 +153,7 @@ class InstructionReadVisitor implements InstructionVisitor {
@Override
public void visit(PutFieldInstruction insn) {
reader.putField(insn.getInstance(), insn.getField(), insn.getValue());
reader.putField(insn.getInstance(), insn.getField(), insn.getValue(), insn.getFieldType());
}
@Override

View File

@ -99,6 +99,10 @@ public class MethodReference {
return Arrays.copyOf(signature, signature.length);
}
public ValueType getReturnType() {
return signature[signature.length - 1];
}
public String getName() {
return name;
}

View File

@ -79,7 +79,7 @@ public interface InstructionReader {
void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType);
void putField(VariableReader instance, FieldReference field, VariableReader value);
void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType);
void arrayLength(VariableReader receiver, VariableReader array);

View File

@ -17,6 +17,7 @@ package org.teavm.model.instructions;
import org.teavm.model.FieldReference;
import org.teavm.model.Instruction;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
/**
@ -27,6 +28,7 @@ public class PutFieldInstruction extends Instruction {
private Variable instance;
private FieldReference field;
private Variable value;
private ValueType fieldType;
public Variable getInstance() {
return instance;
@ -52,6 +54,14 @@ public class PutFieldInstruction extends Instruction {
this.value = value;
}
public ValueType getFieldType() {
return fieldType;
}
public void setFieldType(ValueType fieldType) {
this.fieldType = fieldType;
}
@Override
public void acceptVisitor(InstructionVisitor visitor) {
visitor.visit(this);

View File

@ -330,7 +330,8 @@ public class AsyncMethodFinder {
}
@Override
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) {
}
@Override

View File

@ -280,7 +280,7 @@ public class InstructionStringifier implements InstructionReader {
}
@Override
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
public void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType) {
if (instance != null) {
sb.append("@").append(instance.getIndex());
} else {

View File

@ -398,11 +398,13 @@ public final class ProgramUtils {
}
@Override
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) {
PutFieldInstruction insnCopy = new PutFieldInstruction();
insnCopy.setField(field);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setValue(copyVar(value));
insnCopy.setFieldType(fieldType);
copy = insnCopy;
copy.setLocation(location);
}

View File

@ -1611,6 +1611,7 @@ public class ProgramParser implements VariableDebugInformation {
insn.setInstance(getVariable(instance));
insn.setField(new FieldReference(ownerCls, name));
insn.setValue(getVariable(value));
insn.setFieldType(ValueType.parse(desc));
addInstruction(insn);
break;
}

View File

@ -77,7 +77,8 @@ class ProgramSourceAggregator implements InstructionReader {
@Override public void create(VariableReader receiver, String type) { }
@Override public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
ValueType fieldType) { }
@Override public void putField(VariableReader instance, FieldReference field, VariableReader value) { }
@Override public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) { }
@Override public void arrayLength(VariableReader receiver, VariableReader array) { }
@Override public void cloneArray(VariableReader receiver, VariableReader array) { }
@Override public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) { }