• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // ASM: a very small and fast Java bytecode manipulation framework
2 // Copyright (c) 2000-2011 INRIA, France Telecom
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 // 1. Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in the
12 //    documentation and/or other materials provided with the distribution.
13 // 3. Neither the name of the copyright holders nor the names of its
14 //    contributors may be used to endorse or promote products derived from
15 //    this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 // THE POSSIBILITY OF SUCH DAMAGE.
28 package org.objectweb.asm.tree;
29 
30 import java.util.ArrayList;
31 import java.util.List;
32 import org.objectweb.asm.AnnotationVisitor;
33 import org.objectweb.asm.Attribute;
34 import org.objectweb.asm.ClassVisitor;
35 import org.objectweb.asm.ConstantDynamic;
36 import org.objectweb.asm.Handle;
37 import org.objectweb.asm.Label;
38 import org.objectweb.asm.MethodVisitor;
39 import org.objectweb.asm.Opcodes;
40 import org.objectweb.asm.Type;
41 import org.objectweb.asm.TypePath;
42 
43 /**
44  * A node that represents a method.
45  *
46  * @author Eric Bruneton
47  */
48 public class MethodNode extends MethodVisitor {
49 
50   /**
51    * The method's access flags (see {@link Opcodes}). This field also indicates if the method is
52    * synthetic and/or deprecated.
53    */
54   public int access;
55 
56   /** The method's name. */
57   public String name;
58 
59   /** The method's descriptor (see {@link Type}). */
60   public String desc;
61 
62   /** The method's signature. May be {@literal null}. */
63   public String signature;
64 
65   /** The internal names of the method's exception classes (see {@link Type#getInternalName()}). */
66   public List<String> exceptions;
67 
68   /** The method parameter info (access flags and name). */
69   public List<ParameterNode> parameters;
70 
71   /** The runtime visible annotations of this method. May be {@literal null}. */
72   public List<AnnotationNode> visibleAnnotations;
73 
74   /** The runtime invisible annotations of this method. May be {@literal null}. */
75   public List<AnnotationNode> invisibleAnnotations;
76 
77   /** The runtime visible type annotations of this method. May be {@literal null}. */
78   public List<TypeAnnotationNode> visibleTypeAnnotations;
79 
80   /** The runtime invisible type annotations of this method. May be {@literal null}. */
81   public List<TypeAnnotationNode> invisibleTypeAnnotations;
82 
83   /** The non standard attributes of this method. May be {@literal null}. */
84   public List<Attribute> attrs;
85 
86   /**
87    * The default value of this annotation interface method. This field must be a {@link Byte},
88    * {@link Boolean}, {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link
89    * Float}, {@link Double}, {@link String} or {@link Type}, or an two elements String array (for
90    * enumeration values), a {@link AnnotationNode}, or a {@link List} of values of one of the
91    * preceding types. May be {@literal null}.
92    */
93   public Object annotationDefault;
94 
95   /**
96    * The number of method parameters than can have runtime visible annotations. This number must be
97    * less or equal than the number of parameter types in the method descriptor (the default value 0
98    * indicates that all the parameters described in the method descriptor can have annotations). It
99    * can be strictly less when a method has synthetic parameters and when these parameters are
100    * ignored when computing parameter indices for the purpose of parameter annotations (see
101    * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
102    */
103   public int visibleAnnotableParameterCount;
104 
105   /**
106    * The runtime visible parameter annotations of this method. These lists are lists of {@link
107    * AnnotationNode} objects. May be {@literal null}.
108    */
109   public List<AnnotationNode>[] visibleParameterAnnotations;
110 
111   /**
112    * The number of method parameters than can have runtime invisible annotations. This number must
113    * be less or equal than the number of parameter types in the method descriptor (the default value
114    * 0 indicates that all the parameters described in the method descriptor can have annotations).
115    * It can be strictly less when a method has synthetic parameters and when these parameters are
116    * ignored when computing parameter indices for the purpose of parameter annotations (see
117    * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18).
118    */
119   public int invisibleAnnotableParameterCount;
120 
121   /**
122    * The runtime invisible parameter annotations of this method. These lists are lists of {@link
123    * AnnotationNode} objects. May be {@literal null}.
124    */
125   public List<AnnotationNode>[] invisibleParameterAnnotations;
126 
127   /** The instructions of this method. */
128   public InsnList instructions;
129 
130   /** The try catch blocks of this method. */
131   public List<TryCatchBlockNode> tryCatchBlocks;
132 
133   /** The maximum stack size of this method. */
134   public int maxStack;
135 
136   /** The maximum number of local variables of this method. */
137   public int maxLocals;
138 
139   /** The local variables of this method. May be {@literal null} */
140   public List<LocalVariableNode> localVariables;
141 
142   /** The visible local variable annotations of this method. May be {@literal null} */
143   public List<LocalVariableAnnotationNode> visibleLocalVariableAnnotations;
144 
145   /** The invisible local variable annotations of this method. May be {@literal null} */
146   public List<LocalVariableAnnotationNode> invisibleLocalVariableAnnotations;
147 
148   /** Whether the accept method has been called on this object. */
149   private boolean visited;
150 
151   /**
152    * Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not use this
153    * constructor</i>. Instead, they must use the {@link #MethodNode(int)} version.
154    *
155    * @throws IllegalStateException If a subclass calls this constructor.
156    */
MethodNode()157   public MethodNode() {
158     this(/* latest api = */ Opcodes.ASM9);
159     if (getClass() != MethodNode.class) {
160       throw new IllegalStateException();
161     }
162   }
163 
164   /**
165    * Constructs an uninitialized {@link MethodNode}.
166    *
167    * @param api the ASM API version implemented by this visitor. Must be one of the {@code
168    *     ASM}<i>x</i> values in {@link Opcodes}.
169    */
MethodNode(final int api)170   public MethodNode(final int api) {
171     super(api);
172     this.instructions = new InsnList();
173   }
174 
175   /**
176    * Constructs a new {@link MethodNode}. <i>Subclasses must not use this constructor</i>. Instead,
177    * they must use the {@link #MethodNode(int, int, String, String, String, String[])} version.
178    *
179    * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
180    *     the method is synthetic and/or deprecated.
181    * @param name the method's name.
182    * @param descriptor the method's descriptor (see {@link Type}).
183    * @param signature the method's signature. May be {@literal null}.
184    * @param exceptions the internal names of the method's exception classes (see {@link
185    *     Type#getInternalName()}). May be {@literal null}.
186    * @throws IllegalStateException If a subclass calls this constructor.
187    */
MethodNode( final int access, final String name, final String descriptor, final String signature, final String[] exceptions)188   public MethodNode(
189       final int access,
190       final String name,
191       final String descriptor,
192       final String signature,
193       final String[] exceptions) {
194     this(/* latest api = */ Opcodes.ASM9, access, name, descriptor, signature, exceptions);
195     if (getClass() != MethodNode.class) {
196       throw new IllegalStateException();
197     }
198   }
199 
200   /**
201    * Constructs a new {@link MethodNode}.
202    *
203    * @param api the ASM API version implemented by this visitor. Must be one of the {@code
204    *     ASM}<i>x</i> values in {@link Opcodes}.
205    * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
206    *     the method is synthetic and/or deprecated.
207    * @param name the method's name.
208    * @param descriptor the method's descriptor (see {@link Type}).
209    * @param signature the method's signature. May be {@literal null}.
210    * @param exceptions the internal names of the method's exception classes (see {@link
211    *     Type#getInternalName()}). May be {@literal null}.
212    */
MethodNode( final int api, final int access, final String name, final String descriptor, final String signature, final String[] exceptions)213   public MethodNode(
214       final int api,
215       final int access,
216       final String name,
217       final String descriptor,
218       final String signature,
219       final String[] exceptions) {
220     super(api);
221     this.access = access;
222     this.name = name;
223     this.desc = descriptor;
224     this.signature = signature;
225     this.exceptions = Util.asArrayList(exceptions);
226     if ((access & Opcodes.ACC_ABSTRACT) == 0) {
227       this.localVariables = new ArrayList<>(5);
228     }
229     this.tryCatchBlocks = new ArrayList<>();
230     this.instructions = new InsnList();
231   }
232 
233   // -----------------------------------------------------------------------------------------------
234   // Implementation of the MethodVisitor abstract class
235   // -----------------------------------------------------------------------------------------------
236 
237   @Override
visitParameter(final String name, final int access)238   public void visitParameter(final String name, final int access) {
239     if (parameters == null) {
240       parameters = new ArrayList<>(5);
241     }
242     parameters.add(new ParameterNode(name, access));
243   }
244 
245   @Override
246   @SuppressWarnings("serial")
visitAnnotationDefault()247   public AnnotationVisitor visitAnnotationDefault() {
248     return new AnnotationNode(
249         new ArrayList<Object>(0) {
250           @Override
251           public boolean add(final Object o) {
252             annotationDefault = o;
253             return super.add(o);
254           }
255         });
256   }
257 
258   @Override
259   public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
260     AnnotationNode annotation = new AnnotationNode(descriptor);
261     if (visible) {
262       visibleAnnotations = Util.add(visibleAnnotations, annotation);
263     } else {
264       invisibleAnnotations = Util.add(invisibleAnnotations, annotation);
265     }
266     return annotation;
267   }
268 
269   @Override
270   public AnnotationVisitor visitTypeAnnotation(
271       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
272     TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
273     if (visible) {
274       visibleTypeAnnotations = Util.add(visibleTypeAnnotations, typeAnnotation);
275     } else {
276       invisibleTypeAnnotations = Util.add(invisibleTypeAnnotations, typeAnnotation);
277     }
278     return typeAnnotation;
279   }
280 
281   @Override
282   public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
283     if (visible) {
284       visibleAnnotableParameterCount = parameterCount;
285     } else {
286       invisibleAnnotableParameterCount = parameterCount;
287     }
288   }
289 
290   @Override
291   @SuppressWarnings("unchecked")
292   public AnnotationVisitor visitParameterAnnotation(
293       final int parameter, final String descriptor, final boolean visible) {
294     AnnotationNode annotation = new AnnotationNode(descriptor);
295     if (visible) {
296       if (visibleParameterAnnotations == null) {
297         int params = Type.getArgumentCount(desc);
298         visibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
299       }
300       visibleParameterAnnotations[parameter] =
301           Util.add(visibleParameterAnnotations[parameter], annotation);
302     } else {
303       if (invisibleParameterAnnotations == null) {
304         int params = Type.getArgumentCount(desc);
305         invisibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
306       }
307       invisibleParameterAnnotations[parameter] =
308           Util.add(invisibleParameterAnnotations[parameter], annotation);
309     }
310     return annotation;
311   }
312 
313   @Override
314   public void visitAttribute(final Attribute attribute) {
315     attrs = Util.add(attrs, attribute);
316   }
317 
318   @Override
319   public void visitCode() {
320     // Nothing to do.
321   }
322 
323   @Override
324   public void visitFrame(
325       final int type,
326       final int numLocal,
327       final Object[] local,
328       final int numStack,
329       final Object[] stack) {
330     instructions.add(
331         new FrameNode(
332             type,
333             numLocal,
334             local == null ? null : getLabelNodes(local),
335             numStack,
336             stack == null ? null : getLabelNodes(stack)));
337   }
338 
339   @Override
340   public void visitInsn(final int opcode) {
341     instructions.add(new InsnNode(opcode));
342   }
343 
344   @Override
345   public void visitIntInsn(final int opcode, final int operand) {
346     instructions.add(new IntInsnNode(opcode, operand));
347   }
348 
349   @Override
350   public void visitVarInsn(final int opcode, final int varIndex) {
351     instructions.add(new VarInsnNode(opcode, varIndex));
352   }
353 
354   @Override
355   public void visitTypeInsn(final int opcode, final String type) {
356     instructions.add(new TypeInsnNode(opcode, type));
357   }
358 
359   @Override
360   public void visitFieldInsn(
361       final int opcode, final String owner, final String name, final String descriptor) {
362     instructions.add(new FieldInsnNode(opcode, owner, name, descriptor));
363   }
364 
365   @Override
366   public void visitMethodInsn(
367       final int opcodeAndSource,
368       final String owner,
369       final String name,
370       final String descriptor,
371       final boolean isInterface) {
372     if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
373       // Redirect the call to the deprecated version of this method.
374       super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
375       return;
376     }
377     int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
378 
379     instructions.add(new MethodInsnNode(opcode, owner, name, descriptor, isInterface));
380   }
381 
382   @Override
383   public void visitInvokeDynamicInsn(
384       final String name,
385       final String descriptor,
386       final Handle bootstrapMethodHandle,
387       final Object... bootstrapMethodArguments) {
388     instructions.add(
389         new InvokeDynamicInsnNode(
390             name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments));
391   }
392 
393   @Override
394   public void visitJumpInsn(final int opcode, final Label label) {
395     instructions.add(new JumpInsnNode(opcode, getLabelNode(label)));
396   }
397 
398   @Override
399   public void visitLabel(final Label label) {
400     instructions.add(getLabelNode(label));
401   }
402 
403   @Override
404   public void visitLdcInsn(final Object value) {
405     instructions.add(new LdcInsnNode(value));
406   }
407 
408   @Override
409   public void visitIincInsn(final int varIndex, final int increment) {
410     instructions.add(new IincInsnNode(varIndex, increment));
411   }
412 
413   @Override
414   public void visitTableSwitchInsn(
415       final int min, final int max, final Label dflt, final Label... labels) {
416     instructions.add(new TableSwitchInsnNode(min, max, getLabelNode(dflt), getLabelNodes(labels)));
417   }
418 
419   @Override
420   public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
421     instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), keys, getLabelNodes(labels)));
422   }
423 
424   @Override
425   public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
426     instructions.add(new MultiANewArrayInsnNode(descriptor, numDimensions));
427   }
428 
429   @Override
430   public AnnotationVisitor visitInsnAnnotation(
431       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
432     // Find the last real instruction, i.e. the instruction targeted by this annotation.
433     AbstractInsnNode currentInsn = instructions.getLast();
434     while (currentInsn.getOpcode() == -1) {
435       currentInsn = currentInsn.getPrevious();
436     }
437     // Add the annotation to this instruction.
438     TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
439     if (visible) {
440       currentInsn.visibleTypeAnnotations =
441           Util.add(currentInsn.visibleTypeAnnotations, typeAnnotation);
442     } else {
443       currentInsn.invisibleTypeAnnotations =
444           Util.add(currentInsn.invisibleTypeAnnotations, typeAnnotation);
445     }
446     return typeAnnotation;
447   }
448 
449   @Override
450   public void visitTryCatchBlock(
451       final Label start, final Label end, final Label handler, final String type) {
452     TryCatchBlockNode tryCatchBlock =
453         new TryCatchBlockNode(getLabelNode(start), getLabelNode(end), getLabelNode(handler), type);
454     tryCatchBlocks = Util.add(tryCatchBlocks, tryCatchBlock);
455   }
456 
457   @Override
458   public AnnotationVisitor visitTryCatchAnnotation(
459       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
460     TryCatchBlockNode tryCatchBlock = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
461     TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
462     if (visible) {
463       tryCatchBlock.visibleTypeAnnotations =
464           Util.add(tryCatchBlock.visibleTypeAnnotations, typeAnnotation);
465     } else {
466       tryCatchBlock.invisibleTypeAnnotations =
467           Util.add(tryCatchBlock.invisibleTypeAnnotations, typeAnnotation);
468     }
469     return typeAnnotation;
470   }
471 
472   @Override
473   public void visitLocalVariable(
474       final String name,
475       final String descriptor,
476       final String signature,
477       final Label start,
478       final Label end,
479       final int index) {
480     LocalVariableNode localVariable =
481         new LocalVariableNode(
482             name, descriptor, signature, getLabelNode(start), getLabelNode(end), index);
483     localVariables = Util.add(localVariables, localVariable);
484   }
485 
486   @Override
487   public AnnotationVisitor visitLocalVariableAnnotation(
488       final int typeRef,
489       final TypePath typePath,
490       final Label[] start,
491       final Label[] end,
492       final int[] index,
493       final String descriptor,
494       final boolean visible) {
495     LocalVariableAnnotationNode localVariableAnnotation =
496         new LocalVariableAnnotationNode(
497             typeRef, typePath, getLabelNodes(start), getLabelNodes(end), index, descriptor);
498     if (visible) {
499       visibleLocalVariableAnnotations =
500           Util.add(visibleLocalVariableAnnotations, localVariableAnnotation);
501     } else {
502       invisibleLocalVariableAnnotations =
503           Util.add(invisibleLocalVariableAnnotations, localVariableAnnotation);
504     }
505     return localVariableAnnotation;
506   }
507 
508   @Override
509   public void visitLineNumber(final int line, final Label start) {
510     instructions.add(new LineNumberNode(line, getLabelNode(start)));
511   }
512 
513   @Override
514   public void visitMaxs(final int maxStack, final int maxLocals) {
515     this.maxStack = maxStack;
516     this.maxLocals = maxLocals;
517   }
518 
519   @Override
520   public void visitEnd() {
521     // Nothing to do.
522   }
523 
524   /**
525    * Returns the LabelNode corresponding to the given Label. Creates a new LabelNode if necessary.
526    * The default implementation of this method uses the {@link Label#info} field to store
527    * associations between labels and label nodes.
528    *
529    * @param label a Label.
530    * @return the LabelNode corresponding to label.
531    */
532   protected LabelNode getLabelNode(final Label label) {
533     if (!(label.info instanceof LabelNode)) {
534       label.info = new LabelNode();
535     }
536     return (LabelNode) label.info;
537   }
538 
539   private LabelNode[] getLabelNodes(final Label[] labels) {
540     LabelNode[] labelNodes = new LabelNode[labels.length];
541     for (int i = 0, n = labels.length; i < n; ++i) {
542       labelNodes[i] = getLabelNode(labels[i]);
543     }
544     return labelNodes;
545   }
546 
547   private Object[] getLabelNodes(final Object[] objects) {
548     Object[] labelNodes = new Object[objects.length];
549     for (int i = 0, n = objects.length; i < n; ++i) {
550       Object o = objects[i];
551       if (o instanceof Label) {
552         o = getLabelNode((Label) o);
553       }
554       labelNodes[i] = o;
555     }
556     return labelNodes;
557   }
558 
559   // -----------------------------------------------------------------------------------------------
560   // Accept method
561   // -----------------------------------------------------------------------------------------------
562 
563   /**
564    * Checks that this method node is compatible with the given ASM API version. This method checks
565    * that this node, and all its children recursively, do not contain elements that were introduced
566    * in more recent versions of the ASM API than the given version.
567    *
568    * @param api an ASM API version. Must be one of the {@code ASM}<i>x</i> values in {@link
569    *     Opcodes}.
570    */
571   public void check(final int api) {
572     if (api == Opcodes.ASM4) {
573       if (parameters != null && !parameters.isEmpty()) {
574         throw new UnsupportedClassVersionException();
575       }
576       if (visibleTypeAnnotations != null && !visibleTypeAnnotations.isEmpty()) {
577         throw new UnsupportedClassVersionException();
578       }
579       if (invisibleTypeAnnotations != null && !invisibleTypeAnnotations.isEmpty()) {
580         throw new UnsupportedClassVersionException();
581       }
582       if (tryCatchBlocks != null) {
583         for (int i = tryCatchBlocks.size() - 1; i >= 0; --i) {
584           TryCatchBlockNode tryCatchBlock = tryCatchBlocks.get(i);
585           if (tryCatchBlock.visibleTypeAnnotations != null
586               && !tryCatchBlock.visibleTypeAnnotations.isEmpty()) {
587             throw new UnsupportedClassVersionException();
588           }
589           if (tryCatchBlock.invisibleTypeAnnotations != null
590               && !tryCatchBlock.invisibleTypeAnnotations.isEmpty()) {
591             throw new UnsupportedClassVersionException();
592           }
593         }
594       }
595       for (int i = instructions.size() - 1; i >= 0; --i) {
596         AbstractInsnNode insn = instructions.get(i);
597         if (insn.visibleTypeAnnotations != null && !insn.visibleTypeAnnotations.isEmpty()) {
598           throw new UnsupportedClassVersionException();
599         }
600         if (insn.invisibleTypeAnnotations != null && !insn.invisibleTypeAnnotations.isEmpty()) {
601           throw new UnsupportedClassVersionException();
602         }
603         if (insn instanceof MethodInsnNode) {
604           boolean isInterface = ((MethodInsnNode) insn).itf;
605           if (isInterface != (insn.opcode == Opcodes.INVOKEINTERFACE)) {
606             throw new UnsupportedClassVersionException();
607           }
608         } else if (insn instanceof LdcInsnNode) {
609           Object value = ((LdcInsnNode) insn).cst;
610           if (value instanceof Handle
611               || (value instanceof Type && ((Type) value).getSort() == Type.METHOD)) {
612             throw new UnsupportedClassVersionException();
613           }
614         }
615       }
616       if (visibleLocalVariableAnnotations != null && !visibleLocalVariableAnnotations.isEmpty()) {
617         throw new UnsupportedClassVersionException();
618       }
619       if (invisibleLocalVariableAnnotations != null
620           && !invisibleLocalVariableAnnotations.isEmpty()) {
621         throw new UnsupportedClassVersionException();
622       }
623     }
624     if (api < Opcodes.ASM7) {
625       for (int i = instructions.size() - 1; i >= 0; --i) {
626         AbstractInsnNode insn = instructions.get(i);
627         if (insn instanceof LdcInsnNode) {
628           Object value = ((LdcInsnNode) insn).cst;
629           if (value instanceof ConstantDynamic) {
630             throw new UnsupportedClassVersionException();
631           }
632         }
633       }
634     }
635   }
636 
637   /**
638    * Makes the given class visitor visit this method.
639    *
640    * @param classVisitor a class visitor.
641    */
642   public void accept(final ClassVisitor classVisitor) {
643     String[] exceptionsArray = exceptions == null ? null : exceptions.toArray(new String[0]);
644     MethodVisitor methodVisitor =
645         classVisitor.visitMethod(access, name, desc, signature, exceptionsArray);
646     if (methodVisitor != null) {
647       accept(methodVisitor);
648     }
649   }
650 
651   /**
652    * Makes the given method visitor visit this method.
653    *
654    * @param methodVisitor a method visitor.
655    */
656   public void accept(final MethodVisitor methodVisitor) {
657     // Visit the parameters.
658     if (parameters != null) {
659       for (int i = 0, n = parameters.size(); i < n; i++) {
660         parameters.get(i).accept(methodVisitor);
661       }
662     }
663     // Visit the annotations.
664     if (annotationDefault != null) {
665       AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
666       AnnotationNode.accept(annotationVisitor, null, annotationDefault);
667       if (annotationVisitor != null) {
668         annotationVisitor.visitEnd();
669       }
670     }
671     if (visibleAnnotations != null) {
672       for (int i = 0, n = visibleAnnotations.size(); i < n; ++i) {
673         AnnotationNode annotation = visibleAnnotations.get(i);
674         annotation.accept(methodVisitor.visitAnnotation(annotation.desc, true));
675       }
676     }
677     if (invisibleAnnotations != null) {
678       for (int i = 0, n = invisibleAnnotations.size(); i < n; ++i) {
679         AnnotationNode annotation = invisibleAnnotations.get(i);
680         annotation.accept(methodVisitor.visitAnnotation(annotation.desc, false));
681       }
682     }
683     if (visibleTypeAnnotations != null) {
684       for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
685         TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
686         typeAnnotation.accept(
687             methodVisitor.visitTypeAnnotation(
688                 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
689       }
690     }
691     if (invisibleTypeAnnotations != null) {
692       for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
693         TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
694         typeAnnotation.accept(
695             methodVisitor.visitTypeAnnotation(
696                 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
697       }
698     }
699     if (visibleAnnotableParameterCount > 0) {
700       methodVisitor.visitAnnotableParameterCount(visibleAnnotableParameterCount, true);
701     }
702     if (visibleParameterAnnotations != null) {
703       for (int i = 0, n = visibleParameterAnnotations.length; i < n; ++i) {
704         List<AnnotationNode> parameterAnnotations = visibleParameterAnnotations[i];
705         if (parameterAnnotations == null) {
706           continue;
707         }
708         for (int j = 0, m = parameterAnnotations.size(); j < m; ++j) {
709           AnnotationNode annotation = parameterAnnotations.get(j);
710           annotation.accept(methodVisitor.visitParameterAnnotation(i, annotation.desc, true));
711         }
712       }
713     }
714     if (invisibleAnnotableParameterCount > 0) {
715       methodVisitor.visitAnnotableParameterCount(invisibleAnnotableParameterCount, false);
716     }
717     if (invisibleParameterAnnotations != null) {
718       for (int i = 0, n = invisibleParameterAnnotations.length; i < n; ++i) {
719         List<AnnotationNode> parameterAnnotations = invisibleParameterAnnotations[i];
720         if (parameterAnnotations == null) {
721           continue;
722         }
723         for (int j = 0, m = parameterAnnotations.size(); j < m; ++j) {
724           AnnotationNode annotation = parameterAnnotations.get(j);
725           annotation.accept(methodVisitor.visitParameterAnnotation(i, annotation.desc, false));
726         }
727       }
728     }
729     // Visit the non standard attributes.
730     if (visited) {
731       instructions.resetLabels();
732     }
733     if (attrs != null) {
734       for (int i = 0, n = attrs.size(); i < n; ++i) {
735         methodVisitor.visitAttribute(attrs.get(i));
736       }
737     }
738     // Visit the code.
739     if (instructions.size() > 0) {
740       methodVisitor.visitCode();
741       // Visits the try catch blocks.
742       if (tryCatchBlocks != null) {
743         for (int i = 0, n = tryCatchBlocks.size(); i < n; ++i) {
744           tryCatchBlocks.get(i).updateIndex(i);
745           tryCatchBlocks.get(i).accept(methodVisitor);
746         }
747       }
748       // Visit the instructions.
749       instructions.accept(methodVisitor);
750       // Visits the local variables.
751       if (localVariables != null) {
752         for (int i = 0, n = localVariables.size(); i < n; ++i) {
753           localVariables.get(i).accept(methodVisitor);
754         }
755       }
756       // Visits the local variable annotations.
757       if (visibleLocalVariableAnnotations != null) {
758         for (int i = 0, n = visibleLocalVariableAnnotations.size(); i < n; ++i) {
759           visibleLocalVariableAnnotations.get(i).accept(methodVisitor, true);
760         }
761       }
762       if (invisibleLocalVariableAnnotations != null) {
763         for (int i = 0, n = invisibleLocalVariableAnnotations.size(); i < n; ++i) {
764           invisibleLocalVariableAnnotations.get(i).accept(methodVisitor, false);
765         }
766       }
767       methodVisitor.visitMaxs(maxStack, maxLocals);
768       visited = true;
769     }
770     methodVisitor.visitEnd();
771   }
772 }
773