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 }