1 // ASM: a very small and fast Java bytecode manipulation framework 2 // Copyright (c) 2000-2011 INRIA, France Telecom 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the copyright holders nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 // THE POSSIBILITY OF SUCH DAMAGE. 28 package org.objectweb.asm.commons; 29 30 import org.objectweb.asm.ConstantDynamic; 31 import org.objectweb.asm.Handle; 32 import org.objectweb.asm.Label; 33 import org.objectweb.asm.MethodVisitor; 34 import org.objectweb.asm.Opcodes; 35 36 /** 37 * A {@link MethodVisitor} that approximates the size of the methods it visits. 38 * 39 * @author Eugene Kuleshov 40 */ 41 public class CodeSizeEvaluator extends MethodVisitor implements Opcodes { 42 43 /** The minimum size in bytes of the visited method. */ 44 private int minSize; 45 46 /** The maximum size in bytes of the visited method. */ 47 private int maxSize; 48 CodeSizeEvaluator(final MethodVisitor methodVisitor)49 public CodeSizeEvaluator(final MethodVisitor methodVisitor) { 50 this(/* latest api = */ Opcodes.ASM9, methodVisitor); 51 } 52 CodeSizeEvaluator(final int api, final MethodVisitor methodVisitor)53 protected CodeSizeEvaluator(final int api, final MethodVisitor methodVisitor) { 54 super(api, methodVisitor); 55 } 56 getMinSize()57 public int getMinSize() { 58 return this.minSize; 59 } 60 getMaxSize()61 public int getMaxSize() { 62 return this.maxSize; 63 } 64 65 @Override visitInsn(final int opcode)66 public void visitInsn(final int opcode) { 67 minSize += 1; 68 maxSize += 1; 69 super.visitInsn(opcode); 70 } 71 72 @Override visitIntInsn(final int opcode, final int operand)73 public void visitIntInsn(final int opcode, final int operand) { 74 if (opcode == SIPUSH) { 75 minSize += 3; 76 maxSize += 3; 77 } else { 78 minSize += 2; 79 maxSize += 2; 80 } 81 super.visitIntInsn(opcode, operand); 82 } 83 84 @Override visitVarInsn(final int opcode, final int varIndex)85 public void visitVarInsn(final int opcode, final int varIndex) { 86 if (varIndex < 4 && opcode != RET) { 87 minSize += 1; 88 maxSize += 1; 89 } else if (varIndex >= 256) { 90 minSize += 4; 91 maxSize += 4; 92 } else { 93 minSize += 2; 94 maxSize += 2; 95 } 96 super.visitVarInsn(opcode, varIndex); 97 } 98 99 @Override visitTypeInsn(final int opcode, final String type)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 visitFieldInsn( final int opcode, final String owner, final String name, final String descriptor)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 visitMethodInsn( final int opcodeAndSource, final String owner, final String name, final String descriptor, final boolean isInterface)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 visitInvokeDynamicInsn( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)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 visitJumpInsn(final int opcode, final Label label)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 visitLdcInsn(final Object value)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 visitIincInsn(final int varIndex, final int increment)175 public void visitIincInsn(final int varIndex, final int increment) { 176 if (varIndex > 255 || increment > 127 || increment < -128) { 177 minSize += 6; 178 maxSize += 6; 179 } else { 180 minSize += 3; 181 maxSize += 3; 182 } 183 super.visitIincInsn(varIndex, increment); 184 } 185 186 @Override visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label... labels)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 visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)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 visitMultiANewArrayInsn(final String descriptor, final int numDimensions)202 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { 203 minSize += 4; 204 maxSize += 4; 205 super.visitMultiANewArrayInsn(descriptor, numDimensions); 206 } 207 } 208