http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypeReference.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypeReference.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypeReference.java old mode 100644 new mode 100755 index d518864..96bfe33 --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypeReference.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/TypeReference.java @@ -1,452 +1,436 @@ -/*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2013 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.apache.tapestry5.internal.plastic.asm; - -/** - * A reference to a type appearing in a class, field or method declaration, or - * on an instruction. Such a reference designates the part of the class where - * the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws' - * clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable - * declaration, etc). - * - * @author Eric Bruneton - */ -public class TypeReference { - - /** - * The sort of type references that target a type parameter of a generic - * class. See {@link #getSort getSort}. - */ - public final static int CLASS_TYPE_PARAMETER = 0x00; - - /** - * The sort of type references that target a type parameter of a generic - * method. See {@link #getSort getSort}. - */ - public final static int METHOD_TYPE_PARAMETER = 0x01; - - /** - * The sort of type references that target the super class of a class or one - * of the interfaces it implements. See {@link #getSort getSort}. - */ - public final static int CLASS_EXTENDS = 0x10; - - /** - * The sort of type references that target a bound of a type parameter of a - * generic class. See {@link #getSort getSort}. - */ - public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11; - - /** - * The sort of type references that target a bound of a type parameter of a - * generic method. See {@link #getSort getSort}. - */ - public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12; - - /** - * The sort of type references that target the type of a field. See - * {@link #getSort getSort}. - */ - public final static int FIELD = 0x13; - - /** - * The sort of type references that target the return type of a method. See - * {@link #getSort getSort}. - */ - public final static int METHOD_RETURN = 0x14; - - /** - * The sort of type references that target the receiver type of a method. - * See {@link #getSort getSort}. - */ - public final static int METHOD_RECEIVER = 0x15; - - /** - * The sort of type references that target the type of a formal parameter of - * a method. See {@link #getSort getSort}. - */ - public final static int METHOD_FORMAL_PARAMETER = 0x16; - - /** - * The sort of type references that target the type of an exception declared - * in the throws clause of a method. See {@link #getSort getSort}. - */ - public final static int THROWS = 0x17; - - /** - * The sort of type references that target the type of a local variable in a - * method. See {@link #getSort getSort}. - */ - public final static int LOCAL_VARIABLE = 0x40; - - /** - * The sort of type references that target the type of a resource variable - * in a method. See {@link #getSort getSort}. - */ - public final static int RESOURCE_VARIABLE = 0x41; - - /** - * The sort of type references that target the type of the exception of a - * 'catch' clause in a method. See {@link #getSort getSort}. - */ - public final static int EXCEPTION_PARAMETER = 0x42; - - /** - * The sort of type references that target the type declared in an - * 'instanceof' instruction. See {@link #getSort getSort}. - */ - public final static int INSTANCEOF = 0x43; - - /** - * The sort of type references that target the type of the object created by - * a 'new' instruction. See {@link #getSort getSort}. - */ - public final static int NEW = 0x44; - - /** - * The sort of type references that target the receiver type of a - * constructor reference. See {@link #getSort getSort}. - */ - public final static int CONSTRUCTOR_REFERENCE = 0x45; - - /** - * The sort of type references that target the receiver type of a method - * reference. See {@link #getSort getSort}. - */ - public final static int METHOD_REFERENCE = 0x46; - - /** - * The sort of type references that target the type declared in an explicit - * or implicit cast instruction. See {@link #getSort getSort}. - */ - public final static int CAST = 0x47; - - /** - * The sort of type references that target a type parameter of a generic - * constructor in a constructor call. See {@link #getSort getSort}. - */ - public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; - - /** - * The sort of type references that target a type parameter of a generic - * method in a method call. See {@link #getSort getSort}. - */ - public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; - - /** - * The sort of type references that target a type parameter of a generic - * constructor in a constructor reference. See {@link #getSort getSort}. - */ - public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; - - /** - * The sort of type references that target a type parameter of a generic - * method in a method reference. See {@link #getSort getSort}. - */ - public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; - - /** - * The type reference value in Java class file format. - */ - private int value; - - /** - * Creates a new TypeReference. - * - * @param typeRef - * the int encoded value of the type reference, as received in a - * visit method related to type annotations, like - * visitTypeAnnotation. - */ - public TypeReference(int typeRef) { - this.value = typeRef; - } - - /** - * Returns a type reference of the given sort. - * - * @param sort - * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, - * {@link #METHOD_RECEIVER METHOD_RECEIVER}, - * {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, - * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, - * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, - * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or - * {@link #METHOD_REFERENCE METHOD_REFERENCE}. - * @return a type reference of the given sort. - */ - public static TypeReference newTypeReference(int sort) { - return new TypeReference(sort << 24); - } - - /** - * Returns a reference to a type parameter of a generic class or method. - * - * @param sort - * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or - * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. - * @param paramIndex - * the type parameter index. - * @return a reference to the given generic class or method type parameter. - */ - public static TypeReference newTypeParameterReference(int sort, - int paramIndex) { - return new TypeReference((sort << 24) | (paramIndex << 16)); - } - - /** - * Returns a reference to a type parameter bound of a generic class or - * method. - * - * @param sort - * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or - * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. - * @param paramIndex - * the type parameter index. - * @param boundIndex - * the type bound index within the above type parameters. - * @return a reference to the given generic class or method type parameter - * bound. - */ - public static TypeReference newTypeParameterBoundReference(int sort, - int paramIndex, int boundIndex) { - return new TypeReference((sort << 24) | (paramIndex << 16) - | (boundIndex << 8)); - } - - /** - * Returns a reference to the super class or to an interface of the - * 'implements' clause of a class. - * - * @param itfIndex - * the index of an interface in the 'implements' clause of a - * class, or -1 to reference the super class of the class. - * @return a reference to the given super type of a class. - */ - public static TypeReference newSuperTypeReference(int itfIndex) { - itfIndex &= 0xFFFF; - return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8)); - } - - /** - * Returns a reference to the type of a formal parameter of a method. - * - * @param paramIndex - * the formal parameter index. - * - * @return a reference to the type of the given method formal parameter. - */ - public static TypeReference newFormalParameterReference(int paramIndex) { - return new TypeReference((METHOD_FORMAL_PARAMETER << 24) - | (paramIndex << 16)); - } - - /** - * Returns a reference to the type of an exception, in a 'throws' clause of - * a method. - * - * @param exceptionIndex - * the index of an exception in a 'throws' clause of a method. - * - * @return a reference to the type of the given exception. - */ - public static TypeReference newExceptionReference(int exceptionIndex) { - return new TypeReference((THROWS << 24) | (exceptionIndex << 8)); - } - - /** - * Returns a reference to the type of the exception declared in a 'catch' - * clause of a method. - * - * @param tryCatchBlockIndex - * the index of a try catch block (using the order in which they - * are visited with visitTryCatchBlock). - * - * @return a reference to the type of the given exception. - */ - public static TypeReference newTryCatchReference(int tryCatchBlockIndex) { - return new TypeReference((EXCEPTION_PARAMETER << 24) - | (tryCatchBlockIndex << 8)); - } - - /** - * Returns a reference to the type of a type argument in a constructor or - * method call or reference. - * - * @param sort - * {@link #CAST CAST}, - * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT - * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, - * {@link #METHOD_INVOCATION_TYPE_ARGUMENT - * METHOD_INVOCATION_TYPE_ARGUMENT}, - * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT - * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or - * {@link #METHOD_REFERENCE_TYPE_ARGUMENT - * METHOD_REFERENCE_TYPE_ARGUMENT}. - * @param argIndex - * the type argument index. - * - * @return a reference to the type of the given type argument. - */ - public static TypeReference newTypeArgumentReference(int sort, int argIndex) { - return new TypeReference((sort << 24) | argIndex); - } - - /** - * Returns the sort of this type reference. - * - * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, - * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, - * {@link #CLASS_EXTENDS CLASS_EXTENDS}, - * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND}, - * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, - * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, - * {@link #METHOD_RECEIVER METHOD_RECEIVER}, - * {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}, - * {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, - * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, - * {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER}, - * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, - * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, - * {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST}, - * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT - * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, - * {@link #METHOD_INVOCATION_TYPE_ARGUMENT - * METHOD_INVOCATION_TYPE_ARGUMENT}, - * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT - * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or - * {@link #METHOD_REFERENCE_TYPE_ARGUMENT - * METHOD_REFERENCE_TYPE_ARGUMENT}. - */ - public int getSort() { - return value >>> 24; - } - - /** - * Returns the index of the type parameter referenced by this type - * reference. This method must only be used for type references whose sort - * is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, - * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, - * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or - * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. - * - * @return a type parameter index. - */ - public int getTypeParameterIndex() { - return (value & 0x00FF0000) >> 16; - } - - /** - * Returns the index of the type parameter bound, within the type parameter - * {@link #getTypeParameterIndex}, referenced by this type reference. This - * method must only be used for type references whose sort is - * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or - * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. - * - * @return a type parameter bound index. - */ - public int getTypeParameterBoundIndex() { - return (value & 0x0000FF00) >> 8; - } - - /** - * Returns the index of the "super type" of a class that is referenced by - * this type reference. This method must only be used for type references - * whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}. - * - * @return the index of an interface in the 'implements' clause of a class, - * or -1 if this type reference references the type of the super - * class. - */ - public int getSuperTypeIndex() { - return (short) ((value & 0x00FFFF00) >> 8); - } - - /** - * Returns the index of the formal parameter whose type is referenced by - * this type reference. This method must only be used for type references - * whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}. - * - * @return a formal parameter index. - */ - public int getFormalParameterIndex() { - return (value & 0x00FF0000) >> 16; - } - - /** - * Returns the index of the exception, in a 'throws' clause of a method, - * whose type is referenced by this type reference. This method must only be - * used for type references whose sort is {@link #THROWS THROWS}. - * - * @return the index of an exception in the 'throws' clause of a method. - */ - public int getExceptionIndex() { - return (value & 0x00FFFF00) >> 8; - } - - /** - * Returns the index of the try catch block (using the order in which they - * are visited with visitTryCatchBlock), whose 'catch' type is referenced by - * this type reference. This method must only be used for type references - * whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} . - * - * @return the index of an exception in the 'throws' clause of a method. - */ - public int getTryCatchBlockIndex() { - return (value & 0x00FFFF00) >> 8; - } - - /** - * Returns the index of the type argument referenced by this type reference. - * This method must only be used for type references whose sort is - * {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT - * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, - * {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT}, - * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT - * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or - * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}. - * - * @return a type parameter index. - */ - public int getTypeArgumentIndex() { - return value & 0xFF; - } - - /** - * Returns the int encoded value of this type reference, suitable for use in - * visit methods related to type annotations, like visitTypeAnnotation. - * - * @return the int encoded value of this type reference. - */ - public int getValue() { - return value; - } -} +// ASM: a very small and fast Java bytecode manipulation framework +// Copyright (c) 2000-2011 INRIA, France Telecom +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. + +package org.apache.tapestry5.internal.plastic.asm; + +/** + * A reference to a type appearing in a class, field or method declaration, or on an instruction. + * Such a reference designates the part of the class where the referenced type is appearing (e.g. an + * 'extends', 'implements' or 'throws' clause, a 'new' instruction, a 'catch' clause, a type cast, a + * local variable declaration, etc). + * + * @author Eric Bruneton + */ +public class TypeReference { + + /** + * The sort of type references that target a type parameter of a generic class. See {@link + * #getSort}. + */ + public static final int CLASS_TYPE_PARAMETER = 0x00; + + /** + * The sort of type references that target a type parameter of a generic method. See {@link + * #getSort}. + */ + public static final int METHOD_TYPE_PARAMETER = 0x01; + + /** + * The sort of type references that target the super class of a class or one of the interfaces it + * implements. See {@link #getSort}. + */ + public static final int CLASS_EXTENDS = 0x10; + + /** + * The sort of type references that target a bound of a type parameter of a generic class. See + * {@link #getSort}. + */ + public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11; + + /** + * The sort of type references that target a bound of a type parameter of a generic method. See + * {@link #getSort}. + */ + public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; + + /** The sort of type references that target the type of a field. See {@link #getSort}. */ + public static final int FIELD = 0x13; + + /** The sort of type references that target the return type of a method. See {@link #getSort}. */ + public static final int METHOD_RETURN = 0x14; + + /** + * The sort of type references that target the receiver type of a method. See {@link #getSort}. + */ + public static final int METHOD_RECEIVER = 0x15; + + /** + * The sort of type references that target the type of a formal parameter of a method. See {@link + * #getSort}. + */ + public static final int METHOD_FORMAL_PARAMETER = 0x16; + + /** + * The sort of type references that target the type of an exception declared in the throws clause + * of a method. See {@link #getSort}. + */ + public static final int THROWS = 0x17; + + /** + * The sort of type references that target the type of a local variable in a method. See {@link + * #getSort}. + */ + public static final int LOCAL_VARIABLE = 0x40; + + /** + * The sort of type references that target the type of a resource variable in a method. See {@link + * #getSort}. + */ + public static final int RESOURCE_VARIABLE = 0x41; + + /** + * The sort of type references that target the type of the exception of a 'catch' clause in a + * method. See {@link #getSort}. + */ + public static final int EXCEPTION_PARAMETER = 0x42; + + /** + * The sort of type references that target the type declared in an 'instanceof' instruction. See + * {@link #getSort}. + */ + public static final int INSTANCEOF = 0x43; + + /** + * The sort of type references that target the type of the object created by a 'new' instruction. + * See {@link #getSort}. + */ + public static final int NEW = 0x44; + + /** + * The sort of type references that target the receiver type of a constructor reference. See + * {@link #getSort}. + */ + public static final int CONSTRUCTOR_REFERENCE = 0x45; + + /** + * The sort of type references that target the receiver type of a method reference. See {@link + * #getSort}. + */ + public static final int METHOD_REFERENCE = 0x46; + + /** + * The sort of type references that target the type declared in an explicit or implicit cast + * instruction. See {@link #getSort}. + */ + public static final int CAST = 0x47; + + /** + * The sort of type references that target a type parameter of a generic constructor in a + * constructor call. See {@link #getSort}. + */ + public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; + + /** + * The sort of type references that target a type parameter of a generic method in a method call. + * See {@link #getSort}. + */ + public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; + + /** + * The sort of type references that target a type parameter of a generic constructor in a + * constructor reference. See {@link #getSort}. + */ + public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; + + /** + * The sort of type references that target a type parameter of a generic method in a method + * reference. See {@link #getSort}. + */ + public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; + + /** + * The target_type and target_info structures - as defined in the Java Virtual Machine + * Specification (JVMS) - corresponding to this type reference. target_type uses one byte, and all + * the target_info union fields use up to 3 bytes (except localvar_target, handled with the + * specific method {@link MethodVisitor#visitLocalVariableAnnotation}). Thus, both structures can + * be stored in an int. + * + * <p>This int field stores target_type (called the TypeReference 'sort' in the public API of this + * class) in its most significant byte, followed by the target_info fields. Depending on + * target_type, 1, 2 or even 3 least significant bytes of this field are unused. target_info + * fields which reference bytecode offsets are set to 0 (these offsets are ignored in ClassReader, + * and recomputed in MethodWriter). + * + * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20">JVMS + * 4.7.20</a> + * @see <a + * href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.1">JVMS + * 4.7.20.1</a> + */ + private final int targetTypeAndInfo; + + /** + * Constructs a new TypeReference. + * + * @param typeRef the int encoded value of the type reference, as received in a visit method + * related to type annotations, such as {@link ClassVisitor#visitTypeAnnotation}. + */ + public TypeReference(final int typeRef) { + this.targetTypeAndInfo = typeRef; + } + + /** + * Returns a type reference of the given sort. + * + * @param sort one of {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link + * #LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE}, {@link #INSTANCEOF}, {@link #NEW}, {@link + * #CONSTRUCTOR_REFERENCE}, or {@link #METHOD_REFERENCE}. + * @return a type reference of the given sort. + */ + public static TypeReference newTypeReference(final int sort) { + return new TypeReference(sort << 24); + } + + /** + * Returns a reference to a type parameter of a generic class or method. + * + * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}. + * @param paramIndex the type parameter index. + * @return a reference to the given generic class or method type parameter. + */ + public static TypeReference newTypeParameterReference(final int sort, final int paramIndex) { + return new TypeReference((sort << 24) | (paramIndex << 16)); + } + + /** + * Returns a reference to a type parameter bound of a generic class or method. + * + * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}. + * @param paramIndex the type parameter index. + * @param boundIndex the type bound index within the above type parameters. + * @return a reference to the given generic class or method type parameter bound. + */ + public static TypeReference newTypeParameterBoundReference( + final int sort, final int paramIndex, final int boundIndex) { + return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8)); + } + + /** + * Returns a reference to the super class or to an interface of the 'implements' clause of a + * class. + * + * @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to + * reference the super class of the class. + * @return a reference to the given super type of a class. + */ + public static TypeReference newSuperTypeReference(final int itfIndex) { + return new TypeReference((CLASS_EXTENDS << 24) | ((itfIndex & 0xFFFF) << 8)); + } + + /** + * Returns a reference to the type of a formal parameter of a method. + * + * @param paramIndex the formal parameter index. + * @return a reference to the type of the given method formal parameter. + */ + public static TypeReference newFormalParameterReference(final int paramIndex) { + return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16)); + } + + /** + * Returns a reference to the type of an exception, in a 'throws' clause of a method. + * + * @param exceptionIndex the index of an exception in a 'throws' clause of a method. + * @return a reference to the type of the given exception. + */ + public static TypeReference newExceptionReference(final int exceptionIndex) { + return new TypeReference((THROWS << 24) | (exceptionIndex << 8)); + } + + /** + * Returns a reference to the type of the exception declared in a 'catch' clause of a method. + * + * @param tryCatchBlockIndex the index of a try catch block (using the order in which they are + * visited with visitTryCatchBlock). + * @return a reference to the type of the given exception. + */ + public static TypeReference newTryCatchReference(final int tryCatchBlockIndex) { + return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8)); + } + + /** + * Returns a reference to the type of a type argument in a constructor or method call or + * reference. + * + * @param sort one of {@link #CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link + * #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link + * #METHOD_REFERENCE_TYPE_ARGUMENT}. + * @param argIndex the type argument index. + * @return a reference to the type of the given type argument. + */ + public static TypeReference newTypeArgumentReference(final int sort, final int argIndex) { + return new TypeReference((sort << 24) | argIndex); + } + + /** + * Returns the sort of this type reference. + * + * @return one of {@link #CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER}, {@link + * #CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND}, {@link #METHOD_TYPE_PARAMETER_BOUND}, + * {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link + * #METHOD_FORMAL_PARAMETER}, {@link #THROWS}, {@link #LOCAL_VARIABLE}, {@link + * #RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER}, {@link #INSTANCEOF}, {@link #NEW}, + * {@link #CONSTRUCTOR_REFERENCE}, {@link #METHOD_REFERENCE}, {@link #CAST}, {@link + * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link + * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}. + */ + public int getSort() { + return targetTypeAndInfo >>> 24; + } + + /** + * Returns the index of the type parameter referenced by this type reference. This method must + * only be used for type references whose sort is {@link #CLASS_TYPE_PARAMETER}, {@link + * #METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link + * #METHOD_TYPE_PARAMETER_BOUND}. + * + * @return a type parameter index. + */ + public int getTypeParameterIndex() { + return (targetTypeAndInfo & 0x00FF0000) >> 16; + } + + /** + * Returns the index of the type parameter bound, within the type parameter {@link + * #getTypeParameterIndex}, referenced by this type reference. This method must only be used for + * type references whose sort is {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link + * #METHOD_TYPE_PARAMETER_BOUND}. + * + * @return a type parameter bound index. + */ + public int getTypeParameterBoundIndex() { + return (targetTypeAndInfo & 0x0000FF00) >> 8; + } + + /** + * Returns the index of the "super type" of a class that is referenced by this type reference. + * This method must only be used for type references whose sort is {@link #CLASS_EXTENDS}. + * + * @return the index of an interface in the 'implements' clause of a class, or -1 if this type + * reference references the type of the super class. + */ + public int getSuperTypeIndex() { + return (short) ((targetTypeAndInfo & 0x00FFFF00) >> 8); + } + + /** + * Returns the index of the formal parameter whose type is referenced by this type reference. This + * method must only be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER}. + * + * @return a formal parameter index. + */ + public int getFormalParameterIndex() { + return (targetTypeAndInfo & 0x00FF0000) >> 16; + } + + /** + * Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced + * by this type reference. This method must only be used for type references whose sort is {@link + * #THROWS}. + * + * @return the index of an exception in the 'throws' clause of a method. + */ + public int getExceptionIndex() { + return (targetTypeAndInfo & 0x00FFFF00) >> 8; + } + + /** + * Returns the index of the try catch block (using the order in which they are visited with + * visitTryCatchBlock), whose 'catch' type is referenced by this type reference. This method must + * only be used for type references whose sort is {@link #EXCEPTION_PARAMETER} . + * + * @return the index of an exception in the 'throws' clause of a method. + */ + public int getTryCatchBlockIndex() { + return (targetTypeAndInfo & 0x00FFFF00) >> 8; + } + + /** + * Returns the index of the type argument referenced by this type reference. This method must only + * be used for type references whose sort is {@link #CAST}, {@link + * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link + * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}. + * + * @return a type parameter index. + */ + public int getTypeArgumentIndex() { + return targetTypeAndInfo & 0xFF; + } + + /** + * Returns the int encoded value of this type reference, suitable for use in visit methods related + * to type annotations, like visitTypeAnnotation. + * + * @return the int encoded value of this type reference. + */ + public int getValue() { + return targetTypeAndInfo; + } + + /** + * Puts the given target_type and target_info JVMS structures into the given ByteVector. + * + * @param targetTypeAndInfo a target_type and a target_info structures encoded as in {@link + * #targetTypeAndInfo}. LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported. + * @param output where the type reference must be put. + */ + static void putTarget(final int targetTypeAndInfo, final ByteVector output) { + switch (targetTypeAndInfo >>> 24) { + case CLASS_TYPE_PARAMETER: + case METHOD_TYPE_PARAMETER: + case METHOD_FORMAL_PARAMETER: + output.putShort(targetTypeAndInfo >>> 16); + break; + case FIELD: + case METHOD_RETURN: + case METHOD_RECEIVER: + output.putByte(targetTypeAndInfo >>> 24); + break; + case CAST: + case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: + case METHOD_INVOCATION_TYPE_ARGUMENT: + case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: + case METHOD_REFERENCE_TYPE_ARGUMENT: + output.putInt(targetTypeAndInfo); + break; + case CLASS_EXTENDS: + case CLASS_TYPE_PARAMETER_BOUND: + case METHOD_TYPE_PARAMETER_BOUND: + case THROWS: + case EXCEPTION_PARAMETER: + case INSTANCEOF: + case NEW: + case CONSTRUCTOR_REFERENCE: + case METHOD_REFERENCE: + output.put12(targetTypeAndInfo >>> 24, (targetTypeAndInfo & 0xFFFF00) >> 8); + break; + default: + throw new IllegalArgumentException(); + } + } +}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AdviceAdapter.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AdviceAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AdviceAdapter.java old mode 100644 new mode 100755 index a0f6880..96e0c48 --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AdviceAdapter.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/AdviceAdapter.java @@ -1,39 +1,37 @@ -/*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ +// ASM: a very small and fast Java bytecode manipulation framework +// Copyright (c) 2000-2011 INRIA, France Telecom +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. package org.apache.tapestry5.internal.plastic.asm.commons; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - +import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic; import org.apache.tapestry5.internal.plastic.asm.Handle; import org.apache.tapestry5.internal.plastic.asm.Label; import org.apache.tapestry5.internal.plastic.asm.MethodVisitor; @@ -41,606 +39,621 @@ import org.apache.tapestry5.internal.plastic.asm.Opcodes; import org.apache.tapestry5.internal.plastic.asm.Type; /** - * A {@link org.objectweb.asm.MethodVisitor} to insert before, after and around - * advices in methods and constructors. - * <p> - * The behavior for constructors is like this: - * <ol> - * - * <li>as long as the INVOKESPECIAL for the object initialization has not been - * reached, every bytecode instruction is dispatched in the ctor code visitor</li> - * - * <li>when this one is reached, it is only added in the ctor code visitor and a - * JP invoke is added</li> - * - * <li>after that, only the other code visitor receives the instructions</li> - * - * </ol> - * + * A {@link MethodVisitor} to insert before, after and around advices in methods and constructors. + * For constructors, the code keeps track of the elements on the stack in order to detect when the + * super class constructor is called (note that there can be multiple such calls in different + * branches). {@code onMethodEnter} is called after each super class constructor call, because the + * object cannot be used before it is properly initialized. + * * @author Eugene Kuleshov * @author Eric Bruneton */ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes { - private static final Object THIS = new Object(); - - private static final Object OTHER = new Object(); - - protected int methodAccess; - - protected String methodDesc; - - private boolean constructor; - - private boolean superInitialized; - - private List<Object> stackFrame; - - private Map<Label, List<Object>> branches; - - /** - * Creates a new {@link AdviceAdapter}. - * - * @param api - * the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param mv - * the method visitor to which this adapter delegates calls. - * @param access - * the method's access flags (see {@link Opcodes}). - * @param name - * the method's name. - * @param desc - * the method's descriptor (see {@link Type Type}). - */ - protected AdviceAdapter(final int api, final MethodVisitor mv, - final int access, final String name, final String desc) { - super(api, mv, access, name, desc); - methodAccess = access; - methodDesc = desc; - constructor = "<init>".equals(name); - } - - @Override - public void visitCode() { - mv.visitCode(); - if (constructor) { - stackFrame = new ArrayList<Object>(); - branches = new HashMap<Label, List<Object>>(); - } else { - superInitialized = true; - onMethodEnter(); - } - } - - @Override - public void visitLabel(final Label label) { - mv.visitLabel(label); - if (constructor && branches != null) { - List<Object> frame = branches.get(label); - if (frame != null) { - stackFrame = frame; - branches.remove(label); - } - } + /** The "uninitialized this" value. */ + private static final Object UNINITIALIZED_THIS = new Object(); + + /** Any value other than "uninitialized this". */ + private static final Object OTHER = new Object(); + + /** Prefix of the error message when invalid opcodes are found. */ + private static final String INVALID_OPCODE = "Invalid opcode "; + + /** The access flags of the visited method. */ + protected int methodAccess; + + /** The descriptor of the visited method. */ + protected String methodDesc; + + /** Whether the visited method is a constructor. */ + private final boolean isConstructor; + + /** + * Whether the super class constructor has been called (if the visited method is a constructor), + * at the current instruction. There can be multiple call sites to the super constructor (e.g. for + * Java code such as {@code super(expr ? value1 : value2);}), in different branches. When scanning + * the bytecode linearly, we can move from one branch where the super constructor has been called + * to another where it has not been called yet. Therefore, this value can change from false to + * true, and vice-versa. + */ + private boolean superClassConstructorCalled; + + /** + * The values on the current execution stack frame (long and double are represented by two + * elements). Each value is either {@link #UNINITIALIZED_THIS} (for the uninitialized this value), + * or {@link #OTHER} (for any other value). This field is only maintained for constructors, in + * branches where the super class constructor has not been called yet. + */ + private List<Object> stackFrame; + + /** + * The stack map frames corresponding to the labels of the forward jumps made *before* the super + * class constructor has been called (note that the Java Virtual Machine forbids backward jumps + * before the super class constructor is called). Note that by definition (cf. the 'before'), when + * we reach a label from this map, {@link #superClassConstructorCalled} must be reset to false. + * This field is only maintained for constructors. + */ + private Map<Label, List<Object>> forwardJumpStackFrames; + + /** + * Constructs a new {@link AdviceAdapter}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link + * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}. + * @param methodVisitor the method visitor to which this adapter delegates calls. + * @param access the method's access flags (see {@link Opcodes}). + * @param name the method's name. + * @param descriptor the method's descriptor (see {@link Type Type}). + */ + protected AdviceAdapter( + final int api, + final MethodVisitor methodVisitor, + final int access, + final String name, + final String descriptor) { + super(api, methodVisitor, access, name, descriptor); + methodAccess = access; + methodDesc = descriptor; + isConstructor = "<init>".equals(name); + } + + @Override + public void visitCode() { + super.visitCode(); + if (isConstructor) { + stackFrame = new ArrayList<Object>(); + forwardJumpStackFrames = new HashMap<Label, List<Object>>(); + } else { + onMethodEnter(); } - - @Override - public void visitInsn(final int opcode) { - if (constructor) { - int s; - switch (opcode) { - case RETURN: // empty stack - onMethodExit(opcode); - break; - case IRETURN: // 1 before n/a after - case FRETURN: // 1 before n/a after - case ARETURN: // 1 before n/a after - case ATHROW: // 1 before n/a after - popValue(); - onMethodExit(opcode); - break; - case LRETURN: // 2 before n/a after - case DRETURN: // 2 before n/a after - popValue(); - popValue(); - onMethodExit(opcode); - break; - case NOP: - case LALOAD: // remove 2 add 2 - case DALOAD: // remove 2 add 2 - case LNEG: - case DNEG: - case FNEG: - case INEG: - case L2D: - case D2L: - case F2I: - case I2B: - case I2C: - case I2S: - case I2F: - case ARRAYLENGTH: - break; - case ACONST_NULL: - case ICONST_M1: - case ICONST_0: - case ICONST_1: - case ICONST_2: - case ICONST_3: - case ICONST_4: - case ICONST_5: - case FCONST_0: - case FCONST_1: - case FCONST_2: - case F2L: // 1 before 2 after - case F2D: - case I2L: - case I2D: - pushValue(OTHER); - break; - case LCONST_0: - case LCONST_1: - case DCONST_0: - case DCONST_1: - pushValue(OTHER); - pushValue(OTHER); - break; - case IALOAD: // remove 2 add 1 - case FALOAD: // remove 2 add 1 - case AALOAD: // remove 2 add 1 - case BALOAD: // remove 2 add 1 - case CALOAD: // remove 2 add 1 - case SALOAD: // remove 2 add 1 - case POP: - case IADD: - case FADD: - case ISUB: - case LSHL: // 3 before 2 after - case LSHR: // 3 before 2 after - case LUSHR: // 3 before 2 after - case L2I: // 2 before 1 after - case L2F: // 2 before 1 after - case D2I: // 2 before 1 after - case D2F: // 2 before 1 after - case FSUB: - case FMUL: - case FDIV: - case FREM: - case FCMPL: // 2 before 1 after - case FCMPG: // 2 before 1 after - case IMUL: - case IDIV: - case IREM: - case ISHL: - case ISHR: - case IUSHR: - case IAND: - case IOR: - case IXOR: - case MONITORENTER: - case MONITOREXIT: - popValue(); - break; - case POP2: - case LSUB: - case LMUL: - case LDIV: - case LREM: - case LADD: - case LAND: - case LOR: - case LXOR: - case DADD: - case DMUL: - case DSUB: - case DDIV: - case DREM: - popValue(); - popValue(); - break; - case IASTORE: - case FASTORE: - case AASTORE: - case BASTORE: - case CASTORE: - case SASTORE: - case LCMP: // 4 before 1 after - case DCMPL: - case DCMPG: - popValue(); - popValue(); - popValue(); - break; - case LASTORE: - case DASTORE: - popValue(); - popValue(); - popValue(); - popValue(); - break; - case DUP: - pushValue(peekValue()); - break; - case DUP_X1: - s = stackFrame.size(); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - break; - case DUP_X2: - s = stackFrame.size(); - stackFrame.add(s - 3, stackFrame.get(s - 1)); - break; - case DUP2: - s = stackFrame.size(); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - break; - case DUP2_X1: - s = stackFrame.size(); - stackFrame.add(s - 3, stackFrame.get(s - 1)); - stackFrame.add(s - 3, stackFrame.get(s - 1)); - break; - case DUP2_X2: - s = stackFrame.size(); - stackFrame.add(s - 4, stackFrame.get(s - 1)); - stackFrame.add(s - 4, stackFrame.get(s - 1)); - break; - case SWAP: - s = stackFrame.size(); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - stackFrame.remove(s); - break; - } - } else { - switch (opcode) { - case RETURN: - case IRETURN: - case FRETURN: - case ARETURN: - case LRETURN: - case DRETURN: - case ATHROW: - onMethodExit(opcode); - break; - } - } - mv.visitInsn(opcode); + } + + @Override + public void visitLabel(final Label label) { + super.visitLabel(label); + if (isConstructor && forwardJumpStackFrames != null) { + List<Object> labelStackFrame = forwardJumpStackFrames.get(label); + if (labelStackFrame != null) { + stackFrame = labelStackFrame; + superClassConstructorCalled = false; + forwardJumpStackFrames.remove(label); + } } - - @Override - public void visitVarInsn(final int opcode, final int var) { - super.visitVarInsn(opcode, var); - if (constructor) { - switch (opcode) { - case ILOAD: - case FLOAD: - pushValue(OTHER); - break; - case LLOAD: - case DLOAD: - pushValue(OTHER); - pushValue(OTHER); - break; - case ALOAD: - pushValue(var == 0 ? THIS : OTHER); - break; - case ASTORE: - case ISTORE: - case FSTORE: - popValue(); - break; - case LSTORE: - case DSTORE: - popValue(); - popValue(); - break; - } - } + } + + @Override + public void visitInsn(final int opcode) { + if (isConstructor && !superClassConstructorCalled) { + int stackSize; + switch (opcode) { + case IRETURN: + case FRETURN: + case ARETURN: + case LRETURN: + case DRETURN: + throw new IllegalArgumentException("Invalid return in constructor"); + case RETURN: // empty stack + onMethodExit(opcode); + break; + case ATHROW: // 1 before n/a after + popValue(); + onMethodExit(opcode); + break; + case NOP: + case LALOAD: // remove 2 add 2 + case DALOAD: // remove 2 add 2 + case LNEG: + case DNEG: + case FNEG: + case INEG: + case L2D: + case D2L: + case F2I: + case I2B: + case I2C: + case I2S: + case I2F: + case ARRAYLENGTH: + break; + case ACONST_NULL: + case ICONST_M1: + case ICONST_0: + case ICONST_1: + case ICONST_2: + case ICONST_3: + case ICONST_4: + case ICONST_5: + case FCONST_0: + case FCONST_1: + case FCONST_2: + case F2L: // 1 before 2 after + case F2D: + case I2L: + case I2D: + pushValue(OTHER); + break; + case LCONST_0: + case LCONST_1: + case DCONST_0: + case DCONST_1: + pushValue(OTHER); + pushValue(OTHER); + break; + case IALOAD: // remove 2 add 1 + case FALOAD: // remove 2 add 1 + case AALOAD: // remove 2 add 1 + case BALOAD: // remove 2 add 1 + case CALOAD: // remove 2 add 1 + case SALOAD: // remove 2 add 1 + case POP: + case IADD: + case FADD: + case ISUB: + case LSHL: // 3 before 2 after + case LSHR: // 3 before 2 after + case LUSHR: // 3 before 2 after + case L2I: // 2 before 1 after + case L2F: // 2 before 1 after + case D2I: // 2 before 1 after + case D2F: // 2 before 1 after + case FSUB: + case FMUL: + case FDIV: + case FREM: + case FCMPL: // 2 before 1 after + case FCMPG: // 2 before 1 after + case IMUL: + case IDIV: + case IREM: + case ISHL: + case ISHR: + case IUSHR: + case IAND: + case IOR: + case IXOR: + case MONITORENTER: + case MONITOREXIT: + popValue(); + break; + case POP2: + case LSUB: + case LMUL: + case LDIV: + case LREM: + case LADD: + case LAND: + case LOR: + case LXOR: + case DADD: + case DMUL: + case DSUB: + case DDIV: + case DREM: + popValue(); + popValue(); + break; + case IASTORE: + case FASTORE: + case AASTORE: + case BASTORE: + case CASTORE: + case SASTORE: + case LCMP: // 4 before 1 after + case DCMPL: + case DCMPG: + popValue(); + popValue(); + popValue(); + break; + case LASTORE: + case DASTORE: + popValue(); + popValue(); + popValue(); + popValue(); + break; + case DUP: + pushValue(peekValue()); + break; + case DUP_X1: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1)); + break; + case DUP_X2: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1)); + break; + case DUP2: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1)); + stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1)); + break; + case DUP2_X1: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1)); + stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1)); + break; + case DUP2_X2: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 4, stackFrame.get(stackSize - 1)); + stackFrame.add(stackSize - 4, stackFrame.get(stackSize - 1)); + break; + case SWAP: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1)); + stackFrame.remove(stackSize); + break; + default: + throw new IllegalArgumentException(INVALID_OPCODE + opcode); + } + } else { + switch (opcode) { + case RETURN: + case IRETURN: + case FRETURN: + case ARETURN: + case LRETURN: + case DRETURN: + case ATHROW: + onMethodExit(opcode); + break; + default: + break; + } } - - @Override - public void visitFieldInsn(final int opcode, final String owner, - final String name, final String desc) { - mv.visitFieldInsn(opcode, owner, name, desc); - if (constructor) { - char c = desc.charAt(0); - boolean longOrDouble = c == 'J' || c == 'D'; - switch (opcode) { - case GETSTATIC: - pushValue(OTHER); - if (longOrDouble) { - pushValue(OTHER); - } - break; - case PUTSTATIC: - popValue(); - if (longOrDouble) { - popValue(); - } - break; - case PUTFIELD: - popValue(); - popValue(); - if (longOrDouble) { - popValue(); - } - break; - // case GETFIELD: - default: - if (longOrDouble) { - pushValue(OTHER); - } - } - } + super.visitInsn(opcode); + } + + @Override + public void visitVarInsn(final int opcode, final int var) { + super.visitVarInsn(opcode, var); + if (isConstructor && !superClassConstructorCalled) { + switch (opcode) { + case ILOAD: + case FLOAD: + pushValue(OTHER); + break; + case LLOAD: + case DLOAD: + pushValue(OTHER); + pushValue(OTHER); + break; + case ALOAD: + pushValue(var == 0 ? UNINITIALIZED_THIS : OTHER); + break; + case ASTORE: + case ISTORE: + case FSTORE: + popValue(); + break; + case LSTORE: + case DSTORE: + popValue(); + popValue(); + break; + default: + throw new IllegalArgumentException(INVALID_OPCODE + opcode); + } } - - @Override - public void visitIntInsn(final int opcode, final int operand) { - mv.visitIntInsn(opcode, operand); - if (constructor && opcode != NEWARRAY) { - pushValue(OTHER); - } - } - - @Override - public void visitLdcInsn(final Object cst) { - mv.visitLdcInsn(cst); - if (constructor) { + } + + @Override + public void visitFieldInsn( + final int opcode, final String owner, final String name, final String descriptor) { + super.visitFieldInsn(opcode, owner, name, descriptor); + if (isConstructor && !superClassConstructorCalled) { + char firstDescriptorChar = descriptor.charAt(0); + boolean longOrDouble = firstDescriptorChar == 'J' || firstDescriptorChar == 'D'; + switch (opcode) { + case GETSTATIC: + pushValue(OTHER); + if (longOrDouble) { pushValue(OTHER); - if (cst instanceof Double || cst instanceof Long) { - pushValue(OTHER); - } - } - } - - @Override - public void visitMultiANewArrayInsn(final String desc, final int dims) { - mv.visitMultiANewArrayInsn(desc, dims); - if (constructor) { - for (int i = 0; i < dims; i++) { - popValue(); - } + } + break; + case PUTSTATIC: + popValue(); + if (longOrDouble) { + popValue(); + } + break; + case PUTFIELD: + popValue(); + popValue(); + if (longOrDouble) { + popValue(); + } + break; + case GETFIELD: + if (longOrDouble) { pushValue(OTHER); - } + } + break; + default: + throw new IllegalArgumentException(INVALID_OPCODE + opcode); + } } + } - @Override - public void visitTypeInsn(final int opcode, final String type) { - mv.visitTypeInsn(opcode, type); - // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack - if (constructor && opcode == NEW) { - pushValue(OTHER); - } + @Override + public void visitIntInsn(final int opcode, final int operand) { + super.visitIntInsn(opcode, operand); + if (isConstructor && !superClassConstructorCalled && opcode != NEWARRAY) { + pushValue(OTHER); } - - @Deprecated - @Override - public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc) { - if (api >= Opcodes.ASM5) { - super.visitMethodInsn(opcode, owner, name, desc); - return; - } - doVisitMethodInsn(opcode, owner, name, desc, - opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitLdcInsn(final Object value) { + super.visitLdcInsn(value); + if (isConstructor && !superClassConstructorCalled) { + pushValue(OTHER); + if (value instanceof Double + || value instanceof Long + || (value instanceof ConstantDynamic && ((ConstantDynamic) value).getSize() == 2)) { + pushValue(OTHER); + } } - - @Override - public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc, final boolean itf) { - if (api < Opcodes.ASM5) { - super.visitMethodInsn(opcode, owner, name, desc, itf); - return; - } - doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + @Override + public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { + super.visitMultiANewArrayInsn(descriptor, numDimensions); + if (isConstructor && !superClassConstructorCalled) { + for (int i = 0; i < numDimensions; i++) { + popValue(); + } + pushValue(OTHER); } - - private void doVisitMethodInsn(int opcode, final String owner, - final String name, final String desc, final boolean itf) { - mv.visitMethodInsn(opcode, owner, name, desc, itf); - if (constructor) { - Type[] types = Type.getArgumentTypes(desc); - for (int i = 0; i < types.length; i++) { - popValue(); - if (types[i].getSize() == 2) { - popValue(); - } - } - switch (opcode) { - // case INVOKESTATIC: - // break; - case INVOKEINTERFACE: - case INVOKEVIRTUAL: - popValue(); // objectref - break; - case INVOKESPECIAL: - Object type = popValue(); // objectref - if (type == THIS && !superInitialized) { - onMethodEnter(); - superInitialized = true; - // once super has been initialized it is no longer - // necessary to keep track of stack state - constructor = false; - } - break; - } - - Type returnType = Type.getReturnType(desc); - if (returnType != Type.VOID_TYPE) { - pushValue(OTHER); - if (returnType.getSize() == 2) { - pushValue(OTHER); - } - } - } + } + + @Override + public void visitTypeInsn(final int opcode, final String type) { + super.visitTypeInsn(opcode, type); + // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack. + if (isConstructor && !superClassConstructorCalled && opcode == NEW) { + pushValue(OTHER); } - - @Override - public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, - Object... bsmArgs) { - mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); - if (constructor) { - Type[] types = Type.getArgumentTypes(desc); - for (int i = 0; i < types.length; i++) { - popValue(); - if (types[i].getSize() == 2) { - popValue(); - } - } - - Type returnType = Type.getReturnType(desc); - if (returnType != Type.VOID_TYPE) { - pushValue(OTHER); - if (returnType.getSize() == 2) { - pushValue(OTHER); - } - } - } + } + + /** + * Deprecated. + * + * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead. + */ + @Deprecated + @Override + public void visitMethodInsn( + final int opcode, final String owner, final String name, final String descriptor) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, descriptor); + return; } - - @Override - public void visitJumpInsn(final int opcode, final Label label) { - mv.visitJumpInsn(opcode, label); - if (constructor) { - switch (opcode) { - case IFEQ: - case IFNE: - case IFLT: - case IFGE: - case IFGT: - case IFLE: - case IFNULL: - case IFNONNULL: - popValue(); - break; - case IF_ICMPEQ: - case IF_ICMPNE: - case IF_ICMPLT: - case IF_ICMPGE: - case IF_ICMPGT: - case IF_ICMPLE: - case IF_ACMPEQ: - case IF_ACMPNE: - popValue(); - popValue(); - break; - case JSR: - pushValue(OTHER); - break; - } - addBranch(label); - } + mv.visitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE); + doVisitMethodInsn(opcode, descriptor); + } + + @Override + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String descriptor, + final boolean isInterface) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + return; } - - @Override - public void visitLookupSwitchInsn(final Label dflt, final int[] keys, - final Label[] labels) { - mv.visitLookupSwitchInsn(dflt, keys, labels); - if (constructor) { - popValue(); - addBranches(dflt, labels); + mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + doVisitMethodInsn(opcode, descriptor); + } + + private void doVisitMethodInsn(final int opcode, final String descriptor) { + if (isConstructor && !superClassConstructorCalled) { + for (Type argumentType : Type.getArgumentTypes(descriptor)) { + popValue(); + if (argumentType.getSize() == 2) { + popValue(); } - } - - @Override - public void visitTableSwitchInsn(final int min, final int max, - final Label dflt, final Label... labels) { - mv.visitTableSwitchInsn(min, max, dflt, labels); - if (constructor) { - popValue(); - addBranches(dflt, labels); - } - } - - @Override - public void visitTryCatchBlock(Label start, Label end, Label handler, - String type) { - super.visitTryCatchBlock(start, end, handler, type); - if (constructor && !branches.containsKey(handler)) { - List<Object> stackFrame = new ArrayList<Object>(); - stackFrame.add(OTHER); - branches.put(handler, stackFrame); - } - } - - private void addBranches(final Label dflt, final Label[] labels) { - addBranch(dflt); - for (int i = 0; i < labels.length; i++) { - addBranch(labels[i]); + } + switch (opcode) { + case INVOKEINTERFACE: + case INVOKEVIRTUAL: + popValue(); + break; + case INVOKESPECIAL: + Object value = popValue(); + if (value == UNINITIALIZED_THIS && !superClassConstructorCalled) { + superClassConstructorCalled = true; + onMethodEnter(); + } + break; + default: + break; + } + + Type returnType = Type.getReturnType(descriptor); + if (returnType != Type.VOID_TYPE) { + pushValue(OTHER); + if (returnType.getSize() == 2) { + pushValue(OTHER); } + } } - - private void addBranch(final Label label) { - if (branches.containsKey(label)) { - return; - } - branches.put(label, new ArrayList<Object>(stackFrame)); + } + + @Override + public void visitInvokeDynamicInsn( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); + doVisitMethodInsn(Opcodes.INVOKEDYNAMIC, descriptor); + } + + @Override + public void visitJumpInsn(final int opcode, final Label label) { + super.visitJumpInsn(opcode, label); + if (isConstructor && !superClassConstructorCalled) { + switch (opcode) { + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: + case IFNULL: + case IFNONNULL: + popValue(); + break; + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ACMPEQ: + case IF_ACMPNE: + popValue(); + popValue(); + break; + case JSR: + pushValue(OTHER); + break; + default: + break; + } + addForwardJump(label); } - - private Object popValue() { - return stackFrame.remove(stackFrame.size() - 1); + } + + @Override + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { + super.visitLookupSwitchInsn(dflt, keys, labels); + if (isConstructor && !superClassConstructorCalled) { + popValue(); + addForwardJumps(dflt, labels); } - - private Object peekValue() { - return stackFrame.get(stackFrame.size() - 1); + } + + @Override + public void visitTableSwitchInsn( + final int min, final int max, final Label dflt, final Label... labels) { + super.visitTableSwitchInsn(min, max, dflt, labels); + if (isConstructor && !superClassConstructorCalled) { + popValue(); + addForwardJumps(dflt, labels); } - - private void pushValue(final Object o) { - stackFrame.add(o); + } + + @Override + public void visitTryCatchBlock( + final Label start, final Label end, final Label handler, final String type) { + super.visitTryCatchBlock(start, end, handler, type); + // By definition of 'forwardJumpStackFrames', 'handler' should be pushed only if there is an + // instruction between 'start' and 'end' at which the super class constructor is not yet + // called. Unfortunately, try catch blocks must be visited before their labels, so we have no + // way to know this at this point. Instead, we suppose that the super class constructor has not + // been called at the start of *any* exception handler. If this is wrong, normally there should + // not be a second super class constructor call in the exception handler (an object can't be + // initialized twice), so this is not issue (in the sense that there is no risk to emit a wrong + // 'onMethodEnter'). + if (isConstructor && !forwardJumpStackFrames.containsKey(handler)) { + List<Object> handlerStackFrame = new ArrayList<Object>(); + handlerStackFrame.add(OTHER); + forwardJumpStackFrames.put(handler, handlerStackFrame); } + } - /** - * Called at the beginning of the method or after super class call in - * the constructor. <br> - * <br> - * - * <i>Custom code can use or change all the local variables, but should not - * change state of the stack.</i> - */ - protected void onMethodEnter() { + private void addForwardJumps(final Label dflt, final Label[] labels) { + addForwardJump(dflt); + for (Label label : labels) { + addForwardJump(label); } + } - /** - * Called before explicit exit from the method using either return or throw. - * Top element on the stack contains the return value or exception instance. - * For example: - * - * <pre> - * public void onMethodExit(int opcode) { - * if(opcode==RETURN) { - * visitInsn(ACONST_NULL); - * } else if(opcode==ARETURN || opcode==ATHROW) { - * dup(); - * } else { - * if(opcode==LRETURN || opcode==DRETURN) { - * dup2(); - * } else { - * dup(); - * } - * box(Type.getReturnType(this.methodDesc)); - * } - * visitIntInsn(SIPUSH, opcode); - * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V"); - * } - * - * // an actual call back method - * public static void onExit(Object param, int opcode) { - * ... - * </pre> - * - * <br> - * <br> - * - * <i>Custom code can use or change all the local variables, but should not - * change state of the stack.</i> - * - * @param opcode - * one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN - * or ATHROW - * - */ - protected void onMethodExit(int opcode) { + private void addForwardJump(final Label label) { + if (forwardJumpStackFrames.containsKey(label)) { + return; } - - // TODO onException, onMethodCall + forwardJumpStackFrames.put(label, new ArrayList<Object>(stackFrame)); + } + + private Object popValue() { + return stackFrame.remove(stackFrame.size() - 1); + } + + private Object peekValue() { + return stackFrame.get(stackFrame.size() - 1); + } + + private void pushValue(final Object value) { + stackFrame.add(value); + } + + /** + * Generates the "before" advice for the visited method. The default implementation of this method + * does nothing. Subclasses can use or change all the local variables, but should not change state + * of the stack. This method is called at the beginning of the method or after super class + * constructor has been called (in constructors). + */ + protected void onMethodEnter() {} + + /** + * Generates the "after" advice for the visited method. The default implementation of this method + * does nothing. Subclasses can use or change all the local variables, but should not change state + * of the stack. This method is called at the end of the method, just before return and athrow + * instructions. The top element on the stack contains the return value or the exception instance. + * For example: + * + * <pre> + * public void onMethodExit(final int opcode) { + * if (opcode == RETURN) { + * visitInsn(ACONST_NULL); + * } else if (opcode == ARETURN || opcode == ATHROW) { + * dup(); + * } else { + * if (opcode == LRETURN || opcode == DRETURN) { + * dup2(); + * } else { + * dup(); + * } + * box(Type.getReturnType(this.methodDesc)); + * } + * visitIntInsn(SIPUSH, opcode); + * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V"); + * } + * + * // An actual call back method. + * public static void onExit(final Object exitValue, final int opcode) { + * ... + * } + * </pre> + * + * @param opcode one of {@link Opcodes#RETURN}, {@link Opcodes#IRETURN}, {@link Opcodes#FRETURN}, + * {@link Opcodes#ARETURN}, {@link Opcodes#LRETURN}, {@link Opcodes#DRETURN} or {@link + * Opcodes#ATHROW}. + */ + protected void onMethodExit(final int opcode) {} }
