You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2018/11/29 00:33:56 UTC
[09/46] tapestry-5 git commit: TAP5-2588: upgrading from ASM 6 to 7
for Java 9+ support
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java
old mode 100644
new mode 100755
index 931a73d..e355c78
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckMethodAdapter.java
@@ -1,46 +1,43 @@
-/***
- * 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.util;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-
import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
import org.apache.tapestry5.internal.plastic.asm.Attribute;
+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;
@@ -50,1503 +47,1420 @@ import org.apache.tapestry5.internal.plastic.asm.TypePath;
import org.apache.tapestry5.internal.plastic.asm.TypeReference;
import org.apache.tapestry5.internal.plastic.asm.tree.MethodNode;
import org.apache.tapestry5.internal.plastic.asm.tree.analysis.Analyzer;
+import org.apache.tapestry5.internal.plastic.asm.tree.analysis.AnalyzerException;
import org.apache.tapestry5.internal.plastic.asm.tree.analysis.BasicValue;
import org.apache.tapestry5.internal.plastic.asm.tree.analysis.BasicVerifier;
/**
- * A {@link MethodVisitor} that checks that its methods are properly used. More
- * precisely this method adapter checks each instruction individually, i.e.,
- * each visit method checks some preconditions based <i>only</i> on its
- * arguments - such as the fact that the given opcode is correct for a given
- * visit method. This adapter can also perform some basic data flow checks (more
- * precisely those that can be performed without the full class hierarchy - see
- * {@link org.objectweb.asm.tree.analysis.BasicVerifier}). For instance in a
- * method whose signature is <tt>void m ()</tt>, the invalid instruction
- * IRETURN, or the invalid sequence IADD L2I will be detected if the data flow
- * checks are enabled. These checks are enabled by using the
- * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)} constructor.
- * They are not performed if any other constructor is used.
- *
+ * A {@link MethodVisitor} that checks that its methods are properly used. More precisely this
+ * method adapter checks each instruction individually, i.e., each visit method checks some
+ * preconditions based <i>only</i> on its arguments - such as the fact that the given opcode is
+ * correct for a given visit method. This adapter can also perform some basic data flow checks (more
+ * precisely those that can be performed without the full class hierarchy - see {@link
+ * org.apache.tapestry5.internal.plastic.asm.tree.analysis.BasicVerifier}). For instance in a method whose signature is
+ * {@code void m ()}, the invalid instruction IRETURN, or the invalid sequence IADD L2I will be
+ * detected if the data flow checks are enabled. These checks are enabled by using the {@link
+ * #CheckMethodAdapter(int,String,String,MethodVisitor,Map)} constructor. They are not performed if
+ * any other constructor is used.
+ *
* @author Eric Bruneton
*/
public class CheckMethodAdapter extends MethodVisitor {
- /**
- * The class version number.
- */
- public int version;
-
- /**
- * The access flags of the method.
- */
- private int access;
-
- /**
- * <tt>true</tt> if the visitCode method has been called.
- */
- private boolean startCode;
-
- /**
- * <tt>true</tt> if the visitMaxs method has been called.
- */
- private boolean endCode;
-
- /**
- * <tt>true</tt> if the visitEnd method has been called.
- */
- private boolean endMethod;
-
- /**
- * Number of visited instructions.
- */
- private int insnCount;
-
- /**
- * The already visited labels. This map associate Integer values to pseudo
- * code offsets.
- */
- private final Map<Label, Integer> labels;
-
- /**
- * The labels used in this method. Every used label must be visited with
- * visitLabel before the end of the method (i.e. should be in #labels).
- */
- private Set<Label> usedLabels;
-
- /**
- * Number of visited frames in expanded form.
- */
- private int expandedFrames;
-
- /**
- * Number of visited frames in compressed form.
- */
- private int compressedFrames;
-
- /**
- * Number of instructions before the last visited frame.
- */
- private int lastFrame = -1;
-
- /**
- * The exception handler ranges. Each pair of list element contains the
- * start and end labels of an exception handler block.
- */
- private List<Label> handlers;
-
- /**
- * Code of the visit method to be used for each opcode.
- */
- private static final int[] TYPE;
-
- /**
- * The Label.status field.
- */
- private static Field labelStatusField;
-
- static {
- String s = "BBBBBBBBBBBBBBBBCCIAADDDDDAAAAAAAAAAAAAAAAAAAABBBBBBBBDD"
- + "DDDAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
- + "BBBBBBBBBBBBBBBBBBBJBBBBBBBBBBBBBBBBBBBBHHHHHHHHHHHHHHHHD"
- + "KLBBBBBBFFFFGGGGAECEBBEEBBAMHHAA";
- TYPE = new int[s.length()];
- for (int i = 0; i < TYPE.length; ++i) {
- TYPE[i] = s.charAt(i) - 'A' - 1;
- }
+ /** The 'generic' instruction visit methods (i.e. those that take an opcode argument). */
+ private enum Method {
+ VISIT_INSN,
+ VISIT_INT_INSN,
+ VISIT_VAR_INSN,
+ VISIT_TYPE_INSN,
+ VISIT_FIELD_INSN,
+ VISIT_METHOD_INSN,
+ VISIT_JUMP_INSN
+ }
+
+ /** The method to use to visit each instruction. Only generic methods are represented here. */
+ private static final Method[] OPCODE_METHODS = {
+ Method.VISIT_INSN, // NOP
+ Method.VISIT_INSN, // ACONST_NULL
+ Method.VISIT_INSN, // ICONST_M1
+ Method.VISIT_INSN, // ICONST_0
+ Method.VISIT_INSN, // ICONST_1
+ Method.VISIT_INSN, // ICONST_2
+ Method.VISIT_INSN, // ICONST_3
+ Method.VISIT_INSN, // ICONST_4
+ Method.VISIT_INSN, // ICONST_5
+ Method.VISIT_INSN, // LCONST_0
+ Method.VISIT_INSN, // LCONST_1
+ Method.VISIT_INSN, // FCONST_0
+ Method.VISIT_INSN, // FCONST_1
+ Method.VISIT_INSN, // FCONST_2
+ Method.VISIT_INSN, // DCONST_0
+ Method.VISIT_INSN, // DCONST_1
+ Method.VISIT_INT_INSN, // BIPUSH
+ Method.VISIT_INT_INSN, // SIPUSH
+ null, // LDC
+ null, // LDC_W
+ null, // LDC2_W
+ Method.VISIT_VAR_INSN, // ILOAD
+ Method.VISIT_VAR_INSN, // LLOAD
+ Method.VISIT_VAR_INSN, // FLOAD
+ Method.VISIT_VAR_INSN, // DLOAD
+ Method.VISIT_VAR_INSN, // ALOAD
+ null, // ILOAD_0
+ null, // ILOAD_1
+ null, // ILOAD_2
+ null, // ILOAD_3
+ null, // LLOAD_0
+ null, // LLOAD_1
+ null, // LLOAD_2
+ null, // LLOAD_3
+ null, // FLOAD_0
+ null, // FLOAD_1
+ null, // FLOAD_2
+ null, // FLOAD_3
+ null, // DLOAD_0
+ null, // DLOAD_1
+ null, // DLOAD_2
+ null, // DLOAD_3
+ null, // ALOAD_0
+ null, // ALOAD_1
+ null, // ALOAD_2
+ null, // ALOAD_3
+ Method.VISIT_INSN, // IALOAD
+ Method.VISIT_INSN, // LALOAD
+ Method.VISIT_INSN, // FALOAD
+ Method.VISIT_INSN, // DALOAD
+ Method.VISIT_INSN, // AALOAD
+ Method.VISIT_INSN, // BALOAD
+ Method.VISIT_INSN, // CALOAD
+ Method.VISIT_INSN, // SALOAD
+ Method.VISIT_VAR_INSN, // ISTORE
+ Method.VISIT_VAR_INSN, // LSTORE
+ Method.VISIT_VAR_INSN, // FSTORE
+ Method.VISIT_VAR_INSN, // DSTORE
+ Method.VISIT_VAR_INSN, // ASTORE
+ null, // ISTORE_0
+ null, // ISTORE_1
+ null, // ISTORE_2
+ null, // ISTORE_3
+ null, // LSTORE_0
+ null, // LSTORE_1
+ null, // LSTORE_2
+ null, // LSTORE_3
+ null, // FSTORE_0
+ null, // FSTORE_1
+ null, // FSTORE_2
+ null, // FSTORE_3
+ null, // DSTORE_0
+ null, // DSTORE_1
+ null, // DSTORE_2
+ null, // DSTORE_3
+ null, // ASTORE_0
+ null, // ASTORE_1
+ null, // ASTORE_2
+ null, // ASTORE_3
+ Method.VISIT_INSN, // IASTORE
+ Method.VISIT_INSN, // LASTORE
+ Method.VISIT_INSN, // FASTORE
+ Method.VISIT_INSN, // DASTORE
+ Method.VISIT_INSN, // AASTORE
+ Method.VISIT_INSN, // BASTORE
+ Method.VISIT_INSN, // CASTORE
+ Method.VISIT_INSN, // SASTORE
+ Method.VISIT_INSN, // POP
+ Method.VISIT_INSN, // POP2
+ Method.VISIT_INSN, // DUP
+ Method.VISIT_INSN, // DUP_X1
+ Method.VISIT_INSN, // DUP_X2
+ Method.VISIT_INSN, // DUP2
+ Method.VISIT_INSN, // DUP2_X1
+ Method.VISIT_INSN, // DUP2_X2
+ Method.VISIT_INSN, // SWAP
+ Method.VISIT_INSN, // IADD
+ Method.VISIT_INSN, // LADD
+ Method.VISIT_INSN, // FADD
+ Method.VISIT_INSN, // DADD
+ Method.VISIT_INSN, // ISUB
+ Method.VISIT_INSN, // LSUB
+ Method.VISIT_INSN, // FSUB
+ Method.VISIT_INSN, // DSUB
+ Method.VISIT_INSN, // IMUL
+ Method.VISIT_INSN, // LMUL
+ Method.VISIT_INSN, // FMUL
+ Method.VISIT_INSN, // DMUL
+ Method.VISIT_INSN, // IDIV
+ Method.VISIT_INSN, // LDIV
+ Method.VISIT_INSN, // FDIV
+ Method.VISIT_INSN, // DDIV
+ Method.VISIT_INSN, // IREM
+ Method.VISIT_INSN, // LREM
+ Method.VISIT_INSN, // FREM
+ Method.VISIT_INSN, // DREM
+ Method.VISIT_INSN, // INEG
+ Method.VISIT_INSN, // LNEG
+ Method.VISIT_INSN, // FNEG
+ Method.VISIT_INSN, // DNEG
+ Method.VISIT_INSN, // ISHL
+ Method.VISIT_INSN, // LSHL
+ Method.VISIT_INSN, // ISHR
+ Method.VISIT_INSN, // LSHR
+ Method.VISIT_INSN, // IUSHR
+ Method.VISIT_INSN, // LUSHR
+ Method.VISIT_INSN, // IAND
+ Method.VISIT_INSN, // LAND
+ Method.VISIT_INSN, // IOR
+ Method.VISIT_INSN, // LOR
+ Method.VISIT_INSN, // IXOR
+ Method.VISIT_INSN, // LXOR
+ null, // IINC
+ Method.VISIT_INSN, // I2L
+ Method.VISIT_INSN, // I2F
+ Method.VISIT_INSN, // I2D
+ Method.VISIT_INSN, // L2I
+ Method.VISIT_INSN, // L2F
+ Method.VISIT_INSN, // L2D
+ Method.VISIT_INSN, // F2I
+ Method.VISIT_INSN, // F2L
+ Method.VISIT_INSN, // F2D
+ Method.VISIT_INSN, // D2I
+ Method.VISIT_INSN, // D2L
+ Method.VISIT_INSN, // D2F
+ Method.VISIT_INSN, // I2B
+ Method.VISIT_INSN, // I2C
+ Method.VISIT_INSN, // I2S
+ Method.VISIT_INSN, // LCMP
+ Method.VISIT_INSN, // FCMPL
+ Method.VISIT_INSN, // FCMPG
+ Method.VISIT_INSN, // DCMPL
+ Method.VISIT_INSN, // DCMPG
+ Method.VISIT_JUMP_INSN, // IFEQ
+ Method.VISIT_JUMP_INSN, // IFNE
+ Method.VISIT_JUMP_INSN, // IFLT
+ Method.VISIT_JUMP_INSN, // IFGE
+ Method.VISIT_JUMP_INSN, // IFGT
+ Method.VISIT_JUMP_INSN, // IFLE
+ Method.VISIT_JUMP_INSN, // IF_ICMPEQ
+ Method.VISIT_JUMP_INSN, // IF_ICMPNE
+ Method.VISIT_JUMP_INSN, // IF_ICMPLT
+ Method.VISIT_JUMP_INSN, // IF_ICMPGE
+ Method.VISIT_JUMP_INSN, // IF_ICMPGT
+ Method.VISIT_JUMP_INSN, // IF_ICMPLE
+ Method.VISIT_JUMP_INSN, // IF_ACMPEQ
+ Method.VISIT_JUMP_INSN, // IF_ACMPNE
+ Method.VISIT_JUMP_INSN, // GOTO
+ Method.VISIT_JUMP_INSN, // JSR
+ Method.VISIT_VAR_INSN, // RET
+ null, // TABLESWITCH
+ null, // LOOKUPSWITCH
+ Method.VISIT_INSN, // IRETURN
+ Method.VISIT_INSN, // LRETURN
+ Method.VISIT_INSN, // FRETURN
+ Method.VISIT_INSN, // DRETURN
+ Method.VISIT_INSN, // ARETURN
+ Method.VISIT_INSN, // RETURN
+ Method.VISIT_FIELD_INSN, // GETSTATIC
+ Method.VISIT_FIELD_INSN, // PUTSTATIC
+ Method.VISIT_FIELD_INSN, // GETFIELD
+ Method.VISIT_FIELD_INSN, // PUTFIELD
+ Method.VISIT_METHOD_INSN, // INVOKEVIRTUAL
+ Method.VISIT_METHOD_INSN, // INVOKESPECIAL
+ Method.VISIT_METHOD_INSN, // INVOKESTATIC
+ Method.VISIT_METHOD_INSN, // INVOKEINTERFACE
+ null, // INVOKEDYNAMIC
+ Method.VISIT_TYPE_INSN, // NEW
+ Method.VISIT_INT_INSN, // NEWARRAY
+ Method.VISIT_TYPE_INSN, // ANEWARRAY
+ Method.VISIT_INSN, // ARRAYLENGTH
+ Method.VISIT_INSN, // ATHROW
+ Method.VISIT_TYPE_INSN, // CHECKCAST
+ Method.VISIT_TYPE_INSN, // INSTANCEOF
+ Method.VISIT_INSN, // MONITORENTER
+ Method.VISIT_INSN, // MONITOREXIT
+ null, // WIDE
+ null, // MULTIANEWARRAY
+ Method.VISIT_JUMP_INSN, // IFNULL
+ Method.VISIT_JUMP_INSN // IFNONNULL
+ };
+
+ private static final String INVALID = "Invalid ";
+ private static final String INVALID_DESCRIPTOR = "Invalid descriptor: ";
+ private static final String INVALID_TYPE_REFERENCE = "Invalid type reference sort 0x";
+ private static final String INVALID_LOCAL_VARIABLE_INDEX = "Invalid local variable index";
+ private static final String MUST_NOT_BE_NULL_OR_EMPTY = " (must not be null or empty)";
+ private static final String START_LABEL = "start label";
+ private static final String END_LABEL = "end label";
+
+ /** The class version number. */
+ public int version;
+
+ /** The access flags of the visited method. */
+ private int access;
+
+ /**
+ * The number of method parameters that can have runtime visible annotations. 0 means that all the
+ * parameters from the method descriptor can have annotations.
+ */
+ private int visibleAnnotableParameterCount;
+
+ /**
+ * The number of method parameters that can have runtime invisible annotations. 0 means that all
+ * the parameters from the method descriptor can have annotations.
+ */
+ private int invisibleAnnotableParameterCount;
+
+ /** Whether the {@link #visitCode} method has been called. */
+ private boolean visitCodeCalled;
+
+ /** Whether the {@link #visitMaxs} method has been called. */
+ private boolean visitMaxCalled;
+
+ /** Whether the {@link #visitEnd} method has been called. */
+ private boolean visitEndCalled;
+
+ /** The number of visited instructions so far. */
+ private int insnCount;
+
+ /** The index of the instruction designated by each visited label. */
+ private final Map<Label, Integer> labelInsnIndices;
+
+ /** The labels referenced by the visited method. */
+ private Set<Label> referencedLabels;
+
+ /** The index of the instruction corresponding to the last visited stack map frame. */
+ private int lastFrameInsnIndex = -1;
+
+ /** The number of visited frames in expanded form. */
+ private int numExpandedFrames;
+
+ /** The number of visited frames in compressed form. */
+ private int numCompressedFrames;
+
+ /**
+ * The exception handler ranges. Each pair of list element contains the start and end labels of an
+ * exception handler block.
+ */
+ private List<Label> handlers;
+
+ /**
+ * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
+ * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
+ * <i>Subclasses must not use this constructor</i>. Instead, they must use the {@link
+ * #CheckMethodAdapter(int, MethodVisitor, Map)} version.
+ *
+ * @param methodvisitor the method visitor to which this adapter must delegate calls.
+ */
+ public CheckMethodAdapter(final MethodVisitor methodvisitor) {
+ this(methodvisitor, new HashMap<Label, Integer>());
+ }
+
+ /**
+ * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
+ * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
+ * <i>Subclasses must not use this constructor</i>. Instead, they must use the {@link
+ * #CheckMethodAdapter(int, MethodVisitor, Map)} version.
+ *
+ * @param methodVisitor the method visitor to which this adapter must delegate calls.
+ * @param labelInsnIndices the index of the instruction designated by each visited label so far
+ * (in other methods). This map is updated with the labels from the visited method.
+ * @throws IllegalStateException If a subclass calls this constructor.
+ */
+ public CheckMethodAdapter(
+ final MethodVisitor methodVisitor, final Map<Label, Integer> labelInsnIndices) {
+ this(Opcodes.ASM7, methodVisitor, labelInsnIndices);
+ if (getClass() != CheckMethodAdapter.class) {
+ throw new IllegalStateException();
}
-
- // code to generate the above string
- // public static void main (String[] args) {
- // int[] TYPE = new int[] {
- // 0, //NOP
- // 0, //ACONST_NULL
- // 0, //ICONST_M1
- // 0, //ICONST_0
- // 0, //ICONST_1
- // 0, //ICONST_2
- // 0, //ICONST_3
- // 0, //ICONST_4
- // 0, //ICONST_5
- // 0, //LCONST_0
- // 0, //LCONST_1
- // 0, //FCONST_0
- // 0, //FCONST_1
- // 0, //FCONST_2
- // 0, //DCONST_0
- // 0, //DCONST_1
- // 1, //BIPUSH
- // 1, //SIPUSH
- // 7, //LDC
- // -1, //LDC_W
- // -1, //LDC2_W
- // 2, //ILOAD
- // 2, //LLOAD
- // 2, //FLOAD
- // 2, //DLOAD
- // 2, //ALOAD
- // -1, //ILOAD_0
- // -1, //ILOAD_1
- // -1, //ILOAD_2
- // -1, //ILOAD_3
- // -1, //LLOAD_0
- // -1, //LLOAD_1
- // -1, //LLOAD_2
- // -1, //LLOAD_3
- // -1, //FLOAD_0
- // -1, //FLOAD_1
- // -1, //FLOAD_2
- // -1, //FLOAD_3
- // -1, //DLOAD_0
- // -1, //DLOAD_1
- // -1, //DLOAD_2
- // -1, //DLOAD_3
- // -1, //ALOAD_0
- // -1, //ALOAD_1
- // -1, //ALOAD_2
- // -1, //ALOAD_3
- // 0, //IALOAD
- // 0, //LALOAD
- // 0, //FALOAD
- // 0, //DALOAD
- // 0, //AALOAD
- // 0, //BALOAD
- // 0, //CALOAD
- // 0, //SALOAD
- // 2, //ISTORE
- // 2, //LSTORE
- // 2, //FSTORE
- // 2, //DSTORE
- // 2, //ASTORE
- // -1, //ISTORE_0
- // -1, //ISTORE_1
- // -1, //ISTORE_2
- // -1, //ISTORE_3
- // -1, //LSTORE_0
- // -1, //LSTORE_1
- // -1, //LSTORE_2
- // -1, //LSTORE_3
- // -1, //FSTORE_0
- // -1, //FSTORE_1
- // -1, //FSTORE_2
- // -1, //FSTORE_3
- // -1, //DSTORE_0
- // -1, //DSTORE_1
- // -1, //DSTORE_2
- // -1, //DSTORE_3
- // -1, //ASTORE_0
- // -1, //ASTORE_1
- // -1, //ASTORE_2
- // -1, //ASTORE_3
- // 0, //IASTORE
- // 0, //LASTORE
- // 0, //FASTORE
- // 0, //DASTORE
- // 0, //AASTORE
- // 0, //BASTORE
- // 0, //CASTORE
- // 0, //SASTORE
- // 0, //POP
- // 0, //POP2
- // 0, //DUP
- // 0, //DUP_X1
- // 0, //DUP_X2
- // 0, //DUP2
- // 0, //DUP2_X1
- // 0, //DUP2_X2
- // 0, //SWAP
- // 0, //IADD
- // 0, //LADD
- // 0, //FADD
- // 0, //DADD
- // 0, //ISUB
- // 0, //LSUB
- // 0, //FSUB
- // 0, //DSUB
- // 0, //IMUL
- // 0, //LMUL
- // 0, //FMUL
- // 0, //DMUL
- // 0, //IDIV
- // 0, //LDIV
- // 0, //FDIV
- // 0, //DDIV
- // 0, //IREM
- // 0, //LREM
- // 0, //FREM
- // 0, //DREM
- // 0, //INEG
- // 0, //LNEG
- // 0, //FNEG
- // 0, //DNEG
- // 0, //ISHL
- // 0, //LSHL
- // 0, //ISHR
- // 0, //LSHR
- // 0, //IUSHR
- // 0, //LUSHR
- // 0, //IAND
- // 0, //LAND
- // 0, //IOR
- // 0, //LOR
- // 0, //IXOR
- // 0, //LXOR
- // 8, //IINC
- // 0, //I2L
- // 0, //I2F
- // 0, //I2D
- // 0, //L2I
- // 0, //L2F
- // 0, //L2D
- // 0, //F2I
- // 0, //F2L
- // 0, //F2D
- // 0, //D2I
- // 0, //D2L
- // 0, //D2F
- // 0, //I2B
- // 0, //I2C
- // 0, //I2S
- // 0, //LCMP
- // 0, //FCMPL
- // 0, //FCMPG
- // 0, //DCMPL
- // 0, //DCMPG
- // 6, //IFEQ
- // 6, //IFNE
- // 6, //IFLT
- // 6, //IFGE
- // 6, //IFGT
- // 6, //IFLE
- // 6, //IF_ICMPEQ
- // 6, //IF_ICMPNE
- // 6, //IF_ICMPLT
- // 6, //IF_ICMPGE
- // 6, //IF_ICMPGT
- // 6, //IF_ICMPLE
- // 6, //IF_ACMPEQ
- // 6, //IF_ACMPNE
- // 6, //GOTO
- // 6, //JSR
- // 2, //RET
- // 9, //TABLESWITCH
- // 10, //LOOKUPSWITCH
- // 0, //IRETURN
- // 0, //LRETURN
- // 0, //FRETURN
- // 0, //DRETURN
- // 0, //ARETURN
- // 0, //RETURN
- // 4, //GETSTATIC
- // 4, //PUTSTATIC
- // 4, //GETFIELD
- // 4, //PUTFIELD
- // 5, //INVOKEVIRTUAL
- // 5, //INVOKESPECIAL
- // 5, //INVOKESTATIC
- // 5, //INVOKEINTERFACE
- // -1, //INVOKEDYNAMIC
- // 3, //NEW
- // 1, //NEWARRAY
- // 3, //ANEWARRAY
- // 0, //ARRAYLENGTH
- // 0, //ATHROW
- // 3, //CHECKCAST
- // 3, //INSTANCEOF
- // 0, //MONITORENTER
- // 0, //MONITOREXIT
- // -1, //WIDE
- // 11, //MULTIANEWARRAY
- // 6, //IFNULL
- // 6, //IFNONNULL
- // -1, //GOTO_W
- // -1 //JSR_W
- // };
- // for (int i = 0; i < TYPE.length; ++i) {
- // System.out.print((char)(TYPE[i] + 1 + 'A'));
- // }
- // System.out.println();
- // }
-
- /**
- * Constructs a new {@link CheckMethodAdapter} object. This method adapter
- * will not perform any data flow check (see
- * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
- * <i>Subclasses must not use this constructor</i>. Instead, they must use
- * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version.
- *
- * @param mv
- * the method visitor to which this adapter must delegate calls.
- */
- public CheckMethodAdapter(final MethodVisitor mv) {
- this(mv, new HashMap<Label, Integer>());
- }
-
- /**
- * Constructs a new {@link CheckMethodAdapter} object. This method adapter
- * will not perform any data flow check (see
- * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
- * <i>Subclasses must not use this constructor</i>. Instead, they must use
- * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version.
- *
- * @param mv
- * the method visitor to which this adapter must delegate calls.
- * @param labels
- * a map of already visited labels (in other methods).
- * @throws IllegalStateException
- * If a subclass calls this constructor.
- */
- public CheckMethodAdapter(final MethodVisitor mv,
- final Map<Label, Integer> labels) {
- this(Opcodes.ASM6, mv, labels);
- if (getClass() != CheckMethodAdapter.class) {
- throw new IllegalStateException();
- }
+ }
+
+ /**
+ * Constructs a new {@link CheckMethodAdapter} object. This method adapter will not perform any
+ * data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
+ *
+ * @param api the ASM API version implemented by this CheckMethodAdapter. 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 must delegate calls.
+ * @param labelInsnIndices the index of the instruction designated by each visited label so far
+ * (in other methods). This map is updated with the labels from the visited method.
+ */
+ protected CheckMethodAdapter(
+ final int api,
+ final MethodVisitor methodVisitor,
+ final Map<Label, Integer> labelInsnIndices) {
+ super(api, methodVisitor);
+ this.labelInsnIndices = labelInsnIndices;
+ this.referencedLabels = new HashSet<Label>();
+ this.handlers = new ArrayList<Label>();
+ }
+
+ /**
+ * Constructs a new {@link CheckMethodAdapter} object. This method adapter will perform basic data
+ * flow checks. For instance in a method whose signature is {@code void m ()}, the invalid
+ * instruction IRETURN, or the invalid sequence IADD L2I will be detected. <i>Subclasses must not
+ * use this constructor</i>. Instead, they must use the {@link
+ * #CheckMethodAdapter(int,int,String,String,MethodVisitor,Map)} version.
+ *
+ * @param access the method's access flags.
+ * @param name the method's name.
+ * @param descriptor the method's descriptor (see {@link Type}).
+ * @param methodVisitor the method visitor to which this adapter must delegate calls.
+ * @param labelInsnIndices the index of the instruction designated by each visited label so far
+ * (in other methods). This map is updated with the labels from the visited method.
+ */
+ public CheckMethodAdapter(
+ final int access,
+ final String name,
+ final String descriptor,
+ final MethodVisitor methodVisitor,
+ final Map<Label, Integer> labelInsnIndices) {
+ this(Opcodes.ASM7, access, name, descriptor, methodVisitor, labelInsnIndices);
+ if (getClass() != CheckMethodAdapter.class) {
+ throw new IllegalStateException();
}
-
- /**
- * Constructs a new {@link CheckMethodAdapter} object. This method adapter
- * will not perform any data flow check (see
- * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
- *
- * @param api
- * the ASM API version implemented by this CheckMethodAdapter.
- * Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5}
- * or {@link Opcodes#ASM6}.
- * @param mv
- * the method visitor to which this adapter must delegate calls.
- * @param labels
- * a map of already visited labels (in other methods).
- */
- protected CheckMethodAdapter(final int api, final MethodVisitor mv,
- final Map<Label, Integer> labels) {
- super(api, mv);
- this.labels = labels;
- this.usedLabels = new HashSet<Label>();
- this.handlers = new ArrayList<Label>();
- }
-
- /**
- * Constructs a new {@link CheckMethodAdapter} object. This method adapter
- * will perform basic data flow checks. For instance in a method whose
- * signature is <tt>void m ()</tt>, the invalid instruction IRETURN, or the
- * invalid sequence IADD L2I will be detected.
- *
- * @param access
- * the method's access flags.
- * @param name
- * the method's name.
- * @param desc
- * the method's descriptor (see {@link Type Type}).
- * @param cmv
- * the method visitor to which this adapter must delegate calls.
- * @param labels
- * a map of already visited labels (in other methods).
- */
- public CheckMethodAdapter(final int access, final String name,
- final String desc, final MethodVisitor cmv,
- final Map<Label, Integer> labels) {
- this(new MethodNode(Opcodes.ASM5, access, name, desc, null, null) {
- @Override
- public void visitEnd() {
- Analyzer<BasicValue> a = new Analyzer<BasicValue>(
- new BasicVerifier());
- try {
- a.analyze("dummy", this);
- } catch (Exception e) {
- if (e instanceof IndexOutOfBoundsException
- && maxLocals == 0 && maxStack == 0) {
- throw new RuntimeException(
- "Data flow checking option requires valid, non zero maxLocals and maxStack values.");
- }
- e.printStackTrace();
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw, true);
- CheckClassAdapter.printAnalyzerResult(this, a, pw);
- pw.close();
- throw new RuntimeException(e.getMessage() + ' '
- + sw.toString());
- }
- accept(cmv);
+ }
+
+ /**
+ * Constructs a new {@link CheckMethodAdapter} object. This method adapter will perform basic data
+ * flow checks. For instance in a method whose signature is {@code void m ()}, the invalid
+ * instruction IRETURN, or the invalid sequence IADD L2I will be detected.
+ *
+ * @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
+ * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+ * @param access the method's access flags.
+ * @param name the method's name.
+ * @param descriptor the method's descriptor (see {@link Type}).
+ * @param methodVisitor the method visitor to which this adapter must delegate calls.
+ * @param labelInsnIndices the index of the instruction designated by each visited label so far
+ * (in other methods). This map is updated with the labels from the visited method.
+ */
+ protected CheckMethodAdapter(
+ final int api,
+ final int access,
+ final String name,
+ final String descriptor,
+ final MethodVisitor methodVisitor,
+ final Map<Label, Integer> labelInsnIndices) {
+ this(
+ api,
+ new MethodNode(api, access, name, descriptor, null, null) {
+ @Override
+ public void visitEnd() {
+ Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicVerifier());
+ try {
+ analyzer.analyze("dummy", this);
+ } catch (IndexOutOfBoundsException e) {
+ if (maxLocals == 0 && maxStack == 0) {
+ throw new IllegalArgumentException(
+ "Data flow checking option requires valid, non zero maxLocals and maxStack.",
+ e);
+ }
+ throwError(analyzer, e);
+ } catch (AnalyzerException e) {
+ throwError(analyzer, e);
}
- }, labels);
- this.access = access;
+ accept(methodVisitor);
+ }
+
+ private void throwError(final Analyzer<BasicValue> analyzer, final Exception e) {
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(stringWriter, true);
+ CheckClassAdapter.printAnalyzerResult(this, analyzer, printWriter);
+ printWriter.close();
+ throw new IllegalArgumentException(e.getMessage() + ' ' + stringWriter.toString(), e);
+ }
+ },
+ labelInsnIndices);
+ this.access = access;
+ }
+
+ @Override
+ public void visitParameter(final String name, final int access) {
+ if (name != null) {
+ checkUnqualifiedName(version, name, "name");
}
-
- @Override
- public void visitParameter(String name, int access) {
- if (name != null) {
- checkUnqualifiedName(version, name, "name");
- }
- CheckClassAdapter.checkAccess(access, Opcodes.ACC_FINAL
- + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
- super.visitParameter(name, access);
- }
-
- @Override
- public AnnotationVisitor visitAnnotation(final String desc,
- final boolean visible) {
- checkEndMethod();
- checkDesc(desc, false);
- return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible));
- }
-
- @Override
- public AnnotationVisitor visitTypeAnnotation(final int typeRef,
- final TypePath typePath, final String desc, final boolean visible) {
- checkEndMethod();
- int sort = typeRef >>> 24;
- if (sort != TypeReference.METHOD_TYPE_PARAMETER
- && sort != TypeReference.METHOD_TYPE_PARAMETER_BOUND
- && sort != TypeReference.METHOD_RETURN
- && sort != TypeReference.METHOD_RECEIVER
- && sort != TypeReference.METHOD_FORMAL_PARAMETER
- && sort != TypeReference.THROWS) {
- throw new IllegalArgumentException("Invalid type reference sort 0x"
- + Integer.toHexString(sort));
- }
- CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
- CheckMethodAdapter.checkDesc(desc, false);
- return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
- typePath, desc, visible));
+ CheckClassAdapter.checkAccess(
+ access, Opcodes.ACC_FINAL + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
+ super.visitParameter(name, access);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+ checkVisitEndNotCalled();
+ checkDescriptor(version, descriptor, false);
+ return new CheckAnnotationAdapter(super.visitAnnotation(descriptor, visible));
+ }
+
+ @Override
+ public AnnotationVisitor visitTypeAnnotation(
+ final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+ checkVisitEndNotCalled();
+ int sort = new TypeReference(typeRef).getSort();
+ if (sort != TypeReference.METHOD_TYPE_PARAMETER
+ && sort != TypeReference.METHOD_TYPE_PARAMETER_BOUND
+ && sort != TypeReference.METHOD_RETURN
+ && sort != TypeReference.METHOD_RECEIVER
+ && sort != TypeReference.METHOD_FORMAL_PARAMETER
+ && sort != TypeReference.THROWS) {
+ throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
}
-
- @Override
- public AnnotationVisitor visitAnnotationDefault() {
- checkEndMethod();
- return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false);
+ CheckClassAdapter.checkTypeRef(typeRef);
+ CheckMethodAdapter.checkDescriptor(version, descriptor, false);
+ return new CheckAnnotationAdapter(
+ super.visitTypeAnnotation(typeRef, typePath, descriptor, visible));
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotationDefault() {
+ checkVisitEndNotCalled();
+ return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false);
+ }
+
+ @Override
+ public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
+ checkVisitEndNotCalled();
+ if (visible) {
+ visibleAnnotableParameterCount = parameterCount;
+ } else {
+ invisibleAnnotableParameterCount = parameterCount;
}
-
- @Override
- public AnnotationVisitor visitParameterAnnotation(final int parameter,
- final String desc, final boolean visible) {
- checkEndMethod();
- checkDesc(desc, false);
- return new CheckAnnotationAdapter(super.visitParameterAnnotation(
- parameter, desc, visible));
+ super.visitAnnotableParameterCount(parameterCount, visible);
+ }
+
+ @Override
+ public AnnotationVisitor visitParameterAnnotation(
+ final int parameter, final String descriptor, final boolean visible) {
+ checkVisitEndNotCalled();
+ if ((visible
+ && visibleAnnotableParameterCount > 0
+ && parameter >= visibleAnnotableParameterCount)
+ || (!visible
+ && invisibleAnnotableParameterCount > 0
+ && parameter >= invisibleAnnotableParameterCount)) {
+ throw new IllegalArgumentException("Invalid parameter index");
}
-
- @Override
- public void visitAttribute(final Attribute attr) {
- checkEndMethod();
- if (attr == null) {
- throw new IllegalArgumentException(
- "Invalid attribute (must not be null)");
- }
- super.visitAttribute(attr);
+ checkDescriptor(version, descriptor, false);
+ return new CheckAnnotationAdapter(
+ super.visitParameterAnnotation(parameter, descriptor, visible));
+ }
+
+ @Override
+ public void visitAttribute(final Attribute attribute) {
+ checkVisitEndNotCalled();
+ if (attribute == null) {
+ throw new IllegalArgumentException("Invalid attribute (must not be null)");
}
+ super.visitAttribute(attribute);
+ }
- @Override
- public void visitCode() {
- if ((access & Opcodes.ACC_ABSTRACT) != 0) {
- throw new RuntimeException("Abstract methods cannot have code");
- }
- startCode = true;
- super.visitCode();
+ @Override
+ public void visitCode() {
+ if ((access & Opcodes.ACC_ABSTRACT) != 0) {
+ throw new UnsupportedOperationException("Abstract methods cannot have code");
}
-
- @Override
- public void visitFrame(final int type, final int nLocal,
- final Object[] local, final int nStack, final Object[] stack) {
- if (insnCount == lastFrame) {
- throw new IllegalStateException(
- "At most one frame can be visited at a given code location.");
- }
- lastFrame = insnCount;
- int mLocal;
- int mStack;
- switch (type) {
- case Opcodes.F_NEW:
- case Opcodes.F_FULL:
- mLocal = Integer.MAX_VALUE;
- mStack = Integer.MAX_VALUE;
- break;
-
- case Opcodes.F_SAME:
- mLocal = 0;
- mStack = 0;
- break;
-
- case Opcodes.F_SAME1:
- mLocal = 0;
- mStack = 1;
- break;
-
- case Opcodes.F_APPEND:
- case Opcodes.F_CHOP:
- mLocal = 3;
- mStack = 0;
- break;
-
- default:
- throw new IllegalArgumentException("Invalid frame type " + type);
- }
-
- if (nLocal > mLocal) {
- throw new IllegalArgumentException("Invalid nLocal=" + nLocal
- + " for frame type " + type);
- }
- if (nStack > mStack) {
- throw new IllegalArgumentException("Invalid nStack=" + nStack
- + " for frame type " + type);
- }
-
- if (type != Opcodes.F_CHOP) {
- if (nLocal > 0 && (local == null || local.length < nLocal)) {
- throw new IllegalArgumentException(
- "Array local[] is shorter than nLocal");
- }
- for (int i = 0; i < nLocal; ++i) {
- checkFrameValue(local[i]);
- }
- }
- if (nStack > 0 && (stack == null || stack.length < nStack)) {
- throw new IllegalArgumentException(
- "Array stack[] is shorter than nStack");
- }
- for (int i = 0; i < nStack; ++i) {
- checkFrameValue(stack[i]);
- }
- if (type == Opcodes.F_NEW) {
- ++expandedFrames;
- } else {
- ++compressedFrames;
- }
- if (expandedFrames > 0 && compressedFrames > 0) {
- throw new RuntimeException(
- "Expanded and compressed frames must not be mixed.");
- }
- super.visitFrame(type, nLocal, local, nStack, stack);
- }
-
- @Override
- public void visitInsn(final int opcode) {
- checkStartCode();
- checkEndCode();
- checkOpcode(opcode, 0);
- super.visitInsn(opcode);
- ++insnCount;
- }
-
- @Override
- public void visitIntInsn(final int opcode, final int operand) {
- checkStartCode();
- checkEndCode();
- checkOpcode(opcode, 1);
- switch (opcode) {
- case Opcodes.BIPUSH:
- checkSignedByte(operand, "Invalid operand");
- break;
- case Opcodes.SIPUSH:
- checkSignedShort(operand, "Invalid operand");
- break;
- // case Constants.NEWARRAY:
- default:
- if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) {
- throw new IllegalArgumentException(
- "Invalid operand (must be an array type code T_...): "
- + operand);
- }
- }
- super.visitIntInsn(opcode, operand);
- ++insnCount;
- }
-
- @Override
- public void visitVarInsn(final int opcode, final int var) {
- checkStartCode();
- checkEndCode();
- checkOpcode(opcode, 2);
- checkUnsignedShort(var, "Invalid variable index");
- super.visitVarInsn(opcode, var);
- ++insnCount;
- }
-
- @Override
- public void visitTypeInsn(final int opcode, final String type) {
- checkStartCode();
- checkEndCode();
- checkOpcode(opcode, 3);
- checkInternalName(type, "type");
- if (opcode == Opcodes.NEW && type.charAt(0) == '[') {
- throw new IllegalArgumentException(
- "NEW cannot be used to create arrays: " + type);
- }
- super.visitTypeInsn(opcode, type);
- ++insnCount;
- }
-
- @Override
- public void visitFieldInsn(final int opcode, final String owner,
- final String name, final String desc) {
- checkStartCode();
- checkEndCode();
- checkOpcode(opcode, 4);
- checkInternalName(owner, "owner");
- checkUnqualifiedName(version, name, "name");
- checkDesc(desc, false);
- super.visitFieldInsn(opcode, owner, name, desc);
- ++insnCount;
- }
-
- @Deprecated
- @Override
- public void visitMethodInsn(int opcode, String owner, String name,
- String desc) {
- if (api >= Opcodes.ASM5) {
- super.visitMethodInsn(opcode, owner, name, desc);
- return;
- }
- doVisitMethodInsn(opcode, owner, name, desc,
- opcode == Opcodes.INVOKEINTERFACE);
+ visitCodeCalled = true;
+ super.visitCode();
+ }
+
+ @Override
+ public void visitFrame(
+ final int type,
+ final int numLocal,
+ final Object[] local,
+ final int numStack,
+ final Object[] stack) {
+ if (insnCount == lastFrameInsnIndex) {
+ throw new IllegalStateException("At most one frame can be visited at a given code location.");
}
-
- @Override
- public void visitMethodInsn(int opcode, String owner, String name,
- String desc, boolean itf) {
- if (api < Opcodes.ASM5) {
- super.visitMethodInsn(opcode, owner, name, desc, itf);
- return;
- }
- doVisitMethodInsn(opcode, owner, name, desc, itf);
+ lastFrameInsnIndex = insnCount;
+ int maxNumLocal;
+ int maxNumStack;
+ switch (type) {
+ case Opcodes.F_NEW:
+ case Opcodes.F_FULL:
+ maxNumLocal = Integer.MAX_VALUE;
+ maxNumStack = Integer.MAX_VALUE;
+ break;
+
+ case Opcodes.F_SAME:
+ maxNumLocal = 0;
+ maxNumStack = 0;
+ break;
+
+ case Opcodes.F_SAME1:
+ maxNumLocal = 0;
+ maxNumStack = 1;
+ break;
+
+ case Opcodes.F_APPEND:
+ case Opcodes.F_CHOP:
+ maxNumLocal = 3;
+ maxNumStack = 0;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Invalid frame type " + type);
}
- private void doVisitMethodInsn(int opcode, final String owner,
- final String name, final String desc, final boolean itf) {
- checkStartCode();
- checkEndCode();
- checkOpcode(opcode, 5);
- if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) {
- checkMethodIdentifier(version, name, "name");
- }
- checkInternalName(owner, "owner");
- checkMethodDesc(desc);
- if (opcode == Opcodes.INVOKEVIRTUAL && itf) {
- throw new IllegalArgumentException(
- "INVOKEVIRTUAL can't be used with interfaces");
- }
- if (opcode == Opcodes.INVOKEINTERFACE && !itf) {
- throw new IllegalArgumentException(
- "INVOKEINTERFACE can't be used with classes");
- }
- if (opcode == Opcodes.INVOKESPECIAL && itf
- && (version & 0xFFFF) < Opcodes.V1_8) {
- throw new IllegalArgumentException(
- "INVOKESPECIAL can't be used with interfaces prior to Java 8");
- }
-
- // Calling super.visitMethodInsn requires to call the correct version
- // depending on this.api (otherwise infinite loops can occur). To
- // simplify and to make it easier to automatically remove the backward
- // compatibility code, we inline the code of the overridden method here.
- if (mv != null) {
- mv.visitMethodInsn(opcode, owner, name, desc, itf);
- }
- ++insnCount;
- }
-
- @Override
- public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
- Object... bsmArgs) {
- checkStartCode();
- checkEndCode();
- checkMethodIdentifier(version, name, "name");
- checkMethodDesc(desc);
- if (bsm.getTag() != Opcodes.H_INVOKESTATIC
- && bsm.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
- throw new IllegalArgumentException("invalid handle tag "
- + bsm.getTag());
- }
- for (int i = 0; i < bsmArgs.length; i++) {
- checkLDCConstant(bsmArgs[i]);
- }
- super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
- ++insnCount;
- }
-
- @Override
- public void visitJumpInsn(final int opcode, final Label label) {
- checkStartCode();
- checkEndCode();
- checkOpcode(opcode, 6);
- checkLabel(label, false, "label");
- checkNonDebugLabel(label);
- super.visitJumpInsn(opcode, label);
- usedLabels.add(label);
- ++insnCount;
- }
-
- @Override
- public void visitLabel(final Label label) {
- checkStartCode();
- checkEndCode();
- checkLabel(label, false, "label");
- if (labels.get(label) != null) {
- throw new IllegalArgumentException("Already visited label");
- }
- labels.put(label, insnCount);
- super.visitLabel(label);
- }
-
- @Override
- public void visitLdcInsn(final Object cst) {
- checkStartCode();
- checkEndCode();
- checkLDCConstant(cst);
- super.visitLdcInsn(cst);
- ++insnCount;
- }
-
- @Override
- public void visitIincInsn(final int var, final int increment) {
- checkStartCode();
- checkEndCode();
- checkUnsignedShort(var, "Invalid variable index");
- checkSignedShort(increment, "Invalid increment");
- super.visitIincInsn(var, increment);
- ++insnCount;
- }
-
- @Override
- public void visitTableSwitchInsn(final int min, final int max,
- final Label dflt, final Label... labels) {
- checkStartCode();
- checkEndCode();
- if (max < min) {
- throw new IllegalArgumentException("Max = " + max
- + " must be greater than or equal to min = " + min);
- }
- checkLabel(dflt, false, "default label");
- checkNonDebugLabel(dflt);
- if (labels == null || labels.length != max - min + 1) {
- throw new IllegalArgumentException(
- "There must be max - min + 1 labels");
- }
- for (int i = 0; i < labels.length; ++i) {
- checkLabel(labels[i], false, "label at index " + i);
- checkNonDebugLabel(labels[i]);
- }
- super.visitTableSwitchInsn(min, max, dflt, labels);
- for (int i = 0; i < labels.length; ++i) {
- usedLabels.add(labels[i]);
- }
- ++insnCount;
- }
-
- @Override
- public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
- final Label[] labels) {
- checkEndCode();
- checkStartCode();
- checkLabel(dflt, false, "default label");
- checkNonDebugLabel(dflt);
- if (keys == null || labels == null || keys.length != labels.length) {
- throw new IllegalArgumentException(
- "There must be the same number of keys and labels");
- }
- for (int i = 0; i < labels.length; ++i) {
- checkLabel(labels[i], false, "label at index " + i);
- checkNonDebugLabel(labels[i]);
- }
- super.visitLookupSwitchInsn(dflt, keys, labels);
- usedLabels.add(dflt);
- for (int i = 0; i < labels.length; ++i) {
- usedLabels.add(labels[i]);
- }
- ++insnCount;
- }
-
- @Override
- public void visitMultiANewArrayInsn(final String desc, final int dims) {
- checkStartCode();
- checkEndCode();
- checkDesc(desc, false);
- if (desc.charAt(0) != '[') {
- throw new IllegalArgumentException(
- "Invalid descriptor (must be an array type descriptor): "
- + desc);
- }
- if (dims < 1) {
- throw new IllegalArgumentException(
- "Invalid dimensions (must be greater than 0): " + dims);
- }
- if (dims > desc.lastIndexOf('[') + 1) {
- throw new IllegalArgumentException(
- "Invalid dimensions (must not be greater than dims(desc)): "
- + dims);
- }
- super.visitMultiANewArrayInsn(desc, dims);
- ++insnCount;
- }
-
- @Override
- public AnnotationVisitor visitInsnAnnotation(final int typeRef,
- final TypePath typePath, final String desc, final boolean visible) {
- checkStartCode();
- checkEndCode();
- int sort = typeRef >>> 24;
- if (sort != TypeReference.INSTANCEOF && sort != TypeReference.NEW
- && sort != TypeReference.CONSTRUCTOR_REFERENCE
- && sort != TypeReference.METHOD_REFERENCE
- && sort != TypeReference.CAST
- && sort != TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
- && sort != TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT
- && sort != TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
- && sort != TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT) {
- throw new IllegalArgumentException("Invalid type reference sort 0x"
- + Integer.toHexString(sort));
- }
- CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
- CheckMethodAdapter.checkDesc(desc, false);
- return new CheckAnnotationAdapter(super.visitInsnAnnotation(typeRef,
- typePath, desc, visible));
- }
-
- @Override
- public void visitTryCatchBlock(final Label start, final Label end,
- final Label handler, final String type) {
- checkStartCode();
- checkEndCode();
- checkLabel(start, false, "start label");
- checkLabel(end, false, "end label");
- checkLabel(handler, false, "handler label");
- checkNonDebugLabel(start);
- checkNonDebugLabel(end);
- checkNonDebugLabel(handler);
- if (labels.get(start) != null || labels.get(end) != null
- || labels.get(handler) != null) {
- throw new IllegalStateException(
- "Try catch blocks must be visited before their labels");
- }
- if (type != null) {
- checkInternalName(type, "type");
- }
- super.visitTryCatchBlock(start, end, handler, type);
- handlers.add(start);
- handlers.add(end);
- }
-
- @Override
- public AnnotationVisitor visitTryCatchAnnotation(final int typeRef,
- final TypePath typePath, final String desc, final boolean visible) {
- checkStartCode();
- checkEndCode();
- int sort = typeRef >>> 24;
- if (sort != TypeReference.EXCEPTION_PARAMETER) {
- throw new IllegalArgumentException("Invalid type reference sort 0x"
- + Integer.toHexString(sort));
- }
- CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
- CheckMethodAdapter.checkDesc(desc, false);
- return new CheckAnnotationAdapter(super.visitTryCatchAnnotation(
- typeRef, typePath, desc, visible));
- }
-
- @Override
- public void visitLocalVariable(final String name, final String desc,
- final String signature, final Label start, final Label end,
- final int index) {
- checkStartCode();
- checkEndCode();
- checkUnqualifiedName(version, name, "name");
- checkDesc(desc, false);
- checkLabel(start, true, "start label");
- checkLabel(end, true, "end label");
- checkUnsignedShort(index, "Invalid variable index");
- int s = labels.get(start).intValue();
- int e = labels.get(end).intValue();
- if (e < s) {
- throw new IllegalArgumentException(
- "Invalid start and end labels (end must be greater than start)");
- }
- super.visitLocalVariable(name, desc, signature, start, end, index);
- }
-
- @Override
- public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
- TypePath typePath, Label[] start, Label[] end, int[] index,
- String desc, boolean visible) {
- checkStartCode();
- checkEndCode();
- int sort = typeRef >>> 24;
- if (sort != TypeReference.LOCAL_VARIABLE
- && sort != TypeReference.RESOURCE_VARIABLE) {
- throw new IllegalArgumentException("Invalid type reference sort 0x"
- + Integer.toHexString(sort));
- }
- CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
- checkDesc(desc, false);
- if (start == null || end == null || index == null
- || end.length != start.length || index.length != start.length) {
- throw new IllegalArgumentException(
- "Invalid start, end and index arrays (must be non null and of identical length");
- }
- for (int i = 0; i < start.length; ++i) {
- checkLabel(start[i], true, "start label");
- checkLabel(end[i], true, "end label");
- checkUnsignedShort(index[i], "Invalid variable index");
- int s = labels.get(start[i]).intValue();
- int e = labels.get(end[i]).intValue();
- if (e < s) {
- throw new IllegalArgumentException(
- "Invalid start and end labels (end must be greater than start)");
- }
- }
- return super.visitLocalVariableAnnotation(typeRef, typePath, start,
- end, index, desc, visible);
- }
-
- @Override
- public void visitLineNumber(final int line, final Label start) {
- checkStartCode();
- checkEndCode();
- checkUnsignedShort(line, "Invalid line number");
- checkLabel(start, true, "start label");
- super.visitLineNumber(line, start);
- }
-
- @Override
- public void visitMaxs(final int maxStack, final int maxLocals) {
- checkStartCode();
- checkEndCode();
- endCode = true;
- for (Label l : usedLabels) {
- if (labels.get(l) == null) {
- throw new IllegalStateException("Undefined label used");
- }
- }
- for (int i = 0; i < handlers.size();) {
- Integer start = labels.get(handlers.get(i++));
- Integer end = labels.get(handlers.get(i++));
- if (start == null || end == null) {
- throw new IllegalStateException(
- "Undefined try catch block labels");
- }
- if (end.intValue() <= start.intValue()) {
- throw new IllegalStateException(
- "Emty try catch block handler range");
- }
- }
- checkUnsignedShort(maxStack, "Invalid max stack");
- checkUnsignedShort(maxLocals, "Invalid max locals");
- super.visitMaxs(maxStack, maxLocals);
+ if (numLocal > maxNumLocal) {
+ throw new IllegalArgumentException(
+ "Invalid numLocal=" + numLocal + " for frame type " + type);
}
-
- @Override
- public void visitEnd() {
- checkEndMethod();
- endMethod = true;
- super.visitEnd();
+ if (numStack > maxNumStack) {
+ throw new IllegalArgumentException(
+ "Invalid numStack=" + numStack + " for frame type " + type);
}
- // -------------------------------------------------------------------------
-
- /**
- * Checks that the visitCode method has been called.
- */
- void checkStartCode() {
- if (!startCode) {
- throw new IllegalStateException(
- "Cannot visit instructions before visitCode has been called.");
- }
+ if (type != Opcodes.F_CHOP) {
+ if (numLocal > 0 && (local == null || local.length < numLocal)) {
+ throw new IllegalArgumentException("Array local[] is shorter than numLocal");
+ }
+ for (int i = 0; i < numLocal; ++i) {
+ checkFrameValue(local[i]);
+ }
}
-
- /**
- * Checks that the visitMaxs method has not been called.
- */
- void checkEndCode() {
- if (endCode) {
- throw new IllegalStateException(
- "Cannot visit instructions after visitMaxs has been called.");
- }
+ if (numStack > 0 && (stack == null || stack.length < numStack)) {
+ throw new IllegalArgumentException("Array stack[] is shorter than numStack");
}
-
- /**
- * Checks that the visitEnd method has not been called.
- */
- void checkEndMethod() {
- if (endMethod) {
- throw new IllegalStateException(
- "Cannot visit elements after visitEnd has been called.");
- }
+ for (int i = 0; i < numStack; ++i) {
+ checkFrameValue(stack[i]);
}
-
- /**
- * Checks a stack frame value.
- *
- * @param value
- * the value to be checked.
- */
- void checkFrameValue(final Object value) {
- if (value == Opcodes.TOP || value == Opcodes.INTEGER
- || value == Opcodes.FLOAT || value == Opcodes.LONG
- || value == Opcodes.DOUBLE || value == Opcodes.NULL
- || value == Opcodes.UNINITIALIZED_THIS) {
- return;
- }
- if (value instanceof String) {
- checkInternalName((String) value, "Invalid stack frame value");
- return;
- }
- if (!(value instanceof Label)) {
- throw new IllegalArgumentException("Invalid stack frame value: "
- + value);
- } else {
- usedLabels.add((Label) value);
- }
+ if (type == Opcodes.F_NEW) {
+ ++numExpandedFrames;
+ } else {
+ ++numCompressedFrames;
}
-
- /**
- * Checks that the type of the given opcode is equal to the given type.
- *
- * @param opcode
- * the opcode to be checked.
- * @param type
- * the expected opcode type.
- */
- static void checkOpcode(final int opcode, final int type) {
- if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) {
- throw new IllegalArgumentException("Invalid opcode: " + opcode);
- }
+ if (numExpandedFrames > 0 && numCompressedFrames > 0) {
+ throw new IllegalArgumentException("Expanded and compressed frames must not be mixed.");
}
-
- /**
- * Checks that the given value is a signed byte.
- *
- * @param value
- * the value to be checked.
- * @param msg
- * an message to be used in case of error.
- */
- static void checkSignedByte(final int value, final String msg) {
- if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
- throw new IllegalArgumentException(msg
- + " (must be a signed byte): " + value);
- }
+ super.visitFrame(type, numLocal, local, numStack, stack);
+ }
+
+ @Override
+ public void visitInsn(final int opcode) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkOpcodeMethod(opcode, Method.VISIT_INSN);
+ super.visitInsn(opcode);
+ ++insnCount;
+ }
+
+ @Override
+ public void visitIntInsn(final int opcode, final int operand) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkOpcodeMethod(opcode, Method.VISIT_INT_INSN);
+ switch (opcode) {
+ case Opcodes.BIPUSH:
+ checkSignedByte(operand, "Invalid operand");
+ break;
+ case Opcodes.SIPUSH:
+ checkSignedShort(operand, "Invalid operand");
+ break;
+ case Opcodes.NEWARRAY:
+ if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) {
+ throw new IllegalArgumentException(
+ "Invalid operand (must be an array type code T_...): " + operand);
+ }
+ break;
+ default:
+ throw new AssertionError();
}
-
- /**
- * Checks that the given value is a signed short.
- *
- * @param value
- * the value to be checked.
- * @param msg
- * an message to be used in case of error.
- */
- static void checkSignedShort(final int value, final String msg) {
- if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
- throw new IllegalArgumentException(msg
- + " (must be a signed short): " + value);
- }
+ super.visitIntInsn(opcode, operand);
+ ++insnCount;
+ }
+
+ @Override
+ public void visitVarInsn(final int opcode, final int var) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkOpcodeMethod(opcode, Method.VISIT_VAR_INSN);
+ checkUnsignedShort(var, INVALID_LOCAL_VARIABLE_INDEX);
+ super.visitVarInsn(opcode, var);
+ ++insnCount;
+ }
+
+ @Override
+ public void visitTypeInsn(final int opcode, final String type) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkOpcodeMethod(opcode, Method.VISIT_TYPE_INSN);
+ checkInternalName(version, type, "type");
+ if (opcode == Opcodes.NEW && type.charAt(0) == '[') {
+ throw new IllegalArgumentException("NEW cannot be used to create arrays: " + type);
}
-
- /**
- * Checks that the given value is an unsigned short.
- *
- * @param value
- * the value to be checked.
- * @param msg
- * an message to be used in case of error.
- */
- static void checkUnsignedShort(final int value, final String msg) {
- if (value < 0 || value > 65535) {
- throw new IllegalArgumentException(msg
- + " (must be an unsigned short): " + value);
- }
+ super.visitTypeInsn(opcode, type);
+ ++insnCount;
+ }
+
+ @Override
+ public void visitFieldInsn(
+ final int opcode, final String owner, final String name, final String descriptor) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkOpcodeMethod(opcode, Method.VISIT_FIELD_INSN);
+ checkInternalName(version, owner, "owner");
+ checkUnqualifiedName(version, name, "name");
+ checkDescriptor(version, descriptor, false);
+ super.visitFieldInsn(opcode, owner, name, descriptor);
+ ++insnCount;
+ }
+
+ /**
+ * 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;
}
-
- /**
- * Checks that the given value is an {@link Integer}, a{@link Float}, a
- * {@link Long}, a {@link Double} or a {@link String}.
- *
- * @param cst
- * the value to be checked.
- */
- static void checkConstant(final Object cst) {
- if (!(cst instanceof Integer) && !(cst instanceof Float)
- && !(cst instanceof Long) && !(cst instanceof Double)
- && !(cst instanceof String)) {
- throw new IllegalArgumentException("Invalid constant: " + cst);
- }
+ doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
+ }
+
+ @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;
}
-
- void checkLDCConstant(final Object cst) {
- if (cst instanceof Type) {
- int s = ((Type) cst).getSort();
- if (s != Type.OBJECT && s != Type.ARRAY && s != Type.METHOD) {
- throw new IllegalArgumentException("Illegal LDC constant value");
- }
- if (s != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) {
- throw new IllegalArgumentException(
- "ldc of a constant class requires at least version 1.5");
- }
- if (s == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) {
- throw new IllegalArgumentException(
- "ldc of a method type requires at least version 1.7");
- }
- } else if (cst instanceof Handle) {
- if ((version & 0xFFFF) < Opcodes.V1_7) {
- throw new IllegalArgumentException(
- "ldc of a handle requires at least version 1.7");
- }
- int tag = ((Handle) cst).getTag();
- if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) {
- throw new IllegalArgumentException("invalid handle tag " + tag);
- }
- } else {
- checkConstant(cst);
- }
+ doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+
+ private void doVisitMethodInsn(
+ final int opcode,
+ final String owner,
+ final String name,
+ final String descriptor,
+ final boolean isInterface) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkOpcodeMethod(opcode, Method.VISIT_METHOD_INSN);
+ if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) {
+ checkMethodIdentifier(version, name, "name");
}
-
- /**
- * Checks that the given string is a valid unqualified name.
- *
- * @param version
- * the class version.
- * @param name
- * the string to be checked.
- * @param msg
- * a message to be used in case of error.
- */
- static void checkUnqualifiedName(int version, final String name,
- final String msg) {
- if ((version & 0xFFFF) < Opcodes.V1_5) {
- checkIdentifier(name, msg);
- } else {
- for (int i = 0; i < name.length(); ++i) {
- if (".;[/".indexOf(name.charAt(i)) != -1) {
- throw new IllegalArgumentException("Invalid " + msg
- + " (must be a valid unqualified name): " + name);
- }
- }
- }
+ checkInternalName(version, owner, "owner");
+ checkMethodDescriptor(version, descriptor);
+ if (opcode == Opcodes.INVOKEVIRTUAL && isInterface) {
+ throw new IllegalArgumentException("INVOKEVIRTUAL can't be used with interfaces");
}
-
- /**
- * Checks that the given string is a valid Java identifier.
- *
- * @param name
- * the string to be checked.
- * @param msg
- * a message to be used in case of error.
- */
- static void checkIdentifier(final String name, final String msg) {
- checkIdentifier(name, 0, -1, msg);
- }
-
- /**
- * Checks that the given substring is a valid Java identifier.
- *
- * @param name
- * the string to be checked.
- * @param start
- * index of the first character of the identifier (inclusive).
- * @param end
- * index of the last character of the identifier (exclusive). -1
- * is equivalent to <tt>name.length()</tt> if name is not
- * <tt>null</tt>.
- * @param msg
- * a message to be used in case of error.
- */
- static void checkIdentifier(final String name, final int start,
- final int end, final String msg) {
- if (name == null || (end == -1 ? name.length() <= start : end <= start)) {
- throw new IllegalArgumentException("Invalid " + msg
- + " (must not be null or empty)");
- }
- if (!Character.isJavaIdentifierStart(name.charAt(start))) {
- throw new IllegalArgumentException("Invalid " + msg
- + " (must be a valid Java identifier): " + name);
- }
- int max = end == -1 ? name.length() : end;
- for (int i = start + 1; i < max; ++i) {
- if (!Character.isJavaIdentifierPart(name.charAt(i))) {
- throw new IllegalArgumentException("Invalid " + msg
- + " (must be a valid Java identifier): " + name);
- }
- }
+ if (opcode == Opcodes.INVOKEINTERFACE && !isInterface) {
+ throw new IllegalArgumentException("INVOKEINTERFACE can't be used with classes");
}
-
- /**
- * Checks that the given string is a valid Java identifier.
- *
- * @param version
- * the class version.
- * @param name
- * the string to be checked.
- * @param msg
- * a message to be used in case of error.
- */
- static void checkMethodIdentifier(int version, final String name,
- final String msg) {
- if (name == null || name.length() == 0) {
- throw new IllegalArgumentException("Invalid " + msg
- + " (must not be null or empty)");
- }
- if ((version & 0xFFFF) >= Opcodes.V1_5) {
- for (int i = 0; i < name.length(); ++i) {
- if (".;[/<>".indexOf(name.charAt(i)) != -1) {
- throw new IllegalArgumentException("Invalid " + msg
- + " (must be a valid unqualified name): " + name);
- }
- }
- return;
- }
- if (!Character.isJavaIdentifierStart(name.charAt(0))) {
- throw new IllegalArgumentException(
- "Invalid "
- + msg
- + " (must be a '<init>', '<clinit>' or a valid Java identifier): "
- + name);
- }
- for (int i = 1; i < name.length(); ++i) {
- if (!Character.isJavaIdentifierPart(name.charAt(i))) {
- throw new IllegalArgumentException(
- "Invalid "
- + msg
- + " (must be '<init>' or '<clinit>' or a valid Java identifier): "
- + name);
- }
- }
+ if (opcode == Opcodes.INVOKESPECIAL && isInterface && (version & 0xFFFF) < Opcodes.V1_8) {
+ throw new IllegalArgumentException(
+ "INVOKESPECIAL can't be used with interfaces prior to Java 8");
}
- /**
- * Checks that the given string is a valid internal class name.
- *
- * @param name
- * the string to be checked.
- * @param msg
- * a message to be used in case of error.
- */
- static void checkInternalName(final String name, final String msg) {
- if (name == null || name.length() == 0) {
- throw new IllegalArgumentException("Invalid " + msg
- + " (must not be null or empty)");
- }
- if (name.charAt(0) == '[') {
- checkDesc(name, false);
- } else {
- checkInternalName(name, 0, -1, msg);
- }
+ // Calling super.visitMethodInsn requires to call the correct version depending on this.api
+ // (otherwise infinite loops can occur). To simplify and to make it easier to automatically
+ // remove the backward compatibility code, we inline the code of the overridden method here.
+ if (mv != null) {
+ mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
-
- /**
- * Checks that the given substring is a valid internal class name.
- *
- * @param name
- * the string to be checked.
- * @param start
- * index of the first character of the identifier (inclusive).
- * @param end
- * index of the last character of the identifier (exclusive). -1
- * is equivalent to <tt>name.length()</tt> if name is not
- * <tt>null</tt>.
- * @param msg
- * a message to be used in case of error.
- */
- static void checkInternalName(final String name, final int start,
- final int end, final String msg) {
- int max = end == -1 ? name.length() : end;
- try {
- int begin = start;
- int slash;
- do {
- slash = name.indexOf('/', begin + 1);
- if (slash == -1 || slash > max) {
- slash = max;
- }
- checkIdentifier(name, begin, slash, null);
- begin = slash + 1;
- } while (slash != max);
- } catch (IllegalArgumentException unused) {
- throw new IllegalArgumentException(
- "Invalid "
- + msg
- + " (must be a fully qualified class name in internal form): "
- + name);
- }
+ ++insnCount;
+ }
+
+ @Override
+ public void visitInvokeDynamicInsn(
+ final String name,
+ final String descriptor,
+ final Handle bootstrapMethodHandle,
+ final Object... bootstrapMethodArguments) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkMethodIdentifier(version, name, "name");
+ checkMethodDescriptor(version, descriptor);
+ if (bootstrapMethodHandle.getTag() != Opcodes.H_INVOKESTATIC
+ && bootstrapMethodHandle.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
+ throw new IllegalArgumentException("invalid handle tag " + bootstrapMethodHandle.getTag());
}
-
- /**
- * Checks that the given string is a valid type descriptor.
- *
- * @param desc
- * the string to be checked.
- * @param canBeVoid
- * <tt>true</tt> if <tt>V</tt> can be considered valid.
- */
- static void checkDesc(final String desc, final boolean canBeVoid) {
- int end = checkDesc(desc, 0, canBeVoid);
- if (end != desc.length()) {
- throw new IllegalArgumentException("Invalid descriptor: " + desc);
- }
+ for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
+ checkLdcConstant(bootstrapMethodArgument);
}
-
- /**
- * Checks that a the given substring is a valid type descriptor.
- *
- * @param desc
- * the string to be checked.
- * @param start
- * index of the first character of the identifier (inclusive).
- * @param canBeVoid
- * <tt>true</tt> if <tt>V</tt> can be considered valid.
- * @return the index of the last character of the type decriptor, plus one.
- */
- static int checkDesc(final String desc, final int start,
- final boolean canBeVoid) {
- if (desc == null || start >= desc.length()) {
- throw new IllegalArgumentException(
- "Invalid type descriptor (must not be null or empty)");
- }
- int index;
- switch (desc.charAt(start)) {
- case 'V':
- if (canBeVoid) {
- return start + 1;
- } else {
- throw new IllegalArgumentException("Invalid descriptor: "
- + desc);
- }
- case 'Z':
- case 'C':
- case 'B':
- case 'S':
- case 'I':
- case 'F':
- case 'J':
- case 'D':
- return start + 1;
- case '[':
- index = start + 1;
- while (index < desc.length() && desc.charAt(index) == '[') {
- ++index;
- }
- if (index < desc.length()) {
- return checkDesc(desc, index, false);
- } else {
- throw new IllegalArgumentException("Invalid descriptor: "
- + desc);
- }
- case 'L':
- index = desc.indexOf(';', start);
- if (index == -1 || index - start < 2) {
- throw new IllegalArgumentException("Invalid descriptor: "
- + desc);
- }
- try {
- checkInternalName(desc, start + 1, index, null);
- } catch (IllegalArgumentException unused) {
- throw new IllegalArgumentException("Invalid descriptor: "
- + desc);
- }
- return index + 1;
- default:
- throw new IllegalArgumentException("Invalid descriptor: " + desc);
- }
+ super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+ ++insnCount;
+ }
+
+ @Override
+ public void visitJumpInsn(final int opcode, final Label label) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkOpcodeMethod(opcode, Method.VISIT_JUMP_INSN);
+ checkLabel(label, false, "label");
+ super.visitJumpInsn(opcode, label);
+ referencedLabels.add(label);
+ ++insnCount;
+ }
+
+ @Override
+ public void visitLabel(final Label label) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkLabel(label, false, "label");
+ if (labelInsnIndices.get(label) != null) {
+ throw new IllegalArgumentException("Already visited label");
+ }
+ labelInsnIndices.put(label, insnCount);
+ super.visitLabel(label);
+ }
+
+ @Override
+ public void visitLdcInsn(final Object value) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkLdcConstant(value);
+ super.visitLdcInsn(value);
+ ++insnCount;
+ }
+
+ @Override
+ public void visitIincInsn(final int var, final int increment) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkUnsignedShort(var, INVALID_LOCAL_VARIABLE_INDEX);
+ checkSignedShort(increment, "Invalid increment");
+ super.visitIincInsn(var, increment);
+ ++insnCount;
+ }
+
+ @Override
+ public void visitTableSwitchInsn(
+ final int min, final int max, final Label dflt, final Label... labels) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ if (max < min) {
+ throw new IllegalArgumentException(
+ "Max = " + max + " must be greater than or equal to min = " + min);
+ }
+ checkLabel(dflt, false, "default label");
+ if (labels == null || labels.length != max - min + 1) {
+ throw new IllegalArgumentException("There must be max - min + 1 labels");
+ }
+ for (int i = 0; i < labels.length; ++i) {
+ checkLabel(labels[i], false, "label at index " + i);
+ }
+ super.visitTableSwitchInsn(min, max, dflt, labels);
+ for (Label label : labels) {
+ referencedLabels.add(label);
+ }
+ ++insnCount;
+ }
+
+ @Override
+ public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
+ checkVisitMaxsNotCalled();
+ checkVisitCodeCalled();
+ checkLabel(dflt, false, "default label");
+ if (keys == null || labels == null || keys.length != labels.length) {
+ throw new IllegalArgumentException("There must be the same number of keys and labels");
+ }
+ for (int i = 0; i < labels.length; ++i) {
+ checkLabel(labels[i], false, "label at index " + i);
+ }
+ super.visitLookupSwitchInsn(dflt, keys, labels);
+ referencedLabels.add(dflt);
+ for (Label label : labels) {
+ referencedLabels.add(label);
+ }
+ ++insnCount;
+ }
+
+ @Override
+ public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkDescriptor(version, descriptor, false);
+ if (descriptor.charAt(0) != '[') {
+ throw new IllegalArgumentException(
+ "Invalid descriptor (must be an array type descriptor): " + descriptor);
+ }
+ if (numDimensions < 1) {
+ throw new IllegalArgumentException(
+ "Invalid dimensions (must be greater than 0): " + numDimensions);
}
+ if (numDimensions > descriptor.lastIndexOf('[') + 1) {
+ throw new IllegalArgumentException(
+ "Invalid dimensions (must not be greater than numDimensions(descriptor)): "
+ + numDimensions);
+ }
+ super.visitMultiANewArrayInsn(descriptor, numDimensions);
+ ++insnCount;
+ }
+
+ @Override
+ public AnnotationVisitor visitInsnAnnotation(
+ final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ int sort = new TypeReference(typeRef).getSort();
+ if (sort != TypeReference.INSTANCEOF
+ && sort != TypeReference.NEW
+ && sort != TypeReference.CONSTRUCTOR_REFERENCE
+ && sort != TypeReference.METHOD_REFERENCE
+ && sort != TypeReference.CAST
+ && sort != TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ && sort != TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT
+ && sort != TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ && sort != TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT) {
+ throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRef(typeRef);
+ CheckMethodAdapter.checkDescriptor(version, descriptor, false);
+ return new CheckAnnotationAdapter(
+ super.visitInsnAnnotation(typeRef, typePath, descriptor, visible));
+ }
+
+ @Override
+ public void visitTryCatchBlock(
+ final Label start, final Label end, final Label handler, final String type) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkLabel(start, false, START_LABEL);
+ checkLabel(end, false, END_LABEL);
+ checkLabel(handler, false, "handler label");
+ if (labelInsnIndices.get(start) != null
+ || labelInsnIndices.get(end) != null
+ || labelInsnIndices.get(handler) != null) {
+ throw new IllegalStateException("Try catch blocks must be visited before their labels");
+ }
+ if (type != null) {
+ checkInternalName(version, type, "type");
+ }
+ super.visitTryCatchBlock(start, end, handler, type);
+ handlers.add(start);
+ handlers.add(end);
+ }
+
+ @Override
+ public AnnotationVisitor visitTryCatchAnnotation(
+ final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ int sort = new TypeReference(typeRef).getSort();
+ if (sort != TypeReference.EXCEPTION_PARAMETER) {
+ throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRef(typeRef);
+ CheckMethodAdapter.checkDescriptor(version, descriptor, false);
+ return new CheckAnnotationAdapter(
+ super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible));
+ }
+
+ @Override
+ public void visitLocalVariable(
+ final String name,
+ final String descriptor,
+ final String signature,
+ final Label start,
+ final Label end,
+ final int index) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkUnqualifiedName(version, name, "name");
+ checkDescriptor(version, descriptor, false);
+ checkLabel(start, true, START_LABEL);
+ checkLabel(end, true, END_LABEL);
+ checkUnsignedShort(index, INVALID_LOCAL_VARIABLE_INDEX);
+ int startInsnIndex = labelInsnIndices.get(start).intValue();
+ int endInsnIndex = labelInsnIndices.get(end).intValue();
+ if (endInsnIndex < startInsnIndex) {
+ throw new IllegalArgumentException(
+ "Invalid start and end labels (end must be greater than start)");
+ }
+ super.visitLocalVariable(name, descriptor, signature, start, end, index);
+ }
+
+ @Override
+ public AnnotationVisitor visitLocalVariableAnnotation(
+ final int typeRef,
+ final TypePath typePath,
+ final Label[] start,
+ final Label[] end,
+ final int[] index,
+ final String descriptor,
+ final boolean visible) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ int sort = new TypeReference(typeRef).getSort();
+ if (sort != TypeReference.LOCAL_VARIABLE && sort != TypeReference.RESOURCE_VARIABLE) {
+ throw new IllegalArgumentException(INVALID_TYPE_REFERENCE + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRef(typeRef);
+ checkDescriptor(version, descriptor, false);
+ if (start == null
+ || end == null
+ || index == null
+ || end.length != start.length
+ || index.length != start.length) {
+ throw new IllegalArgumentException(
+ "Invalid start, end and index arrays (must be non null and of identical length");
+ }
+ for (int i = 0; i < start.length; ++i) {
+ checkLabel(start[i], true, START_LABEL);
+ checkLabel(end[i], true, END_LABEL);
+ checkUnsignedShort(index[i], INVALID_LOCAL_VARIABLE_INDEX);
+ int startInsnIndex = labelInsnIndices.get(start[i]).intValue();
+ int endInsnIndex = labelInsnIndices.get(end[i]).intValue();
+ if (endInsnIndex < startInsnIndex) {
+ throw new IllegalArgumentException(
+ "Invalid start and end labels (end must be greater than start)");
+ }
+ }
+ return super.visitLocalVariableAnnotation(
+ typeRef, typePath, start, end, index, descriptor, visible);
+ }
+
+ @Override
+ public void visitLineNumber(final int line, final Label start) {
+ checkVisitCodeCalled();
+ checkVisitMaxsNotCalled();
+ checkUnsignedShort(line, "Invalid line number");
+ checkL
<TRUNCATED>