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. 028 029package io.ebean.enhance.asm.commons; 030 031import io.ebean.enhance.asm.AnnotationVisitor; 032import io.ebean.enhance.asm.Handle; 033import io.ebean.enhance.asm.Label; 034import io.ebean.enhance.asm.MethodVisitor; 035import io.ebean.enhance.asm.Opcodes; 036import io.ebean.enhance.asm.TypePath; 037 038/** 039 * A {@link MethodVisitor} that remaps types with a {@link Remapper}. 040 * 041 * @author Eugene Kuleshov 042 */ 043public class MethodRemapper extends MethodVisitor { 044 045 /** The remapper used to remap the types in the visited field. */ 046 protected final Remapper remapper; 047 048 /** 049 * Constructs a new {@link MethodRemapper}. <i>Subclasses must not use this constructor</i>. 050 * Instead, they must use the {@link #MethodRemapper(int, MethodVisitor, Remapper)} version. 051 * 052 * @param methodVisitor the method visitor this remapper must deleted to. 053 * @param remapper the remapper to use to remap the types in the visited method. 054 */ 055 public MethodRemapper(final MethodVisitor methodVisitor, final Remapper remapper) { 056 this(Opcodes.ASM7, methodVisitor, remapper); 057 } 058 059 /** 060 * Constructs a new {@link MethodRemapper}. 061 * 062 * @param api the ASM API version supported by this remapper. Must be one of {@link 063 * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link 064 * Opcodes#ASM6}. 065 * @param methodVisitor the method visitor this remapper must deleted to. 066 * @param remapper the remapper to use to remap the types in the visited method. 067 */ 068 protected MethodRemapper( 069 final int api, final MethodVisitor methodVisitor, final Remapper remapper) { 070 super(api, methodVisitor); 071 this.remapper = remapper; 072 } 073 074 @Override 075 public AnnotationVisitor visitAnnotationDefault() { 076 AnnotationVisitor annotationVisitor = super.visitAnnotationDefault(); 077 return annotationVisitor == null 078 ? annotationVisitor 079 : new AnnotationRemapper(api, annotationVisitor, remapper); 080 } 081 082 @Override 083 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { 084 AnnotationVisitor annotationVisitor = 085 super.visitAnnotation(remapper.mapDesc(descriptor), visible); 086 return annotationVisitor == null 087 ? annotationVisitor 088 : new AnnotationRemapper(api, annotationVisitor, remapper); 089 } 090 091 @Override 092 public AnnotationVisitor visitTypeAnnotation( 093 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 094 AnnotationVisitor annotationVisitor = 095 super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible); 096 return annotationVisitor == null 097 ? annotationVisitor 098 : new AnnotationRemapper(api, annotationVisitor, remapper); 099 } 100 101 @Override 102 public AnnotationVisitor visitParameterAnnotation( 103 final int parameter, final String descriptor, final boolean visible) { 104 AnnotationVisitor annotationVisitor = 105 super.visitParameterAnnotation(parameter, remapper.mapDesc(descriptor), visible); 106 return annotationVisitor == null 107 ? annotationVisitor 108 : new AnnotationRemapper(api, annotationVisitor, remapper); 109 } 110 111 @Override 112 public void visitFrame( 113 final int type, 114 final int numLocal, 115 final Object[] local, 116 final int numStack, 117 final Object[] stack) { 118 super.visitFrame( 119 type, 120 numLocal, 121 remapFrameTypes(numLocal, local), 122 numStack, 123 remapFrameTypes(numStack, stack)); 124 } 125 126 private Object[] remapFrameTypes(final int numTypes, final Object[] frameTypes) { 127 if (frameTypes == null) { 128 return frameTypes; 129 } 130 Object[] remappedFrameTypes = null; 131 for (int i = 0; i < numTypes; ++i) { 132 if (frameTypes[i] instanceof String) { 133 if (remappedFrameTypes == null) { 134 remappedFrameTypes = new Object[numTypes]; 135 System.arraycopy(frameTypes, 0, remappedFrameTypes, 0, numTypes); 136 } 137 remappedFrameTypes[i] = remapper.mapType((String) frameTypes[i]); 138 } 139 } 140 return remappedFrameTypes == null ? frameTypes : remappedFrameTypes; 141 } 142 143 @Override 144 public void visitFieldInsn( 145 final int opcode, final String owner, final String name, final String descriptor) { 146 super.visitFieldInsn( 147 opcode, 148 remapper.mapType(owner), 149 remapper.mapFieldName(owner, name, descriptor), 150 remapper.mapDesc(descriptor)); 151 } 152 153 @Override 154 public void visitMethodInsn( 155 final int opcodeAndSource, 156 final String owner, 157 final String name, 158 final String descriptor, 159 final boolean isInterface) { 160 if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) { 161 // Redirect the call to the deprecated version of this method. 162 super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface); 163 return; 164 } 165 super.visitMethodInsn( 166 opcodeAndSource, 167 remapper.mapType(owner), 168 remapper.mapMethodName(owner, name, descriptor), 169 remapper.mapMethodDesc(descriptor), 170 isInterface); 171 } 172 173 @Override 174 public void visitInvokeDynamicInsn( 175 final String name, 176 final String descriptor, 177 final Handle bootstrapMethodHandle, 178 final Object... bootstrapMethodArguments) { 179 Object[] remappedBootstrapMethodArguments = new Object[bootstrapMethodArguments.length]; 180 for (int i = 0; i < bootstrapMethodArguments.length; ++i) { 181 remappedBootstrapMethodArguments[i] = remapper.mapValue(bootstrapMethodArguments[i]); 182 } 183 super.visitInvokeDynamicInsn( 184 remapper.mapInvokeDynamicMethodName(name, descriptor), 185 remapper.mapMethodDesc(descriptor), 186 (Handle) remapper.mapValue(bootstrapMethodHandle), 187 remappedBootstrapMethodArguments); 188 } 189 190 @Override 191 public void visitTypeInsn(final int opcode, final String type) { 192 super.visitTypeInsn(opcode, remapper.mapType(type)); 193 } 194 195 @Override 196 public void visitLdcInsn(final Object value) { 197 super.visitLdcInsn(remapper.mapValue(value)); 198 } 199 200 @Override 201 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { 202 super.visitMultiANewArrayInsn(remapper.mapDesc(descriptor), numDimensions); 203 } 204 205 @Override 206 public AnnotationVisitor visitInsnAnnotation( 207 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 208 AnnotationVisitor annotationVisitor = 209 super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible); 210 return annotationVisitor == null 211 ? annotationVisitor 212 : new AnnotationRemapper(api, annotationVisitor, remapper); 213 } 214 215 @Override 216 public void visitTryCatchBlock( 217 final Label start, final Label end, final Label handler, final String type) { 218 super.visitTryCatchBlock(start, end, handler, type == null ? null : remapper.mapType(type)); 219 } 220 221 @Override 222 public AnnotationVisitor visitTryCatchAnnotation( 223 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 224 AnnotationVisitor annotationVisitor = 225 super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible); 226 return annotationVisitor == null 227 ? annotationVisitor 228 : new AnnotationRemapper(api, annotationVisitor, remapper); 229 } 230 231 @Override 232 public void visitLocalVariable( 233 final String name, 234 final String descriptor, 235 final String signature, 236 final Label start, 237 final Label end, 238 final int index) { 239 super.visitLocalVariable( 240 name, 241 remapper.mapDesc(descriptor), 242 remapper.mapSignature(signature, true), 243 start, 244 end, 245 index); 246 } 247 248 @Override 249 public AnnotationVisitor visitLocalVariableAnnotation( 250 final int typeRef, 251 final TypePath typePath, 252 final Label[] start, 253 final Label[] end, 254 final int[] index, 255 final String descriptor, 256 final boolean visible) { 257 AnnotationVisitor annotationVisitor = 258 super.visitLocalVariableAnnotation( 259 typeRef, typePath, start, end, index, remapper.mapDesc(descriptor), visible); 260 return annotationVisitor == null 261 ? annotationVisitor 262 : new AnnotationRemapper(api, annotationVisitor, remapper); 263 } 264}