Codebase list clojure / 101dc85
Removed unused files Daigo Moriwaki 12 years ago
32 changed file(s) with 0 addition(s) and 17503 deletion(s). Raw diff Collapse all Expand all
+0
-97
src/jvm/clojure/asm/AnnotationVisitor.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * A visitor to visit a Java annotation. The methods of this interface must be
33 * called in the following order: (<tt>visit<tt> | <tt>visitEnum<tt> |
34 * <tt>visitAnnotation<tt> | <tt>visitArray<tt>)* <tt>visitEnd<tt>.
35 *
36 * @author Eric Bruneton
37 * @author Eugene Kuleshov
38 */
39 public interface AnnotationVisitor{
40
41 /**
42 * Visits a primitive value of the annotation.
43 *
44 * @param name the value name.
45 * @param value the actual value, whose type must be {@link Byte},
46 * {@link Boolean}, {@link Character}, {@link Short},
47 * {@link Integer}, {@link Long}, {@link Float}, {@link Double},
48 * {@link String} or {@link Type}. This value can also be an array
49 * of byte, boolean, short, char, int, long, float or double values
50 * (this is equivalent to using {@link #visitArray visitArray} and
51 * visiting each array element in turn, but is more convenient).
52 */
53 void visit(String name, Object value);
54
55 /**
56 * Visits an enumeration value of the annotation.
57 *
58 * @param name the value name.
59 * @param desc the class descriptor of the enumeration class.
60 * @param value the actual enumeration value.
61 */
62 void visitEnum(String name, String desc, String value);
63
64 /**
65 * Visits a nested annotation value of the annotation.
66 *
67 * @param name the value name.
68 * @param desc the class descriptor of the nested annotation class.
69 * @return a visitor to visit the actual nested annotation value, or
70 * <tt>null</tt> if this visitor is not interested in visiting
71 * this nested annotation. <i>The nested annotation value must be
72 * fully visited before calling other methods on this annotation
73 * visitor</i>.
74 */
75 AnnotationVisitor visitAnnotation(String name, String desc);
76
77 /**
78 * Visits an array value of the annotation. Note that arrays of primitive
79 * types (such as byte, boolean, short, char, int, long, float or double)
80 * can be passed as value to {@link #visit visit}. This is what
81 * {@link ClassReader} does.
82 *
83 * @param name the value name.
84 * @return a visitor to visit the actual array value elements, or
85 * <tt>null</tt> if this visitor is not interested in visiting
86 * these values. The 'name' parameters passed to the methods of this
87 * visitor are ignored. <i>All the array values must be visited
88 * before calling other methods on this annotation visitor</i>.
89 */
90 AnnotationVisitor visitArray(String name);
91
92 /**
93 * Visits the end of the annotation.
94 */
95 void visitEnd();
96 }
+0
-357
src/jvm/clojure/asm/AnnotationWriter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * An {@link AnnotationVisitor} that generates annotations in bytecode form.
33 *
34 * @author Eric Bruneton
35 * @author Eugene Kuleshov
36 */
37 final class AnnotationWriter implements AnnotationVisitor{
38
39 /**
40 * The class writer to which this annotation must be added.
41 */
42 private final ClassWriter cw;
43
44 /**
45 * The number of values in this annotation.
46 */
47 private int size;
48
49 /**
50 * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
51 * writers used for annotation default and annotation arrays use unnamed
52 * values.
53 */
54 private final boolean named;
55
56 /**
57 * The annotation values in bytecode form. This byte vector only contains
58 * the values themselves, i.e. the number of values must be stored as a
59 * unsigned short just before these bytes.
60 */
61 private final ByteVector bv;
62
63 /**
64 * The byte vector to be used to store the number of values of this
65 * annotation. See {@link #bv}.
66 */
67 private final ByteVector parent;
68
69 /**
70 * Where the number of values of this annotation must be stored in
71 * {@link #parent}.
72 */
73 private final int offset;
74
75 /**
76 * Next annotation writer. This field is used to store annotation lists.
77 */
78 AnnotationWriter next;
79
80 /**
81 * Previous annotation writer. This field is used to store annotation lists.
82 */
83 AnnotationWriter prev;
84
85 // ------------------------------------------------------------------------
86 // Constructor
87 // ------------------------------------------------------------------------
88
89 /**
90 * Constructs a new {@link AnnotationWriter}.
91 *
92 * @param cw the class writer to which this annotation must be added.
93 * @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise.
94 * @param bv where the annotation values must be stored.
95 * @param parent where the number of annotation values must be stored.
96 * @param offset where in <tt>parent</tt> the number of annotation values must
97 * be stored.
98 */
99 AnnotationWriter(
100 final ClassWriter cw,
101 final boolean named,
102 final ByteVector bv,
103 final ByteVector parent,
104 final int offset){
105 this.cw = cw;
106 this.named = named;
107 this.bv = bv;
108 this.parent = parent;
109 this.offset = offset;
110 }
111
112 // ------------------------------------------------------------------------
113 // Implementation of the AnnotationVisitor interface
114 // ------------------------------------------------------------------------
115
116 public void visit(final String name, final Object value){
117 ++size;
118 if(named)
119 {
120 bv.putShort(cw.newUTF8(name));
121 }
122 if(value instanceof String)
123 {
124 bv.put12('s', cw.newUTF8((String) value));
125 }
126 else if(value instanceof Byte)
127 {
128 bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
129 }
130 else if(value instanceof Boolean)
131 {
132 int v = ((Boolean) value).booleanValue() ? 1 : 0;
133 bv.put12('Z', cw.newInteger(v).index);
134 }
135 else if(value instanceof Character)
136 {
137 bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
138 }
139 else if(value instanceof Short)
140 {
141 bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
142 }
143 else if(value instanceof Type)
144 {
145 bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
146 }
147 else if(value instanceof byte[])
148 {
149 byte[] v = (byte[]) value;
150 bv.put12('[', v.length);
151 for(int i = 0; i < v.length; i++)
152 {
153 bv.put12('B', cw.newInteger(v[i]).index);
154 }
155 }
156 else if(value instanceof boolean[])
157 {
158 boolean[] v = (boolean[]) value;
159 bv.put12('[', v.length);
160 for(int i = 0; i < v.length; i++)
161 {
162 bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
163 }
164 }
165 else if(value instanceof short[])
166 {
167 short[] v = (short[]) value;
168 bv.put12('[', v.length);
169 for(int i = 0; i < v.length; i++)
170 {
171 bv.put12('S', cw.newInteger(v[i]).index);
172 }
173 }
174 else if(value instanceof char[])
175 {
176 char[] v = (char[]) value;
177 bv.put12('[', v.length);
178 for(int i = 0; i < v.length; i++)
179 {
180 bv.put12('C', cw.newInteger(v[i]).index);
181 }
182 }
183 else if(value instanceof int[])
184 {
185 int[] v = (int[]) value;
186 bv.put12('[', v.length);
187 for(int i = 0; i < v.length; i++)
188 {
189 bv.put12('I', cw.newInteger(v[i]).index);
190 }
191 }
192 else if(value instanceof long[])
193 {
194 long[] v = (long[]) value;
195 bv.put12('[', v.length);
196 for(int i = 0; i < v.length; i++)
197 {
198 bv.put12('J', cw.newLong(v[i]).index);
199 }
200 }
201 else if(value instanceof float[])
202 {
203 float[] v = (float[]) value;
204 bv.put12('[', v.length);
205 for(int i = 0; i < v.length; i++)
206 {
207 bv.put12('F', cw.newFloat(v[i]).index);
208 }
209 }
210 else if(value instanceof double[])
211 {
212 double[] v = (double[]) value;
213 bv.put12('[', v.length);
214 for(int i = 0; i < v.length; i++)
215 {
216 bv.put12('D', cw.newDouble(v[i]).index);
217 }
218 }
219 else
220 {
221 Item i = cw.newConstItem(value);
222 bv.put12(".s.IFJDCS".charAt(i.type), i.index);
223 }
224 }
225
226 public void visitEnum(
227 final String name,
228 final String desc,
229 final String value){
230 ++size;
231 if(named)
232 {
233 bv.putShort(cw.newUTF8(name));
234 }
235 bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
236 }
237
238 public AnnotationVisitor visitAnnotation(
239 final String name,
240 final String desc){
241 ++size;
242 if(named)
243 {
244 bv.putShort(cw.newUTF8(name));
245 }
246 // write tag and type, and reserve space for values count
247 bv.put12('@', cw.newUTF8(desc)).putShort(0);
248 return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
249 }
250
251 public AnnotationVisitor visitArray(final String name){
252 ++size;
253 if(named)
254 {
255 bv.putShort(cw.newUTF8(name));
256 }
257 // write tag, and reserve space for array size
258 bv.put12('[', 0);
259 return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
260 }
261
262 public void visitEnd(){
263 if(parent != null)
264 {
265 byte[] data = parent.data;
266 data[offset] = (byte) (size >>> 8);
267 data[offset + 1] = (byte) size;
268 }
269 }
270
271 // ------------------------------------------------------------------------
272 // Utility methods
273 // ------------------------------------------------------------------------
274
275 /**
276 * Returns the size of this annotation writer list.
277 *
278 * @return the size of this annotation writer list.
279 */
280 int getSize(){
281 int size = 0;
282 AnnotationWriter aw = this;
283 while(aw != null)
284 {
285 size += aw.bv.length;
286 aw = aw.next;
287 }
288 return size;
289 }
290
291 /**
292 * Puts the annotations of this annotation writer list into the given byte
293 * vector.
294 *
295 * @param out where the annotations must be put.
296 */
297 void put(final ByteVector out){
298 int n = 0;
299 int size = 2;
300 AnnotationWriter aw = this;
301 AnnotationWriter last = null;
302 while(aw != null)
303 {
304 ++n;
305 size += aw.bv.length;
306 aw.visitEnd(); // in case user forgot to call visitEnd
307 aw.prev = last;
308 last = aw;
309 aw = aw.next;
310 }
311 out.putInt(size);
312 out.putShort(n);
313 aw = last;
314 while(aw != null)
315 {
316 out.putByteArray(aw.bv.data, 0, aw.bv.length);
317 aw = aw.prev;
318 }
319 }
320
321 /**
322 * Puts the given annotation lists into the given byte vector.
323 *
324 * @param panns an array of annotation writer lists.
325 * @param out where the annotations must be put.
326 */
327 static void put(final AnnotationWriter[] panns, final ByteVector out){
328 int size = 1 + 2 * panns.length;
329 for(int i = 0; i < panns.length; ++i)
330 {
331 size += panns[i] == null ? 0 : panns[i].getSize();
332 }
333 out.putInt(size).putByte(panns.length);
334 for(int i = 0; i < panns.length; ++i)
335 {
336 AnnotationWriter aw = panns[i];
337 AnnotationWriter last = null;
338 int n = 0;
339 while(aw != null)
340 {
341 ++n;
342 aw.visitEnd(); // in case user forgot to call visitEnd
343 aw.prev = last;
344 last = aw;
345 aw = aw.next;
346 }
347 out.putShort(n);
348 aw = last;
349 while(aw != null)
350 {
351 out.putByteArray(aw.bv.data, 0, aw.bv.length);
352 aw = aw.prev;
353 }
354 }
355 }
356 }
+0
-253
src/jvm/clojure/asm/Attribute.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * A non standard class, field, method or code attribute.
33 *
34 * @author Eric Bruneton
35 * @author Eugene Kuleshov
36 */
37 public class Attribute{
38
39 /**
40 * The type of this attribute.
41 */
42 public final String type;
43
44 /**
45 * The raw value of this attribute, used only for unknown attributes.
46 */
47 byte[] value;
48
49 /**
50 * The next attribute in this attribute list. May be <tt>null</tt>.
51 */
52 Attribute next;
53
54 /**
55 * Constructs a new empty attribute.
56 *
57 * @param type the type of the attribute.
58 */
59 protected Attribute(final String type){
60 this.type = type;
61 }
62
63 /**
64 * Returns <tt>true</tt> if this type of attribute is unknown. The default
65 * implementation of this method always returns <tt>true</tt>.
66 *
67 * @return <tt>true</tt> if this type of attribute is unknown.
68 */
69 public boolean isUnknown(){
70 return true;
71 }
72
73 /**
74 * Returns <tt>true</tt> if this type of attribute is a code attribute.
75 *
76 * @return <tt>true</tt> if this type of attribute is a code attribute.
77 */
78 public boolean isCodeAttribute(){
79 return false;
80 }
81
82 /**
83 * Returns the labels corresponding to this attribute.
84 *
85 * @return the labels corresponding to this attribute, or <tt>null</tt> if
86 * this attribute is not a code attribute that contains labels.
87 */
88 protected Label[] getLabels(){
89 return null;
90 }
91
92 /**
93 * Reads a {@link #type type} attribute. This method must return a <i>new</i>
94 * {@link Attribute} object, of type {@link #type type}, corresponding to
95 * the <tt>len</tt> bytes starting at the given offset, in the given class
96 * reader.
97 *
98 * @param cr the class that contains the attribute to be read.
99 * @param off index of the first byte of the attribute's content in {@link
100 * ClassReader#b cr.b}. The 6 attribute header bytes, containing the
101 * type and the length of the attribute, are not taken into account
102 * here.
103 * @param len the length of the attribute's content.
104 * @param buf buffer to be used to call
105 * {@link ClassReader#readUTF8 readUTF8},
106 * {@link ClassReader#readClass(int,char[]) readClass} or
107 * {@link ClassReader#readConst readConst}.
108 * @param codeOff index of the first byte of code's attribute content in
109 * {@link ClassReader#b cr.b}, or -1 if the attribute to be read is
110 * not a code attribute. The 6 attribute header bytes, containing the
111 * type and the length of the attribute, are not taken into account
112 * here.
113 * @param labels the labels of the method's code, or <tt>null</tt> if the
114 * attribute to be read is not a code attribute.
115 * @return a <i>new</i> {@link Attribute} object corresponding to the given
116 * bytes.
117 */
118 protected Attribute read(
119 final ClassReader cr,
120 final int off,
121 final int len,
122 final char[] buf,
123 final int codeOff,
124 final Label[] labels){
125 Attribute attr = new Attribute(type);
126 attr.value = new byte[len];
127 System.arraycopy(cr.b, off, attr.value, 0, len);
128 return attr;
129 }
130
131 /**
132 * Returns the byte array form of this attribute.
133 *
134 * @param cw the class to which this attribute must be added. This parameter
135 * can be used to add to the constant pool of this class the items
136 * that corresponds to this attribute.
137 * @param code the bytecode of the method corresponding to this code
138 * attribute, or <tt>null</tt> if this attribute is not a code
139 * attributes.
140 * @param len the length of the bytecode of the method corresponding to this
141 * code attribute, or <tt>null</tt> if this attribute is not a code
142 * attribute.
143 * @param maxStack the maximum stack size of the method corresponding to
144 * this code attribute, or -1 if this attribute is not a code
145 * attribute.
146 * @param maxLocals the maximum number of local variables of the method
147 * corresponding to this code attribute, or -1 if this attribute is
148 * not a code attribute.
149 * @return the byte array form of this attribute.
150 */
151 protected ByteVector write(
152 final ClassWriter cw,
153 final byte[] code,
154 final int len,
155 final int maxStack,
156 final int maxLocals){
157 ByteVector v = new ByteVector();
158 v.data = value;
159 v.length = value.length;
160 return v;
161 }
162
163 /**
164 * Returns the length of the attribute list that begins with this attribute.
165 *
166 * @return the length of the attribute list that begins with this attribute.
167 */
168 final int getCount(){
169 int count = 0;
170 Attribute attr = this;
171 while(attr != null)
172 {
173 count += 1;
174 attr = attr.next;
175 }
176 return count;
177 }
178
179 /**
180 * Returns the size of all the attributes in this attribute list.
181 *
182 * @param cw the class writer to be used to convert the attributes into byte
183 * arrays, with the {@link #write write} method.
184 * @param code the bytecode of the method corresponding to these code
185 * attributes, or <tt>null</tt> if these attributes are not code
186 * attributes.
187 * @param len the length of the bytecode of the method corresponding to
188 * these code attributes, or <tt>null</tt> if these attributes are
189 * not code attributes.
190 * @param maxStack the maximum stack size of the method corresponding to
191 * these code attributes, or -1 if these attributes are not code
192 * attributes.
193 * @param maxLocals the maximum number of local variables of the method
194 * corresponding to these code attributes, or -1 if these attributes
195 * are not code attributes.
196 * @return the size of all the attributes in this attribute list. This size
197 * includes the size of the attribute headers.
198 */
199 final int getSize(
200 final ClassWriter cw,
201 final byte[] code,
202 final int len,
203 final int maxStack,
204 final int maxLocals){
205 Attribute attr = this;
206 int size = 0;
207 while(attr != null)
208 {
209 cw.newUTF8(attr.type);
210 size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
211 attr = attr.next;
212 }
213 return size;
214 }
215
216 /**
217 * Writes all the attributes of this attribute list in the given byte
218 * vector.
219 *
220 * @param cw the class writer to be used to convert the attributes into byte
221 * arrays, with the {@link #write write} method.
222 * @param code the bytecode of the method corresponding to these code
223 * attributes, or <tt>null</tt> if these attributes are not code
224 * attributes.
225 * @param len the length of the bytecode of the method corresponding to
226 * these code attributes, or <tt>null</tt> if these attributes are
227 * not code attributes.
228 * @param maxStack the maximum stack size of the method corresponding to
229 * these code attributes, or -1 if these attributes are not code
230 * attributes.
231 * @param maxLocals the maximum number of local variables of the method
232 * corresponding to these code attributes, or -1 if these attributes
233 * are not code attributes.
234 * @param out where the attributes must be written.
235 */
236 final void put(
237 final ClassWriter cw,
238 final byte[] code,
239 final int len,
240 final int maxStack,
241 final int maxLocals,
242 final ByteVector out){
243 Attribute attr = this;
244 while(attr != null)
245 {
246 ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
247 out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
248 out.putByteArray(b.data, 0, b.length);
249 attr = attr.next;
250 }
251 }
252 }
+0
-318
src/jvm/clojure/asm/ByteVector.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * A dynamically extensible vector of bytes. This class is roughly equivalent to
33 * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
34 *
35 * @author Eric Bruneton
36 */
37 public class ByteVector{
38
39 /**
40 * The content of this vector.
41 */
42 byte[] data;
43
44 /**
45 * Actual number of bytes in this vector.
46 */
47 int length;
48
49 /**
50 * Constructs a new {@link ByteVector ByteVector} with a default initial
51 * size.
52 */
53 public ByteVector(){
54 data = new byte[64];
55 }
56
57 /**
58 * Constructs a new {@link ByteVector ByteVector} with the given initial
59 * size.
60 *
61 * @param initialSize the initial size of the byte vector to be constructed.
62 */
63 public ByteVector(final int initialSize){
64 data = new byte[initialSize];
65 }
66
67 /**
68 * Puts a byte into this byte vector. The byte vector is automatically
69 * enlarged if necessary.
70 *
71 * @param b a byte.
72 * @return this byte vector.
73 */
74 public ByteVector putByte(final int b){
75 int length = this.length;
76 if(length + 1 > data.length)
77 {
78 enlarge(1);
79 }
80 data[length++] = (byte) b;
81 this.length = length;
82 return this;
83 }
84
85 /**
86 * Puts two bytes into this byte vector. The byte vector is automatically
87 * enlarged if necessary.
88 *
89 * @param b1 a byte.
90 * @param b2 another byte.
91 * @return this byte vector.
92 */
93 ByteVector put11(final int b1, final int b2){
94 int length = this.length;
95 if(length + 2 > data.length)
96 {
97 enlarge(2);
98 }
99 byte[] data = this.data;
100 data[length++] = (byte) b1;
101 data[length++] = (byte) b2;
102 this.length = length;
103 return this;
104 }
105
106 /**
107 * Puts a short into this byte vector. The byte vector is automatically
108 * enlarged if necessary.
109 *
110 * @param s a short.
111 * @return this byte vector.
112 */
113 public ByteVector putShort(final int s){
114 int length = this.length;
115 if(length + 2 > data.length)
116 {
117 enlarge(2);
118 }
119 byte[] data = this.data;
120 data[length++] = (byte) (s >>> 8);
121 data[length++] = (byte) s;
122 this.length = length;
123 return this;
124 }
125
126 /**
127 * Puts a byte and a short into this byte vector. The byte vector is
128 * automatically enlarged if necessary.
129 *
130 * @param b a byte.
131 * @param s a short.
132 * @return this byte vector.
133 */
134 ByteVector put12(final int b, final int s){
135 int length = this.length;
136 if(length + 3 > data.length)
137 {
138 enlarge(3);
139 }
140 byte[] data = this.data;
141 data[length++] = (byte) b;
142 data[length++] = (byte) (s >>> 8);
143 data[length++] = (byte) s;
144 this.length = length;
145 return this;
146 }
147
148 /**
149 * Puts an int into this byte vector. The byte vector is automatically
150 * enlarged if necessary.
151 *
152 * @param i an int.
153 * @return this byte vector.
154 */
155 public ByteVector putInt(final int i){
156 int length = this.length;
157 if(length + 4 > data.length)
158 {
159 enlarge(4);
160 }
161 byte[] data = this.data;
162 data[length++] = (byte) (i >>> 24);
163 data[length++] = (byte) (i >>> 16);
164 data[length++] = (byte) (i >>> 8);
165 data[length++] = (byte) i;
166 this.length = length;
167 return this;
168 }
169
170 /**
171 * Puts a long into this byte vector. The byte vector is automatically
172 * enlarged if necessary.
173 *
174 * @param l a long.
175 * @return this byte vector.
176 */
177 public ByteVector putLong(final long l){
178 int length = this.length;
179 if(length + 8 > data.length)
180 {
181 enlarge(8);
182 }
183 byte[] data = this.data;
184 int i = (int) (l >>> 32);
185 data[length++] = (byte) (i >>> 24);
186 data[length++] = (byte) (i >>> 16);
187 data[length++] = (byte) (i >>> 8);
188 data[length++] = (byte) i;
189 i = (int) l;
190 data[length++] = (byte) (i >>> 24);
191 data[length++] = (byte) (i >>> 16);
192 data[length++] = (byte) (i >>> 8);
193 data[length++] = (byte) i;
194 this.length = length;
195 return this;
196 }
197
198 /**
199 * Puts an UTF8 string into this byte vector. The byte vector is
200 * automatically enlarged if necessary.
201 *
202 * @param s a String.
203 * @return this byte vector.
204 */
205 public ByteVector putUTF8(final String s){
206 int charLength = s.length();
207 if(length + 2 + charLength > data.length)
208 {
209 enlarge(2 + charLength);
210 }
211 int len = length;
212 byte[] data = this.data;
213 // optimistic algorithm: instead of computing the byte length and then
214 // serializing the string (which requires two loops), we assume the byte
215 // length is equal to char length (which is the most frequent case), and
216 // we start serializing the string right away. During the serialization,
217 // if we find that this assumption is wrong, we continue with the
218 // general method.
219 data[len++] = (byte) (charLength >>> 8);
220 data[len++] = (byte) charLength;
221 for(int i = 0; i < charLength; ++i)
222 {
223 char c = s.charAt(i);
224 if(c >= '\001' && c <= '\177')
225 {
226 data[len++] = (byte) c;
227 }
228 else
229 {
230 int byteLength = i;
231 for(int j = i; j < charLength; ++j)
232 {
233 c = s.charAt(j);
234 if(c >= '\001' && c <= '\177')
235 {
236 byteLength++;
237 }
238 else if(c > '\u07FF')
239 {
240 byteLength += 3;
241 }
242 else
243 {
244 byteLength += 2;
245 }
246 }
247 data[length] = (byte) (byteLength >>> 8);
248 data[length + 1] = (byte) byteLength;
249 if(length + 2 + byteLength > data.length)
250 {
251 length = len;
252 enlarge(2 + byteLength);
253 data = this.data;
254 }
255 for(int j = i; j < charLength; ++j)
256 {
257 c = s.charAt(j);
258 if(c >= '\001' && c <= '\177')
259 {
260 data[len++] = (byte) c;
261 }
262 else if(c > '\u07FF')
263 {
264 data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
265 data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
266 data[len++] = (byte) (0x80 | c & 0x3F);
267 }
268 else
269 {
270 data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
271 data[len++] = (byte) (0x80 | c & 0x3F);
272 }
273 }
274 break;
275 }
276 }
277 length = len;
278 return this;
279 }
280
281 /**
282 * Puts an array of bytes into this byte vector. The byte vector is
283 * automatically enlarged if necessary.
284 *
285 * @param b an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
286 * null bytes into this byte vector.
287 * @param off index of the fist byte of b that must be copied.
288 * @param len number of bytes of b that must be copied.
289 * @return this byte vector.
290 */
291 public ByteVector putByteArray(final byte[] b, final int off, final int len){
292 if(length + len > data.length)
293 {
294 enlarge(len);
295 }
296 if(b != null)
297 {
298 System.arraycopy(b, off, data, length, len);
299 }
300 length += len;
301 return this;
302 }
303
304 /**
305 * Enlarge this byte vector so that it can receive n more bytes.
306 *
307 * @param size number of additional bytes that this byte vector should be
308 * able to receive.
309 */
310 private void enlarge(final int size){
311 int length1 = 2 * data.length;
312 int length2 = length + size;
313 byte[] newData = new byte[length1 > length2 ? length1 : length2];
314 System.arraycopy(data, 0, newData, 0, length);
315 data = newData;
316 }
317 }
+0
-115
src/jvm/clojure/asm/ClassAdapter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * An empty {@link ClassVisitor} that delegates to another {@link ClassVisitor}.
33 * This class can be used as a super class to quickly implement usefull class
34 * adapter classes, just by overriding the necessary methods.
35 *
36 * @author Eric Bruneton
37 */
38 public class ClassAdapter implements ClassVisitor{
39
40 /**
41 * The {@link ClassVisitor} to which this adapter delegates calls.
42 */
43 protected ClassVisitor cv;
44
45 /**
46 * Constructs a new {@link ClassAdapter} object.
47 *
48 * @param cv the class visitor to which this adapter must delegate calls.
49 */
50 public ClassAdapter(final ClassVisitor cv){
51 this.cv = cv;
52 }
53
54 public void visit(
55 final int version,
56 final int access,
57 final String name,
58 final String signature,
59 final String superName,
60 final String[] interfaces){
61 cv.visit(version, access, name, signature, superName, interfaces);
62 }
63
64 public void visitSource(final String source, final String debug){
65 cv.visitSource(source, debug);
66 }
67
68 public void visitOuterClass(
69 final String owner,
70 final String name,
71 final String desc){
72 cv.visitOuterClass(owner, name, desc);
73 }
74
75 public AnnotationVisitor visitAnnotation(
76 final String desc,
77 final boolean visible){
78 return cv.visitAnnotation(desc, visible);
79 }
80
81 public void visitAttribute(final Attribute attr){
82 cv.visitAttribute(attr);
83 }
84
85 public void visitInnerClass(
86 final String name,
87 final String outerName,
88 final String innerName,
89 final int access){
90 cv.visitInnerClass(name, outerName, innerName, access);
91 }
92
93 public FieldVisitor visitField(
94 final int access,
95 final String name,
96 final String desc,
97 final String signature,
98 final Object value){
99 return cv.visitField(access, name, desc, signature, value);
100 }
101
102 public MethodVisitor visitMethod(
103 final int access,
104 final String name,
105 final String desc,
106 final String signature,
107 final String[] exceptions){
108 return cv.visitMethod(access, name, desc, signature, exceptions);
109 }
110
111 public void visitEnd(){
112 cv.visitEnd();
113 }
114 }
+0
-2224
src/jvm/clojure/asm/ClassReader.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 import java.io.InputStream;
32 import java.io.IOException;
33
34 /**
35 * A Java class parser to make a {@link ClassVisitor} visit an existing class.
36 * This class parses a byte array conforming to the Java class file format and
37 * calls the appropriate visit methods of a given class visitor for each field,
38 * method and bytecode instruction encountered.
39 *
40 * @author Eric Bruneton
41 * @author Eugene Kuleshov
42 */
43 public class ClassReader{
44
45 /**
46 * Flag to skip method code. If this class is set <code>CODE</code>
47 * attribute won't be visited. This can be used, for example, to retrieve
48 * annotations for methods and method parameters.
49 */
50 public final static int SKIP_CODE = 1;
51
52 /**
53 * Flag to skip the debug information in the class. If this flag is set the
54 * debug information of the class is not visited, i.e. the
55 * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
56 * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be
57 * called.
58 */
59 public final static int SKIP_DEBUG = 2;
60
61 /**
62 * Flag to skip the stack map frames in the class. If this flag is set the
63 * stack map frames of the class is not visited, i.e. the
64 * {@link MethodVisitor#visitFrame visitFrame} method will not be called.
65 * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is
66 * used: it avoids visiting frames that will be ignored and recomputed from
67 * scratch in the class writer.
68 */
69 public final static int SKIP_FRAMES = 4;
70
71 /**
72 * Flag to expand the stack map frames. By default stack map frames are
73 * visited in their original format (i.e. "expanded" for classes whose
74 * version is less than V1_6, and "compressed" for the other classes). If
75 * this flag is set, stack map frames are always visited in expanded format
76 * (this option adds a decompression/recompression step in ClassReader and
77 * ClassWriter which degrades performances quite a lot).
78 */
79 public final static int EXPAND_FRAMES = 8;
80
81 /**
82 * The class to be parsed. <i>The content of this array must not be
83 * modified. This field is intended for {@link Attribute} sub classes, and
84 * is normally not needed by class generators or adapters.</i>
85 */
86 public final byte[] b;
87
88 /**
89 * The start index of each constant pool item in {@link #b b}, plus one.
90 * The one byte offset skips the constant pool item tag that indicates its
91 * type.
92 */
93 private final int[] items;
94
95 /**
96 * The String objects corresponding to the CONSTANT_Utf8 items. This cache
97 * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,
98 * which GREATLY improves performances (by a factor 2 to 3). This caching
99 * strategy could be extended to all constant pool items, but its benefit
100 * would not be so great for these items (because they are much less
101 * expensive to parse than CONSTANT_Utf8 items).
102 */
103 private final String[] strings;
104
105 /**
106 * Maximum length of the strings contained in the constant pool of the
107 * class.
108 */
109 private final int maxStringLength;
110
111 /**
112 * Start index of the class header information (access, name...) in
113 * {@link #b b}.
114 */
115 public final int header;
116
117 // ------------------------------------------------------------------------
118 // Constructors
119 // ------------------------------------------------------------------------
120
121 /**
122 * Constructs a new {@link ClassReader} object.
123 *
124 * @param b the bytecode of the class to be read.
125 */
126 public ClassReader(final byte[] b){
127 this(b, 0, b.length);
128 }
129
130 /**
131 * Constructs a new {@link ClassReader} object.
132 *
133 * @param b the bytecode of the class to be read.
134 * @param off the start offset of the class data.
135 * @param len the length of the class data.
136 */
137 public ClassReader(final byte[] b, final int off, final int len){
138 this.b = b;
139 // parses the constant pool
140 items = new int[readUnsignedShort(off + 8)];
141 int n = items.length;
142 strings = new String[n];
143 int max = 0;
144 int index = off + 10;
145 for(int i = 1; i < n; ++i)
146 {
147 items[i] = index + 1;
148 int size;
149 switch(b[index])
150 {
151 case ClassWriter.FIELD:
152 case ClassWriter.METH:
153 case ClassWriter.IMETH:
154 case ClassWriter.INT:
155 case ClassWriter.FLOAT:
156 case ClassWriter.NAME_TYPE:
157 size = 5;
158 break;
159 case ClassWriter.LONG:
160 case ClassWriter.DOUBLE:
161 size = 9;
162 ++i;
163 break;
164 case ClassWriter.UTF8:
165 size = 3 + readUnsignedShort(index + 1);
166 if(size > max)
167 {
168 max = size;
169 }
170 break;
171 // case ClassWriter.CLASS:
172 // case ClassWriter.STR:
173 default:
174 size = 3;
175 break;
176 }
177 index += size;
178 }
179 maxStringLength = max;
180 // the class header information starts just after the constant pool
181 header = index;
182 }
183
184 /**
185 * Returns the class's access flags (see {@link Opcodes}). This value may
186 * not reflect Deprecated and Synthetic flags when bytecode is before 1.5
187 * and those flags are represented by attributes.
188 *
189 * @return the class access flags
190 * @see ClassVisitor#visit(int,int,String,String,String,String[])
191 */
192 public int getAccess(){
193 return readUnsignedShort(header);
194 }
195
196 /**
197 * Returns the internal name of the class (see
198 * {@link Type#getInternalName() getInternalName}).
199 *
200 * @return the internal class name
201 * @see ClassVisitor#visit(int,int,String,String,String,String[])
202 */
203 public String getClassName(){
204 return readClass(header + 2, new char[maxStringLength]);
205 }
206
207 /**
208 * Returns the internal of name of the super class (see
209 * {@link Type#getInternalName() getInternalName}). For interfaces, the
210 * super class is {@link Object}.
211 *
212 * @return the internal name of super class, or <tt>null</tt> for
213 * {@link Object} class.
214 * @see ClassVisitor#visit(int,int,String,String,String,String[])
215 */
216 public String getSuperName(){
217 int n = items[readUnsignedShort(header + 4)];
218 return n == 0 ? null : readUTF8(n, new char[maxStringLength]);
219 }
220
221 /**
222 * Returns the internal names of the class's interfaces (see
223 * {@link Type#getInternalName() getInternalName}).
224 *
225 * @return the array of internal names for all implemented interfaces or
226 * <tt>null</tt>.
227 * @see ClassVisitor#visit(int,int,String,String,String,String[])
228 */
229 public String[] getInterfaces(){
230 int index = header + 6;
231 int n = readUnsignedShort(index);
232 String[] interfaces = new String[n];
233 if(n > 0)
234 {
235 char[] buf = new char[maxStringLength];
236 for(int i = 0; i < n; ++i)
237 {
238 index += 2;
239 interfaces[i] = readClass(index, buf);
240 }
241 }
242 return interfaces;
243 }
244
245 /**
246 * Copies the constant pool data into the given {@link ClassWriter}. Should
247 * be called before the {@link #accept(ClassVisitor,int)} method.
248 *
249 * @param classWriter the {@link ClassWriter} to copy constant pool into.
250 */
251 void copyPool(final ClassWriter classWriter){
252 char[] buf = new char[maxStringLength];
253 int ll = items.length;
254 Item[] items2 = new Item[ll];
255 for(int i = 1; i < ll; i++)
256 {
257 int index = items[i];
258 int tag = b[index - 1];
259 Item item = new Item(i);
260 int nameType;
261 switch(tag)
262 {
263 case ClassWriter.FIELD:
264 case ClassWriter.METH:
265 case ClassWriter.IMETH:
266 nameType = items[readUnsignedShort(index + 2)];
267 item.set(tag,
268 readClass(index, buf),
269 readUTF8(nameType, buf),
270 readUTF8(nameType + 2, buf));
271 break;
272
273 case ClassWriter.INT:
274 item.set(readInt(index));
275 break;
276
277 case ClassWriter.FLOAT:
278 item.set(Float.intBitsToFloat(readInt(index)));
279 break;
280
281 case ClassWriter.NAME_TYPE:
282 item.set(tag,
283 readUTF8(index, buf),
284 readUTF8(index + 2, buf),
285 null);
286 break;
287
288 case ClassWriter.LONG:
289 item.set(readLong(index));
290 ++i;
291 break;
292
293 case ClassWriter.DOUBLE:
294 item.set(Double.longBitsToDouble(readLong(index)));
295 ++i;
296 break;
297
298 case ClassWriter.UTF8:
299 {
300 String s = strings[i];
301 if(s == null)
302 {
303 index = items[i];
304 s = strings[i] = readUTF(index + 2,
305 readUnsignedShort(index),
306 buf);
307 }
308 item.set(tag, s, null, null);
309 }
310 break;
311
312 // case ClassWriter.STR:
313 // case ClassWriter.CLASS:
314 default:
315 item.set(tag, readUTF8(index, buf), null, null);
316 break;
317 }
318
319 int index2 = item.hashCode % items2.length;
320 item.next = items2[index2];
321 items2[index2] = item;
322 }
323
324 int off = items[1] - 1;
325 classWriter.pool.putByteArray(b, off, header - off);
326 classWriter.items = items2;
327 classWriter.threshold = (int) (0.75d * ll);
328 classWriter.index = ll;
329 }
330
331 /**
332 * Constructs a new {@link ClassReader} object.
333 *
334 * @param is an input stream from which to read the class.
335 * @throws IOException if a problem occurs during reading.
336 */
337 public ClassReader(final InputStream is) throws IOException{
338 this(readClass(is));
339 }
340
341 /**
342 * Constructs a new {@link ClassReader} object.
343 *
344 * @param name the fully qualified name of the class to be read.
345 * @throws IOException if an exception occurs during reading.
346 */
347 public ClassReader(final String name) throws IOException{
348 this(ClassLoader.getSystemResourceAsStream(name.replace('.', '/')
349 + ".class"));
350 }
351
352 /**
353 * Reads the bytecode of a class.
354 *
355 * @param is an input stream from which to read the class.
356 * @return the bytecode read from the given input stream.
357 * @throws IOException if a problem occurs during reading.
358 */
359 private static byte[] readClass(final InputStream is) throws IOException{
360 if(is == null)
361 {
362 throw new IOException("Class not found");
363 }
364 byte[] b = new byte[is.available()];
365 int len = 0;
366 while(true)
367 {
368 int n = is.read(b, len, b.length - len);
369 if(n == -1)
370 {
371 if(len < b.length)
372 {
373 byte[] c = new byte[len];
374 System.arraycopy(b, 0, c, 0, len);
375 b = c;
376 }
377 return b;
378 }
379 len += n;
380 if(len == b.length)
381 {
382 byte[] c = new byte[b.length + 1000];
383 System.arraycopy(b, 0, c, 0, len);
384 b = c;
385 }
386 }
387 }
388
389 // ------------------------------------------------------------------------
390 // Public methods
391 // ------------------------------------------------------------------------
392
393 /**
394 * Makes the given visitor visit the Java class of this {@link ClassReader}.
395 * This class is the one specified in the constructor (see
396 * {@link #ClassReader(byte[]) ClassReader}).
397 *
398 * @param classVisitor the visitor that must visit this class.
399 * @param flags option flags that can be used to modify the default behavior
400 * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}.
401 */
402 public void accept(final ClassVisitor classVisitor, final int flags){
403 accept(classVisitor, new Attribute[0], flags);
404 }
405
406 /**
407 * Makes the given visitor visit the Java class of this {@link ClassReader}.
408 * This class is the one specified in the constructor (see
409 * {@link #ClassReader(byte[]) ClassReader}).
410 *
411 * @param classVisitor the visitor that must visit this class.
412 * @param attrs prototypes of the attributes that must be parsed during the
413 * visit of the class. Any attribute whose type is not equal to the
414 * type of one the prototypes will not be parsed: its byte array
415 * value will be passed unchanged to the ClassWriter. <i>This may
416 * corrupt it if this value contains references to the constant pool,
417 * or has syntactic or semantic links with a class element that has
418 * been transformed by a class adapter between the reader and the
419 * writer</i>.
420 * @param flags option flags that can be used to modify the default behavior
421 * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}.
422 */
423 public void accept(
424 final ClassVisitor classVisitor,
425 final Attribute[] attrs,
426 final int flags){
427 byte[] b = this.b; // the bytecode array
428 char[] c = new char[maxStringLength]; // buffer used to read strings
429 int i, j, k; // loop variables
430 int u, v, w; // indexes in b
431 Attribute attr;
432
433 int access;
434 String name;
435 String desc;
436 String attrName;
437 String signature;
438 int anns = 0;
439 int ianns = 0;
440 Attribute cattrs = null;
441
442 // visits the header
443 u = header;
444 access = readUnsignedShort(u);
445 name = readClass(u + 2, c);
446 v = items[readUnsignedShort(u + 4)];
447 String superClassName = v == 0 ? null : readUTF8(v, c);
448 String[] implementedItfs = new String[readUnsignedShort(u + 6)];
449 w = 0;
450 u += 8;
451 for(i = 0; i < implementedItfs.length; ++i)
452 {
453 implementedItfs[i] = readClass(u, c);
454 u += 2;
455 }
456
457 boolean skipCode = (flags & SKIP_CODE) != 0;
458 boolean skipDebug = (flags & SKIP_DEBUG) != 0;
459 boolean unzip = (flags & EXPAND_FRAMES) != 0;
460
461 // skips fields and methods
462 v = u;
463 i = readUnsignedShort(v);
464 v += 2;
465 for(; i > 0; --i)
466 {
467 j = readUnsignedShort(v + 6);
468 v += 8;
469 for(; j > 0; --j)
470 {
471 v += 6 + readInt(v + 2);
472 }
473 }
474 i = readUnsignedShort(v);
475 v += 2;
476 for(; i > 0; --i)
477 {
478 j = readUnsignedShort(v + 6);
479 v += 8;
480 for(; j > 0; --j)
481 {
482 v += 6 + readInt(v + 2);
483 }
484 }
485 // reads the class's attributes
486 signature = null;
487 String sourceFile = null;
488 String sourceDebug = null;
489 String enclosingOwner = null;
490 String enclosingName = null;
491 String enclosingDesc = null;
492
493 i = readUnsignedShort(v);
494 v += 2;
495 for(; i > 0; --i)
496 {
497 attrName = readUTF8(v, c);
498 // tests are sorted in decreasing frequency order
499 // (based on frequencies observed on typical classes)
500 if(attrName.equals("SourceFile"))
501 {
502 sourceFile = readUTF8(v + 6, c);
503 }
504 else if(attrName.equals("InnerClasses"))
505 {
506 w = v + 6;
507 }
508 else if(attrName.equals("EnclosingMethod"))
509 {
510 enclosingOwner = readClass(v + 6, c);
511 int item = readUnsignedShort(v + 8);
512 if(item != 0)
513 {
514 enclosingName = readUTF8(items[item], c);
515 enclosingDesc = readUTF8(items[item] + 2, c);
516 }
517 }
518 else if(attrName.equals("Signature"))
519 {
520 signature = readUTF8(v + 6, c);
521 }
522 else if(attrName.equals("RuntimeVisibleAnnotations"))
523 {
524 anns = v + 6;
525 }
526 else if(attrName.equals("Deprecated"))
527 {
528 access |= Opcodes.ACC_DEPRECATED;
529 }
530 else if(attrName.equals("Synthetic"))
531 {
532 access |= Opcodes.ACC_SYNTHETIC;
533 }
534 else if(attrName.equals("SourceDebugExtension"))
535 {
536 int len = readInt(v + 2);
537 sourceDebug = readUTF(v + 6, len, new char[len]);
538 }
539 else if(attrName.equals("RuntimeInvisibleAnnotations"))
540 {
541 ianns = v + 6;
542 }
543 else
544 {
545 attr = readAttribute(attrs,
546 attrName,
547 v + 6,
548 readInt(v + 2),
549 c,
550 -1,
551 null);
552 if(attr != null)
553 {
554 attr.next = cattrs;
555 cattrs = attr;
556 }
557 }
558 v += 6 + readInt(v + 2);
559 }
560 // calls the visit method
561 classVisitor.visit(readInt(4),
562 access,
563 name,
564 signature,
565 superClassName,
566 implementedItfs);
567
568 // calls the visitSource method
569 if(!skipDebug && (sourceFile != null || sourceDebug != null))
570 {
571 classVisitor.visitSource(sourceFile, sourceDebug);
572 }
573
574 // calls the visitOuterClass method
575 if(enclosingOwner != null)
576 {
577 classVisitor.visitOuterClass(enclosingOwner,
578 enclosingName,
579 enclosingDesc);
580 }
581
582 // visits the class annotations
583 for(i = 1; i >= 0; --i)
584 {
585 v = i == 0 ? ianns : anns;
586 if(v != 0)
587 {
588 j = readUnsignedShort(v);
589 v += 2;
590 for(; j > 0; --j)
591 {
592 v = readAnnotationValues(v + 2,
593 c,
594 true,
595 classVisitor.visitAnnotation(readUTF8(v, c), i != 0));
596 }
597 }
598 }
599
600 // visits the class attributes
601 while(cattrs != null)
602 {
603 attr = cattrs.next;
604 cattrs.next = null;
605 classVisitor.visitAttribute(cattrs);
606 cattrs = attr;
607 }
608
609 // calls the visitInnerClass method
610 if(w != 0)
611 {
612 i = readUnsignedShort(w);
613 w += 2;
614 for(; i > 0; --i)
615 {
616 classVisitor.visitInnerClass(readUnsignedShort(w) == 0
617 ? null
618 : readClass(w, c), readUnsignedShort(w + 2) == 0
619 ? null
620 : readClass(w + 2, c), readUnsignedShort(w + 4) == 0
621 ? null
622 : readUTF8(w + 4, c),
623 readUnsignedShort(w + 6));
624 w += 8;
625 }
626 }
627
628 // visits the fields
629 i = readUnsignedShort(u);
630 u += 2;
631 for(; i > 0; --i)
632 {
633 access = readUnsignedShort(u);
634 name = readUTF8(u + 2, c);
635 desc = readUTF8(u + 4, c);
636 // visits the field's attributes and looks for a ConstantValue
637 // attribute
638 int fieldValueItem = 0;
639 signature = null;
640 anns = 0;
641 ianns = 0;
642 cattrs = null;
643
644 j = readUnsignedShort(u + 6);
645 u += 8;
646 for(; j > 0; --j)
647 {
648 attrName = readUTF8(u, c);
649 // tests are sorted in decreasing frequency order
650 // (based on frequencies observed on typical classes)
651 if(attrName.equals("ConstantValue"))
652 {
653 fieldValueItem = readUnsignedShort(u + 6);
654 }
655 else if(attrName.equals("Signature"))
656 {
657 signature = readUTF8(u + 6, c);
658 }
659 else if(attrName.equals("Deprecated"))
660 {
661 access |= Opcodes.ACC_DEPRECATED;
662 }
663 else if(attrName.equals("Synthetic"))
664 {
665 access |= Opcodes.ACC_SYNTHETIC;
666 }
667 else if(attrName.equals("RuntimeVisibleAnnotations"))
668 {
669 anns = u + 6;
670 }
671 else if(attrName.equals("RuntimeInvisibleAnnotations"))
672 {
673 ianns = u + 6;
674 }
675 else
676 {
677 attr = readAttribute(attrs,
678 attrName,
679 u + 6,
680 readInt(u + 2),
681 c,
682 -1,
683 null);
684 if(attr != null)
685 {
686 attr.next = cattrs;
687 cattrs = attr;
688 }
689 }
690 u += 6 + readInt(u + 2);
691 }
692 // visits the field
693 FieldVisitor fv = classVisitor.visitField(access,
694 name,
695 desc,
696 signature,
697 fieldValueItem == 0 ? null : readConst(fieldValueItem, c));
698 // visits the field annotations and attributes
699 if(fv != null)
700 {
701 for(j = 1; j >= 0; --j)
702 {
703 v = j == 0 ? ianns : anns;
704 if(v != 0)
705 {
706 k = readUnsignedShort(v);
707 v += 2;
708 for(; k > 0; --k)
709 {
710 v = readAnnotationValues(v + 2,
711 c,
712 true,
713 fv.visitAnnotation(readUTF8(v, c), j != 0));
714 }
715 }
716 }
717 while(cattrs != null)
718 {
719 attr = cattrs.next;
720 cattrs.next = null;
721 fv.visitAttribute(cattrs);
722 cattrs = attr;
723 }
724 fv.visitEnd();
725 }
726 }
727
728 // visits the methods
729 i = readUnsignedShort(u);
730 u += 2;
731 for(; i > 0; --i)
732 {
733 int u0 = u + 6;
734 access = readUnsignedShort(u);
735 name = readUTF8(u + 2, c);
736 desc = readUTF8(u + 4, c);
737 signature = null;
738 anns = 0;
739 ianns = 0;
740 int dann = 0;
741 int mpanns = 0;
742 int impanns = 0;
743 cattrs = null;
744 v = 0;
745 w = 0;
746
747 // looks for Code and Exceptions attributes
748 j = readUnsignedShort(u + 6);
749 u += 8;
750 for(; j > 0; --j)
751 {
752 attrName = readUTF8(u, c);
753 int attrSize = readInt(u + 2);
754 u += 6;
755 // tests are sorted in decreasing frequency order
756 // (based on frequencies observed on typical classes)
757 if(attrName.equals("Code"))
758 {
759 if(!skipCode)
760 {
761 v = u;
762 }
763 }
764 else if(attrName.equals("Exceptions"))
765 {
766 w = u;
767 }
768 else if(attrName.equals("Signature"))
769 {
770 signature = readUTF8(u, c);
771 }
772 else if(attrName.equals("Deprecated"))
773 {
774 access |= Opcodes.ACC_DEPRECATED;
775 }
776 else if(attrName.equals("RuntimeVisibleAnnotations"))
777 {
778 anns = u;
779 }
780 else if(attrName.equals("AnnotationDefault"))
781 {
782 dann = u;
783 }
784 else if(attrName.equals("Synthetic"))
785 {
786 access |= Opcodes.ACC_SYNTHETIC;
787 }
788 else if(attrName.equals("RuntimeInvisibleAnnotations"))
789 {
790 ianns = u;
791 }
792 else if(attrName.equals("RuntimeVisibleParameterAnnotations"))
793 {
794 mpanns = u;
795 }
796 else if(attrName.equals("RuntimeInvisibleParameterAnnotations"))
797 {
798 impanns = u;
799 }
800 else
801 {
802 attr = readAttribute(attrs,
803 attrName,
804 u,
805 attrSize,
806 c,
807 -1,
808 null);
809 if(attr != null)
810 {
811 attr.next = cattrs;
812 cattrs = attr;
813 }
814 }
815 u += attrSize;
816 }
817 // reads declared exceptions
818 String[] exceptions;
819 if(w == 0)
820 {
821 exceptions = null;
822 }
823 else
824 {
825 exceptions = new String[readUnsignedShort(w)];
826 w += 2;
827 for(j = 0; j < exceptions.length; ++j)
828 {
829 exceptions[j] = readClass(w, c);
830 w += 2;
831 }
832 }
833
834 // visits the method's code, if any
835 MethodVisitor mv = classVisitor.visitMethod(access,
836 name,
837 desc,
838 signature,
839 exceptions);
840
841 if(mv != null)
842 {
843 /*
844 * if the returned MethodVisitor is in fact a MethodWriter, it
845 * means there is no method adapter between the reader and the
846 * writer. If, in addition, the writer's constant pool was
847 * copied from this reader (mw.cw.cr == this), and the signature
848 * and exceptions of the method have not been changed, then it
849 * is possible to skip all visit events and just copy the
850 * original code of the method to the writer (the access, name
851 * and descriptor can have been changed, this is not important
852 * since they are not copied as is from the reader).
853 */
854 if(mv instanceof MethodWriter)
855 {
856 MethodWriter mw = (MethodWriter) mv;
857 if(mw.cw.cr == this)
858 {
859 if(signature == mw.signature)
860 {
861 boolean sameExceptions = false;
862 if(exceptions == null)
863 {
864 sameExceptions = mw.exceptionCount == 0;
865 }
866 else
867 {
868 if(exceptions.length == mw.exceptionCount)
869 {
870 sameExceptions = true;
871 for(j = exceptions.length - 1; j >= 0; --j)
872 {
873 w -= 2;
874 if(mw.exceptions[j] != readUnsignedShort(w))
875 {
876 sameExceptions = false;
877 break;
878 }
879 }
880 }
881 }
882 if(sameExceptions)
883 {
884 /*
885 * we do not copy directly the code into
886 * MethodWriter to save a byte array copy
887 * operation. The real copy will be done in
888 * ClassWriter.toByteArray().
889 */
890 mw.classReaderOffset = u0;
891 mw.classReaderLength = u - u0;
892 continue;
893 }
894 }
895 }
896 }
897
898 if(dann != 0)
899 {
900 AnnotationVisitor dv = mv.visitAnnotationDefault();
901 readAnnotationValue(dann, c, null, dv);
902 if(dv != null)
903 {
904 dv.visitEnd();
905 }
906 }
907 for(j = 1; j >= 0; --j)
908 {
909 w = j == 0 ? ianns : anns;
910 if(w != 0)
911 {
912 k = readUnsignedShort(w);
913 w += 2;
914 for(; k > 0; --k)
915 {
916 w = readAnnotationValues(w + 2,
917 c,
918 true,
919 mv.visitAnnotation(readUTF8(w, c), j != 0));
920 }
921 }
922 }
923 if(mpanns != 0)
924 {
925 readParameterAnnotations(mpanns, c, true, mv);
926 }
927 if(impanns != 0)
928 {
929 readParameterAnnotations(impanns, c, false, mv);
930 }
931 while(cattrs != null)
932 {
933 attr = cattrs.next;
934 cattrs.next = null;
935 mv.visitAttribute(cattrs);
936 cattrs = attr;
937 }
938 }
939
940 if(mv != null && v != 0)
941 {
942 int maxStack = readUnsignedShort(v);
943 int maxLocals = readUnsignedShort(v + 2);
944 int codeLength = readInt(v + 4);
945 v += 8;
946
947 int codeStart = v;
948 int codeEnd = v + codeLength;
949
950 mv.visitCode();
951
952 // 1st phase: finds the labels
953 int label;
954 Label[] labels = new Label[codeLength + 1];
955 while(v < codeEnd)
956 {
957 int opcode = b[v] & 0xFF;
958 switch(ClassWriter.TYPE[opcode])
959 {
960 case ClassWriter.NOARG_INSN:
961 case ClassWriter.IMPLVAR_INSN:
962 v += 1;
963 break;
964 case ClassWriter.LABEL_INSN:
965 label = v - codeStart + readShort(v + 1);
966 if(labels[label] == null)
967 {
968 labels[label] = new Label();
969 }
970 v += 3;
971 break;
972 case ClassWriter.LABELW_INSN:
973 label = v - codeStart + readInt(v + 1);
974 if(labels[label] == null)
975 {
976 labels[label] = new Label();
977 }
978 v += 5;
979 break;
980 case ClassWriter.WIDE_INSN:
981 opcode = b[v + 1] & 0xFF;
982 if(opcode == Opcodes.IINC)
983 {
984 v += 6;
985 }
986 else
987 {
988 v += 4;
989 }
990 break;
991 case ClassWriter.TABL_INSN:
992 // skips 0 to 3 padding bytes
993 w = v - codeStart;
994 v = v + 4 - (w & 3);
995 // reads instruction
996 label = w + readInt(v);
997 if(labels[label] == null)
998 {
999 labels[label] = new Label();
1000 }
1001 j = readInt(v + 8) - readInt(v + 4) + 1;
1002 v += 12;
1003 for(; j > 0; --j)
1004 {
1005 label = w + readInt(v);
1006 v += 4;
1007 if(labels[label] == null)
1008 {
1009 labels[label] = new Label();
1010 }
1011 }
1012 break;
1013 case ClassWriter.LOOK_INSN:
1014 // skips 0 to 3 padding bytes
1015 w = v - codeStart;
1016 v = v + 4 - (w & 3);
1017 // reads instruction
1018 label = w + readInt(v);
1019 if(labels[label] == null)
1020 {
1021 labels[label] = new Label();
1022 }
1023 j = readInt(v + 4);
1024 v += 8;
1025 for(; j > 0; --j)
1026 {
1027 label = w + readInt(v + 4);
1028 v += 8;
1029 if(labels[label] == null)
1030 {
1031 labels[label] = new Label();
1032 }
1033 }
1034 break;
1035 case ClassWriter.VAR_INSN:
1036 case ClassWriter.SBYTE_INSN:
1037 case ClassWriter.LDC_INSN:
1038 v += 2;
1039 break;
1040 case ClassWriter.SHORT_INSN:
1041 case ClassWriter.LDCW_INSN:
1042 case ClassWriter.FIELDORMETH_INSN:
1043 case ClassWriter.TYPE_INSN:
1044 case ClassWriter.IINC_INSN:
1045 v += 3;
1046 break;
1047 case ClassWriter.ITFMETH_INSN:
1048 v += 5;
1049 break;
1050 // case MANA_INSN:
1051 default:
1052 v += 4;
1053 break;
1054 }
1055 }
1056 // parses the try catch entries
1057 j = readUnsignedShort(v);
1058 v += 2;
1059 for(; j > 0; --j)
1060 {
1061 label = readUnsignedShort(v);
1062 Label start = labels[label];
1063 if(start == null)
1064 {
1065 labels[label] = start = new Label();
1066 }
1067 label = readUnsignedShort(v + 2);
1068 Label end = labels[label];
1069 if(end == null)
1070 {
1071 labels[label] = end = new Label();
1072 }
1073 label = readUnsignedShort(v + 4);
1074 Label handler = labels[label];
1075 if(handler == null)
1076 {
1077 labels[label] = handler = new Label();
1078 }
1079 int type = readUnsignedShort(v + 6);
1080 if(type == 0)
1081 {
1082 mv.visitTryCatchBlock(start, end, handler, null);
1083 }
1084 else
1085 {
1086 mv.visitTryCatchBlock(start,
1087 end,
1088 handler,
1089 readUTF8(items[type], c));
1090 }
1091 v += 8;
1092 }
1093 // parses the local variable, line number tables, and code
1094 // attributes
1095 int varTable = 0;
1096 int varTypeTable = 0;
1097 int stackMap = 0;
1098 int frameCount = 0;
1099 int frameMode = 0;
1100 int frameOffset = 0;
1101 int frameLocalCount = 0;
1102 int frameLocalDiff = 0;
1103 int frameStackCount = 0;
1104 Object[] frameLocal = null;
1105 Object[] frameStack = null;
1106 boolean zip = true;
1107 cattrs = null;
1108 j = readUnsignedShort(v);
1109 v += 2;
1110 for(; j > 0; --j)
1111 {
1112 attrName = readUTF8(v, c);
1113 if(attrName.equals("LocalVariableTable"))
1114 {
1115 if(!skipDebug)
1116 {
1117 varTable = v + 6;
1118 k = readUnsignedShort(v + 6);
1119 w = v + 8;
1120 for(; k > 0; --k)
1121 {
1122 label = readUnsignedShort(w);
1123 if(labels[label] == null)
1124 {
1125 labels[label] = new Label(true);
1126 }
1127 label += readUnsignedShort(w + 2);
1128 if(labels[label] == null)
1129 {
1130 labels[label] = new Label(true);
1131 }
1132 w += 10;
1133 }
1134 }
1135 }
1136 else if(attrName.equals("LocalVariableTypeTable"))
1137 {
1138 varTypeTable = v + 6;
1139 }
1140 else if(attrName.equals("LineNumberTable"))
1141 {
1142 if(!skipDebug)
1143 {
1144 k = readUnsignedShort(v + 6);
1145 w = v + 8;
1146 for(; k > 0; --k)
1147 {
1148 label = readUnsignedShort(w);
1149 if(labels[label] == null)
1150 {
1151 labels[label] = new Label(true);
1152 }
1153 labels[label].line = readUnsignedShort(w + 2);
1154 w += 4;
1155 }
1156 }
1157 }
1158 else if(attrName.equals("StackMapTable"))
1159 {
1160 if((flags & SKIP_FRAMES) == 0)
1161 {
1162 stackMap = v + 8;
1163 frameCount = readUnsignedShort(v + 6);
1164 }
1165 /*
1166 * here we do not extract the labels corresponding to
1167 * the attribute content. This would require a full
1168 * parsing of the attribute, which would need to be
1169 * repeated in the second phase (see below). Instead the
1170 * content of the attribute is read one frame at a time
1171 * (i.e. after a frame has been visited, the next frame
1172 * is read), and the labels it contains are also
1173 * extracted one frame at a time. Thanks to the ordering
1174 * of frames, having only a "one frame lookahead" is not
1175 * a problem, i.e. it is not possible to see an offset
1176 * smaller than the offset of the current insn and for
1177 * which no Label exist.
1178 */
1179 // TODO true for frame offsets,
1180 // but for UNINITIALIZED type offsets?
1181 }
1182 else if(attrName.equals("StackMap"))
1183 {
1184 if((flags & SKIP_FRAMES) == 0)
1185 {
1186 stackMap = v + 8;
1187 frameCount = readUnsignedShort(v + 6);
1188 zip = false;
1189 }
1190 /*
1191 * IMPORTANT! here we assume that the frames are
1192 * ordered, as in the StackMapTable attribute, although
1193 * this is not guaranteed by the attribute format.
1194 */
1195 }
1196 else
1197 {
1198 for(k = 0; k < attrs.length; ++k)
1199 {
1200 if(attrs[k].type.equals(attrName))
1201 {
1202 attr = attrs[k].read(this,
1203 v + 6,
1204 readInt(v + 2),
1205 c,
1206 codeStart - 8,
1207 labels);
1208 if(attr != null)
1209 {
1210 attr.next = cattrs;
1211 cattrs = attr;
1212 }
1213 }
1214 }
1215 }
1216 v += 6 + readInt(v + 2);
1217 }
1218
1219 // 2nd phase: visits each instruction
1220 if(stackMap != 0)
1221 {
1222 // creates the very first (implicit) frame from the method
1223 // descriptor
1224 frameLocal = new Object[maxLocals];
1225 frameStack = new Object[maxStack];
1226 if(unzip)
1227 {
1228 int local = 0;
1229 if((access & Opcodes.ACC_STATIC) == 0)
1230 {
1231 if(name.equals("<init>"))
1232 {
1233 frameLocal[local++] = Opcodes.UNINITIALIZED_THIS;
1234 }
1235 else
1236 {
1237 frameLocal[local++] = readClass(header + 2, c);
1238 }
1239 }
1240 j = 1;
1241 loop:
1242 while(true)
1243 {
1244 k = j;
1245 switch(desc.charAt(j++))
1246 {
1247 case'Z':
1248 case'C':
1249 case'B':
1250 case'S':
1251 case'I':
1252 frameLocal[local++] = Opcodes.INTEGER;
1253 break;
1254 case'F':
1255 frameLocal[local++] = Opcodes.FLOAT;
1256 break;
1257 case'J':
1258 frameLocal[local++] = Opcodes.LONG;
1259 break;
1260 case'D':
1261 frameLocal[local++] = Opcodes.DOUBLE;
1262 break;
1263 case'[':
1264 while(desc.charAt(j) == '[')
1265 {
1266 ++j;
1267 }
1268 if(desc.charAt(j) == 'L')
1269 {
1270 ++j;
1271 while(desc.charAt(j) != ';')
1272 {
1273 ++j;
1274 }
1275 }
1276 frameLocal[local++] = desc.substring(k, ++j);
1277 break;
1278 case'L':
1279 while(desc.charAt(j) != ';')
1280 {
1281 ++j;
1282 }
1283 frameLocal[local++] = desc.substring(k + 1,
1284 j++);
1285 break;
1286 default:
1287 break loop;
1288 }
1289 }
1290 frameLocalCount = local;
1291 }
1292 /*
1293 * for the first explicit frame the offset is not
1294 * offset_delta + 1 but only offset_delta; setting the
1295 * implicit frame offset to -1 allow the use of the
1296 * "offset_delta + 1" rule in all cases
1297 */
1298 frameOffset = -1;
1299 }
1300 v = codeStart;
1301 Label l;
1302 while(v < codeEnd)
1303 {
1304 w = v - codeStart;
1305
1306 l = labels[w];
1307 if(l != null)
1308 {
1309 mv.visitLabel(l);
1310 if(!skipDebug && l.line > 0)
1311 {
1312 mv.visitLineNumber(l.line, l);
1313 }
1314 }
1315
1316 while(frameLocal != null
1317 && (frameOffset == w || frameOffset == -1))
1318 {
1319 // if there is a frame for this offset,
1320 // makes the visitor visit it,
1321 // and reads the next frame if there is one.
1322 if(!zip || unzip)
1323 {
1324 mv.visitFrame(Opcodes.F_NEW,
1325 frameLocalCount,
1326 frameLocal,
1327 frameStackCount,
1328 frameStack);
1329 }
1330 else if(frameOffset != -1)
1331 {
1332 mv.visitFrame(frameMode,
1333 frameLocalDiff,
1334 frameLocal,
1335 frameStackCount,
1336 frameStack);
1337 }
1338
1339 if(frameCount > 0)
1340 {
1341 int tag, delta, n;
1342 if(zip)
1343 {
1344 tag = b[stackMap++] & 0xFF;
1345 }
1346 else
1347 {
1348 tag = MethodWriter.FULL_FRAME;
1349 frameOffset = -1;
1350 }
1351 frameLocalDiff = 0;
1352 if(tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME)
1353 {
1354 delta = tag;
1355 frameMode = Opcodes.F_SAME;
1356 frameStackCount = 0;
1357 }
1358 else if(tag < MethodWriter.RESERVED)
1359 {
1360 delta = tag
1361 - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME;
1362 stackMap = readFrameType(frameStack,
1363 0,
1364 stackMap,
1365 c,
1366 labels);
1367 frameMode = Opcodes.F_SAME1;
1368 frameStackCount = 1;
1369 }
1370 else
1371 {
1372 delta = readUnsignedShort(stackMap);
1373 stackMap += 2;
1374 if(tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
1375 {
1376 stackMap = readFrameType(frameStack,
1377 0,
1378 stackMap,
1379 c,
1380 labels);
1381 frameMode = Opcodes.F_SAME1;
1382 frameStackCount = 1;
1383 }
1384 else if(tag >= MethodWriter.CHOP_FRAME
1385 && tag < MethodWriter.SAME_FRAME_EXTENDED)
1386 {
1387 frameMode = Opcodes.F_CHOP;
1388 frameLocalDiff = MethodWriter.SAME_FRAME_EXTENDED
1389 - tag;
1390 frameLocalCount -= frameLocalDiff;
1391 frameStackCount = 0;
1392 }
1393 else if(tag == MethodWriter.SAME_FRAME_EXTENDED)
1394 {
1395 frameMode = Opcodes.F_SAME;
1396 frameStackCount = 0;
1397 }
1398 else if(tag < MethodWriter.FULL_FRAME)
1399 {
1400 j = unzip ? frameLocalCount : 0;
1401 for(k = tag
1402 - MethodWriter.SAME_FRAME_EXTENDED; k > 0; k--)
1403 {
1404 stackMap = readFrameType(frameLocal,
1405 j++,
1406 stackMap,
1407 c,
1408 labels);
1409 }
1410 frameMode = Opcodes.F_APPEND;
1411 frameLocalDiff = tag
1412 - MethodWriter.SAME_FRAME_EXTENDED;
1413 frameLocalCount += frameLocalDiff;
1414 frameStackCount = 0;
1415 }
1416 else
1417 { // if (tag == FULL_FRAME) {
1418 frameMode = Opcodes.F_FULL;
1419 n = frameLocalDiff = frameLocalCount = readUnsignedShort(stackMap);
1420 stackMap += 2;
1421 for(j = 0; n > 0; n--)
1422 {
1423 stackMap = readFrameType(frameLocal,
1424 j++,
1425 stackMap,
1426 c,
1427 labels);
1428 }
1429 n = frameStackCount = readUnsignedShort(stackMap);
1430 stackMap += 2;
1431 for(j = 0; n > 0; n--)
1432 {
1433 stackMap = readFrameType(frameStack,
1434 j++,
1435 stackMap,
1436 c,
1437 labels);
1438 }
1439 }
1440 }
1441 frameOffset += delta + 1;
1442 if(labels[frameOffset] == null)
1443 {
1444 labels[frameOffset] = new Label();
1445 }
1446
1447 --frameCount;
1448 }
1449 else
1450 {
1451 frameLocal = null;
1452 }
1453 }
1454
1455 int opcode = b[v] & 0xFF;
1456 switch(ClassWriter.TYPE[opcode])
1457 {
1458 case ClassWriter.NOARG_INSN:
1459 mv.visitInsn(opcode);
1460 v += 1;
1461 break;
1462 case ClassWriter.IMPLVAR_INSN:
1463 if(opcode > Opcodes.ISTORE)
1464 {
1465 opcode -= 59; // ISTORE_0
1466 mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2),
1467 opcode & 0x3);
1468 }
1469 else
1470 {
1471 opcode -= 26; // ILOAD_0
1472 mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2),
1473 opcode & 0x3);
1474 }
1475 v += 1;
1476 break;
1477 case ClassWriter.LABEL_INSN:
1478 mv.visitJumpInsn(opcode, labels[w
1479 + readShort(v + 1)]);
1480 v += 3;
1481 break;
1482 case ClassWriter.LABELW_INSN:
1483 mv.visitJumpInsn(opcode - 33, labels[w
1484 + readInt(v + 1)]);
1485 v += 5;
1486 break;
1487 case ClassWriter.WIDE_INSN:
1488 opcode = b[v + 1] & 0xFF;
1489 if(opcode == Opcodes.IINC)
1490 {
1491 mv.visitIincInsn(readUnsignedShort(v + 2),
1492 readShort(v + 4));
1493 v += 6;
1494 }
1495 else
1496 {
1497 mv.visitVarInsn(opcode,
1498 readUnsignedShort(v + 2));
1499 v += 4;
1500 }
1501 break;
1502 case ClassWriter.TABL_INSN:
1503 // skips 0 to 3 padding bytes
1504 v = v + 4 - (w & 3);
1505 // reads instruction
1506 label = w + readInt(v);
1507 int min = readInt(v + 4);
1508 int max = readInt(v + 8);
1509 v += 12;
1510 Label[] table = new Label[max - min + 1];
1511 for(j = 0; j < table.length; ++j)
1512 {
1513 table[j] = labels[w + readInt(v)];
1514 v += 4;
1515 }
1516 mv.visitTableSwitchInsn(min,
1517 max,
1518 labels[label],
1519 table);
1520 break;
1521 case ClassWriter.LOOK_INSN:
1522 // skips 0 to 3 padding bytes
1523 v = v + 4 - (w & 3);
1524 // reads instruction
1525 label = w + readInt(v);
1526 j = readInt(v + 4);
1527 v += 8;
1528 int[] keys = new int[j];
1529 Label[] values = new Label[j];
1530 for(j = 0; j < keys.length; ++j)
1531 {
1532 keys[j] = readInt(v);
1533 values[j] = labels[w + readInt(v + 4)];
1534 v += 8;
1535 }
1536 mv.visitLookupSwitchInsn(labels[label],
1537 keys,
1538 values);
1539 break;
1540 case ClassWriter.VAR_INSN:
1541 mv.visitVarInsn(opcode, b[v + 1] & 0xFF);
1542 v += 2;
1543 break;
1544 case ClassWriter.SBYTE_INSN:
1545 mv.visitIntInsn(opcode, b[v + 1]);
1546 v += 2;
1547 break;
1548 case ClassWriter.SHORT_INSN:
1549 mv.visitIntInsn(opcode, readShort(v + 1));
1550 v += 3;
1551 break;
1552 case ClassWriter.LDC_INSN:
1553 mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));
1554 v += 2;
1555 break;
1556 case ClassWriter.LDCW_INSN:
1557 mv.visitLdcInsn(readConst(readUnsignedShort(v + 1),
1558 c));
1559 v += 3;
1560 break;
1561 case ClassWriter.FIELDORMETH_INSN:
1562 case ClassWriter.ITFMETH_INSN:
1563 int cpIndex = items[readUnsignedShort(v + 1)];
1564 String iowner = readClass(cpIndex, c);
1565 cpIndex = items[readUnsignedShort(cpIndex + 2)];
1566 String iname = readUTF8(cpIndex, c);
1567 String idesc = readUTF8(cpIndex + 2, c);
1568 if(opcode < Opcodes.INVOKEVIRTUAL)
1569 {
1570 mv.visitFieldInsn(opcode, iowner, iname, idesc);
1571 }
1572 else
1573 {
1574 mv.visitMethodInsn(opcode, iowner, iname, idesc);
1575 }
1576 if(opcode == Opcodes.INVOKEINTERFACE)
1577 {
1578 v += 5;
1579 }
1580 else
1581 {
1582 v += 3;
1583 }
1584 break;
1585 case ClassWriter.TYPE_INSN:
1586 mv.visitTypeInsn(opcode, readClass(v + 1, c));
1587 v += 3;
1588 break;
1589 case ClassWriter.IINC_INSN:
1590 mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);
1591 v += 3;
1592 break;
1593 // case MANA_INSN:
1594 default:
1595 mv.visitMultiANewArrayInsn(readClass(v + 1, c),
1596 b[v + 3] & 0xFF);
1597 v += 4;
1598 break;
1599 }
1600 }
1601 l = labels[codeEnd - codeStart];
1602 if(l != null)
1603 {
1604 mv.visitLabel(l);
1605 }
1606 // visits the local variable tables
1607 if(!skipDebug && varTable != 0)
1608 {
1609 int[] typeTable = null;
1610 if(varTypeTable != 0)
1611 {
1612 k = readUnsignedShort(varTypeTable) * 3;
1613 w = varTypeTable + 2;
1614 typeTable = new int[k];
1615 while(k > 0)
1616 {
1617 typeTable[--k] = w + 6; // signature
1618 typeTable[--k] = readUnsignedShort(w + 8); // index
1619 typeTable[--k] = readUnsignedShort(w); // start
1620 w += 10;
1621 }
1622 }
1623 k = readUnsignedShort(varTable);
1624 w = varTable + 2;
1625 for(; k > 0; --k)
1626 {
1627 int start = readUnsignedShort(w);
1628 int length = readUnsignedShort(w + 2);
1629 int index = readUnsignedShort(w + 8);
1630 String vsignature = null;
1631 if(typeTable != null)
1632 {
1633 for(int a = 0; a < typeTable.length; a += 3)
1634 {
1635 if(typeTable[a] == start
1636 && typeTable[a + 1] == index)
1637 {
1638 vsignature = readUTF8(typeTable[a + 2], c);
1639 break;
1640 }
1641 }
1642 }
1643 mv.visitLocalVariable(readUTF8(w + 4, c),
1644 readUTF8(w + 6, c),
1645 vsignature,
1646 labels[start],
1647 labels[start + length],
1648 index);
1649 w += 10;
1650 }
1651 }
1652 // visits the other attributes
1653 while(cattrs != null)
1654 {
1655 attr = cattrs.next;
1656 cattrs.next = null;
1657 mv.visitAttribute(cattrs);
1658 cattrs = attr;
1659 }
1660 // visits the max stack and max locals values
1661 mv.visitMaxs(maxStack, maxLocals);
1662 }
1663
1664 if(mv != null)
1665 {
1666 mv.visitEnd();
1667 }
1668 }
1669
1670 // visits the end of the class
1671 classVisitor.visitEnd();
1672 }
1673
1674 /**
1675 * Reads parameter annotations and makes the given visitor visit them.
1676 *
1677 * @param v start offset in {@link #b b} of the annotations to be read.
1678 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1679 * {@link #readClass(int,char[]) readClass} or
1680 * {@link #readConst readConst}.
1681 * @param visible <tt>true</tt> if the annotations to be read are visible
1682 * at runtime.
1683 * @param mv the visitor that must visit the annotations.
1684 */
1685 private void readParameterAnnotations(
1686 int v,
1687 final char[] buf,
1688 final boolean visible,
1689 final MethodVisitor mv){
1690 int n = b[v++] & 0xFF;
1691 for(int i = 0; i < n; ++i)
1692 {
1693 int j = readUnsignedShort(v);
1694 v += 2;
1695 for(; j > 0; --j)
1696 {
1697 v = readAnnotationValues(v + 2,
1698 buf,
1699 true,
1700 mv.visitParameterAnnotation(i,
1701 readUTF8(v, buf),
1702 visible));
1703 }
1704 }
1705 }
1706
1707 /**
1708 * Reads the values of an annotation and makes the given visitor visit them.
1709 *
1710 * @param v the start offset in {@link #b b} of the values to be read
1711 * (including the unsigned short that gives the number of values).
1712 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1713 * {@link #readClass(int,char[]) readClass} or
1714 * {@link #readConst readConst}.
1715 * @param named if the annotation values are named or not.
1716 * @param av the visitor that must visit the values.
1717 * @return the end offset of the annotation values.
1718 */
1719 private int readAnnotationValues(
1720 int v,
1721 final char[] buf,
1722 final boolean named,
1723 final AnnotationVisitor av){
1724 int i = readUnsignedShort(v);
1725 v += 2;
1726 if(named)
1727 {
1728 for(; i > 0; --i)
1729 {
1730 v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av);
1731 }
1732 }
1733 else
1734 {
1735 for(; i > 0; --i)
1736 {
1737 v = readAnnotationValue(v, buf, null, av);
1738 }
1739 }
1740 if(av != null)
1741 {
1742 av.visitEnd();
1743 }
1744 return v;
1745 }
1746
1747 /**
1748 * Reads a value of an annotation and makes the given visitor visit it.
1749 *
1750 * @param v the start offset in {@link #b b} of the value to be read (<i>not
1751 * including the value name constant pool index</i>).
1752 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1753 * {@link #readClass(int,char[]) readClass} or
1754 * {@link #readConst readConst}.
1755 * @param name the name of the value to be read.
1756 * @param av the visitor that must visit the value.
1757 * @return the end offset of the annotation value.
1758 */
1759 private int readAnnotationValue(
1760 int v,
1761 final char[] buf,
1762 final String name,
1763 final AnnotationVisitor av){
1764 int i;
1765 if(av == null)
1766 {
1767 switch(b[v] & 0xFF)
1768 {
1769 case'e': // enum_const_value
1770 return v + 5;
1771 case'@': // annotation_value
1772 return readAnnotationValues(v + 3, buf, true, null);
1773 case'[': // array_value
1774 return readAnnotationValues(v + 1, buf, false, null);
1775 default:
1776 return v + 3;
1777 }
1778 }
1779 switch(b[v++] & 0xFF)
1780 {
1781 case'I': // pointer to CONSTANT_Integer
1782 case'J': // pointer to CONSTANT_Long
1783 case'F': // pointer to CONSTANT_Float
1784 case'D': // pointer to CONSTANT_Double
1785 av.visit(name, readConst(readUnsignedShort(v), buf));
1786 v += 2;
1787 break;
1788 case'B': // pointer to CONSTANT_Byte
1789 av.visit(name,
1790 new Byte((byte) readInt(items[readUnsignedShort(v)])));
1791 v += 2;
1792 break;
1793 case'Z': // pointer to CONSTANT_Boolean
1794 av.visit(name, readInt(items[readUnsignedShort(v)]) == 0
1795 ? Boolean.FALSE
1796 : Boolean.TRUE);
1797 v += 2;
1798 break;
1799 case'S': // pointer to CONSTANT_Short
1800 av.visit(name,
1801 new Short((short) readInt(items[readUnsignedShort(v)])));
1802 v += 2;
1803 break;
1804 case'C': // pointer to CONSTANT_Char
1805 av.visit(name,
1806 new Character((char) readInt(items[readUnsignedShort(v)])));
1807 v += 2;
1808 break;
1809 case's': // pointer to CONSTANT_Utf8
1810 av.visit(name, readUTF8(v, buf));
1811 v += 2;
1812 break;
1813 case'e': // enum_const_value
1814 av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf));
1815 v += 4;
1816 break;
1817 case'c': // class_info
1818 av.visit(name, Type.getType(readUTF8(v, buf)));
1819 v += 2;
1820 break;
1821 case'@': // annotation_value
1822 v = readAnnotationValues(v + 2,
1823 buf,
1824 true,
1825 av.visitAnnotation(name, readUTF8(v, buf)));
1826 break;
1827 case'[': // array_value
1828 int size = readUnsignedShort(v);
1829 v += 2;
1830 if(size == 0)
1831 {
1832 return readAnnotationValues(v - 2,
1833 buf,
1834 false,
1835 av.visitArray(name));
1836 }
1837 switch(this.b[v++] & 0xFF)
1838 {
1839 case'B':
1840 byte[] bv = new byte[size];
1841 for(i = 0; i < size; i++)
1842 {
1843 bv[i] = (byte) readInt(items[readUnsignedShort(v)]);
1844 v += 3;
1845 }
1846 av.visit(name, bv);
1847 --v;
1848 break;
1849 case'Z':
1850 boolean[] zv = new boolean[size];
1851 for(i = 0; i < size; i++)
1852 {
1853 zv[i] = readInt(items[readUnsignedShort(v)]) != 0;
1854 v += 3;
1855 }
1856 av.visit(name, zv);
1857 --v;
1858 break;
1859 case'S':
1860 short[] sv = new short[size];
1861 for(i = 0; i < size; i++)
1862 {
1863 sv[i] = (short) readInt(items[readUnsignedShort(v)]);
1864 v += 3;
1865 }
1866 av.visit(name, sv);
1867 --v;
1868 break;
1869 case'C':
1870 char[] cv = new char[size];
1871 for(i = 0; i < size; i++)
1872 {
1873 cv[i] = (char) readInt(items[readUnsignedShort(v)]);
1874 v += 3;
1875 }
1876 av.visit(name, cv);
1877 --v;
1878 break;
1879 case'I':
1880 int[] iv = new int[size];
1881 for(i = 0; i < size; i++)
1882 {
1883 iv[i] = readInt(items[readUnsignedShort(v)]);
1884 v += 3;
1885 }
1886 av.visit(name, iv);
1887 --v;
1888 break;
1889 case'J':
1890 long[] lv = new long[size];
1891 for(i = 0; i < size; i++)
1892 {
1893 lv[i] = readLong(items[readUnsignedShort(v)]);
1894 v += 3;
1895 }
1896 av.visit(name, lv);
1897 --v;
1898 break;
1899 case'F':
1900 float[] fv = new float[size];
1901 for(i = 0; i < size; i++)
1902 {
1903 fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)]));
1904 v += 3;
1905 }
1906 av.visit(name, fv);
1907 --v;
1908 break;
1909 case'D':
1910 double[] dv = new double[size];
1911 for(i = 0; i < size; i++)
1912 {
1913 dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)]));
1914 v += 3;
1915 }
1916 av.visit(name, dv);
1917 --v;
1918 break;
1919 default:
1920 v = readAnnotationValues(v - 3,
1921 buf,
1922 false,
1923 av.visitArray(name));
1924 }
1925 }
1926 return v;
1927 }
1928
1929 private int readFrameType(
1930 final Object[] frame,
1931 final int index,
1932 int v,
1933 final char[] buf,
1934 final Label[] labels){
1935 int type = b[v++] & 0xFF;
1936 switch(type)
1937 {
1938 case 0:
1939 frame[index] = Opcodes.TOP;
1940 break;
1941 case 1:
1942 frame[index] = Opcodes.INTEGER;
1943 break;
1944 case 2:
1945 frame[index] = Opcodes.FLOAT;
1946 break;
1947 case 3:
1948 frame[index] = Opcodes.DOUBLE;
1949 break;
1950 case 4:
1951 frame[index] = Opcodes.LONG;
1952 break;
1953 case 5:
1954 frame[index] = Opcodes.NULL;
1955 break;
1956 case 6:
1957 frame[index] = Opcodes.UNINITIALIZED_THIS;
1958 break;
1959 case 7: // Object
1960 frame[index] = readClass(v, buf);
1961 v += 2;
1962 break;
1963 default: // Uninitialized
1964 int offset = readUnsignedShort(v);
1965 if(labels[offset] == null)
1966 {
1967 labels[offset] = new Label();
1968 }
1969 frame[index] = labels[offset];
1970 v += 2;
1971 }
1972 return v;
1973 }
1974
1975 /**
1976 * Reads an attribute in {@link #b b}.
1977 *
1978 * @param attrs prototypes of the attributes that must be parsed during the
1979 * visit of the class. Any attribute whose type is not equal to the
1980 * type of one the prototypes is ignored (i.e. an empty
1981 * {@link Attribute} instance is returned).
1982 * @param type the type of the attribute.
1983 * @param off index of the first byte of the attribute's content in
1984 * {@link #b b}. The 6 attribute header bytes, containing the type
1985 * and the length of the attribute, are not taken into account here
1986 * (they have already been read).
1987 * @param len the length of the attribute's content.
1988 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1989 * {@link #readClass(int,char[]) readClass} or
1990 * {@link #readConst readConst}.
1991 * @param codeOff index of the first byte of code's attribute content in
1992 * {@link #b b}, or -1 if the attribute to be read is not a code
1993 * attribute. The 6 attribute header bytes, containing the type and
1994 * the length of the attribute, are not taken into account here.
1995 * @param labels the labels of the method's code, or <tt>null</tt> if the
1996 * attribute to be read is not a code attribute.
1997 * @return the attribute that has been read, or <tt>null</tt> to skip this
1998 * attribute.
1999 */
2000 private Attribute readAttribute(
2001 final Attribute[] attrs,
2002 final String type,
2003 final int off,
2004 final int len,
2005 final char[] buf,
2006 final int codeOff,
2007 final Label[] labels){
2008 for(int i = 0; i < attrs.length; ++i)
2009 {
2010 if(attrs[i].type.equals(type))
2011 {
2012 return attrs[i].read(this, off, len, buf, codeOff, labels);
2013 }
2014 }
2015 return new Attribute(type).read(this, off, len, null, -1, null);
2016 }
2017
2018 // ------------------------------------------------------------------------
2019 // Utility methods: low level parsing
2020 // ------------------------------------------------------------------------
2021
2022 /**
2023 * Returns the start index of the constant pool item in {@link #b b}, plus
2024 * one. <i>This method is intended for {@link Attribute} sub classes, and is
2025 * normally not needed by class generators or adapters.</i>
2026 *
2027 * @param item the index a constant pool item.
2028 * @return the start index of the constant pool item in {@link #b b}, plus
2029 * one.
2030 */
2031 public int getItem(final int item){
2032 return items[item];
2033 }
2034
2035 /**
2036 * Reads a byte value in {@link #b b}. <i>This method is intended for
2037 * {@link Attribute} sub classes, and is normally not needed by class
2038 * generators or adapters.</i>
2039 *
2040 * @param index the start index of the value to be read in {@link #b b}.
2041 * @return the read value.
2042 */
2043 public int readByte(final int index){
2044 return b[index] & 0xFF;
2045 }
2046
2047 /**
2048 * Reads an unsigned short value in {@link #b b}. <i>This method is
2049 * intended for {@link Attribute} sub classes, and is normally not needed by
2050 * class generators or adapters.</i>
2051 *
2052 * @param index the start index of the value to be read in {@link #b b}.
2053 * @return the read value.
2054 */
2055 public int readUnsignedShort(final int index){
2056 byte[] b = this.b;
2057 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
2058 }
2059
2060 /**
2061 * Reads a signed short value in {@link #b b}. <i>This method is intended
2062 * for {@link Attribute} sub classes, and is normally not needed by class
2063 * generators or adapters.</i>
2064 *
2065 * @param index the start index of the value to be read in {@link #b b}.
2066 * @return the read value.
2067 */
2068 public short readShort(final int index){
2069 byte[] b = this.b;
2070 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
2071 }
2072
2073 /**
2074 * Reads a signed int value in {@link #b b}. <i>This method is intended for
2075 * {@link Attribute} sub classes, and is normally not needed by class
2076 * generators or adapters.</i>
2077 *
2078 * @param index the start index of the value to be read in {@link #b b}.
2079 * @return the read value.
2080 */
2081 public int readInt(final int index){
2082 byte[] b = this.b;
2083 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
2084 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
2085 }
2086
2087 /**
2088 * Reads a signed long value in {@link #b b}. <i>This method is intended
2089 * for {@link Attribute} sub classes, and is normally not needed by class
2090 * generators or adapters.</i>
2091 *
2092 * @param index the start index of the value to be read in {@link #b b}.
2093 * @return the read value.
2094 */
2095 public long readLong(final int index){
2096 long l1 = readInt(index);
2097 long l0 = readInt(index + 4) & 0xFFFFFFFFL;
2098 return (l1 << 32) | l0;
2099 }
2100
2101 /**
2102 * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method
2103 * is intended for {@link Attribute} sub classes, and is normally not needed
2104 * by class generators or adapters.</i>
2105 *
2106 * @param index the start index of an unsigned short value in {@link #b b},
2107 * whose value is the index of an UTF8 constant pool item.
2108 * @param buf buffer to be used to read the item. This buffer must be
2109 * sufficiently large. It is not automatically resized.
2110 * @return the String corresponding to the specified UTF8 item.
2111 */
2112 public String readUTF8(int index, final char[] buf){
2113 int item = readUnsignedShort(index);
2114 String s = strings[item];
2115 if(s != null)
2116 {
2117 return s;
2118 }
2119 index = items[item];
2120 return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf);
2121 }
2122
2123 /**
2124 * Reads UTF8 string in {@link #b b}.
2125 *
2126 * @param index start offset of the UTF8 string to be read.
2127 * @param utfLen length of the UTF8 string to be read.
2128 * @param buf buffer to be used to read the string. This buffer must be
2129 * sufficiently large. It is not automatically resized.
2130 * @return the String corresponding to the specified UTF8 string.
2131 */
2132 private String readUTF(int index, final int utfLen, final char[] buf){
2133 int endIndex = index + utfLen;
2134 byte[] b = this.b;
2135 int strLen = 0;
2136 int c, d, e;
2137 while(index < endIndex)
2138 {
2139 c = b[index++] & 0xFF;
2140 switch(c >> 4)
2141 {
2142 case 0:
2143 case 1:
2144 case 2:
2145 case 3:
2146 case 4:
2147 case 5:
2148 case 6:
2149 case 7:
2150 // 0xxxxxxx
2151 buf[strLen++] = (char) c;
2152 break;
2153 case 12:
2154 case 13:
2155 // 110x xxxx 10xx xxxx
2156 d = b[index++];
2157 buf[strLen++] = (char) (((c & 0x1F) << 6) | (d & 0x3F));
2158 break;
2159 default:
2160 // 1110 xxxx 10xx xxxx 10xx xxxx
2161 d = b[index++];
2162 e = b[index++];
2163 buf[strLen++] = (char) (((c & 0x0F) << 12)
2164 | ((d & 0x3F) << 6) | (e & 0x3F));
2165 break;
2166 }
2167 }
2168 return new String(buf, 0, strLen);
2169 }
2170
2171 /**
2172 * Reads a class constant pool item in {@link #b b}. <i>This method is
2173 * intended for {@link Attribute} sub classes, and is normally not needed by
2174 * class generators or adapters.</i>
2175 *
2176 * @param index the start index of an unsigned short value in {@link #b b},
2177 * whose value is the index of a class constant pool item.
2178 * @param buf buffer to be used to read the item. This buffer must be
2179 * sufficiently large. It is not automatically resized.
2180 * @return the String corresponding to the specified class item.
2181 */
2182 public String readClass(final int index, final char[] buf){
2183 // computes the start index of the CONSTANT_Class item in b
2184 // and reads the CONSTANT_Utf8 item designated by
2185 // the first two bytes of this CONSTANT_Class item
2186 return readUTF8(items[readUnsignedShort(index)], buf);
2187 }
2188
2189 /**
2190 * Reads a numeric or string constant pool item in {@link #b b}. <i>This
2191 * method is intended for {@link Attribute} sub classes, and is normally not
2192 * needed by class generators or adapters.</i>
2193 *
2194 * @param item the index of a constant pool item.
2195 * @param buf buffer to be used to read the item. This buffer must be
2196 * sufficiently large. It is not automatically resized.
2197 * @return the {@link Integer}, {@link Float}, {@link Long},
2198 * {@link Double}, {@link String} or {@link Type} corresponding to
2199 * the given constant pool item.
2200 */
2201 public Object readConst(final int item, final char[] buf){
2202 int index = items[item];
2203 switch(b[index - 1])
2204 {
2205 case ClassWriter.INT:
2206 return new Integer(readInt(index));
2207 case ClassWriter.FLOAT:
2208 return new Float(Float.intBitsToFloat(readInt(index)));
2209 case ClassWriter.LONG:
2210 return new Long(readLong(index));
2211 case ClassWriter.DOUBLE:
2212 return new Double(Double.longBitsToDouble(readLong(index)));
2213 case ClassWriter.CLASS:
2214 String s = readUTF8(index, buf);
2215 return s.charAt(0) == '['
2216 ? Type.getType(s)
2217 : Type.getObjectType(s);
2218 // case ClassWriter.STR:
2219 default:
2220 return readUTF8(index, buf);
2221 }
2222 }
2223 }
+0
-196
src/jvm/clojure/asm/ClassVisitor.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * A visitor to visit a Java class. The methods of this interface must be called
33 * in the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
34 * <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
35 * <tt>visitAttribute</tt> )* (<tt>visitInnerClass</tt> |
36 * <tt>visitField</tt> | <tt>visitMethod</tt> )* <tt>visitEnd</tt>.
37 *
38 * @author Eric Bruneton
39 */
40 public interface ClassVisitor{
41
42 /**
43 * Visits the header of the class.
44 *
45 * @param version the class version.
46 * @param access the class's access flags (see {@link Opcodes}). This
47 * parameter also indicates if the class is deprecated.
48 * @param name the internal name of the class (see
49 * {@link Type#getInternalName() getInternalName}).
50 * @param signature the signature of this class. May be <tt>null</tt> if
51 * the class is not a generic one, and does not extend or implement
52 * generic classes or interfaces.
53 * @param superName the internal of name of the super class (see
54 * {@link Type#getInternalName() getInternalName}). For interfaces,
55 * the super class is {@link Object}. May be <tt>null</tt>, but
56 * only for the {@link Object} class.
57 * @param interfaces the internal names of the class's interfaces (see
58 * {@link Type#getInternalName() getInternalName}). May be
59 * <tt>null</tt>.
60 */
61 void visit(
62 int version,
63 int access,
64 String name,
65 String signature,
66 String superName,
67 String[] interfaces);
68
69 /**
70 * Visits the source of the class.
71 *
72 * @param source the name of the source file from which the class was
73 * compiled. May be <tt>null</tt>.
74 * @param debug additional debug information to compute the correspondance
75 * between source and compiled elements of the class. May be
76 * <tt>null</tt>.
77 */
78 void visitSource(String source, String debug);
79
80 /**
81 * Visits the enclosing class of the class. This method must be called only
82 * if the class has an enclosing class.
83 *
84 * @param owner internal name of the enclosing class of the class.
85 * @param name the name of the method that contains the class, or
86 * <tt>null</tt> if the class is not enclosed in a method of its
87 * enclosing class.
88 * @param desc the descriptor of the method that contains the class, or
89 * <tt>null</tt> if the class is not enclosed in a method of its
90 * enclosing class.
91 */
92 void visitOuterClass(String owner, String name, String desc);
93
94 /**
95 * Visits an annotation of the class.
96 *
97 * @param desc the class descriptor of the annotation class.
98 * @param visible <tt>true</tt> if the annotation is visible at runtime.
99 * @return a visitor to visit the annotation values, or <tt>null</tt> if
100 * this visitor is not interested in visiting this annotation.
101 */
102 AnnotationVisitor visitAnnotation(String desc, boolean visible);
103
104 /**
105 * Visits a non standard attribute of the class.
106 *
107 * @param attr an attribute.
108 */
109 void visitAttribute(Attribute attr);
110
111 /**
112 * Visits information about an inner class. This inner class is not
113 * necessarily a member of the class being visited.
114 *
115 * @param name the internal name of an inner class (see
116 * {@link Type#getInternalName() getInternalName}).
117 * @param outerName the internal name of the class to which the inner class
118 * belongs (see {@link Type#getInternalName() getInternalName}). May
119 * be <tt>null</tt> for not member classes.
120 * @param innerName the (simple) name of the inner class inside its
121 * enclosing class. May be <tt>null</tt> for anonymous inner
122 * classes.
123 * @param access the access flags of the inner class as originally declared
124 * in the enclosing class.
125 */
126 void visitInnerClass(
127 String name,
128 String outerName,
129 String innerName,
130 int access);
131
132 /**
133 * Visits a field of the class.
134 *
135 * @param access the field's access flags (see {@link Opcodes}). This
136 * parameter also indicates if the field is synthetic and/or
137 * deprecated.
138 * @param name the field's name.
139 * @param desc the field's descriptor (see {@link Type Type}).
140 * @param signature the field's signature. May be <tt>null</tt> if the
141 * field's type does not use generic types.
142 * @param value the field's initial value. This parameter, which may be
143 * <tt>null</tt> if the field does not have an initial value, must
144 * be an {@link Integer}, a {@link Float}, a {@link Long}, a
145 * {@link Double} or a {@link String} (for <tt>int</tt>,
146 * <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
147 * respectively). <i>This parameter is only used for static fields</i>.
148 * Its value is ignored for non static fields, which must be
149 * initialized through bytecode instructions in constructors or
150 * methods.
151 * @return a visitor to visit field annotations and attributes, or
152 * <tt>null</tt> if this class visitor is not interested in
153 * visiting these annotations and attributes.
154 */
155 FieldVisitor visitField(
156 int access,
157 String name,
158 String desc,
159 String signature,
160 Object value);
161
162 /**
163 * Visits a method of the class. This method <i>must</i> return a new
164 * {@link MethodVisitor} instance (or <tt>null</tt>) each time it is
165 * called, i.e., it should not return a previously returned visitor.
166 *
167 * @param access the method's access flags (see {@link Opcodes}). This
168 * parameter also indicates if the method is synthetic and/or
169 * deprecated.
170 * @param name the method's name.
171 * @param desc the method's descriptor (see {@link Type Type}).
172 * @param signature the method's signature. May be <tt>null</tt> if the
173 * method parameters, return type and exceptions do not use generic
174 * types.
175 * @param exceptions the internal names of the method's exception classes
176 * (see {@link Type#getInternalName() getInternalName}). May be
177 * <tt>null</tt>.
178 * @return an object to visit the byte code of the method, or <tt>null</tt>
179 * if this class visitor is not interested in visiting the code of
180 * this method.
181 */
182 MethodVisitor visitMethod(
183 int access,
184 String name,
185 String desc,
186 String signature,
187 String[] exceptions);
188
189 /**
190 * Visits the end of the class. This method, which is the last one to be
191 * called, is used to inform the visitor that all the fields and methods of
192 * the class have been visited.
193 */
194 void visitEnd();
195 }
+0
-1415
src/jvm/clojure/asm/ClassWriter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * A {@link ClassVisitor} that generates classes in bytecode form. More
33 * precisely this visitor generates a byte array conforming to the Java class
34 * file format. It can be used alone, to generate a Java class "from scratch",
35 * or with one or more {@link ClassReader ClassReader} and adapter class visitor
36 * to generate a modified class from one or more existing Java classes.
37 *
38 * @author Eric Bruneton
39 */
40 public class ClassWriter implements ClassVisitor{
41
42 /**
43 * Flag to automatically compute the maximum stack size and the maximum
44 * number of local variables of methods. If this flag is set, then the
45 * arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the
46 * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod}
47 * method will be ignored, and computed automatically from the signature and
48 * the bytecode of each method.
49 *
50 * @see #ClassWriter(int)
51 */
52 public final static int COMPUTE_MAXS = 1;
53
54 /**
55 * Flag to automatically compute the stack map frames of methods from
56 * scratch. If this flag is set, then the calls to the
57 * {@link MethodVisitor#visitFrame} method are ignored, and the stack map
58 * frames are recomputed from the methods bytecode. The arguments of the
59 * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and
60 * recomputed from the bytecode. In other words, computeFrames implies
61 * computeMaxs.
62 *
63 * @see #ClassWriter(int)
64 */
65 public final static int COMPUTE_FRAMES = 2;
66
67 /**
68 * The type of instructions without any argument.
69 */
70 final static int NOARG_INSN = 0;
71
72 /**
73 * The type of instructions with an signed byte argument.
74 */
75 final static int SBYTE_INSN = 1;
76
77 /**
78 * The type of instructions with an signed short argument.
79 */
80 final static int SHORT_INSN = 2;
81
82 /**
83 * The type of instructions with a local variable index argument.
84 */
85 final static int VAR_INSN = 3;
86
87 /**
88 * The type of instructions with an implicit local variable index argument.
89 */
90 final static int IMPLVAR_INSN = 4;
91
92 /**
93 * The type of instructions with a type descriptor argument.
94 */
95 final static int TYPE_INSN = 5;
96
97 /**
98 * The type of field and method invocations instructions.
99 */
100 final static int FIELDORMETH_INSN = 6;
101
102 /**
103 * The type of the INVOKEINTERFACE instruction.
104 */
105 final static int ITFMETH_INSN = 7;
106
107 /**
108 * The type of instructions with a 2 bytes bytecode offset label.
109 */
110 final static int LABEL_INSN = 8;
111
112 /**
113 * The type of instructions with a 4 bytes bytecode offset label.
114 */
115 final static int LABELW_INSN = 9;
116
117 /**
118 * The type of the LDC instruction.
119 */
120 final static int LDC_INSN = 10;
121
122 /**
123 * The type of the LDC_W and LDC2_W instructions.
124 */
125 final static int LDCW_INSN = 11;
126
127 /**
128 * The type of the IINC instruction.
129 */
130 final static int IINC_INSN = 12;
131
132 /**
133 * The type of the TABLESWITCH instruction.
134 */
135 final static int TABL_INSN = 13;
136
137 /**
138 * The type of the LOOKUPSWITCH instruction.
139 */
140 final static int LOOK_INSN = 14;
141
142 /**
143 * The type of the MULTIANEWARRAY instruction.
144 */
145 final static int MANA_INSN = 15;
146
147 /**
148 * The type of the WIDE instruction.
149 */
150 final static int WIDE_INSN = 16;
151
152 /**
153 * The instruction types of all JVM opcodes.
154 */
155 static byte[] TYPE;
156
157 /**
158 * The type of CONSTANT_Class constant pool items.
159 */
160 final static int CLASS = 7;
161
162 /**
163 * The type of CONSTANT_Fieldref constant pool items.
164 */
165 final static int FIELD = 9;
166
167 /**
168 * The type of CONSTANT_Methodref constant pool items.
169 */
170 final static int METH = 10;
171
172 /**
173 * The type of CONSTANT_InterfaceMethodref constant pool items.
174 */
175 final static int IMETH = 11;
176
177 /**
178 * The type of CONSTANT_String constant pool items.
179 */
180 final static int STR = 8;
181
182 /**
183 * The type of CONSTANT_Integer constant pool items.
184 */
185 final static int INT = 3;
186
187 /**
188 * The type of CONSTANT_Float constant pool items.
189 */
190 final static int FLOAT = 4;
191
192 /**
193 * The type of CONSTANT_Long constant pool items.
194 */
195 final static int LONG = 5;
196
197 /**
198 * The type of CONSTANT_Double constant pool items.
199 */
200 final static int DOUBLE = 6;
201
202 /**
203 * The type of CONSTANT_NameAndType constant pool items.
204 */
205 final static int NAME_TYPE = 12;
206
207 /**
208 * The type of CONSTANT_Utf8 constant pool items.
209 */
210 final static int UTF8 = 1;
211
212 /**
213 * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable},
214 * instead of the constant pool, in order to avoid clashes with normal
215 * constant pool items in the ClassWriter constant pool's hash table.
216 */
217 final static int TYPE_NORMAL = 13;
218
219 /**
220 * Uninitialized type Item stored in the ClassWriter
221 * {@link ClassWriter#typeTable}, instead of the constant pool, in order to
222 * avoid clashes with normal constant pool items in the ClassWriter constant
223 * pool's hash table.
224 */
225 final static int TYPE_UNINIT = 14;
226
227 /**
228 * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable},
229 * instead of the constant pool, in order to avoid clashes with normal
230 * constant pool items in the ClassWriter constant pool's hash table.
231 */
232 final static int TYPE_MERGED = 15;
233
234 /**
235 * The class reader from which this class writer was constructed, if any.
236 */
237 ClassReader cr;
238
239 /**
240 * Minor and major version numbers of the class to be generated.
241 */
242 int version;
243
244 /**
245 * Index of the next item to be added in the constant pool.
246 */
247 int index;
248
249 /**
250 * The constant pool of this class.
251 */
252 ByteVector pool;
253
254 /**
255 * The constant pool's hash table data.
256 */
257 Item[] items;
258
259 /**
260 * The threshold of the constant pool's hash table.
261 */
262 int threshold;
263
264 /**
265 * A reusable key used to look for items in the {@link #items} hash table.
266 */
267 Item key;
268
269 /**
270 * A reusable key used to look for items in the {@link #items} hash table.
271 */
272 Item key2;
273
274 /**
275 * A reusable key used to look for items in the {@link #items} hash table.
276 */
277 Item key3;
278
279 /**
280 * A type table used to temporarily store internal names that will not
281 * necessarily be stored in the constant pool. This type table is used by
282 * the control flow and data flow analysis algorithm used to compute stack
283 * map frames from scratch. This array associates to each index <tt>i</tt>
284 * the Item whose index is <tt>i</tt>. All Item objects stored in this
285 * array are also stored in the {@link #items} hash table. These two arrays
286 * allow to retrieve an Item from its index or, conversly, to get the index
287 * of an Item from its value. Each Item stores an internal name in its
288 * {@link Item#strVal1} field.
289 */
290 Item[] typeTable;
291
292 /**
293 * Number of elements in the {@link #typeTable} array.
294 */
295 private short typeCount; // TODO int?
296
297 /**
298 * The access flags of this class.
299 */
300 private int access;
301
302 /**
303 * The constant pool item that contains the internal name of this class.
304 */
305 private int name;
306
307 /**
308 * The internal name of this class.
309 */
310 String thisName;
311
312 /**
313 * The constant pool item that contains the signature of this class.
314 */
315 private int signature;
316
317 /**
318 * The constant pool item that contains the internal name of the super class
319 * of this class.
320 */
321 private int superName;
322
323 /**
324 * Number of interfaces implemented or extended by this class or interface.
325 */
326 private int interfaceCount;
327
328 /**
329 * The interfaces implemented or extended by this class or interface. More
330 * precisely, this array contains the indexes of the constant pool items
331 * that contain the internal names of these interfaces.
332 */
333 private int[] interfaces;
334
335 /**
336 * The index of the constant pool item that contains the name of the source
337 * file from which this class was compiled.
338 */
339 private int sourceFile;
340
341 /**
342 * The SourceDebug attribute of this class.
343 */
344 private ByteVector sourceDebug;
345
346 /**
347 * The constant pool item that contains the name of the enclosing class of
348 * this class.
349 */
350 private int enclosingMethodOwner;
351
352 /**
353 * The constant pool item that contains the name and descriptor of the
354 * enclosing method of this class.
355 */
356 private int enclosingMethod;
357
358 /**
359 * The runtime visible annotations of this class.
360 */
361 private AnnotationWriter anns;
362
363 /**
364 * The runtime invisible annotations of this class.
365 */
366 private AnnotationWriter ianns;
367
368 /**
369 * The non standard attributes of this class.
370 */
371 private Attribute attrs;
372
373 /**
374 * The number of entries in the InnerClasses attribute.
375 */
376 private int innerClassesCount;
377
378 /**
379 * The InnerClasses attribute.
380 */
381 private ByteVector innerClasses;
382
383 /**
384 * The fields of this class. These fields are stored in a linked list of
385 * {@link FieldWriter} objects, linked to each other by their
386 * {@link FieldWriter#next} field. This field stores the first element of
387 * this list.
388 */
389 FieldWriter firstField;
390
391 /**
392 * The fields of this class. These fields are stored in a linked list of
393 * {@link FieldWriter} objects, linked to each other by their
394 * {@link FieldWriter#next} field. This field stores the last element of
395 * this list.
396 */
397 FieldWriter lastField;
398
399 /**
400 * The methods of this class. These methods are stored in a linked list of
401 * {@link MethodWriter} objects, linked to each other by their
402 * {@link MethodWriter#next} field. This field stores the first element of
403 * this list.
404 */
405 MethodWriter firstMethod;
406
407 /**
408 * The methods of this class. These methods are stored in a linked list of
409 * {@link MethodWriter} objects, linked to each other by their
410 * {@link MethodWriter#next} field. This field stores the last element of
411 * this list.
412 */
413 MethodWriter lastMethod;
414
415 /**
416 * <tt>true</tt> if the maximum stack size and number of local variables
417 * must be automatically computed.
418 */
419 private boolean computeMaxs;
420
421 /**
422 * <tt>true</tt> if the stack map frames must be recomputed from scratch.
423 */
424 private boolean computeFrames;
425
426 /**
427 * <tt>true</tt> if the stack map tables of this class are invalid. The
428 * {@link MethodWriter#resizeInstructions} method cannot transform existing
429 * stack map tables, and so produces potentially invalid classes when it is
430 * executed. In this case the class is reread and rewritten with the
431 * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize
432 * stack map tables when this option is used).
433 */
434 boolean invalidFrames;
435
436 // ------------------------------------------------------------------------
437 // Static initializer
438 // ------------------------------------------------------------------------
439
440 /**
441 * Computes the instruction types of JVM opcodes.
442 */
443 static
444 {
445 int i;
446 byte[] b = new byte[220];
447 String s = "AAAAAAAAAAAAAAAABCKLLDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"
448 + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
449 + "AAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAIIIIIIIIIIIIIIIIDNOAA"
450 + "AAAAGGGGGGGHAFBFAAFFAAQPIIJJIIIIIIIIIIIIIIIIII";
451 for(i = 0; i < b.length; ++i)
452 {
453 b[i] = (byte) (s.charAt(i) - 'A');
454 }
455 TYPE = b;
456
457 // code to generate the above string
458 //
459 // // SBYTE_INSN instructions
460 // b[Constants.NEWARRAY] = SBYTE_INSN;
461 // b[Constants.BIPUSH] = SBYTE_INSN;
462 //
463 // // SHORT_INSN instructions
464 // b[Constants.SIPUSH] = SHORT_INSN;
465 //
466 // // (IMPL)VAR_INSN instructions
467 // b[Constants.RET] = VAR_INSN;
468 // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) {
469 // b[i] = VAR_INSN;
470 // }
471 // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) {
472 // b[i] = VAR_INSN;
473 // }
474 // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3
475 // b[i] = IMPLVAR_INSN;
476 // }
477 // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3
478 // b[i] = IMPLVAR_INSN;
479 // }
480 //
481 // // TYPE_INSN instructions
482 // b[Constants.NEW] = TYPE_INSN;
483 // b[Constants.ANEWARRAY] = TYPE_INSN;
484 // b[Constants.CHECKCAST] = TYPE_INSN;
485 // b[Constants.INSTANCEOF] = TYPE_INSN;
486 //
487 // // (Set)FIELDORMETH_INSN instructions
488 // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) {
489 // b[i] = FIELDORMETH_INSN;
490 // }
491 // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN;
492 //
493 // // LABEL(W)_INSN instructions
494 // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) {
495 // b[i] = LABEL_INSN;
496 // }
497 // b[Constants.IFNULL] = LABEL_INSN;
498 // b[Constants.IFNONNULL] = LABEL_INSN;
499 // b[200] = LABELW_INSN; // GOTO_W
500 // b[201] = LABELW_INSN; // JSR_W
501 // // temporary opcodes used internally by ASM - see Label and
502 // MethodWriter
503 // for (i = 202; i < 220; ++i) {
504 // b[i] = LABEL_INSN;
505 // }
506 //
507 // // LDC(_W) instructions
508 // b[Constants.LDC] = LDC_INSN;
509 // b[19] = LDCW_INSN; // LDC_W
510 // b[20] = LDCW_INSN; // LDC2_W
511 //
512 // // special instructions
513 // b[Constants.IINC] = IINC_INSN;
514 // b[Constants.TABLESWITCH] = TABL_INSN;
515 // b[Constants.LOOKUPSWITCH] = LOOK_INSN;
516 // b[Constants.MULTIANEWARRAY] = MANA_INSN;
517 // b[196] = WIDE_INSN; // WIDE
518 //
519 // for (i = 0; i < b.length; ++i) {
520 // System.err.print((char)('A' + b[i]));
521 // }
522 // System.err.println();
523 }
524
525 // ------------------------------------------------------------------------
526 // Constructor
527 // ------------------------------------------------------------------------
528
529 /**
530 * Constructs a new {@link ClassWriter} object.
531 *
532 * @param flags option flags that can be used to modify the default behavior
533 * of this class. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}.
534 */
535 public ClassWriter(final int flags){
536 index = 1;
537 pool = new ByteVector();
538 items = new Item[256];
539 threshold = (int) (0.75d * items.length);
540 key = new Item();
541 key2 = new Item();
542 key3 = new Item();
543 this.computeMaxs = (flags & COMPUTE_MAXS) != 0;
544 this.computeFrames = (flags & COMPUTE_FRAMES) != 0;
545 }
546
547 /**
548 * Constructs a new {@link ClassWriter} object and enables optimizations for
549 * "mostly add" bytecode transformations. These optimizations are the
550 * following:
551 * <p/>
552 * <ul> <li>The constant pool from the original class is copied as is in
553 * the new class, which saves time. New constant pool entries will be added
554 * at the end if necessary, but unused constant pool entries <i>won't be
555 * removed</i>.</li> <li>Methods that are not transformed are copied as
556 * is in the new class, directly from the original class bytecode (i.e.
557 * without emitting visit events for all the method instructions), which
558 * saves a <i>lot</i> of time. Untransformed methods are detected by the
559 * fact that the {@link ClassReader} receives {@link MethodVisitor} objects
560 * that come from a {@link ClassWriter} (and not from a custom
561 * {@link ClassAdapter} or any other {@link ClassVisitor} instance).</li>
562 * </ul>
563 *
564 * @param classReader the {@link ClassReader} used to read the original
565 * class. It will be used to copy the entire constant pool from the
566 * original class and also to copy other fragments of original
567 * bytecode where applicable.
568 * @param flags option flags that can be used to modify the default behavior
569 * of this class. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}.
570 */
571 public ClassWriter(final ClassReader classReader, final int flags){
572 this(flags);
573 classReader.copyPool(this);
574 this.cr = classReader;
575 }
576
577 // ------------------------------------------------------------------------
578 // Implementation of the ClassVisitor interface
579 // ------------------------------------------------------------------------
580
581 public void visit(
582 final int version,
583 final int access,
584 final String name,
585 final String signature,
586 final String superName,
587 final String[] interfaces){
588 this.version = version;
589 this.access = access;
590 this.name = newClass(name);
591 thisName = name;
592 if(signature != null)
593 {
594 this.signature = newUTF8(signature);
595 }
596 this.superName = superName == null ? 0 : newClass(superName);
597 if(interfaces != null && interfaces.length > 0)
598 {
599 interfaceCount = interfaces.length;
600 this.interfaces = new int[interfaceCount];
601 for(int i = 0; i < interfaceCount; ++i)
602 {
603 this.interfaces[i] = newClass(interfaces[i]);
604 }
605 }
606 }
607
608 public void visitSource(final String file, final String debug){
609 if(file != null)
610 {
611 sourceFile = newUTF8(file);
612 }
613 if(debug != null)
614 {
615 sourceDebug = new ByteVector().putUTF8(debug);
616 }
617 }
618
619 public void visitOuterClass(
620 final String owner,
621 final String name,
622 final String desc){
623 enclosingMethodOwner = newClass(owner);
624 if(name != null && desc != null)
625 {
626 enclosingMethod = newNameType(name, desc);
627 }
628 }
629
630 public AnnotationVisitor visitAnnotation(
631 final String desc,
632 final boolean visible){
633 ByteVector bv = new ByteVector();
634 // write type, and reserve space for values count
635 bv.putShort(newUTF8(desc)).putShort(0);
636 AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2);
637 if(visible)
638 {
639 aw.next = anns;
640 anns = aw;
641 }
642 else
643 {
644 aw.next = ianns;
645 ianns = aw;
646 }
647 return aw;
648 }
649
650 public void visitAttribute(final Attribute attr){
651 attr.next = attrs;
652 attrs = attr;
653 }
654
655 public void visitInnerClass(
656 final String name,
657 final String outerName,
658 final String innerName,
659 final int access){
660 if(innerClasses == null)
661 {
662 innerClasses = new ByteVector();
663 }
664 ++innerClassesCount;
665 innerClasses.putShort(name == null ? 0 : newClass(name));
666 innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
667 innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
668 innerClasses.putShort(access);
669 }
670
671 public FieldVisitor visitField(
672 final int access,
673 final String name,
674 final String desc,
675 final String signature,
676 final Object value){
677 return new FieldWriter(this, access, name, desc, signature, value);
678 }
679
680 public MethodVisitor visitMethod(
681 final int access,
682 final String name,
683 final String desc,
684 final String signature,
685 final String[] exceptions){
686 return new MethodWriter(this,
687 access,
688 name,
689 desc,
690 signature,
691 exceptions,
692 computeMaxs,
693 computeFrames);
694 }
695
696 public void visitEnd(){
697 }
698
699 // ------------------------------------------------------------------------
700 // Other public methods
701 // ------------------------------------------------------------------------
702
703 /**
704 * Returns the bytecode of the class that was build with this class writer.
705 *
706 * @return the bytecode of the class that was build with this class writer.
707 */
708 public byte[] toByteArray(){
709 // computes the real size of the bytecode of this class
710 int size = 24 + 2 * interfaceCount;
711 int nbFields = 0;
712 FieldWriter fb = firstField;
713 while(fb != null)
714 {
715 ++nbFields;
716 size += fb.getSize();
717 fb = fb.next;
718 }
719 int nbMethods = 0;
720 MethodWriter mb = firstMethod;
721 while(mb != null)
722 {
723 ++nbMethods;
724 size += mb.getSize();
725 mb = mb.next;
726 }
727 int attributeCount = 0;
728 if(signature != 0)
729 {
730 ++attributeCount;
731 size += 8;
732 newUTF8("Signature");
733 }
734 if(sourceFile != 0)
735 {
736 ++attributeCount;
737 size += 8;
738 newUTF8("SourceFile");
739 }
740 if(sourceDebug != null)
741 {
742 ++attributeCount;
743 size += sourceDebug.length + 4;
744 newUTF8("SourceDebugExtension");
745 }
746 if(enclosingMethodOwner != 0)
747 {
748 ++attributeCount;
749 size += 10;
750 newUTF8("EnclosingMethod");
751 }
752 if((access & Opcodes.ACC_DEPRECATED) != 0)
753 {
754 ++attributeCount;
755 size += 6;
756 newUTF8("Deprecated");
757 }
758 if((access & Opcodes.ACC_SYNTHETIC) != 0
759 && (version & 0xffff) < Opcodes.V1_5)
760 {
761 ++attributeCount;
762 size += 6;
763 newUTF8("Synthetic");
764 }
765 if(innerClasses != null)
766 {
767 ++attributeCount;
768 size += 8 + innerClasses.length;
769 newUTF8("InnerClasses");
770 }
771 if(anns != null)
772 {
773 ++attributeCount;
774 size += 8 + anns.getSize();
775 newUTF8("RuntimeVisibleAnnotations");
776 }
777 if(ianns != null)
778 {
779 ++attributeCount;
780 size += 8 + ianns.getSize();
781 newUTF8("RuntimeInvisibleAnnotations");
782 }
783 if(attrs != null)
784 {
785 attributeCount += attrs.getCount();
786 size += attrs.getSize(this, null, 0, -1, -1);
787 }
788 size += pool.length;
789 // allocates a byte vector of this size, in order to avoid unnecessary
790 // arraycopy operations in the ByteVector.enlarge() method
791 ByteVector out = new ByteVector(size);
792 out.putInt(0xCAFEBABE).putInt(version);
793 out.putShort(index).putByteArray(pool.data, 0, pool.length);
794 out.putShort(access).putShort(name).putShort(superName);
795 out.putShort(interfaceCount);
796 for(int i = 0; i < interfaceCount; ++i)
797 {
798 out.putShort(interfaces[i]);
799 }
800 out.putShort(nbFields);
801 fb = firstField;
802 while(fb != null)
803 {
804 fb.put(out);
805 fb = fb.next;
806 }
807 out.putShort(nbMethods);
808 mb = firstMethod;
809 while(mb != null)
810 {
811 mb.put(out);
812 mb = mb.next;
813 }
814 out.putShort(attributeCount);
815 if(signature != 0)
816 {
817 out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
818 }
819 if(sourceFile != 0)
820 {
821 out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
822 }
823 if(sourceDebug != null)
824 {
825 int len = sourceDebug.length - 2;
826 out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
827 out.putByteArray(sourceDebug.data, 2, len);
828 }
829 if(enclosingMethodOwner != 0)
830 {
831 out.putShort(newUTF8("EnclosingMethod")).putInt(4);
832 out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
833 }
834 if((access & Opcodes.ACC_DEPRECATED) != 0)
835 {
836 out.putShort(newUTF8("Deprecated")).putInt(0);
837 }
838 if((access & Opcodes.ACC_SYNTHETIC) != 0
839 && (version & 0xffff) < Opcodes.V1_5)
840 {
841 out.putShort(newUTF8("Synthetic")).putInt(0);
842 }
843 if(innerClasses != null)
844 {
845 out.putShort(newUTF8("InnerClasses"));
846 out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
847 out.putByteArray(innerClasses.data, 0, innerClasses.length);
848 }
849 if(anns != null)
850 {
851 out.putShort(newUTF8("RuntimeVisibleAnnotations"));
852 anns.put(out);
853 }
854 if(ianns != null)
855 {
856 out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
857 ianns.put(out);
858 }
859 if(attrs != null)
860 {
861 attrs.put(this, null, 0, -1, -1, out);
862 }
863 if(invalidFrames)
864 {
865 ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
866 new ClassReader(out.data).accept(cw, ClassReader.SKIP_FRAMES);
867 return cw.toByteArray();
868 }
869 return out.data;
870 }
871
872 // ------------------------------------------------------------------------
873 // Utility methods: constant pool management
874 // ------------------------------------------------------------------------
875
876 /**
877 * Adds a number or string constant to the constant pool of the class being
878 * build. Does nothing if the constant pool already contains a similar item.
879 *
880 * @param cst the value of the constant to be added to the constant pool.
881 * This parameter must be an {@link Integer}, a {@link Float}, a
882 * {@link Long}, a {@link Double}, a {@link String} or a
883 * {@link Type}.
884 * @return a new or already existing constant item with the given value.
885 */
886 Item newConstItem(final Object cst){
887 if(cst instanceof Integer)
888 {
889 int val = ((Integer) cst).intValue();
890 return newInteger(val);
891 }
892 else if(cst instanceof Byte)
893 {
894 int val = ((Byte) cst).intValue();
895 return newInteger(val);
896 }
897 else if(cst instanceof Character)
898 {
899 int val = ((Character) cst).charValue();
900 return newInteger(val);
901 }
902 else if(cst instanceof Short)
903 {
904 int val = ((Short) cst).intValue();
905 return newInteger(val);
906 }
907 else if(cst instanceof Boolean)
908 {
909 int val = ((Boolean) cst).booleanValue() ? 1 : 0;
910 return newInteger(val);
911 }
912 else if(cst instanceof Float)
913 {
914 float val = ((Float) cst).floatValue();
915 return newFloat(val);
916 }
917 else if(cst instanceof Long)
918 {
919 long val = ((Long) cst).longValue();
920 return newLong(val);
921 }
922 else if(cst instanceof Double)
923 {
924 double val = ((Double) cst).doubleValue();
925 return newDouble(val);
926 }
927 else if(cst instanceof String)
928 {
929 return newString((String) cst);
930 }
931 else if(cst instanceof Type)
932 {
933 Type t = (Type) cst;
934 return newClassItem(t.getSort() == Type.OBJECT
935 ? t.getInternalName()
936 : t.getDescriptor());
937 }
938 else
939 {
940 throw new IllegalArgumentException("value " + cst);
941 }
942 }
943
944 /**
945 * Adds a number or string constant to the constant pool of the class being
946 * build. Does nothing if the constant pool already contains a similar item.
947 * <i>This method is intended for {@link Attribute} sub classes, and is
948 * normally not needed by class generators or adapters.</i>
949 *
950 * @param cst the value of the constant to be added to the constant pool.
951 * This parameter must be an {@link Integer}, a {@link Float}, a
952 * {@link Long}, a {@link Double} or a {@link String}.
953 * @return the index of a new or already existing constant item with the
954 * given value.
955 */
956 public int newConst(final Object cst){
957 return newConstItem(cst).index;
958 }
959
960 /**
961 * Adds an UTF8 string to the constant pool of the class being build. Does
962 * nothing if the constant pool already contains a similar item. <i>This
963 * method is intended for {@link Attribute} sub classes, and is normally not
964 * needed by class generators or adapters.</i>
965 *
966 * @param value the String value.
967 * @return the index of a new or already existing UTF8 item.
968 */
969 public int newUTF8(final String value){
970 key.set(UTF8, value, null, null);
971 Item result = get(key);
972 if(result == null)
973 {
974 pool.putByte(UTF8).putUTF8(value);
975 result = new Item(index++, key);
976 put(result);
977 }
978 return result.index;
979 }
980
981 /**
982 * Adds a class reference to the constant pool of the class being build.
983 * Does nothing if the constant pool already contains a similar item.
984 * <i>This method is intended for {@link Attribute} sub classes, and is
985 * normally not needed by class generators or adapters.</i>
986 *
987 * @param value the internal name of the class.
988 * @return a new or already existing class reference item.
989 */
990 Item newClassItem(final String value){
991 key2.set(CLASS, value, null, null);
992 Item result = get(key2);
993 if(result == null)
994 {
995 pool.put12(CLASS, newUTF8(value));
996 result = new Item(index++, key2);
997 put(result);
998 }
999 return result;
1000 }
1001
1002 /**
1003 * Adds a class reference to the constant pool of the class being build.
1004 * Does nothing if the constant pool already contains a similar item.
1005 * <i>This method is intended for {@link Attribute} sub classes, and is
1006 * normally not needed by class generators or adapters.</i>
1007 *
1008 * @param value the internal name of the class.
1009 * @return the index of a new or already existing class reference item.
1010 */
1011 public int newClass(final String value){
1012 return newClassItem(value).index;
1013 }
1014
1015 /**
1016 * Adds a field reference to the constant pool of the class being build.
1017 * Does nothing if the constant pool already contains a similar item.
1018 *
1019 * @param owner the internal name of the field's owner class.
1020 * @param name the field's name.
1021 * @param desc the field's descriptor.
1022 * @return a new or already existing field reference item.
1023 */
1024 Item newFieldItem(final String owner, final String name, final String desc){
1025 key3.set(FIELD, owner, name, desc);
1026 Item result = get(key3);
1027 if(result == null)
1028 {
1029 put122(FIELD, newClass(owner), newNameType(name, desc));
1030 result = new Item(index++, key3);
1031 put(result);
1032 }
1033 return result;
1034 }
1035
1036 /**
1037 * Adds a field reference to the constant pool of the class being build.
1038 * Does nothing if the constant pool already contains a similar item.
1039 * <i>This method is intended for {@link Attribute} sub classes, and is
1040 * normally not needed by class generators or adapters.</i>
1041 *
1042 * @param owner the internal name of the field's owner class.
1043 * @param name the field's name.
1044 * @param desc the field's descriptor.
1045 * @return the index of a new or already existing field reference item.
1046 */
1047 public int newField(final String owner, final String name, final String desc){
1048 return newFieldItem(owner, name, desc).index;
1049 }
1050
1051 /**
1052 * Adds a method reference to the constant pool of the class being build.
1053 * Does nothing if the constant pool already contains a similar item.
1054 *
1055 * @param owner the internal name of the method's owner class.
1056 * @param name the method's name.
1057 * @param desc the method's descriptor.
1058 * @param itf <tt>true</tt> if <tt>owner</tt> is an interface.
1059 * @return a new or already existing method reference item.
1060 */
1061 Item newMethodItem(
1062 final String owner,
1063 final String name,
1064 final String desc,
1065 final boolean itf){
1066 int type = itf ? IMETH : METH;
1067 key3.set(type, owner, name, desc);
1068 Item result = get(key3);
1069 if(result == null)
1070 {
1071 put122(type, newClass(owner), newNameType(name, desc));
1072 result = new Item(index++, key3);
1073 put(result);
1074 }
1075 return result;
1076 }
1077
1078 /**
1079 * Adds a method reference to the constant pool of the class being build.
1080 * Does nothing if the constant pool already contains a similar item.
1081 * <i>This method is intended for {@link Attribute} sub classes, and is
1082 * normally not needed by class generators or adapters.</i>
1083 *
1084 * @param owner the internal name of the method's owner class.
1085 * @param name the method's name.
1086 * @param desc the method's descriptor.
1087 * @param itf <tt>true</tt> if <tt>owner</tt> is an interface.
1088 * @return the index of a new or already existing method reference item.
1089 */
1090 public int newMethod(
1091 final String owner,
1092 final String name,
1093 final String desc,
1094 final boolean itf){
1095 return newMethodItem(owner, name, desc, itf).index;
1096 }
1097
1098 /**
1099 * Adds an integer to the constant pool of the class being build. Does
1100 * nothing if the constant pool already contains a similar item.
1101 *
1102 * @param value the int value.
1103 * @return a new or already existing int item.
1104 */
1105 Item newInteger(final int value){
1106 key.set(value);
1107 Item result = get(key);
1108 if(result == null)
1109 {
1110 pool.putByte(INT).putInt(value);
1111 result = new Item(index++, key);
1112 put(result);
1113 }
1114 return result;
1115 }
1116
1117 /**
1118 * Adds a float to the constant pool of the class being build. Does nothing
1119 * if the constant pool already contains a similar item.
1120 *
1121 * @param value the float value.
1122 * @return a new or already existing float item.
1123 */
1124 Item newFloat(final float value){
1125 key.set(value);
1126 Item result = get(key);
1127 if(result == null)
1128 {
1129 pool.putByte(FLOAT).putInt(key.intVal);
1130 result = new Item(index++, key);
1131 put(result);
1132 }
1133 return result;
1134 }
1135
1136 /**
1137 * Adds a long to the constant pool of the class being build. Does nothing
1138 * if the constant pool already contains a similar item.
1139 *
1140 * @param value the long value.
1141 * @return a new or already existing long item.
1142 */
1143 Item newLong(final long value){
1144 key.set(value);
1145 Item result = get(key);
1146 if(result == null)
1147 {
1148 pool.putByte(LONG).putLong(value);
1149 result = new Item(index, key);
1150 put(result);
1151 index += 2;
1152 }
1153 return result;
1154 }
1155
1156 /**
1157 * Adds a double to the constant pool of the class being build. Does nothing
1158 * if the constant pool already contains a similar item.
1159 *
1160 * @param value the double value.
1161 * @return a new or already existing double item.
1162 */
1163 Item newDouble(final double value){
1164 key.set(value);
1165 Item result = get(key);
1166 if(result == null)
1167 {
1168 pool.putByte(DOUBLE).putLong(key.longVal);
1169 result = new Item(index, key);
1170 put(result);
1171 index += 2;
1172 }
1173 return result;
1174 }
1175
1176 /**
1177 * Adds a string to the constant pool of the class being build. Does nothing
1178 * if the constant pool already contains a similar item.
1179 *
1180 * @param value the String value.
1181 * @return a new or already existing string item.
1182 */
1183 private Item newString(final String value){
1184 key2.set(STR, value, null, null);
1185 Item result = get(key2);
1186 if(result == null)
1187 {
1188 pool.put12(STR, newUTF8(value));
1189 result = new Item(index++, key2);
1190 put(result);
1191 }
1192 return result;
1193 }
1194
1195 /**
1196 * Adds a name and type to the constant pool of the class being build. Does
1197 * nothing if the constant pool already contains a similar item. <i>This
1198 * method is intended for {@link Attribute} sub classes, and is normally not
1199 * needed by class generators or adapters.</i>
1200 *
1201 * @param name a name.
1202 * @param desc a type descriptor.
1203 * @return the index of a new or already existing name and type item.
1204 */
1205 public int newNameType(final String name, final String desc){
1206 key2.set(NAME_TYPE, name, desc, null);
1207 Item result = get(key2);
1208 if(result == null)
1209 {
1210 put122(NAME_TYPE, newUTF8(name), newUTF8(desc));
1211 result = new Item(index++, key2);
1212 put(result);
1213 }
1214 return result.index;
1215 }
1216
1217 /**
1218 * Adds the given internal name to {@link #typeTable} and returns its index.
1219 * Does nothing if the type table already contains this internal name.
1220 *
1221 * @param type the internal name to be added to the type table.
1222 * @return the index of this internal name in the type table.
1223 */
1224 int addType(final String type){
1225 key.set(TYPE_NORMAL, type, null, null);
1226 Item result = get(key);
1227 if(result == null)
1228 {
1229 result = addType(key);
1230 }
1231 return result.index;
1232 }
1233
1234 /**
1235 * Adds the given "uninitialized" type to {@link #typeTable} and returns its
1236 * index. This method is used for UNINITIALIZED types, made of an internal
1237 * name and a bytecode offset.
1238 *
1239 * @param type the internal name to be added to the type table.
1240 * @param offset the bytecode offset of the NEW instruction that created
1241 * this UNINITIALIZED type value.
1242 * @return the index of this internal name in the type table.
1243 */
1244 int addUninitializedType(final String type, final int offset){
1245 key.type = TYPE_UNINIT;
1246 key.intVal = offset;
1247 key.strVal1 = type;
1248 key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset);
1249 Item result = get(key);
1250 if(result == null)
1251 {
1252 result = addType(key);
1253 }
1254 return result.index;
1255 }
1256
1257 /**
1258 * Adds the given Item to {@link #typeTable}.
1259 *
1260 * @param item the value to be added to the type table.
1261 * @return the added Item, which a new Item instance with the same value as
1262 * the given Item.
1263 */
1264 private Item addType(final Item item){
1265 ++typeCount;
1266 Item result = new Item(typeCount, key);
1267 put(result);
1268 if(typeTable == null)
1269 {
1270 typeTable = new Item[16];
1271 }
1272 if(typeCount == typeTable.length)
1273 {
1274 Item[] newTable = new Item[2 * typeTable.length];
1275 System.arraycopy(typeTable, 0, newTable, 0, typeTable.length);
1276 typeTable = newTable;
1277 }
1278 typeTable[typeCount] = result;
1279 return result;
1280 }
1281
1282 /**
1283 * Returns the index of the common super type of the two given types. This
1284 * method calls {@link #getCommonSuperClass} and caches the result in the
1285 * {@link #items} hash table to speedup future calls with the same
1286 * parameters.
1287 *
1288 * @param type1 index of an internal name in {@link #typeTable}.
1289 * @param type2 index of an internal name in {@link #typeTable}.
1290 * @return the index of the common super type of the two given types.
1291 */
1292 int getMergedType(final int type1, final int type2){
1293 key2.type = TYPE_MERGED;
1294 key2.longVal = type1 | (((long) type2) << 32);
1295 key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2);
1296 Item result = get(key2);
1297 if(result == null)
1298 {
1299 String t = typeTable[type1].strVal1;
1300 String u = typeTable[type2].strVal1;
1301 key2.intVal = addType(getCommonSuperClass(t, u));
1302 result = new Item((short) 0, key2);
1303 put(result);
1304 }
1305 return result.intVal;
1306 }
1307
1308 /**
1309 * Returns the common super type of the two given types. The default
1310 * implementation of this method <i>loads<i> the two given classes and uses
1311 * the java.lang.Class methods to find the common super class. It can be
1312 * overriden to compute this common super type in other ways, in particular
1313 * without actually loading any class, or to take into account the class
1314 * that is currently being generated by this ClassWriter, which can of
1315 * course not be loaded since it is under construction.
1316 *
1317 * @param type1 the internal name of a class.
1318 * @param type2 the internal name of another class.
1319 * @return the internal name of the common super class of the two given
1320 * classes.
1321 */
1322 protected String getCommonSuperClass(final String type1, final String type2){
1323 Class c, d;
1324 try
1325 {
1326 c = Class.forName(type1.replace('/', '.'));
1327 d = Class.forName(type2.replace('/', '.'));
1328 }
1329 catch(ClassNotFoundException e)
1330 {
1331 throw new RuntimeException(e);
1332 }
1333 if(c.isAssignableFrom(d))
1334 {
1335 return type1;
1336 }
1337 if(d.isAssignableFrom(c))
1338 {
1339 return type2;
1340 }
1341 if(c.isInterface() || d.isInterface())
1342 {
1343 return "java/lang/Object";
1344 }
1345 else
1346 {
1347 do
1348 {
1349 c = c.getSuperclass();
1350 } while(!c.isAssignableFrom(d));
1351 return c.getName().replace('.', '/');
1352 }
1353 }
1354
1355 /**
1356 * Returns the constant pool's hash table item which is equal to the given
1357 * item.
1358 *
1359 * @param key a constant pool item.
1360 * @return the constant pool's hash table item which is equal to the given
1361 * item, or <tt>null</tt> if there is no such item.
1362 */
1363 private Item get(final Item key){
1364 Item i = items[key.hashCode % items.length];
1365 while(i != null && !key.isEqualTo(i))
1366 {
1367 i = i.next;
1368 }
1369 return i;
1370 }
1371
1372 /**
1373 * Puts the given item in the constant pool's hash table. The hash table
1374 * <i>must</i> not already contains this item.
1375 *
1376 * @param i the item to be added to the constant pool's hash table.
1377 */
1378 private void put(final Item i){
1379 if(index > threshold)
1380 {
1381 int ll = items.length;
1382 int nl = ll * 2 + 1;
1383 Item[] newItems = new Item[nl];
1384 for(int l = ll - 1; l >= 0; --l)
1385 {
1386 Item j = items[l];
1387 while(j != null)
1388 {
1389 int index = j.hashCode % newItems.length;
1390 Item k = j.next;
1391 j.next = newItems[index];
1392 newItems[index] = j;
1393 j = k;
1394 }
1395 }
1396 items = newItems;
1397 threshold = (int) (nl * 0.75);
1398 }
1399 int index = i.hashCode % items.length;
1400 i.next = items[index];
1401 items[index] = i;
1402 }
1403
1404 /**
1405 * Puts one byte and two shorts into the constant pool.
1406 *
1407 * @param b a byte.
1408 * @param s1 a short.
1409 * @param s2 another short.
1410 */
1411 private void put122(final int b, final int s1, final int s2){
1412 pool.put12(b, s1).putShort(s2);
1413 }
1414 }
+0
-75
src/jvm/clojure/asm/Edge.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * An edge in the control flow graph of a method body. See {@link Label Label}.
33 *
34 * @author Eric Bruneton
35 */
36 class Edge{
37
38 /**
39 * Denotes a normal control flow graph edge.
40 */
41 final static int NORMAL = 0;
42
43 /**
44 * Denotes a control flow graph edge corresponding to an exception handler.
45 * More precisely any {@link Edge} whose {@link #info} is strictly positive
46 * corresponds to an exception handler. The actual value of {@link #info} is
47 * the index, in the {@link ClassWriter} type table, of the exception that
48 * is catched.
49 */
50 final static int EXCEPTION = 0x7FFFFFFF;
51
52 /**
53 * Information about this control flow graph edge. If
54 * {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative)
55 * stack size in the basic block from which this edge originates. This size
56 * is equal to the stack size at the "jump" instruction to which this edge
57 * corresponds, relatively to the stack size at the beginning of the
58 * originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used,
59 * this field is the kind of this control flow graph edge (i.e. NORMAL or
60 * EXCEPTION).
61 */
62 int info;
63
64 /**
65 * The successor block of the basic block from which this edge originates.
66 */
67 Label successor;
68
69 /**
70 * The next edge in the list of successors of the originating basic block.
71 * See {@link Label#successors successors}.
72 */
73 Edge next;
74 }
+0
-64
src/jvm/clojure/asm/FieldVisitor.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * A visitor to visit a Java field. The methods of this interface must be called
33 * in the following order: ( <tt>visitAnnotation</tt> |
34 * <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
35 *
36 * @author Eric Bruneton
37 */
38 public interface FieldVisitor{
39
40 /**
41 * Visits an annotation of the field.
42 *
43 * @param desc the class descriptor of the annotation class.
44 * @param visible <tt>true</tt> if the annotation is visible at runtime.
45 * @return a visitor to visit the annotation values, or <tt>null</tt> if
46 * this visitor is not interested in visiting this annotation.
47 */
48 AnnotationVisitor visitAnnotation(String desc, boolean visible);
49
50 /**
51 * Visits a non standard attribute of the field.
52 *
53 * @param attr an attribute.
54 */
55 void visitAttribute(Attribute attr);
56
57 /**
58 * Visits the end of the field. This method, which is the last one to be
59 * called, is used to inform the visitor that all the annotations and
60 * attributes of the field have been visited.
61 */
62 void visitEnd();
63 }
+0
-290
src/jvm/clojure/asm/FieldWriter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * An {@link FieldVisitor} that generates Java fields in bytecode form.
33 *
34 * @author Eric Bruneton
35 */
36 final class FieldWriter implements FieldVisitor{
37
38 /**
39 * Next field writer (see {@link ClassWriter#firstField firstField}).
40 */
41 FieldWriter next;
42
43 /**
44 * The class writer to which this field must be added.
45 */
46 private ClassWriter cw;
47
48 /**
49 * Access flags of this field.
50 */
51 private int access;
52
53 /**
54 * The index of the constant pool item that contains the name of this
55 * method.
56 */
57 private int name;
58
59 /**
60 * The index of the constant pool item that contains the descriptor of this
61 * field.
62 */
63 private int desc;
64
65 /**
66 * The index of the constant pool item that contains the signature of this
67 * field.
68 */
69 private int signature;
70
71 /**
72 * The index of the constant pool item that contains the constant value of
73 * this field.
74 */
75 private int value;
76
77 /**
78 * The runtime visible annotations of this field. May be <tt>null</tt>.
79 */
80 private AnnotationWriter anns;
81
82 /**
83 * The runtime invisible annotations of this field. May be <tt>null</tt>.
84 */
85 private AnnotationWriter ianns;
86
87 /**
88 * The non standard attributes of this field. May be <tt>null</tt>.
89 */
90 private Attribute attrs;
91
92 // ------------------------------------------------------------------------
93 // Constructor
94 // ------------------------------------------------------------------------
95
96 /**
97 * Constructs a new {@link FieldWriter}.
98 *
99 * @param cw the class writer to which this field must be added.
100 * @param access the field's access flags (see {@link Opcodes}).
101 * @param name the field's name.
102 * @param desc the field's descriptor (see {@link Type}).
103 * @param signature the field's signature. May be <tt>null</tt>.
104 * @param value the field's constant value. May be <tt>null</tt>.
105 */
106 protected FieldWriter(
107 final ClassWriter cw,
108 final int access,
109 final String name,
110 final String desc,
111 final String signature,
112 final Object value){
113 if(cw.firstField == null)
114 {
115 cw.firstField = this;
116 }
117 else
118 {
119 cw.lastField.next = this;
120 }
121 cw.lastField = this;
122 this.cw = cw;
123 this.access = access;
124 this.name = cw.newUTF8(name);
125 this.desc = cw.newUTF8(desc);
126 if(signature != null)
127 {
128 this.signature = cw.newUTF8(signature);
129 }
130 if(value != null)
131 {
132 this.value = cw.newConstItem(value).index;
133 }
134 }
135
136 // ------------------------------------------------------------------------
137 // Implementation of the FieldVisitor interface
138 // ------------------------------------------------------------------------
139
140 public AnnotationVisitor visitAnnotation(
141 final String desc,
142 final boolean visible){
143 ByteVector bv = new ByteVector();
144 // write type, and reserve space for values count
145 bv.putShort(cw.newUTF8(desc)).putShort(0);
146 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
147 if(visible)
148 {
149 aw.next = anns;
150 anns = aw;
151 }
152 else
153 {
154 aw.next = ianns;
155 ianns = aw;
156 }
157 return aw;
158 }
159
160 public void visitAttribute(final Attribute attr){
161 attr.next = attrs;
162 attrs = attr;
163 }
164
165 public void visitEnd(){
166 }
167
168 // ------------------------------------------------------------------------
169 // Utility methods
170 // ------------------------------------------------------------------------
171
172 /**
173 * Returns the size of this field.
174 *
175 * @return the size of this field.
176 */
177 int getSize(){
178 int size = 8;
179 if(value != 0)
180 {
181 cw.newUTF8("ConstantValue");
182 size += 8;
183 }
184 if((access & Opcodes.ACC_SYNTHETIC) != 0
185 && (cw.version & 0xffff) < Opcodes.V1_5)
186 {
187 cw.newUTF8("Synthetic");
188 size += 6;
189 }
190 if((access & Opcodes.ACC_DEPRECATED) != 0)
191 {
192 cw.newUTF8("Deprecated");
193 size += 6;
194 }
195 if(signature != 0)
196 {
197 cw.newUTF8("Signature");
198 size += 8;
199 }
200 if(anns != null)
201 {
202 cw.newUTF8("RuntimeVisibleAnnotations");
203 size += 8 + anns.getSize();
204 }
205 if(ianns != null)
206 {
207 cw.newUTF8("RuntimeInvisibleAnnotations");
208 size += 8 + ianns.getSize();
209 }
210 if(attrs != null)
211 {
212 size += attrs.getSize(cw, null, 0, -1, -1);
213 }
214 return size;
215 }
216
217 /**
218 * Puts the content of this field into the given byte vector.
219 *
220 * @param out where the content of this field must be put.
221 */
222 void put(final ByteVector out){
223 out.putShort(access).putShort(name).putShort(desc);
224 int attributeCount = 0;
225 if(value != 0)
226 {
227 ++attributeCount;
228 }
229 if((access & Opcodes.ACC_SYNTHETIC) != 0
230 && (cw.version & 0xffff) < Opcodes.V1_5)
231 {
232 ++attributeCount;
233 }
234 if((access & Opcodes.ACC_DEPRECATED) != 0)
235 {
236 ++attributeCount;
237 }
238 if(signature != 0)
239 {
240 ++attributeCount;
241 }
242 if(anns != null)
243 {
244 ++attributeCount;
245 }
246 if(ianns != null)
247 {
248 ++attributeCount;
249 }
250 if(attrs != null)
251 {
252 attributeCount += attrs.getCount();
253 }
254 out.putShort(attributeCount);
255 if(value != 0)
256 {
257 out.putShort(cw.newUTF8("ConstantValue"));
258 out.putInt(2).putShort(value);
259 }
260 if((access & Opcodes.ACC_SYNTHETIC) != 0
261 && (cw.version & 0xffff) < Opcodes.V1_5)
262 {
263 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
264 }
265 if((access & Opcodes.ACC_DEPRECATED) != 0)
266 {
267 out.putShort(cw.newUTF8("Deprecated")).putInt(0);
268 }
269 if(signature != 0)
270 {
271 out.putShort(cw.newUTF8("Signature"));
272 out.putInt(2).putShort(signature);
273 }
274 if(anns != null)
275 {
276 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
277 anns.put(out);
278 }
279 if(ianns != null)
280 {
281 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
282 ianns.put(out);
283 }
284 if(attrs != null)
285 {
286 attrs.put(cw, null, 0, -1, -1, out);
287 }
288 }
289 }
+0
-1506
src/jvm/clojure/asm/Frame.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * Information about the input and output stack map frames of a basic block.
33 *
34 * @author Eric Bruneton
35 */
36 final class Frame{
37
38 /*
39 * Frames are computed in a two steps process: during the visit of each
40 * instruction, the state of the frame at the end of current basic block is
41 * updated by simulating the action of the instruction on the previous state
42 * of this so called "output frame". In visitMaxs, a fix point algorithm is
43 * used to compute the "input frame" of each basic block, i.e. the stack map
44 * frame at the begining of the basic block, starting from the input frame
45 * of the first basic block (which is computed from the method descriptor),
46 * and by using the previously computed output frames to compute the input
47 * state of the other blocks.
48 *
49 * All output and input frames are stored as arrays of integers. Reference
50 * and array types are represented by an index into a type table (which is
51 * not the same as the constant pool of the class, in order to avoid adding
52 * unnecessary constants in the pool - not all computed frames will end up
53 * being stored in the stack map table). This allows very fast type
54 * comparisons.
55 *
56 * Output stack map frames are computed relatively to the input frame of the
57 * basic block, which is not yet known when output frames are computed. It
58 * is therefore necessary to be able to represent abstract types such as
59 * "the type at position x in the input frame locals" or "the type at
60 * position x from the top of the input frame stack" or even "the type at
61 * position x in the input frame, with y more (or less) array dimensions".
62 * This explains the rather complicated type format used in output frames.
63 *
64 * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a
65 * signed number of array dimensions (from -8 to 7). KIND is either BASE,
66 * LOCAL or STACK. BASE is used for types that are not relative to the input
67 * frame. LOCAL is used for types that are relative to the input local
68 * variable types. STACK is used for types that are relative to the input
69 * stack types. VALUE depends on KIND. For LOCAL types, it is an index in
70 * the input local variable types. For STACK types, it is a position
71 * relatively to the top of input frame stack. For BASE types, it is either
72 * one of the constants defined in FrameVisitor, or for OBJECT and
73 * UNINITIALIZED types, a tag and an index in the type table.
74 *
75 * Output frames can contain types of any kind and with a positive or
76 * negative dimension (and even unassigned types, represented by 0 - which
77 * does not correspond to any valid type value). Input frames can only
78 * contain BASE types of positive or null dimension. In all cases the type
79 * table contains only internal type names (array type descriptors are
80 * forbidden - dimensions must be represented through the DIM field).
81 *
82 * The LONG and DOUBLE types are always represented by using two slots (LONG +
83 * TOP or DOUBLE + TOP), for local variable types as well as in the operand
84 * stack. This is necessary to be able to simulate DUPx_y instructions,
85 * whose effect would be dependent on the actual type values if types were
86 * always represented by a single slot in the stack (and this is not
87 * possible, since actual type values are not always known - cf LOCAL and
88 * STACK type kinds).
89 */
90
91 /**
92 * Mask to get the dimension of a frame type. This dimension is a signed
93 * integer between -8 and 7.
94 */
95 final static int DIM = 0xF0000000;
96
97 /**
98 * Constant to be added to a type to get a type with one more dimension.
99 */
100 final static int ARRAY_OF = 0x10000000;
101
102 /**
103 * Constant to be added to a type to get a type with one less dimension.
104 */
105 final static int ELEMENT_OF = 0xF0000000;
106
107 /**
108 * Mask to get the kind of a frame type.
109 *
110 * @see #BASE
111 * @see #LOCAL
112 * @see #STACK
113 */
114 final static int KIND = 0xF000000;
115
116 /**
117 * Mask to get the value of a frame type.
118 */
119 final static int VALUE = 0xFFFFFF;
120
121 /**
122 * Mask to get the kind of base types.
123 */
124 final static int BASE_KIND = 0xFF00000;
125
126 /**
127 * Mask to get the value of base types.
128 */
129 final static int BASE_VALUE = 0xFFFFF;
130
131 /**
132 * Kind of the types that are not relative to an input stack map frame.
133 */
134 final static int BASE = 0x1000000;
135
136 /**
137 * Base kind of the base reference types. The BASE_VALUE of such types is an
138 * index into the type table.
139 */
140 final static int OBJECT = BASE | 0x700000;
141
142 /**
143 * Base kind of the uninitialized base types. The BASE_VALUE of such types
144 * in an index into the type table (the Item at that index contains both an
145 * instruction offset and an internal class name).
146 */
147 final static int UNINITIALIZED = BASE | 0x800000;
148
149 /**
150 * Kind of the types that are relative to the local variable types of an
151 * input stack map frame. The value of such types is a local variable index.
152 */
153 private final static int LOCAL = 0x2000000;
154
155 /**
156 * Kind of the the types that are relative to the stack of an input stack
157 * map frame. The value of such types is a position relatively to the top of
158 * this stack.
159 */
160 private final static int STACK = 0x3000000;
161
162 /**
163 * The TOP type. This is a BASE type.
164 */
165 final static int TOP = BASE | 0;
166
167 /**
168 * The BOOLEAN type. This is a BASE type mainly used for array types.
169 */
170 final static int BOOLEAN = BASE | 9;
171
172 /**
173 * The BYTE type. This is a BASE type mainly used for array types.
174 */
175 final static int BYTE = BASE | 10;
176
177 /**
178 * The CHAR type. This is a BASE type mainly used for array types.
179 */
180 final static int CHAR = BASE | 11;
181
182 /**
183 * The SHORT type. This is a BASE type mainly used for array types.
184 */
185 final static int SHORT = BASE | 12;
186
187 /**
188 * The INTEGER type. This is a BASE type.
189 */
190 final static int INTEGER = BASE | 1;
191
192 /**
193 * The FLOAT type. This is a BASE type.
194 */
195 final static int FLOAT = BASE | 2;
196
197 /**
198 * The DOUBLE type. This is a BASE type.
199 */
200 final static int DOUBLE = BASE | 3;
201
202 /**
203 * The LONG type. This is a BASE type.
204 */
205 final static int LONG = BASE | 4;
206
207 /**
208 * The NULL type. This is a BASE type.
209 */
210 final static int NULL = BASE | 5;
211
212 /**
213 * The UNINITIALIZED_THIS type. This is a BASE type.
214 */
215 final static int UNINITIALIZED_THIS = BASE | 6;
216
217 /**
218 * The stack size variation corresponding to each JVM instruction. This
219 * stack variation is equal to the size of the values produced by an
220 * instruction, minus the size of the values consumed by this instruction.
221 */
222 final static int[] SIZE;
223
224 /**
225 * Computes the stack size variation corresponding to each JVM instruction.
226 */
227 static
228 {
229 int i;
230 int[] b = new int[202];
231 String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD"
232 + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD"
233 + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED"
234 + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
235 for(i = 0; i < b.length; ++i)
236 {
237 b[i] = s.charAt(i) - 'E';
238 }
239 SIZE = b;
240
241 // code to generate the above string
242 //
243 // int NA = 0; // not applicable (unused opcode or variable size opcode)
244 //
245 // b = new int[] {
246 // 0, //NOP, // visitInsn
247 // 1, //ACONST_NULL, // -
248 // 1, //ICONST_M1, // -
249 // 1, //ICONST_0, // -
250 // 1, //ICONST_1, // -
251 // 1, //ICONST_2, // -
252 // 1, //ICONST_3, // -
253 // 1, //ICONST_4, // -
254 // 1, //ICONST_5, // -
255 // 2, //LCONST_0, // -
256 // 2, //LCONST_1, // -
257 // 1, //FCONST_0, // -
258 // 1, //FCONST_1, // -
259 // 1, //FCONST_2, // -
260 // 2, //DCONST_0, // -
261 // 2, //DCONST_1, // -
262 // 1, //BIPUSH, // visitIntInsn
263 // 1, //SIPUSH, // -
264 // 1, //LDC, // visitLdcInsn
265 // NA, //LDC_W, // -
266 // NA, //LDC2_W, // -
267 // 1, //ILOAD, // visitVarInsn
268 // 2, //LLOAD, // -
269 // 1, //FLOAD, // -
270 // 2, //DLOAD, // -
271 // 1, //ALOAD, // -
272 // NA, //ILOAD_0, // -
273 // NA, //ILOAD_1, // -
274 // NA, //ILOAD_2, // -
275 // NA, //ILOAD_3, // -
276 // NA, //LLOAD_0, // -
277 // NA, //LLOAD_1, // -
278 // NA, //LLOAD_2, // -
279 // NA, //LLOAD_3, // -
280 // NA, //FLOAD_0, // -
281 // NA, //FLOAD_1, // -
282 // NA, //FLOAD_2, // -
283 // NA, //FLOAD_3, // -
284 // NA, //DLOAD_0, // -
285 // NA, //DLOAD_1, // -
286 // NA, //DLOAD_2, // -
287 // NA, //DLOAD_3, // -
288 // NA, //ALOAD_0, // -
289 // NA, //ALOAD_1, // -
290 // NA, //ALOAD_2, // -
291 // NA, //ALOAD_3, // -
292 // -1, //IALOAD, // visitInsn
293 // 0, //LALOAD, // -
294 // -1, //FALOAD, // -
295 // 0, //DALOAD, // -
296 // -1, //AALOAD, // -
297 // -1, //BALOAD, // -
298 // -1, //CALOAD, // -
299 // -1, //SALOAD, // -
300 // -1, //ISTORE, // visitVarInsn
301 // -2, //LSTORE, // -
302 // -1, //FSTORE, // -
303 // -2, //DSTORE, // -
304 // -1, //ASTORE, // -
305 // NA, //ISTORE_0, // -
306 // NA, //ISTORE_1, // -
307 // NA, //ISTORE_2, // -
308 // NA, //ISTORE_3, // -
309 // NA, //LSTORE_0, // -
310 // NA, //LSTORE_1, // -
311 // NA, //LSTORE_2, // -
312 // NA, //LSTORE_3, // -
313 // NA, //FSTORE_0, // -
314 // NA, //FSTORE_1, // -
315 // NA, //FSTORE_2, // -
316 // NA, //FSTORE_3, // -
317 // NA, //DSTORE_0, // -
318 // NA, //DSTORE_1, // -
319 // NA, //DSTORE_2, // -
320 // NA, //DSTORE_3, // -
321 // NA, //ASTORE_0, // -
322 // NA, //ASTORE_1, // -
323 // NA, //ASTORE_2, // -
324 // NA, //ASTORE_3, // -
325 // -3, //IASTORE, // visitInsn
326 // -4, //LASTORE, // -
327 // -3, //FASTORE, // -
328 // -4, //DASTORE, // -
329 // -3, //AASTORE, // -
330 // -3, //BASTORE, // -
331 // -3, //CASTORE, // -
332 // -3, //SASTORE, // -
333 // -1, //POP, // -
334 // -2, //POP2, // -
335 // 1, //DUP, // -
336 // 1, //DUP_X1, // -
337 // 1, //DUP_X2, // -
338 // 2, //DUP2, // -
339 // 2, //DUP2_X1, // -
340 // 2, //DUP2_X2, // -
341 // 0, //SWAP, // -
342 // -1, //IADD, // -
343 // -2, //LADD, // -
344 // -1, //FADD, // -
345 // -2, //DADD, // -
346 // -1, //ISUB, // -
347 // -2, //LSUB, // -
348 // -1, //FSUB, // -
349 // -2, //DSUB, // -
350 // -1, //IMUL, // -
351 // -2, //LMUL, // -
352 // -1, //FMUL, // -
353 // -2, //DMUL, // -
354 // -1, //IDIV, // -
355 // -2, //LDIV, // -
356 // -1, //FDIV, // -
357 // -2, //DDIV, // -
358 // -1, //IREM, // -
359 // -2, //LREM, // -
360 // -1, //FREM, // -
361 // -2, //DREM, // -
362 // 0, //INEG, // -
363 // 0, //LNEG, // -
364 // 0, //FNEG, // -
365 // 0, //DNEG, // -
366 // -1, //ISHL, // -
367 // -1, //LSHL, // -
368 // -1, //ISHR, // -
369 // -1, //LSHR, // -
370 // -1, //IUSHR, // -
371 // -1, //LUSHR, // -
372 // -1, //IAND, // -
373 // -2, //LAND, // -
374 // -1, //IOR, // -
375 // -2, //LOR, // -
376 // -1, //IXOR, // -
377 // -2, //LXOR, // -
378 // 0, //IINC, // visitIincInsn
379 // 1, //I2L, // visitInsn
380 // 0, //I2F, // -
381 // 1, //I2D, // -
382 // -1, //L2I, // -
383 // -1, //L2F, // -
384 // 0, //L2D, // -
385 // 0, //F2I, // -
386 // 1, //F2L, // -
387 // 1, //F2D, // -
388 // -1, //D2I, // -
389 // 0, //D2L, // -
390 // -1, //D2F, // -
391 // 0, //I2B, // -
392 // 0, //I2C, // -
393 // 0, //I2S, // -
394 // -3, //LCMP, // -
395 // -1, //FCMPL, // -
396 // -1, //FCMPG, // -
397 // -3, //DCMPL, // -
398 // -3, //DCMPG, // -
399 // -1, //IFEQ, // visitJumpInsn
400 // -1, //IFNE, // -
401 // -1, //IFLT, // -
402 // -1, //IFGE, // -
403 // -1, //IFGT, // -
404 // -1, //IFLE, // -
405 // -2, //IF_ICMPEQ, // -
406 // -2, //IF_ICMPNE, // -
407 // -2, //IF_ICMPLT, // -
408 // -2, //IF_ICMPGE, // -
409 // -2, //IF_ICMPGT, // -
410 // -2, //IF_ICMPLE, // -
411 // -2, //IF_ACMPEQ, // -
412 // -2, //IF_ACMPNE, // -
413 // 0, //GOTO, // -
414 // 1, //JSR, // -
415 // 0, //RET, // visitVarInsn
416 // -1, //TABLESWITCH, // visiTableSwitchInsn
417 // -1, //LOOKUPSWITCH, // visitLookupSwitch
418 // -1, //IRETURN, // visitInsn
419 // -2, //LRETURN, // -
420 // -1, //FRETURN, // -
421 // -2, //DRETURN, // -
422 // -1, //ARETURN, // -
423 // 0, //RETURN, // -
424 // NA, //GETSTATIC, // visitFieldInsn
425 // NA, //PUTSTATIC, // -
426 // NA, //GETFIELD, // -
427 // NA, //PUTFIELD, // -
428 // NA, //INVOKEVIRTUAL, // visitMethodInsn
429 // NA, //INVOKESPECIAL, // -
430 // NA, //INVOKESTATIC, // -
431 // NA, //INVOKEINTERFACE, // -
432 // NA, //UNUSED, // NOT VISITED
433 // 1, //NEW, // visitTypeInsn
434 // 0, //NEWARRAY, // visitIntInsn
435 // 0, //ANEWARRAY, // visitTypeInsn
436 // 0, //ARRAYLENGTH, // visitInsn
437 // NA, //ATHROW, // -
438 // 0, //CHECKCAST, // visitTypeInsn
439 // 0, //INSTANCEOF, // -
440 // -1, //MONITORENTER, // visitInsn
441 // -1, //MONITOREXIT, // -
442 // NA, //WIDE, // NOT VISITED
443 // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn
444 // -1, //IFNULL, // visitJumpInsn
445 // -1, //IFNONNULL, // -
446 // NA, //GOTO_W, // -
447 // NA, //JSR_W, // -
448 // };
449 // for (i = 0; i < b.length; ++i) {
450 // System.err.print((char)('E' + b[i]));
451 // }
452 // System.err.println();
453 }
454
455 /**
456 * The label (i.e. basic block) to which these input and output stack map
457 * frames correspond.
458 */
459 Label owner;
460
461 /**
462 * The input stack map frame locals.
463 */
464 int[] inputLocals;
465
466 /**
467 * The input stack map frame stack.
468 */
469 int[] inputStack;
470
471 /**
472 * The output stack map frame locals.
473 */
474 private int[] outputLocals;
475
476 /**
477 * The output stack map frame stack.
478 */
479 private int[] outputStack;
480
481 /**
482 * Relative size of the output stack. The exact semantics of this field
483 * depends on the algorithm that is used.
484 * <p/>
485 * When only the maximum stack size is computed, this field is the size of
486 * the output stack relatively to the top of the input stack.
487 * <p/>
488 * When the stack map frames are completely computed, this field is the
489 * actual number of types in {@link #outputStack}.
490 */
491 private int outputStackTop;
492
493 /**
494 * Number of types that are initialized in the basic block.
495 *
496 * @see #initializations
497 */
498 private int initializationCount;
499
500 /**
501 * The types that are initialized in the basic block. A constructor
502 * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace
503 * <i>every occurence</i> of this type in the local variables and in the
504 * operand stack. This cannot be done during the first phase of the
505 * algorithm since, during this phase, the local variables and the operand
506 * stack are not completely computed. It is therefore necessary to store the
507 * types on which constructors are invoked in the basic block, in order to
508 * do this replacement during the second phase of the algorithm, where the
509 * frames are fully computed. Note that this array can contain types that
510 * are relative to input locals or to the input stack (see below for the
511 * description of the algorithm).
512 */
513 private int[] initializations;
514
515 /**
516 * Returns the output frame local variable type at the given index.
517 *
518 * @param local the index of the local that must be returned.
519 * @return the output frame local variable type at the given index.
520 */
521 private int get(final int local){
522 if(outputLocals == null || local >= outputLocals.length)
523 {
524 // this local has never been assigned in this basic block,
525 // so it is still equal to its value in the input frame
526 return LOCAL | local;
527 }
528 else
529 {
530 int type = outputLocals[local];
531 if(type == 0)
532 {
533 // this local has never been assigned in this basic block,
534 // so it is still equal to its value in the input frame
535 type = outputLocals[local] = LOCAL | local;
536 }
537 return type;
538 }
539 }
540
541 /**
542 * Sets the output frame local variable type at the given index.
543 *
544 * @param local the index of the local that must be set.
545 * @param type the value of the local that must be set.
546 */
547 private void set(final int local, final int type){
548 // creates and/or resizes the output local variables array if necessary
549 if(outputLocals == null)
550 {
551 outputLocals = new int[10];
552 }
553 int n = outputLocals.length;
554 if(local >= n)
555 {
556 int[] t = new int[Math.max(local + 1, 2 * n)];
557 System.arraycopy(outputLocals, 0, t, 0, n);
558 outputLocals = t;
559 }
560 // sets the local variable
561 outputLocals[local] = type;
562 }
563
564 /**
565 * Pushes a new type onto the output frame stack.
566 *
567 * @param type the type that must be pushed.
568 */
569 private void push(final int type){
570 // creates and/or resizes the output stack array if necessary
571 if(outputStack == null)
572 {
573 outputStack = new int[10];
574 }
575 int n = outputStack.length;
576 if(outputStackTop >= n)
577 {
578 int[] t = new int[Math.max(outputStackTop + 1, 2 * n)];
579 System.arraycopy(outputStack, 0, t, 0, n);
580 outputStack = t;
581 }
582 // pushes the type on the output stack
583 outputStack[outputStackTop++] = type;
584 // updates the maximun height reached by the output stack, if needed
585 int top = owner.inputStackTop + outputStackTop;
586 if(top > owner.outputStackMax)
587 {
588 owner.outputStackMax = top;
589 }
590 }
591
592 /**
593 * Pushes a new type onto the output frame stack.
594 *
595 * @param cw the ClassWriter to which this label belongs.
596 * @param desc the descriptor of the type to be pushed. Can also be a method
597 * descriptor (in this case this method pushes its return type onto
598 * the output frame stack).
599 */
600 private void push(final ClassWriter cw, final String desc){
601 int type = type(cw, desc);
602 if(type != 0)
603 {
604 push(type);
605 if(type == LONG || type == DOUBLE)
606 {
607 push(TOP);
608 }
609 }
610 }
611
612 /**
613 * Returns the int encoding of the given type.
614 *
615 * @param cw the ClassWriter to which this label belongs.
616 * @param desc a type descriptor.
617 * @return the int encoding of the given type.
618 */
619 private int type(final ClassWriter cw, final String desc){
620 String t;
621 int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
622 switch(desc.charAt(index))
623 {
624 case'V':
625 return 0;
626 case'Z':
627 case'C':
628 case'B':
629 case'S':
630 case'I':
631 return INTEGER;
632 case'F':
633 return FLOAT;
634 case'J':
635 return LONG;
636 case'D':
637 return DOUBLE;
638 case'L':
639 // stores the internal name, not the descriptor!
640 t = desc.substring(index + 1, desc.length() - 1);
641 return OBJECT | cw.addType(t);
642 // case '[':
643 default:
644 // extracts the dimensions and the element type
645 int data;
646 int dims = index + 1;
647 while(desc.charAt(dims) == '[')
648 {
649 ++dims;
650 }
651 switch(desc.charAt(dims))
652 {
653 case'Z':
654 data = BOOLEAN;
655 break;
656 case'C':
657 data = CHAR;
658 break;
659 case'B':
660 data = BYTE;
661 break;
662 case'S':
663 data = SHORT;
664 break;
665 case'I':
666 data = INTEGER;
667 break;
668 case'F':
669 data = FLOAT;
670 break;
671 case'J':
672 data = LONG;
673 break;
674 case'D':
675 data = DOUBLE;
676 break;
677 // case 'L':
678 default:
679 // stores the internal name, not the descriptor
680 t = desc.substring(dims + 1, desc.length() - 1);
681 data = OBJECT | cw.addType(t);
682 }
683 return (dims - index) << 28 | data;
684 }
685 }
686
687 /**
688 * Pops a type from the output frame stack and returns its value.
689 *
690 * @return the type that has been popped from the output frame stack.
691 */
692 private int pop(){
693 if(outputStackTop > 0)
694 {
695 return outputStack[--outputStackTop];
696 }
697 else
698 {
699 // if the output frame stack is empty, pops from the input stack
700 return STACK | -(--owner.inputStackTop);
701 }
702 }
703
704 /**
705 * Pops the given number of types from the output frame stack.
706 *
707 * @param elements the number of types that must be popped.
708 */
709 private void pop(final int elements){
710 if(outputStackTop >= elements)
711 {
712 outputStackTop -= elements;
713 }
714 else
715 {
716 // if the number of elements to be popped is greater than the number
717 // of elements in the output stack, clear it, and pops the remaining
718 // elements from the input stack.
719 owner.inputStackTop -= elements - outputStackTop;
720 outputStackTop = 0;
721 }
722 }
723
724 /**
725 * Pops a type from the output frame stack.
726 *
727 * @param desc the descriptor of the type to be popped. Can also be a method
728 * descriptor (in this case this method pops the types corresponding
729 * to the method arguments).
730 */
731 private void pop(final String desc){
732 char c = desc.charAt(0);
733 if(c == '(')
734 {
735 pop((MethodWriter.getArgumentsAndReturnSizes(desc) >> 2) - 1);
736 }
737 else if(c == 'J' || c == 'D')
738 {
739 pop(2);
740 }
741 else
742 {
743 pop(1);
744 }
745 }
746
747 /**
748 * Adds a new type to the list of types on which a constructor is invoked in
749 * the basic block.
750 *
751 * @param var a type on a which a constructor is invoked.
752 */
753 private void init(final int var){
754 // creates and/or resizes the initializations array if necessary
755 if(initializations == null)
756 {
757 initializations = new int[2];
758 }
759 int n = initializations.length;
760 if(initializationCount >= n)
761 {
762 int[] t = new int[Math.max(initializationCount + 1, 2 * n)];
763 System.arraycopy(initializations, 0, t, 0, n);
764 initializations = t;
765 }
766 // stores the type to be initialized
767 initializations[initializationCount++] = var;
768 }
769
770 /**
771 * Replaces the given type with the appropriate type if it is one of the
772 * types on which a constructor is invoked in the basic block.
773 *
774 * @param cw the ClassWriter to which this label belongs.
775 * @param t a type
776 * @return t or, if t is one of the types on which a constructor is invoked
777 * in the basic block, the type corresponding to this constructor.
778 */
779 private int init(final ClassWriter cw, final int t){
780 int s;
781 if(t == UNINITIALIZED_THIS)
782 {
783 s = OBJECT | cw.addType(cw.thisName);
784 }
785 else if((t & (DIM | BASE_KIND)) == UNINITIALIZED)
786 {
787 String type = cw.typeTable[t & BASE_VALUE].strVal1;
788 s = OBJECT | cw.addType(type);
789 }
790 else
791 {
792 return t;
793 }
794 for(int j = 0; j < initializationCount; ++j)
795 {
796 int u = initializations[j];
797 int dim = u & DIM;
798 int kind = u & KIND;
799 if(kind == LOCAL)
800 {
801 u = dim + inputLocals[u & VALUE];
802 }
803 else if(kind == STACK)
804 {
805 u = dim + inputStack[inputStack.length - (u & VALUE)];
806 }
807 if(t == u)
808 {
809 return s;
810 }
811 }
812 return t;
813 }
814
815 /**
816 * Initializes the input frame of the first basic block from the method
817 * descriptor.
818 *
819 * @param cw the ClassWriter to which this label belongs.
820 * @param access the access flags of the method to which this label belongs.
821 * @param args the formal parameter types of this method.
822 * @param maxLocals the maximum number of local variables of this method.
823 */
824 void initInputFrame(
825 final ClassWriter cw,
826 final int access,
827 final Type[] args,
828 final int maxLocals){
829 inputLocals = new int[maxLocals];
830 inputStack = new int[0];
831 int i = 0;
832 if((access & Opcodes.ACC_STATIC) == 0)
833 {
834 if((access & MethodWriter.ACC_CONSTRUCTOR) == 0)
835 {
836 inputLocals[i++] = OBJECT | cw.addType(cw.thisName);
837 }
838 else
839 {
840 inputLocals[i++] = UNINITIALIZED_THIS;
841 }
842 }
843 for(int j = 0; j < args.length; ++j)
844 {
845 int t = type(cw, args[j].getDescriptor());
846 inputLocals[i++] = t;
847 if(t == LONG || t == DOUBLE)
848 {
849 inputLocals[i++] = TOP;
850 }
851 }
852 while(i < maxLocals)
853 {
854 inputLocals[i++] = TOP;
855 }
856 }
857
858 /**
859 * Simulates the action of the given instruction on the output stack frame.
860 *
861 * @param opcode the opcode of the instruction.
862 * @param arg the operand of the instruction, if any.
863 * @param cw the class writer to which this label belongs.
864 * @param item the operand of the instructions, if any.
865 */
866 void execute(
867 final int opcode,
868 final int arg,
869 final ClassWriter cw,
870 final Item item){
871 int t1, t2, t3, t4;
872 switch(opcode)
873 {
874 case Opcodes.NOP:
875 case Opcodes.INEG:
876 case Opcodes.LNEG:
877 case Opcodes.FNEG:
878 case Opcodes.DNEG:
879 case Opcodes.I2B:
880 case Opcodes.I2C:
881 case Opcodes.I2S:
882 case Opcodes.GOTO:
883 case Opcodes.RETURN:
884 break;
885 case Opcodes.ACONST_NULL:
886 push(NULL);
887 break;
888 case Opcodes.ICONST_M1:
889 case Opcodes.ICONST_0:
890 case Opcodes.ICONST_1:
891 case Opcodes.ICONST_2:
892 case Opcodes.ICONST_3:
893 case Opcodes.ICONST_4:
894 case Opcodes.ICONST_5:
895 case Opcodes.BIPUSH:
896 case Opcodes.SIPUSH:
897 case Opcodes.ILOAD:
898 push(INTEGER);
899 break;
900 case Opcodes.LCONST_0:
901 case Opcodes.LCONST_1:
902 case Opcodes.LLOAD:
903 push(LONG);
904 push(TOP);
905 break;
906 case Opcodes.FCONST_0:
907 case Opcodes.FCONST_1:
908 case Opcodes.FCONST_2:
909 case Opcodes.FLOAD:
910 push(FLOAT);
911 break;
912 case Opcodes.DCONST_0:
913 case Opcodes.DCONST_1:
914 case Opcodes.DLOAD:
915 push(DOUBLE);
916 push(TOP);
917 break;
918 case Opcodes.LDC:
919 switch(item.type)
920 {
921 case ClassWriter.INT:
922 push(INTEGER);
923 break;
924 case ClassWriter.LONG:
925 push(LONG);
926 push(TOP);
927 break;
928 case ClassWriter.FLOAT:
929 push(FLOAT);
930 break;
931 case ClassWriter.DOUBLE:
932 push(DOUBLE);
933 push(TOP);
934 break;
935 case ClassWriter.CLASS:
936 push(OBJECT | cw.addType("java/lang/Class"));
937 break;
938 // case ClassWriter.STR:
939 default:
940 push(OBJECT | cw.addType("java/lang/String"));
941 }
942 break;
943 case Opcodes.ALOAD:
944 push(get(arg));
945 break;
946 case Opcodes.IALOAD:
947 case Opcodes.BALOAD:
948 case Opcodes.CALOAD:
949 case Opcodes.SALOAD:
950 pop(2);
951 push(INTEGER);
952 break;
953 case Opcodes.LALOAD:
954 case Opcodes.D2L:
955 pop(2);
956 push(LONG);
957 push(TOP);
958 break;
959 case Opcodes.FALOAD:
960 pop(2);
961 push(FLOAT);
962 break;
963 case Opcodes.DALOAD:
964 case Opcodes.L2D:
965 pop(2);
966 push(DOUBLE);
967 push(TOP);
968 break;
969 case Opcodes.AALOAD:
970 pop(1);
971 t1 = pop();
972 push(ELEMENT_OF + t1);
973 break;
974 case Opcodes.ISTORE:
975 case Opcodes.FSTORE:
976 case Opcodes.ASTORE:
977 t1 = pop();
978 set(arg, t1);
979 if(arg > 0)
980 {
981 t2 = get(arg - 1);
982 // if t2 is of kind STACK or LOCAL we cannot know its size!
983 if(t2 == LONG || t2 == DOUBLE)
984 {
985 set(arg - 1, TOP);
986 }
987 }
988 break;
989 case Opcodes.LSTORE:
990 case Opcodes.DSTORE:
991 pop(1);
992 t1 = pop();
993 set(arg, t1);
994 set(arg + 1, TOP);
995 if(arg > 0)
996 {
997 t2 = get(arg - 1);
998 // if t2 is of kind STACK or LOCAL we cannot know its size!
999 if(t2 == LONG || t2 == DOUBLE)
1000 {
1001 set(arg - 1, TOP);
1002 }
1003 }
1004 break;
1005 case Opcodes.IASTORE:
1006 case Opcodes.BASTORE:
1007 case Opcodes.CASTORE:
1008 case Opcodes.SASTORE:
1009 case Opcodes.FASTORE:
1010 case Opcodes.AASTORE:
1011 pop(3);
1012 break;
1013 case Opcodes.LASTORE:
1014 case Opcodes.DASTORE:
1015 pop(4);
1016 break;
1017 case Opcodes.POP:
1018 case Opcodes.IFEQ:
1019 case Opcodes.IFNE:
1020 case Opcodes.IFLT:
1021 case Opcodes.IFGE:
1022 case Opcodes.IFGT:
1023 case Opcodes.IFLE:
1024 case Opcodes.IRETURN:
1025 case Opcodes.FRETURN:
1026 case Opcodes.ARETURN:
1027 case Opcodes.TABLESWITCH:
1028 case Opcodes.LOOKUPSWITCH:
1029 case Opcodes.ATHROW:
1030 case Opcodes.MONITORENTER:
1031 case Opcodes.MONITOREXIT:
1032 case Opcodes.IFNULL:
1033 case Opcodes.IFNONNULL:
1034 pop(1);
1035 break;
1036 case Opcodes.POP2:
1037 case Opcodes.IF_ICMPEQ:
1038 case Opcodes.IF_ICMPNE:
1039 case Opcodes.IF_ICMPLT:
1040 case Opcodes.IF_ICMPGE:
1041 case Opcodes.IF_ICMPGT:
1042 case Opcodes.IF_ICMPLE:
1043 case Opcodes.IF_ACMPEQ:
1044 case Opcodes.IF_ACMPNE:
1045 case Opcodes.LRETURN:
1046 case Opcodes.DRETURN:
1047 pop(2);
1048 break;
1049 case Opcodes.DUP:
1050 t1 = pop();
1051 push(t1);
1052 push(t1);
1053 break;
1054 case Opcodes.DUP_X1:
1055 t1 = pop();
1056 t2 = pop();
1057 push(t1);
1058 push(t2);
1059 push(t1);
1060 break;
1061 case Opcodes.DUP_X2:
1062 t1 = pop();
1063 t2 = pop();
1064 t3 = pop();
1065 push(t1);
1066 push(t3);
1067 push(t2);
1068 push(t1);
1069 break;
1070 case Opcodes.DUP2:
1071 t1 = pop();
1072 t2 = pop();
1073 push(t2);
1074 push(t1);
1075 push(t2);
1076 push(t1);
1077 break;
1078 case Opcodes.DUP2_X1:
1079 t1 = pop();
1080 t2 = pop();
1081 t3 = pop();
1082 push(t2);
1083 push(t1);
1084 push(t3);
1085 push(t2);
1086 push(t1);
1087 break;
1088 case Opcodes.DUP2_X2:
1089 t1 = pop();
1090 t2 = pop();
1091 t3 = pop();
1092 t4 = pop();
1093 push(t2);
1094 push(t1);
1095 push(t4);
1096 push(t3);
1097 push(t2);
1098 push(t1);
1099 break;
1100 case Opcodes.SWAP:
1101 t1 = pop();
1102 t2 = pop();
1103 push(t1);
1104 push(t2);
1105 break;
1106 case Opcodes.IADD:
1107 case Opcodes.ISUB:
1108 case Opcodes.IMUL:
1109 case Opcodes.IDIV:
1110 case Opcodes.IREM:
1111 case Opcodes.IAND:
1112 case Opcodes.IOR:
1113 case Opcodes.IXOR:
1114 case Opcodes.ISHL:
1115 case Opcodes.ISHR:
1116 case Opcodes.IUSHR:
1117 case Opcodes.L2I:
1118 case Opcodes.D2I:
1119 case Opcodes.FCMPL:
1120 case Opcodes.FCMPG:
1121 pop(2);
1122 push(INTEGER);
1123 break;
1124 case Opcodes.LADD:
1125 case Opcodes.LSUB:
1126 case Opcodes.LMUL:
1127 case Opcodes.LDIV:
1128 case Opcodes.LREM:
1129 case Opcodes.LAND:
1130 case Opcodes.LOR:
1131 case Opcodes.LXOR:
1132 pop(4);
1133 push(LONG);
1134 push(TOP);
1135 break;
1136 case Opcodes.FADD:
1137 case Opcodes.FSUB:
1138 case Opcodes.FMUL:
1139 case Opcodes.FDIV:
1140 case Opcodes.FREM:
1141 case Opcodes.L2F:
1142 case Opcodes.D2F:
1143 pop(2);
1144 push(FLOAT);
1145 break;
1146 case Opcodes.DADD:
1147 case Opcodes.DSUB:
1148 case Opcodes.DMUL:
1149 case Opcodes.DDIV:
1150 case Opcodes.DREM:
1151 pop(4);
1152 push(DOUBLE);
1153 push(TOP);
1154 break;
1155 case Opcodes.LSHL:
1156 case Opcodes.LSHR:
1157 case Opcodes.LUSHR:
1158 pop(3);
1159 push(LONG);
1160 push(TOP);
1161 break;
1162 case Opcodes.IINC:
1163 set(arg, INTEGER);
1164 break;
1165 case Opcodes.I2L:
1166 case Opcodes.F2L:
1167 pop(1);
1168 push(LONG);
1169 push(TOP);
1170 break;
1171 case Opcodes.I2F:
1172 pop(1);
1173 push(FLOAT);
1174 break;
1175 case Opcodes.I2D:
1176 case Opcodes.F2D:
1177 pop(1);
1178 push(DOUBLE);
1179 push(TOP);
1180 break;
1181 case Opcodes.F2I:
1182 case Opcodes.ARRAYLENGTH:
1183 case Opcodes.INSTANCEOF:
1184 pop(1);
1185 push(INTEGER);
1186 break;
1187 case Opcodes.LCMP:
1188 case Opcodes.DCMPL:
1189 case Opcodes.DCMPG:
1190 pop(4);
1191 push(INTEGER);
1192 break;
1193 case Opcodes.JSR:
1194 case Opcodes.RET:
1195 throw new RuntimeException("JSR/RET are not supported with computeFrames option");
1196 case Opcodes.GETSTATIC:
1197 push(cw, item.strVal3);
1198 break;
1199 case Opcodes.PUTSTATIC:
1200 pop(item.strVal3);
1201 break;
1202 case Opcodes.GETFIELD:
1203 pop(1);
1204 push(cw, item.strVal3);
1205 break;
1206 case Opcodes.PUTFIELD:
1207 pop(item.strVal3);
1208 pop();
1209 break;
1210 case Opcodes.INVOKEVIRTUAL:
1211 case Opcodes.INVOKESPECIAL:
1212 case Opcodes.INVOKESTATIC:
1213 case Opcodes.INVOKEINTERFACE:
1214 pop(item.strVal3);
1215 if(opcode != Opcodes.INVOKESTATIC)
1216 {
1217 t1 = pop();
1218 if(opcode == Opcodes.INVOKESPECIAL
1219 && item.strVal2.charAt(0) == '<')
1220 {
1221 init(t1);
1222 }
1223 }
1224 push(cw, item.strVal3);
1225 break;
1226 case Opcodes.NEW:
1227 push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg));
1228 break;
1229 case Opcodes.NEWARRAY:
1230 pop();
1231 switch(arg)
1232 {
1233 case Opcodes.T_BOOLEAN:
1234 push(ARRAY_OF | BOOLEAN);
1235 break;
1236 case Opcodes.T_CHAR:
1237 push(ARRAY_OF | CHAR);
1238 break;
1239 case Opcodes.T_BYTE:
1240 push(ARRAY_OF | BYTE);
1241 break;
1242 case Opcodes.T_SHORT:
1243 push(ARRAY_OF | SHORT);
1244 break;
1245 case Opcodes.T_INT:
1246 push(ARRAY_OF | INTEGER);
1247 break;
1248 case Opcodes.T_FLOAT:
1249 push(ARRAY_OF | FLOAT);
1250 break;
1251 case Opcodes.T_DOUBLE:
1252 push(ARRAY_OF | DOUBLE);
1253 break;
1254 // case Opcodes.T_LONG:
1255 default:
1256 push(ARRAY_OF | LONG);
1257 break;
1258 }
1259 break;
1260 case Opcodes.ANEWARRAY:
1261 String s = item.strVal1;
1262 pop();
1263 if(s.charAt(0) == '[')
1264 {
1265 push(cw, "[" + s);
1266 }
1267 else
1268 {
1269 push(ARRAY_OF | OBJECT | cw.addType(s));
1270 }
1271 break;
1272 case Opcodes.CHECKCAST:
1273 s = item.strVal1;
1274 pop();
1275 if(s.charAt(0) == '[')
1276 {
1277 push(cw, s);
1278 }
1279 else
1280 {
1281 push(OBJECT | cw.addType(s));
1282 }
1283 break;
1284 // case Opcodes.MULTIANEWARRAY:
1285 default:
1286 pop(arg);
1287 push(cw, item.strVal1);
1288 break;
1289 }
1290 }
1291
1292 /**
1293 * Merges the input frame of the given basic block with the input and output
1294 * frames of this basic block. Returns <tt>true</tt> if the input frame of
1295 * the given label has been changed by this operation.
1296 *
1297 * @param cw the ClassWriter to which this label belongs.
1298 * @param frame the basic block whose input frame must be updated.
1299 * @param edge the kind of the {@link Edge} between this label and 'label'.
1300 * See {@link Edge#info}.
1301 * @return <tt>true</tt> if the input frame of the given label has been
1302 * changed by this operation.
1303 */
1304 boolean merge(final ClassWriter cw, final Frame frame, final int edge){
1305 boolean changed = false;
1306 int i, s, dim, kind, t;
1307
1308 int nLocal = inputLocals.length;
1309 int nStack = inputStack.length;
1310 if(frame.inputLocals == null)
1311 {
1312 frame.inputLocals = new int[nLocal];
1313 changed = true;
1314 }
1315
1316 for(i = 0; i < nLocal; ++i)
1317 {
1318 if(outputLocals != null && i < outputLocals.length)
1319 {
1320 s = outputLocals[i];
1321 if(s == 0)
1322 {
1323 t = inputLocals[i];
1324 }
1325 else
1326 {
1327 dim = s & DIM;
1328 kind = s & KIND;
1329 if(kind == LOCAL)
1330 {
1331 t = dim + inputLocals[s & VALUE];
1332 }
1333 else if(kind == STACK)
1334 {
1335 t = dim + inputStack[nStack - (s & VALUE)];
1336 }
1337 else
1338 {
1339 t = s;
1340 }
1341 }
1342 }
1343 else
1344 {
1345 t = inputLocals[i];
1346 }
1347 if(initializations != null)
1348 {
1349 t = init(cw, t);
1350 }
1351 changed |= merge(cw, t, frame.inputLocals, i);
1352 }
1353
1354 if(edge > 0)
1355 {
1356 for(i = 0; i < nLocal; ++i)
1357 {
1358 t = inputLocals[i];
1359 changed |= merge(cw, t, frame.inputLocals, i);
1360 }
1361 if(frame.inputStack == null)
1362 {
1363 frame.inputStack = new int[1];
1364 changed = true;
1365 }
1366 changed |= merge(cw, edge, frame.inputStack, 0);
1367 return changed;
1368 }
1369
1370 int nInputStack = inputStack.length + owner.inputStackTop;
1371 if(frame.inputStack == null)
1372 {
1373 frame.inputStack = new int[nInputStack + outputStackTop];
1374 changed = true;
1375 }
1376
1377 for(i = 0; i < nInputStack; ++i)
1378 {
1379 t = inputStack[i];
1380 if(initializations != null)
1381 {
1382 t = init(cw, t);
1383 }
1384 changed |= merge(cw, t, frame.inputStack, i);
1385 }
1386 for(i = 0; i < outputStackTop; ++i)
1387 {
1388 s = outputStack[i];
1389 dim = s & DIM;
1390 kind = s & KIND;
1391 if(kind == LOCAL)
1392 {
1393 t = dim + inputLocals[s & VALUE];
1394 }
1395 else if(kind == STACK)
1396 {
1397 t = dim + inputStack[nStack - (s & VALUE)];
1398 }
1399 else
1400 {
1401 t = s;
1402 }
1403 if(initializations != null)
1404 {
1405 t = init(cw, t);
1406 }
1407 changed |= merge(cw, t, frame.inputStack, nInputStack + i);
1408 }
1409 return changed;
1410 }
1411
1412 /**
1413 * Merges the type at the given index in the given type array with the given
1414 * type. Returns <tt>true</tt> if the type array has been modified by this
1415 * operation.
1416 *
1417 * @param cw the ClassWriter to which this label belongs.
1418 * @param t the type with which the type array element must be merged.
1419 * @param types an array of types.
1420 * @param index the index of the type that must be merged in 'types'.
1421 * @return <tt>true</tt> if the type array has been modified by this
1422 * operation.
1423 */
1424 private boolean merge(
1425 final ClassWriter cw,
1426 int t,
1427 final int[] types,
1428 final int index){
1429 int u = types[index];
1430 if(u == t)
1431 {
1432 // if the types are equal, merge(u,t)=u, so there is no change
1433 return false;
1434 }
1435 if((t & ~DIM) == NULL)
1436 {
1437 if(u == NULL)
1438 {
1439 return false;
1440 }
1441 t = NULL;
1442 }
1443 if(u == 0)
1444 {
1445 // if types[index] has never been assigned, merge(u,t)=t
1446 types[index] = t;
1447 return true;
1448 }
1449 int v;
1450 if((u & BASE_KIND) == OBJECT || (u & DIM) != 0)
1451 {
1452 // if u is a reference type of any dimension
1453 if(t == NULL)
1454 {
1455 // if t is the NULL type, merge(u,t)=u, so there is no change
1456 return false;
1457 }
1458 else if((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND)))
1459 {
1460 if((u & BASE_KIND) == OBJECT)
1461 {
1462 // if t is also a reference type, and if u and t have the
1463 // same dimension merge(u,t) = dim(t) | common parent of the
1464 // element types of u and t
1465 v = (t & DIM) | OBJECT
1466 | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE);
1467 }
1468 else
1469 {
1470 // if u and t are array types, but not with the same element
1471 // type, merge(u,t)=java/lang/Object
1472 v = OBJECT | cw.addType("java/lang/Object");
1473 }
1474 }
1475 else if((t & BASE_KIND) == OBJECT || (t & DIM) != 0)
1476 {
1477 // if t is any other reference or array type,
1478 // merge(u,t)=java/lang/Object
1479 v = OBJECT | cw.addType("java/lang/Object");
1480 }
1481 else
1482 {
1483 // if t is any other type, merge(u,t)=TOP
1484 v = TOP;
1485 }
1486 }
1487 else if(u == NULL)
1488 {
1489 // if u is the NULL type, merge(u,t)=t,
1490 // or TOP if t is not a reference type
1491 v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP;
1492 }
1493 else
1494 {
1495 // if u is any other type, merge(u,t)=TOP whatever t
1496 v = TOP;
1497 }
1498 if(u != v)
1499 {
1500 types[index] = v;
1501 return true;
1502 }
1503 return false;
1504 }
1505 }
+0
-70
src/jvm/clojure/asm/Handler.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * Information about an exception handler block.
33 *
34 * @author Eric Bruneton
35 */
36 class Handler{
37
38 /**
39 * Beginning of the exception handler's scope (inclusive).
40 */
41 Label start;
42
43 /**
44 * End of the exception handler's scope (exclusive).
45 */
46 Label end;
47
48 /**
49 * Beginning of the exception handler's code.
50 */
51 Label handler;
52
53 /**
54 * Internal name of the type of exceptions handled by this handler, or
55 * <tt>null</tt> to catch any exceptions.
56 */
57 String desc;
58
59 /**
60 * Constant pool index of the internal name of the type of exceptions
61 * handled by this handler, or 0 to catch any exceptions.
62 */
63 int type;
64
65 /**
66 * Next exception handler block info.
67 */
68 Handler next;
69 }
+0
-258
src/jvm/clojure/asm/Item.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * A constant pool item. Constant pool items can be created with the 'newXXX'
33 * methods in the {@link ClassWriter} class.
34 *
35 * @author Eric Bruneton
36 */
37 final class Item{
38
39 /**
40 * Index of this item in the constant pool.
41 */
42 int index;
43
44 /**
45 * Type of this constant pool item. A single class is used to represent all
46 * constant pool item types, in order to minimize the bytecode size of this
47 * package. The value of this field is one of {@link ClassWriter#INT},
48 * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT},
49 * {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
50 * {@link ClassWriter#STR}, {@link ClassWriter#CLASS},
51 * {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
52 * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}.
53 * <p/>
54 * Special Item types are used for Items that are stored in the ClassWriter
55 * {@link ClassWriter#typeTable}, instead of the constant pool, in order to
56 * avoid clashes with normal constant pool items in the ClassWriter constant
57 * pool's hash table. These special item types are
58 * {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and
59 * {@link ClassWriter#TYPE_MERGED}.
60 */
61 int type;
62
63 /**
64 * Value of this item, for an integer item.
65 */
66 int intVal;
67
68 /**
69 * Value of this item, for a long item.
70 */
71 long longVal;
72
73 /**
74 * First part of the value of this item, for items that do not hold a
75 * primitive value.
76 */
77 String strVal1;
78
79 /**
80 * Second part of the value of this item, for items that do not hold a
81 * primitive value.
82 */
83 String strVal2;
84
85 /**
86 * Third part of the value of this item, for items that do not hold a
87 * primitive value.
88 */
89 String strVal3;
90
91 /**
92 * The hash code value of this constant pool item.
93 */
94 int hashCode;
95
96 /**
97 * Link to another constant pool item, used for collision lists in the
98 * constant pool's hash table.
99 */
100 Item next;
101
102 /**
103 * Constructs an uninitialized {@link Item}.
104 */
105 Item(){
106 }
107
108 /**
109 * Constructs an uninitialized {@link Item} for constant pool element at
110 * given position.
111 *
112 * @param index index of the item to be constructed.
113 */
114 Item(final int index){
115 this.index = index;
116 }
117
118 /**
119 * Constructs a copy of the given item.
120 *
121 * @param index index of the item to be constructed.
122 * @param i the item that must be copied into the item to be constructed.
123 */
124 Item(final int index, final Item i){
125 this.index = index;
126 type = i.type;
127 intVal = i.intVal;
128 longVal = i.longVal;
129 strVal1 = i.strVal1;
130 strVal2 = i.strVal2;
131 strVal3 = i.strVal3;
132 hashCode = i.hashCode;
133 }
134
135 /**
136 * Sets this item to an integer item.
137 *
138 * @param intVal the value of this item.
139 */
140 void set(final int intVal){
141 this.type = ClassWriter.INT;
142 this.intVal = intVal;
143 this.hashCode = 0x7FFFFFFF & (type + intVal);
144 }
145
146 /**
147 * Sets this item to a long item.
148 *
149 * @param longVal the value of this item.
150 */
151 void set(final long longVal){
152 this.type = ClassWriter.LONG;
153 this.longVal = longVal;
154 this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
155 }
156
157 /**
158 * Sets this item to a float item.
159 *
160 * @param floatVal the value of this item.
161 */
162 void set(final float floatVal){
163 this.type = ClassWriter.FLOAT;
164 this.intVal = Float.floatToRawIntBits(floatVal);
165 this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
166 }
167
168 /**
169 * Sets this item to a double item.
170 *
171 * @param doubleVal the value of this item.
172 */
173 void set(final double doubleVal){
174 this.type = ClassWriter.DOUBLE;
175 this.longVal = Double.doubleToRawLongBits(doubleVal);
176 this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
177 }
178
179 /**
180 * Sets this item to an item that do not hold a primitive value.
181 *
182 * @param type the type of this item.
183 * @param strVal1 first part of the value of this item.
184 * @param strVal2 second part of the value of this item.
185 * @param strVal3 third part of the value of this item.
186 */
187 void set(
188 final int type,
189 final String strVal1,
190 final String strVal2,
191 final String strVal3){
192 this.type = type;
193 this.strVal1 = strVal1;
194 this.strVal2 = strVal2;
195 this.strVal3 = strVal3;
196 switch(type)
197 {
198 case ClassWriter.UTF8:
199 case ClassWriter.STR:
200 case ClassWriter.CLASS:
201 case ClassWriter.TYPE_NORMAL:
202 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
203 return;
204 case ClassWriter.NAME_TYPE:
205 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
206 * strVal2.hashCode());
207 return;
208 // ClassWriter.FIELD:
209 // ClassWriter.METH:
210 // ClassWriter.IMETH:
211 default:
212 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
213 * strVal2.hashCode() * strVal3.hashCode());
214 }
215 }
216
217 /**
218 * Indicates if the given item is equal to this one.
219 *
220 * @param i the item to be compared to this one.
221 * @return <tt>true</tt> if the given item if equal to this one,
222 * <tt>false</tt> otherwise.
223 */
224 boolean isEqualTo(final Item i){
225 if(i.type == type)
226 {
227 switch(type)
228 {
229 case ClassWriter.INT:
230 case ClassWriter.FLOAT:
231 return i.intVal == intVal;
232 case ClassWriter.TYPE_MERGED:
233 case ClassWriter.LONG:
234 case ClassWriter.DOUBLE:
235 return i.longVal == longVal;
236 case ClassWriter.UTF8:
237 case ClassWriter.STR:
238 case ClassWriter.CLASS:
239 case ClassWriter.TYPE_NORMAL:
240 return i.strVal1.equals(strVal1);
241 case ClassWriter.TYPE_UNINIT:
242 return i.intVal == intVal && i.strVal1.equals(strVal1);
243 case ClassWriter.NAME_TYPE:
244 return i.strVal1.equals(strVal1)
245 && i.strVal2.equals(strVal2);
246 // ClassWriter.FIELD:
247 // ClassWriter.METH:
248 // ClassWriter.IMETH:
249 default:
250 return i.strVal1.equals(strVal1)
251 && i.strVal2.equals(strVal2)
252 && i.strVal3.equals(strVal3);
253 }
254 }
255 return false;
256 }
257 }
+0
-437
src/jvm/clojure/asm/Label.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * A label represents a position in the bytecode of a method. Labels are used
33 * for jump, goto, and switch instructions, and for try catch blocks.
34 *
35 * @author Eric Bruneton
36 */
37 public class Label{
38
39 /**
40 * Indicates if this label is only used for debug attributes. Such a label
41 * is not the start of a basic block, the target of a jump instruction, or
42 * an exception handler. It can be safely ignored in control flow graph
43 * analysis algorithms (for optimization purposes).
44 */
45 final static int DEBUG = 1;
46
47 /**
48 * Indicates if the position of this label is known.
49 */
50 final static int RESOLVED = 2;
51
52 /**
53 * Indicates if this label has been updated, after instruction resizing.
54 */
55 final static int RESIZED = 4;
56
57 /**
58 * Indicates if this basic block has been pushed in the basic block stack.
59 * See {@link MethodWriter#visitMaxs visitMaxs}.
60 */
61 final static int PUSHED = 8;
62
63 /**
64 * Indicates if this label is the target of a jump instruction, or the start
65 * of an exception handler.
66 */
67 final static int TARGET = 16;
68
69 /**
70 * Indicates if a stack map frame must be stored for this label.
71 */
72 final static int STORE = 32;
73
74 /**
75 * Indicates if this label corresponds to a reachable basic block.
76 */
77 final static int REACHABLE = 64;
78
79 /**
80 * Indicates if this basic block ends with a JSR instruction.
81 */
82 final static int JSR = 128;
83
84 /**
85 * Indicates if this basic block ends with a RET instruction.
86 */
87 final static int RET = 256;
88
89 /**
90 * Field used to associate user information to a label.
91 */
92 public Object info;
93
94 /**
95 * Flags that indicate the status of this label.
96 *
97 * @see #DEBUG
98 * @see #RESOLVED
99 * @see #RESIZED
100 * @see #PUSHED
101 * @see #TARGET
102 * @see #STORE
103 * @see #REACHABLE
104 * @see #JSR
105 * @see #RET
106 */
107 int status;
108
109 /**
110 * The line number corresponding to this label, if known.
111 */
112 int line;
113
114 /**
115 * The position of this label in the code, if known.
116 */
117 int position;
118
119 /**
120 * Number of forward references to this label, times two.
121 */
122 private int referenceCount;
123
124 /**
125 * Informations about forward references. Each forward reference is
126 * described by two consecutive integers in this array: the first one is the
127 * position of the first byte of the bytecode instruction that contains the
128 * forward reference, while the second is the position of the first byte of
129 * the forward reference itself. In fact the sign of the first integer
130 * indicates if this reference uses 2 or 4 bytes, and its absolute value
131 * gives the position of the bytecode instruction.
132 */
133 private int[] srcAndRefPositions;
134
135 // ------------------------------------------------------------------------
136
137 /*
138 * Fields for the control flow and data flow graph analysis algorithms (used
139 * to compute the maximum stack size or the stack map frames). A control
140 * flow graph contains one node per "basic block", and one edge per "jump"
141 * from one basic block to another. Each node (i.e., each basic block) is
142 * represented by the Label object that corresponds to the first instruction
143 * of this basic block. Each node also stores the list of its successors in
144 * the graph, as a linked list of Edge objects.
145 *
146 * The control flow analysis algorithms used to compute the maximum stack
147 * size or the stack map frames are similar and use two steps. The first
148 * step, during the visit of each instruction, builds information about the
149 * state of the local variables and the operand stack at the end of each
150 * basic block, called the "output frame", <i>relatively</i> to the frame
151 * state at the beginning of the basic block, which is called the "input
152 * frame", and which is <i>unknown</i> during this step. The second step,
153 * in {@link MethodWriter#visitMaxs}, is a fix point algorithm that
154 * computes information about the input frame of each basic block, from the
155 * input state of the first basic block (known from the method signature),
156 * and by the using the previously computed relative output frames.
157 *
158 * The algorithm used to compute the maximum stack size only computes the
159 * relative output and absolute input stack heights, while the algorithm
160 * used to compute stack map frames computes relative output frames and
161 * absolute input frames.
162 */
163
164 /**
165 * Start of the output stack relatively to the input stack. The exact
166 * semantics of this field depends on the algorithm that is used.
167 * <p/>
168 * When only the maximum stack size is computed, this field is the number of
169 * elements in the input stack.
170 * <p/>
171 * When the stack map frames are completely computed, this field is the
172 * offset of the first output stack element relatively to the top of the
173 * input stack. This offset is always negative or null. A null offset means
174 * that the output stack must be appended to the input stack. A -n offset
175 * means that the first n output stack elements must replace the top n input
176 * stack elements, and that the other elements must be appended to the input
177 * stack.
178 */
179 int inputStackTop;
180
181 /**
182 * Maximum height reached by the output stack, relatively to the top of the
183 * input stack. This maximum is always positive or null.
184 */
185 int outputStackMax;
186
187 /**
188 * Information about the input and output stack map frames of this basic
189 * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES}
190 * option is used.
191 */
192 Frame frame;
193
194 /**
195 * The successor of this label, in the order they are visited. This linked
196 * list does not include labels used for debug info only. If
197 * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it
198 * does not contain successive labels that denote the same bytecode position
199 * (in this case only the first label appears in this list).
200 */
201 Label successor;
202
203 /**
204 * The successors of this node in the control flow graph. These successors
205 * are stored in a linked list of {@link Edge Edge} objects, linked to each
206 * other by their {@link Edge#next} field.
207 */
208 Edge successors;
209
210 /**
211 * The next basic block in the basic block stack. This stack is used in the
212 * main loop of the fix point algorithm used in the second step of the
213 * control flow analysis algorithms.
214 *
215 * @see MethodWriter#visitMaxs
216 */
217 Label next;
218
219 // ------------------------------------------------------------------------
220 // Constructor
221 // ------------------------------------------------------------------------
222
223 /**
224 * Constructs a new label.
225 */
226 public Label(){
227 }
228
229 /**
230 * Constructs a new label.
231 *
232 * @param debug if this label is only used for debug attributes.
233 */
234 Label(final boolean debug){
235 this.status = debug ? DEBUG : 0;
236 }
237
238 // ------------------------------------------------------------------------
239 // Methods to compute offsets and to manage forward references
240 // ------------------------------------------------------------------------
241
242 /**
243 * Returns the offset corresponding to this label. This offset is computed
244 * from the start of the method's bytecode. <i>This method is intended for
245 * {@link Attribute} sub classes, and is normally not needed by class
246 * generators or adapters.</i>
247 *
248 * @return the offset corresponding to this label.
249 * @throws IllegalStateException if this label is not resolved yet.
250 */
251 public int getOffset(){
252 if((status & RESOLVED) == 0)
253 {
254 throw new IllegalStateException("Label offset position has not been resolved yet");
255 }
256 return position;
257 }
258
259 /**
260 * Puts a reference to this label in the bytecode of a method. If the
261 * position of the label is known, the offset is computed and written
262 * directly. Otherwise, a null offset is written and a new forward reference
263 * is declared for this label.
264 *
265 * @param owner the code writer that calls this method.
266 * @param out the bytecode of the method.
267 * @param source the position of first byte of the bytecode instruction that
268 * contains this label.
269 * @param wideOffset <tt>true</tt> if the reference must be stored in 4
270 * bytes, or <tt>false</tt> if it must be stored with 2 bytes.
271 * @throws IllegalArgumentException if this label has not been created by
272 * the given code writer.
273 */
274 void put(
275 final MethodWriter owner,
276 final ByteVector out,
277 final int source,
278 final boolean wideOffset){
279 if((status & RESOLVED) != 0)
280 {
281 if(wideOffset)
282 {
283 out.putInt(position - source);
284 }
285 else
286 {
287 out.putShort(position - source);
288 }
289 }
290 else
291 {
292 if(wideOffset)
293 {
294 addReference(-1 - source, out.length);
295 out.putInt(-1);
296 }
297 else
298 {
299 addReference(source, out.length);
300 out.putShort(-1);
301 }
302 }
303 }
304
305 /**
306 * Adds a forward reference to this label. This method must be called only
307 * for a true forward reference, i.e. only if this label is not resolved
308 * yet. For backward references, the offset of the reference can be, and
309 * must be, computed and stored directly.
310 *
311 * @param sourcePosition the position of the referencing instruction. This
312 * position will be used to compute the offset of this forward
313 * reference.
314 * @param referencePosition the position where the offset for this forward
315 * reference must be stored.
316 */
317 private void addReference(
318 final int sourcePosition,
319 final int referencePosition){
320 if(srcAndRefPositions == null)
321 {
322 srcAndRefPositions = new int[6];
323 }
324 if(referenceCount >= srcAndRefPositions.length)
325 {
326 int[] a = new int[srcAndRefPositions.length + 6];
327 System.arraycopy(srcAndRefPositions,
328 0,
329 a,
330 0,
331 srcAndRefPositions.length);
332 srcAndRefPositions = a;
333 }
334 srcAndRefPositions[referenceCount++] = sourcePosition;
335 srcAndRefPositions[referenceCount++] = referencePosition;
336 }
337
338 /**
339 * Resolves all forward references to this label. This method must be called
340 * when this label is added to the bytecode of the method, i.e. when its
341 * position becomes known. This method fills in the blanks that where left
342 * in the bytecode by each forward reference previously added to this label.
343 *
344 * @param owner the code writer that calls this method.
345 * @param position the position of this label in the bytecode.
346 * @param data the bytecode of the method.
347 * @return <tt>true</tt> if a blank that was left for this label was to
348 * small to store the offset. In such a case the corresponding jump
349 * instruction is replaced with a pseudo instruction (using unused
350 * opcodes) using an unsigned two bytes offset. These pseudo
351 * instructions will need to be replaced with true instructions with
352 * wider offsets (4 bytes instead of 2). This is done in
353 * {@link MethodWriter#resizeInstructions}.
354 * @throws IllegalArgumentException if this label has already been resolved,
355 * or if it has not been created by the given code writer.
356 */
357 boolean resolve(
358 final MethodWriter owner,
359 final int position,
360 final byte[] data){
361 boolean needUpdate = false;
362 this.status |= RESOLVED;
363 this.position = position;
364 int i = 0;
365 while(i < referenceCount)
366 {
367 int source = srcAndRefPositions[i++];
368 int reference = srcAndRefPositions[i++];
369 int offset;
370 if(source >= 0)
371 {
372 offset = position - source;
373 if(offset < Short.MIN_VALUE || offset > Short.MAX_VALUE)
374 {
375 /*
376 * changes the opcode of the jump instruction, in order to
377 * be able to find it later (see resizeInstructions in
378 * MethodWriter). These temporary opcodes are similar to
379 * jump instruction opcodes, except that the 2 bytes offset
380 * is unsigned (and can therefore represent values from 0 to
381 * 65535, which is sufficient since the size of a method is
382 * limited to 65535 bytes).
383 */
384 int opcode = data[reference - 1] & 0xFF;
385 if(opcode <= Opcodes.JSR)
386 {
387 // changes IFEQ ... JSR to opcodes 202 to 217
388 data[reference - 1] = (byte) (opcode + 49);
389 }
390 else
391 {
392 // changes IFNULL and IFNONNULL to opcodes 218 and 219
393 data[reference - 1] = (byte) (opcode + 20);
394 }
395 needUpdate = true;
396 }
397 data[reference++] = (byte) (offset >>> 8);
398 data[reference] = (byte) offset;
399 }
400 else
401 {
402 offset = position + source + 1;
403 data[reference++] = (byte) (offset >>> 24);
404 data[reference++] = (byte) (offset >>> 16);
405 data[reference++] = (byte) (offset >>> 8);
406 data[reference] = (byte) offset;
407 }
408 }
409 return needUpdate;
410 }
411
412 /**
413 * Returns the first label of the series to which this label belongs. For an
414 * isolated label or for the first label in a series of successive labels,
415 * this method returns the label itself. For other labels it returns the
416 * first label of the series.
417 *
418 * @return the first label of the series to which this label belongs.
419 */
420 Label getFirst(){
421 return frame == null ? this : frame.owner;
422 }
423
424 // ------------------------------------------------------------------------
425 // Overriden Object methods
426 // ------------------------------------------------------------------------
427
428 /**
429 * Returns a string representation of this label.
430 *
431 * @return a string representation of this label.
432 */
433 public String toString(){
434 return "L" + System.identityHashCode(this);
435 }
436 }
+0
-186
src/jvm/clojure/asm/MethodAdapter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * An empty {@link MethodVisitor} that delegates to another
33 * {@link MethodVisitor}. This class can be used as a super class to quickly
34 * implement usefull method adapter classes, just by overriding the necessary
35 * methods.
36 *
37 * @author Eric Bruneton
38 */
39 public class MethodAdapter implements MethodVisitor{
40
41 /**
42 * The {@link MethodVisitor} to which this adapter delegates calls.
43 */
44 protected MethodVisitor mv;
45
46 /**
47 * Constructs a new {@link MethodAdapter} object.
48 *
49 * @param mv the code visitor to which this adapter must delegate calls.
50 */
51 public MethodAdapter(final MethodVisitor mv){
52 this.mv = mv;
53 }
54
55 public AnnotationVisitor visitAnnotationDefault(){
56 return mv.visitAnnotationDefault();
57 }
58
59 public AnnotationVisitor visitAnnotation(
60 final String desc,
61 final boolean visible){
62 return mv.visitAnnotation(desc, visible);
63 }
64
65 public AnnotationVisitor visitParameterAnnotation(
66 final int parameter,
67 final String desc,
68 final boolean visible){
69 return mv.visitParameterAnnotation(parameter, desc, visible);
70 }
71
72 public void visitAttribute(final Attribute attr){
73 mv.visitAttribute(attr);
74 }
75
76 public void visitCode(){
77 mv.visitCode();
78 }
79
80 public void visitFrame(
81 final int type,
82 final int nLocal,
83 final Object[] local,
84 final int nStack,
85 final Object[] stack){
86 mv.visitFrame(type, nLocal, local, nStack, stack);
87 }
88
89 public void visitInsn(final int opcode){
90 mv.visitInsn(opcode);
91 }
92
93 public void visitIntInsn(final int opcode, final int operand){
94 mv.visitIntInsn(opcode, operand);
95 }
96
97 public void visitVarInsn(final int opcode, final int var){
98 mv.visitVarInsn(opcode, var);
99 }
100
101 public void visitTypeInsn(final int opcode, final String desc){
102 mv.visitTypeInsn(opcode, desc);
103 }
104
105 public void visitFieldInsn(
106 final int opcode,
107 final String owner,
108 final String name,
109 final String desc){
110 mv.visitFieldInsn(opcode, owner, name, desc);
111 }
112
113 public void visitMethodInsn(
114 final int opcode,
115 final String owner,
116 final String name,
117 final String desc){
118 mv.visitMethodInsn(opcode, owner, name, desc);
119 }
120
121 public void visitJumpInsn(final int opcode, final Label label){
122 mv.visitJumpInsn(opcode, label);
123 }
124
125 public void visitLabel(final Label label){
126 mv.visitLabel(label);
127 }
128
129 public void visitLdcInsn(final Object cst){
130 mv.visitLdcInsn(cst);
131 }
132
133 public void visitIincInsn(final int var, final int increment){
134 mv.visitIincInsn(var, increment);
135 }
136
137 public void visitTableSwitchInsn(
138 final int min,
139 final int max,
140 final Label dflt,
141 final Label labels[]){
142 mv.visitTableSwitchInsn(min, max, dflt, labels);
143 }
144
145 public void visitLookupSwitchInsn(
146 final Label dflt,
147 final int keys[],
148 final Label labels[]){
149 mv.visitLookupSwitchInsn(dflt, keys, labels);
150 }
151
152 public void visitMultiANewArrayInsn(final String desc, final int dims){
153 mv.visitMultiANewArrayInsn(desc, dims);
154 }
155
156 public void visitTryCatchBlock(
157 final Label start,
158 final Label end,
159 final Label handler,
160 final String type){
161 mv.visitTryCatchBlock(start, end, handler, type);
162 }
163
164 public void visitLocalVariable(
165 final String name,
166 final String desc,
167 final String signature,
168 final Label start,
169 final Label end,
170 final int index){
171 mv.visitLocalVariable(name, desc, signature, start, end, index);
172 }
173
174 public void visitLineNumber(final int line, final Label start){
175 mv.visitLineNumber(line, start);
176 }
177
178 public void visitMaxs(final int maxStack, final int maxLocals){
179 mv.visitMaxs(maxStack, maxLocals);
180 }
181
182 public void visitEnd(){
183 mv.visitEnd();
184 }
185 }
+0
-396
src/jvm/clojure/asm/MethodVisitor.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * A visitor to visit a Java method. The methods of this interface must be
33 * called in the following order: [ <tt>visitAnnotationDefault</tt> ] (
34 * <tt>visitAnnotation</tt> | <tt>visitParameterAnnotation</tt> |
35 * <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> |
36 * <tt>visit</tt><i>X</i>Insn</tt> | <tt>visitLabel</tt> | <tt>visitTryCatchBlock</tt> |
37 * <tt>visitLocalVariable</tt> | <tt>visitLineNumber</tt>)* <tt>visitMaxs</tt> ]
38 * <tt>visitEnd</tt>. In addition, the <tt>visit</tt><i>X</i>Insn</tt>
39 * and <tt>visitLabel</tt> methods must be called in the sequential order of
40 * the bytecode instructions of the visited code, <tt>visitTryCatchBlock</tt>
41 * must be called <i>before</i> the labels passed as arguments have been
42 * visited, and the <tt>visitLocalVariable</tt> and <tt>visitLineNumber</tt>
43 * methods must be called <i>after</i> the labels passed as arguments have been
44 * visited.
45 *
46 * @author Eric Bruneton
47 */
48 public interface MethodVisitor{
49
50 // -------------------------------------------------------------------------
51 // Annotations and non standard attributes
52 // -------------------------------------------------------------------------
53
54 /**
55 * Visits the default value of this annotation interface method.
56 *
57 * @return a visitor to the visit the actual default value of this
58 * annotation interface method, or <tt>null</tt> if this visitor
59 * is not interested in visiting this default value. The 'name'
60 * parameters passed to the methods of this annotation visitor are
61 * ignored. Moreover, exacly one visit method must be called on this
62 * annotation visitor, followed by visitEnd.
63 */
64 AnnotationVisitor visitAnnotationDefault();
65
66 /**
67 * Visits an annotation of this method.
68 *
69 * @param desc the class descriptor of the annotation class.
70 * @param visible <tt>true</tt> if the annotation is visible at runtime.
71 * @return a visitor to visit the annotation values, or <tt>null</tt> if
72 * this visitor is not interested in visiting this annotation.
73 */
74 AnnotationVisitor visitAnnotation(String desc, boolean visible);
75
76 /**
77 * Visits an annotation of a parameter this method.
78 *
79 * @param parameter the parameter index.
80 * @param desc the class descriptor of the annotation class.
81 * @param visible <tt>true</tt> if the annotation is visible at runtime.
82 * @return a visitor to visit the annotation values, or <tt>null</tt> if
83 * this visitor is not interested in visiting this annotation.
84 */
85 AnnotationVisitor visitParameterAnnotation(
86 int parameter,
87 String desc,
88 boolean visible);
89
90 /**
91 * Visits a non standard attribute of this method.
92 *
93 * @param attr an attribute.
94 */
95 void visitAttribute(Attribute attr);
96
97 /**
98 * Starts the visit of the method's code, if any (i.e. non abstract method).
99 */
100 void visitCode();
101
102 /**
103 * Visits the current state of the local variables and operand stack
104 * elements. This method must(*) be called <i>just before</i> any
105 * instruction <b>i</b> that follows an unconditionnal branch instruction
106 * such as GOTO or THROW, that is the target of a jump instruction, or that
107 * starts an exception handler block. The visited types must describe the
108 * values of the local variables and of the operand stack elements <i>just
109 * before</i> <b>i</b> is executed. <br> <br> (*) this is mandatory only
110 * for classes whose version is greater than or equal to
111 * {@link Opcodes#V1_6 V1_6}. <br> <br> Packed frames are basically
112 * "deltas" from the state of the previous frame (very first frame is
113 * implicitly defined by the method's parameters and access flags): <ul>
114 * <li>{@link Opcodes#F_SAME} representing frame with exactly the same
115 * locals as the previous frame and with the empty stack.</li> <li>{@link Opcodes#F_SAME1}
116 * representing frame with exactly the same locals as the previous frame and
117 * with single value on the stack (<code>nStack</code> is 1 and
118 * <code>stack[0]</code> contains value for the type of the stack item).</li>
119 * <li>{@link Opcodes#F_APPEND} representing frame with current locals are
120 * the same as the locals in the previous frame, except that additional
121 * locals are defined (<code>nLocal</code> is 1, 2 or 3 and
122 * <code>local</code> elements contains values representing added types).</li>
123 * <li>{@link Opcodes#F_CHOP} representing frame with current locals are
124 * the same as the locals in the previous frame, except that the last 1-3
125 * locals are absent and with the empty stack (<code>nLocals</code> is 1,
126 * 2 or 3). </li> <li>{@link Opcodes#F_FULL} representing complete frame
127 * data.</li> </li> </ul>
128 *
129 * @param type the type of this stack map frame. Must be
130 * {@link Opcodes#F_NEW} for expanded frames, or
131 * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
132 * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
133 * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed
134 * frames.
135 * @param nLocal the number of local variables in the visited frame.
136 * @param local the local variable types in this frame. This array must not
137 * be modified. Primitive types are represented by
138 * {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
139 * {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
140 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
141 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are
142 * represented by a single element). Reference types are represented
143 * by String objects (representing internal names, or type
144 * descriptors for array types), and uninitialized types by Label
145 * objects (this label designates the NEW instruction that created
146 * this uninitialized value).
147 * @param nStack the number of operand stack elements in the visited frame.
148 * @param stack the operand stack types in this frame. This array must not
149 * be modified. Its content has the same format as the "local" array.
150 */
151 void visitFrame(
152 int type,
153 int nLocal,
154 Object[] local,
155 int nStack,
156 Object[] stack);
157
158 // -------------------------------------------------------------------------
159 // Normal instructions
160 // -------------------------------------------------------------------------
161
162 /**
163 * Visits a zero operand instruction.
164 *
165 * @param opcode the opcode of the instruction to be visited. This opcode is
166 * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2,
167 * ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0,
168 * FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD,
169 * DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE,
170 * DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP,
171 * DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD, LADD, FADD,
172 * DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV,
173 * FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL,
174 * LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR,
175 * I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B,
176 * I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN,
177 * FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW,
178 * MONITORENTER, or MONITOREXIT.
179 */
180 void visitInsn(int opcode);
181
182 /**
183 * Visits an instruction with a single int operand.
184 *
185 * @param opcode the opcode of the instruction to be visited. This opcode is
186 * either BIPUSH, SIPUSH or NEWARRAY.
187 * @param operand the operand of the instruction to be visited.<br> When
188 * opcode is BIPUSH, operand value should be between Byte.MIN_VALUE
189 * and Byte.MAX_VALUE.<br> When opcode is SIPUSH, operand value
190 * should be between Short.MIN_VALUE and Short.MAX_VALUE.<br> When
191 * opcode is NEWARRAY, operand value should be one of
192 * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
193 * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE},
194 * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
195 * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
196 */
197 void visitIntInsn(int opcode, int operand);
198
199 /**
200 * Visits a local variable instruction. A local variable instruction is an
201 * instruction that loads or stores the value of a local variable.
202 *
203 * @param opcode the opcode of the local variable instruction to be visited.
204 * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE,
205 * LSTORE, FSTORE, DSTORE, ASTORE or RET.
206 * @param var the operand of the instruction to be visited. This operand is
207 * the index of a local variable.
208 */
209 void visitVarInsn(int opcode, int var);
210
211 /**
212 * Visits a type instruction. A type instruction is an instruction that
213 * takes a type descriptor as parameter.
214 *
215 * @param opcode the opcode of the type instruction to be visited. This
216 * opcode is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
217 * @param desc the operand of the instruction to be visited. This operand is
218 * must be a fully qualified class name in internal form, or the type
219 * descriptor of an array type (see {@link Type Type}).
220 */
221 void visitTypeInsn(int opcode, String desc);
222
223 /**
224 * Visits a field instruction. A field instruction is an instruction that
225 * loads or stores the value of a field of an object.
226 *
227 * @param opcode the opcode of the type instruction to be visited. This
228 * opcode is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
229 * @param owner the internal name of the field's owner class (see {@link
230 * Type#getInternalName() getInternalName}).
231 * @param name the field's name.
232 * @param desc the field's descriptor (see {@link Type Type}).
233 */
234 void visitFieldInsn(int opcode, String owner, String name, String desc);
235
236 /**
237 * Visits a method instruction. A method instruction is an instruction that
238 * invokes a method.
239 *
240 * @param opcode the opcode of the type instruction to be visited. This
241 * opcode is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
242 * INVOKEINTERFACE.
243 * @param owner the internal name of the method's owner class (see {@link
244 * Type#getInternalName() getInternalName}).
245 * @param name the method's name.
246 * @param desc the method's descriptor (see {@link Type Type}).
247 */
248 void visitMethodInsn(int opcode, String owner, String name, String desc);
249
250 /**
251 * Visits a jump instruction. A jump instruction is an instruction that may
252 * jump to another instruction.
253 *
254 * @param opcode the opcode of the type instruction to be visited. This
255 * opcode is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
256 * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ,
257 * IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
258 * @param label the operand of the instruction to be visited. This operand
259 * is a label that designates the instruction to which the jump
260 * instruction may jump.
261 */
262 void visitJumpInsn(int opcode, Label label);
263
264 /**
265 * Visits a label. A label designates the instruction that will be visited
266 * just after it.
267 *
268 * @param label a {@link Label Label} object.
269 */
270 void visitLabel(Label label);
271
272 // -------------------------------------------------------------------------
273 // Special instructions
274 // -------------------------------------------------------------------------
275
276 /**
277 * Visits a LDC instruction.
278 *
279 * @param cst the constant to be loaded on the stack. This parameter must be
280 * a non null {@link Integer}, a {@link Float}, a {@link Long}, a
281 * {@link Double} a {@link String} (or a {@link Type} for
282 * <tt>.class</tt> constants, for classes whose version is 49.0 or
283 * more).
284 */
285 void visitLdcInsn(Object cst);
286
287 /**
288 * Visits an IINC instruction.
289 *
290 * @param var index of the local variable to be incremented.
291 * @param increment amount to increment the local variable by.
292 */
293 void visitIincInsn(int var, int increment);
294
295 /**
296 * Visits a TABLESWITCH instruction.
297 *
298 * @param min the minimum key value.
299 * @param max the maximum key value.
300 * @param dflt beginning of the default handler block.
301 * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is
302 * the beginning of the handler block for the <tt>min + i</tt> key.
303 */
304 void visitTableSwitchInsn(int min, int max, Label dflt, Label labels[]);
305
306 /**
307 * Visits a LOOKUPSWITCH instruction.
308 *
309 * @param dflt beginning of the default handler block.
310 * @param keys the values of the keys.
311 * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is
312 * the beginning of the handler block for the <tt>keys[i]</tt> key.
313 */
314 void visitLookupSwitchInsn(Label dflt, int keys[], Label labels[]);
315
316 /**
317 * Visits a MULTIANEWARRAY instruction.
318 *
319 * @param desc an array type descriptor (see {@link Type Type}).
320 * @param dims number of dimensions of the array to allocate.
321 */
322 void visitMultiANewArrayInsn(String desc, int dims);
323
324 // -------------------------------------------------------------------------
325 // Exceptions table entries, debug information, max stack and max locals
326 // -------------------------------------------------------------------------
327
328 /**
329 * Visits a try catch block.
330 *
331 * @param start beginning of the exception handler's scope (inclusive).
332 * @param end end of the exception handler's scope (exclusive).
333 * @param handler beginning of the exception handler's code.
334 * @param type internal name of the type of exceptions handled by the
335 * handler, or <tt>null</tt> to catch any exceptions (for "finally"
336 * blocks).
337 * @throws IllegalArgumentException if one of the labels has already been
338 * visited by this visitor (by the {@link #visitLabel visitLabel}
339 * method).
340 */
341 void visitTryCatchBlock(Label start, Label end, Label handler, String type);
342
343 /**
344 * Visits a local variable declaration.
345 *
346 * @param name the name of a local variable.
347 * @param desc the type descriptor of this local variable.
348 * @param signature the type signature of this local variable. May be
349 * <tt>null</tt> if the local variable type does not use generic
350 * types.
351 * @param start the first instruction corresponding to the scope of this
352 * local variable (inclusive).
353 * @param end the last instruction corresponding to the scope of this local
354 * variable (exclusive).
355 * @param index the local variable's index.
356 * @throws IllegalArgumentException if one of the labels has not already
357 * been visited by this visitor (by the
358 * {@link #visitLabel visitLabel} method).
359 */
360 void visitLocalVariable(
361 String name,
362 String desc,
363 String signature,
364 Label start,
365 Label end,
366 int index);
367
368 /**
369 * Visits a line number declaration.
370 *
371 * @param line a line number. This number refers to the source file from
372 * which the class was compiled.
373 * @param start the first instruction corresponding to this line number.
374 * @throws IllegalArgumentException if <tt>start</tt> has not already been
375 * visited by this visitor (by the {@link #visitLabel visitLabel}
376 * method).
377 */
378 void visitLineNumber(int line, Label start);
379
380 /**
381 * Visits the maximum stack size and the maximum number of local variables
382 * of the method.
383 *
384 * @param maxStack maximum stack size of the method.
385 * @param maxLocals maximum number of local variables for the method.
386 */
387 void visitMaxs(int maxStack, int maxLocals);
388
389 /**
390 * Visits the end of the method. This method, which is the last one to be
391 * called, is used to inform the visitor that all the annotations and
392 * attributes of the method have been visited.
393 */
394 void visitEnd();
395 }
+0
-3029
src/jvm/clojure/asm/MethodWriter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * A {@link MethodVisitor} that generates methods in bytecode form. Each visit
33 * method of this class appends the bytecode corresponding to the visited
34 * instruction to a byte vector, in the order these methods are called.
35 *
36 * @author Eric Bruneton
37 * @author Eugene Kuleshov
38 */
39 class MethodWriter implements MethodVisitor{
40
41 /**
42 * Pseudo access flag used to denote constructors.
43 */
44 final static int ACC_CONSTRUCTOR = 262144;
45
46 /**
47 * Frame has exactly the same locals as the previous stack map frame and
48 * number of stack items is zero.
49 */
50 final static int SAME_FRAME = 0; // to 63 (0-3f)
51
52 /**
53 * Frame has exactly the same locals as the previous stack map frame and
54 * number of stack items is 1
55 */
56 final static int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
57
58 /**
59 * Reserved for future use
60 */
61 final static int RESERVED = 128;
62
63 /**
64 * Frame has exactly the same locals as the previous stack map frame and
65 * number of stack items is 1. Offset is bigger then 63;
66 */
67 final static int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
68
69 /**
70 * Frame where current locals are the same as the locals in the previous
71 * frame, except that the k last locals are absent. The value of k is given
72 * by the formula 251-frame_type.
73 */
74 final static int CHOP_FRAME = 248; // to 250 (f8-fA)
75
76 /**
77 * Frame has exactly the same locals as the previous stack map frame and
78 * number of stack items is zero. Offset is bigger then 63;
79 */
80 final static int SAME_FRAME_EXTENDED = 251; // fb
81
82 /**
83 * Frame where current locals are the same as the locals in the previous
84 * frame, except that k additional locals are defined. The value of k is
85 * given by the formula frame_type-251.
86 */
87 final static int APPEND_FRAME = 252; // to 254 // fc-fe
88
89 /**
90 * Full frame
91 */
92 final static int FULL_FRAME = 255; // ff
93
94 /**
95 * Indicates that the stack map frames must be recomputed from scratch. In
96 * this case the maximum stack size and number of local variables is also
97 * recomputed from scratch.
98 *
99 * @see #compute
100 */
101 private final static int FRAMES = 0;
102
103 /**
104 * Indicates that the maximum stack size and number of local variables must
105 * be automatically computed.
106 *
107 * @see #compute
108 */
109 private final static int MAXS = 1;
110
111 /**
112 * Indicates that nothing must be automatically computed.
113 *
114 * @see #compute
115 */
116 private final static int NOTHING = 2;
117
118 /**
119 * Next method writer (see {@link ClassWriter#firstMethod firstMethod}).
120 */
121 MethodWriter next;
122
123 /**
124 * The class writer to which this method must be added.
125 */
126 ClassWriter cw;
127
128 /**
129 * Access flags of this method.
130 */
131 private int access;
132
133 /**
134 * The index of the constant pool item that contains the name of this
135 * method.
136 */
137 private int name;
138
139 /**
140 * The index of the constant pool item that contains the descriptor of this
141 * method.
142 */
143 private int desc;
144
145 /**
146 * The descriptor of this method.
147 */
148 private String descriptor;
149
150 /**
151 * The signature of this method.
152 */
153 String signature;
154
155 /**
156 * If not zero, indicates that the code of this method must be copied from
157 * the ClassReader associated to this writer in <code>cw.cr</code>. More
158 * precisely, this field gives the index of the first byte to copied from
159 * <code>cw.cr.b</code>.
160 */
161 int classReaderOffset;
162
163 /**
164 * If not zero, indicates that the code of this method must be copied from
165 * the ClassReader associated to this writer in <code>cw.cr</code>. More
166 * precisely, this field gives the number of bytes to copied from
167 * <code>cw.cr.b</code>.
168 */
169 int classReaderLength;
170
171 /**
172 * Number of exceptions that can be thrown by this method.
173 */
174 int exceptionCount;
175
176 /**
177 * The exceptions that can be thrown by this method. More precisely, this
178 * array contains the indexes of the constant pool items that contain the
179 * internal names of these exception classes.
180 */
181 int[] exceptions;
182
183 /**
184 * The annotation default attribute of this method. May be <tt>null</tt>.
185 */
186 private ByteVector annd;
187
188 /**
189 * The runtime visible annotations of this method. May be <tt>null</tt>.
190 */
191 private AnnotationWriter anns;
192
193 /**
194 * The runtime invisible annotations of this method. May be <tt>null</tt>.
195 */
196 private AnnotationWriter ianns;
197
198 /**
199 * The runtime visible parameter annotations of this method. May be
200 * <tt>null</tt>.
201 */
202 private AnnotationWriter[] panns;
203
204 /**
205 * The runtime invisible parameter annotations of this method. May be
206 * <tt>null</tt>.
207 */
208 private AnnotationWriter[] ipanns;
209
210 /**
211 * The non standard attributes of the method.
212 */
213 private Attribute attrs;
214
215 /**
216 * The bytecode of this method.
217 */
218 private ByteVector code = new ByteVector();
219
220 /**
221 * Maximum stack size of this method.
222 */
223 private int maxStack;
224
225 /**
226 * Maximum number of local variables for this method.
227 */
228 private int maxLocals;
229
230 /**
231 * Number of stack map frames in the StackMapTable attribute.
232 */
233 private int frameCount;
234
235 /**
236 * The StackMapTable attribute.
237 */
238 private ByteVector stackMap;
239
240 /**
241 * The offset of the last frame that was written in the StackMapTable
242 * attribute.
243 */
244 private int previousFrameOffset;
245
246 /**
247 * The last frame that was written in the StackMapTable attribute.
248 *
249 * @see #frame
250 */
251 private int[] previousFrame;
252
253 /**
254 * Index of the next element to be added in {@link #frame}.
255 */
256 private int frameIndex;
257
258 /**
259 * The current stack map frame. The first element contains the offset of the
260 * instruction to which the frame corresponds, the second element is the
261 * number of locals and the third one is the number of stack elements. The
262 * local variables start at index 3 and are followed by the operand stack
263 * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] =
264 * nStack, frame[3] = nLocal. All types are encoded as integers, with the
265 * same format as the one used in {@link Label}, but limited to BASE types.
266 */
267 private int[] frame;
268
269 /**
270 * Number of elements in the exception handler list.
271 */
272 private int handlerCount;
273
274 /**
275 * The first element in the exception handler list.
276 */
277 private Handler firstHandler;
278
279 /**
280 * The last element in the exception handler list.
281 */
282 private Handler lastHandler;
283
284 /**
285 * Number of entries in the LocalVariableTable attribute.
286 */
287 private int localVarCount;
288
289 /**
290 * The LocalVariableTable attribute.
291 */
292 private ByteVector localVar;
293
294 /**
295 * Number of entries in the LocalVariableTypeTable attribute.
296 */
297 private int localVarTypeCount;
298
299 /**
300 * The LocalVariableTypeTable attribute.
301 */
302 private ByteVector localVarType;
303
304 /**
305 * Number of entries in the LineNumberTable attribute.
306 */
307 private int lineNumberCount;
308
309 /**
310 * The LineNumberTable attribute.
311 */
312 private ByteVector lineNumber;
313
314 /**
315 * The non standard attributes of the method's code.
316 */
317 private Attribute cattrs;
318
319 /**
320 * Indicates if some jump instructions are too small and need to be resized.
321 */
322 private boolean resize;
323
324 /**
325 * Indicates if the instructions contain at least one JSR instruction.
326 */
327 private boolean jsr;
328
329 // ------------------------------------------------------------------------
330
331 /*
332 * Fields for the control flow graph analysis algorithm (used to compute the
333 * maximum stack size). A control flow graph contains one node per "basic
334 * block", and one edge per "jump" from one basic block to another. Each
335 * node (i.e., each basic block) is represented by the Label object that
336 * corresponds to the first instruction of this basic block. Each node also
337 * stores the list of its successors in the graph, as a linked list of Edge
338 * objects.
339 */
340
341 /**
342 * Indicates what must be automatically computed.
343 *
344 * @see FRAMES
345 * @see MAXS
346 * @see NOTHING
347 */
348 private int compute;
349
350 /**
351 * A list of labels. This list is the list of basic blocks in the method,
352 * i.e. a list of Label objects linked to each other by their
353 * {@link Label#successor} field, in the order they are visited by
354 * {@link visitLabel}, and starting with the first basic block.
355 */
356 private Label labels;
357
358 /**
359 * The previous basic block.
360 */
361 private Label previousBlock;
362
363 /**
364 * The current basic block.
365 */
366 private Label currentBlock;
367
368 /**
369 * The (relative) stack size after the last visited instruction. This size
370 * is relative to the beginning of the current basic block, i.e., the true
371 * stack size after the last visited instruction is equal to the
372 * {@link Label#inputStackTop beginStackSize} of the current basic block
373 * plus <tt>stackSize</tt>.
374 */
375 private int stackSize;
376
377 /**
378 * The (relative) maximum stack size after the last visited instruction.
379 * This size is relative to the beginning of the current basic block, i.e.,
380 * the true maximum stack size after the last visited instruction is equal
381 * to the {@link Label#inputStackTop beginStackSize} of the current basic
382 * block plus <tt>stackSize</tt>.
383 */
384 private int maxStackSize;
385
386 // ------------------------------------------------------------------------
387 // Constructor
388 // ------------------------------------------------------------------------
389
390 /**
391 * Constructs a new {@link MethodWriter}.
392 *
393 * @param cw the class writer in which the method must be added.
394 * @param access the method's access flags (see {@link Opcodes}).
395 * @param name the method's name.
396 * @param desc the method's descriptor (see {@link Type}).
397 * @param signature the method's signature. May be <tt>null</tt>.
398 * @param exceptions the internal names of the method's exceptions. May be
399 * <tt>null</tt>.
400 * @param computeMaxs <tt>true</tt> if the maximum stack size and number
401 * of local variables must be automatically computed.
402 * @param computeFrames <tt>true</tt> if the stack map tables must be
403 * recomputed from scratch.
404 */
405 MethodWriter(
406 final ClassWriter cw,
407 final int access,
408 final String name,
409 final String desc,
410 final String signature,
411 final String[] exceptions,
412 final boolean computeMaxs,
413 final boolean computeFrames){
414 if(cw.firstMethod == null)
415 {
416 cw.firstMethod = this;
417 }
418 else
419 {
420 cw.lastMethod.next = this;
421 }
422 cw.lastMethod = this;
423 this.cw = cw;
424 this.access = access;
425 this.name = cw.newUTF8(name);
426 this.desc = cw.newUTF8(desc);
427 this.descriptor = desc;
428 this.signature = signature;
429 if(exceptions != null && exceptions.length > 0)
430 {
431 exceptionCount = exceptions.length;
432 this.exceptions = new int[exceptionCount];
433 for(int i = 0; i < exceptionCount; ++i)
434 {
435 this.exceptions[i] = cw.newClass(exceptions[i]);
436 }
437 }
438 this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING);
439 if(computeMaxs || computeFrames)
440 {
441 if(computeFrames && name.equals("<init>"))
442 {
443 this.access |= ACC_CONSTRUCTOR;
444 }
445 // updates maxLocals
446 int size = getArgumentsAndReturnSizes(descriptor) >> 2;
447 if((access & Opcodes.ACC_STATIC) != 0)
448 {
449 --size;
450 }
451 maxLocals = size;
452 // creates and visits the label for the first basic block
453 labels = new Label();
454 labels.status |= Label.PUSHED;
455 visitLabel(labels);
456 }
457 }
458
459 // ------------------------------------------------------------------------
460 // Implementation of the MethodVisitor interface
461 // ------------------------------------------------------------------------
462
463 public AnnotationVisitor visitAnnotationDefault(){
464 annd = new ByteVector();
465 return new AnnotationWriter(cw, false, annd, null, 0);
466 }
467
468 public AnnotationVisitor visitAnnotation(
469 final String desc,
470 final boolean visible){
471 ByteVector bv = new ByteVector();
472 // write type, and reserve space for values count
473 bv.putShort(cw.newUTF8(desc)).putShort(0);
474 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
475 if(visible)
476 {
477 aw.next = anns;
478 anns = aw;
479 }
480 else
481 {
482 aw.next = ianns;
483 ianns = aw;
484 }
485 return aw;
486 }
487
488 public AnnotationVisitor visitParameterAnnotation(
489 final int parameter,
490 final String desc,
491 final boolean visible){
492 ByteVector bv = new ByteVector();
493 // write type, and reserve space for values count
494 bv.putShort(cw.newUTF8(desc)).putShort(0);
495 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
496 if(visible)
497 {
498 if(panns == null)
499 {
500 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
501 }
502 aw.next = panns[parameter];
503 panns[parameter] = aw;
504 }
505 else
506 {
507 if(ipanns == null)
508 {
509 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
510 }
511 aw.next = ipanns[parameter];
512 ipanns[parameter] = aw;
513 }
514 return aw;
515 }
516
517 public void visitAttribute(final Attribute attr){
518 if(attr.isCodeAttribute())
519 {
520 attr.next = cattrs;
521 cattrs = attr;
522 }
523 else
524 {
525 attr.next = attrs;
526 attrs = attr;
527 }
528 }
529
530 public void visitCode(){
531 }
532
533 public void visitFrame(
534 final int type,
535 final int nLocal,
536 final Object[] local,
537 final int nStack,
538 final Object[] stack){
539 if(compute == FRAMES)
540 {
541 return;
542 }
543
544 if(type == Opcodes.F_NEW)
545 {
546 startFrame(code.length, nLocal, nStack);
547 for(int i = 0; i < nLocal; ++i)
548 {
549 if(local[i] instanceof String)
550 {
551 frame[frameIndex++] = Frame.OBJECT
552 | cw.addType((String) local[i]);
553 }
554 else if(local[i] instanceof Integer)
555 {
556 frame[frameIndex++] = ((Integer) local[i]).intValue();
557 }
558 else
559 {
560 frame[frameIndex++] = Frame.UNINITIALIZED
561 | cw.addUninitializedType("",
562 ((Label) local[i]).position);
563 }
564 }
565 for(int i = 0; i < nStack; ++i)
566 {
567 if(stack[i] instanceof String)
568 {
569 frame[frameIndex++] = Frame.OBJECT
570 | cw.addType((String) stack[i]);
571 }
572 else if(stack[i] instanceof Integer)
573 {
574 frame[frameIndex++] = ((Integer) stack[i]).intValue();
575 }
576 else
577 {
578 frame[frameIndex++] = Frame.UNINITIALIZED
579 | cw.addUninitializedType("",
580 ((Label) stack[i]).position);
581 }
582 }
583 endFrame();
584 }
585 else
586 {
587 int delta;
588 if(stackMap == null)
589 {
590 stackMap = new ByteVector();
591 delta = code.length;
592 }
593 else
594 {
595 delta = code.length - previousFrameOffset - 1;
596 }
597
598 switch(type)
599 {
600 case Opcodes.F_FULL:
601 stackMap.putByte(FULL_FRAME)
602 .putShort(delta)
603 .putShort(nLocal);
604 for(int i = 0; i < nLocal; ++i)
605 {
606 writeFrameType(local[i]);
607 }
608 stackMap.putShort(nStack);
609 for(int i = 0; i < nStack; ++i)
610 {
611 writeFrameType(stack[i]);
612 }
613 break;
614 case Opcodes.F_APPEND:
615 stackMap.putByte(SAME_FRAME_EXTENDED + nLocal)
616 .putShort(delta);
617 for(int i = 0; i < nLocal; ++i)
618 {
619 writeFrameType(local[i]);
620 }
621 break;
622 case Opcodes.F_CHOP:
623 stackMap.putByte(SAME_FRAME_EXTENDED - nLocal)
624 .putShort(delta);
625 break;
626 case Opcodes.F_SAME:
627 if(delta < 64)
628 {
629 stackMap.putByte(delta);
630 }
631 else
632 {
633 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
634 }
635 break;
636 case Opcodes.F_SAME1:
637 if(delta < 64)
638 {
639 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
640 }
641 else
642 {
643 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
644 .putShort(delta);
645 }
646 writeFrameType(stack[0]);
647 break;
648 }
649
650 previousFrameOffset = code.length;
651 ++frameCount;
652 }
653 }
654
655 public void visitInsn(final int opcode){
656 // adds the instruction to the bytecode of the method
657 code.putByte(opcode);
658 // update currentBlock
659 // Label currentBlock = this.currentBlock;
660 if(currentBlock != null)
661 {
662 if(compute == FRAMES)
663 {
664 currentBlock.frame.execute(opcode, 0, null, null);
665 }
666 else
667 {
668 // updates current and max stack sizes
669 int size = stackSize + Frame.SIZE[opcode];
670 if(size > maxStackSize)
671 {
672 maxStackSize = size;
673 }
674 stackSize = size;
675 }
676 // if opcode == ATHROW or xRETURN, ends current block (no successor)
677 if((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
678 || opcode == Opcodes.ATHROW)
679 {
680 noSuccessor();
681 }
682 }
683 }
684
685 public void visitIntInsn(final int opcode, final int operand){
686 // Label currentBlock = this.currentBlock;
687 if(currentBlock != null)
688 {
689 if(compute == FRAMES)
690 {
691 currentBlock.frame.execute(opcode, operand, null, null);
692 }
693 else if(opcode != Opcodes.NEWARRAY)
694 {
695 // updates current and max stack sizes only for NEWARRAY
696 // (stack size variation = 0 for BIPUSH or SIPUSH)
697 int size = stackSize + 1;
698 if(size > maxStackSize)
699 {
700 maxStackSize = size;
701 }
702 stackSize = size;
703 }
704 }
705 // adds the instruction to the bytecode of the method
706 if(opcode == Opcodes.SIPUSH)
707 {
708 code.put12(opcode, operand);
709 }
710 else
711 { // BIPUSH or NEWARRAY
712 code.put11(opcode, operand);
713 }
714 }
715
716 public void visitVarInsn(final int opcode, final int var){
717 // Label currentBlock = this.currentBlock;
718 if(currentBlock != null)
719 {
720 if(compute == FRAMES)
721 {
722 currentBlock.frame.execute(opcode, var, null, null);
723 }
724 else
725 {
726 // updates current and max stack sizes
727 if(opcode == Opcodes.RET)
728 {
729 // no stack change, but end of current block (no successor)
730 currentBlock.status |= Label.RET;
731 // save 'stackSize' here for future use
732 // (see {@link #findSubroutineSuccessors})
733 currentBlock.inputStackTop = stackSize;
734 noSuccessor();
735 }
736 else
737 { // xLOAD or xSTORE
738 int size = stackSize + Frame.SIZE[opcode];
739 if(size > maxStackSize)
740 {
741 maxStackSize = size;
742 }
743 stackSize = size;
744 }
745 }
746 }
747 if(compute != NOTHING)
748 {
749 // updates max locals
750 int n;
751 if(opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
752 || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE)
753 {
754 n = var + 2;
755 }
756 else
757 {
758 n = var + 1;
759 }
760 if(n > maxLocals)
761 {
762 maxLocals = n;
763 }
764 }
765 // adds the instruction to the bytecode of the method
766 if(var < 4 && opcode != Opcodes.RET)
767 {
768 int opt;
769 if(opcode < Opcodes.ISTORE)
770 {
771 /* ILOAD_0 */
772 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
773 }
774 else
775 {
776 /* ISTORE_0 */
777 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
778 }
779 code.putByte(opt);
780 }
781 else if(var >= 256)
782 {
783 code.putByte(196 /* WIDE */).put12(opcode, var);
784 }
785 else
786 {
787 code.put11(opcode, var);
788 }
789 if(opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0)
790 {
791 visitLabel(new Label());
792 }
793 }
794
795 public void visitTypeInsn(final int opcode, final String desc){
796 Item i = cw.newClassItem(desc);
797 // Label currentBlock = this.currentBlock;
798 if(currentBlock != null)
799 {
800 if(compute == FRAMES)
801 {
802 currentBlock.frame.execute(opcode, code.length, cw, i);
803 }
804 else if(opcode == Opcodes.NEW)
805 {
806 // updates current and max stack sizes only if opcode == NEW
807 // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
808 int size = stackSize + 1;
809 if(size > maxStackSize)
810 {
811 maxStackSize = size;
812 }
813 stackSize = size;
814 }
815 }
816 // adds the instruction to the bytecode of the method
817 code.put12(opcode, i.index);
818 }
819
820 public void visitFieldInsn(
821 final int opcode,
822 final String owner,
823 final String name,
824 final String desc){
825 Item i = cw.newFieldItem(owner, name, desc);
826 // Label currentBlock = this.currentBlock;
827 if(currentBlock != null)
828 {
829 if(compute == FRAMES)
830 {
831 currentBlock.frame.execute(opcode, 0, cw, i);
832 }
833 else
834 {
835 int size;
836 // computes the stack size variation
837 char c = desc.charAt(0);
838 switch(opcode)
839 {
840 case Opcodes.GETSTATIC:
841 size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
842 break;
843 case Opcodes.PUTSTATIC:
844 size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
845 break;
846 case Opcodes.GETFIELD:
847 size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
848 break;
849 // case Constants.PUTFIELD:
850 default:
851 size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
852 break;
853 }
854 // updates current and max stack sizes
855 if(size > maxStackSize)
856 {
857 maxStackSize = size;
858 }
859 stackSize = size;
860 }
861 }
862 // adds the instruction to the bytecode of the method
863 code.put12(opcode, i.index);
864 }
865
866 public void visitMethodInsn(
867 final int opcode,
868 final String owner,
869 final String name,
870 final String desc){
871 boolean itf = opcode == Opcodes.INVOKEINTERFACE;
872 Item i = cw.newMethodItem(owner, name, desc, itf);
873 int argSize = i.intVal;
874 // Label currentBlock = this.currentBlock;
875 if(currentBlock != null)
876 {
877 if(compute == FRAMES)
878 {
879 currentBlock.frame.execute(opcode, 0, cw, i);
880 }
881 else
882 {
883 /*
884 * computes the stack size variation. In order not to recompute
885 * several times this variation for the same Item, we use the
886 * intVal field of this item to store this variation, once it
887 * has been computed. More precisely this intVal field stores
888 * the sizes of the arguments and of the return value
889 * corresponding to desc.
890 */
891 if(argSize == 0)
892 {
893 // the above sizes have not been computed yet,
894 // so we compute them...
895 argSize = getArgumentsAndReturnSizes(desc);
896 // ... and we save them in order
897 // not to recompute them in the future
898 i.intVal = argSize;
899 }
900 int size;
901 if(opcode == Opcodes.INVOKESTATIC)
902 {
903 size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
904 }
905 else
906 {
907 size = stackSize - (argSize >> 2) + (argSize & 0x03);
908 }
909 // updates current and max stack sizes
910 if(size > maxStackSize)
911 {
912 maxStackSize = size;
913 }
914 stackSize = size;
915 }
916 }
917 // adds the instruction to the bytecode of the method
918 if(itf)
919 {
920 if(argSize == 0)
921 {
922 argSize = getArgumentsAndReturnSizes(desc);
923 i.intVal = argSize;
924 }
925 code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
926 }
927 else
928 {
929 code.put12(opcode, i.index);
930 }
931 }
932
933 public void visitJumpInsn(final int opcode, final Label label){
934 Label nextInsn = null;
935 // Label currentBlock = this.currentBlock;
936 if(currentBlock != null)
937 {
938 if(compute == FRAMES)
939 {
940 currentBlock.frame.execute(opcode, 0, null, null);
941 // 'label' is the target of a jump instruction
942 label.getFirst().status |= Label.TARGET;
943 // adds 'label' as a successor of this basic block
944 addSuccessor(Edge.NORMAL, label);
945 if(opcode != Opcodes.GOTO)
946 {
947 // creates a Label for the next basic block
948 nextInsn = new Label();
949 }
950 }
951 else
952 {
953 if(opcode == Opcodes.JSR)
954 {
955 jsr = true;
956 currentBlock.status |= Label.JSR;
957 addSuccessor(stackSize + 1, label);
958 // creates a Label for the next basic block
959 nextInsn = new Label();
960 /*
961 * note that, by construction in this method, a JSR block
962 * has at least two successors in the control flow graph:
963 * the first one leads the next instruction after the JSR,
964 * while the second one leads to the JSR target.
965 */
966 }
967 else
968 {
969 // updates current stack size (max stack size unchanged
970 // because stack size variation always negative in this
971 // case)
972 stackSize += Frame.SIZE[opcode];
973 addSuccessor(stackSize, label);
974 }
975 }
976 }
977 // adds the instruction to the bytecode of the method
978 if((label.status & Label.RESOLVED) != 0
979 && label.position - code.length < Short.MIN_VALUE)
980 {
981 /*
982 * case of a backward jump with an offset < -32768. In this case we
983 * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
984 * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
985 * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
986 * designates the instruction just after the GOTO_W.
987 */
988 if(opcode == Opcodes.GOTO)
989 {
990 code.putByte(200); // GOTO_W
991 }
992 else if(opcode == Opcodes.JSR)
993 {
994 code.putByte(201); // JSR_W
995 }
996 else
997 {
998 // if the IF instruction is transformed into IFNOT GOTO_W the
999 // next instruction becomes the target of the IFNOT instruction
1000 if(nextInsn != null)
1001 {
1002 nextInsn.status |= Label.TARGET;
1003 }
1004 code.putByte(opcode <= 166
1005 ? ((opcode + 1) ^ 1) - 1
1006 : opcode ^ 1);
1007 code.putShort(8); // jump offset
1008 code.putByte(200); // GOTO_W
1009 }
1010 label.put(this, code, code.length - 1, true);
1011 }
1012 else
1013 {
1014 /*
1015 * case of a backward jump with an offset >= -32768, or of a forward
1016 * jump with, of course, an unknown offset. In these cases we store
1017 * the offset in 2 bytes (which will be increased in
1018 * resizeInstructions, if needed).
1019 */
1020 code.putByte(opcode);
1021 label.put(this, code, code.length - 1, false);
1022 }
1023 if(currentBlock != null)
1024 {
1025 if(nextInsn != null)
1026 {
1027 // if the jump instruction is not a GOTO, the next instruction
1028 // is also a successor of this instruction. Calling visitLabel
1029 // adds the label of this next instruction as a successor of the
1030 // current block, and starts a new basic block
1031 visitLabel(nextInsn);
1032 }
1033 if(opcode == Opcodes.GOTO)
1034 {
1035 noSuccessor();
1036 }
1037 }
1038 }
1039
1040 public void visitLabel(final Label label){
1041 // resolves previous forward references to label, if any
1042 resize |= label.resolve(this, code.length, code.data);
1043 // updates currentBlock
1044 if((label.status & Label.DEBUG) != 0)
1045 {
1046 return;
1047 }
1048 if(compute == FRAMES)
1049 {
1050 if(currentBlock != null)
1051 {
1052 if(label.position == currentBlock.position)
1053 {
1054 // successive labels, do not start a new basic block
1055 currentBlock.status |= (label.status & Label.TARGET);
1056 label.frame = currentBlock.frame;
1057 return;
1058 }
1059 // ends current block (with one new successor)
1060 addSuccessor(Edge.NORMAL, label);
1061 }
1062 // begins a new current block
1063 currentBlock = label;
1064 if(label.frame == null)
1065 {
1066 label.frame = new Frame();
1067 label.frame.owner = label;
1068 }
1069 // updates the basic block list
1070 if(previousBlock != null)
1071 {
1072 if(label.position == previousBlock.position)
1073 {
1074 previousBlock.status |= (label.status & Label.TARGET);
1075 label.frame = previousBlock.frame;
1076 currentBlock = previousBlock;
1077 return;
1078 }
1079 previousBlock.successor = label;
1080 }
1081 previousBlock = label;
1082 }
1083 else if(compute == MAXS)
1084 {
1085 if(currentBlock != null)
1086 {
1087 // ends current block (with one new successor)
1088 currentBlock.outputStackMax = maxStackSize;
1089 addSuccessor(stackSize, label);
1090 }
1091 // begins a new current block
1092 currentBlock = label;
1093 // resets the relative current and max stack sizes
1094 stackSize = 0;
1095 maxStackSize = 0;
1096 // updates the basic block list
1097 if(previousBlock != null)
1098 {
1099 previousBlock.successor = label;
1100 }
1101 previousBlock = label;
1102 }
1103 }
1104
1105 public void visitLdcInsn(final Object cst){
1106 Item i = cw.newConstItem(cst);
1107 // Label currentBlock = this.currentBlock;
1108 if(currentBlock != null)
1109 {
1110 if(compute == FRAMES)
1111 {
1112 currentBlock.frame.execute(Opcodes.LDC, 0, cw, i);
1113 }
1114 else
1115 {
1116 int size;
1117 // computes the stack size variation
1118 if(i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE)
1119 {
1120 size = stackSize + 2;
1121 }
1122 else
1123 {
1124 size = stackSize + 1;
1125 }
1126 // updates current and max stack sizes
1127 if(size > maxStackSize)
1128 {
1129 maxStackSize = size;
1130 }
1131 stackSize = size;
1132 }
1133 }
1134 // adds the instruction to the bytecode of the method
1135 int index = i.index;
1136 if(i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE)
1137 {
1138 code.put12(20 /* LDC2_W */, index);
1139 }
1140 else if(index >= 256)
1141 {
1142 code.put12(19 /* LDC_W */, index);
1143 }
1144 else
1145 {
1146 code.put11(Opcodes.LDC, index);
1147 }
1148 }
1149
1150 public void visitIincInsn(final int var, final int increment){
1151 if(currentBlock != null)
1152 {
1153 if(compute == FRAMES)
1154 {
1155 currentBlock.frame.execute(Opcodes.IINC, var, null, null);
1156 }
1157 }
1158 if(compute != NOTHING)
1159 {
1160 // updates max locals
1161 int n = var + 1;
1162 if(n > maxLocals)
1163 {
1164 maxLocals = n;
1165 }
1166 }
1167 // adds the instruction to the bytecode of the method
1168 if((var > 255) || (increment > 127) || (increment < -128))
1169 {
1170 code.putByte(196 /* WIDE */)
1171 .put12(Opcodes.IINC, var)
1172 .putShort(increment);
1173 }
1174 else
1175 {
1176 code.putByte(Opcodes.IINC).put11(var, increment);
1177 }
1178 }
1179
1180 public void visitTableSwitchInsn(
1181 final int min,
1182 final int max,
1183 final Label dflt,
1184 final Label labels[]){
1185 // adds the instruction to the bytecode of the method
1186 int source = code.length;
1187 code.putByte(Opcodes.TABLESWITCH);
1188 code.length += (4 - code.length % 4) % 4;
1189 dflt.put(this, code, source, true);
1190 code.putInt(min).putInt(max);
1191 for(int i = 0; i < labels.length; ++i)
1192 {
1193 labels[i].put(this, code, source, true);
1194 }
1195 // updates currentBlock
1196 visitSwitchInsn(dflt, labels);
1197 }
1198
1199 public void visitLookupSwitchInsn(
1200 final Label dflt,
1201 final int keys[],
1202 final Label labels[]){
1203 // adds the instruction to the bytecode of the method
1204 int source = code.length;
1205 code.putByte(Opcodes.LOOKUPSWITCH);
1206 code.length += (4 - code.length % 4) % 4;
1207 dflt.put(this, code, source, true);
1208 code.putInt(labels.length);
1209 for(int i = 0; i < labels.length; ++i)
1210 {
1211 code.putInt(keys[i]);
1212 labels[i].put(this, code, source, true);
1213 }
1214 // updates currentBlock
1215 visitSwitchInsn(dflt, labels);
1216 }
1217
1218 private void visitSwitchInsn(final Label dflt, final Label[] labels){
1219 // Label currentBlock = this.currentBlock;
1220 if(currentBlock != null)
1221 {
1222 if(compute == FRAMES)
1223 {
1224 currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
1225 // adds current block successors
1226 addSuccessor(Edge.NORMAL, dflt);
1227 dflt.getFirst().status |= Label.TARGET;
1228 for(int i = 0; i < labels.length; ++i)
1229 {
1230 addSuccessor(Edge.NORMAL, labels[i]);
1231 labels[i].getFirst().status |= Label.TARGET;
1232 }
1233 }
1234 else
1235 {
1236 // updates current stack size (max stack size unchanged)
1237 --stackSize;
1238 // adds current block successors
1239 addSuccessor(stackSize, dflt);
1240 for(int i = 0; i < labels.length; ++i)
1241 {
1242 addSuccessor(stackSize, labels[i]);
1243 }
1244 }
1245 // ends current block
1246 noSuccessor();
1247 }
1248 }
1249
1250 public void visitMultiANewArrayInsn(final String desc, final int dims){
1251 Item i = cw.newClassItem(desc);
1252 // Label currentBlock = this.currentBlock;
1253 if(currentBlock != null)
1254 {
1255 if(compute == FRAMES)
1256 {
1257 currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i);
1258 }
1259 else
1260 {
1261 // updates current stack size (max stack size unchanged because
1262 // stack size variation always negative or null)
1263 stackSize += 1 - dims;
1264 }
1265 }
1266 // adds the instruction to the bytecode of the method
1267 code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
1268 }
1269
1270 public void visitTryCatchBlock(
1271 final Label start,
1272 final Label end,
1273 final Label handler,
1274 final String type){
1275 ++handlerCount;
1276 Handler h = new Handler();
1277 h.start = start;
1278 h.end = end;
1279 h.handler = handler;
1280 h.desc = type;
1281 h.type = type != null ? cw.newClass(type) : 0;
1282 if(lastHandler == null)
1283 {
1284 firstHandler = h;
1285 }
1286 else
1287 {
1288 lastHandler.next = h;
1289 }
1290 lastHandler = h;
1291 }
1292
1293 public void visitLocalVariable(
1294 final String name,
1295 final String desc,
1296 final String signature,
1297 final Label start,
1298 final Label end,
1299 final int index){
1300 if(signature != null)
1301 {
1302 if(localVarType == null)
1303 {
1304 localVarType = new ByteVector();
1305 }
1306 ++localVarTypeCount;
1307 localVarType.putShort(start.position)
1308 .putShort(end.position - start.position)
1309 .putShort(cw.newUTF8(name))
1310 .putShort(cw.newUTF8(signature))
1311 .putShort(index);
1312 }
1313 if(localVar == null)
1314 {
1315 localVar = new ByteVector();
1316 }
1317 ++localVarCount;
1318 localVar.putShort(start.position)
1319 .putShort(end.position - start.position)
1320 .putShort(cw.newUTF8(name))
1321 .putShort(cw.newUTF8(desc))
1322 .putShort(index);
1323 if(compute != NOTHING)
1324 {
1325 // updates max locals
1326 char c = desc.charAt(0);
1327 int n = index + (c == 'J' || c == 'D' ? 2 : 1);
1328 if(n > maxLocals)
1329 {
1330 maxLocals = n;
1331 }
1332 }
1333 }
1334
1335 public void visitLineNumber(final int line, final Label start){
1336 if(lineNumber == null)
1337 {
1338 lineNumber = new ByteVector();
1339 }
1340 ++lineNumberCount;
1341 lineNumber.putShort(start.position);
1342 lineNumber.putShort(line);
1343 }
1344
1345 public void visitMaxs(final int maxStack, final int maxLocals){
1346 if(compute == FRAMES)
1347 {
1348 // completes the control flow graph with exception handler blocks
1349 Handler handler = firstHandler;
1350 while(handler != null)
1351 {
1352 Label l = handler.start.getFirst();
1353 Label h = handler.handler.getFirst();
1354 Label e = handler.end.getFirst();
1355 // computes the kind of the edges to 'h'
1356 String t = handler.desc == null
1357 ? "java/lang/Throwable"
1358 : handler.desc;
1359 int kind = Frame.OBJECT | cw.addType(t);
1360 // h is an exception handler
1361 h.status |= Label.TARGET;
1362 // adds 'h' as a successor of labels between 'start' and 'end'
1363 while(l != e)
1364 {
1365 // creates an edge to 'h'
1366 Edge b = new Edge();
1367 b.info = kind;
1368 b.successor = h;
1369 // adds it to the successors of 'l'
1370 b.next = l.successors;
1371 l.successors = b;
1372 // goes to the next label
1373 l = l.successor;
1374 }
1375 handler = handler.next;
1376 }
1377
1378 // creates and visits the first (implicit) frame
1379 Frame f = labels.frame;
1380 Type[] args = Type.getArgumentTypes(descriptor);
1381 f.initInputFrame(cw, access, args, this.maxLocals);
1382 visitFrame(f);
1383
1384 /*
1385 * fix point algorithm: mark the first basic block as 'changed'
1386 * (i.e. put it in the 'changed' list) and, while there are changed
1387 * basic blocks, choose one, mark it as unchanged, and update its
1388 * successors (which can be changed in the process).
1389 */
1390 int max = 0;
1391 Label changed = labels;
1392 while(changed != null)
1393 {
1394 // removes a basic block from the list of changed basic blocks
1395 Label l = changed;
1396 changed = changed.next;
1397 l.next = null;
1398 f = l.frame;
1399 // a reacheable jump target must be stored in the stack map
1400 if((l.status & Label.TARGET) != 0)
1401 {
1402 l.status |= Label.STORE;
1403 }
1404 // all visited labels are reacheable, by definition
1405 l.status |= Label.REACHABLE;
1406 // updates the (absolute) maximum stack size
1407 int blockMax = f.inputStack.length + l.outputStackMax;
1408 if(blockMax > max)
1409 {
1410 max = blockMax;
1411 }
1412 // updates the successors of the current basic block
1413 Edge e = l.successors;
1414 while(e != null)
1415 {
1416 Label n = e.successor.getFirst();
1417 boolean change = f.merge(cw, n.frame, e.info);
1418 if(change && n.next == null)
1419 {
1420 // if n has changed and is not already in the 'changed'
1421 // list, adds it to this list
1422 n.next = changed;
1423 changed = n;
1424 }
1425 e = e.next;
1426 }
1427 }
1428 this.maxStack = max;
1429
1430 // visits all the frames that must be stored in the stack map
1431 Label l = labels;
1432 while(l != null)
1433 {
1434 f = l.frame;
1435 if((l.status & Label.STORE) != 0)
1436 {
1437 visitFrame(f);
1438 }
1439 if((l.status & Label.REACHABLE) == 0)
1440 {
1441 // finds start and end of dead basic block
1442 Label k = l.successor;
1443 int start = l.position;
1444 int end = (k == null ? code.length : k.position) - 1;
1445 // if non empty basic block
1446 if(end >= start)
1447 {
1448 // replaces instructions with NOP ... NOP ATHROW
1449 for(int i = start; i < end; ++i)
1450 {
1451 code.data[i] = Opcodes.NOP;
1452 }
1453 code.data[end] = (byte) Opcodes.ATHROW;
1454 // emits a frame for this unreachable block
1455 startFrame(start, 0, 1);
1456 frame[frameIndex++] = Frame.OBJECT
1457 | cw.addType("java/lang/Throwable");
1458 endFrame();
1459 }
1460 }
1461 l = l.successor;
1462 }
1463 }
1464 else if(compute == MAXS)
1465 {
1466 // completes the control flow graph with exception handler blocks
1467 Handler handler = firstHandler;
1468 while(handler != null)
1469 {
1470 Label l = handler.start;
1471 Label h = handler.handler;
1472 Label e = handler.end;
1473 // adds 'h' as a successor of labels between 'start' and 'end'
1474 while(l != e)
1475 {
1476 // creates an edge to 'h'
1477 Edge b = new Edge();
1478 b.info = Edge.EXCEPTION;
1479 b.successor = h;
1480 // adds it to the successors of 'l'
1481 if((l.status & Label.JSR) != 0)
1482 {
1483 // if l is a JSR block, adds b after the first two edges
1484 // to preserve the hypothesis about JSR block successors
1485 // order (see {@link #visitJumpInsn})
1486 b.next = l.successors.next.next;
1487 l.successors.next.next = b;
1488 }
1489 else
1490 {
1491 b.next = l.successors;
1492 l.successors = b;
1493 }
1494 // goes to the next label
1495 l = l.successor;
1496 }
1497 handler = handler.next;
1498 }
1499
1500 if(jsr)
1501 {
1502 // completes the control flow graph with the RET successors
1503 /*
1504 * first step: finds the subroutines. This step determines, for
1505 * each basic block, to which subroutine(s) it belongs, and
1506 * stores this set as a bit set in the {@link Label#status}
1507 * field. Subroutines are numbered with powers of two, from
1508 * 0x1000 to 0x80000000 (so there must be at most 20 subroutines
1509 * in a method).
1510 */
1511 // finds the basic blocks that belong to the "main" subroutine
1512 int id = 0x1000;
1513 findSubroutine(labels, id);
1514 // finds the basic blocks that belong to the real subroutines
1515 Label l = labels;
1516 while(l != null)
1517 {
1518 if((l.status & Label.JSR) != 0)
1519 {
1520 // the subroutine is defined by l's TARGET, not by l
1521 Label subroutine = l.successors.next.successor;
1522 // if this subroutine does not have an id yet...
1523 if((subroutine.status & ~0xFFF) == 0)
1524 {
1525 // ...assigns it a new id and finds its basic blocks
1526 id = id << 1;
1527 findSubroutine(subroutine, id);
1528 }
1529 }
1530 l = l.successor;
1531 }
1532 // second step: finds the successors of RET blocks
1533 findSubroutineSuccessors(0x1000, new Label[10], 0);
1534 }
1535
1536 /*
1537 * control flow analysis algorithm: while the block stack is not
1538 * empty, pop a block from this stack, update the max stack size,
1539 * compute the true (non relative) begin stack size of the
1540 * successors of this block, and push these successors onto the
1541 * stack (unless they have already been pushed onto the stack).
1542 * Note: by hypothesis, the {@link Label#inputStackTop} of the
1543 * blocks in the block stack are the true (non relative) beginning
1544 * stack sizes of these blocks.
1545 */
1546 int max = 0;
1547 Label stack = labels;
1548 while(stack != null)
1549 {
1550 // pops a block from the stack
1551 Label l = stack;
1552 stack = stack.next;
1553 // computes the true (non relative) max stack size of this block
1554 int start = l.inputStackTop;
1555 int blockMax = start + l.outputStackMax;
1556 // updates the global max stack size
1557 if(blockMax > max)
1558 {
1559 max = blockMax;
1560 }
1561 // analyses the successors of the block
1562 Edge b = l.successors;
1563 if((l.status & Label.JSR) != 0)
1564 {
1565 // ignores the first edge of JSR blocks (virtual successor)
1566 b = b.next;
1567 }
1568 while(b != null)
1569 {
1570 l = b.successor;
1571 // if this successor has not already been pushed...
1572 if((l.status & Label.PUSHED) == 0)
1573 {
1574 // computes its true beginning stack size...
1575 l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start
1576 + b.info;
1577 // ...and pushes it onto the stack
1578 l.status |= Label.PUSHED;
1579 l.next = stack;
1580 stack = l;
1581 }
1582 b = b.next;
1583 }
1584 }
1585 this.maxStack = max;
1586 }
1587 else
1588 {
1589 this.maxStack = maxStack;
1590 this.maxLocals = maxLocals;
1591 }
1592 }
1593
1594 public void visitEnd(){
1595 }
1596
1597 // ------------------------------------------------------------------------
1598 // Utility methods: control flow analysis algorithm
1599 // ------------------------------------------------------------------------
1600
1601 /**
1602 * Computes the size of the arguments and of the return value of a method.
1603 *
1604 * @param desc the descriptor of a method.
1605 * @return the size of the arguments of the method (plus one for the
1606 * implicit this argument), argSize, and the size of its return
1607 * value, retSize, packed into a single int i =
1608 * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal
1609 * to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
1610 */
1611 static int getArgumentsAndReturnSizes(final String desc){
1612 int n = 1;
1613 int c = 1;
1614 while(true)
1615 {
1616 char car = desc.charAt(c++);
1617 if(car == ')')
1618 {
1619 car = desc.charAt(c);
1620 return n << 2
1621 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
1622 }
1623 else if(car == 'L')
1624 {
1625 while(desc.charAt(c++) != ';')
1626 {
1627 }
1628 n += 1;
1629 }
1630 else if(car == '[')
1631 {
1632 while((car = desc.charAt(c)) == '[')
1633 {
1634 ++c;
1635 }
1636 if(car == 'D' || car == 'J')
1637 {
1638 n -= 1;
1639 }
1640 }
1641 else if(car == 'D' || car == 'J')
1642 {
1643 n += 2;
1644 }
1645 else
1646 {
1647 n += 1;
1648 }
1649 }
1650 }
1651
1652 /**
1653 * Adds a successor to the {@link #currentBlock currentBlock} block.
1654 *
1655 * @param info information about the control flow edge to be added.
1656 * @param successor the successor block to be added to the current block.
1657 */
1658 private void addSuccessor(final int info, final Label successor){
1659 // creates and initializes an Edge object...
1660 Edge b = new Edge();
1661 b.info = info;
1662 b.successor = successor;
1663 // ...and adds it to the successor list of the currentBlock block
1664 b.next = currentBlock.successors;
1665 currentBlock.successors = b;
1666 }
1667
1668 /**
1669 * Ends the current basic block. This method must be used in the case where
1670 * the current basic block does not have any successor.
1671 */
1672 private void noSuccessor(){
1673 if(compute == FRAMES)
1674 {
1675 Label l = new Label();
1676 l.frame = new Frame();
1677 l.frame.owner = l;
1678 l.resolve(this, code.length, code.data);
1679 previousBlock.successor = l;
1680 previousBlock = l;
1681 }
1682 else
1683 {
1684 currentBlock.outputStackMax = maxStackSize;
1685 }
1686 currentBlock = null;
1687 }
1688
1689 /**
1690 * Finds the basic blocks that belong to a given subroutine, and marks these
1691 * blocks as belonging to this subroutine (by using {@link Label#status} as
1692 * a bit set (see {@link #visitMaxs}). This recursive method follows the
1693 * control flow graph to find all the blocks that are reachable from the
1694 * given block WITHOUT following any JSR target.
1695 *
1696 * @param block a block that belongs to the subroutine
1697 * @param id the id of this subroutine
1698 */
1699 private void findSubroutine(final Label block, final int id){
1700 // if 'block' is already marked as belonging to subroutine 'id', returns
1701 if((block.status & id) != 0)
1702 {
1703 return;
1704 }
1705 // marks 'block' as belonging to subroutine 'id'
1706 block.status |= id;
1707 // calls this method recursively on each successor, except JSR targets
1708 Edge e = block.successors;
1709 while(e != null)
1710 {
1711 // if 'block' is a JSR block, then 'block.successors.next' leads
1712 // to the JSR target (see {@link #visitJumpInsn}) and must therefore
1713 // not be followed
1714 if((block.status & Label.JSR) == 0 || e != block.successors.next)
1715 {
1716 findSubroutine(e.successor, id);
1717 }
1718 e = e.next;
1719 }
1720 }
1721
1722 /**
1723 * Finds the successors of the RET blocks of the specified subroutine, and
1724 * of any nested subroutine it calls.
1725 *
1726 * @param id id of the subroutine whose RET block successors must be found.
1727 * @param JSRs the JSR blocks that were followed to reach this subroutine.
1728 * @param nJSRs number of JSR blocks in the JSRs array.
1729 */
1730 private void findSubroutineSuccessors(
1731 final int id,
1732 final Label[] JSRs,
1733 final int nJSRs){
1734 // iterates over all the basic blocks...
1735 Label l = labels;
1736 while(l != null)
1737 {
1738 // for those that belong to subroutine 'id'...
1739 if((l.status & id) != 0)
1740 {
1741 if((l.status & Label.JSR) != 0)
1742 {
1743 // finds the subroutine to which 'l' leads by following the
1744 // second edge of l.successors (see {@link #visitJumpInsn})
1745 int nId = l.successors.next.successor.status & ~0xFFF;
1746 if(nId != id)
1747 {
1748 // calls this method recursively with l pushed onto the
1749 // JSRs stack to find the successors of the RET blocks
1750 // of this nested subroutine 'nId'
1751 JSRs[nJSRs] = l;
1752 findSubroutineSuccessors(nId, JSRs, nJSRs + 1);
1753 }
1754 }
1755 else if((l.status & Label.RET) != 0)
1756 {
1757 /*
1758 * finds the JSR block in the JSRs stack that corresponds to
1759 * this RET block, and updates the successors of this RET
1760 * block accordingly. This corresponding JSR is the one that
1761 * leads to the subroutine to which the RET block belongs.
1762 * But the RET block can belong to several subroutines (if a
1763 * nested subroutine returns to its parent subroutine
1764 * implicitely, without a RET). So, in fact, the JSR that
1765 * corresponds to this RET is the first block in the JSRs
1766 * stack, starting from the bottom of the stack, that leads
1767 * to a subroutine to which the RET block belongs.
1768 */
1769 for(int i = 0; i < nJSRs; ++i)
1770 {
1771 int JSRstatus = JSRs[i].successors.next.successor.status;
1772 if(((JSRstatus & ~0xFFF) & (l.status & ~0xFFF)) != 0)
1773 {
1774 Edge e = new Edge();
1775 e.info = l.inputStackTop;
1776 e.successor = JSRs[i].successors.successor;
1777 e.next = l.successors;
1778 l.successors = e;
1779 break;
1780 }
1781 }
1782 }
1783 }
1784 l = l.successor;
1785 }
1786 }
1787
1788 // ------------------------------------------------------------------------
1789 // Utility methods: stack map frames
1790 // ------------------------------------------------------------------------
1791
1792 /**
1793 * Visits a frame that has been computed from scratch.
1794 *
1795 * @param f the frame that must be visited.
1796 */
1797 private void visitFrame(final Frame f){
1798 int i, t;
1799 int nTop = 0;
1800 int nLocal = 0;
1801 int nStack = 0;
1802 int[] locals = f.inputLocals;
1803 int[] stacks = f.inputStack;
1804 // computes the number of locals (ignores TOP types that are just after
1805 // a LONG or a DOUBLE, and all trailing TOP types)
1806 for(i = 0; i < locals.length; ++i)
1807 {
1808 t = locals[i];
1809 if(t == Frame.TOP)
1810 {
1811 ++nTop;
1812 }
1813 else
1814 {
1815 nLocal += nTop + 1;
1816 nTop = 0;
1817 }
1818 if(t == Frame.LONG || t == Frame.DOUBLE)
1819 {
1820 ++i;
1821 }
1822 }
1823 // computes the stack size (ignores TOP types that are just after
1824 // a LONG or a DOUBLE)
1825 for(i = 0; i < stacks.length; ++i)
1826 {
1827 t = stacks[i];
1828 ++nStack;
1829 if(t == Frame.LONG || t == Frame.DOUBLE)
1830 {
1831 ++i;
1832 }
1833 }
1834 // visits the frame and its content
1835 startFrame(f.owner.position, nLocal, nStack);
1836 for(i = 0; nLocal > 0; ++i, --nLocal)
1837 {
1838 t = locals[i];
1839 frame[frameIndex++] = t;
1840 if(t == Frame.LONG || t == Frame.DOUBLE)
1841 {
1842 ++i;
1843 }
1844 }
1845 for(i = 0; i < stacks.length; ++i)
1846 {
1847 t = stacks[i];
1848 frame[frameIndex++] = t;
1849 if(t == Frame.LONG || t == Frame.DOUBLE)
1850 {
1851 ++i;
1852 }
1853 }
1854 endFrame();
1855 }
1856
1857 /**
1858 * Starts the visit of a stack map frame.
1859 *
1860 * @param offset the offset of the instruction to which the frame
1861 * corresponds.
1862 * @param nLocal the number of local variables in the frame.
1863 * @param nStack the number of stack elements in the frame.
1864 */
1865 private void startFrame(final int offset, final int nLocal, final int nStack){
1866 int n = 3 + nLocal + nStack;
1867 if(frame == null || frame.length < n)
1868 {
1869 frame = new int[n];
1870 }
1871 frame[0] = offset;
1872 frame[1] = nLocal;
1873 frame[2] = nStack;
1874 frameIndex = 3;
1875 }
1876
1877 /**
1878 * Checks if the visit of the current frame {@link #frame} is finished, and
1879 * if yes, write it in the StackMapTable attribute.
1880 */
1881 private void endFrame(){
1882 if(previousFrame != null)
1883 { // do not write the first frame
1884 if(stackMap == null)
1885 {
1886 stackMap = new ByteVector();
1887 }
1888 writeFrame();
1889 ++frameCount;
1890 }
1891 previousFrame = frame;
1892 frame = null;
1893 }
1894
1895 /**
1896 * Compress and writes the current frame {@link #frame} in the StackMapTable
1897 * attribute.
1898 */
1899 private void writeFrame(){
1900 int clocalsSize = frame[1];
1901 int cstackSize = frame[2];
1902 if((cw.version & 0xFFFF) < Opcodes.V1_6)
1903 {
1904 stackMap.putShort(frame[0]).putShort(clocalsSize);
1905 writeFrameTypes(3, 3 + clocalsSize);
1906 stackMap.putShort(cstackSize);
1907 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
1908 return;
1909 }
1910 int localsSize = previousFrame[1];
1911 int type = FULL_FRAME;
1912 int k = 0;
1913 int delta;
1914 if(frameCount == 0)
1915 {
1916 delta = frame[0];
1917 }
1918 else
1919 {
1920 delta = frame[0] - previousFrame[0] - 1;
1921 }
1922 if(cstackSize == 0)
1923 {
1924 k = clocalsSize - localsSize;
1925 switch(k)
1926 {
1927 case-3:
1928 case-2:
1929 case-1:
1930 type = CHOP_FRAME;
1931 localsSize = clocalsSize;
1932 break;
1933 case 0:
1934 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
1935 break;
1936 case 1:
1937 case 2:
1938 case 3:
1939 type = APPEND_FRAME;
1940 break;
1941 }
1942 }
1943 else if(clocalsSize == localsSize && cstackSize == 1)
1944 {
1945 type = delta < 63
1946 ? SAME_LOCALS_1_STACK_ITEM_FRAME
1947 : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
1948 }
1949 if(type != FULL_FRAME)
1950 {
1951 // verify if locals are the same
1952 int l = 3;
1953 for(int j = 0; j < localsSize; j++)
1954 {
1955 if(frame[l] != previousFrame[l])
1956 {
1957 type = FULL_FRAME;
1958 break;
1959 }
1960 l++;
1961 }
1962 }
1963 switch(type)
1964 {
1965 case SAME_FRAME:
1966 stackMap.putByte(delta);
1967 break;
1968 case SAME_LOCALS_1_STACK_ITEM_FRAME:
1969 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
1970 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1971 break;
1972 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
1973 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
1974 .putShort(delta);
1975 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1976 break;
1977 case SAME_FRAME_EXTENDED:
1978 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
1979 break;
1980 case CHOP_FRAME:
1981 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1982 break;
1983 case APPEND_FRAME:
1984 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1985 writeFrameTypes(3 + localsSize, 3 + clocalsSize);
1986 break;
1987 // case FULL_FRAME:
1988 default:
1989 stackMap.putByte(FULL_FRAME)
1990 .putShort(delta)
1991 .putShort(clocalsSize);
1992 writeFrameTypes(3, 3 + clocalsSize);
1993 stackMap.putShort(cstackSize);
1994 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
1995 }
1996 }
1997
1998 /**
1999 * Writes some types of the current frame {@link #frame} into the
2000 * StackMapTableAttribute. This method converts types from the format used
2001 * in {@link Label} to the format used in StackMapTable attributes. In
2002 * particular, it converts type table indexes to constant pool indexes.
2003 *
2004 * @param start index of the first type in {@link #frame} to write.
2005 * @param end index of last type in {@link #frame} to write (exclusive).
2006 */
2007 private void writeFrameTypes(final int start, final int end){
2008 for(int i = start; i < end; ++i)
2009 {
2010 int t = frame[i];
2011 int d = t & Frame.DIM;
2012 if(d == 0)
2013 {
2014 int v = t & Frame.BASE_VALUE;
2015 switch(t & Frame.BASE_KIND)
2016 {
2017 case Frame.OBJECT:
2018 stackMap.putByte(7)
2019 .putShort(cw.newClass(cw.typeTable[v].strVal1));
2020 break;
2021 case Frame.UNINITIALIZED:
2022 stackMap.putByte(8).putShort(cw.typeTable[v].intVal);
2023 break;
2024 default:
2025 stackMap.putByte(v);
2026 }
2027 }
2028 else
2029 {
2030 StringBuffer buf = new StringBuffer();
2031 d >>= 28;
2032 while(d-- > 0)
2033 {
2034 buf.append('[');
2035 }
2036 if((t & Frame.BASE_KIND) == Frame.OBJECT)
2037 {
2038 buf.append('L');
2039 buf.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1);
2040 buf.append(';');
2041 }
2042 else
2043 {
2044 switch(t & 0xF)
2045 {
2046 case 1:
2047 buf.append('I');
2048 break;
2049 case 2:
2050 buf.append('F');
2051 break;
2052 case 3:
2053 buf.append('D');
2054 break;
2055 case 9:
2056 buf.append('Z');
2057 break;
2058 case 10:
2059 buf.append('B');
2060 break;
2061 case 11:
2062 buf.append('C');
2063 break;
2064 case 12:
2065 buf.append('S');
2066 break;
2067 default:
2068 buf.append('J');
2069 }
2070 }
2071 stackMap.putByte(7).putShort(cw.newClass(buf.toString()));
2072 }
2073 }
2074 }
2075
2076 private void writeFrameType(final Object type){
2077 if(type instanceof String)
2078 {
2079 stackMap.putByte(7).putShort(cw.newClass((String) type));
2080 }
2081 else if(type instanceof Integer)
2082 {
2083 stackMap.putByte(((Integer) type).intValue());
2084 }
2085 else
2086 {
2087 stackMap.putByte(8).putShort(((Label) type).position);
2088 }
2089 }
2090
2091 // ------------------------------------------------------------------------
2092 // Utility methods: dump bytecode array
2093 // ------------------------------------------------------------------------
2094
2095 /**
2096 * Returns the size of the bytecode of this method.
2097 *
2098 * @return the size of the bytecode of this method.
2099 */
2100 final int getSize(){
2101 if(classReaderOffset != 0)
2102 {
2103 return 6 + classReaderLength;
2104 }
2105 if(resize)
2106 {
2107 // replaces the temporary jump opcodes introduced by Label.resolve.
2108 resizeInstructions();
2109 }
2110 int size = 8;
2111 if(code.length > 0)
2112 {
2113 cw.newUTF8("Code");
2114 size += 18 + code.length + 8 * handlerCount;
2115 if(localVar != null)
2116 {
2117 cw.newUTF8("LocalVariableTable");
2118 size += 8 + localVar.length;
2119 }
2120 if(localVarType != null)
2121 {
2122 cw.newUTF8("LocalVariableTypeTable");
2123 size += 8 + localVarType.length;
2124 }
2125 if(lineNumber != null)
2126 {
2127 cw.newUTF8("LineNumberTable");
2128 size += 8 + lineNumber.length;
2129 }
2130 if(stackMap != null)
2131 {
2132 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2133 cw.newUTF8(zip ? "StackMapTable" : "StackMap");
2134 size += 8 + stackMap.length;
2135 }
2136 if(cattrs != null)
2137 {
2138 size += cattrs.getSize(cw,
2139 code.data,
2140 code.length,
2141 maxStack,
2142 maxLocals);
2143 }
2144 }
2145 if(exceptionCount > 0)
2146 {
2147 cw.newUTF8("Exceptions");
2148 size += 8 + 2 * exceptionCount;
2149 }
2150 if((access & Opcodes.ACC_SYNTHETIC) != 0
2151 && (cw.version & 0xffff) < Opcodes.V1_5)
2152 {
2153 cw.newUTF8("Synthetic");
2154 size += 6;
2155 }
2156 if((access & Opcodes.ACC_DEPRECATED) != 0)
2157 {
2158 cw.newUTF8("Deprecated");
2159 size += 6;
2160 }
2161 if(signature != null)
2162 {
2163 cw.newUTF8("Signature");
2164 cw.newUTF8(signature);
2165 size += 8;
2166 }
2167 if(annd != null)
2168 {
2169 cw.newUTF8("AnnotationDefault");
2170 size += 6 + annd.length;
2171 }
2172 if(anns != null)
2173 {
2174 cw.newUTF8("RuntimeVisibleAnnotations");
2175 size += 8 + anns.getSize();
2176 }
2177 if(ianns != null)
2178 {
2179 cw.newUTF8("RuntimeInvisibleAnnotations");
2180 size += 8 + ianns.getSize();
2181 }
2182 if(panns != null)
2183 {
2184 cw.newUTF8("RuntimeVisibleParameterAnnotations");
2185 size += 7 + 2 * panns.length;
2186 for(int i = panns.length - 1; i >= 0; --i)
2187 {
2188 size += panns[i] == null ? 0 : panns[i].getSize();
2189 }
2190 }
2191 if(ipanns != null)
2192 {
2193 cw.newUTF8("RuntimeInvisibleParameterAnnotations");
2194 size += 7 + 2 * ipanns.length;
2195 for(int i = ipanns.length - 1; i >= 0; --i)
2196 {
2197 size += ipanns[i] == null ? 0 : ipanns[i].getSize();
2198 }
2199 }
2200 if(attrs != null)
2201 {
2202 size += attrs.getSize(cw, null, 0, -1, -1);
2203 }
2204 return size;
2205 }
2206
2207 /**
2208 * Puts the bytecode of this method in the given byte vector.
2209 *
2210 * @param out the byte vector into which the bytecode of this method must be
2211 * copied.
2212 */
2213 final void put(final ByteVector out){
2214 out.putShort(access).putShort(name).putShort(desc);
2215 if(classReaderOffset != 0)
2216 {
2217 out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
2218 return;
2219 }
2220 int attributeCount = 0;
2221 if(code.length > 0)
2222 {
2223 ++attributeCount;
2224 }
2225 if(exceptionCount > 0)
2226 {
2227 ++attributeCount;
2228 }
2229 if((access & Opcodes.ACC_SYNTHETIC) != 0
2230 && (cw.version & 0xffff) < Opcodes.V1_5)
2231 {
2232 ++attributeCount;
2233 }
2234 if((access & Opcodes.ACC_DEPRECATED) != 0)
2235 {
2236 ++attributeCount;
2237 }
2238 if(signature != null)
2239 {
2240 ++attributeCount;
2241 }
2242 if(annd != null)
2243 {
2244 ++attributeCount;
2245 }
2246 if(anns != null)
2247 {
2248 ++attributeCount;
2249 }
2250 if(ianns != null)
2251 {
2252 ++attributeCount;
2253 }
2254 if(panns != null)
2255 {
2256 ++attributeCount;
2257 }
2258 if(ipanns != null)
2259 {
2260 ++attributeCount;
2261 }
2262 if(attrs != null)
2263 {
2264 attributeCount += attrs.getCount();
2265 }
2266 out.putShort(attributeCount);
2267 if(code.length > 0)
2268 {
2269 int size = 12 + code.length + 8 * handlerCount;
2270 if(localVar != null)
2271 {
2272 size += 8 + localVar.length;
2273 }
2274 if(localVarType != null)
2275 {
2276 size += 8 + localVarType.length;
2277 }
2278 if(lineNumber != null)
2279 {
2280 size += 8 + lineNumber.length;
2281 }
2282 if(stackMap != null)
2283 {
2284 size += 8 + stackMap.length;
2285 }
2286 if(cattrs != null)
2287 {
2288 size += cattrs.getSize(cw,
2289 code.data,
2290 code.length,
2291 maxStack,
2292 maxLocals);
2293 }
2294 out.putShort(cw.newUTF8("Code")).putInt(size);
2295 out.putShort(maxStack).putShort(maxLocals);
2296 out.putInt(code.length).putByteArray(code.data, 0, code.length);
2297 out.putShort(handlerCount);
2298 if(handlerCount > 0)
2299 {
2300 Handler h = firstHandler;
2301 while(h != null)
2302 {
2303 out.putShort(h.start.position)
2304 .putShort(h.end.position)
2305 .putShort(h.handler.position)
2306 .putShort(h.type);
2307 h = h.next;
2308 }
2309 }
2310 attributeCount = 0;
2311 if(localVar != null)
2312 {
2313 ++attributeCount;
2314 }
2315 if(localVarType != null)
2316 {
2317 ++attributeCount;
2318 }
2319 if(lineNumber != null)
2320 {
2321 ++attributeCount;
2322 }
2323 if(stackMap != null)
2324 {
2325 ++attributeCount;
2326 }
2327 if(cattrs != null)
2328 {
2329 attributeCount += cattrs.getCount();
2330 }
2331 out.putShort(attributeCount);
2332 if(localVar != null)
2333 {
2334 out.putShort(cw.newUTF8("LocalVariableTable"));
2335 out.putInt(localVar.length + 2).putShort(localVarCount);
2336 out.putByteArray(localVar.data, 0, localVar.length);
2337 }
2338 if(localVarType != null)
2339 {
2340 out.putShort(cw.newUTF8("LocalVariableTypeTable"));
2341 out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
2342 out.putByteArray(localVarType.data, 0, localVarType.length);
2343 }
2344 if(lineNumber != null)
2345 {
2346 out.putShort(cw.newUTF8("LineNumberTable"));
2347 out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
2348 out.putByteArray(lineNumber.data, 0, lineNumber.length);
2349 }
2350 if(stackMap != null)
2351 {
2352 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2353 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap"));
2354 out.putInt(stackMap.length + 2).putShort(frameCount);
2355 out.putByteArray(stackMap.data, 0, stackMap.length);
2356 }
2357 if(cattrs != null)
2358 {
2359 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
2360 }
2361 }
2362 if(exceptionCount > 0)
2363 {
2364 out.putShort(cw.newUTF8("Exceptions"))
2365 .putInt(2 * exceptionCount + 2);
2366 out.putShort(exceptionCount);
2367 for(int i = 0; i < exceptionCount; ++i)
2368 {
2369 out.putShort(exceptions[i]);
2370 }
2371 }
2372 if((access & Opcodes.ACC_SYNTHETIC) != 0
2373 && (cw.version & 0xffff) < Opcodes.V1_5)
2374 {
2375 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
2376 }
2377 if((access & Opcodes.ACC_DEPRECATED) != 0)
2378 {
2379 out.putShort(cw.newUTF8("Deprecated")).putInt(0);
2380 }
2381 if(signature != null)
2382 {
2383 out.putShort(cw.newUTF8("Signature"))
2384 .putInt(2)
2385 .putShort(cw.newUTF8(signature));
2386 }
2387 if(annd != null)
2388 {
2389 out.putShort(cw.newUTF8("AnnotationDefault"));
2390 out.putInt(annd.length);
2391 out.putByteArray(annd.data, 0, annd.length);
2392 }
2393 if(anns != null)
2394 {
2395 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
2396 anns.put(out);
2397 }
2398 if(ianns != null)
2399 {
2400 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
2401 ianns.put(out);
2402 }
2403 if(panns != null)
2404 {
2405 out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
2406 AnnotationWriter.put(panns, out);
2407 }
2408 if(ipanns != null)
2409 {
2410 out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
2411 AnnotationWriter.put(ipanns, out);
2412 }
2413 if(attrs != null)
2414 {
2415 attrs.put(cw, null, 0, -1, -1, out);
2416 }
2417 }
2418
2419 // ------------------------------------------------------------------------
2420 // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
2421 // ------------------------------------------------------------------------
2422
2423 /**
2424 * Resizes and replaces the temporary instructions inserted by
2425 * {@link Label#resolve} for wide forward jumps, while keeping jump offsets
2426 * and instruction addresses consistent. This may require to resize other
2427 * existing instructions, or even to introduce new instructions: for
2428 * example, increasing the size of an instruction by 2 at the middle of a
2429 * method can increases the offset of an IFEQ instruction from 32766 to
2430 * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
2431 * 32765. This, in turn, may require to increase the size of another jump
2432 * instruction, and so on... All these operations are handled automatically
2433 * by this method. <p> <i>This method must be called after all the method
2434 * that is being built has been visited</i>. In particular, the
2435 * {@link Label Label} objects used to construct the method are no longer
2436 * valid after this method has been called.
2437 */
2438 private void resizeInstructions(){
2439 byte[] b = code.data; // bytecode of the method
2440 int u, v, label; // indexes in b
2441 int i, j; // loop indexes
2442 /*
2443 * 1st step: As explained above, resizing an instruction may require to
2444 * resize another one, which may require to resize yet another one, and
2445 * so on. The first step of the algorithm consists in finding all the
2446 * instructions that need to be resized, without modifying the code.
2447 * This is done by the following "fix point" algorithm:
2448 *
2449 * Parse the code to find the jump instructions whose offset will need
2450 * more than 2 bytes to be stored (the future offset is computed from
2451 * the current offset and from the number of bytes that will be inserted
2452 * or removed between the source and target instructions). For each such
2453 * instruction, adds an entry in (a copy of) the indexes and sizes
2454 * arrays (if this has not already been done in a previous iteration!).
2455 *
2456 * If at least one entry has been added during the previous step, go
2457 * back to the beginning, otherwise stop.
2458 *
2459 * In fact the real algorithm is complicated by the fact that the size
2460 * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
2461 * position in the bytecode (because of padding). In order to ensure the
2462 * convergence of the algorithm, the number of bytes to be added or
2463 * removed from these instructions is over estimated during the previous
2464 * loop, and computed exactly only after the loop is finished (this
2465 * requires another pass to parse the bytecode of the method).
2466 */
2467 int[] allIndexes = new int[0]; // copy of indexes
2468 int[] allSizes = new int[0]; // copy of sizes
2469 boolean[] resize; // instructions to be resized
2470 int newOffset; // future offset of a jump instruction
2471
2472 resize = new boolean[code.length];
2473
2474 // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
2475 int state = 3;
2476 do
2477 {
2478 if(state == 3)
2479 {
2480 state = 2;
2481 }
2482 u = 0;
2483 while(u < b.length)
2484 {
2485 int opcode = b[u] & 0xFF; // opcode of current instruction
2486 int insert = 0; // bytes to be added after this instruction
2487
2488 switch(ClassWriter.TYPE[opcode])
2489 {
2490 case ClassWriter.NOARG_INSN:
2491 case ClassWriter.IMPLVAR_INSN:
2492 u += 1;
2493 break;
2494 case ClassWriter.LABEL_INSN:
2495 if(opcode > 201)
2496 {
2497 // converts temporary opcodes 202 to 217, 218 and
2498 // 219 to IFEQ ... JSR (inclusive), IFNULL and
2499 // IFNONNULL
2500 opcode = opcode < 218 ? opcode - 49 : opcode - 20;
2501 label = u + readUnsignedShort(b, u + 1);
2502 }
2503 else
2504 {
2505 label = u + readShort(b, u + 1);
2506 }
2507 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2508 if(newOffset < Short.MIN_VALUE
2509 || newOffset > Short.MAX_VALUE)
2510 {
2511 if(!resize[u])
2512 {
2513 if(opcode == Opcodes.GOTO
2514 || opcode == Opcodes.JSR)
2515 {
2516 // two additional bytes will be required to
2517 // replace this GOTO or JSR instruction with
2518 // a GOTO_W or a JSR_W
2519 insert = 2;
2520 }
2521 else
2522 {
2523 // five additional bytes will be required to
2524 // replace this IFxxx <l> instruction with
2525 // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
2526 // is the "opposite" opcode of IFxxx (i.e.,
2527 // IFNE for IFEQ) and where <l'> designates
2528 // the instruction just after the GOTO_W.
2529 insert = 5;
2530 }
2531 resize[u] = true;
2532 }
2533 }
2534 u += 3;
2535 break;
2536 case ClassWriter.LABELW_INSN:
2537 u += 5;
2538 break;
2539 case ClassWriter.TABL_INSN:
2540 if(state == 1)
2541 {
2542 // true number of bytes to be added (or removed)
2543 // from this instruction = (future number of padding
2544 // bytes - current number of padding byte) -
2545 // previously over estimated variation =
2546 // = ((3 - newOffset%4) - (3 - u%4)) - u%4
2547 // = (-newOffset%4 + u%4) - u%4
2548 // = -(newOffset & 3)
2549 newOffset = getNewOffset(allIndexes, allSizes, 0, u);
2550 insert = -(newOffset & 3);
2551 }
2552 else if(!resize[u])
2553 {
2554 // over estimation of the number of bytes to be
2555 // added to this instruction = 3 - current number
2556 // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
2557 insert = u & 3;
2558 resize[u] = true;
2559 }
2560 // skips instruction
2561 u = u + 4 - (u & 3);
2562 u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
2563 break;
2564 case ClassWriter.LOOK_INSN:
2565 if(state == 1)
2566 {
2567 // like TABL_INSN
2568 newOffset = getNewOffset(allIndexes, allSizes, 0, u);
2569 insert = -(newOffset & 3);
2570 }
2571 else if(!resize[u])
2572 {
2573 // like TABL_INSN
2574 insert = u & 3;
2575 resize[u] = true;
2576 }
2577 // skips instruction
2578 u = u + 4 - (u & 3);
2579 u += 8 * readInt(b, u + 4) + 8;
2580 break;
2581 case ClassWriter.WIDE_INSN:
2582 opcode = b[u + 1] & 0xFF;
2583 if(opcode == Opcodes.IINC)
2584 {
2585 u += 6;
2586 }
2587 else
2588 {
2589 u += 4;
2590 }
2591 break;
2592 case ClassWriter.VAR_INSN:
2593 case ClassWriter.SBYTE_INSN:
2594 case ClassWriter.LDC_INSN:
2595 u += 2;
2596 break;
2597 case ClassWriter.SHORT_INSN:
2598 case ClassWriter.LDCW_INSN:
2599 case ClassWriter.FIELDORMETH_INSN:
2600 case ClassWriter.TYPE_INSN:
2601 case ClassWriter.IINC_INSN:
2602 u += 3;
2603 break;
2604 case ClassWriter.ITFMETH_INSN:
2605 u += 5;
2606 break;
2607 // case ClassWriter.MANA_INSN:
2608 default:
2609 u += 4;
2610 break;
2611 }
2612 if(insert != 0)
2613 {
2614 // adds a new (u, insert) entry in the allIndexes and
2615 // allSizes arrays
2616 int[] newIndexes = new int[allIndexes.length + 1];
2617 int[] newSizes = new int[allSizes.length + 1];
2618 System.arraycopy(allIndexes,
2619 0,
2620 newIndexes,
2621 0,
2622 allIndexes.length);
2623 System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
2624 newIndexes[allIndexes.length] = u;
2625 newSizes[allSizes.length] = insert;
2626 allIndexes = newIndexes;
2627 allSizes = newSizes;
2628 if(insert > 0)
2629 {
2630 state = 3;
2631 }
2632 }
2633 }
2634 if(state < 3)
2635 {
2636 --state;
2637 }
2638 } while(state != 0);
2639
2640 // 2nd step:
2641 // copies the bytecode of the method into a new bytevector, updates the
2642 // offsets, and inserts (or removes) bytes as requested.
2643
2644 ByteVector newCode = new ByteVector(code.length);
2645
2646 u = 0;
2647 while(u < code.length)
2648 {
2649 int opcode = b[u] & 0xFF;
2650 switch(ClassWriter.TYPE[opcode])
2651 {
2652 case ClassWriter.NOARG_INSN:
2653 case ClassWriter.IMPLVAR_INSN:
2654 newCode.putByte(opcode);
2655 u += 1;
2656 break;
2657 case ClassWriter.LABEL_INSN:
2658 if(opcode > 201)
2659 {
2660 // changes temporary opcodes 202 to 217 (inclusive), 218
2661 // and 219 to IFEQ ... JSR (inclusive), IFNULL and
2662 // IFNONNULL
2663 opcode = opcode < 218 ? opcode - 49 : opcode - 20;
2664 label = u + readUnsignedShort(b, u + 1);
2665 }
2666 else
2667 {
2668 label = u + readShort(b, u + 1);
2669 }
2670 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2671 if(resize[u])
2672 {
2673 // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
2674 // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
2675 // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
2676 // and where <l'> designates the instruction just after
2677 // the GOTO_W.
2678 if(opcode == Opcodes.GOTO)
2679 {
2680 newCode.putByte(200); // GOTO_W
2681 }
2682 else if(opcode == Opcodes.JSR)
2683 {
2684 newCode.putByte(201); // JSR_W
2685 }
2686 else
2687 {
2688 newCode.putByte(opcode <= 166
2689 ? ((opcode + 1) ^ 1) - 1
2690 : opcode ^ 1);
2691 newCode.putShort(8); // jump offset
2692 newCode.putByte(200); // GOTO_W
2693 // newOffset now computed from start of GOTO_W
2694 newOffset -= 3;
2695 }
2696 newCode.putInt(newOffset);
2697 }
2698 else
2699 {
2700 newCode.putByte(opcode);
2701 newCode.putShort(newOffset);
2702 }
2703 u += 3;
2704 break;
2705 case ClassWriter.LABELW_INSN:
2706 label = u + readInt(b, u + 1);
2707 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2708 newCode.putByte(opcode);
2709 newCode.putInt(newOffset);
2710 u += 5;
2711 break;
2712 case ClassWriter.TABL_INSN:
2713 // skips 0 to 3 padding bytes
2714 v = u;
2715 u = u + 4 - (v & 3);
2716 // reads and copies instruction
2717 newCode.putByte(Opcodes.TABLESWITCH);
2718 newCode.length += (4 - newCode.length % 4) % 4;
2719 label = v + readInt(b, u);
2720 u += 4;
2721 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2722 newCode.putInt(newOffset);
2723 j = readInt(b, u);
2724 u += 4;
2725 newCode.putInt(j);
2726 j = readInt(b, u) - j + 1;
2727 u += 4;
2728 newCode.putInt(readInt(b, u - 4));
2729 for(; j > 0; --j)
2730 {
2731 label = v + readInt(b, u);
2732 u += 4;
2733 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2734 newCode.putInt(newOffset);
2735 }
2736 break;
2737 case ClassWriter.LOOK_INSN:
2738 // skips 0 to 3 padding bytes
2739 v = u;
2740 u = u + 4 - (v & 3);
2741 // reads and copies instruction
2742 newCode.putByte(Opcodes.LOOKUPSWITCH);
2743 newCode.length += (4 - newCode.length % 4) % 4;
2744 label = v + readInt(b, u);
2745 u += 4;
2746 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2747 newCode.putInt(newOffset);
2748 j = readInt(b, u);
2749 u += 4;
2750 newCode.putInt(j);
2751 for(; j > 0; --j)
2752 {
2753 newCode.putInt(readInt(b, u));
2754 u += 4;
2755 label = v + readInt(b, u);
2756 u += 4;
2757 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2758 newCode.putInt(newOffset);
2759 }
2760 break;
2761 case ClassWriter.WIDE_INSN:
2762 opcode = b[u + 1] & 0xFF;
2763 if(opcode == Opcodes.IINC)
2764 {
2765 newCode.putByteArray(b, u, 6);
2766 u += 6;
2767 }
2768 else
2769 {
2770 newCode.putByteArray(b, u, 4);
2771 u += 4;
2772 }
2773 break;
2774 case ClassWriter.VAR_INSN:
2775 case ClassWriter.SBYTE_INSN:
2776 case ClassWriter.LDC_INSN:
2777 newCode.putByteArray(b, u, 2);
2778 u += 2;
2779 break;
2780 case ClassWriter.SHORT_INSN:
2781 case ClassWriter.LDCW_INSN:
2782 case ClassWriter.FIELDORMETH_INSN:
2783 case ClassWriter.TYPE_INSN:
2784 case ClassWriter.IINC_INSN:
2785 newCode.putByteArray(b, u, 3);
2786 u += 3;
2787 break;
2788 case ClassWriter.ITFMETH_INSN:
2789 newCode.putByteArray(b, u, 5);
2790 u += 5;
2791 break;
2792 // case MANA_INSN:
2793 default:
2794 newCode.putByteArray(b, u, 4);
2795 u += 4;
2796 break;
2797 }
2798 }
2799
2800 // recomputes the stack map frames
2801 if(frameCount > 0)
2802 {
2803 if(compute == FRAMES)
2804 {
2805 frameCount = 0;
2806 stackMap = null;
2807 previousFrame = null;
2808 frame = null;
2809 Frame f = new Frame();
2810 f.owner = labels;
2811 Type[] args = Type.getArgumentTypes(descriptor);
2812 f.initInputFrame(cw, access, args, maxLocals);
2813 visitFrame(f);
2814 Label l = labels;
2815 while(l != null)
2816 {
2817 /*
2818 * here we need the original label position. getNewOffset
2819 * must therefore never have been called for this label.
2820 */
2821 u = l.position - 3;
2822 if((l.status & Label.STORE) != 0 || (u >= 0 && resize[u]))
2823 {
2824 getNewOffset(allIndexes, allSizes, l);
2825 // TODO update offsets in UNINITIALIZED values
2826 visitFrame(l.frame);
2827 }
2828 l = l.successor;
2829 }
2830 }
2831 else
2832 {
2833 /*
2834 * Resizing an existing stack map frame table is really hard.
2835 * Not only the table must be parsed to update the offets, but
2836 * new frames may be needed for jump instructions that were
2837 * inserted by this method. And updating the offsets or
2838 * inserting frames can change the format of the following
2839 * frames, in case of packed frames. In practice the whole table
2840 * must be recomputed. For this the frames are marked as
2841 * potentially invalid. This will cause the whole class to be
2842 * reread and rewritten with the COMPUTE_FRAMES option (see the
2843 * ClassWriter.toByteArray method). This is not very efficient
2844 * but is much easier and requires much less code than any other
2845 * method I can think of.
2846 */
2847 cw.invalidFrames = true;
2848 }
2849 }
2850 // updates the exception handler block labels
2851 Handler h = firstHandler;
2852 while(h != null)
2853 {
2854 getNewOffset(allIndexes, allSizes, h.start);
2855 getNewOffset(allIndexes, allSizes, h.end);
2856 getNewOffset(allIndexes, allSizes, h.handler);
2857 h = h.next;
2858 }
2859 // updates the instructions addresses in the
2860 // local var and line number tables
2861 for(i = 0; i < 2; ++i)
2862 {
2863 ByteVector bv = i == 0 ? localVar : localVarType;
2864 if(bv != null)
2865 {
2866 b = bv.data;
2867 u = 0;
2868 while(u < bv.length)
2869 {
2870 label = readUnsignedShort(b, u);
2871 newOffset = getNewOffset(allIndexes, allSizes, 0, label);
2872 writeShort(b, u, newOffset);
2873 label += readUnsignedShort(b, u + 2);
2874 newOffset = getNewOffset(allIndexes, allSizes, 0, label)
2875 - newOffset;
2876 writeShort(b, u + 2, newOffset);
2877 u += 10;
2878 }
2879 }
2880 }
2881 if(lineNumber != null)
2882 {
2883 b = lineNumber.data;
2884 u = 0;
2885 while(u < lineNumber.length)
2886 {
2887 writeShort(b, u, getNewOffset(allIndexes,
2888 allSizes,
2889 0,
2890 readUnsignedShort(b, u)));
2891 u += 4;
2892 }
2893 }
2894 // updates the labels of the other attributes
2895 Attribute attr = cattrs;
2896 while(attr != null)
2897 {
2898 Label[] labels = attr.getLabels();
2899 if(labels != null)
2900 {
2901 for(i = labels.length - 1; i >= 0; --i)
2902 {
2903 getNewOffset(allIndexes, allSizes, labels[i]);
2904 }
2905 }
2906 attr = attr.next;
2907 }
2908
2909 // replaces old bytecodes with new ones
2910 code = newCode;
2911 }
2912
2913 /**
2914 * Reads an unsigned short value in the given byte array.
2915 *
2916 * @param b a byte array.
2917 * @param index the start index of the value to be read.
2918 * @return the read value.
2919 */
2920 static int readUnsignedShort(final byte[] b, final int index){
2921 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
2922 }
2923
2924 /**
2925 * Reads a signed short value in the given byte array.
2926 *
2927 * @param b a byte array.
2928 * @param index the start index of the value to be read.
2929 * @return the read value.
2930 */
2931 static short readShort(final byte[] b, final int index){
2932 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
2933 }
2934
2935 /**
2936 * Reads a signed int value in the given byte array.
2937 *
2938 * @param b a byte array.
2939 * @param index the start index of the value to be read.
2940 * @return the read value.
2941 */
2942 static int readInt(final byte[] b, final int index){
2943 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
2944 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
2945 }
2946
2947 /**
2948 * Writes a short value in the given byte array.
2949 *
2950 * @param b a byte array.
2951 * @param index where the first byte of the short value must be written.
2952 * @param s the value to be written in the given byte array.
2953 */
2954 static void writeShort(final byte[] b, final int index, final int s){
2955 b[index] = (byte) (s >>> 8);
2956 b[index + 1] = (byte) s;
2957 }
2958
2959 /**
2960 * Computes the future value of a bytecode offset. <p> Note: it is possible
2961 * to have several entries for the same instruction in the <tt>indexes</tt>
2962 * and <tt>sizes</tt>: two entries (index=a,size=b) and (index=a,size=b')
2963 * are equivalent to a single entry (index=a,size=b+b').
2964 *
2965 * @param indexes current positions of the instructions to be resized. Each
2966 * instruction must be designated by the index of its <i>last</i>
2967 * byte, plus one (or, in other words, by the index of the <i>first</i>
2968 * byte of the <i>next</i> instruction).
2969 * @param sizes the number of bytes to be <i>added</i> to the above
2970 * instructions. More precisely, for each i < <tt>len</tt>,
2971 * <tt>sizes</tt>[i] bytes will be added at the end of the
2972 * instruction designated by <tt>indexes</tt>[i] or, if
2973 * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
2974 * bytes of the instruction will be removed (the instruction size
2975 * <i>must not</i> become negative or null).
2976 * @param begin index of the first byte of the source instruction.
2977 * @param end index of the first byte of the target instruction.
2978 * @return the future value of the given bytecode offset.
2979 */
2980 static int getNewOffset(
2981 final int[] indexes,
2982 final int[] sizes,
2983 final int begin,
2984 final int end){
2985 int offset = end - begin;
2986 for(int i = 0; i < indexes.length; ++i)
2987 {
2988 if(begin < indexes[i] && indexes[i] <= end)
2989 {
2990 // forward jump
2991 offset += sizes[i];
2992 }
2993 else if(end < indexes[i] && indexes[i] <= begin)
2994 {
2995 // backward jump
2996 offset -= sizes[i];
2997 }
2998 }
2999 return offset;
3000 }
3001
3002 /**
3003 * Updates the offset of the given label.
3004 *
3005 * @param indexes current positions of the instructions to be resized. Each
3006 * instruction must be designated by the index of its <i>last</i>
3007 * byte, plus one (or, in other words, by the index of the <i>first</i>
3008 * byte of the <i>next</i> instruction).
3009 * @param sizes the number of bytes to be <i>added</i> to the above
3010 * instructions. More precisely, for each i < <tt>len</tt>,
3011 * <tt>sizes</tt>[i] bytes will be added at the end of the
3012 * instruction designated by <tt>indexes</tt>[i] or, if
3013 * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
3014 * bytes of the instruction will be removed (the instruction size
3015 * <i>must not</i> become negative or null).
3016 * @param label the label whose offset must be updated.
3017 */
3018 static void getNewOffset(
3019 final int[] indexes,
3020 final int[] sizes,
3021 final Label label){
3022 if((label.status & Label.RESIZED) == 0)
3023 {
3024 label.position = getNewOffset(indexes, sizes, 0, label.position);
3025 label.status |= Label.RESIZED;
3026 }
3027 }
3028 }
+0
-341
src/jvm/clojure/asm/Opcodes.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 /**
32 * Defines the JVM opcodes, access flags and array type codes. This interface
33 * does not define all the JVM opcodes because some opcodes are automatically
34 * handled. For example, the xLOAD and xSTORE opcodes are automatically replaced
35 * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n
36 * opcodes are therefore not defined in this interface. Likewise for LDC,
37 * automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and
38 * JSR_W.
39 *
40 * @author Eric Bruneton
41 * @author Eugene Kuleshov
42 */
43 public interface Opcodes{
44
45 // versions
46
47 int V1_1 = 3 << 16 | 45;
48 int V1_2 = 0 << 16 | 46;
49 int V1_3 = 0 << 16 | 47;
50 int V1_4 = 0 << 16 | 48;
51 int V1_5 = 0 << 16 | 49;
52 int V1_6 = 0 << 16 | 50;
53
54 // access flags
55
56 int ACC_PUBLIC = 0x0001; // class, field, method
57 int ACC_PRIVATE = 0x0002; // class, field, method
58 int ACC_PROTECTED = 0x0004; // class, field, method
59 int ACC_STATIC = 0x0008; // field, method
60 int ACC_FINAL = 0x0010; // class, field, method
61 int ACC_SUPER = 0x0020; // class
62 int ACC_SYNCHRONIZED = 0x0020; // method
63 int ACC_VOLATILE = 0x0040; // field
64 int ACC_BRIDGE = 0x0040; // method
65 int ACC_VARARGS = 0x0080; // method
66 int ACC_TRANSIENT = 0x0080; // field
67 int ACC_NATIVE = 0x0100; // method
68 int ACC_INTERFACE = 0x0200; // class
69 int ACC_ABSTRACT = 0x0400; // class, method
70 int ACC_STRICT = 0x0800; // method
71 int ACC_SYNTHETIC = 0x1000; // class, field, method
72 int ACC_ANNOTATION = 0x2000; // class
73 int ACC_ENUM = 0x4000; // class(?) field inner
74
75 // ASM specific pseudo access flags
76
77 int ACC_DEPRECATED = 131072; // class, field, method
78
79 // types for NEWARRAY
80
81 int T_BOOLEAN = 4;
82 int T_CHAR = 5;
83 int T_FLOAT = 6;
84 int T_DOUBLE = 7;
85 int T_BYTE = 8;
86 int T_SHORT = 9;
87 int T_INT = 10;
88 int T_LONG = 11;
89
90 // stack map frame types
91
92 /**
93 * Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}.
94 */
95 int F_NEW = -1;
96
97 /**
98 * Represents a compressed frame with complete frame data.
99 */
100 int F_FULL = 0;
101
102 /**
103 * Represents a compressed frame where locals are the same as the locals in
104 * the previous frame, except that additional 1-3 locals are defined, and
105 * with an empty stack.
106 */
107 int F_APPEND = 1;
108
109 /**
110 * Represents a compressed frame where locals are the same as the locals in
111 * the previous frame, except that the last 1-3 locals are absent and with
112 * an empty stack.
113 */
114 int F_CHOP = 2;
115
116 /**
117 * Represents a compressed frame with exactly the same locals as the
118 * previous frame and with an empty stack.
119 */
120 int F_SAME = 3;
121
122 /**
123 * Represents a compressed frame with exactly the same locals as the
124 * previous frame and with a single value on the stack.
125 */
126 int F_SAME1 = 4;
127
128 Integer TOP = new Integer(0);
129 Integer INTEGER = new Integer(1);
130 Integer FLOAT = new Integer(2);
131 Integer DOUBLE = new Integer(3);
132 Integer LONG = new Integer(4);
133 Integer NULL = new Integer(5);
134 Integer UNINITIALIZED_THIS = new Integer(6);
135
136 // opcodes // visit method (- = idem)
137
138 int NOP = 0; // visitInsn
139 int ACONST_NULL = 1; // -
140 int ICONST_M1 = 2; // -
141 int ICONST_0 = 3; // -
142 int ICONST_1 = 4; // -
143 int ICONST_2 = 5; // -
144 int ICONST_3 = 6; // -
145 int ICONST_4 = 7; // -
146 int ICONST_5 = 8; // -
147 int LCONST_0 = 9; // -
148 int LCONST_1 = 10; // -
149 int FCONST_0 = 11; // -
150 int FCONST_1 = 12; // -
151 int FCONST_2 = 13; // -
152 int DCONST_0 = 14; // -
153 int DCONST_1 = 15; // -
154 int BIPUSH = 16; // visitIntInsn
155 int SIPUSH = 17; // -
156 int LDC = 18; // visitLdcInsn
157 // int LDC_W = 19; // -
158 // int LDC2_W = 20; // -
159 int ILOAD = 21; // visitVarInsn
160 int LLOAD = 22; // -
161 int FLOAD = 23; // -
162 int DLOAD = 24; // -
163 int ALOAD = 25; // -
164 // int ILOAD_0 = 26; // -
165 // int ILOAD_1 = 27; // -
166 // int ILOAD_2 = 28; // -
167 // int ILOAD_3 = 29; // -
168 // int LLOAD_0 = 30; // -
169 // int LLOAD_1 = 31; // -
170 // int LLOAD_2 = 32; // -
171 // int LLOAD_3 = 33; // -
172 // int FLOAD_0 = 34; // -
173 // int FLOAD_1 = 35; // -
174 // int FLOAD_2 = 36; // -
175 // int FLOAD_3 = 37; // -
176 // int DLOAD_0 = 38; // -
177 // int DLOAD_1 = 39; // -
178 // int DLOAD_2 = 40; // -
179 // int DLOAD_3 = 41; // -
180 // int ALOAD_0 = 42; // -
181 // int ALOAD_1 = 43; // -
182 // int ALOAD_2 = 44; // -
183 // int ALOAD_3 = 45; // -
184 int IALOAD = 46; // visitInsn
185 int LALOAD = 47; // -
186 int FALOAD = 48; // -
187 int DALOAD = 49; // -
188 int AALOAD = 50; // -
189 int BALOAD = 51; // -
190 int CALOAD = 52; // -
191 int SALOAD = 53; // -
192 int ISTORE = 54; // visitVarInsn
193 int LSTORE = 55; // -
194 int FSTORE = 56; // -
195 int DSTORE = 57; // -
196 int ASTORE = 58; // -
197 // int ISTORE_0 = 59; // -
198 // int ISTORE_1 = 60; // -
199 // int ISTORE_2 = 61; // -
200 // int ISTORE_3 = 62; // -
201 // int LSTORE_0 = 63; // -
202 // int LSTORE_1 = 64; // -
203 // int LSTORE_2 = 65; // -
204 // int LSTORE_3 = 66; // -
205 // int FSTORE_0 = 67; // -
206 // int FSTORE_1 = 68; // -
207 // int FSTORE_2 = 69; // -
208 // int FSTORE_3 = 70; // -
209 // int DSTORE_0 = 71; // -
210 // int DSTORE_1 = 72; // -
211 // int DSTORE_2 = 73; // -
212 // int DSTORE_3 = 74; // -
213 // int ASTORE_0 = 75; // -
214 // int ASTORE_1 = 76; // -
215 // int ASTORE_2 = 77; // -
216 // int ASTORE_3 = 78; // -
217 int IASTORE = 79; // visitInsn
218 int LASTORE = 80; // -
219 int FASTORE = 81; // -
220 int DASTORE = 82; // -
221 int AASTORE = 83; // -
222 int BASTORE = 84; // -
223 int CASTORE = 85; // -
224 int SASTORE = 86; // -
225 int POP = 87; // -
226 int POP2 = 88; // -
227 int DUP = 89; // -
228 int DUP_X1 = 90; // -
229 int DUP_X2 = 91; // -
230 int DUP2 = 92; // -
231 int DUP2_X1 = 93; // -
232 int DUP2_X2 = 94; // -
233 int SWAP = 95; // -
234 int IADD = 96; // -
235 int LADD = 97; // -
236 int FADD = 98; // -
237 int DADD = 99; // -
238 int ISUB = 100; // -
239 int LSUB = 101; // -
240 int FSUB = 102; // -
241 int DSUB = 103; // -
242 int IMUL = 104; // -
243 int LMUL = 105; // -
244 int FMUL = 106; // -
245 int DMUL = 107; // -
246 int IDIV = 108; // -
247 int LDIV = 109; // -
248 int FDIV = 110; // -
249 int DDIV = 111; // -
250 int IREM = 112; // -
251 int LREM = 113; // -
252 int FREM = 114; // -
253 int DREM = 115; // -
254 int INEG = 116; // -
255 int LNEG = 117; // -
256 int FNEG = 118; // -
257 int DNEG = 119; // -
258 int ISHL = 120; // -
259 int LSHL = 121; // -
260 int ISHR = 122; // -
261 int LSHR = 123; // -
262 int IUSHR = 124; // -
263 int LUSHR = 125; // -
264 int IAND = 126; // -
265 int LAND = 127; // -
266 int IOR = 128; // -
267 int LOR = 129; // -
268 int IXOR = 130; // -
269 int LXOR = 131; // -
270 int IINC = 132; // visitIincInsn
271 int I2L = 133; // visitInsn
272 int I2F = 134; // -
273 int I2D = 135; // -
274 int L2I = 136; // -
275 int L2F = 137; // -
276 int L2D = 138; // -
277 int F2I = 139; // -
278 int F2L = 140; // -
279 int F2D = 141; // -
280 int D2I = 142; // -
281 int D2L = 143; // -
282 int D2F = 144; // -
283 int I2B = 145; // -
284 int I2C = 146; // -
285 int I2S = 147; // -
286 int LCMP = 148; // -
287 int FCMPL = 149; // -
288 int FCMPG = 150; // -
289 int DCMPL = 151; // -
290 int DCMPG = 152; // -
291 int IFEQ = 153; // visitJumpInsn
292 int IFNE = 154; // -
293 int IFLT = 155; // -
294 int IFGE = 156; // -
295 int IFGT = 157; // -
296 int IFLE = 158; // -
297 int IF_ICMPEQ = 159; // -
298 int IF_ICMPNE = 160; // -
299 int IF_ICMPLT = 161; // -
300 int IF_ICMPGE = 162; // -
301 int IF_ICMPGT = 163; // -
302 int IF_ICMPLE = 164; // -
303 int IF_ACMPEQ = 165; // -
304 int IF_ACMPNE = 166; // -
305 int GOTO = 167; // -
306 int JSR = 168; // -
307 int RET = 169; // visitVarInsn
308 int TABLESWITCH = 170; // visiTableSwitchInsn
309 int LOOKUPSWITCH = 171; // visitLookupSwitch
310 int IRETURN = 172; // visitInsn
311 int LRETURN = 173; // -
312 int FRETURN = 174; // -
313 int DRETURN = 175; // -
314 int ARETURN = 176; // -
315 int RETURN = 177; // -
316 int GETSTATIC = 178; // visitFieldInsn
317 int PUTSTATIC = 179; // -
318 int GETFIELD = 180; // -
319 int PUTFIELD = 181; // -
320 int INVOKEVIRTUAL = 182; // visitMethodInsn
321 int INVOKESPECIAL = 183; // -
322 int INVOKESTATIC = 184; // -
323 int INVOKEINTERFACE = 185; // -
324 // int UNUSED = 186; // NOT VISITED
325 int NEW = 187; // visitTypeInsn
326 int NEWARRAY = 188; // visitIntInsn
327 int ANEWARRAY = 189; // visitTypeInsn
328 int ARRAYLENGTH = 190; // visitInsn
329 int ATHROW = 191; // -
330 int CHECKCAST = 192; // visitTypeInsn
331 int INSTANCEOF = 193; // -
332 int MONITORENTER = 194; // visitInsn
333 int MONITOREXIT = 195; // -
334 // int WIDE = 196; // NOT VISITED
335 int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
336 int IFNULL = 198; // visitJumpInsn
337 int IFNONNULL = 199; // -
338 // int GOTO_W = 200; // -
339 // int JSR_W = 201; // -
340 }
+0
-872
src/jvm/clojure/asm/Type.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm;
30
31 import java.lang.reflect.Constructor;
32 import java.lang.reflect.Method;
33
34 /**
35 * A Java type. This class can be used to make it easier to manipulate type and
36 * method descriptors.
37 *
38 * @author Eric Bruneton
39 * @author Chris Nokleberg
40 */
41 public class Type{
42
43 /**
44 * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
45 */
46 public final static int VOID = 0;
47
48 /**
49 * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
50 */
51 public final static int BOOLEAN = 1;
52
53 /**
54 * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
55 */
56 public final static int CHAR = 2;
57
58 /**
59 * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
60 */
61 public final static int BYTE = 3;
62
63 /**
64 * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
65 */
66 public final static int SHORT = 4;
67
68 /**
69 * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
70 */
71 public final static int INT = 5;
72
73 /**
74 * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
75 */
76 public final static int FLOAT = 6;
77
78 /**
79 * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
80 */
81 public final static int LONG = 7;
82
83 /**
84 * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
85 */
86 public final static int DOUBLE = 8;
87
88 /**
89 * The sort of array reference types. See {@link #getSort getSort}.
90 */
91 public final static int ARRAY = 9;
92
93 /**
94 * The sort of object reference type. See {@link #getSort getSort}.
95 */
96 public final static int OBJECT = 10;
97
98 /**
99 * The <tt>void</tt> type.
100 */
101 public final static Type VOID_TYPE = new Type(VOID);
102
103 /**
104 * The <tt>boolean</tt> type.
105 */
106 public final static Type BOOLEAN_TYPE = new Type(BOOLEAN);
107
108 /**
109 * The <tt>char</tt> type.
110 */
111 public final static Type CHAR_TYPE = new Type(CHAR);
112
113 /**
114 * The <tt>byte</tt> type.
115 */
116 public final static Type BYTE_TYPE = new Type(BYTE);
117
118 /**
119 * The <tt>short</tt> type.
120 */
121 public final static Type SHORT_TYPE = new Type(SHORT);
122
123 /**
124 * The <tt>int</tt> type.
125 */
126 public final static Type INT_TYPE = new Type(INT);
127
128 /**
129 * The <tt>float</tt> type.
130 */
131 public final static Type FLOAT_TYPE = new Type(FLOAT);
132
133 /**
134 * The <tt>long</tt> type.
135 */
136 public final static Type LONG_TYPE = new Type(LONG);
137
138 /**
139 * The <tt>double</tt> type.
140 */
141 public final static Type DOUBLE_TYPE = new Type(DOUBLE);
142
143 // ------------------------------------------------------------------------
144 // Fields
145 // ------------------------------------------------------------------------
146
147 /**
148 * The sort of this Java type.
149 */
150 private final int sort;
151
152 /**
153 * A buffer containing the descriptor of this Java type. This field is only
154 * used for reference types.
155 */
156 private char[] buf;
157
158 /**
159 * The offset of the descriptor of this Java type in {@link #buf buf}. This
160 * field is only used for reference types.
161 */
162 private int off;
163
164 /**
165 * The length of the descriptor of this Java type.
166 */
167 private int len;
168
169 // ------------------------------------------------------------------------
170 // Constructors
171 // ------------------------------------------------------------------------
172
173 /**
174 * Constructs a primitive type.
175 *
176 * @param sort the sort of the primitive type to be constructed.
177 */
178 private Type(final int sort){
179 this.sort = sort;
180 this.len = 1;
181 }
182
183 /**
184 * Constructs a reference type.
185 *
186 * @param sort the sort of the reference type to be constructed.
187 * @param buf a buffer containing the descriptor of the previous type.
188 * @param off the offset of this descriptor in the previous buffer.
189 * @param len the length of this descriptor.
190 */
191 private Type(final int sort, final char[] buf, final int off, final int len){
192 this.sort = sort;
193 this.buf = buf;
194 this.off = off;
195 this.len = len;
196 }
197
198 /**
199 * Returns the Java type corresponding to the given type descriptor.
200 *
201 * @param typeDescriptor a type descriptor.
202 * @return the Java type corresponding to the given type descriptor.
203 */
204 public static Type getType(final String typeDescriptor){
205 return getType(typeDescriptor.toCharArray(), 0);
206 }
207
208 /**
209 * Returns the Java type corresponding to the given class.
210 *
211 * @param c a class.
212 * @return the Java type corresponding to the given class.
213 */
214 public static Type getType(final Class c){
215 if(c.isPrimitive())
216 {
217 if(c == Integer.TYPE)
218 {
219 return INT_TYPE;
220 }
221 else if(c == Void.TYPE)
222 {
223 return VOID_TYPE;
224 }
225 else if(c == Boolean.TYPE)
226 {
227 return BOOLEAN_TYPE;
228 }
229 else if(c == Byte.TYPE)
230 {
231 return BYTE_TYPE;
232 }
233 else if(c == Character.TYPE)
234 {
235 return CHAR_TYPE;
236 }
237 else if(c == Short.TYPE)
238 {
239 return SHORT_TYPE;
240 }
241 else if(c == Double.TYPE)
242 {
243 return DOUBLE_TYPE;
244 }
245 else if(c == Float.TYPE)
246 {
247 return FLOAT_TYPE;
248 }
249 else /* if (c == Long.TYPE) */
250 {
251 return LONG_TYPE;
252 }
253 }
254 else
255 {
256 return getType(getDescriptor(c));
257 }
258 }
259
260 /**
261 * Returns the {@link Type#OBJECT} type for the given internal class name.
262 * This is a shortcut method for <code>Type.getType("L"+name+";")</code>.
263 * <i>Note that opposed to {@link Type#getType(String)}, this method takes
264 * internal class names and not class descriptor.</i>
265 *
266 * @param name an internal class name.
267 * @return the the {@link Type#OBJECT} type for the given class name.
268 */
269 public static Type getObjectType(String name){
270 int l = name.length();
271 char[] buf = new char[l + 2];
272 buf[0] = 'L';
273 buf[l + 1] = ';';
274 name.getChars(0, l, buf, 1);
275 return new Type(OBJECT, buf, 0, l + 2);
276 }
277
278 /**
279 * Returns the Java types corresponding to the argument types of the given
280 * method descriptor.
281 *
282 * @param methodDescriptor a method descriptor.
283 * @return the Java types corresponding to the argument types of the given
284 * method descriptor.
285 */
286 public static Type[] getArgumentTypes(final String methodDescriptor){
287 char[] buf = methodDescriptor.toCharArray();
288 int off = 1;
289 int size = 0;
290 while(true)
291 {
292 char car = buf[off++];
293 if(car == ')')
294 {
295 break;
296 }
297 else if(car == 'L')
298 {
299 while(buf[off++] != ';')
300 {
301 }
302 ++size;
303 }
304 else if(car != '[')
305 {
306 ++size;
307 }
308 }
309 Type[] args = new Type[size];
310 off = 1;
311 size = 0;
312 while(buf[off] != ')')
313 {
314 args[size] = getType(buf, off);
315 off += args[size].len;
316 size += 1;
317 }
318 return args;
319 }
320
321 /**
322 * Returns the Java types corresponding to the argument types of the given
323 * method.
324 *
325 * @param method a method.
326 * @return the Java types corresponding to the argument types of the given
327 * method.
328 */
329 public static Type[] getArgumentTypes(final Method method){
330 Class[] classes = method.getParameterTypes();
331 Type[] types = new Type[classes.length];
332 for(int i = classes.length - 1; i >= 0; --i)
333 {
334 types[i] = getType(classes[i]);
335 }
336 return types;
337 }
338
339 /**
340 * Returns the Java type corresponding to the return type of the given
341 * method descriptor.
342 *
343 * @param methodDescriptor a method descriptor.
344 * @return the Java type corresponding to the return type of the given
345 * method descriptor.
346 */
347 public static Type getReturnType(final String methodDescriptor){
348 char[] buf = methodDescriptor.toCharArray();
349 return getType(buf, methodDescriptor.indexOf(')') + 1);
350 }
351
352 /**
353 * Returns the Java type corresponding to the return type of the given
354 * method.
355 *
356 * @param method a method.
357 * @return the Java type corresponding to the return type of the given
358 * method.
359 */
360 public static Type getReturnType(final Method method){
361 return getType(method.getReturnType());
362 }
363
364 /**
365 * Returns the Java type corresponding to the given type descriptor.
366 *
367 * @param buf a buffer containing a type descriptor.
368 * @param off the offset of this descriptor in the previous buffer.
369 * @return the Java type corresponding to the given type descriptor.
370 */
371 private static Type getType(final char[] buf, final int off){
372 int len;
373 switch(buf[off])
374 {
375 case'V':
376 return VOID_TYPE;
377 case'Z':
378 return BOOLEAN_TYPE;
379 case'C':
380 return CHAR_TYPE;
381 case'B':
382 return BYTE_TYPE;
383 case'S':
384 return SHORT_TYPE;
385 case'I':
386 return INT_TYPE;
387 case'F':
388 return FLOAT_TYPE;
389 case'J':
390 return LONG_TYPE;
391 case'D':
392 return DOUBLE_TYPE;
393 case'[':
394 len = 1;
395 while(buf[off + len] == '[')
396 {
397 ++len;
398 }
399 if(buf[off + len] == 'L')
400 {
401 ++len;
402 while(buf[off + len] != ';')
403 {
404 ++len;
405 }
406 }
407 return new Type(ARRAY, buf, off, len + 1);
408 // case 'L':
409 default:
410 len = 1;
411 while(buf[off + len] != ';')
412 {
413 ++len;
414 }
415 return new Type(OBJECT, buf, off, len + 1);
416 }
417 }
418
419 // ------------------------------------------------------------------------
420 // Accessors
421 // ------------------------------------------------------------------------
422
423 /**
424 * Returns the sort of this Java type.
425 *
426 * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN},
427 * {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT},
428 * {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG},
429 * {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY} or
430 * {@link #OBJECT OBJECT}.
431 */
432 public int getSort(){
433 return sort;
434 }
435
436 /**
437 * Returns the number of dimensions of this array type. This method should
438 * only be used for an array type.
439 *
440 * @return the number of dimensions of this array type.
441 */
442 public int getDimensions(){
443 int i = 1;
444 while(buf[off + i] == '[')
445 {
446 ++i;
447 }
448 return i;
449 }
450
451 /**
452 * Returns the type of the elements of this array type. This method should
453 * only be used for an array type.
454 *
455 * @return Returns the type of the elements of this array type.
456 */
457 public Type getElementType(){
458 return getType(buf, off + getDimensions());
459 }
460
461 /**
462 * Returns the name of the class corresponding to this type.
463 *
464 * @return the fully qualified name of the class corresponding to this type.
465 */
466 public String getClassName(){
467 switch(sort)
468 {
469 case VOID:
470 return "void";
471 case BOOLEAN:
472 return "boolean";
473 case CHAR:
474 return "char";
475 case BYTE:
476 return "byte";
477 case SHORT:
478 return "short";
479 case INT:
480 return "int";
481 case FLOAT:
482 return "float";
483 case LONG:
484 return "long";
485 case DOUBLE:
486 return "double";
487 case ARRAY:
488 StringBuffer b = new StringBuffer(getElementType().getClassName());
489 for(int i = getDimensions(); i > 0; --i)
490 {
491 b.append("[]");
492 }
493 return b.toString();
494 // case OBJECT:
495 default:
496 return new String(buf, off + 1, len - 2).replace('/', '.');
497 }
498 }
499
500 /**
501 * Returns the internal name of the class corresponding to this object type.
502 * The internal name of a class is its fully qualified name, where '.' are
503 * replaced by '/'. This method should only be used for an object type.
504 *
505 * @return the internal name of the class corresponding to this object type.
506 */
507 public String getInternalName(){
508 return new String(buf, off + 1, len - 2);
509 }
510
511 // ------------------------------------------------------------------------
512 // Conversion to type descriptors
513 // ------------------------------------------------------------------------
514
515 /**
516 * Returns the descriptor corresponding to this Java type.
517 *
518 * @return the descriptor corresponding to this Java type.
519 */
520 public String getDescriptor(){
521 StringBuffer buf = new StringBuffer();
522 getDescriptor(buf);
523 return buf.toString();
524 }
525
526 /**
527 * Returns the descriptor corresponding to the given argument and return
528 * types.
529 *
530 * @param returnType the return type of the method.
531 * @param argumentTypes the argument types of the method.
532 * @return the descriptor corresponding to the given argument and return
533 * types.
534 */
535 public static String getMethodDescriptor(
536 final Type returnType,
537 final Type[] argumentTypes){
538 StringBuffer buf = new StringBuffer();
539 buf.append('(');
540 for(int i = 0; i < argumentTypes.length; ++i)
541 {
542 argumentTypes[i].getDescriptor(buf);
543 }
544 buf.append(')');
545 returnType.getDescriptor(buf);
546 return buf.toString();
547 }
548
549 /**
550 * Appends the descriptor corresponding to this Java type to the given
551 * string buffer.
552 *
553 * @param buf the string buffer to which the descriptor must be appended.
554 */
555 private void getDescriptor(final StringBuffer buf){
556 switch(sort)
557 {
558 case VOID:
559 buf.append('V');
560 return;
561 case BOOLEAN:
562 buf.append('Z');
563 return;
564 case CHAR:
565 buf.append('C');
566 return;
567 case BYTE:
568 buf.append('B');
569 return;
570 case SHORT:
571 buf.append('S');
572 return;
573 case INT:
574 buf.append('I');
575 return;
576 case FLOAT:
577 buf.append('F');
578 return;
579 case LONG:
580 buf.append('J');
581 return;
582 case DOUBLE:
583 buf.append('D');
584 return;
585 // case ARRAY:
586 // case OBJECT:
587 default:
588 buf.append(this.buf, off, len);
589 }
590 }
591
592 // ------------------------------------------------------------------------
593 // Direct conversion from classes to type descriptors,
594 // without intermediate Type objects
595 // ------------------------------------------------------------------------
596
597 /**
598 * Returns the internal name of the given class. The internal name of a
599 * class is its fully qualified name, where '.' are replaced by '/'.
600 *
601 * @param c an object class.
602 * @return the internal name of the given class.
603 */
604 public static String getInternalName(final Class c){
605 return c.getName().replace('.', '/');
606 }
607
608 /**
609 * Returns the descriptor corresponding to the given Java type.
610 *
611 * @param c an object class, a primitive class or an array class.
612 * @return the descriptor corresponding to the given class.
613 */
614 public static String getDescriptor(final Class c){
615 StringBuffer buf = new StringBuffer();
616 getDescriptor(buf, c);
617 return buf.toString();
618 }
619
620 /**
621 * Returns the descriptor corresponding to the given constructor.
622 *
623 * @param c a {@link Constructor Constructor} object.
624 * @return the descriptor of the given constructor.
625 */
626 public static String getConstructorDescriptor(final Constructor c){
627 Class[] parameters = c.getParameterTypes();
628 StringBuffer buf = new StringBuffer();
629 buf.append('(');
630 for(int i = 0; i < parameters.length; ++i)
631 {
632 getDescriptor(buf, parameters[i]);
633 }
634 return buf.append(")V").toString();
635 }
636
637 /**
638 * Returns the descriptor corresponding to the given method.
639 *
640 * @param m a {@link Method Method} object.
641 * @return the descriptor of the given method.
642 */
643 public static String getMethodDescriptor(final Method m){
644 Class[] parameters = m.getParameterTypes();
645 StringBuffer buf = new StringBuffer();
646 buf.append('(');
647 for(int i = 0; i < parameters.length; ++i)
648 {
649 getDescriptor(buf, parameters[i]);
650 }
651 buf.append(')');
652 getDescriptor(buf, m.getReturnType());
653 return buf.toString();
654 }
655
656 /**
657 * Appends the descriptor of the given class to the given string buffer.
658 *
659 * @param buf the string buffer to which the descriptor must be appended.
660 * @param c the class whose descriptor must be computed.
661 */
662 private static void getDescriptor(final StringBuffer buf, final Class c){
663 Class d = c;
664 while(true)
665 {
666 if(d.isPrimitive())
667 {
668 char car;
669 if(d == Integer.TYPE)
670 {
671 car = 'I';
672 }
673 else if(d == Void.TYPE)
674 {
675 car = 'V';
676 }
677 else if(d == Boolean.TYPE)
678 {
679 car = 'Z';
680 }
681 else if(d == Byte.TYPE)
682 {
683 car = 'B';
684 }
685 else if(d == Character.TYPE)
686 {
687 car = 'C';
688 }
689 else if(d == Short.TYPE)
690 {
691 car = 'S';
692 }
693 else if(d == Double.TYPE)
694 {
695 car = 'D';
696 }
697 else if(d == Float.TYPE)
698 {
699 car = 'F';
700 }
701 else /* if (d == Long.TYPE) */
702 {
703 car = 'J';
704 }
705 buf.append(car);
706 return;
707 }
708 else if(d.isArray())
709 {
710 buf.append('[');
711 d = d.getComponentType();
712 }
713 else
714 {
715 buf.append('L');
716 String name = d.getName();
717 int len = name.length();
718 for(int i = 0; i < len; ++i)
719 {
720 char car = name.charAt(i);
721 buf.append(car == '.' ? '/' : car);
722 }
723 buf.append(';');
724 return;
725 }
726 }
727 }
728
729 // ------------------------------------------------------------------------
730 // Corresponding size and opcodes
731 // ------------------------------------------------------------------------
732
733 /**
734 * Returns the size of values of this type.
735 *
736 * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
737 * <tt>double</tt>, and 1 otherwise.
738 */
739 public int getSize(){
740 return sort == LONG || sort == DOUBLE ? 2 : 1;
741 }
742
743 /**
744 * Returns a JVM instruction opcode adapted to this Java type.
745 *
746 * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD,
747 * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL,
748 * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
749 * @return an opcode that is similar to the given opcode, but adapted to
750 * this Java type. For example, if this type is <tt>float</tt> and
751 * <tt>opcode</tt> is IRETURN, this method returns FRETURN.
752 */
753 public int getOpcode(final int opcode){
754 if(opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE)
755 {
756 switch(sort)
757 {
758 case BOOLEAN:
759 case BYTE:
760 return opcode + 5;
761 case CHAR:
762 return opcode + 6;
763 case SHORT:
764 return opcode + 7;
765 case INT:
766 return opcode;
767 case FLOAT:
768 return opcode + 2;
769 case LONG:
770 return opcode + 1;
771 case DOUBLE:
772 return opcode + 3;
773 // case ARRAY:
774 // case OBJECT:
775 default:
776 return opcode + 4;
777 }
778 }
779 else
780 {
781 switch(sort)
782 {
783 case VOID:
784 return opcode + 5;
785 case BOOLEAN:
786 case CHAR:
787 case BYTE:
788 case SHORT:
789 case INT:
790 return opcode;
791 case FLOAT:
792 return opcode + 2;
793 case LONG:
794 return opcode + 1;
795 case DOUBLE:
796 return opcode + 3;
797 // case ARRAY:
798 // case OBJECT:
799 default:
800 return opcode + 4;
801 }
802 }
803 }
804
805 // ------------------------------------------------------------------------
806 // Equals, hashCode and toString
807 // ------------------------------------------------------------------------
808
809 /**
810 * Tests if the given object is equal to this type.
811 *
812 * @param o the object to be compared to this type.
813 * @return <tt>true</tt> if the given object is equal to this type.
814 */
815 public boolean equals(final Object o){
816 if(this == o)
817 {
818 return true;
819 }
820 if(!(o instanceof Type))
821 {
822 return false;
823 }
824 Type t = (Type) o;
825 if(sort != t.sort)
826 {
827 return false;
828 }
829 if(sort == Type.OBJECT || sort == Type.ARRAY)
830 {
831 if(len != t.len)
832 {
833 return false;
834 }
835 for(int i = off, j = t.off, end = i + len; i < end; i++, j++)
836 {
837 if(buf[i] != t.buf[j])
838 {
839 return false;
840 }
841 }
842 }
843 return true;
844 }
845
846 /**
847 * Returns a hash code value for this type.
848 *
849 * @return a hash code value for this type.
850 */
851 public int hashCode(){
852 int hc = 13 * sort;
853 if(sort == Type.OBJECT || sort == Type.ARRAY)
854 {
855 for(int i = off, end = i + len; i < end; i++)
856 {
857 hc = 17 * (hc + buf[i]);
858 }
859 }
860 return hc;
861 }
862
863 /**
864 * Returns a string representation of this type.
865 *
866 * @return the descriptor of this type.
867 */
868 public String toString(){
869 return getDescriptor();
870 }
871 }
+0
-681
src/jvm/clojure/asm/commons/AdviceAdapter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm.commons;
30
31 import java.util.ArrayList;
32 import java.util.HashMap;
33
34 import clojure.asm.Label;
35 import clojure.asm.MethodVisitor;
36 import clojure.asm.Opcodes;
37 import clojure.asm.Type;
38
39 /**
40 * A {@link clojure.asm.MethodAdapter} to insert before, after and around
41 * advices in methods and constructors. <p> The behavior for constructors is
42 * like this: <ol>
43 * <p/>
44 * <li>as long as the INVOKESPECIAL for the object initialization has not been
45 * reached, every bytecode instruction is dispatched in the ctor code visitor</li>
46 * <p/>
47 * <li>when this one is reached, it is only added in the ctor code visitor and
48 * a JP invoke is added</li>
49 * <p/>
50 * <li>after that, only the other code visitor receives the instructions</li>
51 * <p/>
52 * </ol>
53 *
54 * @author Eugene Kuleshov
55 * @author Eric Bruneton
56 */
57 public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes{
58 private static final Object THIS = new Object();
59 private static final Object OTHER = new Object();
60
61 protected int methodAccess;
62 protected String methodDesc;
63
64 private boolean constructor;
65 private boolean superInitialized;
66 private ArrayList stackFrame;
67 private HashMap branches;
68
69 /**
70 * Creates a new {@link AdviceAdapter}.
71 *
72 * @param mv the method visitor to which this adapter delegates calls.
73 * @param access the method's access flags (see {@link Opcodes}).
74 * @param name the method's name.
75 * @param desc the method's descriptor (see {@link Type Type}).
76 */
77 public AdviceAdapter(
78 final MethodVisitor mv,
79 final int access,
80 final String name,
81 final String desc){
82 super(mv, access, name, desc);
83 methodAccess = access;
84 methodDesc = desc;
85
86 constructor = "<init>".equals(name);
87 }
88
89 public void visitCode(){
90 mv.visitCode();
91 if(!constructor)
92 {
93 superInitialized = true;
94 onMethodEnter();
95 }
96 else
97 {
98 stackFrame = new ArrayList();
99 branches = new HashMap();
100 }
101 }
102
103 public void visitLabel(final Label label){
104 mv.visitLabel(label);
105
106 if(constructor && branches != null)
107 {
108 ArrayList frame = (ArrayList) branches.get(label);
109 if(frame != null)
110 {
111 stackFrame = frame;
112 branches.remove(label);
113 }
114 }
115 }
116
117 public void visitInsn(final int opcode){
118 if(constructor)
119 {
120 switch(opcode)
121 {
122 case RETURN: // empty stack
123 onMethodExit(opcode);
124 break;
125
126 case IRETURN: // 1 before n/a after
127 case FRETURN: // 1 before n/a after
128 case ARETURN: // 1 before n/a after
129 case ATHROW: // 1 before n/a after
130 popValue();
131 popValue();
132 onMethodExit(opcode);
133 break;
134
135 case LRETURN: // 2 before n/a after
136 case DRETURN: // 2 before n/a after
137 popValue();
138 popValue();
139 onMethodExit(opcode);
140 break;
141
142 case NOP:
143 case LALOAD: // remove 2 add 2
144 case DALOAD: // remove 2 add 2
145 case LNEG:
146 case DNEG:
147 case FNEG:
148 case INEG:
149 case L2D:
150 case D2L:
151 case F2I:
152 case I2B:
153 case I2C:
154 case I2S:
155 case I2F:
156 case Opcodes.ARRAYLENGTH:
157 break;
158
159 case ACONST_NULL:
160 case ICONST_M1:
161 case ICONST_0:
162 case ICONST_1:
163 case ICONST_2:
164 case ICONST_3:
165 case ICONST_4:
166 case ICONST_5:
167 case FCONST_0:
168 case FCONST_1:
169 case FCONST_2:
170 case F2L: // 1 before 2 after
171 case F2D:
172 case I2L:
173 case I2D:
174 pushValue(OTHER);
175 break;
176
177 case LCONST_0:
178 case LCONST_1:
179 case DCONST_0:
180 case DCONST_1:
181 pushValue(OTHER);
182 pushValue(OTHER);
183 break;
184
185 case IALOAD: // remove 2 add 1
186 case FALOAD: // remove 2 add 1
187 case AALOAD: // remove 2 add 1
188 case BALOAD: // remove 2 add 1
189 case CALOAD: // remove 2 add 1
190 case SALOAD: // remove 2 add 1
191 case POP:
192 case IADD:
193 case FADD:
194 case ISUB:
195 case LSHL: // 3 before 2 after
196 case LSHR: // 3 before 2 after
197 case LUSHR: // 3 before 2 after
198 case L2I: // 2 before 1 after
199 case L2F: // 2 before 1 after
200 case D2I: // 2 before 1 after
201 case D2F: // 2 before 1 after
202 case FSUB:
203 case FMUL:
204 case FDIV:
205 case FREM:
206 case FCMPL: // 2 before 1 after
207 case FCMPG: // 2 before 1 after
208 case IMUL:
209 case IDIV:
210 case IREM:
211 case ISHL:
212 case ISHR:
213 case IUSHR:
214 case IAND:
215 case IOR:
216 case IXOR:
217 case MONITORENTER:
218 case MONITOREXIT:
219 popValue();
220 break;
221
222 case POP2:
223 case LSUB:
224 case LMUL:
225 case LDIV:
226 case LREM:
227 case LADD:
228 case LAND:
229 case LOR:
230 case LXOR:
231 case DADD:
232 case DMUL:
233 case DSUB:
234 case DDIV:
235 case DREM:
236 popValue();
237 popValue();
238 break;
239
240 case IASTORE:
241 case FASTORE:
242 case AASTORE:
243 case BASTORE:
244 case CASTORE:
245 case SASTORE:
246 case LCMP: // 4 before 1 after
247 case DCMPL:
248 case DCMPG:
249 popValue();
250 popValue();
251 popValue();
252 break;
253
254 case LASTORE:
255 case DASTORE:
256 popValue();
257 popValue();
258 popValue();
259 popValue();
260 break;
261
262 case DUP:
263 pushValue(peekValue());
264 break;
265
266 case DUP_X1:
267 // TODO optimize this
268 {
269 Object o1 = popValue();
270 Object o2 = popValue();
271 pushValue(o1);
272 pushValue(o2);
273 pushValue(o1);
274 }
275 break;
276
277 case DUP_X2:
278 // TODO optimize this
279 {
280 Object o1 = popValue();
281 Object o2 = popValue();
282 Object o3 = popValue();
283 pushValue(o1);
284 pushValue(o3);
285 pushValue(o2);
286 pushValue(o1);
287 }
288 break;
289
290 case DUP2:
291 // TODO optimize this
292 {
293 Object o1 = popValue();
294 Object o2 = popValue();
295 pushValue(o2);
296 pushValue(o1);
297 pushValue(o2);
298 pushValue(o1);
299 }
300 break;
301
302 case DUP2_X1:
303 // TODO optimize this
304 {
305 Object o1 = popValue();
306 Object o2 = popValue();
307 Object o3 = popValue();
308 pushValue(o2);
309 pushValue(o1);
310 pushValue(o3);
311 pushValue(o2);
312 pushValue(o1);
313 }
314 break;
315
316 case DUP2_X2:
317 // TODO optimize this
318 {
319 Object o1 = popValue();
320 Object o2 = popValue();
321 Object o3 = popValue();
322 Object o4 = popValue();
323 pushValue(o2);
324 pushValue(o1);
325 pushValue(o4);
326 pushValue(o3);
327 pushValue(o2);
328 pushValue(o1);
329 }
330 break;
331
332 case SWAP:
333 {
334 Object o1 = popValue();
335 Object o2 = popValue();
336 pushValue(o1);
337 pushValue(o2);
338 }
339 break;
340 }
341 }
342 else
343 {
344 switch(opcode)
345 {
346 case RETURN:
347 case IRETURN:
348 case FRETURN:
349 case ARETURN:
350 case LRETURN:
351 case DRETURN:
352 case ATHROW:
353 onMethodExit(opcode);
354 break;
355 }
356 }
357 mv.visitInsn(opcode);
358 }
359
360 public void visitVarInsn(final int opcode, final int var){
361 super.visitVarInsn(opcode, var);
362
363 if(constructor)
364 {
365 switch(opcode)
366 {
367 case ILOAD:
368 case FLOAD:
369 pushValue(OTHER);
370 break;
371 case LLOAD:
372 case DLOAD:
373 pushValue(OTHER);
374 pushValue(OTHER);
375 break;
376 case ALOAD:
377 pushValue(var == 0 ? THIS : OTHER);
378 break;
379 case ASTORE:
380 case ISTORE:
381 case FSTORE:
382 popValue();
383 break;
384 case LSTORE:
385 case DSTORE:
386 popValue();
387 popValue();
388 break;
389 }
390 }
391 }
392
393 public void visitFieldInsn(
394 final int opcode,
395 final String owner,
396 final String name,
397 final String desc){
398 mv.visitFieldInsn(opcode, owner, name, desc);
399
400 if(constructor)
401 {
402 char c = desc.charAt(0);
403 boolean longOrDouble = c == 'J' || c == 'D';
404 switch(opcode)
405 {
406 case GETSTATIC:
407 pushValue(OTHER);
408 if(longOrDouble)
409 {
410 pushValue(OTHER);
411 }
412 break;
413 case PUTSTATIC:
414 popValue();
415 if(longOrDouble)
416 {
417 popValue();
418 }
419 break;
420 case PUTFIELD:
421 popValue();
422 if(longOrDouble)
423 {
424 popValue();
425 popValue();
426 }
427 break;
428 // case GETFIELD:
429 default:
430 if(longOrDouble)
431 {
432 pushValue(OTHER);
433 }
434 }
435 }
436 }
437
438 public void visitIntInsn(final int opcode, final int operand){
439 mv.visitIntInsn(opcode, operand);
440
441 if(constructor && opcode != NEWARRAY)
442 {
443 pushValue(OTHER);
444 }
445 }
446
447 public void visitLdcInsn(final Object cst){
448 mv.visitLdcInsn(cst);
449
450 if(constructor)
451 {
452 pushValue(OTHER);
453 if(cst instanceof Double || cst instanceof Long)
454 {
455 pushValue(OTHER);
456 }
457 }
458 }
459
460 public void visitMultiANewArrayInsn(final String desc, final int dims){
461 mv.visitMultiANewArrayInsn(desc, dims);
462
463 if(constructor)
464 {
465 for(int i = 0; i < dims; i++)
466 {
467 popValue();
468 }
469 pushValue(OTHER);
470 }
471 }
472
473 public void visitTypeInsn(final int opcode, final String name){
474 mv.visitTypeInsn(opcode, name);
475
476 // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
477 if(constructor && opcode == NEW)
478 {
479 pushValue(OTHER);
480 }
481 }
482
483 public void visitMethodInsn(
484 final int opcode,
485 final String owner,
486 final String name,
487 final String desc){
488 mv.visitMethodInsn(opcode, owner, name, desc);
489
490 if(constructor)
491 {
492 Type[] types = Type.getArgumentTypes(desc);
493 for(int i = 0; i < types.length; i++)
494 {
495 popValue();
496 if(types[i].getSize() == 2)
497 {
498 popValue();
499 }
500 }
501 switch(opcode)
502 {
503 // case INVOKESTATIC:
504 // break;
505
506 case INVOKEINTERFACE:
507 case INVOKEVIRTUAL:
508 popValue(); // objectref
509 break;
510
511 case INVOKESPECIAL:
512 Object type = popValue(); // objectref
513 if(type == THIS && !superInitialized)
514 {
515 onMethodEnter();
516 superInitialized = true;
517 // once super has been initialized it is no longer
518 // necessary to keep track of stack state
519 constructor = false;
520 }
521 break;
522 }
523
524 Type returnType = Type.getReturnType(desc);
525 if(returnType != Type.VOID_TYPE)
526 {
527 pushValue(OTHER);
528 if(returnType.getSize() == 2)
529 {
530 pushValue(OTHER);
531 }
532 }
533 }
534 }
535
536 public void visitJumpInsn(final int opcode, final Label label){
537 mv.visitJumpInsn(opcode, label);
538
539 if(constructor)
540 {
541 switch(opcode)
542 {
543 case IFEQ:
544 case IFNE:
545 case IFLT:
546 case IFGE:
547 case IFGT:
548 case IFLE:
549 case IFNULL:
550 case IFNONNULL:
551 popValue();
552 break;
553
554 case IF_ICMPEQ:
555 case IF_ICMPNE:
556 case IF_ICMPLT:
557 case IF_ICMPGE:
558 case IF_ICMPGT:
559 case IF_ICMPLE:
560 case IF_ACMPEQ:
561 case IF_ACMPNE:
562 popValue();
563 popValue();
564 break;
565
566 case JSR:
567 pushValue(OTHER);
568 break;
569 }
570 addBranch(label);
571 }
572 }
573
574 public void visitLookupSwitchInsn(
575 final Label dflt,
576 final int[] keys,
577 final Label[] labels){
578 mv.visitLookupSwitchInsn(dflt, keys, labels);
579
580 if(constructor)
581 {
582 popValue();
583 addBranches(dflt, labels);
584 }
585 }
586
587 public void visitTableSwitchInsn(
588 final int min,
589 final int max,
590 final Label dflt,
591 final Label[] labels){
592 mv.visitTableSwitchInsn(min, max, dflt, labels);
593
594 if(constructor)
595 {
596 popValue();
597 addBranches(dflt, labels);
598 }
599 }
600
601 private void addBranches(final Label dflt, final Label[] labels){
602 addBranch(dflt);
603 for(int i = 0; i < labels.length; i++)
604 {
605 addBranch(labels[i]);
606 }
607 }
608
609 private void addBranch(final Label label){
610 if(branches.containsKey(label))
611 {
612 return;
613 }
614 ArrayList frame = new ArrayList();
615 frame.addAll(stackFrame);
616 branches.put(label, frame);
617 }
618
619 private Object popValue(){
620 return stackFrame.remove(stackFrame.size() - 1);
621 }
622
623 private Object peekValue(){
624 return stackFrame.get(stackFrame.size() - 1);
625 }
626
627 private void pushValue(final Object o){
628 stackFrame.add(o);
629 }
630
631 /**
632 * Called at the beginning of the method or after super class class call in
633 * the constructor. <br><br>
634 * <p/>
635 * <i>Custom code can use or change all the local variables, but should not
636 * change state of the stack.</i>
637 */
638 protected abstract void onMethodEnter();
639
640 /**
641 * Called before explicit exit from the method using either return or throw.
642 * Top element on the stack contains the return value or exception instance.
643 * For example:
644 * <p/>
645 * <pre>
646 * public void onMethodExit(int opcode) {
647 * if(opcode==RETURN) {
648 * visitInsn(ACONST_NULL);
649 * } else if(opcode==ARETURN || opcode==ATHROW) {
650 * dup();
651 * } else {
652 * if(opcode==LRETURN || opcode==DRETURN) {
653 * dup2();
654 * } else {
655 * dup();
656 * }
657 * box(Type.getReturnType(this.methodDesc));
658 * }
659 * visitIntInsn(SIPUSH, opcode);
660 * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
661 * }
662 * <p/>
663 * // an actual call back method
664 * public static void onExit(int opcode, Object param) {
665 * ...
666 * </pre>
667 * <p/>
668 * <br><br>
669 * <p/>
670 * <i>Custom code can use or change all the local variables, but should not
671 * change state of the stack.</i>
672 *
673 * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN,
674 * DRETURN or ATHROW
675 */
676 protected abstract void onMethodExit(int opcode);
677
678 // TODO onException, onMethodCall
679
680 }
+0
-938
src/jvm/clojure/asm/commons/AnalyzerAdapter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm.commons;
30
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35
36 import clojure.asm.Label;
37 import clojure.asm.MethodAdapter;
38 import clojure.asm.MethodVisitor;
39 import clojure.asm.Opcodes;
40 import clojure.asm.Type;
41
42 /**
43 * A {@link MethodAdapter} that keeps track of stack map frame changes between
44 * {@link #visitFrame(int,int,Object[],int,Object[]) visitFrame} calls. This
45 * adapter must be used with the
46 * {@link clojure.asm.ClassReader#EXPAND_FRAMES} option. Each visit<i>XXX</i>
47 * instruction delegates to the next visitor in the chain, if any, and then
48 * simulates the effect of this instruction on the stack map frame, represented
49 * by {@link #locals} and {@link #stack}. The next visitor in the chain can get
50 * the state of the stack map frame <i>before</i> each instruction by reading
51 * the value of these fields in its visit<i>XXX</i> methods (this requires a
52 * reference to the AnalyzerAdapter that is before it in the chain).
53 *
54 * @author Eric Bruneton
55 */
56 public class AnalyzerAdapter extends MethodAdapter{
57
58 /**
59 * <code>List</code> of the local variable slots for current execution
60 * frame. Primitive types are represented by {@link Opcodes#TOP},
61 * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
62 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
63 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a
64 * two elements, the second one being TOP). Reference types are represented
65 * by String objects (representing internal names, or type descriptors for
66 * array types), and uninitialized types by Label objects (this label
67 * designates the NEW instruction that created this uninitialized value).
68 * This field is <tt>null</tt> for unreacheable instructions.
69 */
70 public List locals;
71
72 /**
73 * <code>List</code> of the operand stack slots for current execution
74 * frame. Primitive types are represented by {@link Opcodes#TOP},
75 * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
76 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
77 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a
78 * two elements, the second one being TOP). Reference types are represented
79 * by String objects (representing internal names, or type descriptors for
80 * array types), and uninitialized types by Label objects (this label
81 * designates the NEW instruction that created this uninitialized value).
82 * This field is <tt>null</tt> for unreacheable instructions.
83 */
84 public List stack;
85
86 /**
87 * The labels that designate the next instruction to be visited. May be
88 * <tt>null</tt>.
89 */
90 private List labels;
91
92 /**
93 * Information about uninitialized types in the current execution frame.
94 * This map associates internal names to Label objects. Each label
95 * designates a NEW instruction that created the currently uninitialized
96 * types, and the associated internal name represents the NEW operand, i.e.
97 * the final, initialized type value.
98 */
99 private Map uninitializedTypes;
100
101 /**
102 * The maximum stack size of this method.
103 */
104 private int maxStack;
105
106 /**
107 * The maximum number of local variables of this method.
108 */
109 private int maxLocals;
110
111 /**
112 * Creates a new {@link AnalyzerAdapter}.
113 *
114 * @param owner the owner's class name.
115 * @param access the method's access flags (see {@link Opcodes}).
116 * @param name the method's name.
117 * @param desc the method's descriptor (see {@link Type Type}).
118 * @param mv the method visitor to which this adapter delegates calls. May
119 * be <tt>null</tt>.
120 */
121 public AnalyzerAdapter(
122 final String owner,
123 final int access,
124 final String name,
125 final String desc,
126 final MethodVisitor mv){
127 super(mv);
128 locals = new ArrayList();
129 stack = new ArrayList();
130 uninitializedTypes = new HashMap();
131
132 if((access & Opcodes.ACC_STATIC) == 0)
133 {
134 if(name.equals("<init>"))
135 {
136 locals.add(Opcodes.UNINITIALIZED_THIS);
137 }
138 else
139 {
140 locals.add(owner);
141 }
142 }
143 Type[] types = Type.getArgumentTypes(desc);
144 for(int i = 0; i < types.length; ++i)
145 {
146 Type type = types[i];
147 switch(type.getSort())
148 {
149 case Type.BOOLEAN:
150 case Type.CHAR:
151 case Type.BYTE:
152 case Type.SHORT:
153 case Type.INT:
154 locals.add(Opcodes.INTEGER);
155 break;
156 case Type.FLOAT:
157 locals.add(Opcodes.FLOAT);
158 break;
159 case Type.LONG:
160 locals.add(Opcodes.LONG);
161 locals.add(Opcodes.TOP);
162 break;
163 case Type.DOUBLE:
164 locals.add(Opcodes.DOUBLE);
165 locals.add(Opcodes.TOP);
166 break;
167 case Type.ARRAY:
168 locals.add(types[i].getDescriptor());
169 break;
170 // case Type.OBJECT:
171 default:
172 locals.add(types[i].getInternalName());
173 }
174 }
175 }
176
177 public void visitFrame(
178 final int type,
179 final int nLocal,
180 final Object[] local,
181 final int nStack,
182 final Object[] stack){
183 if(type != Opcodes.F_NEW)
184 { // uncompressed frame
185 throw new IllegalStateException("ClassReader.accept() should be called with EXPAND_FRAMES flag");
186 }
187
188 if(mv != null)
189 {
190 mv.visitFrame(type, nLocal, local, nStack, stack);
191 }
192
193 if(this.locals != null)
194 {
195 this.locals.clear();
196 this.stack.clear();
197 }
198 else
199 {
200 this.locals = new ArrayList();
201 this.stack = new ArrayList();
202 }
203 visitFrameTypes(nLocal, local, this.locals);
204 visitFrameTypes(nStack, stack, this.stack);
205 maxStack = Math.max(maxStack, this.stack.size());
206 }
207
208 private void visitFrameTypes(
209 final int n,
210 final Object[] types,
211 final List result){
212 for(int i = 0; i < n; ++i)
213 {
214 Object type = types[i];
215 result.add(type);
216 if(type == Opcodes.LONG || type == Opcodes.DOUBLE)
217 {
218 result.add(Opcodes.TOP);
219 }
220 }
221 }
222
223 public void visitInsn(final int opcode){
224 if(mv != null)
225 {
226 mv.visitInsn(opcode);
227 }
228 execute(opcode, 0, null);
229 if((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
230 || opcode == Opcodes.ATHROW)
231 {
232 this.locals = null;
233 this.stack = null;
234 }
235 }
236
237 public void visitIntInsn(final int opcode, final int operand){
238 if(mv != null)
239 {
240 mv.visitIntInsn(opcode, operand);
241 }
242 execute(opcode, operand, null);
243 }
244
245 public void visitVarInsn(final int opcode, final int var){
246 if(mv != null)
247 {
248 mv.visitVarInsn(opcode, var);
249 }
250 execute(opcode, var, null);
251 }
252
253 public void visitTypeInsn(final int opcode, final String desc){
254 if(opcode == Opcodes.NEW)
255 {
256 if(labels == null)
257 {
258 Label l = new Label();
259 labels = new ArrayList(3);
260 labels.add(l);
261 if(mv != null)
262 {
263 mv.visitLabel(l);
264 }
265 }
266 for(int i = 0; i < labels.size(); ++i)
267 {
268 uninitializedTypes.put(labels.get(i), desc);
269 }
270 }
271 if(mv != null)
272 {
273 mv.visitTypeInsn(opcode, desc);
274 }
275 execute(opcode, 0, desc);
276 }
277
278 public void visitFieldInsn(
279 final int opcode,
280 final String owner,
281 final String name,
282 final String desc){
283 if(mv != null)
284 {
285 mv.visitFieldInsn(opcode, owner, name, desc);
286 }
287 execute(opcode, 0, desc);
288 }
289
290 public void visitMethodInsn(
291 final int opcode,
292 final String owner,
293 final String name,
294 final String desc){
295 if(mv != null)
296 {
297 mv.visitMethodInsn(opcode, owner, name, desc);
298 }
299 pop(desc);
300 if(opcode != Opcodes.INVOKESTATIC)
301 {
302 Object t = pop();
303 if(opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<')
304 {
305 Object u;
306 if(t == Opcodes.UNINITIALIZED_THIS)
307 {
308 u = owner;
309 }
310 else
311 {
312 u = uninitializedTypes.get(t);
313 }
314 for(int i = 0; i < locals.size(); ++i)
315 {
316 if(locals.get(i) == t)
317 {
318 locals.set(i, u);
319 }
320 }
321 for(int i = 0; i < stack.size(); ++i)
322 {
323 if(stack.get(i) == t)
324 {
325 stack.set(i, u);
326 }
327 }
328 }
329 }
330 pushDesc(desc);
331 labels = null;
332 }
333
334 public void visitJumpInsn(final int opcode, final Label label){
335 if(mv != null)
336 {
337 mv.visitJumpInsn(opcode, label);
338 }
339 execute(opcode, 0, null);
340 if(opcode == Opcodes.GOTO)
341 {
342 this.locals = null;
343 this.stack = null;
344 }
345 }
346
347 public void visitLabel(final Label label){
348 if(mv != null)
349 {
350 mv.visitLabel(label);
351 }
352 if(labels == null)
353 {
354 labels = new ArrayList(3);
355 }
356 labels.add(label);
357 }
358
359 public void visitLdcInsn(final Object cst){
360 if(mv != null)
361 {
362 mv.visitLdcInsn(cst);
363 }
364 if(cst instanceof Integer)
365 {
366 push(Opcodes.INTEGER);
367 }
368 else if(cst instanceof Long)
369 {
370 push(Opcodes.LONG);
371 push(Opcodes.TOP);
372 }
373 else if(cst instanceof Float)
374 {
375 push(Opcodes.FLOAT);
376 }
377 else if(cst instanceof Double)
378 {
379 push(Opcodes.DOUBLE);
380 push(Opcodes.TOP);
381 }
382 else if(cst instanceof String)
383 {
384 push("java/lang/String");
385 }
386 else if(cst instanceof Type)
387 {
388 push("java/lang/Class");
389 }
390 else
391 {
392 throw new IllegalArgumentException();
393 }
394 labels = null;
395 }
396
397 public void visitIincInsn(final int var, final int increment){
398 if(mv != null)
399 {
400 mv.visitIincInsn(var, increment);
401 }
402 execute(Opcodes.IINC, var, null);
403 }
404
405 public void visitTableSwitchInsn(
406 final int min,
407 final int max,
408 final Label dflt,
409 final Label labels[]){
410 if(mv != null)
411 {
412 mv.visitTableSwitchInsn(min, max, dflt, labels);
413 }
414 execute(Opcodes.TABLESWITCH, 0, null);
415 this.locals = null;
416 this.stack = null;
417 }
418
419 public void visitLookupSwitchInsn(
420 final Label dflt,
421 final int keys[],
422 final Label labels[]){
423 if(mv != null)
424 {
425 mv.visitLookupSwitchInsn(dflt, keys, labels);
426 }
427 execute(Opcodes.LOOKUPSWITCH, 0, null);
428 this.locals = null;
429 this.stack = null;
430 }
431
432 public void visitMultiANewArrayInsn(final String desc, final int dims){
433 if(mv != null)
434 {
435 mv.visitMultiANewArrayInsn(desc, dims);
436 }
437 execute(Opcodes.MULTIANEWARRAY, dims, desc);
438 }
439
440 public void visitMaxs(final int maxStack, final int maxLocals){
441 if(mv != null)
442 {
443 this.maxStack = Math.max(this.maxStack, maxStack);
444 this.maxLocals = Math.max(this.maxLocals, maxLocals);
445 mv.visitMaxs(this.maxStack, this.maxLocals);
446 }
447 }
448
449 // ------------------------------------------------------------------------
450
451 private Object get(final int local){
452 maxLocals = Math.max(maxLocals, local);
453 return local < locals.size() ? locals.get(local) : Opcodes.TOP;
454 }
455
456 private void set(final int local, final Object type){
457 maxLocals = Math.max(maxLocals, local);
458 while(local >= locals.size())
459 {
460 locals.add(Opcodes.TOP);
461 }
462 locals.set(local, type);
463 }
464
465 private void push(final Object type){
466 stack.add(type);
467 maxStack = Math.max(maxStack, stack.size());
468 }
469
470 private void pushDesc(final String desc){
471 int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
472 switch(desc.charAt(index))
473 {
474 case'V':
475 return;
476 case'Z':
477 case'C':
478 case'B':
479 case'S':
480 case'I':
481 push(Opcodes.INTEGER);
482 return;
483 case'F':
484 push(Opcodes.FLOAT);
485 return;
486 case'J':
487 push(Opcodes.LONG);
488 push(Opcodes.TOP);
489 return;
490 case'D':
491 push(Opcodes.DOUBLE);
492 push(Opcodes.TOP);
493 return;
494 case'[':
495 if(index == 0)
496 {
497 push(desc);
498 }
499 else
500 {
501 push(desc.substring(index, desc.length()));
502 }
503 break;
504 // case 'L':
505 default:
506 if(index == 0)
507 {
508 push(desc.substring(1, desc.length() - 1));
509 }
510 else
511 {
512 push(desc.substring(index + 1, desc.length() - 1));
513 }
514 return;
515 }
516 }
517
518 private Object pop(){
519 return stack.remove(stack.size() - 1);
520 }
521
522 private void pop(final int n){
523 int size = stack.size();
524 int end = size - n;
525 for(int i = size - 1; i >= end; --i)
526 {
527 stack.remove(i);
528 }
529 }
530
531 private void pop(final String desc){
532 char c = desc.charAt(0);
533 if(c == '(')
534 {
535 int n = 0;
536 Type[] types = Type.getArgumentTypes(desc);
537 for(int i = 0; i < types.length; ++i)
538 {
539 n += types[i].getSize();
540 }
541 pop(n);
542 }
543 else if(c == 'J' || c == 'D')
544 {
545 pop(2);
546 }
547 else
548 {
549 pop(1);
550 }
551 }
552
553 private void execute(final int opcode, final int iarg, final String sarg){
554 if(this.locals == null)
555 {
556 return;
557 }
558 Object t1, t2, t3, t4;
559 switch(opcode)
560 {
561 case Opcodes.NOP:
562 case Opcodes.INEG:
563 case Opcodes.LNEG:
564 case Opcodes.FNEG:
565 case Opcodes.DNEG:
566 case Opcodes.I2B:
567 case Opcodes.I2C:
568 case Opcodes.I2S:
569 case Opcodes.GOTO:
570 case Opcodes.RETURN:
571 break;
572 case Opcodes.ACONST_NULL:
573 push(Opcodes.NULL);
574 break;
575 case Opcodes.ICONST_M1:
576 case Opcodes.ICONST_0:
577 case Opcodes.ICONST_1:
578 case Opcodes.ICONST_2:
579 case Opcodes.ICONST_3:
580 case Opcodes.ICONST_4:
581 case Opcodes.ICONST_5:
582 case Opcodes.BIPUSH:
583 case Opcodes.SIPUSH:
584 push(Opcodes.INTEGER);
585 break;
586 case Opcodes.LCONST_0:
587 case Opcodes.LCONST_1:
588 push(Opcodes.LONG);
589 push(Opcodes.TOP);
590 break;
591 case Opcodes.FCONST_0:
592 case Opcodes.FCONST_1:
593 case Opcodes.FCONST_2:
594 push(Opcodes.FLOAT);
595 break;
596 case Opcodes.DCONST_0:
597 case Opcodes.DCONST_1:
598 push(Opcodes.DOUBLE);
599 push(Opcodes.TOP);
600 break;
601 case Opcodes.ILOAD:
602 case Opcodes.FLOAD:
603 case Opcodes.ALOAD:
604 push(get(iarg));
605 break;
606 case Opcodes.LLOAD:
607 case Opcodes.DLOAD:
608 push(get(iarg));
609 push(Opcodes.TOP);
610 break;
611 case Opcodes.IALOAD:
612 case Opcodes.BALOAD:
613 case Opcodes.CALOAD:
614 case Opcodes.SALOAD:
615 pop(2);
616 push(Opcodes.INTEGER);
617 break;
618 case Opcodes.LALOAD:
619 case Opcodes.D2L:
620 pop(2);
621 push(Opcodes.LONG);
622 push(Opcodes.TOP);
623 break;
624 case Opcodes.FALOAD:
625 pop(2);
626 push(Opcodes.FLOAT);
627 break;
628 case Opcodes.DALOAD:
629 case Opcodes.L2D:
630 pop(2);
631 push(Opcodes.DOUBLE);
632 push(Opcodes.TOP);
633 break;
634 case Opcodes.AALOAD:
635 pop(1);
636 t1 = pop();
637 pushDesc(((String) t1).substring(1));
638 break;
639 case Opcodes.ISTORE:
640 case Opcodes.FSTORE:
641 case Opcodes.ASTORE:
642 t1 = pop();
643 set(iarg, t1);
644 if(iarg > 0)
645 {
646 t2 = get(iarg - 1);
647 if(t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE)
648 {
649 set(iarg - 1, Opcodes.TOP);
650 }
651 }
652 break;
653 case Opcodes.LSTORE:
654 case Opcodes.DSTORE:
655 pop(1);
656 t1 = pop();
657 set(iarg, t1);
658 set(iarg + 1, Opcodes.TOP);
659 if(iarg > 0)
660 {
661 t2 = get(iarg - 1);
662 if(t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE)
663 {
664 set(iarg - 1, Opcodes.TOP);
665 }
666 }
667 break;
668 case Opcodes.IASTORE:
669 case Opcodes.BASTORE:
670 case Opcodes.CASTORE:
671 case Opcodes.SASTORE:
672 case Opcodes.FASTORE:
673 case Opcodes.AASTORE:
674 pop(3);
675 break;
676 case Opcodes.LASTORE:
677 case Opcodes.DASTORE:
678 pop(4);
679 break;
680 case Opcodes.POP:
681 case Opcodes.IFEQ:
682 case Opcodes.IFNE:
683 case Opcodes.IFLT:
684 case Opcodes.IFGE:
685 case Opcodes.IFGT:
686 case Opcodes.IFLE:
687 case Opcodes.IRETURN:
688 case Opcodes.FRETURN:
689 case Opcodes.ARETURN:
690 case Opcodes.TABLESWITCH:
691 case Opcodes.LOOKUPSWITCH:
692 case Opcodes.ATHROW:
693 case Opcodes.MONITORENTER:
694 case Opcodes.MONITOREXIT:
695 case Opcodes.IFNULL:
696 case Opcodes.IFNONNULL:
697 pop(1);
698 break;
699 case Opcodes.POP2:
700 case Opcodes.IF_ICMPEQ:
701 case Opcodes.IF_ICMPNE:
702 case Opcodes.IF_ICMPLT:
703 case Opcodes.IF_ICMPGE:
704 case Opcodes.IF_ICMPGT:
705 case Opcodes.IF_ICMPLE:
706 case Opcodes.IF_ACMPEQ:
707 case Opcodes.IF_ACMPNE:
708 case Opcodes.LRETURN:
709 case Opcodes.DRETURN:
710 pop(2);
711 break;
712 case Opcodes.DUP:
713 t1 = pop();
714 push(t1);
715 push(t1);
716 break;
717 case Opcodes.DUP_X1:
718 t1 = pop();
719 t2 = pop();
720 push(t1);
721 push(t2);
722 push(t1);
723 break;
724 case Opcodes.DUP_X2:
725 t1 = pop();
726 t2 = pop();
727 t3 = pop();
728 push(t1);
729 push(t3);
730 push(t2);
731 push(t1);
732 break;
733 case Opcodes.DUP2:
734 t1 = pop();
735 t2 = pop();
736 push(t2);
737 push(t1);
738 push(t2);
739 push(t1);
740 break;
741 case Opcodes.DUP2_X1:
742 t1 = pop();
743 t2 = pop();
744 t3 = pop();
745 push(t2);
746 push(t1);
747 push(t3);
748 push(t2);
749 push(t1);
750 break;
751 case Opcodes.DUP2_X2:
752 t1 = pop();
753 t2 = pop();
754 t3 = pop();
755 t4 = pop();
756 push(t2);
757 push(t1);
758 push(t4);
759 push(t3);
760 push(t2);
761 push(t1);
762 break;
763 case Opcodes.SWAP:
764 t1 = pop();
765 t2 = pop();
766 push(t1);
767 push(t2);
768 break;
769 case Opcodes.IADD:
770 case Opcodes.ISUB:
771 case Opcodes.IMUL:
772 case Opcodes.IDIV:
773 case Opcodes.IREM:
774 case Opcodes.IAND:
775 case Opcodes.IOR:
776 case Opcodes.IXOR:
777 case Opcodes.ISHL:
778 case Opcodes.ISHR:
779 case Opcodes.IUSHR:
780 case Opcodes.L2I:
781 case Opcodes.D2I:
782 case Opcodes.FCMPL:
783 case Opcodes.FCMPG:
784 pop(2);
785 push(Opcodes.INTEGER);
786 break;
787 case Opcodes.LADD:
788 case Opcodes.LSUB:
789 case Opcodes.LMUL:
790 case Opcodes.LDIV:
791 case Opcodes.LREM:
792 case Opcodes.LAND:
793 case Opcodes.LOR:
794 case Opcodes.LXOR:
795 pop(4);
796 push(Opcodes.LONG);
797 push(Opcodes.TOP);
798 break;
799 case Opcodes.FADD:
800 case Opcodes.FSUB:
801 case Opcodes.FMUL:
802 case Opcodes.FDIV:
803 case Opcodes.FREM:
804 case Opcodes.L2F:
805 case Opcodes.D2F:
806 pop(2);
807 push(Opcodes.FLOAT);
808 break;
809 case Opcodes.DADD:
810 case Opcodes.DSUB:
811 case Opcodes.DMUL:
812 case Opcodes.DDIV:
813 case Opcodes.DREM:
814 pop(4);
815 push(Opcodes.DOUBLE);
816 push(Opcodes.TOP);
817 break;
818 case Opcodes.LSHL:
819 case Opcodes.LSHR:
820 case Opcodes.LUSHR:
821 pop(3);
822 push(Opcodes.LONG);
823 push(Opcodes.TOP);
824 break;
825 case Opcodes.IINC:
826 set(iarg, Opcodes.INTEGER);
827 break;
828 case Opcodes.I2L:
829 case Opcodes.F2L:
830 pop(1);
831 push(Opcodes.LONG);
832 push(Opcodes.TOP);
833 break;
834 case Opcodes.I2F:
835 pop(1);
836 push(Opcodes.FLOAT);
837 break;
838 case Opcodes.I2D:
839 case Opcodes.F2D:
840 pop(1);
841 push(Opcodes.DOUBLE);
842 push(Opcodes.TOP);
843 break;
844 case Opcodes.F2I:
845 case Opcodes.ARRAYLENGTH:
846 case Opcodes.INSTANCEOF:
847 pop(1);
848 push(Opcodes.INTEGER);
849 break;
850 case Opcodes.LCMP:
851 case Opcodes.DCMPL:
852 case Opcodes.DCMPG:
853 pop(4);
854 push(Opcodes.INTEGER);
855 break;
856 case Opcodes.JSR:
857 case Opcodes.RET:
858 throw new RuntimeException("JSR/RET are not supported");
859 case Opcodes.GETSTATIC:
860 pushDesc(sarg);
861 break;
862 case Opcodes.PUTSTATIC:
863 pop(sarg);
864 break;
865 case Opcodes.GETFIELD:
866 pop(1);
867 pushDesc(sarg);
868 break;
869 case Opcodes.PUTFIELD:
870 pop(sarg);
871 pop();
872 break;
873 case Opcodes.NEW:
874 push(labels.get(0));
875 break;
876 case Opcodes.NEWARRAY:
877 pop();
878 switch(iarg)
879 {
880 case Opcodes.T_BOOLEAN:
881 pushDesc("[Z");
882 break;
883 case Opcodes.T_CHAR:
884 pushDesc("[C");
885 break;
886 case Opcodes.T_BYTE:
887 pushDesc("[B");
888 break;
889 case Opcodes.T_SHORT:
890 pushDesc("[S");
891 break;
892 case Opcodes.T_INT:
893 pushDesc("[I");
894 break;
895 case Opcodes.T_FLOAT:
896 pushDesc("[F");
897 break;
898 case Opcodes.T_DOUBLE:
899 pushDesc("[D");
900 break;
901 // case Opcodes.T_LONG:
902 default:
903 pushDesc("[J");
904 break;
905 }
906 break;
907 case Opcodes.ANEWARRAY:
908 pop();
909 if(sarg.charAt(0) == '[')
910 {
911 pushDesc("[" + sarg);
912 }
913 else
914 {
915 pushDesc("[L" + sarg + ";");
916 }
917 break;
918 case Opcodes.CHECKCAST:
919 pop();
920 if(sarg.charAt(0) == '[')
921 {
922 pushDesc(sarg);
923 }
924 else
925 {
926 push(sarg);
927 }
928 break;
929 // case Opcodes.MULTIANEWARRAY:
930 default:
931 pop(iarg);
932 pushDesc(sarg);
933 break;
934 }
935 labels = null;
936 }
937 }
+0
-234
src/jvm/clojure/asm/commons/CodeSizeEvaluator.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm.commons;
30
31 import clojure.asm.Label;
32 import clojure.asm.MethodAdapter;
33 import clojure.asm.MethodVisitor;
34 import clojure.asm.Opcodes;
35
36 /**
37 * A {@link MethodAdapter} that can be used to approximate method size.
38 *
39 * @author Eugene Kuleshov
40 */
41 public class CodeSizeEvaluator extends MethodAdapter implements Opcodes{
42
43 private int minSize;
44
45 private int maxSize;
46
47 public CodeSizeEvaluator(final MethodVisitor mv){
48 super(mv);
49 }
50
51 public int getMinSize(){
52 return this.minSize;
53 }
54
55 public int getMaxSize(){
56 return this.maxSize;
57 }
58
59 public void visitInsn(final int opcode){
60 minSize += 1;
61 maxSize += 1;
62 if(mv != null)
63 {
64 mv.visitInsn(opcode);
65 }
66 }
67
68 public void visitIntInsn(final int opcode, final int operand){
69 if(opcode == SIPUSH)
70 {
71 minSize += 3;
72 maxSize += 3;
73 }
74 else
75 {
76 minSize += 2;
77 maxSize += 2;
78 }
79 if(mv != null)
80 {
81 mv.visitIntInsn(opcode, operand);
82 }
83 }
84
85 public void visitVarInsn(final int opcode, final int var){
86 if(var < 4 && opcode != Opcodes.RET)
87 {
88 minSize += 1;
89 maxSize += 1;
90 }
91 else if(var >= 256)
92 {
93 minSize += 4;
94 maxSize += 4;
95 }
96 else
97 {
98 minSize += 2;
99 maxSize += 2;
100 }
101 if(mv != null)
102 {
103 mv.visitVarInsn(opcode, var);
104 }
105 }
106
107 public void visitTypeInsn(final int opcode, final String desc){
108 minSize += 3;
109 maxSize += 3;
110 if(mv != null)
111 {
112 mv.visitTypeInsn(opcode, desc);
113 }
114 }
115
116 public void visitFieldInsn(
117 final int opcode,
118 final String owner,
119 final String name,
120 final String desc){
121 minSize += 3;
122 maxSize += 3;
123 if(mv != null)
124 {
125 mv.visitFieldInsn(opcode, owner, name, desc);
126 }
127 }
128
129 public void visitMethodInsn(
130 final int opcode,
131 final String owner,
132 final String name,
133 final String desc){
134 if(opcode == INVOKEINTERFACE)
135 {
136 minSize += 5;
137 maxSize += 5;
138 }
139 else
140 {
141 minSize += 3;
142 maxSize += 3;
143 }
144 if(mv != null)
145 {
146 mv.visitMethodInsn(opcode, owner, name, desc);
147 }
148 }
149
150 public void visitJumpInsn(final int opcode, final Label label){
151 minSize += 3;
152 if(opcode == GOTO || opcode == JSR)
153 {
154 maxSize += 5;
155 }
156 else
157 {
158 maxSize += 8;
159 }
160 if(mv != null)
161 {
162 mv.visitJumpInsn(opcode, label);
163 }
164 }
165
166 public void visitLdcInsn(final Object cst){
167 if(cst instanceof Long || cst instanceof Double)
168 {
169 minSize += 3;
170 maxSize += 3;
171 }
172 else
173 {
174 minSize += 2;
175 maxSize += 3;
176 }
177 if(mv != null)
178 {
179 mv.visitLdcInsn(cst);
180 }
181 }
182
183 public void visitIincInsn(final int var, final int increment){
184 if(var > 255 || increment > 127 || increment < -128)
185 {
186 minSize += 6;
187 maxSize += 6;
188 }
189 else
190 {
191 minSize += 3;
192 maxSize += 3;
193 }
194 if(mv != null)
195 {
196 mv.visitIincInsn(var, increment);
197 }
198 }
199
200 public void visitTableSwitchInsn(
201 final int min,
202 final int max,
203 final Label dflt,
204 final Label[] labels){
205 minSize += 13 + labels.length * 4;
206 maxSize += 16 + labels.length * 4;
207 if(mv != null)
208 {
209 mv.visitTableSwitchInsn(min, max, dflt, labels);
210 }
211 }
212
213 public void visitLookupSwitchInsn(
214 final Label dflt,
215 final int[] keys,
216 final Label[] labels){
217 minSize += 9 + keys.length * 8;
218 maxSize += 12 + keys.length * 8;
219 if(mv != null)
220 {
221 mv.visitLookupSwitchInsn(dflt, keys, labels);
222 }
223 }
224
225 public void visitMultiANewArrayInsn(final String desc, final int dims){
226 minSize += 4;
227 maxSize += 4;
228 if(mv != null)
229 {
230 mv.visitMultiANewArrayInsn(desc, dims);
231 }
232 }
233 }
+0
-221
src/jvm/clojure/asm/commons/EmptyVisitor.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm.commons;
30
31 import clojure.asm.AnnotationVisitor;
32 import clojure.asm.Attribute;
33 import clojure.asm.ClassVisitor;
34 import clojure.asm.FieldVisitor;
35 import clojure.asm.Label;
36 import clojure.asm.MethodVisitor;
37
38 /**
39 * An empty implementation of the ASM visitor interfaces.
40 *
41 * @author Eric Bruneton
42 */
43 public class EmptyVisitor implements
44 ClassVisitor,
45 FieldVisitor,
46 MethodVisitor,
47 AnnotationVisitor{
48
49 public void visit(
50 final int version,
51 final int access,
52 final String name,
53 final String signature,
54 final String superName,
55 final String[] interfaces){
56 }
57
58 public void visitSource(final String source, final String debug){
59 }
60
61 public void visitOuterClass(
62 final String owner,
63 final String name,
64 final String desc){
65 }
66
67 public AnnotationVisitor visitAnnotation(
68 final String desc,
69 final boolean visible){
70 return this;
71 }
72
73 public void visitAttribute(final Attribute attr){
74 }
75
76 public void visitInnerClass(
77 final String name,
78 final String outerName,
79 final String innerName,
80 final int access){
81 }
82
83 public FieldVisitor visitField(
84 final int access,
85 final String name,
86 final String desc,
87 final String signature,
88 final Object value){
89 return this;
90 }
91
92 public MethodVisitor visitMethod(
93 final int access,
94 final String name,
95 final String desc,
96 final String signature,
97 final String[] exceptions){
98 return this;
99 }
100
101 public void visitEnd(){
102 }
103
104 public AnnotationVisitor visitAnnotationDefault(){
105 return this;
106 }
107
108 public AnnotationVisitor visitParameterAnnotation(
109 final int parameter,
110 final String desc,
111 final boolean visible){
112 return this;
113 }
114
115 public void visitCode(){
116 }
117
118 public void visitFrame(
119 final int type,
120 final int nLocal,
121 final Object[] local,
122 final int nStack,
123 final Object[] stack){
124 }
125
126 public void visitInsn(final int opcode){
127 }
128
129 public void visitIntInsn(final int opcode, final int operand){
130 }
131
132 public void visitVarInsn(final int opcode, final int var){
133 }
134
135 public void visitTypeInsn(final int opcode, final String desc){
136 }
137
138 public void visitFieldInsn(
139 final int opcode,
140 final String owner,
141 final String name,
142 final String desc){
143 }
144
145 public void visitMethodInsn(
146 final int opcode,
147 final String owner,
148 final String name,
149 final String desc){
150 }
151
152 public void visitJumpInsn(final int opcode, final Label label){
153 }
154
155 public void visitLabel(final Label label){
156 }
157
158 public void visitLdcInsn(final Object cst){
159 }
160
161 public void visitIincInsn(final int var, final int increment){
162 }
163
164 public void visitTableSwitchInsn(
165 final int min,
166 final int max,
167 final Label dflt,
168 final Label labels[]){
169 }
170
171 public void visitLookupSwitchInsn(
172 final Label dflt,
173 final int keys[],
174 final Label labels[]){
175 }
176
177 public void visitMultiANewArrayInsn(final String desc, final int dims){
178 }
179
180 public void visitTryCatchBlock(
181 final Label start,
182 final Label end,
183 final Label handler,
184 final String type){
185 }
186
187 public void visitLocalVariable(
188 final String name,
189 final String desc,
190 final String signature,
191 final Label start,
192 final Label end,
193 final int index){
194 }
195
196 public void visitLineNumber(final int line, final Label start){
197 }
198
199 public void visitMaxs(final int maxStack, final int maxLocals){
200 }
201
202 public void visit(final String name, final Object value){
203 }
204
205 public void visitEnum(
206 final String name,
207 final String desc,
208 final String value){
209 }
210
211 public AnnotationVisitor visitAnnotation(
212 final String name,
213 final String desc){
214 return this;
215 }
216
217 public AnnotationVisitor visitArray(final String name){
218 return this;
219 }
220 }
+0
-1533
src/jvm/clojure/asm/commons/GeneratorAdapter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm.commons;
30
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.List;
34
35 import clojure.asm.ClassVisitor;
36 import clojure.asm.Label;
37 import clojure.asm.MethodVisitor;
38 import clojure.asm.Opcodes;
39 import clojure.asm.Type;
40
41 /**
42 * A {@link clojure.asm.MethodAdapter} with convenient methods to generate
43 * code. For example, using this adapter, the class below
44 * <p/>
45 * <pre>
46 * public class Example {
47 * public static void main(String[] args) {
48 * System.out.println(&quot;Hello world!&quot;);
49 * }
50 * }
51 * </pre>
52 * <p/>
53 * can be generated as follows:
54 * <p/>
55 * <pre>
56 * ClassWriter cw = new ClassWriter(true);
57 * cw.visit(V1_1, ACC_PUBLIC, &quot;Example&quot;, null, &quot;java/lang/Object&quot;, null);
58 * <p/>
59 * Method m = Method.getMethod(&quot;void &lt;init&gt; ()&quot;);
60 * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
61 * mg.loadThis();
62 * mg.invokeConstructor(Type.getType(Object.class), m);
63 * mg.returnValue();
64 * mg.endMethod();
65 * <p/>
66 * m = Method.getMethod(&quot;void main (String[])&quot;);
67 * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
68 * mg.getStatic(Type.getType(System.class), &quot;out&quot;, Type.getType(PrintStream.class));
69 * mg.push(&quot;Hello world!&quot;);
70 * mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod(&quot;void println (String)&quot;));
71 * mg.returnValue();
72 * mg.endMethod();
73 * <p/>
74 * cw.visitEnd();
75 * </pre>
76 *
77 * @author Juozas Baliuka
78 * @author Chris Nokleberg
79 * @author Eric Bruneton
80 */
81 public class GeneratorAdapter extends LocalVariablesSorter{
82
83 private final static Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
84
85 private final static Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
86
87 private final static Type SHORT_TYPE = Type.getObjectType("java/lang/Short");
88
89 private final static Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character");
90
91 private final static Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer");
92
93 private final static Type FLOAT_TYPE = Type.getObjectType("java/lang/Float");
94
95 private final static Type LONG_TYPE = Type.getObjectType("java/lang/Long");
96
97 private final static Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double");
98
99 private final static Type NUMBER_TYPE = Type.getObjectType("java/lang/Number");
100
101 private final static Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
102
103 private final static Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");
104
105 private final static Method CHAR_VALUE = Method.getMethod("char charValue()");
106
107 private final static Method INT_VALUE = Method.getMethod("int intValue()");
108
109 private final static Method FLOAT_VALUE = Method.getMethod("float floatValue()");
110
111 private final static Method LONG_VALUE = Method.getMethod("long longValue()");
112
113 private final static Method DOUBLE_VALUE = Method.getMethod("double doubleValue()");
114
115 /**
116 * Constant for the {@link #math math} method.
117 */
118 public final static int ADD = Opcodes.IADD;
119
120 /**
121 * Constant for the {@link #math math} method.
122 */
123 public final static int SUB = Opcodes.ISUB;
124
125 /**
126 * Constant for the {@link #math math} method.
127 */
128 public final static int MUL = Opcodes.IMUL;
129
130 /**
131 * Constant for the {@link #math math} method.
132 */
133 public final static int DIV = Opcodes.IDIV;
134
135 /**
136 * Constant for the {@link #math math} method.
137 */
138 public final static int REM = Opcodes.IREM;
139
140 /**
141 * Constant for the {@link #math math} method.
142 */
143 public final static int NEG = Opcodes.INEG;
144
145 /**
146 * Constant for the {@link #math math} method.
147 */
148 public final static int SHL = Opcodes.ISHL;
149
150 /**
151 * Constant for the {@link #math math} method.
152 */
153 public final static int SHR = Opcodes.ISHR;
154
155 /**
156 * Constant for the {@link #math math} method.
157 */
158 public final static int USHR = Opcodes.IUSHR;
159
160 /**
161 * Constant for the {@link #math math} method.
162 */
163 public final static int AND = Opcodes.IAND;
164
165 /**
166 * Constant for the {@link #math math} method.
167 */
168 public final static int OR = Opcodes.IOR;
169
170 /**
171 * Constant for the {@link #math math} method.
172 */
173 public final static int XOR = Opcodes.IXOR;
174
175 /**
176 * Constant for the {@link #ifCmp ifCmp} method.
177 */
178 public final static int EQ = Opcodes.IFEQ;
179
180 /**
181 * Constant for the {@link #ifCmp ifCmp} method.
182 */
183 public final static int NE = Opcodes.IFNE;
184
185 /**
186 * Constant for the {@link #ifCmp ifCmp} method.
187 */
188 public final static int LT = Opcodes.IFLT;
189
190 /**
191 * Constant for the {@link #ifCmp ifCmp} method.
192 */
193 public final static int GE = Opcodes.IFGE;
194
195 /**
196 * Constant for the {@link #ifCmp ifCmp} method.
197 */
198 public final static int GT = Opcodes.IFGT;
199
200 /**
201 * Constant for the {@link #ifCmp ifCmp} method.
202 */
203 public final static int LE = Opcodes.IFLE;
204
205 /**
206 * Access flags of the method visited by this adapter.
207 */
208 private final int access;
209
210 /**
211 * Return type of the method visited by this adapter.
212 */
213 private final Type returnType;
214
215 /**
216 * Argument types of the method visited by this adapter.
217 */
218 private final Type[] argumentTypes;
219
220 /**
221 * Types of the local variables of the method visited by this adapter.
222 */
223 private final List localTypes = new ArrayList();
224
225 /**
226 * Creates a new {@link GeneratorAdapter}.
227 *
228 * @param mv the method visitor to which this adapter delegates calls.
229 * @param access the method's access flags (see {@link Opcodes}).
230 * @param name the method's name.
231 * @param desc the method's descriptor (see {@link Type Type}).
232 */
233 public GeneratorAdapter(
234 final MethodVisitor mv,
235 final int access,
236 final String name,
237 final String desc){
238 super(access, desc, mv);
239 this.access = access;
240 this.returnType = Type.getReturnType(desc);
241 this.argumentTypes = Type.getArgumentTypes(desc);
242 }
243
244 /**
245 * Creates a new {@link GeneratorAdapter}.
246 *
247 * @param access access flags of the adapted method.
248 * @param method the adapted method.
249 * @param mv the method visitor to which this adapter delegates calls.
250 */
251 public GeneratorAdapter(
252 final int access,
253 final Method method,
254 final MethodVisitor mv){
255 super(access, method.getDescriptor(), mv);
256 this.access = access;
257 this.returnType = method.getReturnType();
258 this.argumentTypes = method.getArgumentTypes();
259 }
260
261 /**
262 * Creates a new {@link GeneratorAdapter}.
263 *
264 * @param access access flags of the adapted method.
265 * @param method the adapted method.
266 * @param signature the signature of the adapted method (may be
267 * <tt>null</tt>).
268 * @param exceptions the exceptions thrown by the adapted method (may be
269 * <tt>null</tt>).
270 * @param cv the class visitor to which this adapter delegates calls.
271 */
272 public GeneratorAdapter(
273 final int access,
274 final Method method,
275 final String signature,
276 final Type[] exceptions,
277 final ClassVisitor cv){
278 this(access, method, cv.visitMethod(access,
279 method.getName(),
280 method.getDescriptor(),
281 signature,
282 getInternalNames(exceptions)));
283 }
284
285 /**
286 * Returns the internal names of the given types.
287 *
288 * @param types a set of types.
289 * @return the internal names of the given types.
290 */
291 private static String[] getInternalNames(final Type[] types){
292 if(types == null)
293 {
294 return null;
295 }
296 String[] names = new String[types.length];
297 for(int i = 0; i < names.length; ++i)
298 {
299 names[i] = types[i].getInternalName();
300 }
301 return names;
302 }
303
304 // ------------------------------------------------------------------------
305 // Instructions to push constants on the stack
306 // ------------------------------------------------------------------------
307
308 /**
309 * Generates the instruction to push the given value on the stack.
310 *
311 * @param value the value to be pushed on the stack.
312 */
313 public void push(final boolean value){
314 push(value ? 1 : 0);
315 }
316
317 /**
318 * Generates the instruction to push the given value on the stack.
319 *
320 * @param value the value to be pushed on the stack.
321 */
322 public void push(final int value){
323 if(value >= -1 && value <= 5)
324 {
325 mv.visitInsn(Opcodes.ICONST_0 + value);
326 }
327 else if(value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)
328 {
329 mv.visitIntInsn(Opcodes.BIPUSH, value);
330 }
331 else if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
332 {
333 mv.visitIntInsn(Opcodes.SIPUSH, value);
334 }
335 else
336 {
337 mv.visitLdcInsn(new Integer(value));
338 }
339 }
340
341 /**
342 * Generates the instruction to push the given value on the stack.
343 *
344 * @param value the value to be pushed on the stack.
345 */
346 public void push(final long value){
347 if(value == 0L || value == 1L)
348 {
349 mv.visitInsn(Opcodes.LCONST_0 + (int) value);
350 }
351 else
352 {
353 mv.visitLdcInsn(new Long(value));
354 }
355 }
356
357 /**
358 * Generates the instruction to push the given value on the stack.
359 *
360 * @param value the value to be pushed on the stack.
361 */
362 public void push(final float value){
363 int bits = Float.floatToIntBits(value);
364 if(bits == 0L || bits == 0x3f800000 || bits == 0x40000000)
365 { // 0..2
366 mv.visitInsn(Opcodes.FCONST_0 + (int) value);
367 }
368 else
369 {
370 mv.visitLdcInsn(new Float(value));
371 }
372 }
373
374 /**
375 * Generates the instruction to push the given value on the stack.
376 *
377 * @param value the value to be pushed on the stack.
378 */
379 public void push(final double value){
380 long bits = Double.doubleToLongBits(value);
381 if(bits == 0L || bits == 0x3ff0000000000000L)
382 { // +0.0d and 1.0d
383 mv.visitInsn(Opcodes.DCONST_0 + (int) value);
384 }
385 else
386 {
387 mv.visitLdcInsn(new Double(value));
388 }
389 }
390
391 /**
392 * Generates the instruction to push the given value on the stack.
393 *
394 * @param value the value to be pushed on the stack. May be <tt>null</tt>.
395 */
396 public void push(final String value){
397 if(value == null)
398 {
399 mv.visitInsn(Opcodes.ACONST_NULL);
400 }
401 else
402 {
403 mv.visitLdcInsn(value);
404 }
405 }
406
407 /**
408 * Generates the instruction to push the given value on the stack.
409 *
410 * @param value the value to be pushed on the stack.
411 */
412 public void push(final Type value){
413 if(value == null)
414 {
415 mv.visitInsn(Opcodes.ACONST_NULL);
416 }
417 else
418 {
419 mv.visitLdcInsn(value);
420 }
421 }
422
423 // ------------------------------------------------------------------------
424 // Instructions to load and store method arguments
425 // ------------------------------------------------------------------------
426
427 /**
428 * Returns the index of the given method argument in the frame's local
429 * variables array.
430 *
431 * @param arg the index of a method argument.
432 * @return the index of the given method argument in the frame's local
433 * variables array.
434 */
435 private int getArgIndex(final int arg){
436 int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
437 for(int i = 0; i < arg; i++)
438 {
439 index += argumentTypes[i].getSize();
440 }
441 return index;
442 }
443
444 /**
445 * Generates the instruction to push a local variable on the stack.
446 *
447 * @param type the type of the local variable to be loaded.
448 * @param index an index in the frame's local variables array.
449 */
450 private void loadInsn(final Type type, final int index){
451 mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
452 }
453
454 /**
455 * Generates the instruction to store the top stack value in a local
456 * variable.
457 *
458 * @param type the type of the local variable to be stored.
459 * @param index an index in the frame's local variables array.
460 */
461 private void storeInsn(final Type type, final int index){
462 mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
463 }
464
465 /**
466 * Generates the instruction to load 'this' on the stack.
467 */
468 public void loadThis(){
469 if((access & Opcodes.ACC_STATIC) != 0)
470 {
471 throw new IllegalStateException("no 'this' pointer within static method");
472 }
473 mv.visitVarInsn(Opcodes.ALOAD, 0);
474 }
475
476 /**
477 * Generates the instruction to load the given method argument on the stack.
478 *
479 * @param arg the index of a method argument.
480 */
481 public void loadArg(final int arg){
482 loadInsn(argumentTypes[arg], getArgIndex(arg));
483 }
484
485 /**
486 * Generates the instructions to load the given method arguments on the
487 * stack.
488 *
489 * @param arg the index of the first method argument to be loaded.
490 * @param count the number of method arguments to be loaded.
491 */
492 public void loadArgs(final int arg, final int count){
493 int index = getArgIndex(arg);
494 for(int i = 0; i < count; ++i)
495 {
496 Type t = argumentTypes[arg + i];
497 loadInsn(t, index);
498 index += t.getSize();
499 }
500 }
501
502 /**
503 * Generates the instructions to load all the method arguments on the stack.
504 */
505 public void loadArgs(){
506 loadArgs(0, argumentTypes.length);
507 }
508
509 /**
510 * Generates the instructions to load all the method arguments on the stack,
511 * as a single object array.
512 */
513 public void loadArgArray(){
514 push(argumentTypes.length);
515 newArray(OBJECT_TYPE);
516 for(int i = 0; i < argumentTypes.length; i++)
517 {
518 dup();
519 push(i);
520 loadArg(i);
521 box(argumentTypes[i]);
522 arrayStore(OBJECT_TYPE);
523 }
524 }
525
526 /**
527 * Generates the instruction to store the top stack value in the given
528 * method argument.
529 *
530 * @param arg the index of a method argument.
531 */
532 public void storeArg(final int arg){
533 storeInsn(argumentTypes[arg], getArgIndex(arg));
534 }
535
536 // ------------------------------------------------------------------------
537 // Instructions to load and store local variables
538 // ------------------------------------------------------------------------
539
540 /**
541 * Returns the type of the given local variable.
542 *
543 * @param local a local variable identifier, as returned by
544 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
545 * @return the type of the given local variable.
546 */
547 public Type getLocalType(final int local){
548 return (Type) localTypes.get(local - firstLocal);
549 }
550
551 protected void setLocalType(final int local, final Type type){
552 int index = local - firstLocal;
553 while(localTypes.size() < index + 1)
554 {
555 localTypes.add(null);
556 }
557 localTypes.set(index, type);
558 }
559
560 /**
561 * Generates the instruction to load the given local variable on the stack.
562 *
563 * @param local a local variable identifier, as returned by
564 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
565 */
566 public void loadLocal(final int local){
567 loadInsn(getLocalType(local), local);
568 }
569
570 /**
571 * Generates the instruction to load the given local variable on the stack.
572 *
573 * @param local a local variable identifier, as returned by
574 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
575 * @param type the type of this local variable.
576 */
577 public void loadLocal(final int local, final Type type){
578 setLocalType(local, type);
579 loadInsn(type, local);
580 }
581
582 /**
583 * Generates the instruction to store the top stack value in the given local
584 * variable.
585 *
586 * @param local a local variable identifier, as returned by
587 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
588 */
589 public void storeLocal(final int local){
590 storeInsn(getLocalType(local), local);
591 }
592
593 /**
594 * Generates the instruction to store the top stack value in the given local
595 * variable.
596 *
597 * @param local a local variable identifier, as returned by
598 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
599 * @param type the type of this local variable.
600 */
601 public void storeLocal(final int local, final Type type){
602 setLocalType(local, type);
603 storeInsn(type, local);
604 }
605
606 /**
607 * Generates the instruction to load an element from an array.
608 *
609 * @param type the type of the array element to be loaded.
610 */
611 public void arrayLoad(final Type type){
612 mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
613 }
614
615 /**
616 * Generates the instruction to store an element in an array.
617 *
618 * @param type the type of the array element to be stored.
619 */
620 public void arrayStore(final Type type){
621 mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
622 }
623
624 // ------------------------------------------------------------------------
625 // Instructions to manage the stack
626 // ------------------------------------------------------------------------
627
628 /**
629 * Generates a POP instruction.
630 */
631 public void pop(){
632 mv.visitInsn(Opcodes.POP);
633 }
634
635 /**
636 * Generates a POP2 instruction.
637 */
638 public void pop2(){
639 mv.visitInsn(Opcodes.POP2);
640 }
641
642 /**
643 * Generates a DUP instruction.
644 */
645 public void dup(){
646 mv.visitInsn(Opcodes.DUP);
647 }
648
649 /**
650 * Generates a DUP2 instruction.
651 */
652 public void dup2(){
653 mv.visitInsn(Opcodes.DUP2);
654 }
655
656 /**
657 * Generates a DUP_X1 instruction.
658 */
659 public void dupX1(){
660 mv.visitInsn(Opcodes.DUP_X1);
661 }
662
663 /**
664 * Generates a DUP_X2 instruction.
665 */
666 public void dupX2(){
667 mv.visitInsn(Opcodes.DUP_X2);
668 }
669
670 /**
671 * Generates a DUP2_X1 instruction.
672 */
673 public void dup2X1(){
674 mv.visitInsn(Opcodes.DUP2_X1);
675 }
676
677 /**
678 * Generates a DUP2_X2 instruction.
679 */
680 public void dup2X2(){
681 mv.visitInsn(Opcodes.DUP2_X2);
682 }
683
684 /**
685 * Generates a SWAP instruction.
686 */
687 public void swap(){
688 mv.visitInsn(Opcodes.SWAP);
689 }
690
691 /**
692 * Generates the instructions to swap the top two stack values.
693 *
694 * @param prev type of the top - 1 stack value.
695 * @param type type of the top stack value.
696 */
697 public void swap(final Type prev, final Type type){
698 if(type.getSize() == 1)
699 {
700 if(prev.getSize() == 1)
701 {
702 swap(); // same as dupX1(), pop();
703 }
704 else
705 {
706 dupX2();
707 pop();
708 }
709 }
710 else
711 {
712 if(prev.getSize() == 1)
713 {
714 dup2X1();
715 pop2();
716 }
717 else
718 {
719 dup2X2();
720 pop2();
721 }
722 }
723 }
724
725 // ------------------------------------------------------------------------
726 // Instructions to do mathematical and logical operations
727 // ------------------------------------------------------------------------
728
729 /**
730 * Generates the instruction to do the specified mathematical or logical
731 * operation.
732 *
733 * @param op a mathematical or logical operation. Must be one of ADD, SUB,
734 * MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR.
735 * @param type the type of the operand(s) for this operation.
736 */
737 public void math(final int op, final Type type){
738 mv.visitInsn(type.getOpcode(op));
739 }
740
741 /**
742 * Generates the instructions to compute the bitwise negation of the top
743 * stack value.
744 */
745 public void not(){
746 mv.visitInsn(Opcodes.ICONST_1);
747 mv.visitInsn(Opcodes.IXOR);
748 }
749
750 /**
751 * Generates the instruction to increment the given local variable.
752 *
753 * @param local the local variable to be incremented.
754 * @param amount the amount by which the local variable must be incremented.
755 */
756 public void iinc(final int local, final int amount){
757 mv.visitIincInsn(local, amount);
758 }
759
760 /**
761 * Generates the instructions to cast a numerical value from one type to
762 * another.
763 *
764 * @param from the type of the top stack value
765 * @param to the type into which this value must be cast.
766 */
767 public void cast(final Type from, final Type to){
768 if(from != to)
769 {
770 if(from == Type.DOUBLE_TYPE)
771 {
772 if(to == Type.FLOAT_TYPE)
773 {
774 mv.visitInsn(Opcodes.D2F);
775 }
776 else if(to == Type.LONG_TYPE)
777 {
778 mv.visitInsn(Opcodes.D2L);
779 }
780 else
781 {
782 mv.visitInsn(Opcodes.D2I);
783 cast(Type.INT_TYPE, to);
784 }
785 }
786 else if(from == Type.FLOAT_TYPE)
787 {
788 if(to == Type.DOUBLE_TYPE)
789 {
790 mv.visitInsn(Opcodes.F2D);
791 }
792 else if(to == Type.LONG_TYPE)
793 {
794 mv.visitInsn(Opcodes.F2L);
795 }
796 else
797 {
798 mv.visitInsn(Opcodes.F2I);
799 cast(Type.INT_TYPE, to);
800 }
801 }
802 else if(from == Type.LONG_TYPE)
803 {
804 if(to == Type.DOUBLE_TYPE)
805 {
806 mv.visitInsn(Opcodes.L2D);
807 }
808 else if(to == Type.FLOAT_TYPE)
809 {
810 mv.visitInsn(Opcodes.L2F);
811 }
812 else
813 {
814 mv.visitInsn(Opcodes.L2I);
815 cast(Type.INT_TYPE, to);
816 }
817 }
818 else
819 {
820 if(to == Type.BYTE_TYPE)
821 {
822 mv.visitInsn(Opcodes.I2B);
823 }
824 else if(to == Type.CHAR_TYPE)
825 {
826 mv.visitInsn(Opcodes.I2C);
827 }
828 else if(to == Type.DOUBLE_TYPE)
829 {
830 mv.visitInsn(Opcodes.I2D);
831 }
832 else if(to == Type.FLOAT_TYPE)
833 {
834 mv.visitInsn(Opcodes.I2F);
835 }
836 else if(to == Type.LONG_TYPE)
837 {
838 mv.visitInsn(Opcodes.I2L);
839 }
840 else if(to == Type.SHORT_TYPE)
841 {
842 mv.visitInsn(Opcodes.I2S);
843 }
844 }
845 }
846 }
847
848 // ------------------------------------------------------------------------
849 // Instructions to do boxing and unboxing operations
850 // ------------------------------------------------------------------------
851
852 /**
853 * Generates the instructions to box the top stack value. This value is
854 * replaced by its boxed equivalent on top of the stack.
855 *
856 * @param type the type of the top stack value.
857 */
858 public void box(final Type type){
859 if(type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY)
860 {
861 return;
862 }
863 if(type == Type.VOID_TYPE)
864 {
865 push((String) null);
866 }
867 else
868 {
869 Type boxed = type;
870 switch(type.getSort())
871 {
872 case Type.BYTE:
873 boxed = BYTE_TYPE;
874 break;
875 case Type.BOOLEAN:
876 boxed = BOOLEAN_TYPE;
877 break;
878 case Type.SHORT:
879 boxed = SHORT_TYPE;
880 break;
881 case Type.CHAR:
882 boxed = CHARACTER_TYPE;
883 break;
884 case Type.INT:
885 boxed = INTEGER_TYPE;
886 break;
887 case Type.FLOAT:
888 boxed = FLOAT_TYPE;
889 break;
890 case Type.LONG:
891 boxed = LONG_TYPE;
892 break;
893 case Type.DOUBLE:
894 boxed = DOUBLE_TYPE;
895 break;
896 }
897 newInstance(boxed);
898 if(type.getSize() == 2)
899 {
900 // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
901 dupX2();
902 dupX2();
903 pop();
904 }
905 else
906 {
907 // p -> po -> opo -> oop -> o
908 dupX1();
909 swap();
910 }
911 invokeConstructor(boxed, new Method("<init>",
912 Type.VOID_TYPE,
913 new Type[]{type}));
914 }
915 }
916
917 /**
918 * Generates the instructions to unbox the top stack value. This value is
919 * replaced by its unboxed equivalent on top of the stack.
920 *
921 * @param type the type of the top stack value.
922 */
923 public void unbox(final Type type){
924 Type t = NUMBER_TYPE;
925 Method sig = null;
926 switch(type.getSort())
927 {
928 case Type.VOID:
929 return;
930 case Type.CHAR:
931 t = CHARACTER_TYPE;
932 sig = CHAR_VALUE;
933 break;
934 case Type.BOOLEAN:
935 t = BOOLEAN_TYPE;
936 sig = BOOLEAN_VALUE;
937 break;
938 case Type.DOUBLE:
939 sig = DOUBLE_VALUE;
940 break;
941 case Type.FLOAT:
942 sig = FLOAT_VALUE;
943 break;
944 case Type.LONG:
945 sig = LONG_VALUE;
946 break;
947 case Type.INT:
948 case Type.SHORT:
949 case Type.BYTE:
950 sig = INT_VALUE;
951 }
952 if(sig == null)
953 {
954 checkCast(type);
955 }
956 else
957 {
958 checkCast(t);
959 invokeVirtual(t, sig);
960 }
961 }
962
963 // ------------------------------------------------------------------------
964 // Instructions to jump to other instructions
965 // ------------------------------------------------------------------------
966
967 /**
968 * Creates a new {@link Label}.
969 *
970 * @return a new {@link Label}.
971 */
972 public Label newLabel(){
973 return new Label();
974 }
975
976 /**
977 * Marks the current code position with the given label.
978 *
979 * @param label a label.
980 */
981 public void mark(final Label label){
982 mv.visitLabel(label);
983 }
984
985 /**
986 * Marks the current code position with a new label.
987 *
988 * @return the label that was created to mark the current code position.
989 */
990 public Label mark(){
991 Label label = new Label();
992 mv.visitLabel(label);
993 return label;
994 }
995
996 /**
997 * Generates the instructions to jump to a label based on the comparison of
998 * the top two stack values.
999 *
1000 * @param type the type of the top two stack values.
1001 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
1002 * LE.
1003 * @param label where to jump if the comparison result is <tt>true</tt>.
1004 */
1005 public void ifCmp(final Type type, final int mode, final Label label){
1006 int intOp = -1;
1007 switch(type.getSort())
1008 {
1009 case Type.LONG:
1010 mv.visitInsn(Opcodes.LCMP);
1011 break;
1012 case Type.DOUBLE:
1013 mv.visitInsn(Opcodes.DCMPG);
1014 break;
1015 case Type.FLOAT:
1016 mv.visitInsn(Opcodes.FCMPG);
1017 break;
1018 case Type.ARRAY:
1019 case Type.OBJECT:
1020 switch(mode)
1021 {
1022 case EQ:
1023 mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
1024 return;
1025 case NE:
1026 mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
1027 return;
1028 }
1029 throw new IllegalArgumentException("Bad comparison for type "
1030 + type);
1031 default:
1032 switch(mode)
1033 {
1034 case EQ:
1035 intOp = Opcodes.IF_ICMPEQ;
1036 break;
1037 case NE:
1038 intOp = Opcodes.IF_ICMPNE;
1039 break;
1040 case GE:
1041 intOp = Opcodes.IF_ICMPGE;
1042 break;
1043 case LT:
1044 intOp = Opcodes.IF_ICMPLT;
1045 break;
1046 case LE:
1047 intOp = Opcodes.IF_ICMPLE;
1048 break;
1049 case GT:
1050 intOp = Opcodes.IF_ICMPGT;
1051 break;
1052 }
1053 mv.visitJumpInsn(intOp, label);
1054 return;
1055 }
1056 int jumpMode = mode;
1057 switch(mode)
1058 {
1059 case GE:
1060 jumpMode = LT;
1061 break;
1062 case LE:
1063 jumpMode = GT;
1064 break;
1065 }
1066 mv.visitJumpInsn(jumpMode, label);
1067 }
1068
1069 /**
1070 * Generates the instructions to jump to a label based on the comparison of
1071 * the top two integer stack values.
1072 *
1073 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
1074 * LE.
1075 * @param label where to jump if the comparison result is <tt>true</tt>.
1076 */
1077 public void ifICmp(final int mode, final Label label){
1078 ifCmp(Type.INT_TYPE, mode, label);
1079 }
1080
1081 /**
1082 * Generates the instructions to jump to a label based on the comparison of
1083 * the top integer stack value with zero.
1084 *
1085 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
1086 * LE.
1087 * @param label where to jump if the comparison result is <tt>true</tt>.
1088 */
1089 public void ifZCmp(final int mode, final Label label){
1090 mv.visitJumpInsn(mode, label);
1091 }
1092
1093 /**
1094 * Generates the instruction to jump to the given label if the top stack
1095 * value is null.
1096 *
1097 * @param label where to jump if the condition is <tt>true</tt>.
1098 */
1099 public void ifNull(final Label label){
1100 mv.visitJumpInsn(Opcodes.IFNULL, label);
1101 }
1102
1103 /**
1104 * Generates the instruction to jump to the given label if the top stack
1105 * value is not null.
1106 *
1107 * @param label where to jump if the condition is <tt>true</tt>.
1108 */
1109 public void ifNonNull(final Label label){
1110 mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1111 }
1112
1113 /**
1114 * Generates the instruction to jump to the given label.
1115 *
1116 * @param label where to jump if the condition is <tt>true</tt>.
1117 */
1118 public void goTo(final Label label){
1119 mv.visitJumpInsn(Opcodes.GOTO, label);
1120 }
1121
1122 /**
1123 * Generates a RET instruction.
1124 *
1125 * @param local a local variable identifier, as returned by
1126 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
1127 */
1128 public void ret(final int local){
1129 mv.visitVarInsn(Opcodes.RET, local);
1130 }
1131
1132 /**
1133 * Generates the instructions for a switch statement.
1134 *
1135 * @param keys the switch case keys.
1136 * @param generator a generator to generate the code for the switch cases.
1137 */
1138 public void tableSwitch(
1139 final int[] keys,
1140 final TableSwitchGenerator generator){
1141 float density;
1142 if(keys.length == 0)
1143 {
1144 density = 0;
1145 }
1146 else
1147 {
1148 density = (float) keys.length
1149 / (keys[keys.length - 1] - keys[0] + 1);
1150 }
1151 tableSwitch(keys, generator, density >= 0.5f);
1152 }
1153
1154 /**
1155 * Generates the instructions for a switch statement.
1156 *
1157 * @param keys the switch case keys.
1158 * @param generator a generator to generate the code for the switch cases.
1159 * @param useTable <tt>true</tt> to use a TABLESWITCH instruction, or
1160 * <tt>false</tt> to use a LOOKUPSWITCH instruction.
1161 */
1162 public void tableSwitch(
1163 final int[] keys,
1164 final TableSwitchGenerator generator,
1165 final boolean useTable){
1166 for(int i = 1; i < keys.length; ++i)
1167 {
1168 if(keys[i] < keys[i - 1])
1169 {
1170 throw new IllegalArgumentException("keys must be sorted ascending");
1171 }
1172 }
1173 Label def = newLabel();
1174 Label end = newLabel();
1175 if(keys.length > 0)
1176 {
1177 int len = keys.length;
1178 int min = keys[0];
1179 int max = keys[len - 1];
1180 int range = max - min + 1;
1181 if(useTable)
1182 {
1183 Label[] labels = new Label[range];
1184 Arrays.fill(labels, def);
1185 for(int i = 0; i < len; ++i)
1186 {
1187 labels[keys[i] - min] = newLabel();
1188 }
1189 mv.visitTableSwitchInsn(min, max, def, labels);
1190 for(int i = 0; i < range; ++i)
1191 {
1192 Label label = labels[i];
1193 if(label != def)
1194 {
1195 mark(label);
1196 generator.generateCase(i + min, end);
1197 }
1198 }
1199 }
1200 else
1201 {
1202 Label[] labels = new Label[len];
1203 for(int i = 0; i < len; ++i)
1204 {
1205 labels[i] = newLabel();
1206 }
1207 mv.visitLookupSwitchInsn(def, keys, labels);
1208 for(int i = 0; i < len; ++i)
1209 {
1210 mark(labels[i]);
1211 generator.generateCase(keys[i], end);
1212 }
1213 }
1214 }
1215 mark(def);
1216 generator.generateDefault();
1217 mark(end);
1218 }
1219
1220 /**
1221 * Generates the instruction to return the top stack value to the caller.
1222 */
1223 public void returnValue(){
1224 mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
1225 }
1226
1227 // ------------------------------------------------------------------------
1228 // Instructions to load and store fields
1229 // ------------------------------------------------------------------------
1230
1231 /**
1232 * Generates a get field or set field instruction.
1233 *
1234 * @param opcode the instruction's opcode.
1235 * @param ownerType the class in which the field is defined.
1236 * @param name the name of the field.
1237 * @param fieldType the type of the field.
1238 */
1239 private void fieldInsn(
1240 final int opcode,
1241 final Type ownerType,
1242 final String name,
1243 final Type fieldType){
1244 mv.visitFieldInsn(opcode,
1245 ownerType.getInternalName(),
1246 name,
1247 fieldType.getDescriptor());
1248 }
1249
1250 /**
1251 * Generates the instruction to push the value of a static field on the
1252 * stack.
1253 *
1254 * @param owner the class in which the field is defined.
1255 * @param name the name of the field.
1256 * @param type the type of the field.
1257 */
1258 public void getStatic(final Type owner, final String name, final Type type){
1259 fieldInsn(Opcodes.GETSTATIC, owner, name, type);
1260 }
1261
1262 /**
1263 * Generates the instruction to store the top stack value in a static field.
1264 *
1265 * @param owner the class in which the field is defined.
1266 * @param name the name of the field.
1267 * @param type the type of the field.
1268 */
1269 public void putStatic(final Type owner, final String name, final Type type){
1270 fieldInsn(Opcodes.PUTSTATIC, owner, name, type);
1271 }
1272
1273 /**
1274 * Generates the instruction to push the value of a non static field on the
1275 * stack.
1276 *
1277 * @param owner the class in which the field is defined.
1278 * @param name the name of the field.
1279 * @param type the type of the field.
1280 */
1281 public void getField(final Type owner, final String name, final Type type){
1282 fieldInsn(Opcodes.GETFIELD, owner, name, type);
1283 }
1284
1285 /**
1286 * Generates the instruction to store the top stack value in a non static
1287 * field.
1288 *
1289 * @param owner the class in which the field is defined.
1290 * @param name the name of the field.
1291 * @param type the type of the field.
1292 */
1293 public void putField(final Type owner, final String name, final Type type){
1294 fieldInsn(Opcodes.PUTFIELD, owner, name, type);
1295 }
1296
1297 // ------------------------------------------------------------------------
1298 // Instructions to invoke methods
1299 // ------------------------------------------------------------------------
1300
1301 /**
1302 * Generates an invoke method instruction.
1303 *
1304 * @param opcode the instruction's opcode.
1305 * @param type the class in which the method is defined.
1306 * @param method the method to be invoked.
1307 */
1308 private void invokeInsn(
1309 final int opcode,
1310 final Type type,
1311 final Method method){
1312 String owner = type.getSort() == Type.ARRAY
1313 ? type.getDescriptor()
1314 : type.getInternalName();
1315 mv.visitMethodInsn(opcode,
1316 owner,
1317 method.getName(),
1318 method.getDescriptor());
1319 }
1320
1321 /**
1322 * Generates the instruction to invoke a normal method.
1323 *
1324 * @param owner the class in which the method is defined.
1325 * @param method the method to be invoked.
1326 */
1327 public void invokeVirtual(final Type owner, final Method method){
1328 invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method);
1329 }
1330
1331 /**
1332 * Generates the instruction to invoke a constructor.
1333 *
1334 * @param type the class in which the constructor is defined.
1335 * @param method the constructor to be invoked.
1336 */
1337 public void invokeConstructor(final Type type, final Method method){
1338 invokeInsn(Opcodes.INVOKESPECIAL, type, method);
1339 }
1340
1341 /**
1342 * Generates the instruction to invoke a static method.
1343 *
1344 * @param owner the class in which the method is defined.
1345 * @param method the method to be invoked.
1346 */
1347 public void invokeStatic(final Type owner, final Method method){
1348 invokeInsn(Opcodes.INVOKESTATIC, owner, method);
1349 }
1350
1351 /**
1352 * Generates the instruction to invoke an interface method.
1353 *
1354 * @param owner the class in which the method is defined.
1355 * @param method the method to be invoked.
1356 */
1357 public void invokeInterface(final Type owner, final Method method){
1358 invokeInsn(Opcodes.INVOKEINTERFACE, owner, method);
1359 }
1360
1361 // ------------------------------------------------------------------------
1362 // Instructions to create objects and arrays
1363 // ------------------------------------------------------------------------
1364
1365 /**
1366 * Generates a type dependent instruction.
1367 *
1368 * @param opcode the instruction's opcode.
1369 * @param type the instruction's operand.
1370 */
1371 private void typeInsn(final int opcode, final Type type){
1372 String desc;
1373 if(type.getSort() == Type.ARRAY)
1374 {
1375 desc = type.getDescriptor();
1376 }
1377 else
1378 {
1379 desc = type.getInternalName();
1380 }
1381 mv.visitTypeInsn(opcode, desc);
1382 }
1383
1384 /**
1385 * Generates the instruction to create a new object.
1386 *
1387 * @param type the class of the object to be created.
1388 */
1389 public void newInstance(final Type type){
1390 typeInsn(Opcodes.NEW, type);
1391 }
1392
1393 /**
1394 * Generates the instruction to create a new array.
1395 *
1396 * @param type the type of the array elements.
1397 */
1398 public void newArray(final Type type){
1399 int typ;
1400 switch(type.getSort())
1401 {
1402 case Type.BOOLEAN:
1403 typ = Opcodes.T_BOOLEAN;
1404 break;
1405 case Type.CHAR:
1406 typ = Opcodes.T_CHAR;
1407 break;
1408 case Type.BYTE:
1409 typ = Opcodes.T_BYTE;
1410 break;
1411 case Type.SHORT:
1412 typ = Opcodes.T_SHORT;
1413 break;
1414 case Type.INT:
1415 typ = Opcodes.T_INT;
1416 break;
1417 case Type.FLOAT:
1418 typ = Opcodes.T_FLOAT;
1419 break;
1420 case Type.LONG:
1421 typ = Opcodes.T_LONG;
1422 break;
1423 case Type.DOUBLE:
1424 typ = Opcodes.T_DOUBLE;
1425 break;
1426 default:
1427 typeInsn(Opcodes.ANEWARRAY, type);
1428 return;
1429 }
1430 mv.visitIntInsn(Opcodes.NEWARRAY, typ);
1431 }
1432
1433 // ------------------------------------------------------------------------
1434 // Miscelaneous instructions
1435 // ------------------------------------------------------------------------
1436
1437 /**
1438 * Generates the instruction to compute the length of an array.
1439 */
1440 public void arrayLength(){
1441 mv.visitInsn(Opcodes.ARRAYLENGTH);
1442 }
1443
1444 /**
1445 * Generates the instruction to throw an exception.
1446 */
1447 public void throwException(){
1448 mv.visitInsn(Opcodes.ATHROW);
1449 }
1450
1451 /**
1452 * Generates the instructions to create and throw an exception. The
1453 * exception class must have a constructor with a single String argument.
1454 *
1455 * @param type the class of the exception to be thrown.
1456 * @param msg the detailed message of the exception.
1457 */
1458 public void throwException(final Type type, final String msg){
1459 newInstance(type);
1460 dup();
1461 push(msg);
1462 invokeConstructor(type, Method.getMethod("void <init> (String)"));
1463 throwException();
1464 }
1465
1466 /**
1467 * Generates the instruction to check that the top stack value is of the
1468 * given type.
1469 *
1470 * @param type a class or interface type.
1471 */
1472 public void checkCast(final Type type){
1473 if(!type.equals(OBJECT_TYPE))
1474 {
1475 typeInsn(Opcodes.CHECKCAST, type);
1476 }
1477 }
1478
1479 /**
1480 * Generates the instruction to test if the top stack value is of the given
1481 * type.
1482 *
1483 * @param type a class or interface type.
1484 */
1485 public void instanceOf(final Type type){
1486 typeInsn(Opcodes.INSTANCEOF, type);
1487 }
1488
1489 /**
1490 * Generates the instruction to get the monitor of the top stack value.
1491 */
1492 public void monitorEnter(){
1493 mv.visitInsn(Opcodes.MONITORENTER);
1494 }
1495
1496 /**
1497 * Generates the instruction to release the monitor of the top stack value.
1498 */
1499 public void monitorExit(){
1500 mv.visitInsn(Opcodes.MONITOREXIT);
1501 }
1502
1503 // ------------------------------------------------------------------------
1504 // Non instructions
1505 // ------------------------------------------------------------------------
1506
1507 /**
1508 * Marks the end of the visited method.
1509 */
1510 public void endMethod(){
1511 if((access & Opcodes.ACC_ABSTRACT) == 0)
1512 {
1513 mv.visitMaxs(0, 0);
1514 }
1515 mv.visitEnd();
1516 }
1517
1518 /**
1519 * Marks the start of an exception handler.
1520 *
1521 * @param start beginning of the exception handler's scope (inclusive).
1522 * @param end end of the exception handler's scope (exclusive).
1523 * @param exception internal name of the type of exceptions handled by the
1524 * handler.
1525 */
1526 public void catchException(
1527 final Label start,
1528 final Label end,
1529 final Type exception){
1530 mv.visitTryCatchBlock(start, end, mark(), exception.getInternalName());
1531 }
1532 }
+0
-330
src/jvm/clojure/asm/commons/LocalVariablesSorter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm.commons;
30
31 import clojure.asm.Label;
32 import clojure.asm.MethodAdapter;
33 import clojure.asm.MethodVisitor;
34 import clojure.asm.Opcodes;
35 import clojure.asm.Type;
36
37 /**
38 * A {@link MethodAdapter} that renumbers local variables in their order of
39 * appearance. This adapter allows one to easily add new local variables to a
40 * method. It may be used by inheriting from this class, but the preferred way
41 * of using it is via delegation: the next visitor in the chain can indeed add
42 * new locals when needed by calling {@link #newLocal} on this adapter (this
43 * requires a reference back to this {@link LocalVariablesSorter}).
44 *
45 * @author Chris Nokleberg
46 * @author Eugene Kuleshov
47 * @author Eric Bruneton
48 */
49 public class LocalVariablesSorter extends MethodAdapter{
50
51 private final static Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
52
53 /**
54 * Mapping from old to new local variable indexes. A local variable at index
55 * i of size 1 is remapped to 'mapping[2*i]', while a local variable at
56 * index i of size 2 is remapped to 'mapping[2*i+1]'.
57 */
58 private int[] mapping = new int[40];
59
60 /**
61 * Array used to store stack map local variable types after remapping.
62 */
63 private Object[] newLocals = new Object[20];
64
65 /**
66 * Index of the first local variable, after formal parameters.
67 */
68 protected final int firstLocal;
69
70 /**
71 * Index of the next local variable to be created by {@link #newLocal}.
72 */
73 protected int nextLocal;
74
75 /**
76 * Indicates if at least one local variable has moved due to remapping.
77 */
78 private boolean changed;
79
80 /**
81 * Creates a new {@link LocalVariablesSorter}.
82 *
83 * @param access access flags of the adapted method.
84 * @param desc the method's descriptor (see {@link Type Type}).
85 * @param mv the method visitor to which this adapter delegates calls.
86 */
87 public LocalVariablesSorter(
88 final int access,
89 final String desc,
90 final MethodVisitor mv){
91 super(mv);
92 Type[] args = Type.getArgumentTypes(desc);
93 nextLocal = (Opcodes.ACC_STATIC & access) != 0 ? 0 : 1;
94 for(int i = 0; i < args.length; i++)
95 {
96 nextLocal += args[i].getSize();
97 }
98 firstLocal = nextLocal;
99 }
100
101 public void visitVarInsn(final int opcode, final int var){
102 Type type;
103 switch(opcode)
104 {
105 case Opcodes.LLOAD:
106 case Opcodes.LSTORE:
107 type = Type.LONG_TYPE;
108 break;
109
110 case Opcodes.DLOAD:
111 case Opcodes.DSTORE:
112 type = Type.DOUBLE_TYPE;
113 break;
114
115 case Opcodes.FLOAD:
116 case Opcodes.FSTORE:
117 type = Type.FLOAT_TYPE;
118 break;
119
120 case Opcodes.ILOAD:
121 case Opcodes.ISTORE:
122 type = Type.INT_TYPE;
123 break;
124
125 case Opcodes.ALOAD:
126 case Opcodes.ASTORE:
127 type = OBJECT_TYPE;
128 break;
129
130 // case RET:
131 default:
132 type = Type.VOID_TYPE;
133 }
134 mv.visitVarInsn(opcode, remap(var, type));
135 }
136
137 public void visitIincInsn(final int var, final int increment){
138 mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);
139 }
140
141 public void visitMaxs(final int maxStack, final int maxLocals){
142 mv.visitMaxs(maxStack, nextLocal);
143 }
144
145 public void visitLocalVariable(
146 final String name,
147 final String desc,
148 final String signature,
149 final Label start,
150 final Label end,
151 final int index){
152 int size = "J".equals(desc) || "D".equals(desc) ? 2 : 1;
153 int newIndex = remap(index, size);
154 mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
155 }
156
157 public void visitFrame(
158 final int type,
159 final int nLocal,
160 final Object[] local,
161 final int nStack,
162 final Object[] stack){
163 if(type != Opcodes.F_NEW)
164 { // uncompressed frame
165 throw new IllegalStateException("ClassReader.accept() should be called with EXPAND_FRAMES flag");
166 }
167
168 if(!changed)
169 { // optimization for the case where mapping = identity
170 mv.visitFrame(type, nLocal, local, nStack, stack);
171 return;
172 }
173
174 // creates a copy of newLocals
175 Object[] oldLocals = new Object[newLocals.length];
176 System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);
177
178 // copies types from 'local' to 'newLocals'
179 // 'newLocals' already contains the variables added with 'newLocal'
180
181 int index = 0; // old local variable index
182 int number = 0; // old local variable number
183 for(; number < nLocal; ++number)
184 {
185 Object t = local[number];
186 int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
187 if(t != Opcodes.TOP)
188 {
189 setFrameLocal(remap(index, size), t);
190 }
191 index += size;
192 }
193
194 // removes TOP after long and double types as well as trailing TOPs
195
196 index = 0;
197 number = 0;
198 for(int i = 0; index < newLocals.length; ++i)
199 {
200 Object t = newLocals[index++];
201 if(t != null && t != Opcodes.TOP)
202 {
203 newLocals[i] = t;
204 number = i + 1;
205 if(t == Opcodes.LONG || t == Opcodes.DOUBLE)
206 {
207 index += 1;
208 }
209 }
210 else
211 {
212 newLocals[i] = Opcodes.TOP;
213 }
214 }
215
216 // visits remapped frame
217 mv.visitFrame(type, number, newLocals, nStack, stack);
218
219 // restores original value of 'newLocals'
220 newLocals = oldLocals;
221 }
222
223 // -------------
224
225 /**
226 * Creates a new local variable of the given type.
227 *
228 * @param type the type of the local variable to be created.
229 * @return the identifier of the newly created local variable.
230 */
231 public int newLocal(final Type type){
232 Object t;
233 switch(type.getSort())
234 {
235 case Type.BOOLEAN:
236 case Type.CHAR:
237 case Type.BYTE:
238 case Type.SHORT:
239 case Type.INT:
240 t = Opcodes.INTEGER;
241 break;
242 case Type.FLOAT:
243 t = Opcodes.FLOAT;
244 break;
245 case Type.LONG:
246 t = Opcodes.LONG;
247 break;
248 case Type.DOUBLE:
249 t = Opcodes.DOUBLE;
250 break;
251 case Type.ARRAY:
252 t = type.getDescriptor();
253 break;
254 // case Type.OBJECT:
255 default:
256 t = type.getInternalName();
257 break;
258 }
259 int local = nextLocal;
260 setLocalType(local, type);
261 setFrameLocal(local, t);
262 nextLocal += type.getSize();
263 return local;
264 }
265
266 /**
267 * Sets the current type of the given local variable. The default
268 * implementation of this method does nothing.
269 *
270 * @param local a local variable identifier, as returned by {@link #newLocal
271 * newLocal()}.
272 * @param type the type of the value being stored in the local variable
273 */
274 protected void setLocalType(final int local, final Type type){
275 }
276
277 private void setFrameLocal(final int local, final Object type){
278 int l = newLocals.length;
279 if(local >= l)
280 {
281 Object[] a = new Object[Math.max(2 * l, local + 1)];
282 System.arraycopy(newLocals, 0, a, 0, l);
283 newLocals = a;
284 }
285 newLocals[local] = type;
286 }
287
288 private int remap(final int var, final Type type){
289 if(var < firstLocal)
290 {
291 return var;
292 }
293 int key = 2 * var + type.getSize() - 1;
294 int size = mapping.length;
295 if(key >= size)
296 {
297 int[] newMapping = new int[Math.max(2 * size, key + 1)];
298 System.arraycopy(mapping, 0, newMapping, 0, size);
299 mapping = newMapping;
300 }
301 int value = mapping[key];
302 if(value == 0)
303 {
304 value = nextLocal + 1;
305 mapping[key] = value;
306 setLocalType(nextLocal, type);
307 nextLocal += type.getSize();
308 }
309 if(value - 1 != var)
310 {
311 changed = true;
312 }
313 return value - 1;
314 }
315
316 private int remap(final int var, final int size){
317 if(var < firstLocal || !changed)
318 {
319 return var;
320 }
321 int key = 2 * var + size - 1;
322 int value = key < mapping.length ? mapping[key] : 0;
323 if(value == 0)
324 {
325 throw new IllegalStateException("Unknown local variable " + var);
326 }
327 return value - 1;
328 }
329 }
+0
-267
src/jvm/clojure/asm/commons/Method.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm.commons;
30
31 import java.util.HashMap;
32 import java.util.Map;
33
34 import clojure.asm.Type;
35
36 /**
37 * A named method descriptor.
38 *
39 * @author Juozas Baliuka
40 * @author Chris Nokleberg
41 * @author Eric Bruneton
42 */
43 public class Method{
44
45 /**
46 * The method name.
47 */
48 private final String name;
49
50 /**
51 * The method descriptor.
52 */
53 private final String desc;
54
55 /**
56 * Maps primitive Java type names to their descriptors.
57 */
58 private final static Map DESCRIPTORS;
59
60 static
61 {
62 DESCRIPTORS = new HashMap();
63 DESCRIPTORS.put("void", "V");
64 DESCRIPTORS.put("byte", "B");
65 DESCRIPTORS.put("char", "C");
66 DESCRIPTORS.put("double", "D");
67 DESCRIPTORS.put("float", "F");
68 DESCRIPTORS.put("int", "I");
69 DESCRIPTORS.put("long", "J");
70 DESCRIPTORS.put("short", "S");
71 DESCRIPTORS.put("boolean", "Z");
72 }
73
74 /**
75 * Creates a new {@link Method}.
76 *
77 * @param name the method's name.
78 * @param desc the method's descriptor.
79 */
80 public Method(final String name, final String desc){
81 this.name = name;
82 this.desc = desc;
83 }
84
85 /**
86 * Creates a new {@link Method}.
87 *
88 * @param name the method's name.
89 * @param returnType the method's return type.
90 * @param argumentTypes the method's argument types.
91 */
92 public Method(
93 final String name,
94 final Type returnType,
95 final Type[] argumentTypes){
96 this(name, Type.getMethodDescriptor(returnType, argumentTypes));
97 }
98
99 /**
100 * Returns a {@link Method} corresponding to the given Java method
101 * declaration.
102 *
103 * @param method a Java method declaration, without argument names, of the
104 * form "returnType name (argumentType1, ... argumentTypeN)", where
105 * the types are in plain Java (e.g. "int", "float",
106 * "java.util.List", ...). Classes of the java.lang package can be
107 * specified by their unqualified name; all other classes names must
108 * be fully qualified.
109 * @return a {@link Method} corresponding to the given Java method
110 * declaration.
111 * @throws IllegalArgumentException if <code>method</code> could not get
112 * parsed.
113 */
114 public static Method getMethod(final String method)
115 throws IllegalArgumentException{
116 return getMethod(method, false);
117 }
118
119 /**
120 * Returns a {@link Method} corresponding to the given Java method
121 * declaration.
122 *
123 * @param method a Java method declaration, without argument names, of the
124 * form "returnType name (argumentType1, ... argumentTypeN)", where
125 * the types are in plain Java (e.g. "int", "float",
126 * "java.util.List", ...). Classes of the java.lang package may be
127 * specified by their unqualified name, depending on the
128 * defaultPackage argument; all other classes names must be fully
129 * qualified.
130 * @param defaultPackage true if unqualified class names belong to the
131 * default package, or false if they correspond to java.lang classes.
132 * For instance "Object" means "Object" if this option is true, or
133 * "java.lang.Object" otherwise.
134 * @return a {@link Method} corresponding to the given Java method
135 * declaration.
136 * @throws IllegalArgumentException if <code>method</code> could not get
137 * parsed.
138 */
139 public static Method getMethod(
140 final String method,
141 final boolean defaultPackage) throws IllegalArgumentException{
142 int space = method.indexOf(' ');
143 int start = method.indexOf('(', space) + 1;
144 int end = method.indexOf(')', start);
145 if(space == -1 || start == -1 || end == -1)
146 {
147 throw new IllegalArgumentException();
148 }
149 // TODO: Check validity of returnType, methodName and arguments.
150 String returnType = method.substring(0, space);
151 String methodName = method.substring(space + 1, start - 1).trim();
152 StringBuffer sb = new StringBuffer();
153 sb.append('(');
154 int p;
155 do
156 {
157 String s;
158 p = method.indexOf(',', start);
159 if(p == -1)
160 {
161 s = map(method.substring(start, end).trim(), defaultPackage);
162 }
163 else
164 {
165 s = map(method.substring(start, p).trim(), defaultPackage);
166 start = p + 1;
167 }
168 sb.append(s);
169 } while(p != -1);
170 sb.append(')');
171 sb.append(map(returnType, defaultPackage));
172 return new Method(methodName, sb.toString());
173 }
174
175 private static String map(final String type, final boolean defaultPackage){
176 if(type.equals(""))
177 {
178 return type;
179 }
180
181 StringBuffer sb = new StringBuffer();
182 int index = 0;
183 while((index = type.indexOf("[]", index) + 1) > 0)
184 {
185 sb.append('[');
186 }
187
188 String t = type.substring(0, type.length() - sb.length() * 2);
189 String desc = (String) DESCRIPTORS.get(t);
190 if(desc != null)
191 {
192 sb.append(desc);
193 }
194 else
195 {
196 sb.append('L');
197 if(t.indexOf('.') < 0)
198 {
199 if(!defaultPackage)
200 {
201 sb.append("java/lang/");
202 }
203 sb.append(t);
204 }
205 else
206 {
207 sb.append(t.replace('.', '/'));
208 }
209 sb.append(';');
210 }
211 return sb.toString();
212 }
213
214 /**
215 * Returns the name of the method described by this object.
216 *
217 * @return the name of the method described by this object.
218 */
219 public String getName(){
220 return name;
221 }
222
223 /**
224 * Returns the descriptor of the method described by this object.
225 *
226 * @return the descriptor of the method described by this object.
227 */
228 public String getDescriptor(){
229 return desc;
230 }
231
232 /**
233 * Returns the return type of the method described by this object.
234 *
235 * @return the return type of the method described by this object.
236 */
237 public Type getReturnType(){
238 return Type.getReturnType(desc);
239 }
240
241 /**
242 * Returns the argument types of the method described by this object.
243 *
244 * @return the argument types of the method described by this object.
245 */
246 public Type[] getArgumentTypes(){
247 return Type.getArgumentTypes(desc);
248 }
249
250 public String toString(){
251 return name + desc;
252 }
253
254 public boolean equals(final Object o){
255 if(!(o instanceof Method))
256 {
257 return false;
258 }
259 Method other = (Method) o;
260 return name.equals(other.name) && desc.equals(other.desc);
261 }
262
263 public int hashCode(){
264 return name.hashCode() ^ desc.hashCode();
265 }
266 }
+0
-508
src/jvm/clojure/asm/commons/SerialVersionUIDAdder.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm.commons;
30
31 import java.io.ByteArrayOutputStream;
32 import java.io.DataOutputStream;
33 import java.io.IOException;
34 import java.security.MessageDigest;
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.Collection;
38
39 import clojure.asm.ClassAdapter;
40 import clojure.asm.ClassVisitor;
41 import clojure.asm.FieldVisitor;
42 import clojure.asm.MethodVisitor;
43 import clojure.asm.Opcodes;
44
45 /**
46 * A {@link ClassAdapter} that adds a serial version unique identifier to a
47 * class if missing. Here is typical usage of this class:
48 * <p/>
49 * <pre>
50 * ClassWriter cw = new ClassWriter(...);
51 * ClassVisitor sv = new SerialVersionUIDAdder(cw);
52 * ClassVisitor ca = new MyClassAdapter(sv);
53 * new ClassReader(orginalClass).accept(ca, false);
54 * </pre>
55 * <p/>
56 * The SVUID algorithm can be found <a href=
57 * "http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html"
58 * >http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html</a>:
59 * <p/>
60 * <pre>
61 * The serialVersionUID is computed using the signature of a stream of bytes
62 * that reflect the class definition. The National Institute of Standards and
63 * Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a
64 * signature for the stream. The first two 32-bit quantities are used to form a
65 * 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data
66 * types to a sequence of bytes. The values input to the stream are defined by
67 * the Java Virtual Machine (VM) specification for classes.
68 * <p/>
69 * The sequence of items in the stream is as follows:
70 * <p/>
71 * 1. The class name written using UTF encoding.
72 * 2. The class modifiers written as a 32-bit integer.
73 * 3. The name of each interface sorted by name written using UTF encoding.
74 * 4. For each field of the class sorted by field name (except private static
75 * and private transient fields):
76 * 1. The name of the field in UTF encoding.
77 * 2. The modifiers of the field written as a 32-bit integer.
78 * 3. The descriptor of the field in UTF encoding
79 * 5. If a class initializer exists, write out the following:
80 * 1. The name of the method, &lt;clinit&gt;, in UTF encoding.
81 * 2. The modifier of the method, java.lang.reflect.Modifier.STATIC,
82 * written as a 32-bit integer.
83 * 3. The descriptor of the method, ()V, in UTF encoding.
84 * 6. For each non-private constructor sorted by method name and signature:
85 * 1. The name of the method, &lt;init&gt;, in UTF encoding.
86 * 2. The modifiers of the method written as a 32-bit integer.
87 * 3. The descriptor of the method in UTF encoding.
88 * 7. For each non-private method sorted by method name and signature:
89 * 1. The name of the method in UTF encoding.
90 * 2. The modifiers of the method written as a 32-bit integer.
91 * 3. The descriptor of the method in UTF encoding.
92 * 8. The SHA-1 algorithm is executed on the stream of bytes produced by
93 * DataOutputStream and produces five 32-bit values sha[0..4].
94 * <p/>
95 * 9. The hash value is assembled from the first and second 32-bit values of
96 * the SHA-1 message digest. If the result of the message digest, the five
97 * 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named
98 * sha, the hash value would be computed as follows:
99 * <p/>
100 * long hash = ((sha[0] &gt;&gt;&gt; 24) &amp; 0xFF) |
101 * ((sha[0] &gt;&gt;&gt; 16) &amp; 0xFF) &lt;&lt; 8 |
102 * ((sha[0] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 16 |
103 * ((sha[0] &gt;&gt;&gt; 0) &amp; 0xFF) &lt;&lt; 24 |
104 * ((sha[1] &gt;&gt;&gt; 24) &amp; 0xFF) &lt;&lt; 32 |
105 * ((sha[1] &gt;&gt;&gt; 16) &amp; 0xFF) &lt;&lt; 40 |
106 * ((sha[1] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 48 |
107 * ((sha[1] &gt;&gt;&gt; 0) &amp; 0xFF) &lt;&lt; 56;
108 * </pre>
109 *
110 * @author Rajendra Inamdar, Vishal Vishnoi
111 */
112 public class SerialVersionUIDAdder extends ClassAdapter{
113
114 /**
115 * Flag that indicates if we need to compute SVUID.
116 */
117 protected boolean computeSVUID;
118
119 /**
120 * Set to true if the class already has SVUID.
121 */
122 protected boolean hasSVUID;
123
124 /**
125 * Classes access flags.
126 */
127 protected int access;
128
129 /**
130 * Internal name of the class
131 */
132 protected String name;
133
134 /**
135 * Interfaces implemented by the class.
136 */
137 protected String[] interfaces;
138
139 /**
140 * Collection of fields. (except private static and private transient
141 * fields)
142 */
143 protected Collection svuidFields;
144
145 /**
146 * Set to true if the class has static initializer.
147 */
148 protected boolean hasStaticInitializer;
149
150 /**
151 * Collection of non-private constructors.
152 */
153 protected Collection svuidConstructors;
154
155 /**
156 * Collection of non-private methods.
157 */
158 protected Collection svuidMethods;
159
160 /**
161 * Creates a new {@link SerialVersionUIDAdder}.
162 *
163 * @param cv a {@link ClassVisitor} to which this visitor will delegate
164 * calls.
165 */
166 public SerialVersionUIDAdder(final ClassVisitor cv){
167 super(cv);
168 svuidFields = new ArrayList();
169 svuidConstructors = new ArrayList();
170 svuidMethods = new ArrayList();
171 }
172
173 // ------------------------------------------------------------------------
174 // Overriden methods
175 // ------------------------------------------------------------------------
176
177 /*
178 * Visit class header and get class name, access , and intefraces
179 * informatoin (step 1,2, and 3) for SVUID computation.
180 */
181
182 public void visit(
183 final int version,
184 final int access,
185 final String name,
186 final String signature,
187 final String superName,
188 final String[] interfaces){
189 computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0;
190
191 if(computeSVUID)
192 {
193 this.name = name;
194 this.access = access;
195 this.interfaces = interfaces;
196 }
197
198 super.visit(version, access, name, signature, superName, interfaces);
199 }
200
201 /*
202 * Visit the methods and get constructor and method information (step 5 and
203 * 7). Also determince if there is a class initializer (step 6).
204 */
205 public MethodVisitor visitMethod(
206 final int access,
207 final String name,
208 final String desc,
209 final String signature,
210 final String[] exceptions){
211 if(computeSVUID)
212 {
213 if(name.equals("<clinit>"))
214 {
215 hasStaticInitializer = true;
216 }
217 /*
218 * Remembers non private constructors and methods for SVUID
219 * computation For constructor and method modifiers, only the
220 * ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,
221 * ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags
222 * are used.
223 */
224 int mods = access
225 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
226 | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
227 | Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED
228 | Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT);
229
230 // all non private methods
231 if((access & Opcodes.ACC_PRIVATE) == 0)
232 {
233 if(name.equals("<init>"))
234 {
235 svuidConstructors.add(new Item(name, mods, desc));
236 }
237 else if(!name.equals("<clinit>"))
238 {
239 svuidMethods.add(new Item(name, mods, desc));
240 }
241 }
242 }
243
244 return cv.visitMethod(access, name, desc, signature, exceptions);
245 }
246
247 /*
248 * Gets class field information for step 4 of the alogrithm. Also determines
249 * if the class already has a SVUID.
250 */
251 public FieldVisitor visitField(
252 final int access,
253 final String name,
254 final String desc,
255 final String signature,
256 final Object value){
257 if(computeSVUID)
258 {
259 if(name.equals("serialVersionUID"))
260 {
261 // since the class already has SVUID, we won't be computing it.
262 computeSVUID = false;
263 hasSVUID = true;
264 }
265 /*
266 * Remember field for SVUID computation For field modifiers, only
267 * the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
268 * ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when
269 * computing serialVersionUID values.
270 */
271 int mods = access
272 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
273 | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
274 | Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT);
275
276 if((access & Opcodes.ACC_PRIVATE) == 0
277 || (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0)
278 {
279 svuidFields.add(new Item(name, mods, desc));
280 }
281 }
282
283 return super.visitField(access, name, desc, signature, value);
284 }
285
286 /*
287 * Add the SVUID if class doesn't have one
288 */
289 public void visitEnd(){
290 // compute SVUID and add it to the class
291 if(computeSVUID && !hasSVUID)
292 {
293 try
294 {
295 cv.visitField(Opcodes.ACC_FINAL + Opcodes.ACC_STATIC,
296 "serialVersionUID",
297 "J",
298 null,
299 new Long(computeSVUID()));
300 }
301 catch(Throwable e)
302 {
303 throw new RuntimeException("Error while computing SVUID for "
304 + name, e);
305 }
306 }
307
308 super.visitEnd();
309 }
310
311 // ------------------------------------------------------------------------
312 // Utility methods
313 // ------------------------------------------------------------------------
314
315 /**
316 * Returns the value of SVUID if the class doesn't have one already. Please
317 * note that 0 is returned if the class already has SVUID, thus use
318 * <code>isHasSVUID</code> to determine if the class already had an SVUID.
319 *
320 * @return Returns the serial version UID
321 * @throws IOException
322 */
323 protected long computeSVUID() throws IOException{
324 ByteArrayOutputStream bos = null;
325 DataOutputStream dos = null;
326 long svuid = 0;
327
328 try
329 {
330 bos = new ByteArrayOutputStream();
331 dos = new DataOutputStream(bos);
332
333 /*
334 * 1. The class name written using UTF encoding.
335 */
336 dos.writeUTF(name.replace('/', '.'));
337
338 /*
339 * 2. The class modifiers written as a 32-bit integer.
340 */
341 dos.writeInt(access
342 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL
343 | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT));
344
345 /*
346 * 3. The name of each interface sorted by name written using UTF
347 * encoding.
348 */
349 Arrays.sort(interfaces);
350 for(int i = 0; i < interfaces.length; i++)
351 {
352 dos.writeUTF(interfaces[i].replace('/', '.'));
353 }
354
355 /*
356 * 4. For each field of the class sorted by field name (except
357 * private static and private transient fields):
358 *
359 * 1. The name of the field in UTF encoding. 2. The modifiers of the
360 * field written as a 32-bit integer. 3. The descriptor of the field
361 * in UTF encoding
362 *
363 * Note that field signatutes are not dot separated. Method and
364 * constructor signatures are dot separated. Go figure...
365 */
366 writeItems(svuidFields, dos, false);
367
368 /*
369 * 5. If a class initializer exists, write out the following: 1. The
370 * name of the method, <clinit>, in UTF encoding. 2. The modifier of
371 * the method, java.lang.reflect.Modifier.STATIC, written as a
372 * 32-bit integer. 3. The descriptor of the method, ()V, in UTF
373 * encoding.
374 */
375 if(hasStaticInitializer)
376 {
377 dos.writeUTF("<clinit>");
378 dos.writeInt(Opcodes.ACC_STATIC);
379 dos.writeUTF("()V");
380 } // if..
381
382 /*
383 * 6. For each non-private constructor sorted by method name and
384 * signature: 1. The name of the method, <init>, in UTF encoding. 2.
385 * The modifiers of the method written as a 32-bit integer. 3. The
386 * descriptor of the method in UTF encoding.
387 */
388 writeItems(svuidConstructors, dos, true);
389
390 /*
391 * 7. For each non-private method sorted by method name and
392 * signature: 1. The name of the method in UTF encoding. 2. The
393 * modifiers of the method written as a 32-bit integer. 3. The
394 * descriptor of the method in UTF encoding.
395 */
396 writeItems(svuidMethods, dos, true);
397
398 dos.flush();
399
400 /*
401 * 8. The SHA-1 algorithm is executed on the stream of bytes
402 * produced by DataOutputStream and produces five 32-bit values
403 * sha[0..4].
404 */
405 byte[] hashBytes = computeSHAdigest(bos.toByteArray());
406
407 /*
408 * 9. The hash value is assembled from the first and second 32-bit
409 * values of the SHA-1 message digest. If the result of the message
410 * digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of
411 * five int values named sha, the hash value would be computed as
412 * follows:
413 *
414 * long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF) <<
415 * 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) <<
416 * 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) <<
417 * 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) <<
418 * 56;
419 */
420 for(int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--)
421 {
422 svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
423 }
424 }
425 finally
426 {
427 // close the stream (if open)
428 if(dos != null)
429 {
430 dos.close();
431 }
432 }
433
434 return svuid;
435 }
436
437 /**
438 * Returns the SHA-1 message digest of the given value.
439 *
440 * @param value the value whose SHA message digest must be computed.
441 * @return the SHA-1 message digest of the given value.
442 */
443 protected byte[] computeSHAdigest(final byte[] value){
444 try
445 {
446 return MessageDigest.getInstance("SHA").digest(value);
447 }
448 catch(Exception e)
449 {
450 throw new UnsupportedOperationException(e);
451 }
452 }
453
454 /**
455 * Sorts the items in the collection and writes it to the data output stream
456 *
457 * @param itemCollection collection of items
458 * @param dos a <code>DataOutputStream</code> value
459 * @param dotted a <code>boolean</code> value
460 * @throws IOException if an error occurs
461 */
462 private void writeItems(
463 final Collection itemCollection,
464 final DataOutputStream dos,
465 final boolean dotted) throws IOException{
466 int size = itemCollection.size();
467 Item items[] = (Item[]) itemCollection.toArray(new Item[size]);
468 Arrays.sort(items);
469 for(int i = 0; i < size; i++)
470 {
471 dos.writeUTF(items[i].name);
472 dos.writeInt(items[i].access);
473 dos.writeUTF(dotted
474 ? items[i].desc.replace('/', '.')
475 : items[i].desc);
476 }
477 }
478
479 // ------------------------------------------------------------------------
480 // Inner classes
481 // ------------------------------------------------------------------------
482
483 static class Item implements Comparable{
484
485 String name;
486
487 int access;
488
489 String desc;
490
491 Item(final String name, final int access, final String desc){
492 this.name = name;
493 this.access = access;
494 this.desc = desc;
495 }
496
497 public int compareTo(final Object o){
498 Item other = (Item) o;
499 int retVal = name.compareTo(other.name);
500 if(retVal == 0)
501 {
502 retVal = desc.compareTo(other.desc);
503 }
504 return retVal;
505 }
506 }
507 }
+0
-102
src/jvm/clojure/asm/commons/StaticInitMerger.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm.commons;
30
31 import clojure.asm.ClassAdapter;
32 import clojure.asm.ClassVisitor;
33 import clojure.asm.MethodVisitor;
34 import clojure.asm.Opcodes;
35
36 /**
37 * A {@link ClassAdapter} that merges clinit methods into a single one.
38 *
39 * @author Eric Bruneton
40 */
41 public class StaticInitMerger extends ClassAdapter{
42
43 private String name;
44
45 private MethodVisitor clinit;
46
47 private String prefix;
48
49 private int counter;
50
51 public StaticInitMerger(final String prefix, final ClassVisitor cv){
52 super(cv);
53 this.prefix = prefix;
54 }
55
56 public void visit(
57 final int version,
58 final int access,
59 final String name,
60 final String signature,
61 final String superName,
62 final String[] interfaces){
63 cv.visit(version, access, name, signature, superName, interfaces);
64 this.name = name;
65 }
66
67 public MethodVisitor visitMethod(
68 final int access,
69 final String name,
70 final String desc,
71 final String signature,
72 final String[] exceptions){
73 MethodVisitor mv;
74 if(name.equals("<clinit>"))
75 {
76 int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
77 String n = prefix + counter++;
78 mv = cv.visitMethod(a, n, desc, signature, exceptions);
79
80 if(clinit == null)
81 {
82 clinit = cv.visitMethod(a, name, desc, null, null);
83 }
84 clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc);
85 }
86 else
87 {
88 mv = cv.visitMethod(access, name, desc, signature, exceptions);
89 }
90 return mv;
91 }
92
93 public void visitEnd(){
94 if(clinit != null)
95 {
96 clinit.visitInsn(Opcodes.RETURN);
97 clinit.visitMaxs(0, 0);
98 }
99 cv.visitEnd();
100 }
101 }
+0
-55
src/jvm/clojure/asm/commons/TableSwitchGenerator.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2005 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 */
29 package clojure.asm.commons;
30
31 import clojure.asm.Label;
32
33 /**
34 * A code generator for switch statements.
35 *
36 * @author Juozas Baliuka
37 * @author Chris Nokleberg
38 * @author Eric Bruneton
39 */
40 public interface TableSwitchGenerator{
41
42 /**
43 * Generates the code for a switch case.
44 *
45 * @param key the switch case key.
46 * @param end a label that corresponds to the end of the switch statement.
47 */
48 void generateCase(int key, Label end);
49
50 /**
51 * Generates the code for the default switch case.
52 */
53 void generateDefault();
54 }
+0
-48
src/jvm/clojure/asm/commons/package.html less more
0 <html>
1 <!--
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2005 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 -->
30 <body>
31 Provides some useful class and method adapters. <i>The preferred way of using
32 these adapters is by chaining them together and to custom adapters (instead of
33 inheriting from them)</i>. Indeed this approach provides more combination
34 possibilities than inheritance. For instance, suppose you want to implement an
35 adapter MyAdapter than needs sorted local variables and intermediate stack map
36 frame values taking into account the local variables sort. By using inheritance,
37 this would require MyAdapter to extend AnalyzerAdapter, itself extending
38 LocalVariablesSorter. But AnalyzerAdapter is not a subclass of
39 LocalVariablesSorter, so this is not possible. On the contrary, by using
40 delegation, you can make LocalVariablesSorter delegate to AnalyzerAdapter,
41 itself delegating to MyAdapter. In this case AnalyzerAdapter computes
42 intermediate frames based on the output of LocalVariablesSorter, and MyAdapter
43 can add new locals by calling the newLocal method on LocalVariablesSorter, and
44 can get the stack map frame state before each instruction by reading the locals
45 and stack fields in AnalyzerAdapter (this requires references from MyAdapter
46 back to LocalVariablesSorter and AnalyzerAdapter).
47 </body>
+0
-87
src/jvm/clojure/asm/package.html less more
0 <html>
1 <!--
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2005 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 -->
30 <body>
31 Provides a small and fast bytecode manipulation framework.
32
33 <p>
34 The <a href="http://www.objectweb.org/asm">ASM</a> framework is organized
35 around the {@link clojure.asm.ClassVisitor ClassVisitor},
36 {@link clojure.asm.FieldVisitor FieldVisitor} and
37 {@link clojure.asm.MethodVisitor MethodVisitor} interfaces, which allow
38 one to visit the fields and methods of a class, including the bytecode
39 instructions of each method.
40
41 <p>
42 In addition to these main interfaces, ASM provides a {@link
43 clojure.asm.ClassReader ClassReader} class, that can parse an
44 existing class and make a given visitor visit it. ASM also provides
45 a {@link clojure.asm.ClassWriter ClassWriter} class, which is
46 a visitor that generates Java class files.
47
48 <p>
49 In order to generate a class from scratch, only the {@link
50 clojure.asm.ClassWriter ClassWriter} class is necessary. Indeed,
51 in order to generate a class, one must just call its visit<i>XXX</i>
52 methods with the appropriate arguments to generate the desired fields
53 and methods. See the "helloworld" example in the ASM distribution for
54 more details about class generation.
55
56 <p>
57 In order to modify existing classes, one must use a {@link
58 clojure.asm.ClassReader ClassReader} class to analyze
59 the original class, a class modifier, and a {@link clojure.asm.ClassWriter
60 ClassWriter} to construct the modified class. The class modifier
61 is just a {@link clojure.asm.ClassVisitor ClassVisitor}
62 that delegates most of the work to another {@link clojure.asm.ClassVisitor
63 ClassVisitor}, but that sometimes changes some parameter values,
64 or call additional methods, in order to implement the desired
65 modification process. In order to make it easier to implement such
66 class modifiers, ASM provides the {@link clojure.asm.ClassAdapter
67 ClassAdapter} and {@link clojure.asm.MethodAdapter MethodAdapter}
68 classes, which implement the {@link clojure.asm.ClassVisitor ClassVisitor}
69 and {@link clojure.asm.MethodVisitor MethodVisitor} interfaces by
70 delegating all work to other visitors. See the "adapt" example in the ASM
71 distribution for more details about class modification.
72
73 <p>
74 The size of the core ASM library, <tt>asm.jar</tt>, is only 42KB, which is much
75 smaller than the size of the
76 <a href="http://jakarta.apache.org/bcel">BCEL</a> library (504KB), and than the
77 size of the
78 <a href="http://serp.sourceforge.net">SERP</a> library (150KB). ASM is also
79 much faster than these tools. Indeed the overhead of a load time class
80 transformation process is of the order of 60% with ASM, 700% or more with BCEL,
81 and 1100% or more with SERP (see the <tt>test/perf</tt> directory in the ASM
82 distribution)!
83
84 @since ASM 1.3
85 </body>
86 </html>