Search in sources :

Example 1 with TypedConstant

use of com.android.dx.rop.cst.TypedConstant in project buck by facebook.

the class CfTranslator method processFields.

/**
     * Processes the fields of the given class.
     *
     * @param cf {@code non-null;} class being translated
     * @param out {@code non-null;} output class
     * @param dexFile {@code non-null;} dex output
     */
private static void processFields(DirectClassFile cf, ClassDefItem out, DexFile dexFile) {
    CstType thisClass = cf.getThisClass();
    FieldList fields = cf.getFields();
    int sz = fields.size();
    for (int i = 0; i < sz; i++) {
        Field one = fields.get(i);
        try {
            CstFieldRef field = new CstFieldRef(thisClass, one.getNat());
            int accessFlags = one.getAccessFlags();
            if (AccessFlags.isStatic(accessFlags)) {
                TypedConstant constVal = one.getConstantValue();
                EncodedField fi = new EncodedField(field, accessFlags);
                if (constVal != null) {
                    constVal = coerceConstant(constVal, field.getType());
                }
                out.addStaticField(fi, constVal);
            } else {
                EncodedField fi = new EncodedField(field, accessFlags);
                out.addInstanceField(fi);
            }
            Annotations annotations = AttributeTranslator.getAnnotations(one.getAttributes());
            if (annotations.size() != 0) {
                out.addFieldAnnotations(field, annotations, dexFile);
            }
            dexFile.getFieldIds().intern(field);
        } catch (RuntimeException ex) {
            String msg = "...while processing " + one.getName().toHuman() + " " + one.getDescriptor().toHuman();
            throw ExceptionWithContext.withContext(ex, msg);
        }
    }
}
Also used : Field(com.android.dx.cf.iface.Field) EncodedField(com.android.dx.dex.file.EncodedField) Annotations(com.android.dx.rop.annotation.Annotations) TypedConstant(com.android.dx.rop.cst.TypedConstant) CstType(com.android.dx.rop.cst.CstType) CstFieldRef(com.android.dx.rop.cst.CstFieldRef) EncodedField(com.android.dx.dex.file.EncodedField) CstString(com.android.dx.rop.cst.CstString) FieldList(com.android.dx.cf.iface.FieldList)

Example 2 with TypedConstant

use of com.android.dx.rop.cst.TypedConstant in project buck by facebook.

the class SCCP method replaceConstants.

/**
     * Replaces TypeBearers in source register specs with constant type
     * bearers if possible. These are then referenced in later optimization
     * steps.
     */
private void replaceConstants() {
    for (int reg = 0; reg < regCount; reg++) {
        if (latticeValues[reg] != CONSTANT) {
            continue;
        }
        if (!(latticeConstants[reg] instanceof TypedConstant)) {
            // We can't do much with these
            continue;
        }
        SsaInsn defn = ssaMeth.getDefinitionForRegister(reg);
        TypeBearer typeBearer = defn.getResult().getTypeBearer();
        if (typeBearer.isConstant()) {
            /*
                 * The definition was a constant already.
                 * The uses should be as well.
                 */
            continue;
        }
        // Update the destination RegisterSpec with the constant value
        RegisterSpec dest = defn.getResult();
        RegisterSpec newDest = dest.withType((TypedConstant) latticeConstants[reg]);
        defn.setResult(newDest);
        /*
             * Update the sources RegisterSpec's of all non-move uses.
             * These will be used in later steps.
             */
        for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
            if (insn.isPhiOrMove()) {
                continue;
            }
            NormalSsaInsn nInsn = (NormalSsaInsn) insn;
            RegisterSpecList sources = insn.getSources();
            int index = sources.indexOfRegister(reg);
            RegisterSpec spec = sources.get(index);
            RegisterSpec newSpec = spec.withType((TypedConstant) latticeConstants[reg]);
            nInsn.changeOneSource(index, newSpec);
        }
    }
}
Also used : TypedConstant(com.android.dx.rop.cst.TypedConstant) TypeBearer(com.android.dx.rop.type.TypeBearer) RegisterSpecList(com.android.dx.rop.code.RegisterSpecList) RegisterSpec(com.android.dx.rop.code.RegisterSpec)

Example 3 with TypedConstant

use of com.android.dx.rop.cst.TypedConstant in project buck by facebook.

the class SCCP method simulateBranch.

/**
     * Simulates branch insns, if possible. Adds reachable successor blocks
     * to the CFG worklists.
     * @param insn branch to simulate
     */
private void simulateBranch(SsaInsn insn) {
    Rop opcode = insn.getOpcode();
    RegisterSpecList sources = insn.getSources();
    boolean constantBranch = false;
    boolean constantSuccessor = false;
    // Check if the insn is a branch with a constant condition
    if (opcode.getBranchingness() == Rop.BRANCH_IF) {
        Constant cA = null;
        Constant cB = null;
        RegisterSpec specA = sources.get(0);
        int regA = specA.getReg();
        if (!ssaMeth.isRegALocal(specA) && latticeValues[regA] == CONSTANT) {
            cA = latticeConstants[regA];
        }
        if (sources.size() == 2) {
            RegisterSpec specB = sources.get(1);
            int regB = specB.getReg();
            if (!ssaMeth.isRegALocal(specB) && latticeValues[regB] == CONSTANT) {
                cB = latticeConstants[regB];
            }
        }
        // Calculate the result of the condition
        if (cA != null && sources.size() == 1) {
            switch(((TypedConstant) cA).getBasicType()) {
                case Type.BT_INT:
                    constantBranch = true;
                    int vA = ((CstInteger) cA).getValue();
                    switch(opcode.getOpcode()) {
                        case RegOps.IF_EQ:
                            constantSuccessor = (vA == 0);
                            break;
                        case RegOps.IF_NE:
                            constantSuccessor = (vA != 0);
                            break;
                        case RegOps.IF_LT:
                            constantSuccessor = (vA < 0);
                            break;
                        case RegOps.IF_GE:
                            constantSuccessor = (vA >= 0);
                            break;
                        case RegOps.IF_LE:
                            constantSuccessor = (vA <= 0);
                            break;
                        case RegOps.IF_GT:
                            constantSuccessor = (vA > 0);
                            break;
                        default:
                            throw new RuntimeException("Unexpected op");
                    }
                    break;
                default:
            }
        } else if (cA != null && cB != null) {
            switch(((TypedConstant) cA).getBasicType()) {
                case Type.BT_INT:
                    constantBranch = true;
                    int vA = ((CstInteger) cA).getValue();
                    int vB = ((CstInteger) cB).getValue();
                    switch(opcode.getOpcode()) {
                        case RegOps.IF_EQ:
                            constantSuccessor = (vA == vB);
                            break;
                        case RegOps.IF_NE:
                            constantSuccessor = (vA != vB);
                            break;
                        case RegOps.IF_LT:
                            constantSuccessor = (vA < vB);
                            break;
                        case RegOps.IF_GE:
                            constantSuccessor = (vA >= vB);
                            break;
                        case RegOps.IF_LE:
                            constantSuccessor = (vA <= vB);
                            break;
                        case RegOps.IF_GT:
                            constantSuccessor = (vA > vB);
                            break;
                        default:
                            throw new RuntimeException("Unexpected op");
                    }
                    break;
                default:
            }
        }
    }
    /*
         * If condition is constant, add only the target block to the
         * worklist. Otherwise, add all successors to the worklist.
         */
    SsaBasicBlock block = insn.getBlock();
    if (constantBranch) {
        int successorBlock;
        if (constantSuccessor) {
            successorBlock = block.getSuccessorList().get(1);
        } else {
            successorBlock = block.getSuccessorList().get(0);
        }
        addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
        branchWorklist.add(insn);
    } else {
        for (int i = 0; i < block.getSuccessorList().size(); i++) {
            int successorBlock = block.getSuccessorList().get(i);
            addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
        }
    }
}
Also used : Rop(com.android.dx.rop.code.Rop) TypedConstant(com.android.dx.rop.cst.TypedConstant) Constant(com.android.dx.rop.cst.Constant) TypedConstant(com.android.dx.rop.cst.TypedConstant) CstInteger(com.android.dx.rop.cst.CstInteger) RegisterSpecList(com.android.dx.rop.code.RegisterSpecList) RegisterSpec(com.android.dx.rop.code.RegisterSpec)

Example 4 with TypedConstant

use of com.android.dx.rop.cst.TypedConstant in project buck by facebook.

the class ConstCollector method getConstsSortedByCountUse.

/**
     * 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;
}
Also used : HashMap(java.util.HashMap) Constant(com.android.dx.rop.cst.Constant) TypedConstant(com.android.dx.rop.cst.TypedConstant) CstString(com.android.dx.rop.cst.CstString) ArrayList(java.util.ArrayList) TypedConstant(com.android.dx.rop.cst.TypedConstant) TypeBearer(com.android.dx.rop.type.TypeBearer) HashMap(java.util.HashMap) Map(java.util.Map) RegisterSpec(com.android.dx.rop.code.RegisterSpec) HashSet(java.util.HashSet)

Example 5 with TypedConstant

use of com.android.dx.rop.cst.TypedConstant in project buck by facebook.

the class ConstCollector method updateConstUses.

/**
     * 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);
        }
    }
}
Also used : TypedConstant(com.android.dx.rop.cst.TypedConstant) ArrayList(java.util.ArrayList) TypeBearer(com.android.dx.rop.type.TypeBearer) RegisterSpec(com.android.dx.rop.code.RegisterSpec) HashSet(java.util.HashSet)

Aggregations

TypedConstant (com.android.dx.rop.cst.TypedConstant)8 RegisterSpec (com.android.dx.rop.code.RegisterSpec)6 Constant (com.android.dx.rop.cst.Constant)3 TypeBearer (com.android.dx.rop.type.TypeBearer)3 RegisterSpecList (com.android.dx.rop.code.RegisterSpecList)2 Rop (com.android.dx.rop.code.Rop)2 CstString (com.android.dx.rop.cst.CstString)2 CstType (com.android.dx.rop.cst.CstType)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 AttConstantValue (com.android.dx.cf.attrib.AttConstantValue)1 Attribute (com.android.dx.cf.iface.Attribute)1 Field (com.android.dx.cf.iface.Field)1 FieldList (com.android.dx.cf.iface.FieldList)1 EncodedField (com.android.dx.dex.file.EncodedField)1 Annotations (com.android.dx.rop.annotation.Annotations)1 PlainCstInsn (com.android.dx.rop.code.PlainCstInsn)1 PlainInsn (com.android.dx.rop.code.PlainInsn)1 ThrowingCstInsn (com.android.dx.rop.code.ThrowingCstInsn)1