src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodNode.java
Print this page
@@ -28,11 +28,10 @@
* However, the following notice accompanied the original version of this
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
- * Copyright (c) 2011 Google
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -69,10 +68,12 @@
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
+import jdk.internal.org.objectweb.asm.TypePath;
+import jdk.internal.org.objectweb.asm.TypeReference;
/**
* A node that represents a method.
*
* @author Eric Bruneton
@@ -106,10 +107,15 @@
* {@link String} objects.
*/
public List<String> exceptions;
/**
+ * The method parameter info (access flags and name)
+ */
+ public List<ParameterNode> parameters;
+
+ /**
* The runtime visible annotations of this method. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.AnnotationNode
* @label visible
@@ -124,10 +130,28 @@
* @label invisible
*/
public List<AnnotationNode> invisibleAnnotations;
/**
+ * The runtime visible type annotations of this method. This list is a list
+ * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
+ * @label visible
+ */
+ public List<TypeAnnotationNode> visibleTypeAnnotations;
+
+ /**
+ * The runtime invisible type annotations of this method. This list is a
+ * list of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
+ * @label invisible
+ */
+ public List<TypeAnnotationNode> invisibleTypeAnnotations;
+
+ /**
* The non standard attributes of this method. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.Attribute
*/
@@ -195,10 +219,26 @@
* @associates jdk.internal.org.objectweb.asm.tree.LocalVariableNode
*/
public List<LocalVariableNode> localVariables;
/**
+ * The visible local variable annotations of this method. This list is a
+ * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
+ *
+ * @associates jdk.internal.org.objectweb.asm.tree.LocalVariableAnnotationNode
+ */
+ public List<LocalVariableAnnotationNode> visibleLocalVariableAnnotations;
+
+ /**
+ * The invisible local variable annotations of this method. This list is a
+ * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
+ *
+ * @associates jdk.internal.org.objectweb.asm.tree.LocalVariableAnnotationNode
+ */
+ public List<LocalVariableAnnotationNode> invisibleLocalVariableAnnotations;
+
+ /**
* If the accept method has been called on this object.
*/
private boolean visited;
/**
@@ -205,18 +245,19 @@
* Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not
* use this constructor</i>. Instead, they must use the
* {@link #MethodNode(int)} version.
*/
public MethodNode() {
- this(Opcodes.ASM4);
+ this(Opcodes.ASM5);
}
/**
* Constructs an uninitialized {@link MethodNode}.
*
- * @param api the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * @param api
+ * the ASM API version implemented by this visitor. Must be one
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public MethodNode(final int api) {
super(api);
this.instructions = new InsnList();
}
@@ -224,60 +265,59 @@
/**
* Constructs a new {@link MethodNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #MethodNode(int, int, String, String, String, String[])} version.
*
- * @param access the method's access flags (see {@link Opcodes}). This
+ * @param access
+ * the method's access flags (see {@link Opcodes}). This
* parameter also indicates if the method is synthetic and/or
* deprecated.
- * @param name the method's name.
- * @param desc the method's descriptor (see {@link Type}).
- * @param signature the method's signature. May be <tt>null</tt>.
- * @param exceptions the internal names of the method's exception classes
- * (see {@link Type#getInternalName() getInternalName}). May be
+ * @param name
+ * the method's name.
+ * @param desc
+ * the method's descriptor (see {@link Type}).
+ * @param signature
+ * the method's signature. May be <tt>null</tt>.
+ * @param exceptions
+ * the internal names of the method's exception classes (see
+ * {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
*/
- public MethodNode(
- final int access,
- final String name,
- final String desc,
- final String signature,
- final String[] exceptions)
- {
- this(Opcodes.ASM4, access, name, desc, signature, exceptions);
+ public MethodNode(final int access, final String name, final String desc,
+ final String signature, final String[] exceptions) {
+ this(Opcodes.ASM5, access, name, desc, signature, exceptions);
}
/**
* Constructs a new {@link MethodNode}.
*
- * @param api the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
- * @param access the method's access flags (see {@link Opcodes}). This
+ * @param api
+ * the ASM API version implemented by this visitor. Must be one
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
+ * @param access
+ * the method's access flags (see {@link Opcodes}). This
* parameter also indicates if the method is synthetic and/or
* deprecated.
- * @param name the method's name.
- * @param desc the method's descriptor (see {@link Type}).
- * @param signature the method's signature. May be <tt>null</tt>.
- * @param exceptions the internal names of the method's exception classes
- * (see {@link Type#getInternalName() getInternalName}). May be
+ * @param name
+ * the method's name.
+ * @param desc
+ * the method's descriptor (see {@link Type}).
+ * @param signature
+ * the method's signature. May be <tt>null</tt>.
+ * @param exceptions
+ * the internal names of the method's exception classes (see
+ * {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
*/
- public MethodNode(
- final int api,
- final int access,
- final String name,
- final String desc,
- final String signature,
- final String[] exceptions)
- {
+ public MethodNode(final int api, final int access, final String name,
+ final String desc, final String signature, final String[] exceptions) {
super(api);
this.access = access;
this.name = name;
this.desc = desc;
this.signature = signature;
- this.exceptions = new ArrayList<String>(exceptions == null
- ? 0
+ this.exceptions = new ArrayList<String>(exceptions == null ? 0
: exceptions.length);
boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0;
if (!isAbstract) {
this.localVariables = new ArrayList<LocalVariableNode>(5);
}
@@ -291,10 +331,18 @@
// ------------------------------------------------------------------------
// Implementation of the MethodVisitor abstract class
// ------------------------------------------------------------------------
@Override
+ public void visitParameter(String name, int access) {
+ if (parameters == null) {
+ parameters = new ArrayList<ParameterNode>(5);
+ }
+ parameters.add(new ParameterNode(name, access));
+ }
+
+ @Override
public AnnotationVisitor visitAnnotationDefault() {
return new AnnotationNode(new ArrayList<Object>(0) {
@Override
public boolean add(final Object o) {
annotationDefault = o;
@@ -302,14 +350,12 @@
}
});
}
@Override
- public AnnotationVisitor visitAnnotation(
- final String desc,
- final boolean visible)
- {
+ public AnnotationVisitor visitAnnotation(final String desc,
+ final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
if (visible) {
if (visibleAnnotations == null) {
visibleAnnotations = new ArrayList<AnnotationNode>(1);
}
@@ -322,32 +368,49 @@
}
return an;
}
@Override
- public AnnotationVisitor visitParameterAnnotation(
- final int parameter,
- final String desc,
- final boolean visible)
- {
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (visibleTypeAnnotations == null) {
+ visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ visibleTypeAnnotations.add(an);
+ } else {
+ if (invisibleTypeAnnotations == null) {
+ invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
+ public AnnotationVisitor visitParameterAnnotation(final int parameter,
+ final String desc, final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
if (visible) {
if (visibleParameterAnnotations == null) {
int params = Type.getArgumentTypes(this.desc).length;
- visibleParameterAnnotations = (List<AnnotationNode>[])new List<?>[params];
+ visibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
}
if (visibleParameterAnnotations[parameter] == null) {
- visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
+ visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(
+ 1);
}
visibleParameterAnnotations[parameter].add(an);
} else {
if (invisibleParameterAnnotations == null) {
int params = Type.getArgumentTypes(this.desc).length;
- invisibleParameterAnnotations = (List<AnnotationNode>[])new List<?>[params];
+ invisibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
}
if (invisibleParameterAnnotations[parameter] == null) {
- invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
+ invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(
+ 1);
}
invisibleParameterAnnotations[parameter].add(an);
}
return an;
}
@@ -363,21 +426,14 @@
@Override
public void visitCode() {
}
@Override
- public void visitFrame(
- final int type,
- final int nLocal,
- final Object[] local,
- final int nStack,
- final Object[] stack)
- {
- instructions.add(new FrameNode(type, nLocal, local == null
- ? null
- : getLabelNodes(local), nStack, stack == null
- ? null
+ public void visitFrame(final int type, final int nLocal,
+ final Object[] local, final int nStack, final Object[] stack) {
+ instructions.add(new FrameNode(type, nLocal, local == null ? null
+ : getLabelNodes(local), nStack, stack == null ? null
: getLabelNodes(stack)));
}
@Override
public void visitInsn(final int opcode) {
@@ -398,36 +454,24 @@
public void visitTypeInsn(final int opcode, final String type) {
instructions.add(new TypeInsnNode(opcode, type));
}
@Override
- public void visitFieldInsn(
- final int opcode,
- final String owner,
- final String name,
- final String desc)
- {
+ public void visitFieldInsn(final int opcode, final String owner,
+ final String name, final String desc) {
instructions.add(new FieldInsnNode(opcode, owner, name, desc));
}
@Override
- public void visitMethodInsn(
- final int opcode,
- final String owner,
- final String name,
- final String desc)
- {
+ public void visitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc) {
instructions.add(new MethodInsnNode(opcode, owner, name, desc));
}
@Override
- public void visitInvokeDynamicInsn(
- String name,
- String desc,
- Handle bsm,
- Object... bsmArgs)
- {
+ public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
+ Object... bsmArgs) {
instructions.add(new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs));
}
@Override
public void visitJumpInsn(final int opcode, final Label label) {
@@ -448,69 +492,115 @@
public void visitIincInsn(final int var, final int increment) {
instructions.add(new IincInsnNode(var, increment));
}
@Override
- public void visitTableSwitchInsn(
- final int min,
- final int max,
- final Label dflt,
- final Label... labels)
- {
- instructions.add(new TableSwitchInsnNode(min,
- max,
- getLabelNode(dflt),
+ public void visitTableSwitchInsn(final int min, final int max,
+ final Label dflt, final Label... labels) {
+ instructions.add(new TableSwitchInsnNode(min, max, getLabelNode(dflt),
getLabelNodes(labels)));
}
@Override
- public void visitLookupSwitchInsn(
- final Label dflt,
- final int[] keys,
- final Label[] labels)
- {
- instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt),
- keys,
+ public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
+ final Label[] labels) {
+ instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), keys,
getLabelNodes(labels)));
}
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
instructions.add(new MultiANewArrayInsnNode(desc, dims));
}
@Override
- public void visitTryCatchBlock(
- final Label start,
- final Label end,
- final Label handler,
- final String type)
- {
+ public AnnotationVisitor visitInsnAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ // Finds the last real instruction, i.e. the instruction targeted by
+ // this annotation.
+ AbstractInsnNode insn = instructions.getLast();
+ while (insn.getOpcode() == -1) {
+ insn = insn.getPrevious();
+ }
+ // Adds the annotation to this instruction.
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (insn.visibleTypeAnnotations == null) {
+ insn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
+ }
+ insn.visibleTypeAnnotations.add(an);
+ } else {
+ if (insn.invisibleTypeAnnotations == null) {
+ insn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
+ }
+ insn.invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
+ public void visitTryCatchBlock(final Label start, final Label end,
+ final Label handler, final String type) {
tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start),
- getLabelNode(end),
- getLabelNode(handler),
- type));
+ getLabelNode(end), getLabelNode(handler), type));
}
@Override
- public void visitLocalVariable(
- final String name,
- final String desc,
- final String signature,
- final Label start,
- final Label end,
- final int index)
- {
- localVariables.add(new LocalVariableNode(name,
- desc,
- signature,
- getLabelNode(start),
- getLabelNode(end),
- index));
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ TryCatchBlockNode tcb = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (tcb.visibleTypeAnnotations == null) {
+ tcb.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
}
+ tcb.visibleTypeAnnotations.add(an);
+ } else {
+ if (tcb.invisibleTypeAnnotations == null) {
+ tcb.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
+ }
+ tcb.invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
@Override
+ public void visitLocalVariable(final String name, final String desc,
+ final String signature, final Label start, final Label end,
+ final int index) {
+ localVariables.add(new LocalVariableNode(name, desc, signature,
+ getLabelNode(start), getLabelNode(end), index));
+ }
+
+ @Override
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+ TypePath typePath, Label[] start, Label[] end, int[] index,
+ String desc, boolean visible) {
+ LocalVariableAnnotationNode an = new LocalVariableAnnotationNode(
+ typeRef, typePath, getLabelNodes(start), getLabelNodes(end),
+ index, desc);
+ if (visible) {
+ if (visibleLocalVariableAnnotations == null) {
+ visibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
+ 1);
+ }
+ visibleLocalVariableAnnotations.add(an);
+ } else {
+ if (invisibleLocalVariableAnnotations == null) {
+ invisibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
+ 1);
+ }
+ invisibleLocalVariableAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
instructions.add(new LineNumberNode(line, getLabelNode(start)));
}
@Override
@@ -527,16 +617,17 @@
* Returns the LabelNode corresponding to the given Label. Creates a new
* LabelNode if necessary. The default implementation of this method uses
* the {@link Label#info} field to store associations between labels and
* label nodes.
*
- * @param l a Label.
+ * @param l
+ * a Label.
* @return the LabelNode corresponding to l.
*/
protected LabelNode getLabelNode(final Label l) {
if (!(l.info instanceof LabelNode)) {
- l.info = new LabelNode(l);
+ l.info = new LabelNode();
}
return (LabelNode) l.info;
}
private LabelNode[] getLabelNodes(final Label[] l) {
@@ -567,42 +658,90 @@
* Checks that this method node is compatible with the given ASM API
* version. This methods checks that this node, and all its nodes
* recursively, do not contain elements that were introduced in more recent
* versions of the ASM API than the given version.
*
- * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}.
+ * @param api
+ * an ASM API version. Must be one of {@link Opcodes#ASM4} or
+ * {@link Opcodes#ASM5}.
*/
public void check(final int api) {
- // nothing to do
+ if (api == Opcodes.ASM4) {
+ if (visibleTypeAnnotations != null
+ && visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
}
+ if (invisibleTypeAnnotations != null
+ && invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ int n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
+ for (int i = 0; i < n; ++i) {
+ TryCatchBlockNode tcb = tryCatchBlocks.get(i);
+ if (tcb.visibleTypeAnnotations != null
+ && tcb.visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (tcb.invisibleTypeAnnotations != null
+ && tcb.invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ }
+ for (int i = 0; i < instructions.size(); ++i) {
+ AbstractInsnNode insn = instructions.get(i);
+ if (insn.visibleTypeAnnotations != null
+ && insn.visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (insn.invisibleTypeAnnotations != null
+ && insn.invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ }
+ if (visibleLocalVariableAnnotations != null
+ && visibleLocalVariableAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (invisibleLocalVariableAnnotations != null
+ && invisibleLocalVariableAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ }
+ }
+
/**
* Makes the given class visitor visit this method.
*
- * @param cv a class visitor.
+ * @param cv
+ * a class visitor.
*/
public void accept(final ClassVisitor cv) {
String[] exceptions = new String[this.exceptions.size()];
this.exceptions.toArray(exceptions);
- MethodVisitor mv = cv.visitMethod(access,
- name,
- desc,
- signature,
+ MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
exceptions);
if (mv != null) {
accept(mv);
}
}
/**
* Makes the given method visitor visit this method.
*
- * @param mv a method visitor.
+ * @param mv
+ * a method visitor.
*/
public void accept(final MethodVisitor mv) {
- // visits the method attributes
+ // visits the method parameters
int i, j, n;
+ n = parameters == null ? 0 : parameters.size();
+ for (i = 0; i < n; i++) {
+ ParameterNode parameter = parameters.get(i);
+ mv.visitParameter(parameter.name, parameter.access);
+ }
+ // visits the method attributes
if (annotationDefault != null) {
AnnotationVisitor av = mv.visitAnnotationDefault();
AnnotationNode.accept(av, null, annotationDefault);
if (av != null) {
av.visitEnd();
@@ -616,12 +755,24 @@
n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(mv.visitAnnotation(an.desc, false));
}
- n = visibleParameterAnnotations == null
- ? 0
+ n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = visibleTypeAnnotations.get(i);
+ an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ true));
+ }
+ n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
+ .size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
+ an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ false));
+ }
+ n = visibleParameterAnnotations == null ? 0
: visibleParameterAnnotations.length;
for (i = 0; i < n; ++i) {
List<?> l = visibleParameterAnnotations[i];
if (l == null) {
continue;
@@ -629,12 +780,11 @@
for (j = 0; j < l.size(); ++j) {
AnnotationNode an = (AnnotationNode) l.get(j);
an.accept(mv.visitParameterAnnotation(i, an.desc, true));
}
}
- n = invisibleParameterAnnotations == null
- ? 0
+ n = invisibleParameterAnnotations == null ? 0
: invisibleParameterAnnotations.length;
for (i = 0; i < n; ++i) {
List<?> l = invisibleParameterAnnotations[i];
if (l == null) {
continue;
@@ -655,19 +805,31 @@
if (instructions.size() > 0) {
mv.visitCode();
// visits try catch blocks
n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
for (i = 0; i < n; ++i) {
+ tryCatchBlocks.get(i).updateIndex(i);
tryCatchBlocks.get(i).accept(mv);
}
// visits instructions
instructions.accept(mv);
// visits local variables
n = localVariables == null ? 0 : localVariables.size();
for (i = 0; i < n; ++i) {
localVariables.get(i).accept(mv);
}
+ // visits local variable annotations
+ n = visibleLocalVariableAnnotations == null ? 0
+ : visibleLocalVariableAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ visibleLocalVariableAnnotations.get(i).accept(mv, true);
+ }
+ n = invisibleLocalVariableAnnotations == null ? 0
+ : invisibleLocalVariableAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ invisibleLocalVariableAnnotations.get(i).accept(mv, false);
+ }
// visits maxs
mv.visitMaxs(maxStack, maxLocals);
visited = true;
}
mv.visitEnd();