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 <clinit> 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 <clinit> 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