FileDocCategorySizeDatePackage
LocalVariableExtractor.javaAPI DocAndroid 1.5 API6412Wed May 06 22:41:02 BST 2009com.android.dx.rop.code

LocalVariableExtractor

public final class LocalVariableExtractor extends Object
Code to figure out which local variables are active at which points in a method.

Fields Summary
private final RopMethod
method
non-null; method being extracted from
private final BasicBlockList
blocks
non-null; block list for the method
private final LocalVariableInfo
resultInfo
non-null; result in-progress
private final int[]
workSet
non-null; work set indicating blocks needing to be processed
Constructors Summary
private LocalVariableExtractor(RopMethod method)
Constructs an instance. This method is private. Use {@link #extract}.

param
method non-null; the method to extract from

        if (method == null) {
            throw new NullPointerException("method == null");
        }

        BasicBlockList blocks = method.getBlocks();
        int maxLabel = blocks.getMaxLabel();

        this.method = method;
        this.blocks = blocks;
        this.resultInfo = new LocalVariableInfo(method);
        this.workSet = Bits.makeBitSet(maxLabel);
    
Methods Summary
private LocalVariableInfodoit()
Does the extraction.

return
non-null; the extracted information

        for (int label = method.getFirstLabel();
             label >= 0;
             label = Bits.findFirst(workSet, 0)) {
            Bits.clear(workSet, label);
            processBlock(label);
        }
        
        resultInfo.setImmutable();
        return resultInfo;
    
public static LocalVariableInfoextract(RopMethod method)
Extracts out all the local variable information from the given method.

param
method non-null; the method to extract from
return
non-null; the extracted information

        LocalVariableExtractor lve = new LocalVariableExtractor(method);
        return lve.doit();
    
private voidprocessBlock(int label)
Processes a single block.

param
label >= 0; label of the block to process

        RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(label);
        BasicBlock block = blocks.labelToBlock(label);
        InsnList insns = block.getInsns();
        int insnSz = insns.size();

        /*
         * 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.
         */
        Insn lastInsn = insns.getLast();
        boolean canThrowDuringLastInsn = block.hasExceptionHandlers() &&
            (insns.getLast().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();
            }

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

            result = insn.getLocalAssignment();

            if (result == null) {
                /*
                 * If an assignment assigns over an existing local, make
                 * sure to mark the local as going out of scope.
                 */

                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.getSuccessors();
        int succSz = successors.size();
        int primarySuccessor = block.getPrimarySuccessor();

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

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