FileDocCategorySizeDatePackage
LocalVariableExtractor.javaAPI DocAndroid 1.5 API6932Wed May 06 22:41:02 BST 2009com.android.dx.ssa

LocalVariableExtractor

public class LocalVariableExtractor extends Object
Code to figure out which local variables are active at which points in a method. Stolen and retrofitted from com.android.dx.rop.code.LocalVariableExtractor TODO remove this. Allow Rop-form LocalVariableInfo to be passed in, converted, and adapted through edge-splitting.

Fields Summary
private final SsaMethod
method
non-null; method being extracted from
private final ArrayList
blocks
non-null; block list for the method
private final LocalVariableInfo
resultInfo
non-null; result in-progress
private final BitSet
workSet
non-null; work set indicating blocks needing to be processed
Constructors Summary
private LocalVariableExtractor(SsaMethod 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");
        }

        ArrayList<SsaBasicBlock> blocks = method.getBlocks();

        this.method = method;
        this.blocks = blocks;
        this.resultInfo = new LocalVariableInfo(method);
        this.workSet = new BitSet(blocks.size());
    
Methods Summary
private LocalVariableInfodoit()
Does the extraction.

return
non-null; the extracted information


        //FIXME why is this needed here?
        if (method.getRegCount() > 0 ) {
            for (int bi = method.getEntryBlockIndex();
                 bi >= 0;
                 bi = workSet.nextSetBit(0)) {
                workSet.clear(bi);
                processBlock(bi);
            }
        }

        resultInfo.setImmutable();
        return resultInfo;
    
public static LocalVariableInfoextract(SsaMethod 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 blockIndex)
Processes a single block.

param
blockIndex >= 0; block index of the block to process

        RegisterSpecSet primaryState
                = resultInfo.mutableCopyOfStarts(blockIndex);
        SsaBasicBlock block = blocks.get(blockIndex);
        List<SsaInsn> insns = block.getInsns();
        int insnSz = insns.size();

        // The exit block has no insns and no successors
        if (blockIndex == method.getExitBlockIndex()) {
            return;
        }

        /*
         * 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.
         */
        SsaInsn lastInsn = insns.get(insnSz - 1);
        boolean hasExceptionHandlers
                = lastInsn.getOriginalRopInsn().getCatches().size() !=0 ;
        boolean canThrowDuringLastInsn = hasExceptionHandlers
                && (lastInsn.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();
            }

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

            result = insn.getLocalAssignment();

            if (result == null) {
                // We may be nuking an existing local

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

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

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