List of usage examples for org.objectweb.asm.tree AbstractInsnNode clone
public abstract AbstractInsnNode clone(Map<LabelNode, LabelNode> clonedLabels);
From source file:org.coldswap.asm.field.ProtectedStaticFieldReplacer.java
License:Open Source License
/** * Removes any initializing reference of the field. * * @param classNode containing the old class. * @param fieldNode containing the old field. * @param canRemove <code>true</code> if this method should remove the initializing code and return it * or <code>false</code> if you only want to return the init code. * @return the initializing list of instructions. */// w w w . j a v a2 s . com @SuppressWarnings("unchecked") private InsnList cleanClInit(ClassNode classNode, FieldNode fieldNode, boolean canRemove) { List<MethodNode> methodNodes = classNode.methods; AbstractInsnNode firstInst = null; int counter = 0; for (MethodNode methodNode : methodNodes) { if (methodNode.name.equals("<clinit>")) { // search for PUTSTATIC InsnList insnList = methodNode.instructions; Iterator iterator1 = insnList.iterator(); while (iterator1.hasNext()) { AbstractInsnNode ins2 = (AbstractInsnNode) iterator1.next(); // if a initializing has been found, then copy everything from // the coresponding label to the PUTSTATIC if (ins2.getOpcode() == Opcodes.PUTSTATIC) { final Boolean[] fieldFound = { false }; final FieldNode fNode = fieldNode; ins2.accept(new MethodVisitor(Opcodes.ASM5) { @Override public void visitFieldInsn(int i, String s, String s2, String s3) { if (s2.equals(fNode.name)) { fieldFound[0] = true; } super.visitFieldInsn(i, s, s2, s3); } }); if (fieldFound[0]) { // find the first PUTSTATIC before this one. boolean staticFound = false; while (!staticFound) { AbstractInsnNode tmpInst = ins2.getPrevious(); if (tmpInst != null) { if (tmpInst.getOpcode() != Opcodes.F_NEW) { if (tmpInst.getOpcode() == Opcodes.PUTSTATIC) { staticFound = true; } else { firstInst = tmpInst; counter++; } } } else { staticFound = true; } ins2 = tmpInst; } break; } } } if (firstInst != null) { InsnList iList = new InsnList(); iList.add(firstInst.clone(null)); counter--; while (counter > 0) { AbstractInsnNode ain = firstInst.getNext(); iList.add(ain.clone(null)); counter--; if (canRemove) { insnList.remove(firstInst); } firstInst = ain; } if (canRemove) { // remove last instruction and the putstatic instruction AbstractInsnNode putStatic = firstInst.getNext(); insnList.remove(firstInst); insnList.remove(putStatic); } return iList; } } } return null; }
From source file:pku.sei.checkedcoverage.tracer.instrumentation.PauseTracingInstrumenter.java
License:Creative Commons License
@SuppressWarnings("unchecked") public void transformMethod(final MethodNode method, final ListIterator<MethodNode> methodIt, final String className) { if ((method.access & ACC_ABSTRACT) != 0 || (method.access & ACC_NATIVE) != 0) return;/* ww w .ja v a 2 s. c om*/ int tracerLocalVarIndex = (method.access & Opcodes.ACC_STATIC) == 0 ? 1 : 0; for (final Type t : Type.getArgumentTypes(method.desc)) tracerLocalVarIndex += t.getSize(); // increment number of local variables by one (for the threadtracer) ++method.maxLocals; // and increment all local variable indexes after the new one by one for (final Object o : method.localVariables) { final LocalVariableNode localVar = (LocalVariableNode) o; if (localVar.index >= tracerLocalVarIndex) ++localVar.index; } final LabelNode l0 = new LabelNode(); final LabelNode l1 = new LabelNode(); final ListIterator<AbstractInsnNode> insnIt = method.instructions.iterator(); insnIt.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(Tracer.class), "getInstance", "()L" + Type.getInternalName(Tracer.class) + ";")); insnIt.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(Tracer.class), "getThreadTracer", "()L" + Type.getInternalName(ThreadTracer.class) + ";")); insnIt.add(new InsnNode(DUP)); insnIt.add(new VarInsnNode(ASTORE, tracerLocalVarIndex)); insnIt.add(new MethodInsnNode(INVOKEINTERFACE, Type.getInternalName(ThreadTracer.class), "pauseTracing", "()V")); insnIt.add(l0); while (insnIt.hasNext()) { final AbstractInsnNode insn = insnIt.next(); switch (insn.getType()) { case AbstractInsnNode.INSN: switch (insn.getOpcode()) { case IRETURN: case LRETURN: case FRETURN: case DRETURN: case ARETURN: case RETURN: insnIt.previous(); insnIt.add(new VarInsnNode(ALOAD, tracerLocalVarIndex)); insnIt.add(new MethodInsnNode(INVOKEINTERFACE, Type.getInternalName(ThreadTracer.class), "resumeTracing", "()V")); insnIt.next(); } break; case AbstractInsnNode.IINC_INSN: if (((IincInsnNode) insn).var >= tracerLocalVarIndex) ++((IincInsnNode) insn).var; break; case AbstractInsnNode.VAR_INSN: if (((VarInsnNode) insn).var >= tracerLocalVarIndex) ++((VarInsnNode) insn).var; break; default: break; } } method.instructions.add(l1); method.instructions.add(new VarInsnNode(ALOAD, tracerLocalVarIndex)); method.instructions.add(new MethodInsnNode(INVOKEINTERFACE, Type.getInternalName(ThreadTracer.class), "resumeTracing", "()V")); method.instructions.add(new InsnNode(ATHROW)); method.tryCatchBlocks.add(new TryCatchBlockNode(l0, l1, l1, null)); // finally: create a copy of the method that gets the ThreadTracer as argument if (!"<clinit>".equals(method.name) && this.tracer.wasRedefined(className)) { final Type[] oldMethodArguments = Type.getArgumentTypes(method.desc); final Type[] newMethodArguments = Arrays.copyOf(oldMethodArguments, oldMethodArguments.length + 1); newMethodArguments[oldMethodArguments.length] = Type.getType(ThreadTracer.class); final String newMethodDesc = Type.getMethodDescriptor(Type.getReturnType(method.desc), newMethodArguments); final MethodNode newMethod = new MethodNode(method.access, method.name, newMethodDesc, method.signature, (String[]) method.exceptions.toArray(new String[method.exceptions.size()])); methodIt.add(newMethod); final Map<LabelNode, LabelNode> newMethodLabels = LazyMap.decorate(new HashMap<LabelNode, LabelNode>(), new Factory() { public Object create() { return new LabelNode(); } }); // copy the local variables information to the new method for (final Object o : method.localVariables) { final LocalVariableNode lv = (LocalVariableNode) o; newMethod.localVariables.add(new LocalVariableNode(lv.name, lv.desc, lv.signature, newMethodLabels.get(lv.start), newMethodLabels.get(lv.end), lv.index)); } newMethod.maxLocals = method.maxLocals; newMethod.maxStack = method.maxStack; // copy the try-catch-blocks for (final Object o : method.tryCatchBlocks) { final TryCatchBlockNode tcb = (TryCatchBlockNode) o; newMethod.tryCatchBlocks.add(new TryCatchBlockNode(newMethodLabels.get(tcb.start), newMethodLabels.get(tcb.end), newMethodLabels.get(tcb.handler), tcb.type)); } // skip the first 4 instructions, replace them with this: newMethod.instructions.add(new VarInsnNode(ALOAD, tracerLocalVarIndex)); final Iterator<AbstractInsnNode> oldInsnIt = method.instructions.iterator(4); // and add all the other instructions while (oldInsnIt.hasNext()) { final AbstractInsnNode insn = oldInsnIt.next(); newMethod.instructions.add(insn.clone(newMethodLabels)); } } }
From source file:pku.sei.checkedcoverage.tracer.instrumentation.TracingMethodInstrumenter.java
License:Creative Commons License
@SuppressWarnings("unchecked") public void transform(final ListIterator<MethodNode> methodIt) { // do not modify abstract or native methods if ((this.methodNode.access & ACC_ABSTRACT) != 0 || (this.methodNode.access & ACC_NATIVE) != 0) return;//ww w . ja v a2 s.c o m // check out what labels are jump targets (only these have to be traced) analyze(this.methodNode); this.instructionIterator = new FixedInstructionIterator(this.methodNode.instructions); // in the old method, initialize the new local variable for the threadtracer this.instructionIterator.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(Tracer.class), "getInstance", "()L" + Type.getInternalName(Tracer.class) + ";")); this.instructionIterator.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(Tracer.class), "getThreadTracer", "()L" + Type.getInternalName(ThreadTracer.class) + ";")); this.instructionIterator.add(new InsnNode(DUP)); this.instructionIterator.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex)); this.instructionIterator.add( new MethodInsnNode(INVOKEINTERFACE, Type.getInternalName(ThreadTracer.class), "isPaused", "()Z")); final LabelNode noTracingLabel = new LabelNode(); this.instructionIterator.add(new JumpInsnNode(IFNE, noTracingLabel)); // create a copy of the (uninstrumented) instructions (later, while iterating through the instructions) final InsnList oldInstructions = new InsnList(); final Map<LabelNode, LabelNode> labelCopies = LazyMap.decorate(new HashMap<LabelNode, LabelNode>(), new Factory() { @Override public Object create() { return new LabelNode(); } }); // copy the try-catch-blocks final Object[] oldTryCatchblockNodes = this.methodNode.tryCatchBlocks.toArray(); for (final Object o : oldTryCatchblockNodes) { final TryCatchBlockNode tcb = (TryCatchBlockNode) o; final TryCatchBlockNode newTcb = new TryCatchBlockNode(labelCopies.get(tcb.start), labelCopies.get(tcb.end), labelCopies.get(tcb.handler), tcb.type); this.methodNode.tryCatchBlocks.add(newTcb); } // increment number of local variables by one (for the threadtracer) ++this.methodNode.maxLocals; // and increment all local variable indexes after the new one by one for (final Object o : this.methodNode.localVariables) { final LocalVariableNode localVar = (LocalVariableNode) o; if (localVar.index >= this.tracerLocalVarIndex) ++localVar.index; } // store information about local variables in the ReadMethod object List<LocalVariable> localVariables = new ArrayList<LocalVariable>(); for (final Object o : this.methodNode.localVariables) { final LocalVariableNode localVar = (LocalVariableNode) o; while (localVariables.size() <= localVar.index) localVariables.add(null); localVariables.set(localVar.index, new LocalVariable(localVar.index, localVar.name, localVar.desc)); } this.readMethod.setLocalVariables(localVariables.toArray(new LocalVariable[localVariables.size()])); localVariables = null; // each method must start with a (dedicated) label: assert this.readMethod.getInstructions().isEmpty(); traceLabel(null, InstructionType.METHODENTRY); assert this.readMethod.getInstructions().size() == 1 && this.readMethod.getInstructions().get(0) instanceof LabelMarker && ((LabelMarker) this.readMethod.getInstructions().get(0)).isAdditionalLabel(); this.readMethod.setMethodEntryLabel((LabelMarker) this.readMethod.getInstructions().get(0)); // needed later: final LabelNode l0 = new LabelNode(); this.instructionIterator.add(l0); // then, visit the instructions that were in the method before while (this.instructionIterator.hasNext()) { final AbstractInsnNode insnNode = this.instructionIterator.next(); switch (insnNode.getType()) { case AbstractInsnNode.INSN: transformInsn((InsnNode) insnNode); break; case AbstractInsnNode.INT_INSN: transformIntInsn((IntInsnNode) insnNode); break; case AbstractInsnNode.VAR_INSN: transformVarInsn((VarInsnNode) insnNode); break; case AbstractInsnNode.TYPE_INSN: transformTypeInsn((TypeInsnNode) insnNode); break; case AbstractInsnNode.FIELD_INSN: transformFieldInsn((FieldInsnNode) insnNode); break; case AbstractInsnNode.METHOD_INSN: transformMethodInsn((MethodInsnNode) insnNode); break; case AbstractInsnNode.JUMP_INSN: transformJumpInsn((JumpInsnNode) insnNode); break; case AbstractInsnNode.LABEL: transformLabel((LabelNode) insnNode); break; case AbstractInsnNode.LDC_INSN: transformLdcInsn((LdcInsnNode) insnNode); break; case AbstractInsnNode.IINC_INSN: transformIincInsn((IincInsnNode) insnNode); break; case AbstractInsnNode.TABLESWITCH_INSN: transformTableSwitchInsn((TableSwitchInsnNode) insnNode); break; case AbstractInsnNode.LOOKUPSWITCH_INSN: transformLookupSwitchInsn((LookupSwitchInsnNode) insnNode); break; case AbstractInsnNode.MULTIANEWARRAY_INSN: transformMultiANewArrayInsn((MultiANewArrayInsnNode) insnNode); break; case AbstractInsnNode.FRAME: // ignore break; case AbstractInsnNode.LINE: // ignore break; default: throw new RuntimeException("Unknown instruction type " + insnNode.getType() + " (" + insnNode.getClass().getSimpleName() + ")"); } oldInstructions.add(insnNode.clone(labelCopies)); } assert this.outstandingInitializations == 0; // add the (old) try-catch blocks to the readMethods // (can only be done down here since we use the information in the // labels map) for (final Object o : oldTryCatchblockNodes) { final TryCatchBlockNode tcb = (TryCatchBlockNode) o; this.readMethod.addTryCatchBlock(new TryCatchBlock(this.labels.get(tcb.start), this.labels.get(tcb.end), this.labels.get(tcb.handler), tcb.type)); } final LabelNode l1 = new LabelNode(); this.instructionIterator.add(l1); final int newPos = this.readMethod.getInstructions().size(); traceLabel(null, InstructionType.METHODEXIT); assert this.readMethod.getInstructions().size() == newPos + 1; final AbstractInstruction abnormalTerminationLabel = this.readMethod.getInstructions().get(newPos); assert abnormalTerminationLabel instanceof LabelMarker; this.readMethod.setAbnormalTerminationLabel((LabelMarker) abnormalTerminationLabel); this.methodNode.instructions.add(new InsnNode(ATHROW)); // add a try catch block around the method so that we can trace when this method is left // a thrown exception this.methodNode.tryCatchBlocks.add(new TryCatchBlockNode(l0, l1, l1, null)); // now add the code that is executed if no tracing should be performed this.methodNode.instructions.add(noTracingLabel); if (this.firstLine != -1) this.methodNode.instructions.add(new LineNumberNode(this.firstLine, noTracingLabel)); this.methodNode.instructions.add(new InsnNode(ACONST_NULL)); this.methodNode.instructions.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex)); this.methodNode.instructions.add(oldInstructions); // finally: create a copy of the method that gets the ThreadTracer as argument // this is only necessary for private methods or "<init>" if (this.tracer.wasRedefined(this.readMethod.getReadClass().getName()) && (this.methodNode.access & ACC_PRIVATE) != 0) { final Type[] oldMethodArguments = Type.getArgumentTypes(this.methodNode.desc); final Type[] newMethodArguments = Arrays.copyOf(oldMethodArguments, oldMethodArguments.length + 1); newMethodArguments[oldMethodArguments.length] = Type.getType(ThreadTracer.class); final String newMethodDesc = Type.getMethodDescriptor(Type.getReturnType(this.methodNode.desc), newMethodArguments); final MethodNode newMethod = new MethodNode(this.methodNode.access, this.methodNode.name, newMethodDesc, this.methodNode.signature, (String[]) this.methodNode.exceptions.toArray(new String[this.methodNode.exceptions.size()])); methodIt.add(newMethod); int threadTracerParamPos = ((this.readMethod.getAccess() & Opcodes.ACC_STATIC) == 0 ? 1 : 0); for (final Type t : oldMethodArguments) threadTracerParamPos += t.getSize(); final Map<LabelNode, LabelNode> newMethodLabels = LazyMap.decorate(new HashMap<LabelNode, LabelNode>(), new Factory() { @Override public Object create() { return new LabelNode(); } }); // copy the local variables information to the new method for (final Object o : this.methodNode.localVariables) { final LocalVariableNode lv = (LocalVariableNode) o; newMethod.localVariables.add(new LocalVariableNode(lv.name, lv.desc, lv.signature, newMethodLabels.get(lv.start), newMethodLabels.get(lv.end), lv.index)); } newMethod.maxLocals = this.methodNode.maxLocals; newMethod.maxStack = this.methodNode.maxStack; // copy the try-catch-blocks for (final Object o : this.methodNode.tryCatchBlocks) { final TryCatchBlockNode tcb = (TryCatchBlockNode) o; newMethod.tryCatchBlocks.add(new TryCatchBlockNode(newMethodLabels.get(tcb.start), newMethodLabels.get(tcb.end), newMethodLabels.get(tcb.handler), tcb.type)); } // skip the first 6 instructions, replace them with these: newMethod.instructions.add(new VarInsnNode(ALOAD, threadTracerParamPos)); newMethod.instructions.add(new InsnNode(DUP)); newMethod.instructions.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex)); newMethod.instructions.add(new JumpInsnNode(IFNULL, newMethodLabels.get(noTracingLabel))); final Iterator<AbstractInsnNode> oldInsnIt = this.methodNode.instructions.iterator(6); // and add all the other instructions while (oldInsnIt.hasNext()) { final AbstractInsnNode insn = oldInsnIt.next(); newMethod.instructions.add(insn.clone(newMethodLabels)); } } ready(); }
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/* ww w . ja va 2 s . c om*/ 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; }
From source file:pxb.android.dex2jar.optimize.D.java
License:Apache License
private void cut(MethodNode method) { InsnList insns = method.instructions; method.instructions = null;/*from w ww.j a v a 2s . c o m*/ { AbstractInsnNode p = insns.getFirst(); if (!(p instanceof LabelNode)) { insns.insertBefore(p, new LabelNode()); } AbstractInsnNode q = insns.getLast(); if (!(q instanceof LabelNode)) { insns.insert(q, new LabelNode()); } } @SuppressWarnings("serial") Map<LabelNode, LabelNode> cloneMap = new HashMap<LabelNode, LabelNode>() { public LabelNode get(Object key) { LabelNode l = super.get(key); if (l == null) { l = new LabelNode(); put((LabelNode) key, l); } return l; } }; Map<LabelNode, Block> preBlockMap = new HashMap<LabelNode, Block>(); int i = 0; LabelNode label = null; Block block = null; List<AbstractInsnNode> currentInsnList = null; for (AbstractInsnNode p = insns.getFirst(); p != null; p = p.getNext()) { final AbstractInsnNode cp = p.clone(cloneMap); switch (cp.getType()) { case AbstractInsnNode.LABEL: { if (label != null) { block = new Block(i++, label); block.insns = currentInsnList; block.next = (LabelNode) cp; addToMap(block); } currentInsnList = new ArrayList<AbstractInsnNode>(); label = (LabelNode) cp; preBlockMap.put(label, block); break; } case AbstractInsnNode.JUMP_INSN: case AbstractInsnNode.LOOKUPSWITCH_INSN: case AbstractInsnNode.TABLESWITCH_INSN: { if (cp.getOpcode() == GOTO) { block = new Block(i++, label); block.next = (LabelNode) ((JumpInsnNode) cp).label; } else {// block = new BranchBlock(i++, label, cp); block.next = (LabelNode) getNextLabelNode(p, insns).clone(cloneMap); } block.insns = currentInsnList; addToMap(block); currentInsnList = null; label = null; break; } case AbstractInsnNode.FRAME: case AbstractInsnNode.LINE: // ignore break; default: switch (cp.getOpcode()) { case IRETURN: case LRETURN: case FRETURN: case DRETURN: case ARETURN: case RETURN: case ATHROW: block = new EndBlock(i++, label, cp); block.next = null; getNextLabelNode(p, insns); block.insns = currentInsnList; addToMap(block); currentInsnList = null; label = null; break; default: currentInsnList.add(cp); } } } for (Iterator<?> it = method.tryCatchBlocks.iterator(); it.hasNext();) { TryCatchBlockNode tcn = (TryCatchBlockNode) it.next(); Block s = map.get((LabelNode) tcn.start.clone(cloneMap)); Block e = map.get((LabelNode) tcn.end.clone(cloneMap)); Block handler = map.get(tcn.handler.clone(cloneMap)); TcbK key = new TcbK(s, e); Map<Block, String> handlers = tcbs.get(key); if (handlers == null) { handlers = new TreeMap<Block, String>(new Comparator<Block>() { @Override public int compare(Block o1, Block o2) { return o1.id - o2.id; } }); tcbs.put(key, handlers); } handlers.put(handler, tcn.type); tcn.start = s.label; tcn.end = e.label; tcn.handler = handler.label; } }