List of usage examples for org.objectweb.asm.tree AbstractInsnNode clone
public abstract AbstractInsnNode clone(Map<LabelNode, LabelNode> clonedLabels);
From source file:cl.inria.stiq.instrumenter.BCIUtils.java
License:Open Source License
private static InsnList cloneInstructions(ClonerMap aMap, InsnList aList) { InsnList theInsnListClone = new InsnList(); AbstractInsnNode theNode = aList.getFirst(); while (theNode != null) { AbstractInsnNode theClone = theNode.clone(aMap); if (theClone instanceof LabelNode) { LabelNode theLabelNode = (LabelNode) theClone; }// w w w . jav a 2 s.c om theInsnListClone.add(theClone); theNode = theNode.getNext(); } return theInsnListClone; }
From source file:com.offbynull.coroutines.instrumenter.asm.InstructionUtils.java
License:Open Source License
/** * Clones an invokevirtual/invokespecial/invokeinterface/invokedynamic node and returns it as an instruction list. * @param insnNode instruction to clone/*from www .j av a 2 s. c o m*/ * @throws NullPointerException if any argument is {@code null} * @throws IllegalArgumentException if node isn't of invoke type * @return instruction list with cloned instruction */ public static InsnList cloneInvokeNode(AbstractInsnNode insnNode) { Validate.notNull(insnNode); Validate.isTrue(insnNode instanceof MethodInsnNode || insnNode instanceof InvokeDynamicInsnNode); InsnList ret = new InsnList(); ret.add(insnNode.clone(new HashMap<>())); return ret; }
From source file:com.offbynull.coroutines.instrumenter.asm.InstructionUtils.java
License:Open Source License
/** * Clones a monitorenter/monitorexit node and returns it as an instruction list. * @param insnNode instruction to clone//from w w w .j a va 2s . c om * @throws NullPointerException if any argument is {@code null} * @throws IllegalArgumentException if node isn't of invoke type * @return instruction list with cloned instruction */ public static InsnList cloneMonitorNode(AbstractInsnNode insnNode) { Validate.notNull(insnNode); Validate.isTrue(insnNode instanceof InsnNode); Validate.isTrue( insnNode.getOpcode() == Opcodes.MONITORENTER || insnNode.getOpcode() == Opcodes.MONITOREXIT); InsnList ret = new InsnList(); ret.add(insnNode.clone(new HashMap<>())); return ret; }
From source file:com.offbynull.coroutines.instrumenter.asm.InstructionUtils.java
License:Open Source License
/** * Clones an instruction list. All labels are remapped unless otherwise specified in {@code globalLabels}. * @param insnList instruction list to clone * @param globalLabels set of labels that should not be remapped * @throws NullPointerException if any argument is {@code null} * @return instruction list with cloned instructions *//*from w ww . j av a 2 s . c o m*/ public static InsnList cloneInsnList(InsnList insnList, Set<LabelNode> globalLabels) { Validate.notNull(insnList); // remap all labelnodes Map<LabelNode, LabelNode> labelNodeMapping = new HashMap<>(); ListIterator<AbstractInsnNode> it = insnList.iterator(); while (it.hasNext()) { AbstractInsnNode abstractInsnNode = it.next(); if (abstractInsnNode instanceof LabelNode) { LabelNode existingLabelNode = (LabelNode) abstractInsnNode; labelNodeMapping.put(existingLabelNode, new LabelNode()); } } // override remapping such that global labels stay the same for (LabelNode globalLabel : globalLabels) { labelNodeMapping.put(globalLabel, globalLabel); } // clone InsnList ret = new InsnList(); it = insnList.iterator(); while (it.hasNext()) { AbstractInsnNode abstractInsnNode = it.next(); ret.add(abstractInsnNode.clone(labelNodeMapping)); } return ret; }
From source file:de.tuberlin.uebb.jbop.optimizer.loop.ForLoopBody.java
License:Open Source License
/** * Gets the insn list./* w w w . ja va2s . co m*/ * * @param i * the curretn counter * @param footer * the footer * @param method * the method * @return the insn list of the body in respect to the current counter (<code>i</code>). */ public InsnList getInsnList(final int i, final ForLoopFooter footer, final MethodNode method) { final InsnList list = new InsnList(); if (body.isEmpty()) { return list; } final LabelMap labelMap = new LabelMap(); final int newLocalVar = method.maxLocals + 1; final int oldLocalVar = footer.getVarIndex(); list.add(NodeHelper.getInsnNodeFor(i)); list.add(new VarInsnNode(Opcodes.ISTORE, newLocalVar)); for (final AbstractInsnNode node : body) { final AbstractInsnNode copyNode = node.clone(labelMap); if (copyNode instanceof VarInsnNode) { if (((VarInsnNode) copyNode).var == oldLocalVar) { ((VarInsnNode) copyNode).var = newLocalVar; } } list.add(copyNode); } list.add(new SplitMarkNode()); method.maxLocals++; return list; }
From source file:de.unisb.cs.st.javaslicer.tracer.instrumentation.PauseTracingInstrumenter.java
License:Open Source 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;/* w w w . j av a 2s. co m*/ 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) + ";", false)); insnIt.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(Tracer.class), "getThreadTracer", "()L" + Type.getInternalName(ThreadTracer.class) + ";", false)); insnIt.add(new InsnNode(DUP)); insnIt.add(new VarInsnNode(ASTORE, tracerLocalVarIndex)); insnIt.add(new MethodInsnNode(INVOKEINTERFACE, Type.getInternalName(ThreadTracer.class), "pauseTracing", "()V", true)); 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", true)); 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", true)); 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 = new LazyLabelMap(); // 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:de.unisb.cs.st.javaslicer.tracer.instrumentation.TracingClassInstrumenter.java
License:Open Source License
@SuppressWarnings("unchecked") private static void copyMethod(final MethodNode from, final MethodNode to) { to.access = from.access;/*w ww . j av a2 s . co m*/ to.annotationDefault = from.annotationDefault; to.attrs = from.attrs == null ? null : new ArrayList<Attribute>(from.attrs); to.desc = from.desc; to.exceptions = from.exceptions == null ? null : new ArrayList<String>(from.exceptions); to.instructions.clear(); final Iterator<?> insnIt = from.instructions.iterator(); final Map<LabelNode, LabelNode> labelsMap = new HashMap<LabelNode, LabelNode>() { private static final long serialVersionUID = 6883684625241587713L; @Override public LabelNode get(final Object key) { LabelNode label = super.get(key); if (label == null) put((LabelNode) key, label = new LabelNode()); return label; } }; while (insnIt.hasNext()) { final AbstractInsnNode insn = (AbstractInsnNode) insnIt.next(); to.instructions.add(insn.clone(labelsMap)); } to.invisibleAnnotations = from.invisibleAnnotations == null ? null : new ArrayList<AnnotationNode>(from.invisibleAnnotations); if (from.invisibleParameterAnnotations == null) { to.invisibleParameterAnnotations = null; } else { to.invisibleParameterAnnotations = new List[from.invisibleParameterAnnotations.length]; for (int i = 0; i < from.invisibleParameterAnnotations.length; ++i) { to.invisibleParameterAnnotations[i] = from.invisibleParameterAnnotations[i] == null ? null : new ArrayList<AnnotationNode>(from.invisibleParameterAnnotations[i]); } } if (from.localVariables == null) { to.localVariables = null; } else { to.localVariables = new ArrayList<LocalVariableNode>(from.localVariables.size()); for (final Object lvObj : from.localVariables) { final LocalVariableNode lv = (LocalVariableNode) lvObj; to.localVariables.add(new LocalVariableNode(lv.name, lv.desc, lv.signature, labelsMap.get(lv.start), labelsMap.get(lv.end), lv.index)); } } to.maxLocals = from.maxLocals; to.maxStack = from.maxStack; to.name = from.name; to.signature = from.signature; if (from.tryCatchBlocks == null) { to.tryCatchBlocks = null; } else { to.tryCatchBlocks = new ArrayList<TryCatchBlockNode>(from.tryCatchBlocks.size()); for (final Object tcbObj : from.tryCatchBlocks) { final TryCatchBlockNode tcb = (TryCatchBlockNode) tcbObj; to.tryCatchBlocks.add(new TryCatchBlockNode(labelsMap.get(tcb.start), labelsMap.get(tcb.end), labelsMap.get(tcb.handler), tcb.type)); } } to.visibleAnnotations = from.visibleAnnotations == null ? null : new ArrayList<AnnotationNode>(from.visibleAnnotations); if (from.visibleParameterAnnotations == null) { to.visibleParameterAnnotations = null; } else { to.visibleParameterAnnotations = new List[from.visibleParameterAnnotations.length]; for (int i = 0; i < from.visibleParameterAnnotations.length; ++i) { to.visibleParameterAnnotations[i] = from.visibleParameterAnnotations[i] == null ? null : new ArrayList<AnnotationNode>(from.visibleParameterAnnotations[i]); } } }
From source file:de.unisb.cs.st.javaslicer.tracer.instrumentation.TracingMethodInstrumenter.java
License:Open Source 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;//from w w w . java2 s. com // 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) + ";", false)); this.instructionIterator.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(Tracer.class), "getThreadTracer", "()L" + Type.getInternalName(ThreadTracer.class) + ";", false)); 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", true)); 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 = new LazyLabelMap(); // 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 // by 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 = new LazyLabelMap(); // 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:jaspex.speculation.newspec.FlowFrame.java
License:Open Source License
/** Mtodo que implementa a deteco e correco do problema dos mltiplos fluxos de controlo. * Retorna true se alterou o mtodo, e false cc. **//*from w w w .ja v a2s . com*/ private static boolean computeControlFlowGraph(String owner, String superOwner, MethodNode mn, LabelMap labelMap, boolean ranBefore) { //Log.debug("Visiting: {}.{}", owner, mn.name); FlowAnalyzer analyzer = new FlowAnalyzer(new FutureVerifier(owner, superOwner)); try { analyzer.analyze(owner, mn); //if (ranBefore) printCode(mn, Arrays.asList(analyzer.getFrames()), null, null); FrameInjector.injectFrames(mn, analyzer.getFrames()); return false; } catch (AnalyzerException e) { /*e.printStackTrace();*/ } // Se chegmos aqui, o Analyzer detectou problemas, e vamos ter que fazer correces no mtodo // Detectar o primeiro LabelNode onde aparece um MergedUninitializedValue LabelNode problemLabelNode = null; FlowFrame problemFrame = null; int problemPosition = -1; boolean problemInStack = false; List<FlowFrame> frames = listGenericCast(Arrays.asList(analyzer.getFrames())); outer: for (int i = 0; i < frames.size(); i++) { FlowFrame f = frames.get(i); if (f == null) continue; int localsStartPos = 0; int stackStartPos = 0; // Identificar se alguma entrada nos locals/stack da frame deve ser escolhida como // problemtica // Isto um loop porque algumas das entradas encontradas podem ser backwards edges, // e no estamos interessadas nessas while (true) { for (int j = localsStartPos; j < f.getLocals(); j++) { if (f.getLocal(j) instanceof MergedUninitializedValue) { problemPosition = j; problemInStack = false; localsStartPos = j + 1; } } for (int j = stackStartPos; j < f.getStackSize() && (problemPosition < 0); j++) { if (f.getStack(j) instanceof MergedUninitializedValue) { problemPosition = j; problemInStack = true; stackStartPos = j + 1; } } // J processamos completamente a frame e no encontramos nada, ou s // encontramos backwards edges, passar prxima if (problemPosition < 0) continue outer; if ((f.predecessors().size() > 0) && (getPredecessorWithFuture(f, problemInStack, problemPosition) == null)) { // Isto pode acontecer quando instruco que encontrmos o target de // um "backwards edge". Nesse caso, no esta a instruco que queremos // processar, mas queremos uma que tenha como predecessor um Future, // no um MergedUninitializedValue /*Log.debug("Found result of backwards edge at " + (problemInStack ? "stack" : "locals") + " position " + i + ", continuing");*/ problemPosition = -1; continue; } if (problemInStack && !(mn.instructions.get(i) instanceof LabelNode) && (mn.instructions.get(i - 1) instanceof VarInsnNode)) { // Caso especial: Uma instruco de load colocou um // MergedUninitializedValue na stack, e como no estava l na instruco // anterior o getPredecessorWithFuture no detecta este caso, mas no // estamos interessados nesta frame, estamos interessadas na que originou // o MUV que estava nos locals problemPosition = -1; continue; } // Frame e posio escolhidas so consideradas problemticas break; } AbstractInsnNode insn = mn.instructions.get(i); // First node with problematic frame should be a LabelNode if (!(insn instanceof LabelNode)) throw new AssertionError(); problemLabelNode = (LabelNode) insn; problemFrame = f; printCode(mn, frames, problemFrame.predecessors(), f); Log.trace("First problematic frame is " + f + "\n\t\tPredecessors: " + f.predecessors()); break; } if (problemLabelNode == null) { Log.warn("Errors found during analysis, bytecode possibly invalid, bailing out"); throw new AssertionError(); // Causar revert de todas as alteraes no mtodo //return false; } // Duplicar cdigo problemtico, para depois o alterar com o DelayGetFutureMethodVisitor InsnList il = new InsnList(); // Label que marca o inicio do cdigo a copiar LabelNode copiedBlockStartLabel = new LabelNode(); // Criar mapa para passar ao AbstractInsnNode (ver javadoc ASM) //LabelMap labelMap = new LabelMap(); labelMap.put(problemLabelNode, copiedBlockStartLabel); // Adiciona copiedBlockStartLabel nova il il.add(problemLabelNode.clone(labelMap)); // Usado para manter a ltima (inclusiv) instruco do bloco copiado AbstractInsnNode lastInsn = null; // Simular execuo das frames durante a cpia // O objectivo disto resolver problemas como o NewSpecExample17, onde cdigo copiado deve // fazer branch para: // -- Cdigo copiado numa iterao anterior ("cdigo novo") se a frame continuar a conter um // futuro, porque o cdigo novo o que suposto lidar com a existncia do futuro // -- Cdigo existente do mtodo ("cdigo antigo") se a frame j no contm um futuro, o que // significa que a concretizao se faz durante o bloco actual FlowFrame currentFrame = analyzer.newFrame(problemFrame); if (problemInStack) { currentFrame.setStack(problemPosition, ((MergedUninitializedValue) currentFrame.getStack(problemPosition)).getFuture()); } else { currentFrame.setLocal(problemPosition, ((MergedUninitializedValue) currentFrame.getLocal(problemPosition)).getFuture()); } for (AbstractInsnNode n = problemLabelNode.getNext(); n != null; n = n.getNext()) { if (n instanceof LabelNode) { LabelNode labelNode = (LabelNode) n; if (getNextIgnoreLabelLineNop(labelNode) instanceof FrameNode) { // Se label se refere a uma frame, o bloco terminou // FIXME: Tem que se saltar sempre para labels novas, se existirem? il.add(new JumpInsnNode(GOTO, labelMap.get(labelNode))); break; } else { // Caso contrrio, substituimos por uma nova label, para permitir // que os LineNumberNodes continuem a existir no novo cdigo. labelMap.put(labelNode, new LabelNode()); } } // Detectar, no caso de um salto, qual a label que se deve utilizar (ver comentrios acima) // FIXME: Ser que no caso do switch/case algumas das labels tm que apontar para o cdigo // novo, e outras para o antigo? if (n instanceof JumpInsnNode || n instanceof LookupSwitchInsnNode || n instanceof TableSwitchInsnNode) { // Se ProblemPosition ainda tem um Futuro, saltar para cdigo novo if ((problemInStack && isFuture(currentFrame.getStack(problemPosition))) || (!problemInStack && isFuture(currentFrame.getLocal(problemPosition)))) { il.add(n.clone(labelMap)); } else { // Deixou de ter um Futuro, saltar para cdigo antigo il.add(n.clone(new LabelMap())); } } else { il.add(n.clone(labelMap)); } lastInsn = n; // Se chegamos ao fim do bloco (GOTO, ATHROW ou *RETURN) tambm paramos a cpia if (n.getOpcode() == GOTO || n.getOpcode() == ATHROW || returnOpcodes.contains(n.getOpcode())) break; // Actualizar currentFrame -- simular execuo da instruco actual try { currentFrame = analyzer.computeNextFrame(currentFrame, n); } catch (AnalyzerException e) { // Ocorreu um erro, continuamos com a ltima frame vlida //Log.debug("WARNING: AnalyzerException during computeNextFrame"); } //Log.debug("CurrentFrame: " + currentFrame + " (isFuture? " + // (isFuture(currentFrame.getLocal(problemPosition)) ? "yes" : "no") + ")"); } LabelNode copiedBlockEndLabel = new LabelNode(); il.add(copiedBlockEndLabel); mn.instructions.add(il); il = mn.instructions; // Detectar qual dos seus predecessores originou o Futuro que ficou no MergedUninitializedValue if (problemFrame.predecessors().isEmpty()) { // ProblemFrame o inicio de um exception handler // Popular predecessors da problemFrame com control flows de exceptions analyzer.populateExceptionPredecessors(problemFrame); //printCode(mn, frames, problemFrame.predecessors()); // Adicionar um novo tryCatchBlock com: // - Range [Primeira instruco com Future, // ltima instruco que tem future *E* faz parte da lista de predecessors] // Razo: Lista de predecessors --> handler ainda est activo // Tem future --> future pode ser substituido mais tarde // (por exemplo { i = doA(); j = doB(); i = 0 }) // - Target: Novo bloco copiado -- copiedBlockStartLabel AbstractInsnNode startBlockInsn = null; AbstractInsnNode endBlockInsn = null; for (FlowFrame f : problemFrame.predecessors()) { BasicValue v = problemInStack ? f.getStack(problemPosition) : f.getLocal(problemPosition); if (isFuture(v)) { AbstractInsnNode insn = insnForFrame(il, frames, f); if (startBlockInsn == null) { startBlockInsn = insn; } if (endBlockInsn != null) { // Detectar se o bloco actual terminou if (getTryCatchBlock(mn, startBlockInsn, insn) == null) break; } endBlockInsn = insn; } else if (startBlockInsn != null) { break; } } // Provavelmente o problema do NewSpecExample20, ver comentrios no ficheiro if (startBlockInsn == null || endBlockInsn == null) { throw new AssertionError("KNOWN BUG: Probably picked the wrong code to copy"); } //Log.debug("PredecessorInsn [Exception]: First " + startBlockInsn + " Last " + endBlockInsn); LabelNode startBlockLabel = labelBefore(il, startBlockInsn); LabelNode endBlockLabel = labelAfter(il, endBlockInsn); TryCatchBlockNode originalBlock = getTryCatchBlock(mn, startBlockInsn, endBlockInsn); assert (originalBlock != null); mn.tryCatchBlocks.add(0, new SafeTryCatchBlockNode(startBlockLabel, endBlockLabel, copiedBlockStartLabel, originalBlock.type)); if (originalBlock.start.equals(startBlockLabel) && originalBlock.end.equals(endBlockLabel)) { // Novo bloco substitui completamente o antigo mn.tryCatchBlocks.remove(originalBlock); } else { // Como o novo try/catch substitui o antigo, para que o verificador da JVM e do ASM // lidem melhor com a coisa (embora segundo os specs no seria necessrio), vamos // alterar o inicio e/ou o fim do bloco original para deixar de conter as instruces // que esto cobertas pelo novo bloco if (originalBlock.start.equals(startBlockLabel)) { originalBlock.start = endBlockLabel; } else if (originalBlock.end.equals(endBlockLabel)) { originalBlock.end = startBlockLabel; } else { Log.debug("FIXME: Original (old) try catch block should be adjusted"); } } } else { // Existem predecessores, problemFrame um bloco de cdigo normal FlowFrame predecessorWithFuture = getPredecessorWithFuture(problemFrame, problemInStack, problemPosition); if (predecessorWithFuture == null) throw new AssertionError(); AbstractInsnNode predecessorInsn = insnForFrame(il, frames, predecessorWithFuture); //Log.debug("PredecessorInsn: " + predecessorInsn); // Detectar como vai ser feito o salto para a nova seco do cdigo // Casos possveis: // - Predecessor instruco imediatamente antes da labelnode (e no um salto) // -> No alteramos, adicionamos goto // -> Se for um salto, podemos ou no ter que alterar, dependendo de ser ou no // um salto para a labelNode que marca o incio da seco problemtica // - Predecessor jump / table|lookup switch // -> Temos que alterar // Fazendo clone com o labelmap obtemos um n que tem o salto para a nova label trocado // pelo salto para a antiga. if (directlyPrecedes(predecessorInsn, problemLabelNode) && !hasLabelAsTarget(predecessorInsn, problemLabelNode)) { // No temos que alterar n, saltamos directamente para novo bloco il.insert(predecessorInsn, new JumpInsnNode(GOTO, copiedBlockStartLabel)); } else { if (!((predecessorInsn instanceof LookupSwitchInsnNode) || (predecessorInsn instanceof TableSwitchInsnNode) || (predecessorInsn instanceof JumpInsnNode))) { throw new AssertionError(); // Instruco tem que ser salto } // N tem que ser alterado AbstractInsnNode replacementNode = predecessorInsn.clone(labelMap); il.set(predecessorInsn, replacementNode); if (lastInsn == predecessorInsn) lastInsn = replacementNode; } } // Corrigir exception handlers do mtodo // Como blocos de cdigo so copiados, temos tambm que copiar os exception handlers, // para que os try/catch continuem a funcionar correctamente List<AbstractInsnNode> copiedCodeRange = getRange(problemLabelNode, lastInsn); List<SafeTryCatchBlockNode> newTryCatchBlocks = new ArrayList<SafeTryCatchBlockNode>(); for (TryCatchBlockNode tryCatchBlock : mn.tryCatchBlocks) { List<AbstractInsnNode> blockRange = getRange(tryCatchBlock.start, tryCatchBlock.end); blockRange.retainAll(copiedCodeRange); if (blockRange.isEmpty()) continue; // Corner case: Supostamente um try/catch block cobre [start, end[, enquanto // que o getRange devolve [start, end] if (blockRange.size() == 1 && problemLabelNode == tryCatchBlock.end) continue; //Log.debug("Exception handler table needs fixup"); // Determinar a nova label de inicio LabelNode newStart; if (copiedCodeRange.contains(tryCatchBlock.start)) { // loco excepo comea j dentro do copiedCodeRange newStart = labelMap.getMapping(tryCatchBlock.start); } else { // Bloco excepo comea fora do copiedCodeRange newStart = copiedBlockStartLabel; } // Determinar a nova label de fim LabelNode newEnd; if (copiedCodeRange.contains(tryCatchBlock.end)) { // Bloco excepo comea dentro do copiedCodeRange newEnd = labelMap.getMapping(tryCatchBlock.end); } else { // Bloco excepo acaba fora do copiedCodeRange newEnd = copiedBlockEndLabel; } newTryCatchBlocks .add(new SafeTryCatchBlockNode(newStart, newEnd, tryCatchBlock.handler, tryCatchBlock.type)); } mn.tryCatchBlocks.addAll(newTryCatchBlocks); return true; }
From source file:org.coldswap.asm.field.PrivateStaticFieldReplacer.java
License:Open Source License
/** * Removes any initializing reference of the field. * * @param classNode containing the old class. * @param fieldNode containing the old field. * @return the initializing list of instructions. *//*from w w w . ja v a 2 s . c o m*/ @SuppressWarnings("unchecked") private InsnList cleanClInit(ClassNode classNode, FieldNode fieldNode) { 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 corresponding 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--; insnList.remove(firstInst); firstInst = ain; } // remove last instruction and the putstatic instruction AbstractInsnNode putStatic = firstInst.getNext(); insnList.remove(firstInst); insnList.remove(putStatic); return iList; } } } return null; }