示例#1
0
  /**
   * Tries to replace an instruction with a const instruction. The given instruction must have a
   * constant result for it to be replaced.
   *
   * @param insn {@code non-null;} instruction to try to replace
   * @return true if the instruction was replaced
   */
  private boolean tryReplacingWithConstant(NormalSsaInsn insn) {
    Insn originalRopInsn = insn.getOriginalRopInsn();
    Rop opcode = originalRopInsn.getOpcode();
    RegisterSpec result = insn.getResult();

    if (result != null && !ssaMeth.isRegALocal(result) && opcode.getOpcode() != RegOps.CONST) {
      TypeBearer type = insn.getResult().getTypeBearer();
      if (type.isConstant() && type.getBasicType() == Type.BT_INT) {
        // Replace the instruction with a constant
        replacePlainInsn(insn, RegisterSpecList.EMPTY, RegOps.CONST, (Constant) type);

        // Remove the source as well if this is a move-result-pseudo
        if (opcode.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
          int pred = insn.getBlock().getPredecessors().nextSetBit(0);
          ArrayList<SsaInsn> predInsns = ssaMeth.getBlocks().get(pred).getInsns();
          NormalSsaInsn sourceInsn = (NormalSsaInsn) predInsns.get(predInsns.size() - 1);
          replacePlainInsn(sourceInsn, RegisterSpecList.EMPTY, RegOps.GOTO, null);
        }
        return true;
      }
    }
    return false;
  }
示例#2
0
  /**
   * Updates all uses of various consts to use the values in the newly assigned registers.
   *
   * @param newRegs {@code non-null;} mapping between constant and new reg
   * @param origRegCount {@code >=0;} original SSA reg count, not including newly added constant
   *     regs
   */
  private void updateConstUses(HashMap<TypedConstant, RegisterSpec> newRegs, int origRegCount) {

    /*
     * set of constants associated with a local variable; used only if
     * COLLECT_ONE_LOCAL is true.
     */
    final HashSet<TypedConstant> usedByLocal = new HashSet<TypedConstant>();

    final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();

    for (int i = 0; i < origRegCount; i++) {
      SsaInsn insn = ssaMeth.getDefinitionForRegister(i);

      if (insn == null) {
        continue;
      }

      final RegisterSpec origReg = insn.getResult();
      TypeBearer typeBearer = insn.getResult().getTypeBearer();

      if (!typeBearer.isConstant()) continue;

      TypedConstant cst = (TypedConstant) typeBearer;
      final RegisterSpec newReg = newRegs.get(cst);

      if (newReg == null) {
        continue;
      }

      if (ssaMeth.isRegALocal(origReg)) {
        if (!COLLECT_ONE_LOCAL) {
          continue;
        } else {
          /*
           * TODO: If the same local gets the same cst multiple times,
           * it would be nice to reuse the register.
           */
          if (usedByLocal.contains(cst)) {
            continue;
          } else {
            usedByLocal.add(cst);
            fixLocalAssignment(origReg, newRegs.get(cst));
          }
        }
      }

      // maps an original const register to the new collected register
      RegisterMapper mapper =
          new RegisterMapper() {

            @Override
            public int getNewRegisterCount() {
              return ssaMeth.getRegCount();
            }

            @Override
            public RegisterSpec map(RegisterSpec registerSpec) {
              if (registerSpec.getReg() == origReg.getReg()) {
                return newReg.withLocalItem(registerSpec.getLocalItem());
              }

              return registerSpec;
            }
          };

      for (SsaInsn use : useList[origReg.getReg()]) {
        if (use.canThrow() && use.getBlock().getSuccessors().cardinality() > 1) {
          continue;
        }
        use.mapSourceRegisters(mapper);
      }
    }
  }
示例#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;
  }