예제 #1
0
파일: BCEL.java 프로젝트: tempbottle/ASM
 byte[] nullAdaptClass(final InputStream is, final String name) throws Exception {
   JavaClass jc = new ClassParser(is, name + ".class").parse();
   ClassGen cg = new ClassGen(jc);
   String cName = cg.getClassName();
   ConstantPoolGen cp = cg.getConstantPool();
   Method[] ms = cg.getMethods();
   for (int j = 0; j < ms.length; ++j) {
     MethodGen mg = new MethodGen(ms[j], cg.getClassName(), cp);
     boolean lv = ms[j].getLocalVariableTable() == null;
     boolean ln = ms[j].getLineNumberTable() == null;
     if (lv) {
       mg.removeLocalVariables();
     }
     if (ln) {
       mg.removeLineNumbers();
     }
     mg.stripAttributes(skipDebug);
     InstructionList il = mg.getInstructionList();
     if (il != null) {
       InstructionHandle ih = il.getStart();
       while (ih != null) {
         ih = ih.getNext();
       }
       if (compute) {
         mg.setMaxStack();
         mg.setMaxLocals();
       }
     }
     cg.replaceMethod(ms[j], mg.getMethod());
   }
   return cg.getJavaClass().getBytes();
 }
예제 #2
0
 /**
  * @param verbose toggle output format
  * @return String containing all instructions in this list.
  */
 public String toString(boolean verbose) {
   StringBuilder buf = new StringBuilder();
   for (InstructionHandle ih = start; ih != null; ih = ih.next) {
     buf.append(ih.toString(verbose)).append("\n");
   }
   return buf.toString();
 }
예제 #3
0
 /**
  * Sets the leaving RET instruction. Must be invoked after all instructions are added. Must not
  * be invoked for top-level 'subroutine'.
  */
 void setLeavingRET() {
   if (localVariable == UNSET) {
     throw new AssertionViolatedException(
         "setLeavingRET() called for top-level 'subroutine' or forgot to set local variable first.");
   }
   Iterator iter = instructions.iterator();
   InstructionHandle ret = null;
   while (iter.hasNext()) {
     InstructionHandle actual = (InstructionHandle) iter.next();
     if (actual.getInstruction() instanceof RET) {
       if (ret != null) {
         throw new StructuralCodeConstraintException(
             "Subroutine with more then one RET detected: '" + ret + "' and '" + actual + "'.");
       } else {
         ret = actual;
       }
     }
   }
   if (ret == null) {
     throw new StructuralCodeConstraintException("Subroutine without a RET detected.");
   }
   if (((RET) ret.getInstruction()).getIndex() != localVariable) {
     throw new StructuralCodeConstraintException(
         "Subroutine uses '"
             + ret
             + "' which does not match the correct local variable '"
             + localVariable
             + "'.");
   }
   theRET = ret;
 }
예제 #4
0
 /**
  * Get CodeException object.<br>
  * This relies on that the instruction list has already been dumped to byte code or or that the
  * `setPositions' methods has been called for the instruction list.
  *
  * @param cp constant pool
  */
 public CodeException getCodeException(ConstantPoolGen cp) {
   return new CodeException(
       start_pc.getPosition(),
       end_pc.getPosition() + end_pc.getInstruction().getLength(),
       handler_pc.getPosition(),
       (catch_type == null) ? 0 : cp.addClass(catch_type));
 }
예제 #5
0
  /** Instrument the specified method to replace mapped calls. */
  public void instrument_method(Method m, MethodGen mg) {

    // Loop through each instruction, making substitutions
    InstructionList il = mg.getInstructionList();
    for (InstructionHandle ih = il.getStart(); ih != null; ) {
      if (debug_instrument_inst.enabled()) {
        debug_instrument_inst.log("instrumenting instruction %s%n", ih);
        // ih.getInstruction().toString(pool.getConstantPool()));
      }
      InstructionList new_il = null;

      // Remember the next instruction to process
      InstructionHandle next_ih = ih.getNext();

      // Get the translation for this instruction (if any)
      new_il = xform_inst(mg, ih.getInstruction());
      if (debug_instrument_inst.enabled()) debug_instrument_inst.log("  new inst: %s%n", new_il);

      // If this instruction was modified, replace it with the new
      // instruction list. If this instruction was the target of any
      // jumps or line numbers , replace them with the first
      // instruction in the new list
      replace_instructions(il, ih, new_il);

      ih = next_ih;
    }
  }
예제 #6
0
  CFG createCFG(String className) throws ClassNotFoundException {
    CFG cfg = new CFG();
    JavaClass jc = Repository.lookupClass(className);
    ClassGen cg = new ClassGen(jc);
    ConstantPoolGen cpg = cg.getConstantPool();
    for (Method m : cg.getMethods()) {
      MethodGen mg = new MethodGen(m, cg.getClassName(), cpg);
      InstructionList il = mg.getInstructionList();
      InstructionHandle[] handles = il.getInstructionHandles();
      int prev = 0;
      for (InstructionHandle ih : handles) {
        int position = ih.getPosition();
        cfg.addNode(position, m, jc);
        Instruction inst = ih.getInstruction();

        boolean br = inst.getName().contains("if") || inst.getName().contains("goto");
        boolean ret = inst.getName().contains("return");
        boolean stat = inst.getName().contains("invokestatic");
        int len = inst.getLength();

        if (stat) {
          int index = inst.toString(true).indexOf(" ");
          String name = inst.toString(true).substring(index + 1);
          int tar = Integer.valueOf(name);
          INVOKESTATIC inv = new INVOKESTATIC(tar);
          name = inv.getMethodName(cpg);

          Method m2 = null;
          Method[] tm = cg.getMethods();
          for (int i = 0; i < tm.length; i++) {
            if (tm[i].getName().equals(name)) {
              m2 = tm[i];
            }
          }
          cfg.addEdge(position, m, jc, 0, m2, jc);
          cfg.addEdge(-1, m2, jc, position + len, m, jc);
        }

        if (!ret && !stat) {
          cfg.addEdge(position, position + len, m, jc);
        }
        if (br) {
          cfg.addEdge(position, position + len, m, jc);
          IF_ICMPGE comp = new IF_ICMPGE(ih);
          String name = comp.getTarget().toString(false);
          int index = name.indexOf(">");
          name = name.substring(index + 2);
          int tar = Integer.valueOf(name);
          cfg.addEdge(position, tar, m, jc);
        }
        if (ret) {
          cfg.addEdge(position, -1, m, jc);
        }

        prev = position;
      }
      System.out.println(cfg.toString());
    }
    return cfg;
  }
예제 #7
0
  /** Build the array of line number information for the optimized instruction sequence. */
  private LineNumberInfo[] buildLineNumberInfo() {
    Vector lineNumbers = new Vector();

    for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) {
      handle.addLineNumberInfo(lineNumbers);
    }

    return (LineNumberInfo[]) Utils.toArray(lineNumbers, LineNumberInfo.class);
  }
예제 #8
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();
 }
예제 #9
0
 private void dumpCode() {
   int i = 0;
   for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) {
     System.err.println(
         i++
             + ":\t"
             + org.caesarj.classfile.OpcodeNames.getName(handle.getInstruction().getOpcode()));
   }
   System.err.flush();
 }
예제 #10
0
  /** Start the method's visit. */
  public void start() {
    if (!mg.isAbstract() && !mg.isNative()) {
      for (InstructionHandle ih = mg.getInstructionList().getStart();
          ih != null;
          ih = ih.getNext()) {
        Instruction i = ih.getInstruction();

        if (!visitInstruction(i)) i.accept(this);
      }
      updateExceptionHandlers();
    }
  }
예제 #11
0
  /**
   * Get LocalVariable object.
   *
   * <p>This relies on that the instruction list has already been dumped to byte code or or that the
   * `setPositions' methods has been called for the instruction list.
   *
   * <p>Note that for local variables whose scope end at the last instruction of the method's code,
   * the JVM specification is ambiguous: both a start_pc+length ending at the last instruction and
   * start_pc+length ending at first index beyond the end of the code are valid.
   *
   * @param il instruction list (byte code) which this variable belongs to
   * @param cp constant pool
   */
  public LocalVariable getLocalVariable(ConstantPoolGen cp) {
    int start_pc = start.getPosition();
    int length = end.getPosition() - start_pc;

    if (length > 0) length += end.getInstruction().getLength();

    int name_index = cp.addUtf8(name);
    int signature_index = cp.addUtf8(type.getSignature());

    return new LocalVariable(
        start_pc, length, name_index, signature_index, index, cp.getConstantPool());
  }
예제 #12
0
 /**
  * Insert an instruction at start of this list.
  *
  * @param ih instruction to insert
  */
 private void insert(InstructionHandle ih) {
   if (isEmpty()) {
     start = end = ih;
     ih.next = ih.prev = null;
   } else {
     start.prev = ih;
     ih.next = start;
     ih.prev = null;
     start = ih;
   }
   length++;
 }
예제 #13
0
  /**
   * A utility method that calculates the successors of a given InstructionHandle <B>in the same
   * subroutine</B>. That means, a RET does not have any successors as defined here. A
   * JsrInstruction has its physical successor as its successor (opposed to its target) as defined
   * here.
   */
  private static InstructionHandle[] getSuccessors(InstructionHandle instruction) {
    final InstructionHandle[] empty = new InstructionHandle[0];
    final InstructionHandle[] single = new InstructionHandle[1];
    final InstructionHandle[] pair = new InstructionHandle[2];

    Instruction inst = instruction.getInstruction();

    if (inst instanceof RET) {
      return empty;
    }

    // Terminates method normally.
    if (inst instanceof ReturnInstruction) {
      return empty;
    }

    // Terminates method abnormally, because JustIce mandates
    // subroutines not to be protected by exception handlers.
    if (inst instanceof ATHROW) {
      return empty;
    }

    // See method comment.
    if (inst instanceof JsrInstruction) {
      single[0] = instruction.getNext();
      return single;
    }

    if (inst instanceof GotoInstruction) {
      single[0] = ((GotoInstruction) inst).getTarget();
      return single;
    }

    if (inst instanceof BranchInstruction) {
      if (inst instanceof Select) {
        // BCEL's getTargets() returns only the non-default targets,
        // thanks to Eli Tilevich for reporting.
        InstructionHandle[] matchTargets = ((Select) inst).getTargets();
        InstructionHandle[] ret = new InstructionHandle[matchTargets.length + 1];
        ret[0] = ((Select) inst).getTarget();
        System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length);
        return ret;
      } else {
        pair[0] = instruction.getNext();
        pair[1] = ((BranchInstruction) inst).getTarget();
        return pair;
      }
    }

    // default case: Fall through.
    single[0] = instruction.getNext();
    return single;
  }
예제 #14
0
 /**
  * Append an instruction to the end of this list.
  *
  * @param ih instruction to append
  */
 private void append(InstructionHandle ih) {
   if (isEmpty()) {
     start = end = ih;
     ih.next = ih.prev = null;
   } else {
     end.next = ih;
     ih.prev = end;
     ih.next = null;
     end = ih;
   }
   length++; // Update length
 }
예제 #15
0
  private boolean optimizeCodeSequence() {
    boolean codeChanged = false;

    buildBasicBlocks(codeStart);

    for (InstructionHandle handle = codeStart; handle != null; handle = handle.getNext()) {
      codeChanged |= Patterns.optimize(handle);
    }

    codeChanged |= cleanCode();

    return codeChanged;
  }
예제 #16
0
  /**
   * Replace instruction ih in list il with the instructions in new_il. If new_il is null, do
   * nothing
   */
  protected static void replace_instructions(
      InstructionList il, InstructionHandle ih, InstructionList new_il) {

    if ((new_il == null) || new_il.isEmpty()) return;

    // If there is only one new instruction, just replace it in the handle
    if (new_il.getLength() == 1) {
      ih.setInstruction(new_il.getEnd().getInstruction());
      return;
    }

    // Get the start and end instruction of the new instructions
    InstructionHandle new_end = new_il.getEnd();
    InstructionHandle new_start = il.insert(ih, new_il);

    // Move all of the branches from the old instruction to the new start
    il.redirectBranches(ih, new_start);

    // Move other targets to the new instuctions.
    if (ih.hasTargeters()) {
      for (InstructionTargeter it : ih.getTargeters()) {
        if (it instanceof LineNumberGen) {
          it.updateTarget(ih, new_start);
        } else if (it instanceof LocalVariableGen) {
          it.updateTarget(ih, new_end);
        } else if (it instanceof CodeExceptionGen) {
          CodeExceptionGen exc = (CodeExceptionGen) it;
          if (exc.getStartPC() == ih) exc.updateTarget(ih, new_start);
          else if (exc.getEndPC() == ih) exc.updateTarget(ih, new_end);
          else if (exc.getHandlerPC() == ih) exc.setHandlerPC(new_start);
          else System.out.printf("Malformed CodeException: %s%n", exc);
        } else {
          System.out.printf("unexpected target %s%n", it);
        }
      }
    }

    // Remove the old handle.  There should be no targeters left to it.
    try {
      il.delete(ih);
    } catch (Exception e) {
      throw new Error("Can't delete instruction", e);
    }
  }
예제 #17
0
  /**
   * Build the array of the instructions resulting from the optimization process.
   *
   * @return the array of instructions
   */
  private Instruction[] buildInstructionArray() {
    int length;

    // count size of instruction array
    length = 0;
    for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) {
      length += 1;
    }

    Instruction[] insns = new Instruction[length];

    length = 0;
    for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) {
      insns[length] = handle.getInstruction();
      length += 1;
    }

    return insns;
  }
예제 #18
0
  /**
   * Long output format:
   *
   * <p>&lt;position in byte code&gt; &lt;name of opcode&gt; "["&lt;opcode number&gt;"]"
   * "("&lt;length of instruction&gt;")" "&lt;"&lt;target instruction&gt;"&gt;" "@"&lt;branch target
   * offset&gt;
   *
   * @param verbose long/short format switch
   * @return mnemonic for instruction
   */
  public String toString(boolean verbose) {
    String s = super.toString(verbose);
    String t = "null";

    if (verbose) {
      if (target != null) {
        if (target.getInstruction() == this) t = "<points to itself>";
        else if (target.getInstruction() == null) t = "<null instruction!!!?>";
        else t = target.getInstruction().toString(false); // Avoid circles
      }
    } else {
      if (target != null) {
        index = getTargetOffset();
        t = "" + (index + position);
      }
    }

    return s + " -> " + t;
  }
예제 #19
0
 /** Adds a new JSR or JSR_W that has this subroutine as its target. */
 public void addEnteringJsrInstruction(InstructionHandle jsrInst) {
   if ((jsrInst == null) || (!(jsrInst.getInstruction() instanceof JsrInstruction))) {
     throw new AssertionViolatedException("Expecting JsrInstruction InstructionHandle.");
   }
   if (localVariable == UNSET) {
     throw new AssertionViolatedException("Set the localVariable first!");
   } else {
     // Something is wrong when an ASTORE is targeted that does not operate on the same local
     // variable than the rest of the
     // JsrInstruction-targets and the RET.
     // (We don't know out leader here so we cannot check if we're really targeted!)
     if (localVariable
         != ((ASTORE) (((JsrInstruction) jsrInst.getInstruction()).getTarget().getInstruction()))
             .getIndex()) {
       throw new AssertionViolatedException("Setting a wrong JsrInstruction.");
     }
   }
   theJSRs.add(jsrInst);
 }
예제 #20
0
 /**
  * Append another list after instruction (handle) ih contained in this list. Consumes argument
  * list, i.e., it becomes empty.
  *
  * @param ih where to append the instruction list
  * @param il Instruction list to append to this one
  * @return instruction handle pointing to the <B>first</B> appended instruction
  */
 public InstructionHandle append(InstructionHandle ih, InstructionList il) {
   if (il == null) {
     throw new ClassGenException("Appending null InstructionList");
   }
   if (il.isEmpty()) {
     return ih;
   }
   InstructionHandle next = ih.next, ret = il.start;
   ih.next = il.start;
   il.start.prev = ih;
   il.end.next = next;
   if (next != null) {
     next.prev = il.end;
   } else {
     end = il.end; // Update end ...
   }
   length += il.length; // Update length
   il.clear();
   return ret;
 }
예제 #21
0
 /**
  * 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);
           }
         }
       }
     }
   }
 }
예제 #22
0
 /**
  * Insert another list before Instruction handle ih contained in this list. Consumes argument
  * list, i.e., it becomes empty.
  *
  * @param ih where to append the instruction list
  * @param il Instruction list to insert
  * @return instruction handle of the first inserted instruction
  */
 public InstructionHandle insert(InstructionHandle ih, InstructionList il) {
   if (il == null) {
     throw new ClassGenException("Inserting null InstructionList");
   }
   if (il.isEmpty()) {
     return ih;
   }
   InstructionHandle prev = ih.prev, ret = il.start;
   ih.prev = il.end;
   il.end.next = ih;
   il.start.prev = prev;
   if (prev != null) {
     prev.next = il.start;
   } else {
     start = il.start; // Update start ...
   }
   length += il.length; // Update length
   il.clear();
   return ret;
 }
예제 #23
0
  private void buildBasicBlocks(InstructionHandle start) {
    for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) {
      handle.reset();
    }

    for (int i = 0; i < handlers.length; i++) {
      // !!! if (start.isReachable())
      ((InstructionHandle) handlers[i].getHandler()).addAccessor(handlers[i]);
      ((InstructionHandle) handlers[i].getStart()).addAccessor(handlers[i]);
      // !!! WHY ??? graf 010111
      // ((InstructionHandle)handlers[i].getEnd()).addAccessor(handlers[i]);
      // !!! WHY ??? graf 010111
    }

    // add local variable infos as accessors to their start and end instructions in order
    // to be notified by changes.
    for (int j = 0; localVariables != null && j < localVariables.length; j++) {

      ((InstructionHandle) localVariables[j].getEnd()).addAccessor(localVariables[j]);
      ((InstructionHandle) localVariables[j].getStart()).addAccessor(localVariables[j]);
    }
  }
예제 #24
0
  /**
   * @param target branch target
   * @return the offset to `target' relative to this instruction
   */
  protected int getTargetOffset(InstructionHandle target) {
    if (target == null)
      throw new ClassGenException("Target of " + super.toString(true) + " is invalid null handle");

    int t = target.getPosition();

    if (t < 0)
      throw new ClassGenException(
          "Invalid branch target position offset for "
              + super.toString(true)
              + ":"
              + t
              + ":"
              + target);

    return t - position;
  }
예제 #25
0
  private boolean cleanCode() {
    boolean codeRemoved = false;

    // Test if all end-instructions are reached... (copied from exception"handlers" see below)
    for (int j = 0; localVariables != null && j < localVariables.length; j++) {
      while (!((InstructionHandle) localVariables[j].getEnd()).isReached()) {
        localVariables[j].setEnd(((InstructionHandle) localVariables[j].getEnd()).getPrevious());
      }
    }

    for (int i = 0; i < handlers.length; i++) {
      while (!((InstructionHandle) handlers[i].getEnd()).isReached()) {
        handlers[i].setEnd(((InstructionHandle) handlers[i].getEnd()).getPrevious());
      }

      // !!!if (start > end) remove handler
    }

    InstructionHandle current = codeStart;

    for (InstructionHandle handle = current.getNext(); handle != null; handle = handle.getNext()) {
      if (handle.isReached()) {
        current.setNext(handle);
        current = handle;
      } else {
        current.setNext(null);
        codeRemoved = true;
      }
      /* Andreas start
      handle.clean();
      */
      handle._clean();
      // Andreas end
    }

    if (current == codeStart) {
      codeStart.setNext(null);
    }

    return codeRemoved;
  }
예제 #26
0
    /*
     * Satisfies Subroutine.getAccessedLocalIndices().
     */
    public int[] getAccessedLocalsIndices() {
      // TODO: Implement caching.
      HashSet<Integer> acc = new HashSet<Integer>();
      if (theRET == null && this != TOPLEVEL) {
        throw new AssertionViolatedException(
            "This subroutine object must be built up completely before calculating accessed locals.");
      }
      Iterator i = instructions.iterator();
      while (i.hasNext()) {
        InstructionHandle ih = (InstructionHandle) i.next();
        // RET is not a LocalVariableInstruction in the current version of BCEL.
        if (ih.getInstruction() instanceof LocalVariableInstruction
            || ih.getInstruction() instanceof RET) {
          int idx = ((IndexedInstruction) (ih.getInstruction())).getIndex();
          acc.add(new Integer(idx));
          // LONG? DOUBLE?.
          try {
            // LocalVariableInstruction instances are typed without the need to look into
            // the constant pool.
            if (ih.getInstruction() instanceof LocalVariableInstruction) {
              int s = ((LocalVariableInstruction) ih.getInstruction()).getType(null).getSize();
              if (s == 2) acc.add(new Integer(idx + 1));
            }
          } catch (RuntimeException re) {
            throw new AssertionViolatedException(
                "Oops. BCEL did not like NULL as a ConstantPoolGen object.");
          }
        }
      }

      int[] ret = new int[acc.size()];
      i = acc.iterator();
      int j = -1;
      while (i.hasNext()) {
        j++;
        ret[j] = ((Integer) i.next()).intValue();
      }
      return ret;
    }
