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.ConstantDynamic;
031import io.ebean.enhance.asm.Handle;
032import io.ebean.enhance.asm.Label;
033import io.ebean.enhance.asm.MethodVisitor;
034import io.ebean.enhance.asm.Opcodes;
035
036/**
037 * A {@link MethodVisitor} that approximates the size of the methods it visits.
038 *
039 * @author Eugene Kuleshov
040 */
041public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
042
043  /** The minimum size in bytes of the visited method. */
044  private int minSize;
045
046  /** The maximum size in bytes of the visited method. */
047  private int maxSize;
048
049  public CodeSizeEvaluator(final MethodVisitor methodVisitor) {
050    this(Opcodes.ASM7, methodVisitor);
051  }
052
053  protected CodeSizeEvaluator(final int api, final MethodVisitor methodVisitor) {
054    super(api, methodVisitor);
055  }
056
057  public int getMinSize() {
058    return this.minSize;
059  }
060
061  public int getMaxSize() {
062    return this.maxSize;
063  }
064
065  @Override
066  public void visitInsn(final int opcode) {
067    minSize += 1;
068    maxSize += 1;
069    super.visitInsn(opcode);
070  }
071
072  @Override
073  public void visitIntInsn(final int opcode, final int operand) {
074    if (opcode == SIPUSH) {
075      minSize += 3;
076      maxSize += 3;
077    } else {
078      minSize += 2;
079      maxSize += 2;
080    }
081    super.visitIntInsn(opcode, operand);
082  }
083
084  @Override
085  public void visitVarInsn(final int opcode, final int var) {
086    if (var < 4 && opcode != RET) {
087      minSize += 1;
088      maxSize += 1;
089    } else if (var >= 256) {
090      minSize += 4;
091      maxSize += 4;
092    } else {
093      minSize += 2;
094      maxSize += 2;
095    }
096    super.visitVarInsn(opcode, var);
097  }
098
099  @Override
100  public void visitTypeInsn(final int opcode, final String type) {
101    minSize += 3;
102    maxSize += 3;
103    super.visitTypeInsn(opcode, type);
104  }
105
106  @Override
107  public void visitFieldInsn(
108      final int opcode, final String owner, final String name, final String descriptor) {
109    minSize += 3;
110    maxSize += 3;
111    super.visitFieldInsn(opcode, owner, name, descriptor);
112  }
113
114  @Override
115  public void visitMethodInsn(
116      final int opcodeAndSource,
117      final String owner,
118      final String name,
119      final String descriptor,
120      final boolean isInterface) {
121    if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
122      // Redirect the call to the deprecated version of this method.
123      super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
124      return;
125    }
126    int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
127
128    if (opcode == INVOKEINTERFACE) {
129      minSize += 5;
130      maxSize += 5;
131    } else {
132      minSize += 3;
133      maxSize += 3;
134    }
135    super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
136  }
137
138  @Override
139  public void visitInvokeDynamicInsn(
140      final String name,
141      final String descriptor,
142      final Handle bootstrapMethodHandle,
143      final Object... bootstrapMethodArguments) {
144    minSize += 5;
145    maxSize += 5;
146    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
147  }
148
149  @Override
150  public void visitJumpInsn(final int opcode, final Label label) {
151    minSize += 3;
152    if (opcode == GOTO || opcode == JSR) {
153      maxSize += 5;
154    } else {
155      maxSize += 8;
156    }
157    super.visitJumpInsn(opcode, label);
158  }
159
160  @Override
161  public void visitLdcInsn(final Object value) {
162    if (value instanceof Long
163        || value instanceof Double
164        || (value instanceof ConstantDynamic && ((ConstantDynamic) value).getSize() == 2)) {
165      minSize += 3;
166      maxSize += 3;
167    } else {
168      minSize += 2;
169      maxSize += 3;
170    }
171    super.visitLdcInsn(value);
172  }
173
174  @Override
175  public void visitIincInsn(final int var, final int increment) {
176    if (var > 255 || increment > 127 || increment < -128) {
177      minSize += 6;
178      maxSize += 6;
179    } else {
180      minSize += 3;
181      maxSize += 3;
182    }
183    super.visitIincInsn(var, increment);
184  }
185
186  @Override
187  public void visitTableSwitchInsn(
188    final int min, final int max, final Label dflt, final Label... labels) {
189    minSize += 13 + labels.length * 4;
190    maxSize += 16 + labels.length * 4;
191    super.visitTableSwitchInsn(min, max, dflt, labels);
192  }
193
194  @Override
195  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
196    minSize += 9 + keys.length * 8;
197    maxSize += 12 + keys.length * 8;
198    super.visitLookupSwitchInsn(dflt, keys, labels);
199  }
200
201  @Override
202  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
203    minSize += 4;
204    maxSize += 4;
205    super.visitMultiANewArrayInsn(descriptor, numDimensions);
206  }
207}