Example #1
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;
  }
Example #2
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;
    }
  }
Example #3
0
 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();
 }
  /** 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);
  }
  /**
   * 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;
  }
 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();
 }
  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;
  }
Example #8
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();
    }
  }
  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;
  }
  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]);
    }
  }
Example #11
0
  /**
   * Constructor.
   *
   * @param il A MethodGen object representing method to create the Subroutine objects of.
   */
  public Subroutines(MethodGen mg) {

    InstructionHandle[] all = mg.getInstructionList().getInstructionHandles();
    CodeExceptionGen[] handlers = mg.getExceptionHandlers();

    // Define our "Toplevel" fake subroutine.
    TOPLEVEL = new SubroutineImpl();

    // Calculate "real" subroutines.
    HashSet<InstructionHandle> sub_leaders =
        new HashSet<InstructionHandle>(); // Elements: InstructionHandle
    for (int i = 0; i < all.length; i++) {
      Instruction inst = all[i].getInstruction();
      if (inst instanceof JsrInstruction) {
        sub_leaders.add(((JsrInstruction) inst).getTarget());
      }
    }

    // Build up the database.
    Iterator iter = sub_leaders.iterator();
    while (iter.hasNext()) {
      SubroutineImpl sr = new SubroutineImpl();
      InstructionHandle astore = (InstructionHandle) (iter.next());
      sr.setLocalVariable(((ASTORE) (astore.getInstruction())).getIndex());
      subroutines.put(astore, sr);
    }

    // Fake it a bit. We want a virtual "TopLevel" subroutine.
    subroutines.put(all[0], TOPLEVEL);
    sub_leaders.add(all[0]);

    // Tell the subroutines about their JsrInstructions.
    // Note that there cannot be a JSR targeting the top-level
    // since "Jsr 0" is disallowed in Pass 3a.
    // Instructions shared by a subroutine and the toplevel are
    // disallowed and checked below, after the BFS.
    for (int i = 0; i < all.length; i++) {
      Instruction inst = all[i].getInstruction();
      if (inst instanceof JsrInstruction) {
        InstructionHandle leader = ((JsrInstruction) inst).getTarget();
        ((SubroutineImpl) getSubroutine(leader)).addEnteringJsrInstruction(all[i]);
      }
    }

    // Now do a BFS from every subroutine leader to find all the
    // instructions that belong to a subroutine.
    HashSet<InstructionHandle> instructions_assigned =
        new HashSet<InstructionHandle>(); // we don't want to assign an instruction to two or more
    // Subroutine objects.

    Hashtable<InstructionHandle, Color> colors =
        new Hashtable<
            InstructionHandle,
            Color>(); // Graph colouring. Key: InstructionHandle, Value: java.awt.Color .

    iter = sub_leaders.iterator();
    while (iter.hasNext()) {
      // Do some BFS with "actual" as the root of the graph.
      InstructionHandle actual = (InstructionHandle) (iter.next());
      // Init colors
      for (int i = 0; i < all.length; i++) {
        colors.put(all[i], Color.white);
      }
      colors.put(actual, Color.gray);
      // Init Queue
      ArrayList<InstructionHandle> Q = new ArrayList<InstructionHandle>();
      Q.add(actual); // add(Obj) adds to the end, remove(0) removes from the start.

      /* BFS ALGORITHM MODIFICATION: Start out with multiple "root" nodes, as exception handlers are starting points of top-level code, too. [why top-level? TODO: Refer to the special JustIce notion of subroutines.]*/
      if (actual == all[0]) {
        for (int j = 0; j < handlers.length; j++) {
          colors.put(handlers[j].getHandlerPC(), Color.gray);
          Q.add(handlers[j].getHandlerPC());
        }
      }
      /* CONTINUE NORMAL BFS ALGORITHM */

      // Loop until Queue is empty
      while (Q.size() != 0) {
        InstructionHandle u = (InstructionHandle) Q.remove(0);
        InstructionHandle[] successors = getSuccessors(u);
        for (int i = 0; i < successors.length; i++) {
          if (((Color) colors.get(successors[i])) == Color.white) {
            colors.put(successors[i], Color.gray);
            Q.add(successors[i]);
          }
        }
        colors.put(u, Color.black);
      }
      // BFS ended above.
      for (int i = 0; i < all.length; i++) {
        if (colors.get(all[i]) == Color.black) {
          ((SubroutineImpl) (actual == all[0] ? getTopLevel() : getSubroutine(actual)))
              .addInstruction(all[i]);
          if (instructions_assigned.contains(all[i])) {
            throw new StructuralCodeConstraintException(
                "Instruction '"
                    + all[i]
                    + "' is part of more than one subroutine (or of the top level and a subroutine).");
          } else {
            instructions_assigned.add(all[i]);
          }
        }
      }
      if (actual != all[0]) { // If we don't deal with the top-level 'subroutine'
        ((SubroutineImpl) getSubroutine(actual)).setLeavingRET();
      }
    }

    // Now make sure no instruction of a Subroutine is protected by exception handling code
    // as is mandated by JustIces notion of subroutines.
    for (int i = 0; i < handlers.length; i++) {
      InstructionHandle _protected = handlers[i].getStartPC();
      while (_protected
          != handlers[i]
              .getEndPC()
              .getNext()) { // Note the inclusive/inclusive notation of "generic API" exception
        // handlers!
        Enumeration subs = subroutines.elements();
        while (subs.hasMoreElements()) {
          Subroutine sub = (Subroutine) subs.nextElement();
          if (sub
              != subroutines.get(all[0])) { // We don't want to forbid top-level exception handlers.
            if (sub.contains(_protected)) {
              throw new StructuralCodeConstraintException(
                  "Subroutine instruction '"
                      + _protected
                      + "' is protected by an exception handler, '"
                      + handlers[i]
                      + "'. This is forbidden by the JustIce verifier due to its clear definition of subroutines.");
            }
          }
        }
        _protected = _protected.getNext();
      }
    }

    // Now make sure no subroutine is calling a subroutine
    // that uses the same local variable for the RET as themselves
    // (recursively).
    // This includes that subroutines may not call themselves
    // recursively, even not through intermediate calls to other
    // subroutines.
    noRecursiveCalls(getTopLevel(), new HashSet<Integer>());
  }