Commit f50e2a1d authored by Lukas Rytz's avatar Lukas Rytz Committed by Jason Zaugg

Multiple methods for initializing analysis values

Introduces a number of methods that are called when initializing or
updating abstract values in an analyzer frame.

Before this commit, Analyzer.analyze and Frame.execute would always
call Interpreter.newValue for initializing or updating frame values.

Having multiple methods allows users to return more precise values
for the individual cases. For example, in a nullness analysis, the
initial value for the `this` parameter of an instance method can be
set to not-null.
parent c4a9e49c
......@@ -274,7 +274,7 @@ public class Analyzer<V extends Value> implements Opcodes {
if (newControlFlowExceptionEdge(insnIndex, tryCatchBlock)) {
Frame<V> handler = newFrame(oldFrame);
handler.clearStack();
handler.push(interpreter.newValue(catchType));
handler.push(interpreter.newExceptionValue(tryCatchBlock, handler, catchType));
merge(insnList.indexOf(tryCatchBlock.handler), handler, subroutine);
}
}
......@@ -381,21 +381,29 @@ public class Analyzer<V extends Value> implements Opcodes {
private Frame<V> computeInitialFrame(final String owner, final MethodNode method) {
Frame<V> frame = newFrame(method.maxLocals, method.maxStack);
int currentLocal = 0;
if ((method.access & ACC_STATIC) == 0) {
boolean isInstanceMethod = (method.access & ACC_STATIC) == 0;
if (isInstanceMethod) {
Type ownerType = Type.getObjectType(owner);
frame.setLocal(currentLocal++, interpreter.newValue(ownerType));
frame.setLocal(
currentLocal, interpreter.newParameterValue(isInstanceMethod, currentLocal, ownerType));
currentLocal++;
}
Type[] argumentTypes = Type.getArgumentTypes(method.desc);
for (int i = 0; i < argumentTypes.length; ++i) {
frame.setLocal(currentLocal++, interpreter.newValue(argumentTypes[i]));
frame.setLocal(
currentLocal,
interpreter.newParameterValue(isInstanceMethod, currentLocal, argumentTypes[i]));
currentLocal++;
if (argumentTypes[i].getSize() == 2) {
frame.setLocal(currentLocal++, interpreter.newValue(null));
frame.setLocal(currentLocal, interpreter.newEmptyValueAfterSize2Local(currentLocal));
currentLocal++;
}
}
while (currentLocal < method.maxLocals) {
frame.setLocal(currentLocal++, interpreter.newValue(null));
frame.setLocal(currentLocal, interpreter.newEmptyNonParameterLocalValue(currentLocal));
currentLocal++;
}
frame.setReturn(interpreter.newValue(Type.getReturnType(method.desc)));
frame.setReturn(interpreter.newReturnTypeValue(Type.getReturnType(method.desc)));
return frame;
}
......
......@@ -264,12 +264,12 @@ public class Frame<V extends Value> {
var = ((VarInsnNode) insn).var;
setLocal(var, value1);
if (value1.getSize() == 2) {
setLocal(var + 1, interpreter.newValue(null));
setLocal(var + 1, interpreter.newEmptyValueAfterSize2Local(var + 1));
}
if (var > 0) {
Value local = getLocal(var - 1);
if (local != null && local.getSize() == 2) {
setLocal(var - 1, interpreter.newValue(null));
setLocal(var - 1, interpreter.newEmptyValueForPreviousSize2Local(var - 1));
}
}
break;
......
......@@ -30,6 +30,7 @@ package org.objectweb.asm.tree.analysis;
import java.util.List;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
/**
* A semantic bytecode interpreter. More precisely, this interpreter only manages the computation of
......@@ -67,6 +68,14 @@ public abstract class Interpreter<V extends Value> {
* <p>Called for method parameters (including <code>this</code>), exception handler variable and
* with <code>null</code> type for variables reserved by long and double types.
*
* <p>An interpreter may choose to implement one or more of {@link
* Interpreter#newReturnTypeValue(Type)}, {@link Interpreter#newParameterValue(boolean, int,
* Type)}, {@link Interpreter#newEmptyNonParameterLocalValue(int)}, {@link
* Interpreter#newEmptyValueAfterSize2Local(int)}, {@link
* Interpreter#newEmptyValueForPreviousSize2Local(int)}, {@link
* Interpreter#newExceptionValue(TryCatchBlockNode, Frame, Type)} to distinguish different types
* of new value.
*
* @param type a primitive or reference type, or <tt>null</tt> to represent an uninitialized
* value.
* @return a value that represents the given type. The size of the returned value must be equal to
......@@ -88,6 +97,104 @@ public abstract class Interpreter<V extends Value> {
*/
public abstract V newOperation(AbstractInsnNode insn) throws AnalyzerException;
/**
* Called by the analyzer for initializing the return type value of a frame.
*
* <p>By default, calls <code>newValue(type)</code>.
*
* @param type a primitive or reference type, or <tt>null</tt> to represent an uninitialized
* value.
* @return a value that represents the given type. The size of the returned value must be equal to
* the size of the given type.
* @since ASM 1.7
*/
public V newReturnTypeValue(Type type) {
return newValue(type);
}
/**
* Called by the analyzer when initializing the value of a parameter in a frame.
*
* <p>By default, calls <code>newValue(type)</code>.
*
* @param isInstanceMethod <tt>true</tt> if the owner of the parameter is is non-static method, a
* primitive or reference type, or <tt>false</tt> otherwise. value.
* @param type a primitive or reference type, or <tt>null</tt> to represent an uninitialized
* value.
* @return a value that represents the given type. The size of the returned value must be equal to
* the size of the given type.
* @since ASM 1.7
*/
public V newParameterValue(boolean isInstanceMethod, int local, Type type) {
return newValue(type);
}
/**
* Called by the analyzer when initializing a non-parameter local in a frame. This method has to
* return a size-1 value representing an empty slot.
*
* <p>By default, calls <code>newValue(null)</code>.
*
* @param local The index of the local in the frame.
* @return a value that represents the given type. The size of the returned value must be equal to
* the size of the given type.
* @since ASM 1.7
*/
public V newEmptyNonParameterLocalValue(int local) {
return newValue(null);
}
/**
* Called by the analyzer and the interpreter. When initializing or setting the value of a size-2
* local, the value of the subsequent slot is reset using this method. This method has to return a
* size-1 value representing an empty slot.
*
* <p>By default, calls <code>newValue(null)</code>.
*
* @param local The index of the local in the frame.
* @return a value that represents the given type. The size of the returned value must be equal to
* the size of the given type.
* @since ASM 1.7
*/
public V newEmptyValueAfterSize2Local(int local) {
return newValue(null);
}
/**
* Called by the interpreter. When setting the value of a local variable, the interpreter checks
* whether the current value stored at the preceding index is of size-2. In this case, the
* preceding size-2 value is no longer valid and reset using this method. This method has to
* return a size-1 value representing an empty slot.
*
* <p>By default, calls <code>newValue(null)</code>.
*
* @param local The index of the local in the frame.
* @return a value that represents the given type. The size of the returned value must be equal to
* the size of the given type.
* @since ASM 1.7
*/
public V newEmptyValueForPreviousSize2Local(int local) {
return newValue(null);
}
/**
* Called by the analyzer when initializing the exception value on the call stack at the entry of
* an exception handler.
*
* <p>By default, calls <code>newValue(exceptionType)</code>.
*
* @param tryCatchBlockNode The exception handler
* @param handlerFrame The frame of the handler catching an exception from the current instruction
* @param exceptionType The excption type handled by this handler.
* @return a value that represents the given type. The size of the returned value must be equal to
* the size of the given type.
* @since ASM 1.7
*/
public V newExceptionValue(
TryCatchBlockNode tryCatchBlockNode, Frame handlerFrame, Type exceptionType) {
return newValue(exceptionType);
}
/**
* Interprets a bytecode instruction that moves a value on the stack or to or from local
* variables. This method is called for the following opcodes:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment