下面列出了org.objectweb.asm.Opcodes# ALOAD 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Parses a test class into extents.
*/
@Test
public void testMethodBlocks() throws Exception {
List<BasicBlock> initBlocks = METHOD_BLOCKS.get("<init>(I)V");
int[][] expectedInitBlocks = new int[][]{
{Opcodes.ALOAD, Opcodes.INVOKESPECIAL, Opcodes.ALOAD, Opcodes.ILOAD, Opcodes.PUTFIELD, Opcodes.RETURN}
};
boolean didMatch = compareBlocks(expectedInitBlocks, initBlocks);
Assert.assertTrue(didMatch);
List<BasicBlock> hashCodeBlocks = METHOD_BLOCKS.get("hashCode()I");
int[][] expectedHashCodeBlocks = new int[][]{
{Opcodes.ALOAD, Opcodes.GETFIELD, Opcodes.IRETURN}
};
didMatch = compareBlocks(expectedHashCodeBlocks, hashCodeBlocks);
Assert.assertTrue(didMatch);
}
public static int getVarOpcode(Type type, boolean store) {
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return store ? Opcodes.ISTORE : Opcodes.ILOAD;
case Type.FLOAT:
return store ? Opcodes.FSTORE : Opcodes.FLOAD;
case Type.LONG:
return store ? Opcodes.LSTORE : Opcodes.LLOAD;
case Type.DOUBLE:
return store ? Opcodes.DSTORE : Opcodes.DLOAD;
case Type.ARRAY:
case Type.OBJECT:
return store ? Opcodes.ASTORE : Opcodes.ALOAD;
default:
throw new AssertionError("Unknown type: " + type.getClassName());
}
}
/**
* Returns the bytecode instruction to load the given Jandex Type. This returns the specialised
* bytecodes <tt>ILOAD, DLOAD, FLOAD and LLOAD</tt> for primitives, or <tt>ALOAD</tt> otherwise.
*
* @param jandexType The Jandex Type whose load instruction to return.
* @return The bytecode instruction to load the given Jandex Type.
*/
public static int getLoadOpcode(Type jandexType) {
if (jandexType.kind() == Kind.PRIMITIVE) {
switch (jandexType.asPrimitiveType().primitive()) {
case BOOLEAN:
case BYTE:
case SHORT:
case INT:
case CHAR:
return Opcodes.ILOAD;
case DOUBLE:
return Opcodes.DLOAD;
case FLOAT:
return Opcodes.FLOAD;
case LONG:
return Opcodes.LLOAD;
default:
throw new IllegalArgumentException("Unknown primitive type: " + jandexType);
}
}
return Opcodes.ALOAD;
}
private void dupStackElementBeforeSignatureArgs(final String sig) {
final Label beginScopeLabel = new Label();
final Label endScopeLabel = new Label();
super.visitLabel(beginScopeLabel);
Type[] argTypes = Type.getArgumentTypes(sig);
int[] args = new int[argTypes.length];
for (int i = argTypes.length - 1; i >= 0; --i) {
args[i] = newLocal(argTypes[i], beginScopeLabel, endScopeLabel);
super.visitVarInsn(argTypes[i].getOpcode(Opcodes.ISTORE), args[i]);
}
super.visitInsn(Opcodes.DUP);
for (int i = 0; i < argTypes.length; ++i) {
int op = argTypes[i].getOpcode(Opcodes.ILOAD);
super.visitVarInsn(op, args[i]);
if (op == Opcodes.ALOAD) {
super.visitInsn(Opcodes.ACONST_NULL);
super.visitVarInsn(Opcodes.ASTORE, args[i]);
}
}
super.visitLabel(endScopeLabel);
}
@Override
public void visitInsn(int opcode) {
if(opcode == Opcodes.RETURN) {
// Load this.
super.visitVarInsn(Opcodes.ALOAD, 0);
// Execute drill init.
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, SignatureHolder.DRILL_INIT_METHOD, "()V", false);
}
super.visitInsn(opcode);
}
@Override
public void visitVarInsn(final int opcode, final int var) {
ReplacingBasicValue v;
if (opcode == Opcodes.ASTORE && (v = peekFromTop(0)) != null) {
final ValueHolderSub from = oldToNew.get(v.getIndex());
final ReplacingBasicValue current = getLocal(var);
// if local var is set, then transfer to it to the existing holders in the local position.
if (current != null) {
final ValueHolderSub newSub = oldToNew.get(current.getIndex());
if (newSub.iden() == from.iden()) {
final int targetFirst = newSub.first();
from.transfer(this, targetFirst);
return;
}
}
// if local var is not set, then check map to see if existing holders are mapped to local var.
if (oldLocalToFirst.containsKey(var)) {
final ValueHolderSub sub = oldToNew.get(oldLocalToFirst.get(var));
if (sub.iden() == from.iden()) {
// if they are, then transfer to that.
from.transfer(this, sub.first());
return;
}
}
// map from variables to global space for future use.
oldLocalToFirst.put(var, v.getIndex());
return;
} else if (opcode == Opcodes.ALOAD && (v = getLocal(var)) != null) {
/*
* Not forwarding this removes a now unnecessary ALOAD for a holder. The required LOAD/STORE
* sequences will be generated by the ASTORE code above.
*/
return;
}
super.visitVarInsn(opcode, var);
}
@Override
public void visitCode()
{
super.visitCode();
if(methodData.hasHookAt(HookPosition.METHOD_START))
{
HookData hookData = methodData.getHook(HookPosition.METHOD_START);
super.visitLdcInsn(className + "." + methodName + "|start");
if(hookData.collectsParams())
{
super.visitIntInsn(Opcodes.BIPUSH, paramCount);
super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for(byte i = 0; i < paramCount; i++)
{
super.visitInsn(Opcodes.DUP);
super.visitIntInsn(Opcodes.BIPUSH, i);
super.visitVarInsn(Opcodes.ALOAD, i);
super.visitInsn(Opcodes.AASTORE);
}
}
// TODO: Custom class path
super.visitMethodInsn(Opcodes.INVOKESTATIC,
"tk/wurst_client/hooks/HookManager", "hook",
"(Ljava/lang/String;"
+ (hookData.collectsParams() ? "[Ljava/lang/Object;" : "")
+ ")V", false);
}
}
@Override
public void visitInsn(int opcode)
{
if(methodData.hasHookAt(HookPosition.METHOD_END) && opcode >= 172
&& opcode <= 177)
{
HookData hookData = methodData.getHook(HookPosition.METHOD_END);
super.visitLdcInsn(className + "." + methodName + "|end");
if(hookData.collectsParams())
{
super.visitIntInsn(Opcodes.BIPUSH, paramCount);
super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
for(byte i = 0; i < paramCount; i++)
{
super.visitInsn(Opcodes.DUP);
super.visitIntInsn(Opcodes.BIPUSH, i);
super.visitVarInsn(Opcodes.ALOAD, i);
super.visitInsn(Opcodes.AASTORE);
}
}
// TODO: Custom class path
super.visitMethodInsn(Opcodes.INVOKESTATIC,
"tk/wurst_client/hooks/HookManager", "hook",
"(Ljava/lang/String;"
+ (hookData.collectsParams() ? "[Ljava/lang/Object;" : "")
+ ")V", false);
}
super.visitInsn(opcode);
}
@Override
public boolean assignTo(String varName, StringBuilder sb) {
StringBuilder b = new StringBuilder();
if (varName != null) {
b.append(" ").append(varName).append(" = ");
}
boolean ret = false;
if (sourceInstr != null) {
switch (sourceInstr.getOpcode()) {
case Opcodes.ALOAD: {
if (sourceInstr instanceof AssignableExpression) {
StringBuilder devNull = new StringBuilder();
if (((AssignableExpression)sourceInstr).assignTo(null, devNull)) {
b.append(devNull.toString().trim());
ret = true;
}
}
break;
}
}
}
if (varName != null) {
b.append(";\n");
}
if (!ret) {
return false;
}
sb.append(b);
return true;
}
/**
* @param opcode
* @return
*/
private static Type toType ( int opcode ) {
switch ( opcode ) {
case Opcodes.LLOAD:
return Type.LONG_TYPE;
case Opcodes.ILOAD:
return Type.INT_TYPE;
case Opcodes.FLOAD:
return Type.FLOAT_TYPE;
case Opcodes.DLOAD:
return Type.DOUBLE_TYPE;
case Opcodes.ALOAD:
return Type.getType("Ljava/lang/Object;"); //$NON-NLS-1$
case Opcodes.IALOAD:
return Type.INT_TYPE;
case Opcodes.LALOAD:
return Type.LONG_TYPE;
case Opcodes.FALOAD:
return Type.FLOAT_TYPE;
case Opcodes.DALOAD:
return Type.DOUBLE_TYPE;
case Opcodes.BALOAD:
return Type.BYTE_TYPE;
case Opcodes.CALOAD:
return Type.CHAR_TYPE;
case Opcodes.SALOAD:
return Type.SHORT_TYPE;
}
return Type.VOID_TYPE;
}
@Override
public void visitVarInsn(final int opcode, final int var) {
Type varType;
switch (opcode) {
case Opcodes.LLOAD:
case Opcodes.LSTORE:
varType = Type.LONG_TYPE;
break;
case Opcodes.DLOAD:
case Opcodes.DSTORE:
varType = Type.DOUBLE_TYPE;
break;
case Opcodes.FLOAD:
case Opcodes.FSTORE:
varType = Type.FLOAT_TYPE;
break;
case Opcodes.ILOAD:
case Opcodes.ISTORE:
varType = Type.INT_TYPE;
break;
case Opcodes.ALOAD:
case Opcodes.ASTORE:
case Opcodes.RET:
varType = OBJECT_TYPE;
break;
default:
throw new IllegalArgumentException("Invalid opcode " + opcode);
}
super.visitVarInsn(opcode, remap(var, varType));
}
@Override
public void apply(Map<String, ClassDefinition> definitions, ClassNode clazz) {
for (MethodNode method : (List<MethodNode>) clazz.methods) {
if (method.name.equals(methodDef.actualName) && method.desc.equals(methodDef.actualDesc)) {InsnList inject = new InsnList();
inject.add(new MethodInsnNode(INVOKESTATIC, "client", "getEventBus", "()L" + Events.class.getCanonicalName().replaceAll("\\.", "/") + ";"));
inject.add(new TypeInsnNode(NEW, PlayerMenuCreatedEvent.class.getCanonicalName().replaceAll("\\.", "/")));
inject.add(new InsnNode(Opcodes.DUP));
VarInsnNode player = null;
List<VarInsnNode> intInsns = new ArrayList<>();
for (int i = 0; i < methodDef.paramLoadOpcodes.size(); i++) {
if (methodDef.paramLoadOpcodes.get(i) == Opcodes.ALOAD) {
player = new VarInsnNode(Opcodes.ALOAD, i);
} else if (methodDef.paramLoadOpcodes.get(i) == Opcodes.ILOAD) {
intInsns.add(new VarInsnNode(Opcodes.ILOAD, i));
}
}
inject.add(player);
inject.add(new TypeInsnNode(Opcodes.CHECKCAST, IPlayer.class.getCanonicalName().replaceAll("\\.", "/")));
intInsns.forEach(inject::add);
inject.add(new MethodInsnNode(INVOKESPECIAL, PlayerMenuCreatedEvent.class.getCanonicalName().replaceAll("\\.", "/"), "<init>", "(L" + IPlayer.class.getCanonicalName().replaceAll("\\.", "/") + ";III)V"));
inject.add(new MethodInsnNode(INVOKEVIRTUAL, Events.class.getCanonicalName().replaceAll("\\.", "/"), "submitPlayerMenuCreatedEvent", "(L" + PlayerMenuCreatedEvent.class.getCanonicalName().replaceAll("\\.", "/") + ";)V"));
method.instructions.insertBefore(method.instructions.get(methodDef.insnToInjectBefore), inject);
method.visitEnd();
}
}
}
@Override
public void visitVarInsn(final int opcode, final int var) {
switch (opcode) {
case Opcodes.ILOAD:
load(var, Type.INT_TYPE);
break;
case Opcodes.LLOAD:
load(var, Type.LONG_TYPE);
break;
case Opcodes.FLOAD:
load(var, Type.FLOAT_TYPE);
break;
case Opcodes.DLOAD:
load(var, Type.DOUBLE_TYPE);
break;
case Opcodes.ALOAD:
load(var, OBJECT_TYPE);
break;
case Opcodes.ISTORE:
store(var, Type.INT_TYPE);
break;
case Opcodes.LSTORE:
store(var, Type.LONG_TYPE);
break;
case Opcodes.FSTORE:
store(var, Type.FLOAT_TYPE);
break;
case Opcodes.DSTORE:
store(var, Type.DOUBLE_TYPE);
break;
case Opcodes.ASTORE:
store(var, OBJECT_TYPE);
break;
case Opcodes.RET:
ret(var);
break;
default:
throw new IllegalArgumentException();
}
}
/**
* @param opcode
* @param var
* @param s
*/
static void handleVarInsn ( int opcode, int var, JVMStackState s ) {
Set<BaseType> v;
switch ( opcode ) {
case Opcodes.LLOAD:
case Opcodes.ILOAD:
case Opcodes.FLOAD:
case Opcodes.DLOAD:
case Opcodes.ALOAD:
v = s.getVariable(var);
if ( log.isTraceEnabled() ) {
log.trace("LOAD " + opcode + "@" + var + ":" + v); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
if ( v == null || v.isEmpty() ) {
s.push(new BasicVariable(toType(opcode), "unknown " + var, true)); //$NON-NLS-1$
}
else if ( v.size() == 1 ) {
s.push(v.iterator().next());
}
else {
Set<BaseType> alts = new HashSet<>();
for ( BaseType o : v ) {
if ( o instanceof MultiAlternatives && ! ( (MultiAlternatives) o ).getAlternatives().isEmpty() ) {
alts.addAll( ( (MultiAlternatives) o ).getAlternatives());
}
else {
alts.add(o);
}
}
s.push(new MultiAlternatives(alts));
}
break;
case Opcodes.LSTORE:
case Opcodes.ISTORE:
case Opcodes.FSTORE:
case Opcodes.DSTORE:
case Opcodes.ASTORE:
s.getVariable(var).add(s.pop());
break;
case Opcodes.RET:
break;
default:
log.warn("Unimplemented opcode " + opcode); //$NON-NLS-1$
}
}
public VarInsnNode() {
super(Opcodes.ALOAD);
}
@Override
public void appendInstruction(StringBuilder b) {
b.append(" ");
switch(opcode) {
case Opcodes.ILOAD:
b.append("(*SP).type = CN1_TYPE_INT; /* ILOAD */ \n" +
" (*SP).data.i = ilocals_");
b.append(var);
b.append("_; \n SP++;\n");
return;
case Opcodes.LLOAD:
b.append("BC_LLOAD(");
break;
case Opcodes.FLOAD:
b.append("BC_FLOAD(");
break;
case Opcodes.DLOAD:
b.append("BC_DLOAD(");
break;
case Opcodes.ALOAD:
b.append("BC_ALOAD(");
break;
case Opcodes.ISTORE:
b.append("BC_ISTORE(");
break;
case Opcodes.LSTORE:
b.append("BC_LSTORE(");
break;
case Opcodes.FSTORE:
b.append("BC_FSTORE(");
break;
case Opcodes.DSTORE:
b.append("BC_DSTORE(");
break;
case Opcodes.ASTORE:
b.append("BC_ASTORE(");
break;
case Opcodes.RET:
b.append("/* RET TODO */");
//b.append("goto label_");
//b.append(var);
//b.append("; /* RET */\n");
return;
case Opcodes.SIPUSH:
case Opcodes.BIPUSH:
b.append("PUSH_INT(");
break;
case Opcodes.NEWARRAY:
switch(var) {
case 4: // boolean
b.append("PUSH_OBJ(allocArray(threadStateData, POP_INT(), &class_array1__JAVA_BOOLEAN, sizeof(JAVA_ARRAY_BOOLEAN), 1));\n");
break;
case 5: // char
b.append("PUSH_OBJ(allocArray(threadStateData, POP_INT(), &class_array1__JAVA_CHAR, sizeof(JAVA_ARRAY_CHAR), 1));\n");
break;
case 6: // float
b.append("PUSH_OBJ(allocArray(threadStateData, POP_INT(), &class_array1__JAVA_FLOAT, sizeof(JAVA_ARRAY_FLOAT), 1));\n");
break;
case 7: // double
b.append("PUSH_OBJ(allocArray(threadStateData, POP_INT(), &class_array1__JAVA_DOUBLE, sizeof(JAVA_ARRAY_DOUBLE), 1));\n");
break;
case 8: // byte
b.append("PUSH_OBJ(allocArray(threadStateData, POP_INT(), &class_array1__JAVA_BYTE, sizeof(JAVA_ARRAY_BYTE), 1));\n");
break;
case 9: // short
b.append("PUSH_OBJ(allocArray(threadStateData, POP_INT(), &class_array1__JAVA_SHORT, sizeof(JAVA_ARRAY_SHORT), 1));\n");
break;
case 10: // int
b.append("PUSH_OBJ(allocArray(threadStateData, POP_INT(), &class_array1__JAVA_INT, sizeof(JAVA_ARRAY_INT), 1));\n");
break;
case 11: // long
b.append("PUSH_OBJ(allocArray(threadStateData, POP_INT(), &class_array1__JAVA_LONG, sizeof(JAVA_ARRAY_LONG), 1));\n");
break;
}
return;
default:
throw new RuntimeException("Missing opcode: " + opcode);
}
b.append(var);
b.append(");\n");
}
private static Map<String, String> checkMethods(ClassNode classNode, Set<String> names) {
Map<String, String> validGetters = Maps.newHashMap();
@SuppressWarnings("rawtypes")
List methods = classNode.methods;
String fieldName = null;
checkMethod:
for (Object methodObject : methods) {
MethodNode method = (MethodNode) methodObject;
if (names.contains(method.name)
&& method.desc.startsWith("()")) { //$NON-NLS-1$ // (): No arguments
InsnList instructions = method.instructions;
int mState = 1;
for (AbstractInsnNode curr = instructions.getFirst();
curr != null;
curr = curr.getNext()) {
switch (curr.getOpcode()) {
case -1:
// Skip label and line number nodes
continue;
case Opcodes.ALOAD:
if (mState == 1) {
fieldName = null;
mState = 2;
} else {
continue checkMethod;
}
break;
case Opcodes.GETFIELD:
if (mState == 2) {
FieldInsnNode field = (FieldInsnNode) curr;
fieldName = field.name;
mState = 3;
} else {
continue checkMethod;
}
break;
case Opcodes.ARETURN:
case Opcodes.FRETURN:
case Opcodes.IRETURN:
case Opcodes.DRETURN:
case Opcodes.LRETURN:
case Opcodes.RETURN:
if (mState == 3) {
validGetters.put(method.name, fieldName);
}
continue checkMethod;
default:
continue checkMethod;
}
}
}
}
return validGetters;
}
/**
* <p>
* Finds information about the ChainReducer.setReducer() &
* ChainReducer.addMapper() methods
* </p>
*
* @param min
* Method instruction node which represents the above methods
* @param isMapTask
* Whether the task is map or reduce
* @see ChainReducer#setReducer(JobConf, Class, Class, Class, Class, Class,
* boolean, JobConf)
* @see ChainReducer#addMapper(JobConf, Class, Class, Class, Class, Class,
* boolean, JobConf)
*/
private void preProcessChainedTask(MethodInsnNode min, boolean isMapTask) {
AbstractInsnNode ain = null;
// getting variable index of the task conf object
ain = min.getPrevious();
int taskConfIndex = getTaskJobConfIndex(ain);
InsnList insnToMove = null;
// if the task conf is passed as new JobConf() or using a method call,
// we need to move these instructions above, add a new local variable
// for
// the conf & pass this local variable to the method call
if (ain instanceof MethodInsnNode) {
addLocalJobConf(taskConfIndex);
// add a new VarInsnNode to load the new conf
AbstractInsnNode vin = new VarInsnNode(Opcodes.ALOAD, taskConfIndex);
instructions.insert(ain, vin);
insnToMove = deleteInsnsAndMove(ain);
// storing the value returned by the moved insn to the conf variable
insnToMove.add(new VarInsnNode(Opcodes.ASTORE, taskConfIndex));
// setting the newly added vin as the current node for further
// traversal, as we have removed the above ain node.
ain = vin;
}
// getting node which represents parameter for Mapper/Reducer class
AbstractInsnNode mrClassParamNode = getMRClassParamNode(ain);
Object mrClassParam = getMRClassParam(mrClassParamNode);
// getting variable index for Job Conf object
AbstractInsnNode jobNode = getJobConfNode(mrClassParamNode);
int jobVariableIndex = ((VarInsnNode) jobNode).var;
// insert the instructions to be moved
if (insnToMove != null) {
instructions.insertBefore(jobNode, insnToMove);
}
if (isMapTask) {
addMapJobAndTaskConfToIndex(taskConfIndex, mrClassParam, jobVariableIndex);
} else {
addReducerJobAndTaskConfToIndex(taskConfIndex, mrClassParam, jobVariableIndex);
}
}
private void pushProductOfIntArrayOnStack() {
Label beginScopeLabel = new Label();
Label endScopeLabel = new Label();
int dimsArrayIndex = newLocal("[I", beginScopeLabel, endScopeLabel);
int counterIndex = newLocal("I", beginScopeLabel, endScopeLabel);
int productIndex = newLocal("I", beginScopeLabel, endScopeLabel);
Label loopLabel = new Label();
Label endLabel = new Label();
super.visitLabel(beginScopeLabel);
// stack: ... intArray
super.visitVarInsn(Opcodes.ASTORE, dimsArrayIndex);
// -> stack: ...
// counter = 0
super.visitInsn(Opcodes.ICONST_0);
super.visitVarInsn(Opcodes.ISTORE, counterIndex);
// product = 1
super.visitInsn(Opcodes.ICONST_1);
super.visitVarInsn(Opcodes.ISTORE, productIndex);
// loop:
super.visitLabel(loopLabel);
// if index >= arraylength goto end:
super.visitVarInsn(Opcodes.ILOAD, counterIndex);
super.visitVarInsn(Opcodes.ALOAD, dimsArrayIndex);
super.visitInsn(Opcodes.ARRAYLENGTH);
super.visitJumpInsn(Opcodes.IF_ICMPGE, endLabel);
// product = product * max(array[counter],1)
super.visitVarInsn(Opcodes.ALOAD, dimsArrayIndex);
super.visitVarInsn(Opcodes.ILOAD, counterIndex);
super.visitInsn(Opcodes.IALOAD);
super.visitInsn(Opcodes.DUP);
Label nonZeroDimension = new Label();
super.visitJumpInsn(Opcodes.IFNE, nonZeroDimension);
super.visitInsn(Opcodes.POP);
super.visitInsn(Opcodes.ICONST_1);
super.visitLabel(nonZeroDimension);
super.visitVarInsn(Opcodes.ILOAD, productIndex);
super.visitInsn(Opcodes.IMUL); // if overflow happens it happens.
super.visitVarInsn(Opcodes.ISTORE, productIndex);
// iinc counter 1
super.visitIincInsn(counterIndex, 1);
// goto loop
super.visitJumpInsn(Opcodes.GOTO, loopLabel);
// end:
super.visitLabel(endLabel);
// re-push dimensions array
super.visitVarInsn(Opcodes.ALOAD, dimsArrayIndex);
// push product
super.visitVarInsn(Opcodes.ILOAD, productIndex);
super.visitLabel(endScopeLabel);
}
public void visitVarInsn(final int opcode, final int var) {
switch (opcode) {
case Opcodes.ILOAD :
load(var, JavaType.INT);
break;
case Opcodes.LLOAD :
load(var, JavaType.LONG);
break;
case Opcodes.FLOAD :
load(var, JavaType.FLOAT);
break;
case Opcodes.DLOAD :
load(var, JavaType.DOUBLE);
break;
case Opcodes.ALOAD :
load(var, JavaType.OBJECT);
break;
case Opcodes.ISTORE :
store(var, JavaType.INT);
break;
case Opcodes.LSTORE :
store(var, JavaType.LONG);
break;
case Opcodes.FSTORE :
store(var, JavaType.FLOAT);
break;
case Opcodes.DSTORE :
store(var, JavaType.DOUBLE);
break;
case Opcodes.ASTORE :
store(var, JavaType.OBJECT);
break;
case Opcodes.RET :
recorder.add(new Runnable() {
public void run() {
block.addOp(new RetSub(lineNumber));
}
});
break;
default :
throw new UnsupportedOperationException("opcode: " + opcode);
}
}