001/***
002 * ASM: a very small and fast Java bytecode manipulation framework
003 * Copyright (c) 2000-2011 INRIA, France Telecom
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions
008 * are met:
009 * 1. Redistributions of source code must retain the above copyright
010 *    notice, this list of conditions and the following disclaimer.
011 * 2. Redistributions in binary form must reproduce the above copyright
012 *    notice, this list of conditions and the following disclaimer in the
013 *    documentation and/or other materials provided with the distribution.
014 * 3. Neither the name of the copyright holders nor the names of its
015 *    contributors may be used to endorse or promote products derived from
016 *    this software without specific prior written permission.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028 * THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package io.ebean.enhance.asm.commons;
031
032import io.ebean.enhance.asm.Handle;
033import io.ebean.enhance.asm.Label;
034import io.ebean.enhance.asm.MethodVisitor;
035import io.ebean.enhance.asm.Opcodes;
036
037/**
038 * A {@link MethodVisitor} that can be used to approximate method size.
039 * 
040 * @author Eugene Kuleshov
041 */
042public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
043
044    private int minSize;
045
046    private int maxSize;
047
048    public CodeSizeEvaluator(final MethodVisitor mv) {
049        this(Opcodes.ASM6, mv);
050    }
051
052    protected CodeSizeEvaluator(final int api, final MethodVisitor mv) {
053        super(api, mv);
054    }
055
056    public int getMinSize() {
057        return this.minSize;
058    }
059
060    public int getMaxSize() {
061        return this.maxSize;
062    }
063
064    @Override
065    public void visitInsn(final int opcode) {
066        minSize += 1;
067        maxSize += 1;
068        if (mv != null) {
069            mv.visitInsn(opcode);
070        }
071    }
072
073    @Override
074    public void visitIntInsn(final int opcode, final int operand) {
075        if (opcode == SIPUSH) {
076            minSize += 3;
077            maxSize += 3;
078        } else {
079            minSize += 2;
080            maxSize += 2;
081        }
082        if (mv != null) {
083            mv.visitIntInsn(opcode, operand);
084        }
085    }
086
087    @Override
088    public void visitVarInsn(final int opcode, final int var) {
089        if (var < 4 && opcode != RET) {
090            minSize += 1;
091            maxSize += 1;
092        } else if (var >= 256) {
093            minSize += 4;
094            maxSize += 4;
095        } else {
096            minSize += 2;
097            maxSize += 2;
098        }
099        if (mv != null) {
100            mv.visitVarInsn(opcode, var);
101        }
102    }
103
104    @Override
105    public void visitTypeInsn(final int opcode, final String type) {
106        minSize += 3;
107        maxSize += 3;
108        if (mv != null) {
109            mv.visitTypeInsn(opcode, type);
110        }
111    }
112
113    @Override
114    public void visitFieldInsn(final int opcode, final String owner,
115            final String name, final String desc) {
116        minSize += 3;
117        maxSize += 3;
118        if (mv != null) {
119            mv.visitFieldInsn(opcode, owner, name, desc);
120        }
121    }
122
123    @Deprecated
124    @Override
125    public void visitMethodInsn(final int opcode, final String owner,
126            final String name, final String desc) {
127        if (api >= Opcodes.ASM5) {
128            super.visitMethodInsn(opcode, owner, name, desc);
129            return;
130        }
131        doVisitMethodInsn(opcode, owner, name, desc,
132                opcode == Opcodes.INVOKEINTERFACE);
133    }
134
135    @Override
136    public void visitMethodInsn(final int opcode, final String owner,
137            final String name, final String desc, final boolean itf) {
138        if (api < Opcodes.ASM5) {
139            super.visitMethodInsn(opcode, owner, name, desc, itf);
140            return;
141        }
142        doVisitMethodInsn(opcode, owner, name, desc, itf);
143    }
144
145    private void doVisitMethodInsn(int opcode, final String owner,
146            final String name, final String desc, final boolean itf) {
147        if (opcode == INVOKEINTERFACE) {
148            minSize += 5;
149            maxSize += 5;
150        } else {
151            minSize += 3;
152            maxSize += 3;
153        }
154        if (mv != null) {
155            mv.visitMethodInsn(opcode, owner, name, desc, itf);
156        }
157    }
158
159    @Override
160    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
161            Object... bsmArgs) {
162        minSize += 5;
163        maxSize += 5;
164        if (mv != null) {
165            mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
166        }
167    }
168
169    @Override
170    public void visitJumpInsn(final int opcode, final Label label) {
171        minSize += 3;
172        if (opcode == GOTO || opcode == JSR) {
173            maxSize += 5;
174        } else {
175            maxSize += 8;
176        }
177        if (mv != null) {
178            mv.visitJumpInsn(opcode, label);
179        }
180    }
181
182    @Override
183    public void visitLdcInsn(final Object cst) {
184        if (cst instanceof Long || cst instanceof Double) {
185            minSize += 3;
186            maxSize += 3;
187        } else {
188            minSize += 2;
189            maxSize += 3;
190        }
191        if (mv != null) {
192            mv.visitLdcInsn(cst);
193        }
194    }
195
196    @Override
197    public void visitIincInsn(final int var, final int increment) {
198        if (var > 255 || increment > 127 || increment < -128) {
199            minSize += 6;
200            maxSize += 6;
201        } else {
202            minSize += 3;
203            maxSize += 3;
204        }
205        if (mv != null) {
206            mv.visitIincInsn(var, increment);
207        }
208    }
209
210    @Override
211    public void visitTableSwitchInsn(final int min, final int max,
212                                     final Label dflt, final Label... labels) {
213        minSize += 13 + labels.length * 4;
214        maxSize += 16 + labels.length * 4;
215        if (mv != null) {
216            mv.visitTableSwitchInsn(min, max, dflt, labels);
217        }
218    }
219
220    @Override
221    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
222                                      final Label[] labels) {
223        minSize += 9 + keys.length * 8;
224        maxSize += 12 + keys.length * 8;
225        if (mv != null) {
226            mv.visitLookupSwitchInsn(dflt, keys, labels);
227        }
228    }
229
230    @Override
231    public void visitMultiANewArrayInsn(final String desc, final int dims) {
232        minSize += 4;
233        maxSize += 4;
234        if (mv != null) {
235            mv.visitMultiANewArrayInsn(desc, dims);
236        }
237    }
238}