com.android.dx.ssa.LocalVariableExtractor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of builder Show documentation
Show all versions of builder Show documentation
Library to build Android applications.
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.ssa;
import com.android.dx.rop.code.RegisterSpec;
import com.android.dx.rop.code.RegisterSpecSet;
import com.android.dx.util.IntList;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
/**
* 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.
*/
public class LocalVariableExtractor {
/** {@code non-null;} method being extracted from */
private final SsaMethod method;
/** {@code non-null;} block list for the method */
private final ArrayList blocks;
/** {@code non-null;} result in-progress */
private final LocalVariableInfo resultInfo;
/** {@code non-null;} work set indicating blocks needing to be processed */
private final BitSet workSet;
/**
* Extracts out all the local variable information from the given method.
*
* @param method {@code non-null;} the method to extract from
* @return {@code non-null;} the extracted information
*/
public static LocalVariableInfo extract(SsaMethod method) {
LocalVariableExtractor lve = new LocalVariableExtractor(method);
return lve.doit();
}
/**
* Constructs an instance. This method is private. Use {@link #extract}.
*
* @param method {@code non-null;} the method to extract from
*/
private LocalVariableExtractor(SsaMethod method) {
if (method == null) {
throw new NullPointerException("method == null");
}
ArrayList blocks = method.getBlocks();
this.method = method;
this.blocks = blocks;
this.resultInfo = new LocalVariableInfo(method);
this.workSet = new BitSet(blocks.size());
}
/**
* Does the extraction.
*
* @return {@code non-null;} the extracted information
*/
private LocalVariableInfo doit() {
//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;
}
/**
* Processes a single block.
*
* @param blockIndex {@code >= 0;} block index of the block to process
*/
private void processBlock(int blockIndex) {
RegisterSpecSet primaryState
= resultInfo.mutableCopyOfStarts(blockIndex);
SsaBasicBlock block = blocks.get(blockIndex);
List 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);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy