1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.  Oracle designates this
7  * particular file as subject to the "Classpath" exception as provided
8  * by Oracle in the LICENSE file that accompanied this code.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  */
24 
25 /*
26  * This file is available under and governed by the GNU General Public
27  * License version 2 only, as published by the Free Software Foundation.
28  * However, the following notice accompanied the original version of this
29  * file:
30  *
31  * ASM: a very small and fast Java bytecode manipulation framework
32  * Copyright (c) 2000-2011 INRIA, France Telecom
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  * 3. Neither the name of the copyright holders nor the names of its
44  *    contributors may be used to endorse or promote products derived from
45  *    this software without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57  * THE POSSIBILITY OF SUCH DAMAGE.
58  */
59 package jdk.internal.org.objectweb.asm.commons;
60 
61 import jdk.internal.org.objectweb.asm.Handle;
62 import jdk.internal.org.objectweb.asm.Label;
63 import jdk.internal.org.objectweb.asm.MethodVisitor;
64 import jdk.internal.org.objectweb.asm.Opcodes;
65 
66 /**
67  * A {@link MethodVisitor} that can be used to approximate method size.
68  *
69  * @author Eugene Kuleshov
70  */
71 public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
72 
73     private int minSize;
74 
75     private int maxSize;
76 
CodeSizeEvaluator(final MethodVisitor mv)77     public CodeSizeEvaluator(final MethodVisitor mv) {
78         this(Opcodes.ASM6, mv);
79     }
80 
CodeSizeEvaluator(final int api, final MethodVisitor mv)81     protected CodeSizeEvaluator(final int api, final MethodVisitor mv) {
82         super(api, mv);
83     }
84 
getMinSize()85     public int getMinSize() {
86         return this.minSize;
87     }
88 
getMaxSize()89     public int getMaxSize() {
90         return this.maxSize;
91     }
92 
93     @Override
visitInsn(final int opcode)94     public void visitInsn(final int opcode) {
95         minSize += 1;
96         maxSize += 1;
97         if (mv != null) {
98             mv.visitInsn(opcode);
99         }
100     }
101 
102     @Override
visitIntInsn(final int opcode, final int operand)103     public void visitIntInsn(final int opcode, final int operand) {
104         if (opcode == SIPUSH) {
105             minSize += 3;
106             maxSize += 3;
107         } else {
108             minSize += 2;
109             maxSize += 2;
110         }
111         if (mv != null) {
112             mv.visitIntInsn(opcode, operand);
113         }
114     }
115 
116     @Override
visitVarInsn(final int opcode, final int var)117     public void visitVarInsn(final int opcode, final int var) {
118         if (var < 4 && opcode != RET) {
119             minSize += 1;
120             maxSize += 1;
121         } else if (var >= 256) {
122             minSize += 4;
123             maxSize += 4;
124         } else {
125             minSize += 2;
126             maxSize += 2;
127         }
128         if (mv != null) {
129             mv.visitVarInsn(opcode, var);
130         }
131     }
132 
133     @Override
visitTypeInsn(final int opcode, final String type)134     public void visitTypeInsn(final int opcode, final String type) {
135         minSize += 3;
136         maxSize += 3;
137         if (mv != null) {
138             mv.visitTypeInsn(opcode, type);
139         }
140     }
141 
142     @Override
visitFieldInsn(final int opcode, final String owner, final String name, final String desc)143     public void visitFieldInsn(final int opcode, final String owner,
144             final String name, final String desc) {
145         minSize += 3;
146         maxSize += 3;
147         if (mv != null) {
148             mv.visitFieldInsn(opcode, owner, name, desc);
149         }
150     }
151 
152     @Deprecated
153     @Override
visitMethodInsn(final int opcode, final String owner, final String name, final String desc)154     public void visitMethodInsn(final int opcode, final String owner,
155             final String name, final String desc) {
156         if (api >= Opcodes.ASM5) {
157             super.visitMethodInsn(opcode, owner, name, desc);
158             return;
159         }
160         doVisitMethodInsn(opcode, owner, name, desc,
161                 opcode == Opcodes.INVOKEINTERFACE);
162     }
163 
164     @Override
visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf)165     public void visitMethodInsn(final int opcode, final String owner,
166             final String name, final String desc, final boolean itf) {
167         if (api < Opcodes.ASM5) {
168             super.visitMethodInsn(opcode, owner, name, desc, itf);
169             return;
170         }
171         doVisitMethodInsn(opcode, owner, name, desc, itf);
172     }
173 
doVisitMethodInsn(int opcode, final String owner, final String name, final String desc, final boolean itf)174     private void doVisitMethodInsn(int opcode, final String owner,
175             final String name, final String desc, final boolean itf) {
176         if (opcode == INVOKEINTERFACE) {
177             minSize += 5;
178             maxSize += 5;
179         } else {
180             minSize += 3;
181             maxSize += 3;
182         }
183         if (mv != null) {
184             mv.visitMethodInsn(opcode, owner, name, desc, itf);
185         }
186     }
187 
188     @Override
visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs)189     public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
190             Object... bsmArgs) {
191         minSize += 5;
192         maxSize += 5;
193         if (mv != null) {
194             mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
195         }
196     }
197 
198     @Override
visitJumpInsn(final int opcode, final Label label)199     public void visitJumpInsn(final int opcode, final Label label) {
200         minSize += 3;
201         if (opcode == GOTO || opcode == JSR) {
202             maxSize += 5;
203         } else {
204             maxSize += 8;
205         }
206         if (mv != null) {
207             mv.visitJumpInsn(opcode, label);
208         }
209     }
210 
211     @Override
visitLdcInsn(final Object cst)212     public void visitLdcInsn(final Object cst) {
213         if (cst instanceof Long || cst instanceof Double) {
214             minSize += 3;
215             maxSize += 3;
216         } else {
217             minSize += 2;
218             maxSize += 3;
219         }
220         if (mv != null) {
221             mv.visitLdcInsn(cst);
222         }
223     }
224 
225     @Override
visitIincInsn(final int var, final int increment)226     public void visitIincInsn(final int var, final int increment) {
227         if (var > 255 || increment > 127 || increment < -128) {
228             minSize += 6;
229             maxSize += 6;
230         } else {
231             minSize += 3;
232             maxSize += 3;
233         }
234         if (mv != null) {
235             mv.visitIincInsn(var, increment);
236         }
237     }
238 
239     @Override
visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels)240     public void visitTableSwitchInsn(final int min, final int max,
241             final Label dflt, final Label... labels) {
242         minSize += 13 + labels.length * 4;
243         maxSize += 16 + labels.length * 4;
244         if (mv != null) {
245             mv.visitTableSwitchInsn(min, max, dflt, labels);
246         }
247     }
248 
249     @Override
visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)250     public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
251             final Label[] labels) {
252         minSize += 9 + keys.length * 8;
253         maxSize += 12 + keys.length * 8;
254         if (mv != null) {
255             mv.visitLookupSwitchInsn(dflt, keys, labels);
256         }
257     }
258 
259     @Override
visitMultiANewArrayInsn(final String desc, final int dims)260     public void visitMultiANewArrayInsn(final String desc, final int dims) {
261         minSize += 4;
262         maxSize += 4;
263         if (mv != null) {
264             mv.visitMultiANewArrayInsn(desc, dims);
265         }
266     }
267 }
268