예제 #27
0
 /**
  * Get LineNumber attribute .
  *
  * <p>This relies on that the instruction list has already been dumped to byte code or or that the
  * `setPositions' methods has been called for the instruction list.
  */
 public LineNumber getLineNumber() {
   return new LineNumber(ih.getPosition(), src_line);
 }
예제 #28
0
 /**
  * Take all instructions (handles) from "start" to "end" and append them after the new location
  * "target". Of course, "end" must be after "start" and target must not be located withing this
  * range. If you want to move something to the start of the list use null as value for target.<br>
  * Any instruction targeters pointing to handles within the block, keep their targets.
  *
  * @param start of moved block
  * @param end of moved block
  * @param target of moved block
  */
 public void move(InstructionHandle start, InstructionHandle end, InstructionHandle target) {
   // Step 1: Check constraints
   if ((start == null) || (end == null)) {
     throw new ClassGenException("Invalid null handle: From " + start + " to " + end);
   }
   if ((target == start) || (target == end)) {
     throw new ClassGenException(
         "Invalid range: From " + start + " to " + end + " contains target " + target);
   }
   for (InstructionHandle ih = start; ih != end.next; ih = ih.next) {
     if (ih == null) {
       throw new ClassGenException("Invalid range: From " + start + " to " + end);
     } else if (ih == target) {
       throw new ClassGenException(
           "Invalid range: From " + start + " to " + end + " contains target " + target);
     }
   }
   // Step 2: Temporarily remove the given instructions from the list
   InstructionHandle prev = start.prev, next = end.next;
   if (prev != null) {
     prev.next = next;
   } else {
     this.start = next;
   }
   if (next != null) {
     next.prev = prev;
   } else {
     this.end = prev;
   }
   start.prev = end.next = null;
   // Step 3: append after target
   if (target == null) { // append to start of list
     if (this.start != null) {
       this.start.prev = end;
     }
     end.next = this.start;
     this.start = start;
   } else {
     next = target.next;
     target.next = start;
     start.prev = target;
     end.next = next;
     if (next != null) {
       next.prev = end;
     } else {
       this.end = end;
     }
   }
 }
예제 #29
0
 /**
  * Remove from instruction `prev' to instruction `next' both contained in this list. Throws
  * TargetLostException when one of the removed instruction handles is still being targeted.
  *
  * @param prev where to start deleting (predecessor, exclusive)
  * @param next where to end deleting (successor, exclusive)
  */
 private void remove(InstructionHandle prev, InstructionHandle next) throws TargetLostException {
   InstructionHandle first, last; // First and last deleted instruction
   if ((prev == null) && (next == null)) {
     first = start;
     last = end;
     start = end = null;
   } else {
     if (prev == null) { // At start of list
       first = start;
       start = next;
     } else {
       first = prev.next;
       prev.next = next;
     }
     if (next == null) { // At end of list
       last = end;
       end = prev;
     } else {
       last = next.prev;
       next.prev = prev;
     }
   }
   first.prev = null; // Completely separated from rest of list
   last.next = null;
   List<InstructionHandle> target_vec = new ArrayList<InstructionHandle>();
   for (InstructionHandle ih = first; ih != null; ih = ih.next) {
     ih.getInstruction().dispose(); // e.g. BranchInstructions release their targets
   }
   StringBuilder buf = new StringBuilder("{ ");
   for (InstructionHandle ih = first; ih != null; ih = next) {
     next = ih.next;
     length--;
     if (ih.hasTargeters()) { // Still got targeters?
       target_vec.add(ih);
       buf.append(ih.toString(true) + " ");
       ih.next = ih.prev = null;
     } else {
       ih.dispose();
     }
   }
   buf.append("}");
   if (!target_vec.isEmpty()) {
     InstructionHandle[] targeted = new InstructionHandle[target_vec.size()];
     target_vec.toArray(targeted);
     throw new TargetLostException(targeted, buf.toString());
   }
 }
예제 #30
0
 /**
  * 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 (InstructionHandle target : targets) {
             inst = target.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);
 }