• 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.commons;
29 
30 import org.objectweb.asm.ClassVisitor;
31 import org.objectweb.asm.MethodVisitor;
32 import org.objectweb.asm.Opcodes;
33 
34 /**
35  * A {@link ClassVisitor} that merges <clinit> methods into a single one. All the existing
36  * <clinit> methods are renamed, and a new one is created, which calls all the renamed
37  * methods.
38  *
39  * @author Eric Bruneton
40  */
41 public class StaticInitMerger extends ClassVisitor {
42 
43   /** The internal name of the visited class. */
44   private String owner;
45 
46   /** The prefix to use to rename the existing <clinit> methods. */
47   private final String renamedClinitMethodPrefix;
48 
49   /** The number of <clinit> methods visited so far. */
50   private int numClinitMethods;
51 
52   /** The MethodVisitor for the merged <clinit> method. */
53   private MethodVisitor mergedClinitVisitor;
54 
55   /**
56    * Constructs a new {@link StaticInitMerger}. <i>Subclasses must not use this constructor</i>.
57    * Instead, they must use the {@link #StaticInitMerger(int, String, ClassVisitor)} version.
58    *
59    * @param prefix the prefix to use to rename the existing &lt;clinit&gt; methods.
60    * @param classVisitor the class visitor to which this visitor must delegate method calls. May be
61    *     null.
62    */
StaticInitMerger(final String prefix, final ClassVisitor classVisitor)63   public StaticInitMerger(final String prefix, final ClassVisitor classVisitor) {
64     this(/* latest api = */ Opcodes.ASM9, prefix, classVisitor);
65   }
66 
67   /**
68    * Constructs a new {@link StaticInitMerger}.
69    *
70    * @param api the ASM API version implemented by this visitor. Must be one of the {@code
71    *     ASM}<i>x</i> values in {@link Opcodes}.
72    * @param prefix the prefix to use to rename the existing &lt;clinit&gt; methods.
73    * @param classVisitor the class visitor to which this visitor must delegate method calls. May be
74    *     null.
75    */
StaticInitMerger(final int api, final String prefix, final ClassVisitor classVisitor)76   protected StaticInitMerger(final int api, final String prefix, final ClassVisitor classVisitor) {
77     super(api, classVisitor);
78     this.renamedClinitMethodPrefix = prefix;
79   }
80 
81   @Override
visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)82   public void visit(
83       final int version,
84       final int access,
85       final String name,
86       final String signature,
87       final String superName,
88       final String[] interfaces) {
89     super.visit(version, access, name, signature, superName, interfaces);
90     this.owner = name;
91   }
92 
93   @Override
visitMethod( final int access, final String name, final String descriptor, final String signature, final String[] exceptions)94   public MethodVisitor visitMethod(
95       final int access,
96       final String name,
97       final String descriptor,
98       final String signature,
99       final String[] exceptions) {
100     MethodVisitor methodVisitor;
101     if ("<clinit>".equals(name)) {
102       int newAccess = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
103       String newName = renamedClinitMethodPrefix + numClinitMethods++;
104       methodVisitor = super.visitMethod(newAccess, newName, descriptor, signature, exceptions);
105 
106       if (mergedClinitVisitor == null) {
107         mergedClinitVisitor = super.visitMethod(newAccess, name, descriptor, null, null);
108       }
109       mergedClinitVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, owner, newName, descriptor, false);
110     } else {
111       methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
112     }
113     return methodVisitor;
114   }
115 
116   @Override
visitEnd()117   public void visitEnd() {
118     if (mergedClinitVisitor != null) {
119       mergedClinitVisitor.visitInsn(Opcodes.RETURN);
120       mergedClinitVisitor.visitMaxs(0, 0);
121     }
122     super.visitEnd();
123   }
124 }
125