Methods Summary |
---|
private static LocalsArray | adjustLocalsForSubroutines(LocalsArray locals, com.android.dx.util.IntList subroutines)Adjusts a locals array to account for a merged subroutines list.
If a frame merge results in, effectively, a subroutine return through
a throw then the current locals will be a LocalsArraySet that will
need to be trimmed of all OneLocalsArray elements that relevent to
the subroutine that is returning.
if (! (locals instanceof LocalsArraySet)) {
// nothing to see here
return locals;
}
LocalsArraySet laSet = (LocalsArraySet)locals;
if (subroutines.size() == 0) {
/*
* We've merged from a subroutine context to a non-subroutine
* context, likely via a throw. Our successor will only need
* to consider the primary locals state, not the state of
* all possible subroutine paths.
*/
return laSet.getPrimary();
}
/*
* It's unclear to me if the locals set needs to be trimmed here.
* If it does, then I believe it is all of the calling blocks
* in the subroutine at the end of "subroutines" passed into
* this method that should be removed.
*/
return laSet;
|
public void | annotate(com.android.dex.util.ExceptionWithContext ex)Annotates (adds context to) the given exception with information
about this frame.
locals.annotate(ex);
stack.annotate(ex);
|
public com.android.dx.cf.code.Frame | copy()Makes and returns a mutable copy of this instance. The copy
contains copies of the locals and stack (that is, it doesn't
share them with the original).
return new Frame(locals.copy(), stack.copy(), subroutines);
|
public LocalsArray | getLocals()Gets the locals array for this instance.
return locals;
|
public ExecutionStack | getStack()Gets the execution stack for this instance.
return stack;
|
public com.android.dx.util.IntList | getSubroutines()Returns the largest subroutine nesting this block may be in. An
empty list is returned if this block is not in any subroutine.
Subroutines are identified by the label of their start block. The
list is ordered such that the deepest nesting (the actual subroutine
this block is in) is the last label in the list.
return subroutines;
|
public void | initializeWithParameters(com.android.dx.rop.type.StdTypeList params)Initialize this frame with the method's parameters. Used for the first
frame.
int at = 0;
int sz = params.size();
for (int i = 0; i < sz; i++) {
Type one = params.get(i);
locals.set(at, one);
at += one.getCategory();
}
|
public com.android.dx.cf.code.Frame | makeExceptionHandlerStartFrame(com.android.dx.rop.cst.CstType exceptionClass)Makes a new frame for an exception handler block invoked from this
frame.
ExecutionStack newStack = getStack().copy();
newStack.clear();
newStack.push(exceptionClass);
return new Frame(getLocals(), newStack, subroutines);
|
public void | makeInitialized(com.android.dx.rop.type.Type type)Replaces all the occurrences of the given uninitialized type in
this frame with its initialized equivalent.
locals.makeInitialized(type);
stack.makeInitialized(type);
|
public com.android.dx.cf.code.Frame | makeNewSubroutineStartFrame(int subLabel, int callerLabel)Makes a frame for a subroutine start block, given that this is the
ending frame of one of the subroutine's calling blocks. Subroutine
calls may be nested and thus may have nested locals state, so we
start with an initial state as seen by the subroutine, but keep track
of the individual locals states that will be expected when the individual
subroutine calls return.
IntList newSubroutines = subroutines.mutableCopy();
newSubroutines.add(subLabel);
Frame newFrame = new Frame(locals.getPrimary(), stack,
IntList.makeImmutable(subLabel));
return newFrame.mergeWithSubroutineCaller(this, subLabel, callerLabel);
|
private com.android.dx.util.IntList | mergeSubroutineLists(com.android.dx.util.IntList otherSubroutines)Merges this frame's subroutine lists with another. The result
is the deepest common nesting (effectively, the common prefix of the
two lists).
if (subroutines.equals(otherSubroutines)) {
return subroutines;
}
IntList resultSubroutines = new IntList();
int szSubroutines = subroutines.size();
int szOthers = otherSubroutines.size();
for (int i = 0; i < szSubroutines && i < szOthers
&& (subroutines.get(i) == otherSubroutines.get(i)); i++) {
resultSubroutines.add(i);
}
resultSubroutines.setImmutable();
return resultSubroutines;
|
public com.android.dx.cf.code.Frame | mergeWith(com.android.dx.cf.code.Frame other)Merges two frames. If the merged result is the same as this frame,
then this instance is returned.
LocalsArray resultLocals;
ExecutionStack resultStack;
IntList resultSubroutines;
resultLocals = getLocals().merge(other.getLocals());
resultStack = getStack().merge(other.getStack());
resultSubroutines = mergeSubroutineLists(other.subroutines);
resultLocals = adjustLocalsForSubroutines(
resultLocals, resultSubroutines);
if ((resultLocals == getLocals())
&& (resultStack == getStack())
&& subroutines == resultSubroutines) {
return this;
}
return new Frame(resultLocals, resultStack, resultSubroutines);
|
public com.android.dx.cf.code.Frame | mergeWithSubroutineCaller(com.android.dx.cf.code.Frame other, int subLabel, int predLabel)Merges this frame with the frame of a subroutine caller at
{@code predLabel}. Only called on the frame at the first
block of a subroutine.
LocalsArray resultLocals;
ExecutionStack resultStack;
resultLocals = getLocals().mergeWithSubroutineCaller(
other.getLocals(), predLabel);
resultStack = getStack().merge(other.getStack());
IntList newOtherSubroutines = other.subroutines.mutableCopy();
newOtherSubroutines.add(subLabel);
newOtherSubroutines.setImmutable();
if ((resultLocals == getLocals())
&& (resultStack == getStack())
&& subroutines.equals(newOtherSubroutines)) {
return this;
}
IntList resultSubroutines;
if (subroutines.equals(newOtherSubroutines)) {
resultSubroutines = subroutines;
} else {
/*
* The new subroutines list should be the deepest of the two
* lists being merged, but the postfix of the resultant list
* must be equal to the shorter list.
*/
IntList nonResultSubroutines;
if (subroutines.size() > newOtherSubroutines.size()) {
resultSubroutines = subroutines;
nonResultSubroutines = newOtherSubroutines;
} else {
resultSubroutines = newOtherSubroutines;
nonResultSubroutines = subroutines;
}
int szResult = resultSubroutines.size();
int szNonResult = nonResultSubroutines.size();
for (int i = szNonResult - 1; i >=0; i-- ) {
if (nonResultSubroutines.get(i)
!= resultSubroutines.get(
i + (szResult - szNonResult))) {
throw new
RuntimeException("Incompatible merged subroutines");
}
}
}
return new Frame(resultLocals, resultStack, resultSubroutines);
|
public void | setImmutable()Makes this instance immutable.
locals.setImmutable();
stack.setImmutable();
// "subroutines" is always immutable
|
public com.android.dx.cf.code.Frame | subFrameForLabel(int startLabel, int subLabel)Returns a Frame instance representing the frame state that should
be used when returning from a subroutine. The stack state of all
subroutine invocations is identical, but the locals state may differ.
LocalsArray subLocals = null;
if (locals instanceof LocalsArraySet) {
subLocals = ((LocalsArraySet)locals).subArrayForLabel(subLabel);
}
IntList newSubroutines;
try {
newSubroutines = subroutines.mutableCopy();
if (newSubroutines.pop() != startLabel) {
throw new RuntimeException("returning from invalid subroutine");
}
newSubroutines.setImmutable();
} catch (IndexOutOfBoundsException ex) {
throw new RuntimeException("returning from invalid subroutine");
} catch (NullPointerException ex) {
throw new NullPointerException("can't return from non-subroutine");
}
return (subLocals == null) ? null
: new Frame(subLocals, stack, newSubroutines);
|