⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 instructionlist.java

📁 Java Bytecode Editor 是一个 JAVA 的字节码反汇编和修改器。它可以很方便的修改已经编译成 Class 文件的 JAVA 文件。
💻 JAVA
📖 第 1 页 / 共 3 页
字号:

  public boolean contains(Instruction i) {
    return findInstruction1(i) != null;
  }

  public void setPositions() {
    setPositions(false);
  }

  /**
   * Give all instructions their position number (offset in byte stream), i.e.,
   * make the list ready to be dumped.
   *
   * @param check Perform sanity checks, e.g. if all targeted instructions really belong
   * to this list
   */
  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());
    ArrayList<Instruction>     instructions = new ArrayList<Instruction>();

    try {
      while(bytes.available() > 0) {
	instructions.add(Instruction.readInstruction(bytes));
      }
    } catch(IOException e) { throw new ClassGenException(e.toString()); }

    Instruction[] result = new Instruction[instructions.size()];
    instructions.toArray(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 Iterator iterator() {
    return new Iterator() {
      private InstructionHandle ih = start;

      public Object next() {
	InstructionHandle i = ih;
	ih = ih.next;
	return i;
      }

      public void remove() {
	throw new UnsupportedOperationException();
      }

      public boolean hasNext() { 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() {
    HashMap<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((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 ArrayList<InstructionListObserver> observers;

  /** Add observer for this object.
   */
  public void addObserver(InstructionListObserver o) {
    if(observers == null)
      observers = new ArrayList<InstructionListObserver>();

    observers.add(o);
  }

  /** Remove observer for this object.
   */
  public void removeObserver(InstructionListObserver o) {
    if(observers != null)
      observers.remove(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(Iterator e = observers.iterator(); e.hasNext(); )
	((InstructionListObserver)e.next()).notify(this);
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -