Example #1
0
  /**
   * Constructs and inserts a new empty GOTO block {@code Z} between this block ({@code A}) and a
   * current successor block ({@code B}). The new block will replace B as A's successor and A as B's
   * predecessor. A and B will no longer be directly connected. If B is listed as a successor
   * multiple times, all references are replaced.
   *
   * @param other current successor (B)
   * @return {@code non-null;} an appropriately-constructed instance
   */
  public SsaBasicBlock insertNewSuccessor(SsaBasicBlock other) {
    SsaBasicBlock newSucc = parent.makeNewGotoBlock();

    if (!successors.get(other.index)) {
      throw new RuntimeException(
          "Block " + other.getRopLabelString() + " not successor of " + getRopLabelString());
    }

    // Update the new block.
    newSucc.predecessors.set(this.index);
    newSucc.successors.set(other.index);
    newSucc.successorList.add(other.index);
    newSucc.primarySuccessor = other.index;

    // Update us.
    for (int i = successorList.size() - 1; i >= 0; i--) {
      if (successorList.get(i) == other.index) {
        successorList.set(i, newSucc.index);
      }
    }

    if (primarySuccessor == other.index) {
      primarySuccessor = newSucc.index;
    }
    successors.clear(other.index);
    successors.set(newSucc.index);

    // Update "other".
    other.predecessors.set(newSucc.index);
    other.predecessors.set(index, successors.get(other.index));

    return newSucc;
  }
Example #2
0
  /**
   * Inserts a new empty GOTO block as a predecessor to this block. All previous predecessors will
   * be predecessors to the new block.
   *
   * @return {@code non-null;} an appropriately-constructed instance
   */
  public SsaBasicBlock insertNewPredecessor() {
    SsaBasicBlock newPred = parent.makeNewGotoBlock();

    // Update the new block.
    newPred.predecessors = predecessors;
    newPred.successors.set(index);
    newPred.successorList.add(index);
    newPred.primarySuccessor = index;

    // Update us.
    predecessors = new BitSet(parent.getBlocks().size());
    predecessors.set(newPred.index);

    // Update our (soon-to-be) old predecessors.
    for (int i = newPred.predecessors.nextSetBit(0);
        i >= 0;
        i = newPred.predecessors.nextSetBit(i + 1)) {

      SsaBasicBlock predBlock = parent.getBlocks().get(i);

      predBlock.replaceSuccessor(index, newPred.index);
    }

    return newPred;
  }
Example #3
0
  /**
   * Creates a new SSA basic block from a ROP form basic block.
   *
   * @param rmeth original method
   * @param basicBlockIndex index this block will have
   * @param parent method of this block predecessor set will be updated
   * @return new instance
   */
  public static SsaBasicBlock newFromRop(
      RopMethod rmeth, int basicBlockIndex, final SsaMethod parent) {
    BasicBlockList ropBlocks = rmeth.getBlocks();
    BasicBlock bb = ropBlocks.get(basicBlockIndex);
    SsaBasicBlock result = new SsaBasicBlock(basicBlockIndex, bb.getLabel(), parent);
    InsnList ropInsns = bb.getInsns();

    result.insns.ensureCapacity(ropInsns.size());

    for (int i = 0, sz = ropInsns.size(); i < sz; i++) {
      result.insns.add(new NormalSsaInsn(ropInsns.get(i), result));
    }

    result.predecessors =
        SsaMethod.bitSetFromLabelList(ropBlocks, rmeth.labelToPredecessors(bb.getLabel()));

    result.successors = SsaMethod.bitSetFromLabelList(ropBlocks, bb.getSuccessors());

    result.successorList = SsaMethod.indexListFromLabelList(ropBlocks, bb.getSuccessors());

    if (result.successorList.size() != 0) {
      int primarySuccessor = bb.getPrimarySuccessor();

      result.primarySuccessor =
          (primarySuccessor < 0) ? -1 : ropBlocks.indexOfLabel(primarySuccessor);
    }

    return result;
  }
Example #4
0
  /** Applies the optimization. */
  private void run() {
    int regSz = ssaMeth.getRegCount();

    ArrayList<TypedConstant> constantList = getConstsSortedByCountUse();

    int toCollect = Math.min(constantList.size(), MAX_COLLECTED_CONSTANTS);

    SsaBasicBlock start = ssaMeth.getEntryBlock();

    // Constant to new register containing the constant
    HashMap<TypedConstant, RegisterSpec> newRegs =
        new HashMap<TypedConstant, RegisterSpec>(toCollect);

    for (int i = 0; i < toCollect; i++) {
      TypedConstant cst = constantList.get(i);
      RegisterSpec result = RegisterSpec.make(ssaMeth.makeNewSsaReg(), cst);

      Rop constRop = Rops.opConst(cst);

      if (constRop.getBranchingness() == Rop.BRANCH_NONE) {
        start.addInsnToHead(
            new PlainCstInsn(
                Rops.opConst(cst), SourcePosition.NO_INFO, result, RegisterSpecList.EMPTY, cst));
      } else {
        // We need two new basic blocks along with the new insn
        SsaBasicBlock entryBlock = ssaMeth.getEntryBlock();
        SsaBasicBlock successorBlock = entryBlock.getPrimarySuccessor();

        // Insert a block containing the const insn.
        SsaBasicBlock constBlock = entryBlock.insertNewSuccessor(successorBlock);

        constBlock.replaceLastInsn(
            new ThrowingCstInsn(
                constRop, SourcePosition.NO_INFO, RegisterSpecList.EMPTY, StdTypeList.EMPTY, cst));

        // Insert a block containing the move-result-pseudo insn.

        SsaBasicBlock resultBlock = constBlock.insertNewSuccessor(successorBlock);
        PlainInsn insn =
            new PlainInsn(
                Rops.opMoveResultPseudo(result.getTypeBearer()),
                SourcePosition.NO_INFO,
                result,
                RegisterSpecList.EMPTY);

        resultBlock.addInsnToHead(insn);
      }

      newRegs.put(cst, result);
    }

    updateConstUses(newRegs, regSz);
  }
