📄 instructionlist.java
字号:
public void setPositions(boolean check) { int max_additional_bytes = 0, additional_bytes = 0; int index = 0, count = 0; int[] pos = new int[length]; /* Pass 0: Sanity checks */ if(check) { for(InstructionHandle ih=start; ih != null; ih = ih.next) { Instruction i = ih.instruction; if(i instanceof BranchInstruction) { // target instruction within list? Instruction inst = ((BranchInstruction)i).getTarget().instruction; if(!contains(inst)) throw new ClassGenException("Branch target of " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst + " not in instruction list"); if(i instanceof Select) { InstructionHandle[] targets = ((Select)i).getTargets(); for(int j=0; j < targets.length; j++) { inst = targets[j].instruction; if(!contains(inst)) throw new ClassGenException("Branch target of " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst + " not in instruction list"); } } if(!(ih instanceof BranchHandle)) throw new ClassGenException("Branch instruction " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst + " not contained in BranchHandle."); } } } /* Pass 1: Set position numbers and sum up the maximum number of bytes an * instruction may be shifted. */ for(InstructionHandle ih=start; ih != null; ih = ih.next) { Instruction i = ih.instruction; ih.setPosition(index); pos[count++] = index; /* Get an estimate about how many additional bytes may be added, because * BranchInstructions may have variable length depending on the target * offset (short vs. int) or alignment issues (TABLESWITCH and * LOOKUPSWITCH). */ switch(i.getOpcode()) { case Constants.JSR: case Constants.GOTO: max_additional_bytes += 2; break; case Constants.TABLESWITCH: case Constants.LOOKUPSWITCH: max_additional_bytes += 3; break; } index += i.getLength(); } /* Pass 2: Expand the variable-length (Branch)Instructions depending on * the target offset (short or int) and ensure that branch targets are * within this list. */ for(InstructionHandle ih=start; ih != null; ih = ih.next) additional_bytes += ih.updatePosition(additional_bytes, max_additional_bytes); /* Pass 3: Update position numbers (which may have changed due to the * preceding expansions), like pass 1. */ index=count=0; for(InstructionHandle ih=start; ih != null; ih = ih.next) { Instruction i = ih.instruction; ih.setPosition(index); pos[count++] = index; index += i.getLength(); } byte_positions = new int[count]; // Trim to proper size System.arraycopy(pos, 0, byte_positions, 0, count); } /** * When everything is finished, use this method to convert the instruction * list into an array of bytes. * * @return the byte code ready to be dumped */ public byte[] getByteCode() { // Update position indices of instructions setPositions(); ByteArrayOutputStream b = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(b); try { for(InstructionHandle ih=start; ih != null; ih = ih.next) { Instruction i = ih.instruction; i.dump(out); // Traverse list } } catch(IOException e) { System.err.println(e); return null; } return b.toByteArray(); } /** * @return an array of instructions without target information for branch instructions. */ public Instruction[] getInstructions() { ByteSequence bytes = new ByteSequence(getByteCode()); Vector instructions = new Vector(); try { while(bytes.available() > 0) { instructions.addElement(Instruction.readInstruction(bytes)); } } catch(IOException e) { throw new ClassGenException(e.toString()); } Instruction[] result = new Instruction[instructions.size()]; instructions.copyInto(result); return result; } public String toString() { return toString(true); } /** * @param verbose toggle output format * @return String containing all instructions in this list. */ public String toString(boolean verbose) { StringBuffer buf = new StringBuffer(); for(InstructionHandle ih=start; ih != null; ih = ih.next) { buf.append(ih.toString(verbose) + "\n"); } return buf.toString(); } /** * @return Enumeration that lists all instructions (handles) */ public Enumeration elements() { return new Enumeration() { private InstructionHandle ih = start; public Object nextElement() { InstructionHandle i = ih; ih = ih.next; return i; } public boolean hasMoreElements() { return ih != null; } }; } /** * @return array containing all instructions (handles) */ public InstructionHandle[] getInstructionHandles() { InstructionHandle[] ihs = new InstructionHandle[length]; InstructionHandle ih = start; for(int i=0; i < length; i++) { ihs[i] = ih; ih = ih.next; } return ihs; } /** * Get positions (offsets) of all instructions in the list. This relies on that * the list has been freshly created from an byte code array, or that setPositions() * has been called. Otherwise this may be inaccurate. * * @return array containing all instruction's offset in byte code */ public int[] getInstructionPositions() { return byte_positions; } /** * @return complete, i.e., deep copy of this list */ public InstructionList copy() { Hashtable map = new Hashtable(); 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((InstructionHandle)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] = (InstructionHandle)map.get(itargets[j]); } } } ih = ih.next; ch = ch.next; } return il; } /** Replace all references to the old constant pool with references to the new * constant pool */ public void replaceConstantPool(ConstantPoolGen old_cp, ConstantPoolGen new_cp) { for(InstructionHandle ih=start; ih != null; ih = ih.next) { Instruction i = ih.instruction; if(i instanceof CPInstruction) { CPInstruction ci = (CPInstruction)i; Constant c = old_cp.getConstant(ci.getIndex()); ci.setIndex(new_cp.addConstant(c, old_cp)); } } } private void clear() { start = end = null; length = 0; } /** * Delete contents of list. Provides besser memory utilization, * because the system then may reuse the instruction handles. This * method is typically called right after * <href="MethodGen.html#getMethod()">MethodGen.getMethod()</a>. */ public void dispose() { // Traverse in reverse order, because ih.next is overwritten for(InstructionHandle ih=end; ih != null; ih = ih.prev) /* Causes BranchInstructions to release target and targeters, because it * calls dispose() on the contained instruction. */ ih.dispose(); clear(); } /** * @return start of list */ public InstructionHandle getStart() { return start; } /** * @return end of list */ public InstructionHandle getEnd() { return end; } /** * @return length of list (Number of instructions, not bytes) */ public int getLength() { return length; } /** * @return length of list (Number of instructions, not bytes) */ public int size() { return length; } /** * 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++) // Update targets if(targets[j] == old_target) ((Select)b).setTarget(j, new_target); } } } } /** * Redirect all references of local variables from old_target to new_target. * * @@param lg array of local variables * @@param old_target the old target instruction handle * @@param new_target the new target instruction handle * @@see MethodGen */ public void redirectLocalVariables(LocalVariableGen[] lg, InstructionHandle old_target, InstructionHandle new_target) { for(int i=0; i < lg.length; i++) { InstructionHandle start = lg[i].getStart(); InstructionHandle end = lg[i].getEnd(); if(start == old_target) lg[i].setStart(new_target); if(end == old_target) lg[i].setEnd(new_target); } } /** * Redirect all references of exception handlers from old_target to new_target. * * @@param exceptions array of exception handlers * @@param old_target the old target instruction handle * @@param new_target the new target instruction handle * @@see MethodGen */ public void redirectExceptionHandlers(CodeExceptionGen[] exceptions, InstructionHandle old_target, InstructionHandle new_target) { for(int i=0; i < exceptions.length; i++) { if(exceptions[i].getStartPC() == old_target) exceptions[i].setStartPC(new_target); if(exceptions[i].getEndPC() == old_target) exceptions[i].setEndPC(new_target); if(exceptions[i].getHandlerPC() == old_target) exceptions[i].setHandlerPC(new_target); } } private Vector observers; /** Add observer for this object. */ public void addObserver(InstructionListObserver o) { if(observers == null) observers = new Vector(); observers.addElement(o); } /** Remove observer for this object. */ public void removeObserver(InstructionListObserver o) { if(observers != null) observers.removeElement(o); } /** Call notify() method on all observers. This method is not called * automatically whenever the state has changed, but has to be * called by the user after he has finished editing the object. */ public void update() { if(observers != null) for(Enumeration e = observers.elements(); e.hasMoreElements(); ) ((InstructionListObserver)e.nextElement()).notify(this); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -