1 /***
   2  * ASM: a very small and fast Java bytecode manipulation framework
   3  * Copyright (c) 2000-2011 INRIA, France Telecom
   4  * Copyright (c) 2011 Google
   5  * All rights reserved.
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  * 2. Redistributions in binary form must reproduce the above copyright
  13  *    notice, this list of conditions and the following disclaimer in the
  14  *    documentation and/or other materials provided with the distribution.
  15  * 3. Neither the name of the copyright holders nor the names of its
  16  *    contributors may be used to endorse or promote products derived from
  17  *    this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  29  * THE POSSIBILITY OF SUCH DAMAGE.
  30  */
  31 package jdk.internal.org.objectweb.asm.tree;
  32 
  33 import java.util.ArrayList;
  34 import java.util.Arrays;
  35 import java.util.List;
  36 
  37 import jdk.internal.org.objectweb.asm.AnnotationVisitor;
  38 import jdk.internal.org.objectweb.asm.Attribute;
  39 import jdk.internal.org.objectweb.asm.ClassVisitor;
  40 import jdk.internal.org.objectweb.asm.Handle;
  41 import jdk.internal.org.objectweb.asm.Label;
  42 import jdk.internal.org.objectweb.asm.MethodVisitor;
  43 import jdk.internal.org.objectweb.asm.Opcodes;
  44 import jdk.internal.org.objectweb.asm.Type;
  45 
  46 /**
  47  * A node that represents a method.
  48  *
  49  * @author Eric Bruneton
  50  */
  51 public class MethodNode extends MethodVisitor {
  52 
  53     /**
  54      * The method's access flags (see {@link Opcodes}). This field also
  55      * indicates if the method is synthetic and/or deprecated.
  56      */
  57     public int access;
  58 
  59     /**
  60      * The method's name.
  61      */
  62     public String name;
  63 
  64     /**
  65      * The method's descriptor (see {@link Type}).
  66      */
  67     public String desc;
  68 
  69     /**
  70      * The method's signature. May be <tt>null</tt>.
  71      */
  72     public String signature;
  73 
  74     /**
  75      * The internal names of the method's exception classes (see
  76      * {@link Type#getInternalName() getInternalName}). This list is a list of
  77      * {@link String} objects.
  78      */
  79     public List<String> exceptions;
  80 
  81     /**
  82      * The runtime visible annotations of this method. This list is a list of
  83      * {@link AnnotationNode} objects. May be <tt>null</tt>.
  84      *
  85      * @associates jdk.internal.org.objectweb.asm.tree.AnnotationNode
  86      * @label visible
  87      */
  88     public List<AnnotationNode> visibleAnnotations;
  89 
  90     /**
  91      * The runtime invisible annotations of this method. This list is a list of
  92      * {@link AnnotationNode} objects. May be <tt>null</tt>.
  93      *
  94      * @associates jdk.internal.org.objectweb.asm.tree.AnnotationNode
  95      * @label invisible
  96      */
  97     public List<AnnotationNode> invisibleAnnotations;
  98 
  99     /**
 100      * The non standard attributes of this method. This list is a list of
 101      * {@link Attribute} objects. May be <tt>null</tt>.
 102      *
 103      * @associates jdk.internal.org.objectweb.asm.Attribute
 104      */
 105     public List<Attribute> attrs;
 106 
 107     /**
 108      * The default value of this annotation interface method. This field must be
 109      * a {@link Byte}, {@link Boolean}, {@link Character}, {@link Short},
 110      * {@link Integer}, {@link Long}, {@link Float}, {@link Double},
 111      * {@link String} or {@link Type}, or an two elements String array (for
 112      * enumeration values), a {@link AnnotationNode}, or a {@link List} of
 113      * values of one of the preceding types. May be <tt>null</tt>.
 114      */
 115     public Object annotationDefault;
 116 
 117     /**
 118      * The runtime visible parameter annotations of this method. These lists are
 119      * lists of {@link AnnotationNode} objects. May be <tt>null</tt>.
 120      *
 121      * @associates jdk.internal.org.objectweb.asm.tree.AnnotationNode
 122      * @label invisible parameters
 123      */
 124     public List<AnnotationNode>[] visibleParameterAnnotations;
 125 
 126     /**
 127      * The runtime invisible parameter annotations of this method. These lists
 128      * are lists of {@link AnnotationNode} objects. May be <tt>null</tt>.
 129      *
 130      * @associates jdk.internal.org.objectweb.asm.tree.AnnotationNode
 131      * @label visible parameters
 132      */
 133     public List<AnnotationNode>[] invisibleParameterAnnotations;
 134 
 135     /**
 136      * The instructions of this method. This list is a list of
 137      * {@link AbstractInsnNode} objects.
 138      *
 139      * @associates jdk.internal.org.objectweb.asm.tree.AbstractInsnNode
 140      * @label instructions
 141      */
 142     public InsnList instructions;
 143 
 144     /**
 145      * The try catch blocks of this method. This list is a list of
 146      * {@link TryCatchBlockNode} objects.
 147      *
 148      * @associates jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode
 149      */
 150     public List<TryCatchBlockNode> tryCatchBlocks;
 151 
 152     /**
 153      * The maximum stack size of this method.
 154      */
 155     public int maxStack;
 156 
 157     /**
 158      * The maximum number of local variables of this method.
 159      */
 160     public int maxLocals;
 161 
 162     /**
 163      * The local variables of this method. This list is a list of
 164      * {@link LocalVariableNode} objects. May be <tt>null</tt>
 165      *
 166      * @associates jdk.internal.org.objectweb.asm.tree.LocalVariableNode
 167      */
 168     public List<LocalVariableNode> localVariables;
 169 
 170     /**
 171      * If the accept method has been called on this object.
 172      */
 173     private boolean visited;
 174 
 175     /**
 176      * Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not
 177      * use this constructor</i>. Instead, they must use the
 178      * {@link #MethodNode(int)} version.
 179      */
 180     public MethodNode() {
 181         this(Opcodes.ASM4);
 182     }
 183 
 184     /**
 185      * Constructs an uninitialized {@link MethodNode}.
 186      *
 187      * @param api the ASM API version implemented by this visitor. Must be one
 188      *        of {@link Opcodes#ASM4}.
 189      */
 190     public MethodNode(final int api) {
 191         super(api);
 192         this.instructions = new InsnList();
 193     }
 194 
 195     /**
 196      * Constructs a new {@link MethodNode}. <i>Subclasses must not use this
 197      * constructor</i>. Instead, they must use the
 198      * {@link #MethodNode(int, int, String, String, String, String[])} version.
 199      *
 200      * @param access the method's access flags (see {@link Opcodes}). This
 201      *        parameter also indicates if the method is synthetic and/or
 202      *        deprecated.
 203      * @param name the method's name.
 204      * @param desc the method's descriptor (see {@link Type}).
 205      * @param signature the method's signature. May be <tt>null</tt>.
 206      * @param exceptions the internal names of the method's exception classes
 207      *        (see {@link Type#getInternalName() getInternalName}). May be
 208      *        <tt>null</tt>.
 209      */
 210     public MethodNode(
 211         final int access,
 212         final String name,
 213         final String desc,
 214         final String signature,
 215         final String[] exceptions)
 216     {
 217         this(Opcodes.ASM4, access, name, desc, signature, exceptions);
 218     }
 219 
 220     /**
 221      * Constructs a new {@link MethodNode}.
 222      *
 223      * @param api the ASM API version implemented by this visitor. Must be one
 224      *        of {@link Opcodes#ASM4}.
 225      * @param access the method's access flags (see {@link Opcodes}). This
 226      *        parameter also indicates if the method is synthetic and/or
 227      *        deprecated.
 228      * @param name the method's name.
 229      * @param desc the method's descriptor (see {@link Type}).
 230      * @param signature the method's signature. May be <tt>null</tt>.
 231      * @param exceptions the internal names of the method's exception classes
 232      *        (see {@link Type#getInternalName() getInternalName}). May be
 233      *        <tt>null</tt>.
 234      */
 235     public MethodNode(
 236         final int api,
 237         final int access,
 238         final String name,
 239         final String desc,
 240         final String signature,
 241         final String[] exceptions)
 242     {
 243         super(api);
 244         this.access = access;
 245         this.name = name;
 246         this.desc = desc;
 247         this.signature = signature;
 248         this.exceptions = new ArrayList<String>(exceptions == null
 249                 ? 0
 250                 : exceptions.length);
 251         boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0;
 252         if (!isAbstract) {
 253             this.localVariables = new ArrayList<LocalVariableNode>(5);
 254         }
 255         this.tryCatchBlocks = new ArrayList<TryCatchBlockNode>();
 256         if (exceptions != null) {
 257             this.exceptions.addAll(Arrays.asList(exceptions));
 258         }
 259         this.instructions = new InsnList();
 260     }
 261 
 262     // ------------------------------------------------------------------------
 263     // Implementation of the MethodVisitor abstract class
 264     // ------------------------------------------------------------------------
 265 
 266     @Override
 267     public AnnotationVisitor visitAnnotationDefault() {
 268         return new AnnotationNode(new ArrayList<Object>(0) {
 269             @Override
 270             public boolean add(final Object o) {
 271                 annotationDefault = o;
 272                 return super.add(o);
 273             }
 274         });
 275     }
 276 
 277     @Override
 278     public AnnotationVisitor visitAnnotation(
 279         final String desc,
 280         final boolean visible)
 281     {
 282         AnnotationNode an = new AnnotationNode(desc);
 283         if (visible) {
 284             if (visibleAnnotations == null) {
 285                 visibleAnnotations = new ArrayList<AnnotationNode>(1);
 286             }
 287             visibleAnnotations.add(an);
 288         } else {
 289             if (invisibleAnnotations == null) {
 290                 invisibleAnnotations = new ArrayList<AnnotationNode>(1);
 291             }
 292             invisibleAnnotations.add(an);
 293         }
 294         return an;
 295     }
 296 
 297     @Override
 298     public AnnotationVisitor visitParameterAnnotation(
 299         final int parameter,
 300         final String desc,
 301         final boolean visible)
 302     {
 303         AnnotationNode an = new AnnotationNode(desc);
 304         if (visible) {
 305             if (visibleParameterAnnotations == null) {
 306                 int params = Type.getArgumentTypes(this.desc).length;
 307                 visibleParameterAnnotations = (List<AnnotationNode>[])new List<?>[params];
 308             }
 309             if (visibleParameterAnnotations[parameter] == null) {
 310                 visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
 311             }
 312             visibleParameterAnnotations[parameter].add(an);
 313         } else {
 314             if (invisibleParameterAnnotations == null) {
 315                 int params = Type.getArgumentTypes(this.desc).length;
 316                 invisibleParameterAnnotations = (List<AnnotationNode>[])new List<?>[params];
 317             }
 318             if (invisibleParameterAnnotations[parameter] == null) {
 319                 invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
 320             }
 321             invisibleParameterAnnotations[parameter].add(an);
 322         }
 323         return an;
 324     }
 325 
 326     @Override
 327     public void visitAttribute(final Attribute attr) {
 328         if (attrs == null) {
 329             attrs = new ArrayList<Attribute>(1);
 330         }
 331         attrs.add(attr);
 332     }
 333 
 334     @Override
 335     public void visitCode() {
 336     }
 337 
 338     @Override
 339     public void visitFrame(
 340         final int type,
 341         final int nLocal,
 342         final Object[] local,
 343         final int nStack,
 344         final Object[] stack)
 345     {
 346         instructions.add(new FrameNode(type, nLocal, local == null
 347                 ? null
 348                 : getLabelNodes(local), nStack, stack == null
 349                 ? null
 350                 : getLabelNodes(stack)));
 351     }
 352 
 353     @Override
 354     public void visitInsn(final int opcode) {
 355         instructions.add(new InsnNode(opcode));
 356     }
 357 
 358     @Override
 359     public void visitIntInsn(final int opcode, final int operand) {
 360         instructions.add(new IntInsnNode(opcode, operand));
 361     }
 362 
 363     @Override
 364     public void visitVarInsn(final int opcode, final int var) {
 365         instructions.add(new VarInsnNode(opcode, var));
 366     }
 367 
 368     @Override
 369     public void visitTypeInsn(final int opcode, final String type) {
 370         instructions.add(new TypeInsnNode(opcode, type));
 371     }
 372 
 373     @Override
 374     public void visitFieldInsn(
 375         final int opcode,
 376         final String owner,
 377         final String name,
 378         final String desc)
 379     {
 380         instructions.add(new FieldInsnNode(opcode, owner, name, desc));
 381     }
 382 
 383     @Override
 384     public void visitMethodInsn(
 385         final int opcode,
 386         final String owner,
 387         final String name,
 388         final String desc)
 389     {
 390         instructions.add(new MethodInsnNode(opcode, owner, name, desc));
 391     }
 392 
 393     @Override
 394     public void visitInvokeDynamicInsn(
 395         String name,
 396         String desc,
 397         Handle bsm,
 398         Object... bsmArgs)
 399     {
 400         instructions.add(new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs));
 401     }
 402 
 403     @Override
 404     public void visitJumpInsn(final int opcode, final Label label) {
 405         instructions.add(new JumpInsnNode(opcode, getLabelNode(label)));
 406     }
 407 
 408     @Override
 409     public void visitLabel(final Label label) {
 410         instructions.add(getLabelNode(label));
 411     }
 412 
 413     @Override
 414     public void visitLdcInsn(final Object cst) {
 415         instructions.add(new LdcInsnNode(cst));
 416     }
 417 
 418     @Override
 419     public void visitIincInsn(final int var, final int increment) {
 420         instructions.add(new IincInsnNode(var, increment));
 421     }
 422 
 423     @Override
 424     public void visitTableSwitchInsn(
 425         final int min,
 426         final int max,
 427         final Label dflt,
 428         final Label... labels)
 429     {
 430         instructions.add(new TableSwitchInsnNode(min,
 431                 max,
 432                 getLabelNode(dflt),
 433                 getLabelNodes(labels)));
 434     }
 435 
 436     @Override
 437     public void visitLookupSwitchInsn(
 438         final Label dflt,
 439         final int[] keys,
 440         final Label[] labels)
 441     {
 442         instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt),
 443                 keys,
 444                 getLabelNodes(labels)));
 445     }
 446 
 447     @Override
 448     public void visitMultiANewArrayInsn(final String desc, final int dims) {
 449         instructions.add(new MultiANewArrayInsnNode(desc, dims));
 450     }
 451 
 452     @Override
 453     public void visitTryCatchBlock(
 454         final Label start,
 455         final Label end,
 456         final Label handler,
 457         final String type)
 458     {
 459         tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start),
 460                 getLabelNode(end),
 461                 getLabelNode(handler),
 462                 type));
 463     }
 464 
 465     @Override
 466     public void visitLocalVariable(
 467         final String name,
 468         final String desc,
 469         final String signature,
 470         final Label start,
 471         final Label end,
 472         final int index)
 473     {
 474         localVariables.add(new LocalVariableNode(name,
 475                 desc,
 476                 signature,
 477                 getLabelNode(start),
 478                 getLabelNode(end),
 479                 index));
 480     }
 481 
 482     @Override
 483     public void visitLineNumber(final int line, final Label start) {
 484         instructions.add(new LineNumberNode(line, getLabelNode(start)));
 485     }
 486 
 487     @Override
 488     public void visitMaxs(final int maxStack, final int maxLocals) {
 489         this.maxStack = maxStack;
 490         this.maxLocals = maxLocals;
 491     }
 492 
 493     @Override
 494     public void visitEnd() {
 495     }
 496 
 497     /**
 498      * Returns the LabelNode corresponding to the given Label. Creates a new
 499      * LabelNode if necessary. The default implementation of this method uses
 500      * the {@link Label#info} field to store associations between labels and
 501      * label nodes.
 502      *
 503      * @param l a Label.
 504      * @return the LabelNode corresponding to l.
 505      */
 506     protected LabelNode getLabelNode(final Label l) {
 507         if (!(l.info instanceof LabelNode)) {
 508             l.info = new LabelNode(l);
 509         }
 510         return (LabelNode) l.info;
 511     }
 512 
 513     private LabelNode[] getLabelNodes(final Label[] l) {
 514         LabelNode[] nodes = new LabelNode[l.length];
 515         for (int i = 0; i < l.length; ++i) {
 516             nodes[i] = getLabelNode(l[i]);
 517         }
 518         return nodes;
 519     }
 520 
 521     private Object[] getLabelNodes(final Object[] objs) {
 522         Object[] nodes = new Object[objs.length];
 523         for (int i = 0; i < objs.length; ++i) {
 524             Object o = objs[i];
 525             if (o instanceof Label) {
 526                 o = getLabelNode((Label) o);
 527             }
 528             nodes[i] = o;
 529         }
 530         return nodes;
 531     }
 532 
 533     // ------------------------------------------------------------------------
 534     // Accept method
 535     // ------------------------------------------------------------------------
 536 
 537     /**
 538      * Checks that this method node is compatible with the given ASM API
 539      * version. This methods checks that this node, and all its nodes
 540      * recursively, do not contain elements that were introduced in more recent
 541      * versions of the ASM API than the given version.
 542      *
 543      * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}.
 544      */
 545     public void check(final int api) {
 546         // nothing to do
 547     }
 548 
 549     /**
 550      * Makes the given class visitor visit this method.
 551      *
 552      * @param cv a class visitor.
 553      */
 554     public void accept(final ClassVisitor cv) {
 555         String[] exceptions = new String[this.exceptions.size()];
 556         this.exceptions.toArray(exceptions);
 557         MethodVisitor mv = cv.visitMethod(access,
 558                 name,
 559                 desc,
 560                 signature,
 561                 exceptions);
 562         if (mv != null) {
 563             accept(mv);
 564         }
 565     }
 566 
 567     /**
 568      * Makes the given method visitor visit this method.
 569      *
 570      * @param mv a method visitor.
 571      */
 572     public void accept(final MethodVisitor mv) {
 573         // visits the method attributes
 574         int i, j, n;
 575         if (annotationDefault != null) {
 576             AnnotationVisitor av = mv.visitAnnotationDefault();
 577             AnnotationNode.accept(av, null, annotationDefault);
 578             if (av != null) {
 579                 av.visitEnd();
 580             }
 581         }
 582         n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
 583         for (i = 0; i < n; ++i) {
 584             AnnotationNode an = visibleAnnotations.get(i);
 585             an.accept(mv.visitAnnotation(an.desc, true));
 586         }
 587         n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
 588         for (i = 0; i < n; ++i) {
 589             AnnotationNode an = invisibleAnnotations.get(i);
 590             an.accept(mv.visitAnnotation(an.desc, false));
 591         }
 592         n = visibleParameterAnnotations == null
 593                 ? 0
 594                 : visibleParameterAnnotations.length;
 595         for (i = 0; i < n; ++i) {
 596             List<?> l = visibleParameterAnnotations[i];
 597             if (l == null) {
 598                 continue;
 599             }
 600             for (j = 0; j < l.size(); ++j) {
 601                 AnnotationNode an = (AnnotationNode) l.get(j);
 602                 an.accept(mv.visitParameterAnnotation(i, an.desc, true));
 603             }
 604         }
 605         n = invisibleParameterAnnotations == null
 606                 ? 0
 607                 : invisibleParameterAnnotations.length;
 608         for (i = 0; i < n; ++i) {
 609             List<?> l = invisibleParameterAnnotations[i];
 610             if (l == null) {
 611                 continue;
 612             }
 613             for (j = 0; j < l.size(); ++j) {
 614                 AnnotationNode an = (AnnotationNode) l.get(j);
 615                 an.accept(mv.visitParameterAnnotation(i, an.desc, false));
 616             }
 617         }
 618         if (visited) {
 619             instructions.resetLabels();
 620         }
 621         n = attrs == null ? 0 : attrs.size();
 622         for (i = 0; i < n; ++i) {
 623             mv.visitAttribute(attrs.get(i));
 624         }
 625         // visits the method's code
 626         if (instructions.size() > 0) {
 627             mv.visitCode();
 628             // visits try catch blocks
 629             n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
 630             for (i = 0; i < n; ++i) {
 631                 tryCatchBlocks.get(i).accept(mv);
 632             }
 633             // visits instructions
 634             instructions.accept(mv);
 635             // visits local variables
 636             n = localVariables == null ? 0 : localVariables.size();
 637             for (i = 0; i < n; ++i) {
 638                 localVariables.get(i).accept(mv);
 639             }
 640             // visits maxs
 641             mv.visitMaxs(maxStack, maxLocals);
 642             visited = true;
 643         }
 644         mv.visitEnd();
 645     }
 646 }