Java tutorial
/** * Copyright (c) 2003,2008 Craig Setera and others. * Copyright (c) 2010 Vt estk * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Craig Setera (EclipseME) - Initial implementation * Diego Sandin (Motorola) - Refactoring package name to follow eclipse * standards * Diego Sandin (Motorola) - Fix errors after updating ASM library form * version 2.2.2 to 3.0.0 * Vt estk - package renamed, visibility reduced */ package v6.java.preverifier; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.LookupSwitchInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TableSwitchInsnNode; import org.objectweb.asm.tree.TryCatchBlockNode; import org.objectweb.asm.tree.analysis.AnalyzerException; import org.objectweb.asm.tree.analysis.Value; /** * Handler for a single method in the class. Capable of inlining subroutines and * creating the Stack map attribute. * <p> * FIXME This class need to be re-implemented * </p> * * @author Craig Setera */ @SuppressWarnings("all") class MethodRewriter { /** * A Label instance mapped to the new region and code offset after inlining * * @author Craig Setera */ public class MappedLabel extends Label { private Label originalLabel; /** * Construct a new instance */ public MappedLabel(Label label) { super(); originalLabel = label; } public Label getOriginalLabel() { return originalLabel; } /** * @see java.lang.Object#toString() */ @Override public String toString() { return originalLabel.toString() + " -> " + super.toString(); } } /** A region of instructions to be handled. */ class Region { protected int endIndex; protected Map labelMap; protected Set<Label> labels; protected Region parentRegion; protected int startIndex; protected List<TryCatchBlockNode> tryCatchBlocks; /** * Construct a new instance. */ Region() { this(0, 0); } /** * Construct a new instance. * * @param startIndex * @param endIndex */ Region(int startIndex, int endIndex) { this.startIndex = startIndex; this.endIndex = endIndex; labelMap = new HashMap(); labels = new HashSet<Label>(); tryCatchBlocks = new ArrayList<TryCatchBlockNode>(); } /** * Find the label map recursively as necessary. * * @param originalLabel * @return */ protected Map<Label, Label> findLabelMap(Label originalLabel) { Map map = findLabelMapRecursive(originalLabel); return (map != null) ? map : labelMap; } /** * Find the label map recursively. * * @param originalLabel * @return */ protected Map findLabelMapRecursive(Label originalLabel) { Map map = null; if (labels.contains(originalLabel)) { map = labelMap; } else if (parentRegion != null) { map = parentRegion.findLabelMapRecursive(originalLabel); } return map; } /** * Find and return the specified label mapped appropriately for the * region or <code>null</code> if not found. * * @param originalLabel * @return */ protected Label findMappedLabel(Label originalLabel) { Label mappedLabel = (Label) labelMap.get(originalLabel); if ((mappedLabel == null) && (parentRegion != null)) { mappedLabel = parentRegion.findMappedLabel(originalLabel); } return mappedLabel; } /** * Add a new label to this region's list. * * @param label */ void addLabel(Label label) { labels.add(label); } /** * Add a new try catch block that is contained within this region. * * @param tryCatchBlock */ void addTryCatchBlock(TryCatchBlockNode tryCatchBlock) { tryCatchBlocks.add(tryCatchBlock); } /** * Return a boolean indicating whether the specified TryCatchBlockNode * is enclosed within this instruction region. * * @param tryCatchBlock * @return */ boolean encloses(TryCatchBlockNode tryCatchBlock) { return labels.contains(tryCatchBlock.start) && labels.contains(tryCatchBlock.end); } /** * Enter the region. Do any setup for this region. * * @param method */ void enter(MethodNode method) { labelMap.clear(); copyTryCatchBlocks(method, this, tryCatchBlocks); } /** * Exit the region. Do any cleanup for this region. * * @param method */ void exit(MethodNode method) { } /** * Return the length (in AbstractInsnNode instances) of this region. * * @return */ int getLength() { return endIndex - startIndex; } /** * Get the mapped label for the specified label based on the current * region. * * @param originalLabel * @return */ Label getMappedLabel(Label originalLabel) { Label mappedLabel = findMappedLabel(originalLabel); if (mappedLabel == null) { mappedLabel = new MappedLabel(originalLabel); Map<Label, Label> map = findLabelMap(originalLabel); map.put(originalLabel, mappedLabel); } return mappedLabel; } /** * Return the try catch blocks in this region. * * @return */ List<TryCatchBlockNode> getTryCatchBlocks() { return tryCatchBlocks; } /** * Returnn a boolean indicating whether the specified opcode at the * specified index in the method is a subroutine store opcode. * * @param methodNode * @param index * @return */ boolean isSubroutineReturnStore(MethodNode methodNode, int index) { return false; } /** * Store the parent region. * * @param parentRegion */ void setParentRegion(Region parentRegion) { this.parentRegion = parentRegion; } } /** Holder for information about a subroutine in a method */ class Subroutine extends Region { Label label; int returnVariable; /** * Construct a new subroutine instance. * * @param label */ Subroutine(Label label) { super(); this.label = label; } /** * @return Returns the returnVariable. */ public int getReturnVariable() { return returnVariable; } /** * @param returnVariable The returnVariable to set. */ public void setReturnVariable(int returnVariable) { this.returnVariable = returnVariable; } /* (non-Javadoc) * @see org.eclipse.mtj.internal.core.preverifier.MethodRewriter.Region#isSubroutineReturnStore(org.objectweb.asm.tree.MethodNode, int) */ @Override boolean isSubroutineReturnStore(MethodNode methodNode, int index) { boolean isReturnStore = false; // AbstractInsnNode insnNode = getInstruction(methodNode, index); // if (insnNode.getOpcode() == Opcodes.ASTORE) { // VarInsnNode varInsnNode = (VarInsnNode) insnNode; // isReturnStore = (varInsnNode.var == returnVariable); // } return isReturnStore; } } private Map lineNumberMap; private Map<LabelNode, ArrayList<LocalVariableNode>> localVariableByEndLabelMap; private Map localVariableByStartLabelMap; private PreverifierMethodNode srcMethod; private Map subroutineMap; private MethodNode updatedMethod; /** * Construct a new rewriter instance. * * @param classNode * @param srcMethod */ public MethodRewriter(PreverificationClassNode classNode, PreverifierMethodNode srcMethod) { super(); this.srcMethod = srcMethod; localVariableByEndLabelMap = new HashMap<LabelNode, ArrayList<LocalVariableNode>>(); } /** * Return the method with subroutines inlined and an associated * StackMapAttribute. * * @return * @throws AnalyzerException */ public MethodNode getUpdatedMethod() throws AnalyzerException { boolean inliningRequired = (srcMethod.getJsrInstructionIndices().size() > 0); if (inliningRequired) { inlineSubroutines(); } else { updatedMethod = srcMethod; } createStackMapAttribute(); return updatedMethod; } /** * Add a new local variabled to the variables by end label map. * * @param newLocalVariable */ private void addNewLocalVariableByEnd(LocalVariableNode newLocalVariable) { ArrayList endLocalVariables = (ArrayList) localVariableByEndLabelMap.get(newLocalVariable.end); if (endLocalVariables == null) { endLocalVariables = new ArrayList(); localVariableByEndLabelMap.put(newLocalVariable.end, endLocalVariables); } endLocalVariables.add(newLocalVariable); } /** * Add a new stack map type. * * @param localOrStack * @param region * @param label * @param value */ private void addStackMapType(List localOrStack, Label label, Value value) { // BasicValue basicValue = (BasicValue) value; // // if (this == BasicValue.UNINITIALIZED_VALUE) { // localOrStack.add(newStackMapType(label, // StackMapType.ITEM_Uninitialized)); // } else { // Type valueType = basicValue.getType(); // // if (valueType == null) { // localOrStack.add(newStackMapType(label, StackMapType.ITEM_Top)); // } else { // switch (valueType.getSort()) { // case Type.BOOLEAN: // case Type.BYTE: // case Type.CHAR: // case Type.INT: // case Type.SHORT: // localOrStack.add(newStackMapType(label, // StackMapType.ITEM_Integer)); // break; // // case Type.DOUBLE: // localOrStack.add(newStackMapType(label, // StackMapType.ITEM_Double)); // localOrStack.add(newStackMapType(label, // StackMapType.ITEM_Top)); // break; // // case Type.FLOAT: // localOrStack.add(newStackMapType(label, // StackMapType.ITEM_Float)); // break; // // case Type.LONG: // localOrStack.add(newStackMapType(label, // StackMapType.ITEM_Long)); // localOrStack.add(newStackMapType(label, // StackMapType.ITEM_Top)); // break; // // case Type.OBJECT: { // StackMapType mapType = null; // // String typeName = valueType.getInternalName(); // if (typeName.equals("null")) { // mapType = newStackMapType(label, StackMapType.ITEM_Null); // } else { // mapType = newStackMapType(label, // StackMapType.ITEM_Object); // mapType.setObject(typeName); // } // // localOrStack.add(mapType); // break; // } // // case Type.ARRAY: { // StackMapType mapType = newStackMapType(label, // StackMapType.ITEM_Object); // mapType.setObject(valueType.toString()); // localOrStack.add(mapType); // break; // } // } // } // } } /** * Copy the method node's metadata that is not changing. * * @param method * @return */ private MethodNode copyMethodMetadata(MethodNode method) { // Start a new method node String[] exceptions = (String[]) method.exceptions.toArray(new String[method.exceptions.size()]); return new MethodNode(method.access, method.name, method.desc, method.signature, exceptions); } /** * Copy the specified region of code potentially recursively. * * @param method * @param region * @throws AnalyzerException */ private void copyRegion(MethodNode method, Region region) throws AnalyzerException { // // Do any region-specific setup // region.enter(method); // // // Walk the instructions.. inlining as we go // for (int index = region.startIndex; index < region.endIndex; ++index) // { // AbstractInsnNode insnNode = getInstruction(srcMethod, index); // // // Special case for labels, as they may indicate the start of // // a subroutine that can be skipped. // if (insnNode.getType() == AbstractInsnNode.LABEL) { // Label label = ((LabelNode) insnNode).label; // visitLabel(method, region, label); // // if (isSubroutineStart(label)) { // // Skip over this subroutine implementation // Subroutine subroutine = (Subroutine) subroutineMap // .get(label); // index = subroutine.endIndex; // } // } else { // if (!region.isSubroutineReturnStore(srcMethod, index)) { // visitInstruction(method, region, insnNode); // } // } // } // // // Do any region-specific cleanup // region.exit(method); } /** * Copy all of the try/catch blocks in the method, realigning based on the * rewritten code. * * @param methodNode * @param methodRegion */ private void copyTryCatchBlocks(MethodNode methodNode, Region region, List blocks) { // Iterator tryCatchBlocks = blocks.iterator(); // while (tryCatchBlocks.hasNext()) { // TryCatchBlockNode tryCatch = (TryCatchBlockNode) tryCatchBlocks // .next(); // if (shouldCopy(tryCatch)) { // methodNode.visitTryCatchBlock(region // .getMappedLabel(tryCatch.start), region // .getMappedLabel(tryCatch.end), region // .getMappedLabel(tryCatch.handler), tryCatch.type); // } // } } /** * Create a mapping from line number location (Label) to the instance of the * line number nodes. * * @return */ private Map createLineNumberMap() { Map map = new HashMap(); // Iterator lineNumbers = srcMethod.lineNumbers.iterator(); // while (lineNumbers.hasNext()) { // LineNumberNode lineNumber = (LineNumberNode) lineNumbers.next(); // map.put(lineNumber.start, lineNumber); // } return map; } /** * Create a mapping from local variable location (Label) to the instance of * the local variable nodes. * * @return */ private Map createLocalVariableMap() { Map map = new HashMap(); Iterator localVariables = srcMethod.localVariables.iterator(); while (localVariables.hasNext()) { LocalVariableNode localVariable = (LocalVariableNode) localVariables.next(); ArrayList startList = (ArrayList) map.get(localVariable.start); if (startList == null) { startList = new ArrayList(); map.put(localVariable.start, startList); } startList.add(localVariable); } return map; } /** * Create a new StackMapAttribute for the method. This method also removes * any dead code that would cause the stack map attribute to be incorrect. * * @throws AnalyzerException */ private void createStackMapAttribute() throws AnalyzerException { // StackMapAttribute stackMapAttribute = new StackMapAttribute(); // // //Attribute attribute = new Attribute("method"); // Set targetLabels = findTargetLabels(); // // // We need to have the verifier operating with the classpath // // of the class being rewritten // Interpreter interpreter = new SimpleVerifierPlusClassloader(classNode // .getClassLoader()); // Analyzer analyzer = new Analyzer(interpreter); // Frame[] frames = analyzer.analyze(classNode.name, updatedMethod); // // int deadCodeFrameCount = 0; // int[] deadCodeIndices = new int[frames.length]; // // for (int i = 0; i < updatedMethod.instructions.size(); i++) { // Frame frame = frames[i]; // // // We only need to add stack map attributes for labels // // that are the target of certain instructions // AbstractInsnNode insnNode = getInstruction(updatedMethod, i); // if (insnNode.getType() == AbstractInsnNode.LABEL) { // LabelNode labelNode = (LabelNode) insnNode; // // if (targetLabels.contains(labelNode.getLabel()) // && (frame != null)) { // stackMapAttribute.frames.add(newStackMapFrame(labelNode // .getLabel(), frame)); // } // } else if (frame == null) { // // Track the indices of dead code for removal after // // building the stack map // deadCodeIndices[deadCodeFrameCount++] = i; // } // // } // // // Write out the newly created stack map attribute // // and remove any unnecessary dead code that would // // have an adverse effect on the stack map attribute // if (stackMapAttribute.frames.size() != 0) { // updatedMethod.visitAttribute(stackMapAttribute); // // // Remove the dead code in reverse order so that // // the indices remain correct after each removal // for (int i = deadCodeFrameCount - 1; i >= 0; i--) { // //updatedMethod.instructions.remove(deadCodeIndices[i]); // System.out.println("Remove the dead code"); // } // } } /** * Scan the instructions in the source method and find the subroutines and * locations of any target labels. * * @param method * @throws AnalyzerException */ private void createSubroutineMap() throws AnalyzerException { subroutineMap = new HashMap(); // // Look through the JSR instructions and collect the // // target labels. Those target labels are the starting // // points for the subroutines. // Set subroutineStartLabels = new HashSet(); // Iterator jsrInstructionIndices = srcMethod.getJsrInstructionIndices() // .iterator(); // while (jsrInstructionIndices.hasNext()) { // Integer instructionIndex = (Integer) jsrInstructionIndices.next(); // JumpInsnNode jumpNode = (JumpInsnNode) getInstruction(srcMethod, // instructionIndex.intValue()); // subroutineStartLabels.add(jumpNode.label); // } // // // Now, start searching for the subroutine starts. This // // must be done to account for nested subroutine implementations // if (subroutineStartLabels.size() > 0) { // for (int i = 0; i < srcMethod.instructions.size(); i++) { // AbstractInsnNode insnNode = getInstruction(srcMethod, i); // if (insnNode.getType() == AbstractInsnNode.LABEL) { // LabelNode labelNode = (LabelNode) insnNode; // if (subroutineStartLabels.contains(labelNode.label)) { // // This is the start of a subroutine // i = captureSubroutine(subroutineStartLabels, // subroutineMap, i, srcMethod, // (LabelNode) insnNode); // } // } // } // } } /** * Return the target labels used in generation of the stack map attribute. * * @return */ private Set findTargetLabels() { Set targetLabels = new HashSet(); Iterator insns = updatedMethod.instructions.iterator(); while (insns.hasNext()) { AbstractInsnNode insnNode = (AbstractInsnNode) insns.next(); switch (insnNode.getType()) { case AbstractInsnNode.JUMP_INSN: JumpInsnNode jumpInsnNode = (JumpInsnNode) insnNode; targetLabels.add(jumpInsnNode.label); break; case AbstractInsnNode.LOOKUPSWITCH_INSN: { LookupSwitchInsnNode lookupSwitchNode = (LookupSwitchInsnNode) insnNode; Iterator labels = lookupSwitchNode.labels.iterator(); while (labels.hasNext()) { Label label = (Label) labels.next(); targetLabels.add(label); } targetLabels.add(lookupSwitchNode.dflt); } break; case AbstractInsnNode.TABLESWITCH_INSN: { TableSwitchInsnNode tableSwitchNode = (TableSwitchInsnNode) insnNode; Iterator labels = tableSwitchNode.labels.iterator(); while (labels.hasNext()) { Label label = (Label) labels.next(); targetLabels.add(label); } targetLabels.add(tableSwitchNode.dflt); } break; } } Iterator blocks = updatedMethod.tryCatchBlocks.iterator(); while (blocks.hasNext()) { TryCatchBlockNode tryCatchBlock = (TryCatchBlockNode) blocks.next(); targetLabels.add(tryCatchBlock.handler); } return targetLabels; } /** * Return the instruction at the specified index. * * @param method * @param index * @return */ // private AbstractInsnNode getInstruction(MethodNode method, int index) { // List instructions = method.instructions; // return (AbstractInsnNode) ((index < instructions.size()) ? instructions // .get(index) : null); // } /** * Return the index of the specified label within the specified method node. * * @param methodNode * @param label * @return */ private int getLabelIndex(PreverifierMethodNode methodNode, Label label) { Integer i = methodNode.getLabelIndices().get(label); return i.intValue(); } /** * Return the last instruction in the specified method. * * @param method * @return */ // private AbstractInsnNode getLastInstruction(MethodNode method) { // return getInstruction(method, method.instructions.size() - 1); // } /** * Map the specified list of labels into an array of labels mapped into the * target region. * * @param region * @param labels * @return */ private Label[] getMappedLabelArray(Region region, List labels) { Label[] mappedLabels = new Label[labels.size()]; for (int i = 0; i < mappedLabels.length; i++) { mappedLabels[i] = region.getMappedLabel((Label) labels.get(i)); } return mappedLabels; } /** * Inline all subroutines. * * @throws AnalyzerException */ private void inlineSubroutines() throws AnalyzerException { // // Set up the first instruction region to be // // processed as the entire method code... // Region methodRegion = new Region(0, srcMethod.instructions.size()); // // // Scan through the instructions in the method and // // get organized // createSubroutineMap(); // sortTryCatchBlocks(methodRegion); // // // Copy the non-code information // updatedMethod = copyMethodMetadata(srcMethod); // // // Set up some mapping information // lineNumberMap = createLineNumberMap(); // localVariableByStartLabelMap = createLocalVariableMap(); // // // Copy the instructions while inlining subroutines // copyRegion(updatedMethod, methodRegion); // // // The WTK reduces the visibility of the local variables // if (shouldReduceVariableVisibility(updatedMethod)) { // InsnList instructions = updatedMethod.instructions; // int instructionCount = instructions.size(); // AbstractInsnNode lastLabel = (AbstractInsnNode) instructions // .remove(instructionCount - 1); // instructions.add(instructionCount - 2, lastLabel); // } // // updatedMethod.visitMaxs(srcMethod.maxStack, srcMethod.maxLocals); } /** * Return a method indicating whether the specified label is the start of a * referenced subroutine. * * @param label * @return */ private boolean isSubroutineStart(Label label) { return subroutineMap.containsKey(label); } /** * Remove the trailing TOP value from the list. * * @param localsOrStack * @return */ private boolean removeTrailingTop(ArrayList localsOrStack) { boolean removed = false; // if (localsOrStack.size() > 0) { // int lastIndex = localsOrStack.size() - 1; // // StackMapType type = (StackMapType) localsOrStack.get(lastIndex); // if (type.getType() == StackMapType.ITEM_Top) { // localsOrStack.remove(lastIndex); // removed = true; // } // } return removed; } /** * Create a new stack map frame. * * @param region * @param label * @param frame * @return * @throws AnalyzerException */ // private StackMapFrame newStackMapFrame(Label label, Frame frame) // throws AnalyzerException { // // Handle the locals // ArrayList locals = new ArrayList(); // int localsCount = frame.getLocals(); // for (int i = 0; i < localsCount; i++) { // addStackMapType(locals, label, frame.getLocal(i)); // } // removeTrailingTops(locals); // // // Handle the stack // ArrayList stack = new ArrayList(); // int stackCount = frame.getStackSize(); // for (int i = 0; i < stackCount; i++) { // addStackMapType(stack, label, frame.getStack(i)); // } // removeTrailingTops(stack); // // return new StackMapFrame(label, locals, stack); // } /** * Create a new StackMapType instance for the specified label. * * @param label * @param typeCode * @return */ // private StackMapType newStackMapType(Label label, int typeCode) { // StackMapType type = StackMapType.getTypeInfo(typeCode); // type.setLabel(label); // return type; // } /** * Remove the trailing TOP types from the specified locals or stack. * * @param locals */ private void removeTrailingTops(ArrayList localsOrStack) { while (removeTrailingTop(localsOrStack)) { } } /** * Capture the specified subroutine, potentially recursively capturing * nested subroutines. Captured subroutines are added to the map of * subroutines. * * @param subroutineStartLabels * @param subroutineMap * @param index * @param method * @param labelNode * @return */ // private int captureSubroutine(Set subroutineStartLabels, Map // subroutineMap, // int index, MethodNode method, LabelNode labelNode) { // Subroutine subroutine = new Subroutine(labelNode.label); // // subroutine.startIndex = index + 1; // for (subroutine.endIndex = subroutine.startIndex; true; // subroutine.endIndex++) { // AbstractInsnNode insn = getInstruction(method, subroutine.endIndex); // // if (insn.getType() == AbstractInsnNode.LABEL) { // Label label = ((LabelNode) insn).label; // if (subroutineStartLabels.contains(label)) { // subroutine.endIndex = captureSubroutine( // subroutineStartLabels, subroutineMap, // subroutine.endIndex, srcMethod, (LabelNode) insn); // } else { // subroutine.addLabel(label); // } // } else { // if (insn.getOpcode() == Opcodes.RET) { // // Figure out the variable that is being used // // for the return instruction // VarInsnNode varInsnNode = (VarInsnNode) insn; // int variableNumber = varInsnNode.var; // subroutine.setReturnVariable(variableNumber); // // break; // } // } // } // // // Add the newly found subroutine to the map // Label label = labelNode.label; // if (!subroutineMap.containsKey(label)) { // subroutineMap.put(label, subroutine); // } // // return subroutine.endIndex + 1; // } /** * Return a boolean indicating whether or not this try-catch block should be * copied to the new class. * * @param tryCatch * @return */ private boolean shouldCopy(TryCatchBlockNode tryCatch) { boolean shouldCopy = true; // int startIndex = getLabelIndex(srcMethod, tryCatch.start); // ArrayList insns = new ArrayList(); // // for (int i = startIndex; i < srcMethod.instructions.size(); i++) { // AbstractInsnNode insn = getInstruction(srcMethod, i); // // if (insn.getType() == AbstractInsnNode.LABEL) { // LabelNode l = (LabelNode) insn; // if (l.label.equals(tryCatch.end)) { // break; // } // } else { // insns.add(insn); // } // } // // if (insns.size() == 1) { // AbstractInsnNode insn = (AbstractInsnNode) insns.get(0); // shouldCopy = (insn.getOpcode() != Opcodes.JSR); // } return shouldCopy; } /** * Return a boolean indicating whether the variable visibility should be * reduced. * * @param method * @return */ private boolean shouldReduceVariableVisibility(MethodNode method) { boolean shouldReduce = false; // if (getLastInstruction(method) instanceof LabelNode) { // List instructions = updatedMethod.instructions; // int instructionCount = instructions.size(); // // AbstractInsnNode node = getInstruction(method, instructionCount - 2); // if (node instanceof InsnNode) { // InsnNode insnNode = (InsnNode) node; // switch (insnNode.getOpcode()) { // case Opcodes.IRETURN: // case Opcodes.LRETURN: // case Opcodes.FRETURN: // case Opcodes.DRETURN: // case Opcodes.ARETURN: // case Opcodes.RETURN: // case Opcodes.ATHROW: // shouldReduce = true; // break; // } // } // } return shouldReduce; } /** * Sort the try/catch blocks such that they are associated with the smallest * region that surrounds that block. * * @param methodRegion */ private void sortTryCatchBlocks(Region methodRegion) { Iterator blocks = srcMethod.tryCatchBlocks.iterator(); while (blocks.hasNext()) { Region enclosingRegion = methodRegion; TryCatchBlockNode block = (TryCatchBlockNode) blocks.next(); Iterator regions = subroutineMap.values().iterator(); while (regions.hasNext()) { Region region = (Region) regions.next(); if (region.encloses(block)) { if (enclosingRegion == null) { enclosingRegion = region; } else { // Pick the smallest region that encloses the block if (region.getLength() < enclosingRegion.getLength()) { enclosingRegion = region; } } } } enclosingRegion.addTryCatchBlock(block); } } /** * Visit the specified instruction and do the right thing. * * @param method * @param region * @param insnNode * @throws AnalyzerException */ private void visitInstruction(MethodNode method, Region region, AbstractInsnNode insnNode) throws AnalyzerException { int opcode = insnNode.getOpcode(); switch (opcode) { case Opcodes.JSR: visitJumpToSubroutine(method, region, (JumpInsnNode) insnNode); break; case Opcodes.IFEQ: case Opcodes.IFNE: case Opcodes.IFLT: case Opcodes.IFGE: case Opcodes.IFGT: case Opcodes.IFLE: case Opcodes.IF_ICMPEQ: case Opcodes.IF_ICMPNE: case Opcodes.IF_ICMPLT: case Opcodes.IF_ICMPGE: case Opcodes.IF_ICMPGT: case Opcodes.IF_ICMPLE: case Opcodes.IF_ACMPEQ: case Opcodes.IF_ACMPNE: case Opcodes.GOTO: case Opcodes.IFNULL: case Opcodes.IFNONNULL: visitJump(method, region, (JumpInsnNode) insnNode); break; case Opcodes.LOOKUPSWITCH: visitLookupSwitch(method, region, (LookupSwitchInsnNode) insnNode); break; case Opcodes.TABLESWITCH: visitTableSwitch(method, region, (TableSwitchInsnNode) insnNode); break; default: insnNode.accept(method); } } /** * Visit the specified jump instructions, mapping the labels into the target * method. * * @param method * @param region * @param jumpNode */ private void visitJump(MethodNode method, Region region, JumpInsnNode jumpNode) { // Label mappedLabel = region.getMappedLabel(jumpNode.label); // JumpInsnNode newJumpNode = new JumpInsnNode(jumpNode.getOpcode(), // mappedLabel); // newJumpNode.accept(method); } /** * Visit a JSR instruction... Inlining the subroutine. * * @param method * @param region * @param jumpNode * @throws AnalyzerException */ private void visitJumpToSubroutine(MethodNode method, Region region, JumpInsnNode jumpNode) throws AnalyzerException { // // Back up and see if we need to remap a local variable label // // The WTK preverifier extends the scope of a local variable // // one instruction further if the last instruction of the block // // is a variable store instruction // AbstractInsnNode insnNode = getLastInstruction(updatedMethod); // // if (insnNode instanceof VarInsnNode) { // List instructions = updatedMethod.instructions; // AbstractInsnNode insnNode2 = (AbstractInsnNode) instructions // .get(instructions.size() - 2); // // if (insnNode2 instanceof LabelNode) { // // Looks like we have the correct situation here. // // Introduce a new label as the last instruction // // and add it to the label map to be used when // // adding the local variables // LabelNode labelNode = (LabelNode) insnNode2; // ArrayList localVariables = (ArrayList) localVariableByEndLabelMap // .get(labelNode.label); // // if (localVariables != null) { // Iterator vars = localVariables.iterator(); // while (vars.hasNext()) { // LocalVariableNode var = (LocalVariableNode) vars.next(); // var.end = new Label(); // method.visitLabel(var.end); // } // } // } // } // // // Inline the subroutine // Subroutine subroutine = (Subroutine) // subroutineMap.get(jumpNode.label); // subroutine.setParentRegion(region); // copyRegion(method, subroutine); } /** * Visit the specified label in the context of the region. Handle all things * related to that label. * * @param method * @param region * @param label */ private void visitLabel(MethodNode method, Region region, Label label) { // Label mappedLabel = region.getMappedLabel(label); // method.visitLabel(mappedLabel); // // // Check for any related attributes // LineNumberNode lineNumber = (LineNumberNode) // lineNumberMap.get(label); // if (lineNumber != null) { // method.visitLineNumber(lineNumber.line, mappedLabel); // } // // ArrayList localVariables = (ArrayList) localVariableByStartLabelMap // .get(label); // if (localVariables != null) { // Iterator vars = localVariables.iterator(); // while (vars.hasNext()) { // int localVariableCount = method.localVariables.size(); // LocalVariableNode localVariable = (LocalVariableNode) vars // .next(); // // method.visitLocalVariable(localVariable.name, // localVariable.desc, localVariable.signature, region // .getMappedLabel(localVariable.start), region // .getMappedLabel(localVariable.end), // localVariable.index); // // LocalVariableNode newLocalVariable = (LocalVariableNode) // method.localVariables // .get(localVariableCount); // addNewLocalVariableByEnd(newLocalVariable); // } // } } /** * Visit the specified instruction, mapping the labels into the target * method. * * @param codeVisitor * @param region * @param node */ private void visitLookupSwitch(MethodNode codeVisitor, Region region, LookupSwitchInsnNode node) { // Label dflt = region.getMappedLabel(node.dflt); // // int[] keys = new int[node.keys.size()]; // for (int i = 0; i < keys.length; i++) { // keys[i] = ((Integer) node.keys.get(i)).intValue(); // } // // Label[] labels = getMappedLabelArray(region, node.labels); // // LookupSwitchInsnNode newSwitch = new LookupSwitchInsnNode(dflt, keys, // labels); // newSwitch.accept(codeVisitor); } /** * Visit the specified instructions, mapping the labels into the target * method. * * @param codeVisitor * @param region * @param node */ private void visitTableSwitch(MethodNode codeVisitor, Region region, TableSwitchInsnNode node) { // Label dflt = region.getMappedLabel(node.dflt); // Label[] labels = getMappedLabelArray(region, node.labels); // // TableSwitchInsnNode newSwitch = new TableSwitchInsnNode(node.min, // node.max, dflt, labels); // newSwitch.accept(codeVisitor); } }