예제 #1
0
 /**
  * Returns true if the register contains an integer 0 or a known-null object reference
  *
  * @param spec non-null spec
  * @return true for 0 or null type bearers
  */
 private static boolean isConstIntZeroOrKnownNull(RegisterSpec spec) {
   TypeBearer tb = spec.getTypeBearer();
   if (tb instanceof CstLiteralBits) {
     CstLiteralBits clb = (CstLiteralBits) tb;
     return (clb.getLongBits() == 0);
   }
   return false;
 }
예제 #2
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);
  }
예제 #3
0
  /**
   * Gets all of the collectable constant values used in this method, sorted by most used first.
   * Skips non-collectable consts, such as non-string object constants
   *
   * @return {@code non-null;} list of constants in most-to-least used order
   */
  private ArrayList<TypedConstant> getConstsSortedByCountUse() {
    int regSz = ssaMeth.getRegCount();

    final HashMap<TypedConstant, Integer> countUses = new HashMap<TypedConstant, Integer>();

    /*
     * Each collected constant can be used by just one local (used only if
     * COLLECT_ONE_LOCAL is true).
     */
    final HashSet<TypedConstant> usedByLocal = new HashSet<TypedConstant>();

    // Count how many times each const value is used.
    for (int i = 0; i < regSz; i++) {
      SsaInsn insn = ssaMeth.getDefinitionForRegister(i);

      if (insn == null || insn.getOpcode() == null) continue;

      RegisterSpec result = insn.getResult();
      TypeBearer typeBearer = result.getTypeBearer();

      if (!typeBearer.isConstant()) continue;

      TypedConstant cst = (TypedConstant) typeBearer;

      // Find defining instruction for move-result-pseudo instructions
      if (insn.getOpcode().getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
        int pred = insn.getBlock().getPredecessors().nextSetBit(0);
        ArrayList<SsaInsn> predInsns;
        predInsns = ssaMeth.getBlocks().get(pred).getInsns();
        insn = predInsns.get(predInsns.size() - 1);
      }

      if (insn.canThrow()) {
        /*
         * Don't move anything other than strings -- the risk of
         * changing where an exception is thrown is too high.
         */
        if (!(cst instanceof CstString) || !COLLECT_STRINGS) {
          continue;
        }
        /*
         * We can't move any throwable const whose throw will be caught,
         * so don't count them.
         */
        if (insn.getBlock().getSuccessors().cardinality() > 1) {
          continue;
        }
      }

      /*
       * TODO: Might be nice to try and figure out which local wins most
       * when collected.
       */
      if (ssaMeth.isRegALocal(result)) {
        if (!COLLECT_ONE_LOCAL) {
          continue;
        } else {
          if (usedByLocal.contains(cst)) {
            // Count one local usage only.
            continue;
          } else {
            usedByLocal.add(cst);
          }
        }
      }

      Integer has = countUses.get(cst);
      if (has == null) {
        countUses.put(cst, 1);
      } else {
        countUses.put(cst, has + 1);
      }
    }

    // Collect constants that have been reused.
    ArrayList<TypedConstant> constantList = new ArrayList<TypedConstant>();
    for (Map.Entry<TypedConstant, Integer> entry : countUses.entrySet()) {
      if (entry.getValue() > 1) {
        constantList.add(entry.getKey());
      }
    }

    // Sort by use, with most used at the beginning of the list.
    Collections.sort(
        constantList,
        new Comparator<Constant>() {

          public int compare(Constant a, Constant b) {
            int ret;
            ret = countUses.get(b) - countUses.get(a);

            if (ret == 0) {
              /*
               * Provide sorting determinisim for constants with same
               * usage count.
               */
              ret = a.compareTo(b);
            }

            return ret;
          }

          @Override
          public boolean equals(Object obj) {
            return obj == this;
          }
        });

    return constantList;
  }