Example #5
0
  /**
   * Adds a move instruction to the end of this basic block, just before the last instruction. If
   * the result of the final instruction is the source in question, then the move is placed at the
   * beginning of the primary successor block. This is for unversioned registers.
   *
   * @param result move destination
   * @param source move source
   */
  public void addMoveToEnd(RegisterSpec result, RegisterSpec source) {

    if (result.getReg() == source.getReg()) {
      // Sometimes we end up with no-op moves. Ignore them here.
      return;
    }

    /*
     * The last Insn has to be a normal SSA insn: a phi can't branch or
     * return or cause an exception, etc.
     */
    NormalSsaInsn lastInsn;
    lastInsn = (NormalSsaInsn) insns.get(insns.size() - 1);

    if (lastInsn.getResult() != null || lastInsn.getSources().size() > 0) {
      /*
       * The final insn in this block has a source or result register, and
       * the moves we may need to place and schedule may interfere. We
       * need to insert this instruction at the beginning of the primary
       * successor block instead. We know this is safe, because when we
       * edge-split earlier, we ensured that each successor has only us as
       * a predecessor.
       */

      for (int i = successors.nextSetBit(0); i >= 0; i = successors.nextSetBit(i + 1)) {

        SsaBasicBlock succ;

        succ = parent.getBlocks().get(i);
        succ.addMoveToBeginning(result, source);
      }
    } else {
      /*
       * We can safely add a move to the end of the block just before the
       * last instruction, because the final insn does not assign to
       * anything.
       */
      RegisterSpecList sources = RegisterSpecList.make(source);
      NormalSsaInsn toAdd =
          new NormalSsaInsn(
              new PlainInsn(Rops.opMove(result.getType()), SourcePosition.NO_INFO, result, sources),
              this);

      insns.add(insns.size() - 1, toAdd);

      movesFromPhisAtEnd++;
    }
  }
Example #6
0
  /**
   * Processes a single block.
   *
   * @param blockIndex {@code >= 0;} block index of the block to process
   */
  private void processBlock(int blockIndex) {
    RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(blockIndex);
    SsaBasicBlock block = blocks.get(blockIndex);
    List<SsaInsn> insns = block.getInsns();
    int insnSz = insns.size();

    // The exit block has no insns and no successors
    if (blockIndex == method.getExitBlockIndex()) {
      return;
    }

    /*
     * We may have to treat the last instruction specially: If it
     * can (but doesn't always) throw, and the exception can be
     * caught within the same method, then we need to use the
     * state *before* executing it to be what is merged into
     * exception targets.
     */
    SsaInsn lastInsn = insns.get(insnSz - 1);
    boolean hasExceptionHandlers = lastInsn.getOriginalRopInsn().getCatches().size() != 0;
    boolean canThrowDuringLastInsn = hasExceptionHandlers && (lastInsn.getResult() != null);
    int freezeSecondaryStateAt = insnSz - 1;
    RegisterSpecSet secondaryState = primaryState;

    /*
     * Iterate over the instructions, adding information for each place
     * that the active variable set changes.
     */

    for (int i = 0; i < insnSz; i++) {
      if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) {
        // Until this point, primaryState == secondaryState.
        primaryState.setImmutable();
        primaryState = primaryState.mutableCopy();
      }

      SsaInsn insn = insns.get(i);
      RegisterSpec result;

      result = insn.getLocalAssignment();

      if (result == null) {
        // We may be nuking an existing local

        result = insn.getResult();

        if (result != null && primaryState.get(result.getReg()) != null) {
          primaryState.remove(primaryState.get(result.getReg()));
        }
        continue;
      }

      result = result.withSimpleType();

      RegisterSpec already = primaryState.get(result);
      /*
       * The equals() check ensures we only add new info if
       * the instruction causes a change to the set of
       * active variables.
       */
      if (!result.equals(already)) {
        /*
         * If this insn represents a local moving from one register
         * to another, remove the association between the old register
         * and the local.
         */
        RegisterSpec previous = primaryState.localItemToSpec(result.getLocalItem());

        if (previous != null && (previous.getReg() != result.getReg())) {

          primaryState.remove(previous);
        }

        resultInfo.addAssignment(insn, result);
        primaryState.put(result);
      }
    }

    primaryState.setImmutable();

    /*
     * Merge this state into the start state for each successor,
     * and update the work set where required (that is, in cases
     * where the start state for a block changes).
     */

    IntList successors = block.getSuccessorList();
    int succSz = successors.size();
    int primarySuccessor = block.getPrimarySuccessorIndex();

    for (int i = 0; i < succSz; i++) {
      int succ = successors.get(i);
      RegisterSpecSet state = (succ == primarySuccessor) ? primaryState : secondaryState;

      if (resultInfo.mergeStarts(succ, state)) {
        workSet.set(succ);
      }
    }
  }