diff options
Diffstat (limited to 'src/compiler/scala/tools/asm/tree/MethodNode.java')
-rw-r--r-- | src/compiler/scala/tools/asm/tree/MethodNode.java | 645 |
1 files changed, 645 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/asm/tree/MethodNode.java b/src/compiler/scala/tools/asm/tree/MethodNode.java new file mode 100644 index 0000000000..70ec39e058 --- /dev/null +++ b/src/compiler/scala/tools/asm/tree/MethodNode.java @@ -0,0 +1,645 @@ +/*** + * 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 scala.tools.asm.tree; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import scala.tools.asm.AnnotationVisitor; +import scala.tools.asm.Attribute; +import scala.tools.asm.ClassVisitor; +import scala.tools.asm.Handle; +import scala.tools.asm.Label; +import scala.tools.asm.MethodVisitor; +import scala.tools.asm.Opcodes; +import scala.tools.asm.Type; + +/** + * A node that represents a method. + * + * @author Eric Bruneton + */ +public class MethodNode extends MethodVisitor { + + /** + * The method's access flags (see {@link Opcodes}). This field also + * indicates if the method is synthetic and/or deprecated. + */ + public int access; + + /** + * The method's name. + */ + public String name; + + /** + * The method's descriptor (see {@link Type}). + */ + public String desc; + + /** + * The method's signature. May be <tt>null</tt>. + */ + public String signature; + + /** + * The internal names of the method's exception classes (see + * {@link Type#getInternalName() getInternalName}). This list is a list of + * {@link String} objects. + */ + public List<String> exceptions; + + /** + * The runtime visible annotations of this method. This list is a list of + * {@link AnnotationNode} objects. May be <tt>null</tt>. + * + * @associates org.objectweb.asm.tree.AnnotationNode + * @label visible + */ + public List<AnnotationNode> visibleAnnotations; + + /** + * The runtime invisible annotations of this method. This list is a list of + * {@link AnnotationNode} objects. May be <tt>null</tt>. + * + * @associates org.objectweb.asm.tree.AnnotationNode + * @label invisible + */ + public List<AnnotationNode> invisibleAnnotations; + + /** + * The non standard attributes of this method. This list is a list of + * {@link Attribute} objects. May be <tt>null</tt>. + * + * @associates org.objectweb.asm.Attribute + */ + public List<Attribute> attrs; + + /** + * The default value of this annotation interface method. This field must be + * a {@link Byte}, {@link Boolean}, {@link Character}, {@link Short}, + * {@link Integer}, {@link Long}, {@link Float}, {@link Double}, + * {@link String} or {@link Type}, or an two elements String array (for + * enumeration values), a {@link AnnotationNode}, or a {@link List} of + * values of one of the preceding types. May be <tt>null</tt>. + */ + public Object annotationDefault; + + /** + * The runtime visible parameter annotations of this method. These lists are + * lists of {@link AnnotationNode} objects. May be <tt>null</tt>. + * + * @associates org.objectweb.asm.tree.AnnotationNode + * @label invisible parameters + */ + public List<AnnotationNode>[] visibleParameterAnnotations; + + /** + * The runtime invisible parameter annotations of this method. These lists + * are lists of {@link AnnotationNode} objects. May be <tt>null</tt>. + * + * @associates org.objectweb.asm.tree.AnnotationNode + * @label visible parameters + */ + public List<AnnotationNode>[] invisibleParameterAnnotations; + + /** + * The instructions of this method. This list is a list of + * {@link AbstractInsnNode} objects. + * + * @associates org.objectweb.asm.tree.AbstractInsnNode + * @label instructions + */ + public InsnList instructions; + + /** + * The try catch blocks of this method. This list is a list of + * {@link TryCatchBlockNode} objects. + * + * @associates org.objectweb.asm.tree.TryCatchBlockNode + */ + public List<TryCatchBlockNode> tryCatchBlocks; + + /** + * The maximum stack size of this method. + */ + public int maxStack; + + /** + * The maximum number of local variables of this method. + */ + public int maxLocals; + + /** + * The local variables of this method. This list is a list of + * {@link LocalVariableNode} objects. May be <tt>null</tt> + * + * @associates org.objectweb.asm.tree.LocalVariableNode + */ + public List<LocalVariableNode> localVariables; + + /** + * If the accept method has been called on this object. + */ + private boolean visited; + + /** + * 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); + } + + /** + * Constructs an uninitialized {@link MethodNode}. + * + * @param api the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + */ + public MethodNode(final int api) { + super(api); + this.instructions = new InsnList(); + } + + /** + * 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 + * 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 + * <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); + } + + /** + * 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 + * 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 + * <tt>null</tt>. + */ + 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 + : exceptions.length); + boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0; + if (!isAbstract) { + this.localVariables = new ArrayList<LocalVariableNode>(5); + } + this.tryCatchBlocks = new ArrayList<TryCatchBlockNode>(); + if (exceptions != null) { + this.exceptions.addAll(Arrays.asList(exceptions)); + } + this.instructions = new InsnList(); + } + + // ------------------------------------------------------------------------ + // Implementation of the MethodVisitor abstract class + // ------------------------------------------------------------------------ + + @Override + public AnnotationVisitor visitAnnotationDefault() { + return new AnnotationNode(new ArrayList<Object>(0) { + @Override + public boolean add(final Object o) { + annotationDefault = o; + return super.add(o); + } + }); + } + + @Override + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + AnnotationNode an = new AnnotationNode(desc); + if (visible) { + if (visibleAnnotations == null) { + visibleAnnotations = new ArrayList<AnnotationNode>(1); + } + visibleAnnotations.add(an); + } else { + if (invisibleAnnotations == null) { + invisibleAnnotations = new ArrayList<AnnotationNode>(1); + } + invisibleAnnotations.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]; + } + if (visibleParameterAnnotations[parameter] == null) { + 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]; + } + if (invisibleParameterAnnotations[parameter] == null) { + invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1); + } + invisibleParameterAnnotations[parameter].add(an); + } + return an; + } + + @Override + public void visitAttribute(final Attribute attr) { + if (attrs == null) { + attrs = new ArrayList<Attribute>(1); + } + attrs.add(attr); + } + + @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 + : getLabelNodes(stack))); + } + + @Override + public void visitInsn(final int opcode) { + instructions.add(new InsnNode(opcode)); + } + + @Override + public void visitIntInsn(final int opcode, final int operand) { + instructions.add(new IntInsnNode(opcode, operand)); + } + + @Override + public void visitVarInsn(final int opcode, final int var) { + instructions.add(new VarInsnNode(opcode, var)); + } + + @Override + 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) + { + instructions.add(new FieldInsnNode(opcode, owner, name, desc)); + } + + @Override + 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) + { + instructions.add(new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs)); + } + + @Override + public void visitJumpInsn(final int opcode, final Label label) { + instructions.add(new JumpInsnNode(opcode, getLabelNode(label))); + } + + @Override + public void visitLabel(final Label label) { + instructions.add(getLabelNode(label)); + } + + @Override + public void visitLdcInsn(final Object cst) { + instructions.add(new LdcInsnNode(cst)); + } + + @Override + 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), + getLabelNodes(labels))); + } + + @Override + 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) + { + tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start), + 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)); + } + + @Override + public void visitLineNumber(final int line, final Label start) { + instructions.add(new LineNumberNode(line, getLabelNode(start))); + } + + @Override + public void visitMaxs(final int maxStack, final int maxLocals) { + this.maxStack = maxStack; + this.maxLocals = maxLocals; + } + + @Override + public void visitEnd() { + } + + /** + * 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. + * @return the LabelNode corresponding to l. + */ + protected LabelNode getLabelNode(final Label l) { + if (!(l.info instanceof LabelNode)) { + l.info = new LabelNode(l); + } + return (LabelNode) l.info; + } + + private LabelNode[] getLabelNodes(final Label[] l) { + LabelNode[] nodes = new LabelNode[l.length]; + for (int i = 0; i < l.length; ++i) { + nodes[i] = getLabelNode(l[i]); + } + return nodes; + } + + private Object[] getLabelNodes(final Object[] objs) { + Object[] nodes = new Object[objs.length]; + for (int i = 0; i < objs.length; ++i) { + Object o = objs[i]; + if (o instanceof Label) { + o = getLabelNode((Label) o); + } + nodes[i] = o; + } + return nodes; + } + + // ------------------------------------------------------------------------ + // Accept method + // ------------------------------------------------------------------------ + + /** + * 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}. + */ + public void check(final int api) { + // nothing to do + } + + /** + * Makes the given class visitor visit this method. + * + * @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, + exceptions); + if (mv != null) { + accept(mv); + } + } + + /** + * Makes the given method visitor visit this method. + * + * @param mv a method visitor. + */ + public void accept(final MethodVisitor mv) { + // visits the method attributes + int i, j, n; + if (annotationDefault != null) { + AnnotationVisitor av = mv.visitAnnotationDefault(); + AnnotationNode.accept(av, null, annotationDefault); + if (av != null) { + av.visitEnd(); + } + } + n = visibleAnnotations == null ? 0 : visibleAnnotations.size(); + for (i = 0; i < n; ++i) { + AnnotationNode an = visibleAnnotations.get(i); + an.accept(mv.visitAnnotation(an.desc, true)); + } + 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 + : visibleParameterAnnotations.length; + for (i = 0; i < n; ++i) { + List<?> l = visibleParameterAnnotations[i]; + if (l == null) { + continue; + } + 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 + : invisibleParameterAnnotations.length; + for (i = 0; i < n; ++i) { + List<?> l = invisibleParameterAnnotations[i]; + if (l == null) { + continue; + } + for (j = 0; j < l.size(); ++j) { + AnnotationNode an = (AnnotationNode) l.get(j); + an.accept(mv.visitParameterAnnotation(i, an.desc, false)); + } + } + if (visited) { + instructions.resetLabels(); + } + n = attrs == null ? 0 : attrs.size(); + for (i = 0; i < n; ++i) { + mv.visitAttribute(attrs.get(i)); + } + // visits the method's code + 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).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 maxs + mv.visitMaxs(maxStack, maxLocals); + visited = true; + } + mv.visitEnd(); + } +} |