/** @return complete, i.e., deep copy of this list */ public InstructionList copy() { Map<InstructionHandle, InstructionHandle> map = new HashMap<InstructionHandle, InstructionHandle>(); InstructionList il = new InstructionList(); /* Pass 1: Make copies of all instructions, append them to the new list * and associate old instruction references with the new ones, i.e., * a 1:1 mapping. */ for (InstructionHandle ih = start; ih != null; ih = ih.next) { Instruction i = ih.instruction; Instruction c = i.copy(); // Use clone for shallow copy if (c instanceof BranchInstruction) { map.put(ih, il.append((BranchInstruction) c)); } else { map.put(ih, il.append(c)); } } /* Pass 2: Update branch targets. */ InstructionHandle ih = start; InstructionHandle ch = il.start; while (ih != null) { Instruction i = ih.instruction; Instruction c = ch.instruction; if (i instanceof BranchInstruction) { BranchInstruction bi = (BranchInstruction) i; BranchInstruction bc = (BranchInstruction) c; InstructionHandle itarget = bi.getTarget(); // old target // New target is in hash map bc.setTarget(map.get(itarget)); if (bi instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH InstructionHandle[] itargets = ((Select) bi).getTargets(); InstructionHandle[] ctargets = ((Select) bc).getTargets(); for (int j = 0; j < itargets.length; j++) { // Update all targets ctargets[j] = map.get(itargets[j]); } } } ih = ih.next; ch = ch.next; } return il; }
/** * Redirect all references from old_target to new_target, i.e., update targets of branch * instructions. * * @param old_target the old target instruction handle * @param new_target the new target instruction handle */ public void redirectBranches(InstructionHandle old_target, InstructionHandle new_target) { for (InstructionHandle ih = start; ih != null; ih = ih.next) { Instruction i = ih.getInstruction(); if (i instanceof BranchInstruction) { BranchInstruction b = (BranchInstruction) i; InstructionHandle target = b.getTarget(); if (target == old_target) { b.setTarget(new_target); } if (b instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH InstructionHandle[] targets = ((Select) b).getTargets(); for (int j = 0; j < targets.length; j++) { if (targets[j] == old_target) { ((Select) b).setTarget(j, new_target); } } } } } }
/** * Initialize instruction list from byte array. * * @param code byte array containing the instructions */ public InstructionList(byte[] code) { ByteSequence bytes = new ByteSequence(code); InstructionHandle[] ihs = new InstructionHandle[code.length]; int[] pos = new int[code.length]; // Can't be more than that int count = 0; // Contains actual length /* Pass 1: Create an object for each byte code and append them * to the list. */ try { while (bytes.available() > 0) { // Remember byte offset and associate it with the instruction int off = bytes.getIndex(); pos[count] = off; /* Read one instruction from the byte stream, the byte position is set * accordingly. */ Instruction i = Instruction.readInstruction(bytes); InstructionHandle ih; if (i instanceof BranchInstruction) { ih = append((BranchInstruction) i); } else { ih = append(i); } ih.setPosition(off); ihs[count] = ih; count++; } } catch (IOException e) { throw new ClassGenException(e.toString(), e); } byte_positions = new int[count]; // Trim to proper size System.arraycopy(pos, 0, byte_positions, 0, count); /* Pass 2: Look for BranchInstruction and update their targets, i.e., * convert offsets to instruction handles. */ for (int i = 0; i < count; i++) { if (ihs[i] instanceof BranchHandle) { BranchInstruction bi = (BranchInstruction) ihs[i].instruction; int target = bi.position + bi.getIndex(); /* Byte code position: * relative -> absolute. */ // Search for target position InstructionHandle ih = findHandle(ihs, pos, count, target); if (ih == null) { throw new ClassGenException("Couldn't find target for branch: " + bi); } bi.setTarget(ih); // Update target // If it is a Select instruction, update all branch targets if (bi instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH Select s = (Select) bi; int[] indices = s.getIndices(); for (int j = 0; j < indices.length; j++) { target = bi.position + indices[j]; ih = findHandle(ihs, pos, count, target); if (ih == null) { throw new ClassGenException("Couldn't find target for switch: " + bi); } s.setTarget(j, ih); // Update target } } } } }