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 the {@code 071 * ASM}<i>x</i> values in {@link Opcodes}. 072 * @param prefix the prefix to use to rename the existing <clinit> methods. 073 * @param classVisitor the class visitor to which this visitor must delegate method calls. May be 074 * null. 075 */ 076 protected StaticInitMerger(final int api, final String prefix, final ClassVisitor classVisitor) { 077 super(api, classVisitor); 078 this.renamedClinitMethodPrefix = prefix; 079 } 080 081 @Override 082 public void visit( 083 final int version, 084 final int access, 085 final String name, 086 final String signature, 087 final String superName, 088 final String[] interfaces) { 089 super.visit(version, access, name, signature, superName, interfaces); 090 this.owner = name; 091 } 092 093 @Override 094 public MethodVisitor visitMethod( 095 final int access, 096 final String name, 097 final String descriptor, 098 final String signature, 099 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 117 public void visitEnd() { 118 if (mergedClinitVisitor != null) { 119 mergedClinitVisitor.visitInsn(Opcodes.RETURN); 120 mergedClinitVisitor.visitMaxs(0, 0); 121 } 122 super.visitEnd(); 123 } 124}