001// ASM: a very small and fast Java bytecode manipulation framework 002// Copyright (c) 2000-2011 INRIA, France Telecom 003// All rights reserved. 004// 005// Redistribution and use in source and binary forms, with or without 006// modification, are permitted provided that the following conditions 007// are met: 008// 1. Redistributions of source code must retain the above copyright 009// notice, this list of conditions and the following disclaimer. 010// 2. Redistributions in binary form must reproduce the above copyright 011// notice, this list of conditions and the following disclaimer in the 012// documentation and/or other materials provided with the distribution. 013// 3. Neither the name of the copyright holders nor the names of its 014// contributors may be used to endorse or promote products derived from 015// this software without specific prior written permission. 016// 017// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 018// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 019// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 020// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 021// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 022// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 023// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 024// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 025// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 026// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 027// THE POSSIBILITY OF SUCH DAMAGE. 028package io.ebean.enhance.asm.commons; 029 030import io.ebean.enhance.asm.ClassVisitor; 031import io.ebean.enhance.asm.MethodVisitor; 032import io.ebean.enhance.asm.Opcodes; 033 034/** 035 * A {@link ClassVisitor} that merges <clinit> methods into a single one. All the existing 036 * <clinit> methods are renamed, and a new one is created, which calls all the renamed 037 * methods. 038 * 039 * @author Eric Bruneton 040 */ 041public class StaticInitMerger extends ClassVisitor { 042 043 /** The internal name of the visited class. */ 044 private String owner; 045 046 /** The prefix to use to rename the existing <clinit> methods. */ 047 private final String renamedClinitMethodPrefix; 048 049 /** The number of <clinit> methods visited so far. */ 050 private int numClinitMethods; 051 052 /** The MethodVisitor for the merged <clinit> method. */ 053 private MethodVisitor mergedClinitVisitor; 054 055 /** 056 * Constructs a new {@link StaticInitMerger}. <i>Subclasses must not use this constructor</i>. 057 * Instead, they must use the {@link #StaticInitMerger(int, String, ClassVisitor)} version. 058 * 059 * @param prefix the prefix to use to rename the existing <clinit> methods. 060 * @param classVisitor the class visitor to which this visitor must delegate method calls. May be 061 * null. 062 */ 063 public StaticInitMerger(final String prefix, final ClassVisitor classVisitor) { 064 this(/* latest api = */ Opcodes.ASM9, prefix, classVisitor); 065 } 066 067 /** 068 * Constructs a new {@link StaticInitMerger}. 069 * 070 * @param api the ASM API version implemented by this visitor. Must be one of {@link 071 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7}, {@link 072 * Opcodes#ASM8} or {@link Opcodes#ASM9}. 073 * @param prefix the prefix to use to rename the existing <clinit> methods. 074 * @param classVisitor the class visitor to which this visitor must delegate method calls. May be 075 * null. 076 */ 077 protected StaticInitMerger(final int api, final String prefix, final ClassVisitor classVisitor) { 078 super(api, classVisitor); 079 this.renamedClinitMethodPrefix = prefix; 080 } 081 082 @Override 083 public void visit( 084 final int version, 085 final int access, 086 final String name, 087 final String signature, 088 final String superName, 089 final String[] interfaces) { 090 super.visit(version, access, name, signature, superName, interfaces); 091 this.owner = name; 092 } 093 094 @Override 095 public MethodVisitor visitMethod( 096 final int access, 097 final String name, 098 final String descriptor, 099 final String signature, 100 final String[] exceptions) { 101 MethodVisitor methodVisitor; 102 if ("<clinit>".equals(name)) { 103 int newAccess = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC; 104 String newName = renamedClinitMethodPrefix + numClinitMethods++; 105 methodVisitor = super.visitMethod(newAccess, newName, descriptor, signature, exceptions); 106 107 if (mergedClinitVisitor == null) { 108 mergedClinitVisitor = super.visitMethod(newAccess, name, descriptor, null, null); 109 } 110 mergedClinitVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, owner, newName, descriptor, false); 111 } else { 112 methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions); 113 } 114 return methodVisitor; 115 } 116 117 @Override 118 public void visitEnd() { 119 if (mergedClinitVisitor != null) { 120 mergedClinitVisitor.visitInsn(Opcodes.RETURN); 121 mergedClinitVisitor.visitMaxs(0, 0); 122 } 123 super.visitEnd(); 124 } 125}