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}