com.android.dx.rop.code.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.rop.code;
import com.android.dx.util.Bits;
import com.android.dx.util.IntList;
/**
* Code to figure out which local variables are active at which points in
* a method.
*/
public final class LocalVariableExtractor {
/** {@code non-null;} method being extracted from */
private final RopMethod method;
/** {@code non-null;} block list for the method */
private final BasicBlockList blocks;
/** {@code non-null;} result in-progress */
private final LocalVariableInfo resultInfo;
/** {@code non-null;} work set indicating blocks needing to be processed */
private final int[] 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(RopMethod 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(RopMethod method) {
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);
}
/**
* Does the extraction.
*
* @return {@code non-null;} the extracted information
*/
private LocalVariableInfo doit() {
for (int label = method.getFirstLabel();
label >= 0;
label = Bits.findFirst(workSet, 0)) {
Bits.clear(workSet, label);
processBlock(label);
}
resultInfo.setImmutable();
return resultInfo;
}
/**
* Processes a single block.
*
* @param label {@code >= 0;} label of the block to process
*/
private void processBlock(int label) {
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.
*/
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);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy