/** * 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; }
/** * 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); } } }
/** * 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; }