diff --git a/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Analyzer.java b/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Analyzer.java index 73113e9c..55e4c6f6 100644 --- a/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Analyzer.java +++ b/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Analyzer.java @@ -275,7 +275,7 @@ public Frame[] analyze(final String owner, final MethodNode method) throws An if (newControlFlowExceptionEdge(insnIndex, tryCatchBlock)) { Frame handler = newFrame(oldFrame); handler.clearStack(); - handler.push(interpreter.newValue(catchType)); + handler.push(interpreter.newExceptionValue(tryCatchBlock, handler, catchType)); merge(insnList.indexOf(tryCatchBlock.handler), handler, subroutine); } } @@ -379,24 +379,30 @@ private void findSubroutine( * @param method the method to be analyzed. * @return the initial execution stack frame of the 'method'. */ + private Frame computeInitialFrame(final String owner, final MethodNode method) { Frame 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; } diff --git a/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Frame.java b/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Frame.java index a3dd6c86..37e77609 100644 --- a/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Frame.java +++ b/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Frame.java @@ -265,12 +265,12 @@ public void execute(final AbstractInsnNode insn, final Interpreter interprete 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; diff --git a/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Interpreter.java b/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Interpreter.java index c0a7cbdd..bfd87beb 100644 --- a/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Interpreter.java +++ b/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Interpreter.java @@ -31,6 +31,7 @@ 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 @@ -68,6 +69,14 @@ protected Interpreter(final int api) { *

Called for method parameters (including this), exception handler variable and * with null type for variables reserved by long and double types. * + * 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 null to represent an uninitialized * value. * @return a value that represents the given type. The size of the returned value must be equal to @@ -89,6 +98,108 @@ protected Interpreter(final int api) { */ public abstract V newOperation(AbstractInsnNode insn) throws AnalyzerException; + + /** + * Called by the analyzer for initializing the return type value of a frame. + * + * By default, calls newValue(type). + * + * @param type a primitive or reference type, or null 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. + * + * By default, calls newValue(type). + * + * @param isInstanceMethod true if the owner of the parameter is is non-static method, a + * primitive or reference type, or false otherwise. value. + * @param type a primitive or reference type, or null 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. + * + * By default, calls newValue(null). + * + * @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. + * + * By default, calls newValue(null). + * + * @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. + * + * By default, calls newValue(null). + * + * @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. + * + * By default, calls newValue(exceptionType). + * + * @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: