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}