List of usage examples for org.objectweb.asm.tree MethodNode MethodNode
public MethodNode()
From source file:org.lenskit.data.entities.AbstractBeanEntityBuilder.java
License:Open Source License
private static MethodNode generateLongSetter(Class<? extends AbstractBeanEntityBuilder> type, Method smethod) { MethodNode setter = new MethodNode(); setter.access = ACC_PUBLIC;//from w ww.j av a2s.c o m setter.desc = getMethodDescriptor(VOID_TYPE, getType(AbstractBeanEntityBuilder.class), getType(long.class)); setter.name = "set"; setter.exceptions = Collections.emptyList(); setter.maxLocals = 4; setter.maxStack = 3; // load target object setter.visitVarInsn(ALOAD, 1); // cast target object setter.visitTypeInsn(CHECKCAST, getInternalName(type)); // load attribute value setter.visitVarInsn(LLOAD, 2); // call real setter setter.visitMethodInsn(INVOKEVIRTUAL, getInternalName(type), smethod.getName(), getMethodDescriptor(smethod), false); setter.visitInsn(RETURN); return setter; }
From source file:org.lenskit.data.entities.AbstractBeanEntityBuilder.java
License:Open Source License
private static MethodNode generateDoubleSetter(Class<? extends AbstractBeanEntityBuilder> type, Method smethod) {//from w ww . ja v a2 s . c om MethodNode setter = new MethodNode(); setter.access = ACC_PUBLIC; setter.desc = getMethodDescriptor(VOID_TYPE, getType(AbstractBeanEntityBuilder.class), getType(double.class)); setter.name = "set"; setter.exceptions = Collections.emptyList(); setter.maxLocals = 4; setter.maxStack = 3; // load target object setter.visitVarInsn(ALOAD, 1); // cast target object setter.visitTypeInsn(CHECKCAST, getInternalName(type)); // load attribute value setter.visitVarInsn(DLOAD, 2); // call real setter setter.visitMethodInsn(INVOKEVIRTUAL, getInternalName(type), smethod.getName(), getMethodDescriptor(smethod), false); setter.visitInsn(RETURN); return setter; }
From source file:org.lenskit.data.entities.AbstractBeanEntityBuilder.java
License:Open Source License
private static MethodNode generateClearer(Class<? extends AbstractBeanEntityBuilder> type, Method smethod, Method cmethod) {/*from w w w . java 2 s . co m*/ MethodNode clearer = new MethodNode(); clearer.access = ACC_PUBLIC; clearer.desc = getMethodDescriptor(VOID_TYPE, getType(AbstractBeanEntityBuilder.class)); clearer.name = "clear"; clearer.exceptions = Collections.emptyList(); clearer.maxLocals = 2; clearer.maxStack = 1; if (cmethod != null) { // load target object clearer.visitVarInsn(ALOAD, 1); // cast to target object type clearer.visitTypeInsn(CHECKCAST, getInternalName(type)); // call clearer method clearer.visitMethodInsn(INVOKEVIRTUAL, getInternalName(type), cmethod.getName(), getMethodDescriptor(cmethod), false); clearer.visitInsn(RETURN); } else if (!smethod.getParameterTypes()[0].isPrimitive()) { // load target object & cast to type clearer.visitVarInsn(ALOAD, 1); clearer.visitTypeInsn(CHECKCAST, getInternalName(type)); // load null and call setter clearer.visitInsn(ACONST_NULL); clearer.maxStack = 2; clearer.visitMethodInsn(INVOKEVIRTUAL, getInternalName(type), smethod.getName(), getMethodDescriptor(smethod), false); clearer.visitInsn(RETURN); } else { // no clearer and primitive method, throw unsupported operation exception clearer.maxStack = 2; clearer.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException"); clearer.visitInsn(DUP); clearer.visitMethodInsn(INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "()V", false); clearer.visitInsn(ATHROW); } return clearer; }
From source file:pl.clareo.coroutines.core.ClassTransformer.java
License:Apache License
@SuppressWarnings("unchecked") void transform() { for (MethodNode coroutine : coroutines) { if (log.isLoggable(Level.FINEST)) { log.finest("Generating method for coroutine " + coroutine.name + coroutine.desc); }/* w ww . j a va 2 s . c om*/ String coroutineName = getCoroutineName(coroutine); MethodTransformer methodTransformer = new MethodTransformer(coroutine, thisType); MethodNode coroutineImpl = methodTransformer.transform(coroutineName, generateDebugCode); thisNode.methods.add(coroutineImpl); /* * generate co iterators and method stubs */ log.finest("Generating CoIterator implementation and method stubs"); String baseCoIteratorName; Map<String, Object> annotation = getCoroutineAnnotationValues(coroutine); if (getBoolean(annotation, "threadLocal")) { baseCoIteratorName = Type.getInternalName(ThreadLocalCoIterator.class); } else { baseCoIteratorName = Type.getInternalName(SingleThreadedCoIterator.class); } String coIteratorClassName = "pl/clareo/coroutines/core/CoIterator" + num; ClassNode coIteratorClass = new ClassNode(); coIteratorClass.version = Opcodes.V1_6; coIteratorClass.access = Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_SUPER; coIteratorClass.name = coIteratorClassName; coIteratorClass.superName = baseCoIteratorName; if (generateDebugCode) { /* * If debugging code is emitted create field keeping JDK logger */ FieldNode loggerField = new FieldNode(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "logger", "Ljava/util/logging/Logger;", null, null); coIteratorClass.fields.add(loggerField); MethodNode clinit = new MethodNode(); clinit.access = Opcodes.ACC_STATIC; clinit.name = "<clinit>"; clinit.desc = "()V"; clinit.exceptions = Collections.EMPTY_LIST; String loggerName = thisType.getClassName(); InsnList clinitCode = clinit.instructions; clinitCode.add(new LdcInsnNode(loggerName)); clinitCode.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/util/logging/Logger", "getLogger", "(Ljava/lang/String;)Ljava/util/logging/Logger;")); clinitCode.add(new FieldInsnNode(Opcodes.PUTSTATIC, coIteratorClassName, "logger", "Ljava/util/logging/Logger;")); clinitCode.add(new InsnNode(Opcodes.RETURN)); clinit.maxStack = 1; clinit.maxLocals = 0; coIteratorClass.methods.add(clinit); } /* * Generate constructor */ MethodNode init = new MethodNode(); init.access = Opcodes.ACC_PUBLIC; init.name = "<init>"; init.desc = CO_ITERATOR_CONSTRUCTOR_DESCRIPTOR; init.exceptions = Collections.EMPTY_LIST; InsnList initCode = init.instructions; initCode.add(new VarInsnNode(Opcodes.ALOAD, 0)); initCode.add(new VarInsnNode(Opcodes.ALOAD, 1)); initCode.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, baseCoIteratorName, "<init>", CO_ITERATOR_CONSTRUCTOR_DESCRIPTOR)); initCode.add(new InsnNode(Opcodes.RETURN)); init.maxStack = 2; init.maxLocals = 2; coIteratorClass.methods.add(init); /* * Generate overriden call to coroutine */ MethodNode call = new MethodNode(); call.access = Opcodes.ACC_PROTECTED; call.name = "call"; call.desc = CALL_METHOD_DESCRIPTOR; call.exceptions = Collections.EMPTY_LIST; InsnList callCode = call.instructions; /* * if debug needed generate call details */ if (generateDebugCode) { String coroutineId = "Coroutine " + coroutine.name; callCode.add(loggingInstructions(coIteratorClassName, "logger", Level.FINER, coroutineId + " call. Caller sent: ", 2)); callCode.add(new FrameNode(Opcodes.F_SAME, 0, EMPTY_LOCALS, 0, EMPTY_STACK)); callCode.add(loggingInstructions(coIteratorClassName, "logger", Level.FINEST, coroutineId + " state ", 1)); callCode.add(new FrameNode(Opcodes.F_SAME, 0, EMPTY_LOCALS, 0, EMPTY_STACK)); } /* * push call arguments: this (if not static), frame, input, output */ boolean isStatic = (coroutine.access & Opcodes.ACC_STATIC) != 0; if (!isStatic) { callCode.add(new VarInsnNode(Opcodes.ALOAD, 1)); callCode.add( new MethodInsnNode(Opcodes.INVOKEVIRTUAL, FRAME_NAME, "getThis", "()Ljava/lang/Object;")); callCode.add(new TypeInsnNode(Opcodes.CHECKCAST, thisType.getInternalName())); } callCode.add(new VarInsnNode(Opcodes.ALOAD, 1)); callCode.add(new InsnNode(Opcodes.ACONST_NULL)); callCode.add(new VarInsnNode(Opcodes.ALOAD, 2)); callCode.add(new MethodInsnNode(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, thisType.getInternalName(), coroutineName, COROUTINE_METHOD_DESCRIPTOR)); // stack: * if (!generateDebugCode) { callCode.add(new InsnNode(Opcodes.ARETURN)); } else { // save result display suspension point (two more locals // needed) callCode.add(new VarInsnNode(Opcodes.ASTORE, 3)); callCode.add(new VarInsnNode(Opcodes.ALOAD, 1)); callCode.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, FRAME_NAME, "getLineOfCode", "()I")); callCode.add(box_int(Type.INT)); callCode.add(new VarInsnNode(Opcodes.ASTORE, 4)); callCode.add(loggingInstructions(coIteratorClassName, "logger", Level.FINER, "Coroutine suspended at line ", 4, ". Yielded:", 3)); callCode.add(new FrameNode(Opcodes.F_APPEND, 2, new Object[] { "java/lang/Object", "java/lang/Integer" }, 0, EMPTY_STACK)); callCode.add(new VarInsnNode(Opcodes.ALOAD, 3)); callCode.add(new InsnNode(Opcodes.ARETURN)); } coIteratorClass.methods.add(call); // if debugging code is emitted it needs space for two // additional locals and 5 stack operand if (generateDebugCode) { call.maxStack = 5; call.maxLocals = 5; } else { if (isStatic) { call.maxStack = 3; } else { call.maxStack = 4; } call.maxLocals = 3; } /* * CoIterator created - define it in the runtime and verify if * needed */ if (log.isLoggable(Level.FINEST)) { log.finest("Generated class " + coIteratorClassName); } ClassWriter cw = new ClassWriter(0); coIteratorClass.accept(cw); byte[] classBytes = cw.toByteArray(); try { CoroutineInstrumentator.dumpClass(coIteratorClassName, classBytes); } catch (IOException e) { throw new CoroutineGenerationException("Unable to write class " + coIteratorClassName, e); } /* * start generating method - new method is named as the method in * user code, it: returns instance of appropriate CoIterator (see * above), saves arguments of call */ if (log.isLoggable(Level.FINEST)) { log.finest("Instrumenting method " + coroutine.name); } InsnList code = coroutine.instructions; code.clear(); /* * create new Frame */ boolean isDebugFramePossible = generateDebugCode && coroutine.localVariables != null; if (isDebugFramePossible) { code.add(createDebugFrame(coroutine)); } else { code.add(createFrame(coroutine)); } /* * save frame in the first, and locals array in the second local * variable */ int argsSize = Type.getArgumentsAndReturnSizes(coroutine.desc) >> 2; if (isStatic) { argsSize -= 1; } code.add(new VarInsnNode(Opcodes.ASTORE, argsSize)); code.add(new VarInsnNode(Opcodes.ALOAD, argsSize)); code.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, FRAME_NAME, "getLocals", "()[Ljava/lang/Object;")); int localsArrayIndex = argsSize + 1; code.add(new VarInsnNode(Opcodes.ASTORE, localsArrayIndex)); /* * save all call arguments (along with this if this method is not * static) into locals array */ Type[] argsTypes = Type.getArgumentTypes(coroutine.desc); if (!isStatic) { code.add(saveloc(localsArrayIndex, 0, 0, JAVA_LANG_OBJECT)); code.add(savelocs(localsArrayIndex, 1, 1, argsTypes)); } else { code.add(savelocs(localsArrayIndex, 0, 0, argsTypes)); } /* * create CoIterator instance with saved frame, make initial call to * next if needed and return to caller */ code.add(new TypeInsnNode(Opcodes.NEW, coIteratorClassName)); code.add(new InsnNode(Opcodes.DUP)); code.add(new VarInsnNode(Opcodes.ALOAD, argsSize)); code.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, coIteratorClassName, "<init>", CO_ITERATOR_CONSTRUCTOR_DESCRIPTOR)); if (!getBoolean(annotation, "generator", true)) { code.add(new InsnNode(Opcodes.DUP)); code.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, coIteratorClassName, "next", "()Ljava/lang/Object;")); code.add(new InsnNode(Opcodes.POP)); } code.add(new InsnNode(Opcodes.ARETURN)); /* * end method generation; maxs can be statically determined 3 * operands on stack (call to frame setLocals and CoIterator * constructor) + 1 if any argument is long or double (debug frame * needs 7 operands for variable names creation); locals = argsSize * + 1 reference to frame + 1 array of locals */ if (isDebugFramePossible) { coroutine.maxStack = 7; } else { boolean isCategory2ArgumentPresent = false; for (Type argType : argsTypes) { int sort = argType.getSort(); if (sort == Type.LONG || sort == Type.DOUBLE) { isCategory2ArgumentPresent = true; break; } } coroutine.maxStack = isCategory2ArgumentPresent ? 4 : 3; } coroutine.maxLocals = localsArrayIndex + 1; coroutine.localVariables.clear(); coroutine.tryCatchBlocks.clear(); num++; } }
From source file:pl.clareo.coroutines.core.MethodTransformer.java
License:Apache License
@SuppressWarnings("unchecked") MethodNode transform(String coroutineName, boolean generateDebugCode) { MethodNode transformedMethod = new MethodNode(); transformedMethod.access = ACC_PUBLIC | ACC_FINAL | (method.access & ACC_STATIC); transformedMethod.name = coroutineName; transformedMethod.desc = COROUTINE_METHOD_DESCRIPTOR; transformedMethod.exceptions = method.exceptions; final InsnList newCode = transformedMethod.instructions; Analyzer analyzer = new Analyzer(new BasicInterpreter() { @Override//from w w w . jav a 2 s. c o m public Value binaryOperation(AbstractInsnNode insn, Value value1, Value value2) throws AnalyzerException { if (insn.getOpcode() == AALOAD) { return new BasicValue(((BasicValue) value1).getType().getElementType()); } return super.binaryOperation(insn, value1, value2); }; @Override public Value merge(Value v, Value w) { if (v == NULL_VALUE) { BasicValue w1 = (BasicValue) w; if (w1.isReference()) { return w1; } } if (w == NULL_VALUE) { BasicValue v1 = (BasicValue) v; if (v1.isReference()) return v1; } if (!v.equals(w)) { BasicValue v1 = (BasicValue) v; BasicValue w1 = (BasicValue) w; if (v1.isReference() & w1.isReference()) { Class<?> c1; Class<?> c2; try { c1 = MethodTransformer.getClass(v1); c2 = MethodTransformer.getClass(w1); } catch (ClassNotFoundException e) { throw new CoroutineGenerationException( "It was needed to load a class during transformation process but loading unexpectedly failed", e); } if (c1.isAssignableFrom(c2)) { return v; } if (c2.isAssignableFrom(c1)) { return w; } } } else { return v; } return BasicValue.UNINITIALIZED_VALUE; } @Override public Value newValue(Type type) { if (type != null) { int typeSort = type.getSort(); switch (typeSort) { case Type.VOID: return NULL_VALUE; case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: return BasicValue.INT_VALUE; case Type.FLOAT: return BasicValue.FLOAT_VALUE; case Type.LONG: return BasicValue.LONG_VALUE; case Type.DOUBLE: return BasicValue.DOUBLE_VALUE; case Type.ARRAY: case Type.OBJECT: if (type.getInternalName().equals("null")) { return NULL_VALUE; } return new BasicValue(type); default: throw new Error("Internal error"); } } return BasicValue.UNINITIALIZED_VALUE; } }); Frame[] frames; try { frames = analyzer.analyze(methodOwner, method); } catch (AnalyzerException e) { throw new CoroutineGenerationException(e); } InsnList code = method.instructions; final List<Integer> yields = new ArrayList<Integer>(8); /* * Copy instructions patching variable indexes and frames, remember * yield indexes */ int ic = 0; Iterator<AbstractInsnNode> i = code.iterator(); while (i.hasNext()) { AbstractInsnNode insn = i.next(); switch (insn.getType()) { case AbstractInsnNode.FRAME: FrameNode frame = (FrameNode) insn.clone(labelsMap); // update values if (frame.type == F_FULL) { if (isStatic) { frame.local.addAll(0, argsStackMapList); } else { frame.local.addAll(1, argsStackMapList); } } newCode.add(frame); break; case AbstractInsnNode.IINC_INSN: IincInsnNode iinc = (IincInsnNode) insn.clone(labelsMap); iinc.var += variableIndexOffset; newCode.add(iinc); break; case AbstractInsnNode.INSN: switch (insn.getOpcode()) { case DRETURN: case FRETURN: case IRETURN: case LRETURN: case ARETURN: case RETURN: newCode.add(new InsnNode(POP)); newCode.add(throwex("java/util/NoSuchElementException")); break; default: newCode.add(insn.clone(labelsMap)); } break; case AbstractInsnNode.JUMP_INSN: if (insn.getOpcode() == JSR) { throw new CoroutineGenerationException("<jsr> not allowed"); } JumpInsnNode jump = (JumpInsnNode) insn; LabelNode target = jump.label; if (!labelsMap.containsKey(target)) { labelsMap.put(target, new LabelNode()); } newCode.add(jump.clone(labelsMap)); break; case AbstractInsnNode.LABEL: if (!labelsMap.containsKey(insn)) { labelsMap.put((LabelNode) insn, new LabelNode()); } newCode.add(insn.clone(labelsMap)); break; case AbstractInsnNode.METHOD_INSN: if (insn.getOpcode() == INVOKESTATIC) { MethodInsnNode method = (MethodInsnNode) insn; if (method.owner.equals(COROUTINES_NAME)) { String methodName = method.name; if (methodName.equals("_")) { /* * a call to artificial CoIterator, since it is * not needed after instrumentation we replace * it with null. This null will be popped by * corresponding ARETURN. Stack is not changed */ newCode.add(new InsnNode(ACONST_NULL)); break; } if (methodName.equals("yield")) { /* * a call to yield - core of coroutine * processing */ yields.add(ic); } } } newCode.add(insn.clone(labelsMap)); break; case AbstractInsnNode.VAR_INSN: if (insn.getOpcode() == RET) { throw new CoroutineGenerationException("<ret> not allowed"); } VarInsnNode var = (VarInsnNode) insn.clone(labelsMap); if (var.var != 0 || isStatic) { var.var += variableIndexOffset; } newCode.add(var); break; default: newCode.add(insn.clone(labelsMap)); break; } ic += 1; } /* * patch yields in transformed code */ final List<LabelNode> gotos = new ArrayList<LabelNode>(9); final Set<TryCatchBlockNode> patchedTryCatchBlocks = new HashSet<TryCatchBlockNode>(); int yieldIndex = 0; i = newCode.iterator(); while (i.hasNext()) { AbstractInsnNode insn = i.next(); /* * track locals */ int insnType = insn.getType(); if (insnType == AbstractInsnNode.VAR_INSN) { int opcode = insn.getOpcode(); if (opcode == ASTORE || opcode == DSTORE || opcode == LSTORE || opcode == ISTORE || opcode == FSTORE) { int varIndex = ((VarInsnNode) insn).var - variableIndexOffset; finals[varIndex] = false; } continue; } /* * track line numbers */ if (insnType == AbstractInsnNode.LINE) { lineNumber = ((LineNumberNode) insn).line; continue; } if (insnType != AbstractInsnNode.METHOD_INSN) { continue; } MethodInsnNode method = (MethodInsnNode) insn; if (!method.owner.equals(COROUTINES_NAME) || !method.name.equals("yield")) { continue; } InsnList yieldCode = new InsnList(); int index = yields.get(yieldIndex); Frame f = frames[index]; /* * a) operand on the top of stack is passed to the caller, we will * save it in 'in' parameter OR there is nothing to be passed to the * caller in case of yield() overload */ boolean yieldWithArgument = Type.getArgumentTypes(method.desc).length != 0; boolean nonemptyStack; Type[] stackContents = null; int stackTop = 0; if (yieldWithArgument) { yieldCode.add(input(getStackTop(f))); nonemptyStack = f.getStackSize() > 1; stackTop = 1; } else { nonemptyStack = f.getStackSize() > 0; } /* * b) save remaining stack */ if (nonemptyStack) { stackContents = getStackContents(f); // sanitize stack for (Type t : stackContents) { if (t == null) { throw new CoroutineGenerationException( "It is not possible to yield with uninitialized memory on the stack. Probably you use construct such as: new A(..,yield,..). Please move this yield call out of constructor"); } } yieldCode.add(savestack(frame, stackContents, stackTop)); } /* * c) save locals and state */ Type[] locals = getLocals(f); yieldCode.add(saveLocals(locals)); yieldCode.add(new VarInsnNode(ALOAD, frame)); yieldCode.add(makeInt(++yieldIndex)); yieldCode.add(new MethodInsnNode(INVOKEVIRTUAL, FRAME_NAME, "setState", "(I)V")); /* * d) jump to exit - in debug mode save line number */ if (generateDebugCode) { yieldCode.add(new VarInsnNode(ALOAD, frame)); yieldCode.add(makeInt(lineNumber)); yieldCode.add(new MethodInsnNode(INVOKEVIRTUAL, FRAME_NAME, "setLineOfCode", "(I)V")); } yieldCode.add(new JumpInsnNode(GOTO, yieldLabel)); /* * e) fix jump from switch statement */ LabelNode jump = new LabelNode(); gotos.add(jump); yieldCode.add(jump); yieldCode.add(emitCleanFrame()); /* * f) check if exit condition occurs, load locals, restore stack and * stack map */ yieldCode.add(new VarInsnNode(ALOAD, frame)); yieldCode.add(new MethodInsnNode(INVOKEVIRTUAL, FRAME_NAME, "isCoroutineClosed", "()Z")); LabelNode continueHere = new LabelNode(); yieldCode.add(new JumpInsnNode(IFEQ, continueHere)); yieldCode.add(throwex(COROUTINE_EXIT_EXCEPTION)); yieldCode.add(continueHere); yieldCode.add(new FrameNode(F_SAME, 0, EMPTY_LOCALS, 0, EMPTY_STACK)); /* * find previous frame node, load locals then emit new frame node * and load rest */ FrameNode prevFrame = findPreviousFrame(code.get(index)); Type[] prevLocals; if (prevFrame != null) { Frame oldFrame = frames[code.indexOf(prevFrame)]; prevLocals = getLocals(oldFrame); } else { prevLocals = getLocals(frames[0]); } yieldCode.add(restoreLocals(prevLocals)); FrameNode frameNode = mergeFrames(getFrameTypes(prevLocals), null); if (frameNode.type != F_SAME) { // bug fix - when no locals are restored and the stack is empty // two frames are collapsed yieldCode.add(frameNode); } if (nonemptyStack) { yieldCode.add(loadstack(frame, stackContents, stackTop)); } // restore temp locals in scope yieldCode.add(restoreLocals(diff(locals, prevLocals))); /* * push "sent" value */ yieldCode.add(new VarInsnNode(ALOAD, out)); newCode.insertBefore(method, yieldCode); /* * patch try catch blocks */ List<TryCatchBlockNode> tryCatchBlocks = analyzer.getHandlers(index); if (tryCatchBlocks != null) { for (TryCatchBlockNode tryCatchBlock : tryCatchBlocks) { if (!patchedTryCatchBlocks.contains(tryCatchBlock)) { LabelNode handler = tryCatchBlock.handler; InsnList handlerPatch = new InsnList(); String exceptionType = tryCatchBlock.type == null ? "java/lang/Throwable" : tryCatchBlock.type; FrameNode catchFrame = emitCatchFrame(exceptionType); handlerPatch.add(catchFrame); Type[] ls = getLocals(frames[code.indexOf(handler)]); handlerPatch.add(restoreLocals(ls)); handlerPatch.add( mergeFrames(getFrameTypes(ls), new Type[] { Type.getObjectType(exceptionType) })); patchedTryCatchBlocks.add(tryCatchBlock); AbstractInsnNode newHandler = labelsMap.get(handler); // remove "real" frame since it is not needed now newCode.remove(findNextFrame(newHandler)); newCode.insert(newHandler, handlerPatch); } } } newCode.remove(method); } /* * copy local variables (wath out for indices change) and try catch * blocks to new method (clone) */ List<TryCatchBlockNode> tryCatchBlocks = method.tryCatchBlocks; if (!tryCatchBlocks.isEmpty()) { transformedMethod.tryCatchBlocks = new ArrayList<TryCatchBlockNode>(tryCatchBlocks.size()); for (TryCatchBlockNode tryCatchBlock : tryCatchBlocks) { transformedMethod.tryCatchBlocks.add( new TryCatchBlockNode(labelsMap.get(tryCatchBlock.start), labelsMap.get(tryCatchBlock.end), labelsMap.get(tryCatchBlock.handler), tryCatchBlock.type)); } } if (method.localVariables != null) { List<LocalVariableNode> localVariables = method.localVariables; List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>(localVariables.size()); for (LocalVariableNode localVariable : localVariables) { int newIndex = localVariable.index; if (newIndex != 0 || isStatic) { newIndex += variableIndexOffset; } newLocalVariables .add(new LocalVariableNode(localVariable.name, localVariable.desc, localVariable.signature, labelsMap.get(localVariable.start), labelsMap.get(localVariable.end), newIndex)); } transformedMethod.localVariables = newLocalVariables; } newCode.insert(codeBefore(gotos)); newCode.add(codeAfter()); return transformedMethod; }