Codebase list clojure / 0c1dab2
Removed third-party files Daigo Moriwaki 9 years ago
32 changed file(s) with 0 addition(s) and 18958 deletion(s). Raw diff Collapse all Expand all
+0
-169
src/jvm/clojure/asm/AnnotationVisitor.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package clojure.asm;
30
31 /**
32 * A visitor to visit a Java annotation. The methods of this class 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 abstract class AnnotationVisitor {
40
41 /**
42 * The ASM API version implemented by this visitor. The value of this field
43 * must be one of {@link Opcodes#ASM4}.
44 */
45 protected final int api;
46
47 /**
48 * The annotation visitor to which this visitor must delegate method calls.
49 * May be null.
50 */
51 protected AnnotationVisitor av;
52
53 /**
54 * Constructs a new {@link AnnotationVisitor}.
55 *
56 * @param api
57 * the ASM API version implemented by this visitor. Must be one
58 * of {@link Opcodes#ASM4}.
59 */
60 public AnnotationVisitor(final int api) {
61 this(api, null);
62 }
63
64 /**
65 * Constructs a new {@link AnnotationVisitor}.
66 *
67 * @param api
68 * the ASM API version implemented by this visitor. Must be one
69 * of {@link Opcodes#ASM4}.
70 * @param av
71 * the annotation visitor to which this visitor must delegate
72 * method calls. May be null.
73 */
74 public AnnotationVisitor(final int api, final AnnotationVisitor av) {
75 if (api != Opcodes.ASM4) {
76 throw new IllegalArgumentException();
77 }
78 this.api = api;
79 this.av = av;
80 }
81
82 /**
83 * Visits a primitive value of the annotation.
84 *
85 * @param name
86 * the value name.
87 * @param value
88 * the actual value, whose type must be {@link Byte},
89 * {@link Boolean}, {@link Character}, {@link Short},
90 * {@link Integer} , {@link Long}, {@link Float}, {@link Double},
91 * {@link String} or {@link Type} or OBJECT or ARRAY sort. This
92 * value can also be an array of byte, boolean, short, char, int,
93 * long, float or double values (this is equivalent to using
94 * {@link #visitArray visitArray} and visiting each array element
95 * in turn, but is more convenient).
96 */
97 public void visit(String name, Object value) {
98 if (av != null) {
99 av.visit(name, value);
100 }
101 }
102
103 /**
104 * Visits an enumeration value of the annotation.
105 *
106 * @param name
107 * the value name.
108 * @param desc
109 * the class descriptor of the enumeration class.
110 * @param value
111 * the actual enumeration value.
112 */
113 public void visitEnum(String name, String desc, String value) {
114 if (av != null) {
115 av.visitEnum(name, desc, value);
116 }
117 }
118
119 /**
120 * Visits a nested annotation value of the annotation.
121 *
122 * @param name
123 * the value name.
124 * @param desc
125 * the class descriptor of the nested annotation class.
126 * @return a visitor to visit the actual nested annotation value, or
127 * <tt>null</tt> if this visitor is not interested in visiting this
128 * nested annotation. <i>The nested annotation value must be fully
129 * visited before calling other methods on this annotation
130 * visitor</i>.
131 */
132 public AnnotationVisitor visitAnnotation(String name, String desc) {
133 if (av != null) {
134 return av.visitAnnotation(name, desc);
135 }
136 return null;
137 }
138
139 /**
140 * Visits an array value of the annotation. Note that arrays of primitive
141 * types (such as byte, boolean, short, char, int, long, float or double)
142 * can be passed as value to {@link #visit visit}. This is what
143 * {@link ClassReader} does.
144 *
145 * @param name
146 * the value name.
147 * @return a visitor to visit the actual array value elements, or
148 * <tt>null</tt> if this visitor is not interested in visiting these
149 * values. The 'name' parameters passed to the methods of this
150 * visitor are ignored. <i>All the array values must be visited
151 * before calling other methods on this annotation visitor</i>.
152 */
153 public AnnotationVisitor visitArray(String name) {
154 if (av != null) {
155 return av.visitArray(name);
156 }
157 return null;
158 }
159
160 /**
161 * Visits the end of the annotation.
162 */
163 public void visitEnd() {
164 if (av != null) {
165 av.visitEnd();
166 }
167 }
168 }
+0
-318
src/jvm/clojure/asm/AnnotationWriter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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 extends 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
93 * the class writer to which this annotation must be added.
94 * @param named
95 * <tt>true<tt> if values are named, <tt>false</tt> otherwise.
96 * @param bv
97 * where the annotation values must be stored.
98 * @param parent
99 * where the number of annotation values must be stored.
100 * @param offset
101 * where in <tt>parent</tt> the number of annotation values must
102 * be stored.
103 */
104 AnnotationWriter(final ClassWriter cw, final boolean named,
105 final ByteVector bv, final ByteVector parent, final int offset) {
106 super(Opcodes.ASM4);
107 this.cw = cw;
108 this.named = named;
109 this.bv = bv;
110 this.parent = parent;
111 this.offset = offset;
112 }
113
114 // ------------------------------------------------------------------------
115 // Implementation of the AnnotationVisitor abstract class
116 // ------------------------------------------------------------------------
117
118 @Override
119 public void visit(final String name, final Object value) {
120 ++size;
121 if (named) {
122 bv.putShort(cw.newUTF8(name));
123 }
124 if (value instanceof String) {
125 bv.put12('s', cw.newUTF8((String) value));
126 } else if (value instanceof Byte) {
127 bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
128 } else if (value instanceof Boolean) {
129 int v = ((Boolean) value).booleanValue() ? 1 : 0;
130 bv.put12('Z', cw.newInteger(v).index);
131 } else if (value instanceof Character) {
132 bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
133 } else if (value instanceof Short) {
134 bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
135 } else if (value instanceof Type) {
136 bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
137 } else if (value instanceof byte[]) {
138 byte[] v = (byte[]) value;
139 bv.put12('[', v.length);
140 for (int i = 0; i < v.length; i++) {
141 bv.put12('B', cw.newInteger(v[i]).index);
142 }
143 } else if (value instanceof boolean[]) {
144 boolean[] v = (boolean[]) value;
145 bv.put12('[', v.length);
146 for (int i = 0; i < v.length; i++) {
147 bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
148 }
149 } else if (value instanceof short[]) {
150 short[] v = (short[]) value;
151 bv.put12('[', v.length);
152 for (int i = 0; i < v.length; i++) {
153 bv.put12('S', cw.newInteger(v[i]).index);
154 }
155 } else if (value instanceof char[]) {
156 char[] v = (char[]) value;
157 bv.put12('[', v.length);
158 for (int i = 0; i < v.length; i++) {
159 bv.put12('C', cw.newInteger(v[i]).index);
160 }
161 } else if (value instanceof int[]) {
162 int[] v = (int[]) value;
163 bv.put12('[', v.length);
164 for (int i = 0; i < v.length; i++) {
165 bv.put12('I', cw.newInteger(v[i]).index);
166 }
167 } else if (value instanceof long[]) {
168 long[] v = (long[]) value;
169 bv.put12('[', v.length);
170 for (int i = 0; i < v.length; i++) {
171 bv.put12('J', cw.newLong(v[i]).index);
172 }
173 } else if (value instanceof float[]) {
174 float[] v = (float[]) value;
175 bv.put12('[', v.length);
176 for (int i = 0; i < v.length; i++) {
177 bv.put12('F', cw.newFloat(v[i]).index);
178 }
179 } else if (value instanceof double[]) {
180 double[] v = (double[]) value;
181 bv.put12('[', v.length);
182 for (int i = 0; i < v.length; i++) {
183 bv.put12('D', cw.newDouble(v[i]).index);
184 }
185 } else {
186 Item i = cw.newConstItem(value);
187 bv.put12(".s.IFJDCS".charAt(i.type), i.index);
188 }
189 }
190
191 @Override
192 public void visitEnum(final String name, final String desc,
193 final String value) {
194 ++size;
195 if (named) {
196 bv.putShort(cw.newUTF8(name));
197 }
198 bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
199 }
200
201 @Override
202 public AnnotationVisitor visitAnnotation(final String name,
203 final String desc) {
204 ++size;
205 if (named) {
206 bv.putShort(cw.newUTF8(name));
207 }
208 // write tag and type, and reserve space for values count
209 bv.put12('@', cw.newUTF8(desc)).putShort(0);
210 return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
211 }
212
213 @Override
214 public AnnotationVisitor visitArray(final String name) {
215 ++size;
216 if (named) {
217 bv.putShort(cw.newUTF8(name));
218 }
219 // write tag, and reserve space for array size
220 bv.put12('[', 0);
221 return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
222 }
223
224 @Override
225 public void visitEnd() {
226 if (parent != null) {
227 byte[] data = parent.data;
228 data[offset] = (byte) (size >>> 8);
229 data[offset + 1] = (byte) size;
230 }
231 }
232
233 // ------------------------------------------------------------------------
234 // Utility methods
235 // ------------------------------------------------------------------------
236
237 /**
238 * Returns the size of this annotation writer list.
239 *
240 * @return the size of this annotation writer list.
241 */
242 int getSize() {
243 int size = 0;
244 AnnotationWriter aw = this;
245 while (aw != null) {
246 size += aw.bv.length;
247 aw = aw.next;
248 }
249 return size;
250 }
251
252 /**
253 * Puts the annotations of this annotation writer list into the given byte
254 * vector.
255 *
256 * @param out
257 * where the annotations must be put.
258 */
259 void put(final ByteVector out) {
260 int n = 0;
261 int size = 2;
262 AnnotationWriter aw = this;
263 AnnotationWriter last = null;
264 while (aw != null) {
265 ++n;
266 size += aw.bv.length;
267 aw.visitEnd(); // in case user forgot to call visitEnd
268 aw.prev = last;
269 last = aw;
270 aw = aw.next;
271 }
272 out.putInt(size);
273 out.putShort(n);
274 aw = last;
275 while (aw != null) {
276 out.putByteArray(aw.bv.data, 0, aw.bv.length);
277 aw = aw.prev;
278 }
279 }
280
281 /**
282 * Puts the given annotation lists into the given byte vector.
283 *
284 * @param panns
285 * an array of annotation writer lists.
286 * @param off
287 * index of the first annotation to be written.
288 * @param out
289 * where the annotations must be put.
290 */
291 static void put(final AnnotationWriter[] panns, final int off,
292 final ByteVector out) {
293 int size = 1 + 2 * (panns.length - off);
294 for (int i = off; i < panns.length; ++i) {
295 size += panns[i] == null ? 0 : panns[i].getSize();
296 }
297 out.putInt(size).putByte(panns.length - off);
298 for (int i = off; i < panns.length; ++i) {
299 AnnotationWriter aw = panns[i];
300 AnnotationWriter last = null;
301 int n = 0;
302 while (aw != null) {
303 ++n;
304 aw.visitEnd(); // in case user forgot to call visitEnd
305 aw.prev = last;
306 last = aw;
307 aw = aw.next;
308 }
309 out.putShort(n);
310 aw = last;
311 while (aw != null) {
312 out.putByteArray(aw.bv.data, 0, aw.bv.length);
313 aw = aw.prev;
314 }
315 }
316 }
317 }
+0
-255
src/jvm/clojure/asm/Attribute.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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
58 * the type of the attribute.
59 */
60 protected Attribute(final String type) {
61 this.type = type;
62 }
63
64 /**
65 * Returns <tt>true</tt> if this type of attribute is unknown. The default
66 * implementation of this method always returns <tt>true</tt>.
67 *
68 * @return <tt>true</tt> if this type of attribute is unknown.
69 */
70 public boolean isUnknown() {
71 return true;
72 }
73
74 /**
75 * Returns <tt>true</tt> if this type of attribute is a code attribute.
76 *
77 * @return <tt>true</tt> if this type of attribute is a code attribute.
78 */
79 public boolean isCodeAttribute() {
80 return false;
81 }
82
83 /**
84 * Returns the labels corresponding to this attribute.
85 *
86 * @return the labels corresponding to this attribute, or <tt>null</tt> if
87 * this attribute is not a code attribute that contains labels.
88 */
89 protected Label[] getLabels() {
90 return null;
91 }
92
93 /**
94 * Reads a {@link #type type} attribute. This method must return a
95 * <i>new</i> {@link Attribute} object, of type {@link #type type},
96 * corresponding to the <tt>len</tt> bytes starting at the given offset, in
97 * the given class reader.
98 *
99 * @param cr
100 * the class that contains the attribute to be read.
101 * @param off
102 * index of the first byte of the attribute's content in
103 * {@link ClassReader#b cr.b}. The 6 attribute header bytes,
104 * containing the type and the length of the attribute, are not
105 * taken into account here.
106 * @param len
107 * the length of the attribute's content.
108 * @param buf
109 * buffer to be used to call {@link ClassReader#readUTF8
110 * readUTF8}, {@link ClassReader#readClass(int,char[]) readClass}
111 * or {@link ClassReader#readConst readConst}.
112 * @param codeOff
113 * index of the first byte of code's attribute content in
114 * {@link ClassReader#b cr.b}, or -1 if the attribute to be read
115 * is not a code attribute. The 6 attribute header bytes,
116 * containing the type and the length of the attribute, are not
117 * taken into account here.
118 * @param labels
119 * the labels of the method's code, or <tt>null</tt> if the
120 * attribute to be read is not a code attribute.
121 * @return a <i>new</i> {@link Attribute} object corresponding to the given
122 * bytes.
123 */
124 protected Attribute read(final ClassReader cr, final int off,
125 final int len, final char[] buf, final int codeOff,
126 final Label[] labels) {
127 Attribute attr = new Attribute(type);
128 attr.value = new byte[len];
129 System.arraycopy(cr.b, off, attr.value, 0, len);
130 return attr;
131 }
132
133 /**
134 * Returns the byte array form of this attribute.
135 *
136 * @param cw
137 * the class to which this attribute must be added. This
138 * parameter can be used to add to the constant pool of this
139 * class the items that corresponds to this attribute.
140 * @param code
141 * the bytecode of the method corresponding to this code
142 * attribute, or <tt>null</tt> if this attribute is not a code
143 * attributes.
144 * @param len
145 * the length of the bytecode of the method corresponding to this
146 * code attribute, or <tt>null</tt> if this attribute is not a
147 * code attribute.
148 * @param maxStack
149 * the maximum stack size of the method corresponding to this
150 * code attribute, or -1 if this attribute is not a code
151 * attribute.
152 * @param maxLocals
153 * the maximum number of local variables of the method
154 * corresponding to this code attribute, or -1 if this attribute
155 * is not a code attribute.
156 * @return the byte array form of this attribute.
157 */
158 protected ByteVector write(final ClassWriter cw, final byte[] code,
159 final int len, final int maxStack, final int maxLocals) {
160 ByteVector v = new ByteVector();
161 v.data = value;
162 v.length = value.length;
163 return v;
164 }
165
166 /**
167 * Returns the length of the attribute list that begins with this attribute.
168 *
169 * @return the length of the attribute list that begins with this attribute.
170 */
171 final int getCount() {
172 int count = 0;
173 Attribute attr = this;
174 while (attr != null) {
175 count += 1;
176 attr = attr.next;
177 }
178 return count;
179 }
180
181 /**
182 * Returns the size of all the attributes in this attribute list.
183 *
184 * @param cw
185 * the class writer to be used to convert the attributes into
186 * byte arrays, with the {@link #write write} method.
187 * @param code
188 * the bytecode of the method corresponding to these code
189 * attributes, or <tt>null</tt> if these attributes are not code
190 * attributes.
191 * @param len
192 * the length of the bytecode of the method corresponding to
193 * these code attributes, or <tt>null</tt> if these attributes
194 * are not code attributes.
195 * @param maxStack
196 * the maximum stack size of the method corresponding to these
197 * code attributes, or -1 if these attributes are not code
198 * attributes.
199 * @param maxLocals
200 * the maximum number of local variables of the method
201 * corresponding to these code attributes, or -1 if these
202 * attributes are not code attributes.
203 * @return the size of all the attributes in this attribute list. This size
204 * includes the size of the attribute headers.
205 */
206 final int getSize(final ClassWriter cw, final byte[] code, final int len,
207 final int maxStack, final int maxLocals) {
208 Attribute attr = this;
209 int size = 0;
210 while (attr != null) {
211 cw.newUTF8(attr.type);
212 size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
213 attr = attr.next;
214 }
215 return size;
216 }
217
218 /**
219 * Writes all the attributes of this attribute list in the given byte
220 * vector.
221 *
222 * @param cw
223 * the class writer to be used to convert the attributes into
224 * byte arrays, with the {@link #write write} method.
225 * @param code
226 * the bytecode of the method corresponding to these code
227 * attributes, or <tt>null</tt> if these attributes are not code
228 * attributes.
229 * @param len
230 * the length of the bytecode of the method corresponding to
231 * these code attributes, or <tt>null</tt> if these attributes
232 * are not code attributes.
233 * @param maxStack
234 * the maximum stack size of the method corresponding to these
235 * code attributes, or -1 if these attributes are not code
236 * attributes.
237 * @param maxLocals
238 * the maximum number of local variables of the method
239 * corresponding to these code attributes, or -1 if these
240 * attributes are not code attributes.
241 * @param out
242 * where the attributes must be written.
243 */
244 final void put(final ClassWriter cw, final byte[] code, final int len,
245 final int maxStack, final int maxLocals, final ByteVector out) {
246 Attribute attr = this;
247 while (attr != null) {
248 ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
249 out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
250 out.putByteArray(b.data, 0, b.length);
251 attr = attr.next;
252 }
253 }
254 }
+0
-306
src/jvm/clojure/asm/ByteVector.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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
62 * the initial size of the byte vector to be constructed.
63 */
64 public ByteVector(final int initialSize) {
65 data = new byte[initialSize];
66 }
67
68 /**
69 * Puts a byte into this byte vector. The byte vector is automatically
70 * enlarged if necessary.
71 *
72 * @param b
73 * a byte.
74 * @return this byte vector.
75 */
76 public ByteVector putByte(final int b) {
77 int length = this.length;
78 if (length + 1 > data.length) {
79 enlarge(1);
80 }
81 data[length++] = (byte) b;
82 this.length = length;
83 return this;
84 }
85
86 /**
87 * Puts two bytes into this byte vector. The byte vector is automatically
88 * enlarged if necessary.
89 *
90 * @param b1
91 * a byte.
92 * @param b2
93 * another byte.
94 * @return this byte vector.
95 */
96 ByteVector put11(final int b1, final int b2) {
97 int length = this.length;
98 if (length + 2 > data.length) {
99 enlarge(2);
100 }
101 byte[] data = this.data;
102 data[length++] = (byte) b1;
103 data[length++] = (byte) b2;
104 this.length = length;
105 return this;
106 }
107
108 /**
109 * Puts a short into this byte vector. The byte vector is automatically
110 * enlarged if necessary.
111 *
112 * @param s
113 * a short.
114 * @return this byte vector.
115 */
116 public ByteVector putShort(final int s) {
117 int length = this.length;
118 if (length + 2 > data.length) {
119 enlarge(2);
120 }
121 byte[] data = this.data;
122 data[length++] = (byte) (s >>> 8);
123 data[length++] = (byte) s;
124 this.length = length;
125 return this;
126 }
127
128 /**
129 * Puts a byte and a short into this byte vector. The byte vector is
130 * automatically enlarged if necessary.
131 *
132 * @param b
133 * a byte.
134 * @param s
135 * a short.
136 * @return this byte vector.
137 */
138 ByteVector put12(final int b, final int s) {
139 int length = this.length;
140 if (length + 3 > data.length) {
141 enlarge(3);
142 }
143 byte[] data = this.data;
144 data[length++] = (byte) b;
145 data[length++] = (byte) (s >>> 8);
146 data[length++] = (byte) s;
147 this.length = length;
148 return this;
149 }
150
151 /**
152 * Puts an int into this byte vector. The byte vector is automatically
153 * enlarged if necessary.
154 *
155 * @param i
156 * an int.
157 * @return this byte vector.
158 */
159 public ByteVector putInt(final int i) {
160 int length = this.length;
161 if (length + 4 > data.length) {
162 enlarge(4);
163 }
164 byte[] data = this.data;
165 data[length++] = (byte) (i >>> 24);
166 data[length++] = (byte) (i >>> 16);
167 data[length++] = (byte) (i >>> 8);
168 data[length++] = (byte) i;
169 this.length = length;
170 return this;
171 }
172
173 /**
174 * Puts a long into this byte vector. The byte vector is automatically
175 * enlarged if necessary.
176 *
177 * @param l
178 * a long.
179 * @return this byte vector.
180 */
181 public ByteVector putLong(final long l) {
182 int length = this.length;
183 if (length + 8 > data.length) {
184 enlarge(8);
185 }
186 byte[] data = this.data;
187 int i = (int) (l >>> 32);
188 data[length++] = (byte) (i >>> 24);
189 data[length++] = (byte) (i >>> 16);
190 data[length++] = (byte) (i >>> 8);
191 data[length++] = (byte) i;
192 i = (int) l;
193 data[length++] = (byte) (i >>> 24);
194 data[length++] = (byte) (i >>> 16);
195 data[length++] = (byte) (i >>> 8);
196 data[length++] = (byte) i;
197 this.length = length;
198 return this;
199 }
200
201 /**
202 * Puts an UTF8 string into this byte vector. The byte vector is
203 * automatically enlarged if necessary.
204 *
205 * @param s
206 * a String.
207 * @return this byte vector.
208 */
209 public ByteVector putUTF8(final String s) {
210 int charLength = s.length();
211 int len = length;
212 if (len + 2 + charLength > data.length) {
213 enlarge(2 + charLength);
214 }
215 byte[] data = this.data;
216 // optimistic algorithm: instead of computing the byte length and then
217 // serializing the string (which requires two loops), we assume the byte
218 // length is equal to char length (which is the most frequent case), and
219 // we start serializing the string right away. During the serialization,
220 // if we find that this assumption is wrong, we continue with the
221 // general method.
222 data[len++] = (byte) (charLength >>> 8);
223 data[len++] = (byte) charLength;
224 for (int i = 0; i < charLength; ++i) {
225 char c = s.charAt(i);
226 if (c >= '\001' && c <= '\177') {
227 data[len++] = (byte) c;
228 } else {
229 int byteLength = i;
230 for (int j = i; j < charLength; ++j) {
231 c = s.charAt(j);
232 if (c >= '\001' && c <= '\177') {
233 byteLength++;
234 } else if (c > '\u07FF') {
235 byteLength += 3;
236 } else {
237 byteLength += 2;
238 }
239 }
240 data[length] = (byte) (byteLength >>> 8);
241 data[length + 1] = (byte) byteLength;
242 if (length + 2 + byteLength > data.length) {
243 length = len;
244 enlarge(2 + byteLength);
245 data = this.data;
246 }
247 for (int j = i; j < charLength; ++j) {
248 c = s.charAt(j);
249 if (c >= '\001' && c <= '\177') {
250 data[len++] = (byte) c;
251 } else if (c > '\u07FF') {
252 data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
253 data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
254 data[len++] = (byte) (0x80 | c & 0x3F);
255 } else {
256 data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
257 data[len++] = (byte) (0x80 | c & 0x3F);
258 }
259 }
260 break;
261 }
262 }
263 length = len;
264 return this;
265 }
266
267 /**
268 * Puts an array of bytes into this byte vector. The byte vector is
269 * automatically enlarged if necessary.
270 *
271 * @param b
272 * an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
273 * null bytes into this byte vector.
274 * @param off
275 * index of the fist byte of b that must be copied.
276 * @param len
277 * number of bytes of b that must be copied.
278 * @return this byte vector.
279 */
280 public ByteVector putByteArray(final byte[] b, final int off, final int len) {
281 if (length + len > data.length) {
282 enlarge(len);
283 }
284 if (b != null) {
285 System.arraycopy(b, off, data, length, len);
286 }
287 length += len;
288 return this;
289 }
290
291 /**
292 * Enlarge this byte vector so that it can receive n more bytes.
293 *
294 * @param size
295 * number of additional bytes that this byte vector should be
296 * able to receive.
297 */
298 private void enlarge(final int size) {
299 int length1 = 2 * data.length;
300 int length2 = length + size;
301 byte[] newData = new byte[length1 > length2 ? length1 : length2];
302 System.arraycopy(data, 0, newData, 0, length);
303 data = newData;
304 }
305 }
+0
-2202
src/jvm/clojure/asm/ClassReader.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package clojure.asm;
30
31 import java.io.IOException;
32 import java.io.InputStream;
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 * True to enable signatures support.
47 */
48 static final boolean SIGNATURES = true;
49
50 /**
51 * True to enable annotations support.
52 */
53 static final boolean ANNOTATIONS = true;
54
55 /**
56 * True to enable stack map frames support.
57 */
58 static final boolean FRAMES = true;
59
60 /**
61 * True to enable bytecode writing support.
62 */
63 static final boolean WRITER = true;
64
65 /**
66 * True to enable JSR_W and GOTO_W support.
67 */
68 static final boolean RESIZE = true;
69
70 /**
71 * Flag to skip method code. If this class is set <code>CODE</code>
72 * attribute won't be visited. This can be used, for example, to retrieve
73 * annotations for methods and method parameters.
74 */
75 public static final int SKIP_CODE = 1;
76
77 /**
78 * Flag to skip the debug information in the class. If this flag is set the
79 * debug information of the class is not visited, i.e. the
80 * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
81 * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be
82 * called.
83 */
84 public static final int SKIP_DEBUG = 2;
85
86 /**
87 * Flag to skip the stack map frames in the class. If this flag is set the
88 * stack map frames of the class is not visited, i.e. the
89 * {@link MethodVisitor#visitFrame visitFrame} method will not be called.
90 * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is
91 * used: it avoids visiting frames that will be ignored and recomputed from
92 * scratch in the class writer.
93 */
94 public static final int SKIP_FRAMES = 4;
95
96 /**
97 * Flag to expand the stack map frames. By default stack map frames are
98 * visited in their original format (i.e. "expanded" for classes whose
99 * version is less than V1_6, and "compressed" for the other classes). If
100 * this flag is set, stack map frames are always visited in expanded format
101 * (this option adds a decompression/recompression step in ClassReader and
102 * ClassWriter which degrades performances quite a lot).
103 */
104 public static final int EXPAND_FRAMES = 8;
105
106 /**
107 * The class to be parsed. <i>The content of this array must not be
108 * modified. This field is intended for {@link Attribute} sub classes, and
109 * is normally not needed by class generators or adapters.</i>
110 */
111 public final byte[] b;
112
113 /**
114 * The start index of each constant pool item in {@link #b b}, plus one. The
115 * one byte offset skips the constant pool item tag that indicates its type.
116 */
117 private final int[] items;
118
119 /**
120 * The String objects corresponding to the CONSTANT_Utf8 items. This cache
121 * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,
122 * which GREATLY improves performances (by a factor 2 to 3). This caching
123 * strategy could be extended to all constant pool items, but its benefit
124 * would not be so great for these items (because they are much less
125 * expensive to parse than CONSTANT_Utf8 items).
126 */
127 private final String[] strings;
128
129 /**
130 * Maximum length of the strings contained in the constant pool of the
131 * class.
132 */
133 private final int maxStringLength;
134
135 /**
136 * Start index of the class header information (access, name...) in
137 * {@link #b b}.
138 */
139 public final int header;
140
141 // ------------------------------------------------------------------------
142 // Constructors
143 // ------------------------------------------------------------------------
144
145 /**
146 * Constructs a new {@link ClassReader} object.
147 *
148 * @param b
149 * the bytecode of the class to be read.
150 */
151 public ClassReader(final byte[] b) {
152 this(b, 0, b.length);
153 }
154
155 /**
156 * Constructs a new {@link ClassReader} object.
157 *
158 * @param b
159 * the bytecode of the class to be read.
160 * @param off
161 * the start offset of the class data.
162 * @param len
163 * the length of the class data.
164 */
165 public ClassReader(final byte[] b, final int off, final int len) {
166 this.b = b;
167 // checks the class version
168 if (readShort(off + 6) > Opcodes.V1_7) {
169 throw new IllegalArgumentException();
170 }
171 // parses the constant pool
172 items = new int[readUnsignedShort(off + 8)];
173 int n = items.length;
174 strings = new String[n];
175 int max = 0;
176 int index = off + 10;
177 for (int i = 1; i < n; ++i) {
178 items[i] = index + 1;
179 int size;
180 switch (b[index]) {
181 case ClassWriter.FIELD:
182 case ClassWriter.METH:
183 case ClassWriter.IMETH:
184 case ClassWriter.INT:
185 case ClassWriter.FLOAT:
186 case ClassWriter.NAME_TYPE:
187 case ClassWriter.INDY:
188 size = 5;
189 break;
190 case ClassWriter.LONG:
191 case ClassWriter.DOUBLE:
192 size = 9;
193 ++i;
194 break;
195 case ClassWriter.UTF8:
196 size = 3 + readUnsignedShort(index + 1);
197 if (size > max) {
198 max = size;
199 }
200 break;
201 case ClassWriter.HANDLE:
202 size = 4;
203 break;
204 // case ClassWriter.CLASS:
205 // case ClassWriter.STR:
206 // case ClassWriter.MTYPE
207 default:
208 size = 3;
209 break;
210 }
211 index += size;
212 }
213 maxStringLength = max;
214 // the class header information starts just after the constant pool
215 header = index;
216 }
217
218 /**
219 * Returns the class's access flags (see {@link Opcodes}). This value may
220 * not reflect Deprecated and Synthetic flags when bytecode is before 1.5
221 * and those flags are represented by attributes.
222 *
223 * @return the class access flags
224 *
225 * @see ClassVisitor#visit(int, int, String, String, String, String[])
226 */
227 public int getAccess() {
228 return readUnsignedShort(header);
229 }
230
231 /**
232 * Returns the internal name of the class (see
233 * {@link Type#getInternalName() getInternalName}).
234 *
235 * @return the internal class name
236 *
237 * @see ClassVisitor#visit(int, int, String, String, String, String[])
238 */
239 public String getClassName() {
240 return readClass(header + 2, new char[maxStringLength]);
241 }
242
243 /**
244 * Returns the internal of name of the super class (see
245 * {@link Type#getInternalName() getInternalName}). For interfaces, the
246 * super class is {@link Object}.
247 *
248 * @return the internal name of super class, or <tt>null</tt> for
249 * {@link Object} class.
250 *
251 * @see ClassVisitor#visit(int, int, String, String, String, String[])
252 */
253 public String getSuperName() {
254 return readClass(header + 4, new char[maxStringLength]);
255 }
256
257 /**
258 * Returns the internal names of the class's interfaces (see
259 * {@link Type#getInternalName() getInternalName}).
260 *
261 * @return the array of internal names for all implemented interfaces or
262 * <tt>null</tt>.
263 *
264 * @see ClassVisitor#visit(int, int, String, String, String, String[])
265 */
266 public String[] getInterfaces() {
267 int index = header + 6;
268 int n = readUnsignedShort(index);
269 String[] interfaces = new String[n];
270 if (n > 0) {
271 char[] buf = new char[maxStringLength];
272 for (int i = 0; i < n; ++i) {
273 index += 2;
274 interfaces[i] = readClass(index, buf);
275 }
276 }
277 return interfaces;
278 }
279
280 /**
281 * Copies the constant pool data into the given {@link ClassWriter}. Should
282 * be called before the {@link #accept(ClassVisitor,int)} method.
283 *
284 * @param classWriter
285 * the {@link ClassWriter} to copy constant pool into.
286 */
287 void copyPool(final ClassWriter classWriter) {
288 char[] buf = new char[maxStringLength];
289 int ll = items.length;
290 Item[] items2 = new Item[ll];
291 for (int i = 1; i < ll; i++) {
292 int index = items[i];
293 int tag = b[index - 1];
294 Item item = new Item(i);
295 int nameType;
296 switch (tag) {
297 case ClassWriter.FIELD:
298 case ClassWriter.METH:
299 case ClassWriter.IMETH:
300 nameType = items[readUnsignedShort(index + 2)];
301 item.set(tag, readClass(index, buf), readUTF8(nameType, buf),
302 readUTF8(nameType + 2, buf));
303 break;
304 case ClassWriter.INT:
305 item.set(readInt(index));
306 break;
307 case ClassWriter.FLOAT:
308 item.set(Float.intBitsToFloat(readInt(index)));
309 break;
310 case ClassWriter.NAME_TYPE:
311 item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf),
312 null);
313 break;
314 case ClassWriter.LONG:
315 item.set(readLong(index));
316 ++i;
317 break;
318 case ClassWriter.DOUBLE:
319 item.set(Double.longBitsToDouble(readLong(index)));
320 ++i;
321 break;
322 case ClassWriter.UTF8: {
323 String s = strings[i];
324 if (s == null) {
325 index = items[i];
326 s = strings[i] = readUTF(index + 2,
327 readUnsignedShort(index), buf);
328 }
329 item.set(tag, s, null, null);
330 break;
331 }
332 case ClassWriter.HANDLE: {
333 int fieldOrMethodRef = items[readUnsignedShort(index + 1)];
334 nameType = items[readUnsignedShort(fieldOrMethodRef + 2)];
335 item.set(ClassWriter.HANDLE_BASE + readByte(index),
336 readClass(fieldOrMethodRef, buf),
337 readUTF8(nameType, buf), readUTF8(nameType + 2, buf));
338 break;
339 }
340 case ClassWriter.INDY:
341 if (classWriter.bootstrapMethods == null) {
342 copyBootstrapMethods(classWriter, items2, buf);
343 }
344 nameType = items[readUnsignedShort(index + 2)];
345 item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf),
346 readUnsignedShort(index));
347 break;
348 // case ClassWriter.STR:
349 // case ClassWriter.CLASS:
350 // case ClassWriter.MTYPE
351 default:
352 item.set(tag, readUTF8(index, buf), null, null);
353 break;
354 }
355
356 int index2 = item.hashCode % items2.length;
357 item.next = items2[index2];
358 items2[index2] = item;
359 }
360
361 int off = items[1] - 1;
362 classWriter.pool.putByteArray(b, off, header - off);
363 classWriter.items = items2;
364 classWriter.threshold = (int) (0.75d * ll);
365 classWriter.index = ll;
366 }
367
368 /**
369 * Copies the bootstrap method data into the given {@link ClassWriter}.
370 * Should be called before the {@link #accept(ClassVisitor,int)} method.
371 *
372 * @param classWriter
373 * the {@link ClassWriter} to copy bootstrap methods into.
374 */
375 private void copyBootstrapMethods(final ClassWriter classWriter,
376 final Item[] items, final char[] c) {
377 // finds the "BootstrapMethods" attribute
378 int u = getAttributes();
379 boolean found = false;
380 for (int i = readUnsignedShort(u); i > 0; --i) {
381 String attrName = readUTF8(u + 2, c);
382 if ("BootstrapMethods".equals(attrName)) {
383 found = true;
384 break;
385 }
386 u += 6 + readInt(u + 4);
387 }
388 if (!found) {
389 return;
390 }
391 // copies the bootstrap methods in the class writer
392 int boostrapMethodCount = readUnsignedShort(u + 8);
393 for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) {
394 int position = v - u - 10;
395 int hashCode = readConst(readUnsignedShort(v), c).hashCode();
396 for (int k = readUnsignedShort(v + 2); k > 0; --k) {
397 hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode();
398 v += 2;
399 }
400 v += 4;
401 Item item = new Item(j);
402 item.set(position, hashCode & 0x7FFFFFFF);
403 int index = item.hashCode % items.length;
404 item.next = items[index];
405 items[index] = item;
406 }
407 int attrSize = readInt(u + 4);
408 ByteVector bootstrapMethods = new ByteVector(attrSize + 62);
409 bootstrapMethods.putByteArray(b, u + 10, attrSize - 2);
410 classWriter.bootstrapMethodsCount = boostrapMethodCount;
411 classWriter.bootstrapMethods = bootstrapMethods;
412 }
413
414 /**
415 * Constructs a new {@link ClassReader} object.
416 *
417 * @param is
418 * an input stream from which to read the class.
419 * @throws IOException
420 * if a problem occurs during reading.
421 */
422 public ClassReader(final InputStream is) throws IOException {
423 this(readClass(is, false));
424 }
425
426 /**
427 * Constructs a new {@link ClassReader} object.
428 *
429 * @param name
430 * the binary qualified name of the class to be read.
431 * @throws IOException
432 * if an exception occurs during reading.
433 */
434 public ClassReader(final String name) throws IOException {
435 this(readClass(
436 ClassLoader.getSystemResourceAsStream(name.replace('.', '/')
437 + ".class"), true));
438 }
439
440 /**
441 * Reads the bytecode of a class.
442 *
443 * @param is
444 * an input stream from which to read the class.
445 * @param close
446 * true to close the input stream after reading.
447 * @return the bytecode read from the given input stream.
448 * @throws IOException
449 * if a problem occurs during reading.
450 */
451 private static byte[] readClass(final InputStream is, boolean close)
452 throws IOException {
453 if (is == null) {
454 throw new IOException("Class not found");
455 }
456 try {
457 byte[] b = new byte[is.available()];
458 int len = 0;
459 while (true) {
460 int n = is.read(b, len, b.length - len);
461 if (n == -1) {
462 if (len < b.length) {
463 byte[] c = new byte[len];
464 System.arraycopy(b, 0, c, 0, len);
465 b = c;
466 }
467 return b;
468 }
469 len += n;
470 if (len == b.length) {
471 int last = is.read();
472 if (last < 0) {
473 return b;
474 }
475 byte[] c = new byte[b.length + 1000];
476 System.arraycopy(b, 0, c, 0, len);
477 c[len++] = (byte) last;
478 b = c;
479 }
480 }
481 } finally {
482 if (close) {
483 is.close();
484 }
485 }
486 }
487
488 // ------------------------------------------------------------------------
489 // Public methods
490 // ------------------------------------------------------------------------
491
492 /**
493 * Makes the given visitor visit the Java class of this {@link ClassReader}
494 * . This class is the one specified in the constructor (see
495 * {@link #ClassReader(byte[]) ClassReader}).
496 *
497 * @param classVisitor
498 * the visitor that must visit this class.
499 * @param flags
500 * option flags that can be used to modify the default behavior
501 * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}
502 * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
503 */
504 public void accept(final ClassVisitor classVisitor, final int flags) {
505 accept(classVisitor, new Attribute[0], flags);
506 }
507
508 /**
509 * Makes the given visitor visit the Java class of this {@link ClassReader}.
510 * This class is the one specified in the constructor (see
511 * {@link #ClassReader(byte[]) ClassReader}).
512 *
513 * @param classVisitor
514 * the visitor that must visit this class.
515 * @param attrs
516 * prototypes of the attributes that must be parsed during the
517 * visit of the class. Any attribute whose type is not equal to
518 * the type of one the prototypes will not be parsed: its byte
519 * array value will be passed unchanged to the ClassWriter.
520 * <i>This may corrupt it if this value contains references to
521 * the constant pool, or has syntactic or semantic links with a
522 * class element that has been transformed by a class adapter
523 * between the reader and the writer</i>.
524 * @param flags
525 * option flags that can be used to modify the default behavior
526 * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}
527 * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
528 */
529 public void accept(final ClassVisitor classVisitor,
530 final Attribute[] attrs, final int flags) {
531 int u = header; // current offset in the class file
532 char[] c = new char[maxStringLength]; // buffer used to read strings
533
534 Context context = new Context();
535 context.attrs = attrs;
536 context.flags = flags;
537 context.buffer = c;
538
539 // reads the class declaration
540 int access = readUnsignedShort(u);
541 String name = readClass(u + 2, c);
542 String superClass = readClass(u + 4, c);
543 String[] interfaces = new String[readUnsignedShort(u + 6)];
544 u += 8;
545 for (int i = 0; i < interfaces.length; ++i) {
546 interfaces[i] = readClass(u, c);
547 u += 2;
548 }
549
550 // reads the class attributes
551 String signature = null;
552 String sourceFile = null;
553 String sourceDebug = null;
554 String enclosingOwner = null;
555 String enclosingName = null;
556 String enclosingDesc = null;
557 int anns = 0;
558 int ianns = 0;
559 int innerClasses = 0;
560 Attribute attributes = null;
561
562 u = getAttributes();
563 for (int i = readUnsignedShort(u); i > 0; --i) {
564 String attrName = readUTF8(u + 2, c);
565 // tests are sorted in decreasing frequency order
566 // (based on frequencies observed on typical classes)
567 if ("SourceFile".equals(attrName)) {
568 sourceFile = readUTF8(u + 8, c);
569 } else if ("InnerClasses".equals(attrName)) {
570 innerClasses = u + 8;
571 } else if ("EnclosingMethod".equals(attrName)) {
572 enclosingOwner = readClass(u + 8, c);
573 int item = readUnsignedShort(u + 10);
574 if (item != 0) {
575 enclosingName = readUTF8(items[item], c);
576 enclosingDesc = readUTF8(items[item] + 2, c);
577 }
578 } else if (SIGNATURES && "Signature".equals(attrName)) {
579 signature = readUTF8(u + 8, c);
580 } else if (ANNOTATIONS
581 && "RuntimeVisibleAnnotations".equals(attrName)) {
582 anns = u + 8;
583 } else if ("Deprecated".equals(attrName)) {
584 access |= Opcodes.ACC_DEPRECATED;
585 } else if ("Synthetic".equals(attrName)) {
586 access |= Opcodes.ACC_SYNTHETIC
587 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
588 } else if ("SourceDebugExtension".equals(attrName)) {
589 int len = readInt(u + 4);
590 sourceDebug = readUTF(u + 8, len, new char[len]);
591 } else if (ANNOTATIONS
592 && "RuntimeInvisibleAnnotations".equals(attrName)) {
593 ianns = u + 8;
594 } else if ("BootstrapMethods".equals(attrName)) {
595 int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
596 for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
597 bootstrapMethods[j] = v;
598 v += 2 + readUnsignedShort(v + 2) << 1;
599 }
600 context.bootstrapMethods = bootstrapMethods;
601 } else {
602 Attribute attr = readAttribute(attrs, attrName, u + 8,
603 readInt(u + 4), c, -1, null);
604 if (attr != null) {
605 attr.next = attributes;
606 attributes = attr;
607 }
608 }
609 u += 6 + readInt(u + 4);
610 }
611
612 // visits the class declaration
613 classVisitor.visit(readInt(items[1] - 7), access, name, signature,
614 superClass, interfaces);
615
616 // visits the source and debug info
617 if ((flags & SKIP_DEBUG) == 0
618 && (sourceFile != null || sourceDebug != null)) {
619 classVisitor.visitSource(sourceFile, sourceDebug);
620 }
621
622 // visits the outer class
623 if (enclosingOwner != null) {
624 classVisitor.visitOuterClass(enclosingOwner, enclosingName,
625 enclosingDesc);
626 }
627
628 // visits the class annotations
629 if (ANNOTATIONS && anns != 0) {
630 for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
631 v = readAnnotationValues(v + 2, c, true,
632 classVisitor.visitAnnotation(readUTF8(v, c), true));
633 }
634 }
635 if (ANNOTATIONS && ianns != 0) {
636 for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
637 v = readAnnotationValues(v + 2, c, true,
638 classVisitor.visitAnnotation(readUTF8(v, c), false));
639 }
640 }
641
642 // visits the attributes
643 while (attributes != null) {
644 Attribute attr = attributes.next;
645 attributes.next = null;
646 classVisitor.visitAttribute(attributes);
647 attributes = attr;
648 }
649
650 // visits the inner classes
651 if (innerClasses != 0) {
652 int v = innerClasses + 2;
653 for (int i = readUnsignedShort(innerClasses); i > 0; --i) {
654 classVisitor.visitInnerClass(readClass(v, c),
655 readClass(v + 2, c), readUTF8(v + 4, c),
656 readUnsignedShort(v + 6));
657 v += 8;
658 }
659 }
660
661 // visits the fields and methods
662 u = header + 10 + 2 * interfaces.length;
663 for (int i = readUnsignedShort(u - 2); i > 0; --i) {
664 u = readField(classVisitor, context, u);
665 }
666 u += 2;
667 for (int i = readUnsignedShort(u - 2); i > 0; --i) {
668 u = readMethod(classVisitor, context, u);
669 }
670
671 // visits the end of the class
672 classVisitor.visitEnd();
673 }
674
675 /**
676 * Reads a field and makes the given visitor visit it.
677 *
678 * @param classVisitor
679 * the visitor that must visit the field.
680 * @param context
681 * information about the class being parsed.
682 * @param u
683 * the start offset of the field in the class file.
684 * @return the offset of the first byte following the field in the class.
685 */
686 private int readField(final ClassVisitor classVisitor,
687 final Context context, int u) {
688 // reads the field declaration
689 char[] c = context.buffer;
690 int access = readUnsignedShort(u);
691 String name = readUTF8(u + 2, c);
692 String desc = readUTF8(u + 4, c);
693 u += 6;
694
695 // reads the field attributes
696 String signature = null;
697 int anns = 0;
698 int ianns = 0;
699 Object value = null;
700 Attribute attributes = null;
701
702 for (int i = readUnsignedShort(u); i > 0; --i) {
703 String attrName = readUTF8(u + 2, c);
704 // tests are sorted in decreasing frequency order
705 // (based on frequencies observed on typical classes)
706 if ("ConstantValue".equals(attrName)) {
707 int item = readUnsignedShort(u + 8);
708 value = item == 0 ? null : readConst(item, c);
709 } else if (SIGNATURES && "Signature".equals(attrName)) {
710 signature = readUTF8(u + 8, c);
711 } else if ("Deprecated".equals(attrName)) {
712 access |= Opcodes.ACC_DEPRECATED;
713 } else if ("Synthetic".equals(attrName)) {
714 access |= Opcodes.ACC_SYNTHETIC
715 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
716 } else if (ANNOTATIONS
717 && "RuntimeVisibleAnnotations".equals(attrName)) {
718 anns = u + 8;
719 } else if (ANNOTATIONS
720 && "RuntimeInvisibleAnnotations".equals(attrName)) {
721 ianns = u + 8;
722 } else {
723 Attribute attr = readAttribute(context.attrs, attrName, u + 8,
724 readInt(u + 4), c, -1, null);
725 if (attr != null) {
726 attr.next = attributes;
727 attributes = attr;
728 }
729 }
730 u += 6 + readInt(u + 4);
731 }
732 u += 2;
733
734 // visits the field declaration
735 FieldVisitor fv = classVisitor.visitField(access, name, desc,
736 signature, value);
737 if (fv == null) {
738 return u;
739 }
740
741 // visits the field annotations
742 if (ANNOTATIONS && anns != 0) {
743 for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
744 v = readAnnotationValues(v + 2, c, true,
745 fv.visitAnnotation(readUTF8(v, c), true));
746 }
747 }
748 if (ANNOTATIONS && ianns != 0) {
749 for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
750 v = readAnnotationValues(v + 2, c, true,
751 fv.visitAnnotation(readUTF8(v, c), false));
752 }
753 }
754
755 // visits the field attributes
756 while (attributes != null) {
757 Attribute attr = attributes.next;
758 attributes.next = null;
759 fv.visitAttribute(attributes);
760 attributes = attr;
761 }
762
763 // visits the end of the field
764 fv.visitEnd();
765
766 return u;
767 }
768
769 /**
770 * Reads a method and makes the given visitor visit it.
771 *
772 * @param classVisitor
773 * the visitor that must visit the method.
774 * @param context
775 * information about the class being parsed.
776 * @param u
777 * the start offset of the method in the class file.
778 * @return the offset of the first byte following the method in the class.
779 */
780 private int readMethod(final ClassVisitor classVisitor,
781 final Context context, int u) {
782 // reads the method declaration
783 char[] c = context.buffer;
784 int access = readUnsignedShort(u);
785 String name = readUTF8(u + 2, c);
786 String desc = readUTF8(u + 4, c);
787 u += 6;
788
789 // reads the method attributes
790 int code = 0;
791 int exception = 0;
792 String[] exceptions = null;
793 String signature = null;
794 int anns = 0;
795 int ianns = 0;
796 int dann = 0;
797 int mpanns = 0;
798 int impanns = 0;
799 int firstAttribute = u;
800 Attribute attributes = null;
801
802 for (int i = readUnsignedShort(u); i > 0; --i) {
803 String attrName = readUTF8(u + 2, c);
804 // tests are sorted in decreasing frequency order
805 // (based on frequencies observed on typical classes)
806 if ("Code".equals(attrName)) {
807 if ((context.flags & SKIP_CODE) == 0) {
808 code = u + 8;
809 }
810 } else if ("Exceptions".equals(attrName)) {
811 exceptions = new String[readUnsignedShort(u + 8)];
812 exception = u + 10;
813 for (int j = 0; j < exceptions.length; ++j) {
814 exceptions[j] = readClass(exception, c);
815 exception += 2;
816 }
817 } else if (SIGNATURES && "Signature".equals(attrName)) {
818 signature = readUTF8(u + 8, c);
819 } else if ("Deprecated".equals(attrName)) {
820 access |= Opcodes.ACC_DEPRECATED;
821 } else if (ANNOTATIONS
822 && "RuntimeVisibleAnnotations".equals(attrName)) {
823 anns = u + 8;
824 } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) {
825 dann = u + 8;
826 } else if ("Synthetic".equals(attrName)) {
827 access |= Opcodes.ACC_SYNTHETIC
828 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
829 } else if (ANNOTATIONS
830 && "RuntimeInvisibleAnnotations".equals(attrName)) {
831 ianns = u + 8;
832 } else if (ANNOTATIONS
833 && "RuntimeVisibleParameterAnnotations".equals(attrName)) {
834 mpanns = u + 8;
835 } else if (ANNOTATIONS
836 && "RuntimeInvisibleParameterAnnotations".equals(attrName)) {
837 impanns = u + 8;
838 } else {
839 Attribute attr = readAttribute(context.attrs, attrName, u + 8,
840 readInt(u + 4), c, -1, null);
841 if (attr != null) {
842 attr.next = attributes;
843 attributes = attr;
844 }
845 }
846 u += 6 + readInt(u + 4);
847 }
848 u += 2;
849
850 // visits the method declaration
851 MethodVisitor mv = classVisitor.visitMethod(access, name, desc,
852 signature, exceptions);
853 if (mv == null) {
854 return u;
855 }
856
857 /*
858 * if the returned MethodVisitor is in fact a MethodWriter, it means
859 * there is no method adapter between the reader and the writer. If, in
860 * addition, the writer's constant pool was copied from this reader
861 * (mw.cw.cr == this), and the signature and exceptions of the method
862 * have not been changed, then it is possible to skip all visit events
863 * and just copy the original code of the method to the writer (the
864 * access, name and descriptor can have been changed, this is not
865 * important since they are not copied as is from the reader).
866 */
867 if (WRITER && mv instanceof MethodWriter) {
868 MethodWriter mw = (MethodWriter) mv;
869 if (mw.cw.cr == this && signature == mw.signature) {
870 boolean sameExceptions = false;
871 if (exceptions == null) {
872 sameExceptions = mw.exceptionCount == 0;
873 } else if (exceptions.length == mw.exceptionCount) {
874 sameExceptions = true;
875 for (int j = exceptions.length - 1; j >= 0; --j) {
876 exception -= 2;
877 if (mw.exceptions[j] != readUnsignedShort(exception)) {
878 sameExceptions = false;
879 break;
880 }
881 }
882 }
883 if (sameExceptions) {
884 /*
885 * we do not copy directly the code into MethodWriter to
886 * save a byte array copy operation. The real copy will be
887 * done in ClassWriter.toByteArray().
888 */
889 mw.classReaderOffset = firstAttribute;
890 mw.classReaderLength = u - firstAttribute;
891 return u;
892 }
893 }
894 }
895
896 // visits the method annotations
897 if (ANNOTATIONS && dann != 0) {
898 AnnotationVisitor dv = mv.visitAnnotationDefault();
899 readAnnotationValue(dann, c, null, dv);
900 if (dv != null) {
901 dv.visitEnd();
902 }
903 }
904 if (ANNOTATIONS && anns != 0) {
905 for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
906 v = readAnnotationValues(v + 2, c, true,
907 mv.visitAnnotation(readUTF8(v, c), true));
908 }
909 }
910 if (ANNOTATIONS && ianns != 0) {
911 for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
912 v = readAnnotationValues(v + 2, c, true,
913 mv.visitAnnotation(readUTF8(v, c), false));
914 }
915 }
916 if (ANNOTATIONS && mpanns != 0) {
917 readParameterAnnotations(mpanns, desc, c, true, mv);
918 }
919 if (ANNOTATIONS && impanns != 0) {
920 readParameterAnnotations(impanns, desc, c, false, mv);
921 }
922
923 // visits the method attributes
924 while (attributes != null) {
925 Attribute attr = attributes.next;
926 attributes.next = null;
927 mv.visitAttribute(attributes);
928 attributes = attr;
929 }
930
931 // visits the method code
932 if (code != 0) {
933 context.access = access;
934 context.name = name;
935 context.desc = desc;
936 mv.visitCode();
937 readCode(mv, context, code);
938 }
939
940 // visits the end of the method
941 mv.visitEnd();
942
943 return u;
944 }
945
946 /**
947 * Reads the bytecode of a method and makes the given visitor visit it.
948 *
949 * @param mv
950 * the visitor that must visit the method's code.
951 * @param context
952 * information about the class being parsed.
953 * @param u
954 * the start offset of the code attribute in the class file.
955 */
956 private void readCode(final MethodVisitor mv, final Context context, int u) {
957 // reads the header
958 byte[] b = this.b;
959 char[] c = context.buffer;
960 int maxStack = readUnsignedShort(u);
961 int maxLocals = readUnsignedShort(u + 2);
962 int codeLength = readInt(u + 4);
963 u += 8;
964
965 // reads the bytecode to find the labels
966 int codeStart = u;
967 int codeEnd = u + codeLength;
968 Label[] labels = new Label[codeLength + 2];
969 readLabel(codeLength + 1, labels);
970 while (u < codeEnd) {
971 int offset = u - codeStart;
972 int opcode = b[u] & 0xFF;
973 switch (ClassWriter.TYPE[opcode]) {
974 case ClassWriter.NOARG_INSN:
975 case ClassWriter.IMPLVAR_INSN:
976 u += 1;
977 break;
978 case ClassWriter.LABEL_INSN:
979 readLabel(offset + readShort(u + 1), labels);
980 u += 3;
981 break;
982 case ClassWriter.LABELW_INSN:
983 readLabel(offset + readInt(u + 1), labels);
984 u += 5;
985 break;
986 case ClassWriter.WIDE_INSN:
987 opcode = b[u + 1] & 0xFF;
988 if (opcode == Opcodes.IINC) {
989 u += 6;
990 } else {
991 u += 4;
992 }
993 break;
994 case ClassWriter.TABL_INSN:
995 // skips 0 to 3 padding bytes
996 u = u + 4 - (offset & 3);
997 // reads instruction
998 readLabel(offset + readInt(u), labels);
999 for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) {
1000 readLabel(offset + readInt(u + 12), labels);
1001 u += 4;
1002 }
1003 u += 12;
1004 break;
1005 case ClassWriter.LOOK_INSN:
1006 // skips 0 to 3 padding bytes
1007 u = u + 4 - (offset & 3);
1008 // reads instruction
1009 readLabel(offset + readInt(u), labels);
1010 for (int i = readInt(u + 4); i > 0; --i) {
1011 readLabel(offset + readInt(u + 12), labels);
1012 u += 8;
1013 }
1014 u += 8;
1015 break;
1016 case ClassWriter.VAR_INSN:
1017 case ClassWriter.SBYTE_INSN:
1018 case ClassWriter.LDC_INSN:
1019 u += 2;
1020 break;
1021 case ClassWriter.SHORT_INSN:
1022 case ClassWriter.LDCW_INSN:
1023 case ClassWriter.FIELDORMETH_INSN:
1024 case ClassWriter.TYPE_INSN:
1025 case ClassWriter.IINC_INSN:
1026 u += 3;
1027 break;
1028 case ClassWriter.ITFMETH_INSN:
1029 case ClassWriter.INDYMETH_INSN:
1030 u += 5;
1031 break;
1032 // case MANA_INSN:
1033 default:
1034 u += 4;
1035 break;
1036 }
1037 }
1038
1039 // reads the try catch entries to find the labels, and also visits them
1040 for (int i = readUnsignedShort(u); i > 0; --i) {
1041 Label start = readLabel(readUnsignedShort(u + 2), labels);
1042 Label end = readLabel(readUnsignedShort(u + 4), labels);
1043 Label handler = readLabel(readUnsignedShort(u + 6), labels);
1044 String type = readUTF8(items[readUnsignedShort(u + 8)], c);
1045 mv.visitTryCatchBlock(start, end, handler, type);
1046 u += 8;
1047 }
1048 u += 2;
1049
1050 // reads the code attributes
1051 int varTable = 0;
1052 int varTypeTable = 0;
1053 boolean zip = true;
1054 boolean unzip = (context.flags & EXPAND_FRAMES) != 0;
1055 int stackMap = 0;
1056 int stackMapSize = 0;
1057 int frameCount = 0;
1058 Context frame = null;
1059 Attribute attributes = null;
1060
1061 for (int i = readUnsignedShort(u); i > 0; --i) {
1062 String attrName = readUTF8(u + 2, c);
1063 if ("LocalVariableTable".equals(attrName)) {
1064 if ((context.flags & SKIP_DEBUG) == 0) {
1065 varTable = u + 8;
1066 for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
1067 int label = readUnsignedShort(v + 10);
1068 if (labels[label] == null) {
1069 readLabel(label, labels).status |= Label.DEBUG;
1070 }
1071 label += readUnsignedShort(v + 12);
1072 if (labels[label] == null) {
1073 readLabel(label, labels).status |= Label.DEBUG;
1074 }
1075 v += 10;
1076 }
1077 }
1078 } else if ("LocalVariableTypeTable".equals(attrName)) {
1079 varTypeTable = u + 8;
1080 } else if ("LineNumberTable".equals(attrName)) {
1081 if ((context.flags & SKIP_DEBUG) == 0) {
1082 for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
1083 int label = readUnsignedShort(v + 10);
1084 if (labels[label] == null) {
1085 readLabel(label, labels).status |= Label.DEBUG;
1086 }
1087 labels[label].line = readUnsignedShort(v + 12);
1088 v += 4;
1089 }
1090 }
1091 } else if (FRAMES && "StackMapTable".equals(attrName)) {
1092 if ((context.flags & SKIP_FRAMES) == 0) {
1093 stackMap = u + 10;
1094 stackMapSize = readInt(u + 4);
1095 frameCount = readUnsignedShort(u + 8);
1096 }
1097 /*
1098 * here we do not extract the labels corresponding to the
1099 * attribute content. This would require a full parsing of the
1100 * attribute, which would need to be repeated in the second
1101 * phase (see below). Instead the content of the attribute is
1102 * read one frame at a time (i.e. after a frame has been
1103 * visited, the next frame is read), and the labels it contains
1104 * are also extracted one frame at a time. Thanks to the
1105 * ordering of frames, having only a "one frame lookahead" is
1106 * not a problem, i.e. it is not possible to see an offset
1107 * smaller than the offset of the current insn and for which no
1108 * Label exist.
1109 */
1110 /*
1111 * This is not true for UNINITIALIZED type offsets. We solve
1112 * this by parsing the stack map table without a full decoding
1113 * (see below).
1114 */
1115 } else if (FRAMES && "StackMap".equals(attrName)) {
1116 if ((context.flags & SKIP_FRAMES) == 0) {
1117 zip = false;
1118 stackMap = u + 10;
1119 stackMapSize = readInt(u + 4);
1120 frameCount = readUnsignedShort(u + 8);
1121 }
1122 /*
1123 * IMPORTANT! here we assume that the frames are ordered, as in
1124 * the StackMapTable attribute, although this is not guaranteed
1125 * by the attribute format.
1126 */
1127 } else {
1128 for (int j = 0; j < context.attrs.length; ++j) {
1129 if (context.attrs[j].type.equals(attrName)) {
1130 Attribute attr = context.attrs[j].read(this, u + 8,
1131 readInt(u + 4), c, codeStart - 8, labels);
1132 if (attr != null) {
1133 attr.next = attributes;
1134 attributes = attr;
1135 }
1136 }
1137 }
1138 }
1139 u += 6 + readInt(u + 4);
1140 }
1141 u += 2;
1142
1143 // generates the first (implicit) stack map frame
1144 if (FRAMES && stackMap != 0) {
1145 /*
1146 * for the first explicit frame the offset is not offset_delta + 1
1147 * but only offset_delta; setting the implicit frame offset to -1
1148 * allow the use of the "offset_delta + 1" rule in all cases
1149 */
1150 frame = context;
1151 frame.offset = -1;
1152 frame.mode = 0;
1153 frame.localCount = 0;
1154 frame.localDiff = 0;
1155 frame.stackCount = 0;
1156 frame.local = new Object[maxLocals];
1157 frame.stack = new Object[maxStack];
1158 if (unzip) {
1159 getImplicitFrame(context);
1160 }
1161 /*
1162 * Finds labels for UNINITIALIZED frame types. Instead of decoding
1163 * each element of the stack map table, we look for 3 consecutive
1164 * bytes that "look like" an UNINITIALIZED type (tag 8, offset
1165 * within code bounds, NEW instruction at this offset). We may find
1166 * false positives (i.e. not real UNINITIALIZED types), but this
1167 * should be rare, and the only consequence will be the creation of
1168 * an unneeded label. This is better than creating a label for each
1169 * NEW instruction, and faster than fully decoding the whole stack
1170 * map table.
1171 */
1172 for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) {
1173 if (b[i] == 8) { // UNINITIALIZED FRAME TYPE
1174 int v = readUnsignedShort(i + 1);
1175 if (v >= 0 && v < codeLength) {
1176 if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) {
1177 readLabel(v, labels);
1178 }
1179 }
1180 }
1181 }
1182 }
1183
1184 // visits the instructions
1185 u = codeStart;
1186 while (u < codeEnd) {
1187 int offset = u - codeStart;
1188
1189 // visits the label and line number for this offset, if any
1190 Label l = labels[offset];
1191 if (l != null) {
1192 mv.visitLabel(l);
1193 if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) {
1194 mv.visitLineNumber(l.line, l);
1195 }
1196 }
1197
1198 // visits the frame for this offset, if any
1199 while (FRAMES && frame != null
1200 && (frame.offset == offset || frame.offset == -1)) {
1201 // if there is a frame for this offset, makes the visitor visit
1202 // it, and reads the next frame if there is one.
1203 if (frame.offset != -1) {
1204 if (!zip || unzip) {
1205 mv.visitFrame(Opcodes.F_NEW, frame.localCount,
1206 frame.local, frame.stackCount, frame.stack);
1207 } else {
1208 mv.visitFrame(frame.mode, frame.localDiff, frame.local,
1209 frame.stackCount, frame.stack);
1210 }
1211 }
1212 if (frameCount > 0) {
1213 stackMap = readFrame(stackMap, zip, unzip, labels, frame);
1214 --frameCount;
1215 } else {
1216 frame = null;
1217 }
1218 }
1219
1220 // visits the instruction at this offset
1221 int opcode = b[u] & 0xFF;
1222 switch (ClassWriter.TYPE[opcode]) {
1223 case ClassWriter.NOARG_INSN:
1224 mv.visitInsn(opcode);
1225 u += 1;
1226 break;
1227 case ClassWriter.IMPLVAR_INSN:
1228 if (opcode > Opcodes.ISTORE) {
1229 opcode -= 59; // ISTORE_0
1230 mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2),
1231 opcode & 0x3);
1232 } else {
1233 opcode -= 26; // ILOAD_0
1234 mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3);
1235 }
1236 u += 1;
1237 break;
1238 case ClassWriter.LABEL_INSN:
1239 mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]);
1240 u += 3;
1241 break;
1242 case ClassWriter.LABELW_INSN:
1243 mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]);
1244 u += 5;
1245 break;
1246 case ClassWriter.WIDE_INSN:
1247 opcode = b[u + 1] & 0xFF;
1248 if (opcode == Opcodes.IINC) {
1249 mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4));
1250 u += 6;
1251 } else {
1252 mv.visitVarInsn(opcode, readUnsignedShort(u + 2));
1253 u += 4;
1254 }
1255 break;
1256 case ClassWriter.TABL_INSN: {
1257 // skips 0 to 3 padding bytes
1258 u = u + 4 - (offset & 3);
1259 // reads instruction
1260 int label = offset + readInt(u);
1261 int min = readInt(u + 4);
1262 int max = readInt(u + 8);
1263 Label[] table = new Label[max - min + 1];
1264 u += 12;
1265 for (int i = 0; i < table.length; ++i) {
1266 table[i] = labels[offset + readInt(u)];
1267 u += 4;
1268 }
1269 mv.visitTableSwitchInsn(min, max, labels[label], table);
1270 break;
1271 }
1272 case ClassWriter.LOOK_INSN: {
1273 // skips 0 to 3 padding bytes
1274 u = u + 4 - (offset & 3);
1275 // reads instruction
1276 int label = offset + readInt(u);
1277 int len = readInt(u + 4);
1278 int[] keys = new int[len];
1279 Label[] values = new Label[len];
1280 u += 8;
1281 for (int i = 0; i < len; ++i) {
1282 keys[i] = readInt(u);
1283 values[i] = labels[offset + readInt(u + 4)];
1284 u += 8;
1285 }
1286 mv.visitLookupSwitchInsn(labels[label], keys, values);
1287 break;
1288 }
1289 case ClassWriter.VAR_INSN:
1290 mv.visitVarInsn(opcode, b[u + 1] & 0xFF);
1291 u += 2;
1292 break;
1293 case ClassWriter.SBYTE_INSN:
1294 mv.visitIntInsn(opcode, b[u + 1]);
1295 u += 2;
1296 break;
1297 case ClassWriter.SHORT_INSN:
1298 mv.visitIntInsn(opcode, readShort(u + 1));
1299 u += 3;
1300 break;
1301 case ClassWriter.LDC_INSN:
1302 mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c));
1303 u += 2;
1304 break;
1305 case ClassWriter.LDCW_INSN:
1306 mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c));
1307 u += 3;
1308 break;
1309 case ClassWriter.FIELDORMETH_INSN:
1310 case ClassWriter.ITFMETH_INSN: {
1311 int cpIndex = items[readUnsignedShort(u + 1)];
1312 String iowner = readClass(cpIndex, c);
1313 cpIndex = items[readUnsignedShort(cpIndex + 2)];
1314 String iname = readUTF8(cpIndex, c);
1315 String idesc = readUTF8(cpIndex + 2, c);
1316 if (opcode < Opcodes.INVOKEVIRTUAL) {
1317 mv.visitFieldInsn(opcode, iowner, iname, idesc);
1318 } else {
1319 mv.visitMethodInsn(opcode, iowner, iname, idesc);
1320 }
1321 if (opcode == Opcodes.INVOKEINTERFACE) {
1322 u += 5;
1323 } else {
1324 u += 3;
1325 }
1326 break;
1327 }
1328 case ClassWriter.INDYMETH_INSN: {
1329 int cpIndex = items[readUnsignedShort(u + 1)];
1330 int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)];
1331 Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c);
1332 int bsmArgCount = readUnsignedShort(bsmIndex + 2);
1333 Object[] bsmArgs = new Object[bsmArgCount];
1334 bsmIndex += 4;
1335 for (int i = 0; i < bsmArgCount; i++) {
1336 bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c);
1337 bsmIndex += 2;
1338 }
1339 cpIndex = items[readUnsignedShort(cpIndex + 2)];
1340 String iname = readUTF8(cpIndex, c);
1341 String idesc = readUTF8(cpIndex + 2, c);
1342 mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs);
1343 u += 5;
1344 break;
1345 }
1346 case ClassWriter.TYPE_INSN:
1347 mv.visitTypeInsn(opcode, readClass(u + 1, c));
1348 u += 3;
1349 break;
1350 case ClassWriter.IINC_INSN:
1351 mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]);
1352 u += 3;
1353 break;
1354 // case MANA_INSN:
1355 default:
1356 mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF);
1357 u += 4;
1358 break;
1359 }
1360 }
1361 if (labels[codeLength] != null) {
1362 mv.visitLabel(labels[codeLength]);
1363 }
1364
1365 // visits the local variable tables
1366 if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) {
1367 int[] typeTable = null;
1368 if (varTypeTable != 0) {
1369 u = varTypeTable + 2;
1370 typeTable = new int[readUnsignedShort(varTypeTable) * 3];
1371 for (int i = typeTable.length; i > 0;) {
1372 typeTable[--i] = u + 6; // signature
1373 typeTable[--i] = readUnsignedShort(u + 8); // index
1374 typeTable[--i] = readUnsignedShort(u); // start
1375 u += 10;
1376 }
1377 }
1378 u = varTable + 2;
1379 for (int i = readUnsignedShort(varTable); i > 0; --i) {
1380 int start = readUnsignedShort(u);
1381 int length = readUnsignedShort(u + 2);
1382 int index = readUnsignedShort(u + 8);
1383 String vsignature = null;
1384 if (typeTable != null) {
1385 for (int j = 0; j < typeTable.length; j += 3) {
1386 if (typeTable[j] == start && typeTable[j + 1] == index) {
1387 vsignature = readUTF8(typeTable[j + 2], c);
1388 break;
1389 }
1390 }
1391 }
1392 mv.visitLocalVariable(readUTF8(u + 4, c), readUTF8(u + 6, c),
1393 vsignature, labels[start], labels[start + length],
1394 index);
1395 u += 10;
1396 }
1397 }
1398
1399 // visits the code attributes
1400 while (attributes != null) {
1401 Attribute attr = attributes.next;
1402 attributes.next = null;
1403 mv.visitAttribute(attributes);
1404 attributes = attr;
1405 }
1406
1407 // visits the max stack and max locals values
1408 mv.visitMaxs(maxStack, maxLocals);
1409 }
1410
1411 /**
1412 * Reads parameter annotations and makes the given visitor visit them.
1413 *
1414 * @param v
1415 * start offset in {@link #b b} of the annotations to be read.
1416 * @param desc
1417 * the method descriptor.
1418 * @param buf
1419 * buffer to be used to call {@link #readUTF8 readUTF8},
1420 * {@link #readClass(int,char[]) readClass} or {@link #readConst
1421 * readConst}.
1422 * @param visible
1423 * <tt>true</tt> if the annotations to be read are visible at
1424 * runtime.
1425 * @param mv
1426 * the visitor that must visit the annotations.
1427 */
1428 private void readParameterAnnotations(int v, final String desc,
1429 final char[] buf, final boolean visible, final MethodVisitor mv) {
1430 int i;
1431 int n = b[v++] & 0xFF;
1432 // workaround for a bug in javac (javac compiler generates a parameter
1433 // annotation array whose size is equal to the number of parameters in
1434 // the Java source file, while it should generate an array whose size is
1435 // equal to the number of parameters in the method descriptor - which
1436 // includes the synthetic parameters added by the compiler). This work-
1437 // around supposes that the synthetic parameters are the first ones.
1438 int synthetics = Type.getArgumentTypes(desc).length - n;
1439 AnnotationVisitor av;
1440 for (i = 0; i < synthetics; ++i) {
1441 // virtual annotation to detect synthetic parameters in MethodWriter
1442 av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false);
1443 if (av != null) {
1444 av.visitEnd();
1445 }
1446 }
1447 for (; i < n + synthetics; ++i) {
1448 int j = readUnsignedShort(v);
1449 v += 2;
1450 for (; j > 0; --j) {
1451 av = mv.visitParameterAnnotation(i, readUTF8(v, buf), visible);
1452 v = readAnnotationValues(v + 2, buf, true, av);
1453 }
1454 }
1455 }
1456
1457 /**
1458 * Reads the values of an annotation and makes the given visitor visit them.
1459 *
1460 * @param v
1461 * the start offset in {@link #b b} of the values to be read
1462 * (including the unsigned short that gives the number of
1463 * values).
1464 * @param buf
1465 * buffer to be used to call {@link #readUTF8 readUTF8},
1466 * {@link #readClass(int,char[]) readClass} or {@link #readConst
1467 * readConst}.
1468 * @param named
1469 * if the annotation values are named or not.
1470 * @param av
1471 * the visitor that must visit the values.
1472 * @return the end offset of the annotation values.
1473 */
1474 private int readAnnotationValues(int v, final char[] buf,
1475 final boolean named, final AnnotationVisitor av) {
1476 int i = readUnsignedShort(v);
1477 v += 2;
1478 if (named) {
1479 for (; i > 0; --i) {
1480 v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av);
1481 }
1482 } else {
1483 for (; i > 0; --i) {
1484 v = readAnnotationValue(v, buf, null, av);
1485 }
1486 }
1487 if (av != null) {
1488 av.visitEnd();
1489 }
1490 return v;
1491 }
1492
1493 /**
1494 * Reads a value of an annotation and makes the given visitor visit it.
1495 *
1496 * @param v
1497 * the start offset in {@link #b b} of the value to be read
1498 * (<i>not including the value name constant pool index</i>).
1499 * @param buf
1500 * buffer to be used to call {@link #readUTF8 readUTF8},
1501 * {@link #readClass(int,char[]) readClass} or {@link #readConst
1502 * readConst}.
1503 * @param name
1504 * the name of the value to be read.
1505 * @param av
1506 * the visitor that must visit the value.
1507 * @return the end offset of the annotation value.
1508 */
1509 private int readAnnotationValue(int v, final char[] buf, final String name,
1510 final AnnotationVisitor av) {
1511 int i;
1512 if (av == null) {
1513 switch (b[v] & 0xFF) {
1514 case 'e': // enum_const_value
1515 return v + 5;
1516 case '@': // annotation_value
1517 return readAnnotationValues(v + 3, buf, true, null);
1518 case '[': // array_value
1519 return readAnnotationValues(v + 1, buf, false, null);
1520 default:
1521 return v + 3;
1522 }
1523 }
1524 switch (b[v++] & 0xFF) {
1525 case 'I': // pointer to CONSTANT_Integer
1526 case 'J': // pointer to CONSTANT_Long
1527 case 'F': // pointer to CONSTANT_Float
1528 case 'D': // pointer to CONSTANT_Double
1529 av.visit(name, readConst(readUnsignedShort(v), buf));
1530 v += 2;
1531 break;
1532 case 'B': // pointer to CONSTANT_Byte
1533 av.visit(name,
1534 new Byte((byte) readInt(items[readUnsignedShort(v)])));
1535 v += 2;
1536 break;
1537 case 'Z': // pointer to CONSTANT_Boolean
1538 av.visit(name,
1539 readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE
1540 : Boolean.TRUE);
1541 v += 2;
1542 break;
1543 case 'S': // pointer to CONSTANT_Short
1544 av.visit(name, new Short(
1545 (short) readInt(items[readUnsignedShort(v)])));
1546 v += 2;
1547 break;
1548 case 'C': // pointer to CONSTANT_Char
1549 av.visit(name, new Character(
1550 (char) readInt(items[readUnsignedShort(v)])));
1551 v += 2;
1552 break;
1553 case 's': // pointer to CONSTANT_Utf8
1554 av.visit(name, readUTF8(v, buf));
1555 v += 2;
1556 break;
1557 case 'e': // enum_const_value
1558 av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf));
1559 v += 4;
1560 break;
1561 case 'c': // class_info
1562 av.visit(name, Type.getType(readUTF8(v, buf)));
1563 v += 2;
1564 break;
1565 case '@': // annotation_value
1566 v = readAnnotationValues(v + 2, buf, true,
1567 av.visitAnnotation(name, readUTF8(v, buf)));
1568 break;
1569 case '[': // array_value
1570 int size = readUnsignedShort(v);
1571 v += 2;
1572 if (size == 0) {
1573 return readAnnotationValues(v - 2, buf, false,
1574 av.visitArray(name));
1575 }
1576 switch (this.b[v++] & 0xFF) {
1577 case 'B':
1578 byte[] bv = new byte[size];
1579 for (i = 0; i < size; i++) {
1580 bv[i] = (byte) readInt(items[readUnsignedShort(v)]);
1581 v += 3;
1582 }
1583 av.visit(name, bv);
1584 --v;
1585 break;
1586 case 'Z':
1587 boolean[] zv = new boolean[size];
1588 for (i = 0; i < size; i++) {
1589 zv[i] = readInt(items[readUnsignedShort(v)]) != 0;
1590 v += 3;
1591 }
1592 av.visit(name, zv);
1593 --v;
1594 break;
1595 case 'S':
1596 short[] sv = new short[size];
1597 for (i = 0; i < size; i++) {
1598 sv[i] = (short) readInt(items[readUnsignedShort(v)]);
1599 v += 3;
1600 }
1601 av.visit(name, sv);
1602 --v;
1603 break;
1604 case 'C':
1605 char[] cv = new char[size];
1606 for (i = 0; i < size; i++) {
1607 cv[i] = (char) readInt(items[readUnsignedShort(v)]);
1608 v += 3;
1609 }
1610 av.visit(name, cv);
1611 --v;
1612 break;
1613 case 'I':
1614 int[] iv = new int[size];
1615 for (i = 0; i < size; i++) {
1616 iv[i] = readInt(items[readUnsignedShort(v)]);
1617 v += 3;
1618 }
1619 av.visit(name, iv);
1620 --v;
1621 break;
1622 case 'J':
1623 long[] lv = new long[size];
1624 for (i = 0; i < size; i++) {
1625 lv[i] = readLong(items[readUnsignedShort(v)]);
1626 v += 3;
1627 }
1628 av.visit(name, lv);
1629 --v;
1630 break;
1631 case 'F':
1632 float[] fv = new float[size];
1633 for (i = 0; i < size; i++) {
1634 fv[i] = Float
1635 .intBitsToFloat(readInt(items[readUnsignedShort(v)]));
1636 v += 3;
1637 }
1638 av.visit(name, fv);
1639 --v;
1640 break;
1641 case 'D':
1642 double[] dv = new double[size];
1643 for (i = 0; i < size; i++) {
1644 dv[i] = Double
1645 .longBitsToDouble(readLong(items[readUnsignedShort(v)]));
1646 v += 3;
1647 }
1648 av.visit(name, dv);
1649 --v;
1650 break;
1651 default:
1652 v = readAnnotationValues(v - 3, buf, false, av.visitArray(name));
1653 }
1654 }
1655 return v;
1656 }
1657
1658 /**
1659 * Computes the implicit frame of the method currently being parsed (as
1660 * defined in the given {@link Context}) and stores it in the given context.
1661 *
1662 * @param frame
1663 * information about the class being parsed.
1664 */
1665 private void getImplicitFrame(final Context frame) {
1666 String desc = frame.desc;
1667 Object[] locals = frame.local;
1668 int local = 0;
1669 if ((frame.access & Opcodes.ACC_STATIC) == 0) {
1670 if ("<init>".equals(frame.name)) {
1671 locals[local++] = Opcodes.UNINITIALIZED_THIS;
1672 } else {
1673 locals[local++] = readClass(header + 2, frame.buffer);
1674 }
1675 }
1676 int i = 1;
1677 loop: while (true) {
1678 int j = i;
1679 switch (desc.charAt(i++)) {
1680 case 'Z':
1681 case 'C':
1682 case 'B':
1683 case 'S':
1684 case 'I':
1685 locals[local++] = Opcodes.INTEGER;
1686 break;
1687 case 'F':
1688 locals[local++] = Opcodes.FLOAT;
1689 break;
1690 case 'J':
1691 locals[local++] = Opcodes.LONG;
1692 break;
1693 case 'D':
1694 locals[local++] = Opcodes.DOUBLE;
1695 break;
1696 case '[':
1697 while (desc.charAt(i) == '[') {
1698 ++i;
1699 }
1700 if (desc.charAt(i) == 'L') {
1701 ++i;
1702 while (desc.charAt(i) != ';') {
1703 ++i;
1704 }
1705 }
1706 locals[local++] = desc.substring(j, ++i);
1707 break;
1708 case 'L':
1709 while (desc.charAt(i) != ';') {
1710 ++i;
1711 }
1712 locals[local++] = desc.substring(j + 1, i++);
1713 break;
1714 default:
1715 break loop;
1716 }
1717 }
1718 frame.localCount = local;
1719 }
1720
1721 /**
1722 * Reads a stack map frame and stores the result in the given
1723 * {@link Context} object.
1724 *
1725 * @param stackMap
1726 * the start offset of a stack map frame in the class file.
1727 * @param zip
1728 * if the stack map frame at stackMap is compressed or not.
1729 * @param unzip
1730 * if the stack map frame must be uncompressed.
1731 * @param labels
1732 * the labels of the method currently being parsed, indexed by
1733 * their offset. A new label for the parsed stack map frame is
1734 * stored in this array if it does not already exist.
1735 * @param frame
1736 * where the parsed stack map frame must be stored.
1737 * @return the offset of the first byte following the parsed frame.
1738 */
1739 private int readFrame(int stackMap, boolean zip, boolean unzip,
1740 Label[] labels, Context frame) {
1741 char[] c = frame.buffer;
1742 int tag;
1743 int delta;
1744 if (zip) {
1745 tag = b[stackMap++] & 0xFF;
1746 } else {
1747 tag = MethodWriter.FULL_FRAME;
1748 frame.offset = -1;
1749 }
1750 frame.localDiff = 0;
1751 if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) {
1752 delta = tag;
1753 frame.mode = Opcodes.F_SAME;
1754 frame.stackCount = 0;
1755 } else if (tag < MethodWriter.RESERVED) {
1756 delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME;
1757 stackMap = readFrameType(frame.stack, 0, stackMap, c, labels);
1758 frame.mode = Opcodes.F_SAME1;
1759 frame.stackCount = 1;
1760 } else {
1761 delta = readUnsignedShort(stackMap);
1762 stackMap += 2;
1763 if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
1764 stackMap = readFrameType(frame.stack, 0, stackMap, c, labels);
1765 frame.mode = Opcodes.F_SAME1;
1766 frame.stackCount = 1;
1767 } else if (tag >= MethodWriter.CHOP_FRAME
1768 && tag < MethodWriter.SAME_FRAME_EXTENDED) {
1769 frame.mode = Opcodes.F_CHOP;
1770 frame.localDiff = MethodWriter.SAME_FRAME_EXTENDED - tag;
1771 frame.localCount -= frame.localDiff;
1772 frame.stackCount = 0;
1773 } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) {
1774 frame.mode = Opcodes.F_SAME;
1775 frame.stackCount = 0;
1776 } else if (tag < MethodWriter.FULL_FRAME) {
1777 int local = unzip ? frame.localCount : 0;
1778 for (int i = tag - MethodWriter.SAME_FRAME_EXTENDED; i > 0; i--) {
1779 stackMap = readFrameType(frame.local, local++, stackMap, c,
1780 labels);
1781 }
1782 frame.mode = Opcodes.F_APPEND;
1783 frame.localDiff = tag - MethodWriter.SAME_FRAME_EXTENDED;
1784 frame.localCount += frame.localDiff;
1785 frame.stackCount = 0;
1786 } else { // if (tag == FULL_FRAME) {
1787 frame.mode = Opcodes.F_FULL;
1788 int n = readUnsignedShort(stackMap);
1789 stackMap += 2;
1790 frame.localDiff = n;
1791 frame.localCount = n;
1792 for (int local = 0; n > 0; n--) {
1793 stackMap = readFrameType(frame.local, local++, stackMap, c,
1794 labels);
1795 }
1796 n = readUnsignedShort(stackMap);
1797 stackMap += 2;
1798 frame.stackCount = n;
1799 for (int stack = 0; n > 0; n--) {
1800 stackMap = readFrameType(frame.stack, stack++, stackMap, c,
1801 labels);
1802 }
1803 }
1804 }
1805 frame.offset += delta + 1;
1806 readLabel(frame.offset, labels);
1807 return stackMap;
1808 }
1809
1810 /**
1811 * Reads a stack map frame type and stores it at the given index in the
1812 * given array.
1813 *
1814 * @param frame
1815 * the array where the parsed type must be stored.
1816 * @param index
1817 * the index in 'frame' where the parsed type must be stored.
1818 * @param v
1819 * the start offset of the stack map frame type to read.
1820 * @param buf
1821 * a buffer to read strings.
1822 * @param labels
1823 * the labels of the method currently being parsed, indexed by
1824 * their offset. If the parsed type is an Uninitialized type, a
1825 * new label for the corresponding NEW instruction is stored in
1826 * this array if it does not already exist.
1827 * @return the offset of the first byte after the parsed type.
1828 */
1829 private int readFrameType(final Object[] frame, final int index, int v,
1830 final char[] buf, final Label[] labels) {
1831 int type = b[v++] & 0xFF;
1832 switch (type) {
1833 case 0:
1834 frame[index] = Opcodes.TOP;
1835 break;
1836 case 1:
1837 frame[index] = Opcodes.INTEGER;
1838 break;
1839 case 2:
1840 frame[index] = Opcodes.FLOAT;
1841 break;
1842 case 3:
1843 frame[index] = Opcodes.DOUBLE;
1844 break;
1845 case 4:
1846 frame[index] = Opcodes.LONG;
1847 break;
1848 case 5:
1849 frame[index] = Opcodes.NULL;
1850 break;
1851 case 6:
1852 frame[index] = Opcodes.UNINITIALIZED_THIS;
1853 break;
1854 case 7: // Object
1855 frame[index] = readClass(v, buf);
1856 v += 2;
1857 break;
1858 default: // Uninitialized
1859 frame[index] = readLabel(readUnsignedShort(v), labels);
1860 v += 2;
1861 }
1862 return v;
1863 }
1864
1865 /**
1866 * Returns the label corresponding to the given offset. The default
1867 * implementation of this method creates a label for the given offset if it
1868 * has not been already created.
1869 *
1870 * @param offset
1871 * a bytecode offset in a method.
1872 * @param labels
1873 * the already created labels, indexed by their offset. If a
1874 * label already exists for offset this method must not create a
1875 * new one. Otherwise it must store the new label in this array.
1876 * @return a non null Label, which must be equal to labels[offset].
1877 */
1878 protected Label readLabel(int offset, Label[] labels) {
1879 if (labels[offset] == null) {
1880 labels[offset] = new Label();
1881 }
1882 return labels[offset];
1883 }
1884
1885 /**
1886 * Returns the start index of the attribute_info structure of this class.
1887 *
1888 * @return the start index of the attribute_info structure of this class.
1889 */
1890 private int getAttributes() {
1891 // skips the header
1892 int u = header + 8 + readUnsignedShort(header + 6) * 2;
1893 // skips fields and methods
1894 for (int i = readUnsignedShort(u); i > 0; --i) {
1895 for (int j = readUnsignedShort(u + 8); j > 0; --j) {
1896 u += 6 + readInt(u + 12);
1897 }
1898 u += 8;
1899 }
1900 u += 2;
1901 for (int i = readUnsignedShort(u); i > 0; --i) {
1902 for (int j = readUnsignedShort(u + 8); j > 0; --j) {
1903 u += 6 + readInt(u + 12);
1904 }
1905 u += 8;
1906 }
1907 // the attribute_info structure starts just after the methods
1908 return u + 2;
1909 }
1910
1911 /**
1912 * Reads an attribute in {@link #b b}.
1913 *
1914 * @param attrs
1915 * prototypes of the attributes that must be parsed during the
1916 * visit of the class. Any attribute whose type is not equal to
1917 * the type of one the prototypes is ignored (i.e. an empty
1918 * {@link Attribute} instance is returned).
1919 * @param type
1920 * the type of the attribute.
1921 * @param off
1922 * index of the first byte of the attribute's content in
1923 * {@link #b b}. The 6 attribute header bytes, containing the
1924 * type and the length of the attribute, are not taken into
1925 * account here (they have already been read).
1926 * @param len
1927 * the length of the attribute's content.
1928 * @param buf
1929 * buffer to be used to call {@link #readUTF8 readUTF8},
1930 * {@link #readClass(int,char[]) readClass} or {@link #readConst
1931 * readConst}.
1932 * @param codeOff
1933 * index of the first byte of code's attribute content in
1934 * {@link #b b}, or -1 if the attribute to be read is not a code
1935 * attribute. The 6 attribute header bytes, containing the type
1936 * and the length of the attribute, are not taken into account
1937 * here.
1938 * @param labels
1939 * the labels of the method's code, or <tt>null</tt> if the
1940 * attribute to be read is not a code attribute.
1941 * @return the attribute that has been read, or <tt>null</tt> to skip this
1942 * attribute.
1943 */
1944 private Attribute readAttribute(final Attribute[] attrs, final String type,
1945 final int off, final int len, final char[] buf, final int codeOff,
1946 final Label[] labels) {
1947 for (int i = 0; i < attrs.length; ++i) {
1948 if (attrs[i].type.equals(type)) {
1949 return attrs[i].read(this, off, len, buf, codeOff, labels);
1950 }
1951 }
1952 return new Attribute(type).read(this, off, len, null, -1, null);
1953 }
1954
1955 // ------------------------------------------------------------------------
1956 // Utility methods: low level parsing
1957 // ------------------------------------------------------------------------
1958
1959 /**
1960 * Returns the number of constant pool items in {@link #b b}.
1961 *
1962 * @return the number of constant pool items in {@link #b b}.
1963 */
1964 public int getItemCount() {
1965 return items.length;
1966 }
1967
1968 /**
1969 * Returns the start index of the constant pool item in {@link #b b}, plus
1970 * one. <i>This method is intended for {@link Attribute} sub classes, and is
1971 * normally not needed by class generators or adapters.</i>
1972 *
1973 * @param item
1974 * the index a constant pool item.
1975 * @return the start index of the constant pool item in {@link #b b}, plus
1976 * one.
1977 */
1978 public int getItem(final int item) {
1979 return items[item];
1980 }
1981
1982 /**
1983 * Returns the maximum length of the strings contained in the constant pool
1984 * of the class.
1985 *
1986 * @return the maximum length of the strings contained in the constant pool
1987 * of the class.
1988 */
1989 public int getMaxStringLength() {
1990 return maxStringLength;
1991 }
1992
1993 /**
1994 * Reads a byte value in {@link #b b}. <i>This method is intended for
1995 * {@link Attribute} sub classes, and is normally not needed by class
1996 * generators or adapters.</i>
1997 *
1998 * @param index
1999 * the start index of the value to be read in {@link #b b}.
2000 * @return the read value.
2001 */
2002 public int readByte(final int index) {
2003 return b[index] & 0xFF;
2004 }
2005
2006 /**
2007 * Reads an unsigned short value in {@link #b b}. <i>This method is intended
2008 * for {@link Attribute} sub classes, and is normally not needed by class
2009 * generators or adapters.</i>
2010 *
2011 * @param index
2012 * the start index of the value to be read in {@link #b b}.
2013 * @return the read value.
2014 */
2015 public int readUnsignedShort(final int index) {
2016 byte[] b = this.b;
2017 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
2018 }
2019
2020 /**
2021 * Reads a signed short value in {@link #b b}. <i>This method is intended
2022 * for {@link Attribute} sub classes, and is normally not needed by class
2023 * generators or adapters.</i>
2024 *
2025 * @param index
2026 * the start index of the value to be read in {@link #b b}.
2027 * @return the read value.
2028 */
2029 public short readShort(final int index) {
2030 byte[] b = this.b;
2031 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
2032 }
2033
2034 /**
2035 * Reads a signed int value in {@link #b b}. <i>This method is intended for
2036 * {@link Attribute} sub classes, and is normally not needed by class
2037 * generators or adapters.</i>
2038 *
2039 * @param index
2040 * the start index of the value to be read in {@link #b b}.
2041 * @return the read value.
2042 */
2043 public int readInt(final int index) {
2044 byte[] b = this.b;
2045 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
2046 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
2047 }
2048
2049 /**
2050 * Reads a signed long value in {@link #b b}. <i>This method is intended for
2051 * {@link Attribute} sub classes, and is normally not needed by class
2052 * generators or adapters.</i>
2053 *
2054 * @param index
2055 * the start index of the value to be read in {@link #b b}.
2056 * @return the read value.
2057 */
2058 public long readLong(final int index) {
2059 long l1 = readInt(index);
2060 long l0 = readInt(index + 4) & 0xFFFFFFFFL;
2061 return (l1 << 32) | l0;
2062 }
2063
2064 /**
2065 * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method
2066 * is intended for {@link Attribute} sub classes, and is normally not needed
2067 * by class generators or adapters.</i>
2068 *
2069 * @param index
2070 * the start index of an unsigned short value in {@link #b b},
2071 * whose value is the index of an UTF8 constant pool item.
2072 * @param buf
2073 * buffer to be used to read the item. This buffer must be
2074 * sufficiently large. It is not automatically resized.
2075 * @return the String corresponding to the specified UTF8 item.
2076 */
2077 public String readUTF8(int index, final char[] buf) {
2078 int item = readUnsignedShort(index);
2079 if (index == 0 || item == 0) {
2080 return null;
2081 }
2082 String s = strings[item];
2083 if (s != null) {
2084 return s;
2085 }
2086 index = items[item];
2087 return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf);
2088 }
2089
2090 /**
2091 * Reads UTF8 string in {@link #b b}.
2092 *
2093 * @param index
2094 * start offset of the UTF8 string to be read.
2095 * @param utfLen
2096 * length of the UTF8 string to be read.
2097 * @param buf
2098 * buffer to be used to read the string. This buffer must be
2099 * sufficiently large. It is not automatically resized.
2100 * @return the String corresponding to the specified UTF8 string.
2101 */
2102 private String readUTF(int index, final int utfLen, final char[] buf) {
2103 int endIndex = index + utfLen;
2104 byte[] b = this.b;
2105 int strLen = 0;
2106 int c;
2107 int st = 0;
2108 char cc = 0;
2109 while (index < endIndex) {
2110 c = b[index++];
2111 switch (st) {
2112 case 0:
2113 c = c & 0xFF;
2114 if (c < 0x80) { // 0xxxxxxx
2115 buf[strLen++] = (char) c;
2116 } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx
2117 cc = (char) (c & 0x1F);
2118 st = 1;
2119 } else { // 1110 xxxx 10xx xxxx 10xx xxxx
2120 cc = (char) (c & 0x0F);
2121 st = 2;
2122 }
2123 break;
2124
2125 case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char
2126 buf[strLen++] = (char) ((cc << 6) | (c & 0x3F));
2127 st = 0;
2128 break;
2129
2130 case 2: // byte 2 of 3-byte char
2131 cc = (char) ((cc << 6) | (c & 0x3F));
2132 st = 1;
2133 break;
2134 }
2135 }
2136 return new String(buf, 0, strLen);
2137 }
2138
2139 /**
2140 * Reads a class constant pool item in {@link #b b}. <i>This method is
2141 * intended for {@link Attribute} sub classes, and is normally not needed by
2142 * class generators or adapters.</i>
2143 *
2144 * @param index
2145 * the start index of an unsigned short value in {@link #b b},
2146 * whose value is the index of a class constant pool item.
2147 * @param buf
2148 * buffer to be used to read the item. This buffer must be
2149 * sufficiently large. It is not automatically resized.
2150 * @return the String corresponding to the specified class item.
2151 */
2152 public String readClass(final int index, final char[] buf) {
2153 // computes the start index of the CONSTANT_Class item in b
2154 // and reads the CONSTANT_Utf8 item designated by
2155 // the first two bytes of this CONSTANT_Class item
2156 return readUTF8(items[readUnsignedShort(index)], buf);
2157 }
2158
2159 /**
2160 * Reads a numeric or string constant pool item in {@link #b b}. <i>This
2161 * method is intended for {@link Attribute} sub classes, and is normally not
2162 * needed by class generators or adapters.</i>
2163 *
2164 * @param item
2165 * the index of a constant pool item.
2166 * @param buf
2167 * buffer to be used to read the item. This buffer must be
2168 * sufficiently large. It is not automatically resized.
2169 * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double},
2170 * {@link String}, {@link Type} or {@link Handle} corresponding to
2171 * the given constant pool item.
2172 */
2173 public Object readConst(final int item, final char[] buf) {
2174 int index = items[item];
2175 switch (b[index - 1]) {
2176 case ClassWriter.INT:
2177 return new Integer(readInt(index));
2178 case ClassWriter.FLOAT:
2179 return new Float(Float.intBitsToFloat(readInt(index)));
2180 case ClassWriter.LONG:
2181 return new Long(readLong(index));
2182 case ClassWriter.DOUBLE:
2183 return new Double(Double.longBitsToDouble(readLong(index)));
2184 case ClassWriter.CLASS:
2185 return Type.getObjectType(readUTF8(index, buf));
2186 case ClassWriter.STR:
2187 return readUTF8(index, buf);
2188 case ClassWriter.MTYPE:
2189 return Type.getMethodType(readUTF8(index, buf));
2190 default: // case ClassWriter.HANDLE_BASE + [1..9]:
2191 int tag = readByte(index);
2192 int[] items = this.items;
2193 int cpIndex = items[readUnsignedShort(index + 1)];
2194 String owner = readClass(cpIndex, buf);
2195 cpIndex = items[readUnsignedShort(cpIndex + 2)];
2196 String name = readUTF8(cpIndex, buf);
2197 String desc = readUTF8(cpIndex + 2, buf);
2198 return new Handle(tag, owner, name, desc);
2199 }
2200 }
2201 }
+0
-286
src/jvm/clojure/asm/ClassVisitor.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package clojure.asm;
30
31 /**
32 * A visitor to visit a Java class. The methods of this class must be called in
33 * the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
34 * <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
35 * <tt>visitAttribute</tt> )* ( <tt>visitInnerClass</tt> | <tt>visitField</tt> |
36 * <tt>visitMethod</tt> )* <tt>visitEnd</tt>.
37 *
38 * @author Eric Bruneton
39 */
40 public abstract class ClassVisitor {
41
42 /**
43 * The ASM API version implemented by this visitor. The value of this field
44 * must be one of {@link Opcodes#ASM4}.
45 */
46 protected final int api;
47
48 /**
49 * The class visitor to which this visitor must delegate method calls. May
50 * be null.
51 */
52 protected ClassVisitor cv;
53
54 /**
55 * Constructs a new {@link ClassVisitor}.
56 *
57 * @param api
58 * the ASM API version implemented by this visitor. Must be one
59 * of {@link Opcodes#ASM4}.
60 */
61 public ClassVisitor(final int api) {
62 this(api, null);
63 }
64
65 /**
66 * Constructs a new {@link ClassVisitor}.
67 *
68 * @param api
69 * the ASM API version implemented by this visitor. Must be one
70 * of {@link Opcodes#ASM4}.
71 * @param cv
72 * the class visitor to which this visitor must delegate method
73 * calls. May be null.
74 */
75 public ClassVisitor(final int api, final ClassVisitor cv) {
76 if (api != Opcodes.ASM4) {
77 throw new IllegalArgumentException();
78 }
79 this.api = api;
80 this.cv = cv;
81 }
82
83 /**
84 * Visits the header of the class.
85 *
86 * @param version
87 * the class version.
88 * @param access
89 * the class's access flags (see {@link Opcodes}). This parameter
90 * also indicates if the class is deprecated.
91 * @param name
92 * the internal name of the class (see
93 * {@link Type#getInternalName() getInternalName}).
94 * @param signature
95 * the signature of this class. May be <tt>null</tt> if the class
96 * is not a generic one, and does not extend or implement generic
97 * classes or interfaces.
98 * @param superName
99 * the internal of name of the super class (see
100 * {@link Type#getInternalName() getInternalName}). For
101 * interfaces, the super class is {@link Object}. May be
102 * <tt>null</tt>, but only for the {@link Object} class.
103 * @param interfaces
104 * the internal names of the class's interfaces (see
105 * {@link Type#getInternalName() getInternalName}). May be
106 * <tt>null</tt>.
107 */
108 public void visit(int version, int access, String name, String signature,
109 String superName, String[] interfaces) {
110 if (cv != null) {
111 cv.visit(version, access, name, signature, superName, interfaces);
112 }
113 }
114
115 /**
116 * Visits the source of the class.
117 *
118 * @param source
119 * the name of the source file from which the class was compiled.
120 * May be <tt>null</tt>.
121 * @param debug
122 * additional debug information to compute the correspondance
123 * between source and compiled elements of the class. May be
124 * <tt>null</tt>.
125 */
126 public void visitSource(String source, String debug) {
127 if (cv != null) {
128 cv.visitSource(source, debug);
129 }
130 }
131
132 /**
133 * Visits the enclosing class of the class. This method must be called only
134 * if the class has an enclosing class.
135 *
136 * @param owner
137 * internal name of the enclosing class of the class.
138 * @param name
139 * the name of the method that contains the class, or
140 * <tt>null</tt> if the class is not enclosed in a method of its
141 * enclosing class.
142 * @param desc
143 * the descriptor of the method that contains the class, or
144 * <tt>null</tt> if the class is not enclosed in a method of its
145 * enclosing class.
146 */
147 public void visitOuterClass(String owner, String name, String desc) {
148 if (cv != null) {
149 cv.visitOuterClass(owner, name, desc);
150 }
151 }
152
153 /**
154 * Visits an annotation of the class.
155 *
156 * @param desc
157 * the class descriptor of the annotation class.
158 * @param visible
159 * <tt>true</tt> if the annotation is visible at runtime.
160 * @return a visitor to visit the annotation values, or <tt>null</tt> if
161 * this visitor is not interested in visiting this annotation.
162 */
163 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
164 if (cv != null) {
165 return cv.visitAnnotation(desc, visible);
166 }
167 return null;
168 }
169
170 /**
171 * Visits a non standard attribute of the class.
172 *
173 * @param attr
174 * an attribute.
175 */
176 public void visitAttribute(Attribute attr) {
177 if (cv != null) {
178 cv.visitAttribute(attr);
179 }
180 }
181
182 /**
183 * Visits information about an inner class. This inner class is not
184 * necessarily a member of the class being visited.
185 *
186 * @param name
187 * the internal name of an inner class (see
188 * {@link Type#getInternalName() getInternalName}).
189 * @param outerName
190 * the internal name of the class to which the inner class
191 * belongs (see {@link Type#getInternalName() getInternalName}).
192 * May be <tt>null</tt> for not member classes.
193 * @param innerName
194 * the (simple) name of the inner class inside its enclosing
195 * class. May be <tt>null</tt> for anonymous inner classes.
196 * @param access
197 * the access flags of the inner class as originally declared in
198 * the enclosing class.
199 */
200 public void visitInnerClass(String name, String outerName,
201 String innerName, int access) {
202 if (cv != null) {
203 cv.visitInnerClass(name, outerName, innerName, access);
204 }
205 }
206
207 /**
208 * Visits a field of the class.
209 *
210 * @param access
211 * the field's access flags (see {@link Opcodes}). This parameter
212 * also indicates if the field is synthetic and/or deprecated.
213 * @param name
214 * the field's name.
215 * @param desc
216 * the field's descriptor (see {@link Type Type}).
217 * @param signature
218 * the field's signature. May be <tt>null</tt> if the field's
219 * type does not use generic types.
220 * @param value
221 * the field's initial value. This parameter, which may be
222 * <tt>null</tt> if the field does not have an initial value,
223 * must be an {@link Integer}, a {@link Float}, a {@link Long}, a
224 * {@link Double} or a {@link String} (for <tt>int</tt>,
225 * <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
226 * respectively). <i>This parameter is only used for static
227 * fields</i>. Its value is ignored for non static fields, which
228 * must be initialized through bytecode instructions in
229 * constructors or methods.
230 * @return a visitor to visit field annotations and attributes, or
231 * <tt>null</tt> if this class visitor is not interested in visiting
232 * these annotations and attributes.
233 */
234 public FieldVisitor visitField(int access, String name, String desc,
235 String signature, Object value) {
236 if (cv != null) {
237 return cv.visitField(access, name, desc, signature, value);
238 }
239 return null;
240 }
241
242 /**
243 * Visits a method of the class. This method <i>must</i> return a new
244 * {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called,
245 * i.e., it should not return a previously returned visitor.
246 *
247 * @param access
248 * the method's access flags (see {@link Opcodes}). This
249 * parameter also indicates if the method is synthetic and/or
250 * deprecated.
251 * @param name
252 * the method's name.
253 * @param desc
254 * the method's descriptor (see {@link Type Type}).
255 * @param signature
256 * the method's signature. May be <tt>null</tt> if the method
257 * parameters, return type and exceptions do not use generic
258 * types.
259 * @param exceptions
260 * the internal names of the method's exception classes (see
261 * {@link Type#getInternalName() getInternalName}). May be
262 * <tt>null</tt>.
263 * @return an object to visit the byte code of the method, or <tt>null</tt>
264 * if this class visitor is not interested in visiting the code of
265 * this method.
266 */
267 public MethodVisitor visitMethod(int access, String name, String desc,
268 String signature, String[] exceptions) {
269 if (cv != null) {
270 return cv.visitMethod(access, name, desc, signature, exceptions);
271 }
272 return null;
273 }
274
275 /**
276 * Visits the end of the class. This method, which is the last one to be
277 * called, is used to inform the visitor that all the fields and methods of
278 * the class have been visited.
279 */
280 public void visitEnd() {
281 if (cv != null) {
282 cv.visitEnd();
283 }
284 }
285 }
+0
-1693
src/jvm/clojure/asm/ClassWriter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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 extends 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 static final 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 static final int COMPUTE_FRAMES = 2;
66
67 /**
68 * Pseudo access flag to distinguish between the synthetic attribute and the
69 * synthetic access flag.
70 */
71 static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000;
72
73 /**
74 * Factor to convert from ACC_SYNTHETIC_ATTRIBUTE to Opcode.ACC_SYNTHETIC.
75 */
76 static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE
77 / Opcodes.ACC_SYNTHETIC;
78
79 /**
80 * The type of instructions without any argument.
81 */
82 static final int NOARG_INSN = 0;
83
84 /**
85 * The type of instructions with an signed byte argument.
86 */
87 static final int SBYTE_INSN = 1;
88
89 /**
90 * The type of instructions with an signed short argument.
91 */
92 static final int SHORT_INSN = 2;
93
94 /**
95 * The type of instructions with a local variable index argument.
96 */
97 static final int VAR_INSN = 3;
98
99 /**
100 * The type of instructions with an implicit local variable index argument.
101 */
102 static final int IMPLVAR_INSN = 4;
103
104 /**
105 * The type of instructions with a type descriptor argument.
106 */
107 static final int TYPE_INSN = 5;
108
109 /**
110 * The type of field and method invocations instructions.
111 */
112 static final int FIELDORMETH_INSN = 6;
113
114 /**
115 * The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction.
116 */
117 static final int ITFMETH_INSN = 7;
118
119 /**
120 * The type of the INVOKEDYNAMIC instruction.
121 */
122 static final int INDYMETH_INSN = 8;
123
124 /**
125 * The type of instructions with a 2 bytes bytecode offset label.
126 */
127 static final int LABEL_INSN = 9;
128
129 /**
130 * The type of instructions with a 4 bytes bytecode offset label.
131 */
132 static final int LABELW_INSN = 10;
133
134 /**
135 * The type of the LDC instruction.
136 */
137 static final int LDC_INSN = 11;
138
139 /**
140 * The type of the LDC_W and LDC2_W instructions.
141 */
142 static final int LDCW_INSN = 12;
143
144 /**
145 * The type of the IINC instruction.
146 */
147 static final int IINC_INSN = 13;
148
149 /**
150 * The type of the TABLESWITCH instruction.
151 */
152 static final int TABL_INSN = 14;
153
154 /**
155 * The type of the LOOKUPSWITCH instruction.
156 */
157 static final int LOOK_INSN = 15;
158
159 /**
160 * The type of the MULTIANEWARRAY instruction.
161 */
162 static final int MANA_INSN = 16;
163
164 /**
165 * The type of the WIDE instruction.
166 */
167 static final int WIDE_INSN = 17;
168
169 /**
170 * The instruction types of all JVM opcodes.
171 */
172 static final byte[] TYPE;
173
174 /**
175 * The type of CONSTANT_Class constant pool items.
176 */
177 static final int CLASS = 7;
178
179 /**
180 * The type of CONSTANT_Fieldref constant pool items.
181 */
182 static final int FIELD = 9;
183
184 /**
185 * The type of CONSTANT_Methodref constant pool items.
186 */
187 static final int METH = 10;
188
189 /**
190 * The type of CONSTANT_InterfaceMethodref constant pool items.
191 */
192 static final int IMETH = 11;
193
194 /**
195 * The type of CONSTANT_String constant pool items.
196 */
197 static final int STR = 8;
198
199 /**
200 * The type of CONSTANT_Integer constant pool items.
201 */
202 static final int INT = 3;
203
204 /**
205 * The type of CONSTANT_Float constant pool items.
206 */
207 static final int FLOAT = 4;
208
209 /**
210 * The type of CONSTANT_Long constant pool items.
211 */
212 static final int LONG = 5;
213
214 /**
215 * The type of CONSTANT_Double constant pool items.
216 */
217 static final int DOUBLE = 6;
218
219 /**
220 * The type of CONSTANT_NameAndType constant pool items.
221 */
222 static final int NAME_TYPE = 12;
223
224 /**
225 * The type of CONSTANT_Utf8 constant pool items.
226 */
227 static final int UTF8 = 1;
228
229 /**
230 * The type of CONSTANT_MethodType constant pool items.
231 */
232 static final int MTYPE = 16;
233
234 /**
235 * The type of CONSTANT_MethodHandle constant pool items.
236 */
237 static final int HANDLE = 15;
238
239 /**
240 * The type of CONSTANT_InvokeDynamic constant pool items.
241 */
242 static final int INDY = 18;
243
244 /**
245 * The base value for all CONSTANT_MethodHandle constant pool items.
246 * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9
247 * different items.
248 */
249 static final int HANDLE_BASE = 20;
250
251 /**
252 * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable},
253 * instead of the constant pool, in order to avoid clashes with normal
254 * constant pool items in the ClassWriter constant pool's hash table.
255 */
256 static final int TYPE_NORMAL = 30;
257
258 /**
259 * Uninitialized type Item stored in the ClassWriter
260 * {@link ClassWriter#typeTable}, instead of the constant pool, in order to
261 * avoid clashes with normal constant pool items in the ClassWriter constant
262 * pool's hash table.
263 */
264 static final int TYPE_UNINIT = 31;
265
266 /**
267 * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable},
268 * instead of the constant pool, in order to avoid clashes with normal
269 * constant pool items in the ClassWriter constant pool's hash table.
270 */
271 static final int TYPE_MERGED = 32;
272
273 /**
274 * The type of BootstrapMethods items. These items are stored in a special
275 * class attribute named BootstrapMethods and not in the constant pool.
276 */
277 static final int BSM = 33;
278
279 /**
280 * The class reader from which this class writer was constructed, if any.
281 */
282 ClassReader cr;
283
284 /**
285 * Minor and major version numbers of the class to be generated.
286 */
287 int version;
288
289 /**
290 * Index of the next item to be added in the constant pool.
291 */
292 int index;
293
294 /**
295 * The constant pool of this class.
296 */
297 final ByteVector pool;
298
299 /**
300 * The constant pool's hash table data.
301 */
302 Item[] items;
303
304 /**
305 * The threshold of the constant pool's hash table.
306 */
307 int threshold;
308
309 /**
310 * A reusable key used to look for items in the {@link #items} hash table.
311 */
312 final Item key;
313
314 /**
315 * A reusable key used to look for items in the {@link #items} hash table.
316 */
317 final Item key2;
318
319 /**
320 * A reusable key used to look for items in the {@link #items} hash table.
321 */
322 final Item key3;
323
324 /**
325 * A reusable key used to look for items in the {@link #items} hash table.
326 */
327 final Item key4;
328
329 /**
330 * A type table used to temporarily store internal names that will not
331 * necessarily be stored in the constant pool. This type table is used by
332 * the control flow and data flow analysis algorithm used to compute stack
333 * map frames from scratch. This array associates to each index <tt>i</tt>
334 * the Item whose index is <tt>i</tt>. All Item objects stored in this array
335 * are also stored in the {@link #items} hash table. These two arrays allow
336 * to retrieve an Item from its index or, conversely, to get the index of an
337 * Item from its value. Each Item stores an internal name in its
338 * {@link Item#strVal1} field.
339 */
340 Item[] typeTable;
341
342 /**
343 * Number of elements in the {@link #typeTable} array.
344 */
345 private short typeCount;
346
347 /**
348 * The access flags of this class.
349 */
350 private int access;
351
352 /**
353 * The constant pool item that contains the internal name of this class.
354 */
355 private int name;
356
357 /**
358 * The internal name of this class.
359 */
360 String thisName;
361
362 /**
363 * The constant pool item that contains the signature of this class.
364 */
365 private int signature;
366
367 /**
368 * The constant pool item that contains the internal name of the super class
369 * of this class.
370 */
371 private int superName;
372
373 /**
374 * Number of interfaces implemented or extended by this class or interface.
375 */
376 private int interfaceCount;
377
378 /**
379 * The interfaces implemented or extended by this class or interface. More
380 * precisely, this array contains the indexes of the constant pool items
381 * that contain the internal names of these interfaces.
382 */
383 private int[] interfaces;
384
385 /**
386 * The index of the constant pool item that contains the name of the source
387 * file from which this class was compiled.
388 */
389 private int sourceFile;
390
391 /**
392 * The SourceDebug attribute of this class.
393 */
394 private ByteVector sourceDebug;
395
396 /**
397 * The constant pool item that contains the name of the enclosing class of
398 * this class.
399 */
400 private int enclosingMethodOwner;
401
402 /**
403 * The constant pool item that contains the name and descriptor of the
404 * enclosing method of this class.
405 */
406 private int enclosingMethod;
407
408 /**
409 * The runtime visible annotations of this class.
410 */
411 private AnnotationWriter anns;
412
413 /**
414 * The runtime invisible annotations of this class.
415 */
416 private AnnotationWriter ianns;
417
418 /**
419 * The non standard attributes of this class.
420 */
421 private Attribute attrs;
422
423 /**
424 * The number of entries in the InnerClasses attribute.
425 */
426 private int innerClassesCount;
427
428 /**
429 * The InnerClasses attribute.
430 */
431 private ByteVector innerClasses;
432
433 /**
434 * The number of entries in the BootstrapMethods attribute.
435 */
436 int bootstrapMethodsCount;
437
438 /**
439 * The BootstrapMethods attribute.
440 */
441 ByteVector bootstrapMethods;
442
443 /**
444 * The fields of this class. These fields are stored in a linked list of
445 * {@link FieldWriter} objects, linked to each other by their
446 * {@link FieldWriter#fv} field. This field stores the first element of this
447 * list.
448 */
449 FieldWriter firstField;
450
451 /**
452 * The fields of this class. These fields are stored in a linked list of
453 * {@link FieldWriter} objects, linked to each other by their
454 * {@link FieldWriter#fv} field. This field stores the last element of this
455 * list.
456 */
457 FieldWriter lastField;
458
459 /**
460 * The methods of this class. These methods are stored in a linked list of
461 * {@link MethodWriter} objects, linked to each other by their
462 * {@link MethodWriter#mv} field. This field stores the first element of
463 * this list.
464 */
465 MethodWriter firstMethod;
466
467 /**
468 * The methods of this class. These methods are stored in a linked list of
469 * {@link MethodWriter} objects, linked to each other by their
470 * {@link MethodWriter#mv} field. This field stores the last element of this
471 * list.
472 */
473 MethodWriter lastMethod;
474
475 /**
476 * <tt>true</tt> if the maximum stack size and number of local variables
477 * must be automatically computed.
478 */
479 private final boolean computeMaxs;
480
481 /**
482 * <tt>true</tt> if the stack map frames must be recomputed from scratch.
483 */
484 private final boolean computeFrames;
485
486 /**
487 * <tt>true</tt> if the stack map tables of this class are invalid. The
488 * {@link MethodWriter#resizeInstructions} method cannot transform existing
489 * stack map tables, and so produces potentially invalid classes when it is
490 * executed. In this case the class is reread and rewritten with the
491 * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize
492 * stack map tables when this option is used).
493 */
494 boolean invalidFrames;
495
496 // ------------------------------------------------------------------------
497 // Static initializer
498 // ------------------------------------------------------------------------
499
500 /**
501 * Computes the instruction types of JVM opcodes.
502 */
503 static {
504 int i;
505 byte[] b = new byte[220];
506 String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"
507 + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
508 + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA"
509 + "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ";
510 for (i = 0; i < b.length; ++i) {
511 b[i] = (byte) (s.charAt(i) - 'A');
512 }
513 TYPE = b;
514
515 // code to generate the above string
516 //
517 // // SBYTE_INSN instructions
518 // b[Constants.NEWARRAY] = SBYTE_INSN;
519 // b[Constants.BIPUSH] = SBYTE_INSN;
520 //
521 // // SHORT_INSN instructions
522 // b[Constants.SIPUSH] = SHORT_INSN;
523 //
524 // // (IMPL)VAR_INSN instructions
525 // b[Constants.RET] = VAR_INSN;
526 // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) {
527 // b[i] = VAR_INSN;
528 // }
529 // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) {
530 // b[i] = VAR_INSN;
531 // }
532 // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3
533 // b[i] = IMPLVAR_INSN;
534 // }
535 // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3
536 // b[i] = IMPLVAR_INSN;
537 // }
538 //
539 // // TYPE_INSN instructions
540 // b[Constants.NEW] = TYPE_INSN;
541 // b[Constants.ANEWARRAY] = TYPE_INSN;
542 // b[Constants.CHECKCAST] = TYPE_INSN;
543 // b[Constants.INSTANCEOF] = TYPE_INSN;
544 //
545 // // (Set)FIELDORMETH_INSN instructions
546 // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) {
547 // b[i] = FIELDORMETH_INSN;
548 // }
549 // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN;
550 // b[Constants.INVOKEDYNAMIC] = INDYMETH_INSN;
551 //
552 // // LABEL(W)_INSN instructions
553 // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) {
554 // b[i] = LABEL_INSN;
555 // }
556 // b[Constants.IFNULL] = LABEL_INSN;
557 // b[Constants.IFNONNULL] = LABEL_INSN;
558 // b[200] = LABELW_INSN; // GOTO_W
559 // b[201] = LABELW_INSN; // JSR_W
560 // // temporary opcodes used internally by ASM - see Label and
561 // MethodWriter
562 // for (i = 202; i < 220; ++i) {
563 // b[i] = LABEL_INSN;
564 // }
565 //
566 // // LDC(_W) instructions
567 // b[Constants.LDC] = LDC_INSN;
568 // b[19] = LDCW_INSN; // LDC_W
569 // b[20] = LDCW_INSN; // LDC2_W
570 //
571 // // special instructions
572 // b[Constants.IINC] = IINC_INSN;
573 // b[Constants.TABLESWITCH] = TABL_INSN;
574 // b[Constants.LOOKUPSWITCH] = LOOK_INSN;
575 // b[Constants.MULTIANEWARRAY] = MANA_INSN;
576 // b[196] = WIDE_INSN; // WIDE
577 //
578 // for (i = 0; i < b.length; ++i) {
579 // System.err.print((char)('A' + b[i]));
580 // }
581 // System.err.println();
582 }
583
584 // ------------------------------------------------------------------------
585 // Constructor
586 // ------------------------------------------------------------------------
587
588 /**
589 * Constructs a new {@link ClassWriter} object.
590 *
591 * @param flags
592 * option flags that can be used to modify the default behavior
593 * of this class. See {@link #COMPUTE_MAXS},
594 * {@link #COMPUTE_FRAMES}.
595 */
596 public ClassWriter(final int flags) {
597 super(Opcodes.ASM4);
598 index = 1;
599 pool = new ByteVector();
600 items = new Item[256];
601 threshold = (int) (0.75d * items.length);
602 key = new Item();
603 key2 = new Item();
604 key3 = new Item();
605 key4 = new Item();
606 this.computeMaxs = (flags & COMPUTE_MAXS) != 0;
607 this.computeFrames = (flags & COMPUTE_FRAMES) != 0;
608 }
609
610 /**
611 * Constructs a new {@link ClassWriter} object and enables optimizations for
612 * "mostly add" bytecode transformations. These optimizations are the
613 * following:
614 *
615 * <ul>
616 * <li>The constant pool from the original class is copied as is in the new
617 * class, which saves time. New constant pool entries will be added at the
618 * end if necessary, but unused constant pool entries <i>won't be
619 * removed</i>.</li>
620 * <li>Methods that are not transformed are copied as is in the new class,
621 * directly from the original class bytecode (i.e. without emitting visit
622 * events for all the method instructions), which saves a <i>lot</i> of
623 * time. Untransformed methods are detected by the fact that the
624 * {@link ClassReader} receives {@link MethodVisitor} objects that come from
625 * a {@link ClassWriter} (and not from any other {@link ClassVisitor}
626 * instance).</li>
627 * </ul>
628 *
629 * @param classReader
630 * the {@link ClassReader} used to read the original class. It
631 * will be used to copy the entire constant pool from the
632 * original class and also to copy other fragments of original
633 * bytecode where applicable.
634 * @param flags
635 * option flags that can be used to modify the default behavior
636 * of this class. <i>These option flags do not affect methods
637 * that are copied as is in the new class. This means that the
638 * maximum stack size nor the stack frames will be computed for
639 * these methods</i>. See {@link #COMPUTE_MAXS},
640 * {@link #COMPUTE_FRAMES}.
641 */
642 public ClassWriter(final ClassReader classReader, final int flags) {
643 this(flags);
644 classReader.copyPool(this);
645 this.cr = classReader;
646 }
647
648 // ------------------------------------------------------------------------
649 // Implementation of the ClassVisitor abstract class
650 // ------------------------------------------------------------------------
651
652 @Override
653 public final void visit(final int version, final int access,
654 final String name, final String signature, final String superName,
655 final String[] interfaces) {
656 this.version = version;
657 this.access = access;
658 this.name = newClass(name);
659 thisName = name;
660 if (ClassReader.SIGNATURES && signature != null) {
661 this.signature = newUTF8(signature);
662 }
663 this.superName = superName == null ? 0 : newClass(superName);
664 if (interfaces != null && interfaces.length > 0) {
665 interfaceCount = interfaces.length;
666 this.interfaces = new int[interfaceCount];
667 for (int i = 0; i < interfaceCount; ++i) {
668 this.interfaces[i] = newClass(interfaces[i]);
669 }
670 }
671 }
672
673 @Override
674 public final void visitSource(final String file, final String debug) {
675 if (file != null) {
676 sourceFile = newUTF8(file);
677 }
678 if (debug != null) {
679 sourceDebug = new ByteVector().putUTF8(debug);
680 }
681 }
682
683 @Override
684 public final void visitOuterClass(final String owner, final String name,
685 final String desc) {
686 enclosingMethodOwner = newClass(owner);
687 if (name != null && desc != null) {
688 enclosingMethod = newNameType(name, desc);
689 }
690 }
691
692 @Override
693 public final AnnotationVisitor visitAnnotation(final String desc,
694 final boolean visible) {
695 if (!ClassReader.ANNOTATIONS) {
696 return null;
697 }
698 ByteVector bv = new ByteVector();
699 // write type, and reserve space for values count
700 bv.putShort(newUTF8(desc)).putShort(0);
701 AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2);
702 if (visible) {
703 aw.next = anns;
704 anns = aw;
705 } else {
706 aw.next = ianns;
707 ianns = aw;
708 }
709 return aw;
710 }
711
712 @Override
713 public final void visitAttribute(final Attribute attr) {
714 attr.next = attrs;
715 attrs = attr;
716 }
717
718 @Override
719 public final void visitInnerClass(final String name,
720 final String outerName, final String innerName, final int access) {
721 if (innerClasses == null) {
722 innerClasses = new ByteVector();
723 }
724 ++innerClassesCount;
725 innerClasses.putShort(name == null ? 0 : newClass(name));
726 innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
727 innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
728 innerClasses.putShort(access);
729 }
730
731 @Override
732 public final FieldVisitor visitField(final int access, final String name,
733 final String desc, final String signature, final Object value) {
734 return new FieldWriter(this, access, name, desc, signature, value);
735 }
736
737 @Override
738 public final MethodVisitor visitMethod(final int access, final String name,
739 final String desc, final String signature, final String[] exceptions) {
740 return new MethodWriter(this, access, name, desc, signature,
741 exceptions, computeMaxs, computeFrames);
742 }
743
744 @Override
745 public final void visitEnd() {
746 }
747
748 // ------------------------------------------------------------------------
749 // Other public methods
750 // ------------------------------------------------------------------------
751
752 /**
753 * Returns the bytecode of the class that was build with this class writer.
754 *
755 * @return the bytecode of the class that was build with this class writer.
756 */
757 public byte[] toByteArray() {
758 if (index > 0xFFFF) {
759 throw new RuntimeException("Class file too large!");
760 }
761 // computes the real size of the bytecode of this class
762 int size = 24 + 2 * interfaceCount;
763 int nbFields = 0;
764 FieldWriter fb = firstField;
765 while (fb != null) {
766 ++nbFields;
767 size += fb.getSize();
768 fb = (FieldWriter) fb.fv;
769 }
770 int nbMethods = 0;
771 MethodWriter mb = firstMethod;
772 while (mb != null) {
773 ++nbMethods;
774 size += mb.getSize();
775 mb = (MethodWriter) mb.mv;
776 }
777 int attributeCount = 0;
778 if (bootstrapMethods != null) {
779 // we put it as first attribute in order to improve a bit
780 // ClassReader.copyBootstrapMethods
781 ++attributeCount;
782 size += 8 + bootstrapMethods.length;
783 newUTF8("BootstrapMethods");
784 }
785 if (ClassReader.SIGNATURES && signature != 0) {
786 ++attributeCount;
787 size += 8;
788 newUTF8("Signature");
789 }
790 if (sourceFile != 0) {
791 ++attributeCount;
792 size += 8;
793 newUTF8("SourceFile");
794 }
795 if (sourceDebug != null) {
796 ++attributeCount;
797 size += sourceDebug.length + 4;
798 newUTF8("SourceDebugExtension");
799 }
800 if (enclosingMethodOwner != 0) {
801 ++attributeCount;
802 size += 10;
803 newUTF8("EnclosingMethod");
804 }
805 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
806 ++attributeCount;
807 size += 6;
808 newUTF8("Deprecated");
809 }
810 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
811 if ((version & 0xFFFF) < Opcodes.V1_5
812 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
813 ++attributeCount;
814 size += 6;
815 newUTF8("Synthetic");
816 }
817 }
818 if (innerClasses != null) {
819 ++attributeCount;
820 size += 8 + innerClasses.length;
821 newUTF8("InnerClasses");
822 }
823 if (ClassReader.ANNOTATIONS && anns != null) {
824 ++attributeCount;
825 size += 8 + anns.getSize();
826 newUTF8("RuntimeVisibleAnnotations");
827 }
828 if (ClassReader.ANNOTATIONS && ianns != null) {
829 ++attributeCount;
830 size += 8 + ianns.getSize();
831 newUTF8("RuntimeInvisibleAnnotations");
832 }
833 if (attrs != null) {
834 attributeCount += attrs.getCount();
835 size += attrs.getSize(this, null, 0, -1, -1);
836 }
837 size += pool.length;
838 // allocates a byte vector of this size, in order to avoid unnecessary
839 // arraycopy operations in the ByteVector.enlarge() method
840 ByteVector out = new ByteVector(size);
841 out.putInt(0xCAFEBABE).putInt(version);
842 out.putShort(index).putByteArray(pool.data, 0, pool.length);
843 int mask = Opcodes.ACC_DEPRECATED | ACC_SYNTHETIC_ATTRIBUTE
844 | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC);
845 out.putShort(access & ~mask).putShort(name).putShort(superName);
846 out.putShort(interfaceCount);
847 for (int i = 0; i < interfaceCount; ++i) {
848 out.putShort(interfaces[i]);
849 }
850 out.putShort(nbFields);
851 fb = firstField;
852 while (fb != null) {
853 fb.put(out);
854 fb = (FieldWriter) fb.fv;
855 }
856 out.putShort(nbMethods);
857 mb = firstMethod;
858 while (mb != null) {
859 mb.put(out);
860 mb = (MethodWriter) mb.mv;
861 }
862 out.putShort(attributeCount);
863 if (bootstrapMethods != null) {
864 out.putShort(newUTF8("BootstrapMethods"));
865 out.putInt(bootstrapMethods.length + 2).putShort(
866 bootstrapMethodsCount);
867 out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
868 }
869 if (ClassReader.SIGNATURES && signature != 0) {
870 out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
871 }
872 if (sourceFile != 0) {
873 out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
874 }
875 if (sourceDebug != null) {
876 int len = sourceDebug.length - 2;
877 out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
878 out.putByteArray(sourceDebug.data, 2, len);
879 }
880 if (enclosingMethodOwner != 0) {
881 out.putShort(newUTF8("EnclosingMethod")).putInt(4);
882 out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
883 }
884 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
885 out.putShort(newUTF8("Deprecated")).putInt(0);
886 }
887 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
888 if ((version & 0xFFFF) < Opcodes.V1_5
889 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
890 out.putShort(newUTF8("Synthetic")).putInt(0);
891 }
892 }
893 if (innerClasses != null) {
894 out.putShort(newUTF8("InnerClasses"));
895 out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
896 out.putByteArray(innerClasses.data, 0, innerClasses.length);
897 }
898 if (ClassReader.ANNOTATIONS && anns != null) {
899 out.putShort(newUTF8("RuntimeVisibleAnnotations"));
900 anns.put(out);
901 }
902 if (ClassReader.ANNOTATIONS && ianns != null) {
903 out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
904 ianns.put(out);
905 }
906 if (attrs != null) {
907 attrs.put(this, null, 0, -1, -1, out);
908 }
909 if (invalidFrames) {
910 ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
911 new ClassReader(out.data).accept(cw, ClassReader.SKIP_FRAMES);
912 return cw.toByteArray();
913 }
914 return out.data;
915 }
916
917 // ------------------------------------------------------------------------
918 // Utility methods: constant pool management
919 // ------------------------------------------------------------------------
920
921 /**
922 * Adds a number or string constant to the constant pool of the class being
923 * build. Does nothing if the constant pool already contains a similar item.
924 *
925 * @param cst
926 * the value of the constant to be added to the constant pool.
927 * This parameter must be an {@link Integer}, a {@link Float}, a
928 * {@link Long}, a {@link Double}, a {@link String} or a
929 * {@link Type}.
930 * @return a new or already existing constant item with the given value.
931 */
932 Item newConstItem(final Object cst) {
933 if (cst instanceof Integer) {
934 int val = ((Integer) cst).intValue();
935 return newInteger(val);
936 } else if (cst instanceof Byte) {
937 int val = ((Byte) cst).intValue();
938 return newInteger(val);
939 } else if (cst instanceof Character) {
940 int val = ((Character) cst).charValue();
941 return newInteger(val);
942 } else if (cst instanceof Short) {
943 int val = ((Short) cst).intValue();
944 return newInteger(val);
945 } else if (cst instanceof Boolean) {
946 int val = ((Boolean) cst).booleanValue() ? 1 : 0;
947 return newInteger(val);
948 } else if (cst instanceof Float) {
949 float val = ((Float) cst).floatValue();
950 return newFloat(val);
951 } else if (cst instanceof Long) {
952 long val = ((Long) cst).longValue();
953 return newLong(val);
954 } else if (cst instanceof Double) {
955 double val = ((Double) cst).doubleValue();
956 return newDouble(val);
957 } else if (cst instanceof String) {
958 return newString((String) cst);
959 } else if (cst instanceof Type) {
960 Type t = (Type) cst;
961 int s = t.getSort();
962 if (s == Type.OBJECT) {
963 return newClassItem(t.getInternalName());
964 } else if (s == Type.METHOD) {
965 return newMethodTypeItem(t.getDescriptor());
966 } else { // s == primitive type or array
967 return newClassItem(t.getDescriptor());
968 }
969 } else if (cst instanceof Handle) {
970 Handle h = (Handle) cst;
971 return newHandleItem(h.tag, h.owner, h.name, h.desc);
972 } else {
973 throw new IllegalArgumentException("value " + cst);
974 }
975 }
976
977 /**
978 * Adds a number or string constant to the constant pool of the class being
979 * build. Does nothing if the constant pool already contains a similar item.
980 * <i>This method is intended for {@link Attribute} sub classes, and is
981 * normally not needed by class generators or adapters.</i>
982 *
983 * @param cst
984 * the value of the constant to be added to the constant pool.
985 * This parameter must be an {@link Integer}, a {@link Float}, a
986 * {@link Long}, a {@link Double} or a {@link String}.
987 * @return the index of a new or already existing constant item with the
988 * given value.
989 */
990 public int newConst(final Object cst) {
991 return newConstItem(cst).index;
992 }
993
994 /**
995 * Adds an UTF8 string to the constant pool of the class being build. Does
996 * nothing if the constant pool already contains a similar item. <i>This
997 * method is intended for {@link Attribute} sub classes, and is normally not
998 * needed by class generators or adapters.</i>
999 *
1000 * @param value
1001 * the String value.
1002 * @return the index of a new or already existing UTF8 item.
1003 */
1004 public int newUTF8(final String value) {
1005 key.set(UTF8, value, null, null);
1006 Item result = get(key);
1007 if (result == null) {
1008 pool.putByte(UTF8).putUTF8(value);
1009 result = new Item(index++, key);
1010 put(result);
1011 }
1012 return result.index;
1013 }
1014
1015 /**
1016 * Adds a class reference to the constant pool of the class being build.
1017 * Does nothing if the constant pool already contains a similar item.
1018 * <i>This method is intended for {@link Attribute} sub classes, and is
1019 * normally not needed by class generators or adapters.</i>
1020 *
1021 * @param value
1022 * the internal name of the class.
1023 * @return a new or already existing class reference item.
1024 */
1025 Item newClassItem(final String value) {
1026 key2.set(CLASS, value, null, null);
1027 Item result = get(key2);
1028 if (result == null) {
1029 pool.put12(CLASS, newUTF8(value));
1030 result = new Item(index++, key2);
1031 put(result);
1032 }
1033 return result;
1034 }
1035
1036 /**
1037 * Adds a class 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 value
1043 * the internal name of the class.
1044 * @return the index of a new or already existing class reference item.
1045 */
1046 public int newClass(final String value) {
1047 return newClassItem(value).index;
1048 }
1049
1050 /**
1051 * Adds a method type reference to the constant pool of the class being
1052 * build. Does nothing if the constant pool already contains a similar item.
1053 * <i>This method is intended for {@link Attribute} sub classes, and is
1054 * normally not needed by class generators or adapters.</i>
1055 *
1056 * @param methodDesc
1057 * method descriptor of the method type.
1058 * @return a new or already existing method type reference item.
1059 */
1060 Item newMethodTypeItem(final String methodDesc) {
1061 key2.set(MTYPE, methodDesc, null, null);
1062 Item result = get(key2);
1063 if (result == null) {
1064 pool.put12(MTYPE, newUTF8(methodDesc));
1065 result = new Item(index++, key2);
1066 put(result);
1067 }
1068 return result;
1069 }
1070
1071 /**
1072 * Adds a method type reference to the constant pool of the class being
1073 * build. Does nothing if the constant pool already contains a similar item.
1074 * <i>This method is intended for {@link Attribute} sub classes, and is
1075 * normally not needed by class generators or adapters.</i>
1076 *
1077 * @param methodDesc
1078 * method descriptor of the method type.
1079 * @return the index of a new or already existing method type reference
1080 * item.
1081 */
1082 public int newMethodType(final String methodDesc) {
1083 return newMethodTypeItem(methodDesc).index;
1084 }
1085
1086 /**
1087 * Adds a handle to the constant pool of the class being build. Does nothing
1088 * if the constant pool already contains a similar item. <i>This method is
1089 * intended for {@link Attribute} sub classes, and is normally not needed by
1090 * class generators or adapters.</i>
1091 *
1092 * @param tag
1093 * the kind of this handle. Must be {@link Opcodes#H_GETFIELD},
1094 * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
1095 * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
1096 * {@link Opcodes#H_INVOKESTATIC},
1097 * {@link Opcodes#H_INVOKESPECIAL},
1098 * {@link Opcodes#H_NEWINVOKESPECIAL} or
1099 * {@link Opcodes#H_INVOKEINTERFACE}.
1100 * @param owner
1101 * the internal name of the field or method owner class.
1102 * @param name
1103 * the name of the field or method.
1104 * @param desc
1105 * the descriptor of the field or method.
1106 * @return a new or an already existing method type reference item.
1107 */
1108 Item newHandleItem(final int tag, final String owner, final String name,
1109 final String desc) {
1110 key4.set(HANDLE_BASE + tag, owner, name, desc);
1111 Item result = get(key4);
1112 if (result == null) {
1113 if (tag <= Opcodes.H_PUTSTATIC) {
1114 put112(HANDLE, tag, newField(owner, name, desc));
1115 } else {
1116 put112(HANDLE,
1117 tag,
1118 newMethod(owner, name, desc,
1119 tag == Opcodes.H_INVOKEINTERFACE));
1120 }
1121 result = new Item(index++, key4);
1122 put(result);
1123 }
1124 return result;
1125 }
1126
1127 /**
1128 * Adds a handle to the constant pool of the class being build. Does nothing
1129 * if the constant pool already contains a similar item. <i>This method is
1130 * intended for {@link Attribute} sub classes, and is normally not needed by
1131 * class generators or adapters.</i>
1132 *
1133 * @param tag
1134 * the kind of this handle. Must be {@link Opcodes#H_GETFIELD},
1135 * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
1136 * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
1137 * {@link Opcodes#H_INVOKESTATIC},
1138 * {@link Opcodes#H_INVOKESPECIAL},
1139 * {@link Opcodes#H_NEWINVOKESPECIAL} or
1140 * {@link Opcodes#H_INVOKEINTERFACE}.
1141 * @param owner
1142 * the internal name of the field or method owner class.
1143 * @param name
1144 * the name of the field or method.
1145 * @param desc
1146 * the descriptor of the field or method.
1147 * @return the index of a new or already existing method type reference
1148 * item.
1149 */
1150 public int newHandle(final int tag, final String owner, final String name,
1151 final String desc) {
1152 return newHandleItem(tag, owner, name, desc).index;
1153 }
1154
1155 /**
1156 * Adds an invokedynamic reference to the constant pool of the class being
1157 * build. Does nothing if the constant pool already contains a similar item.
1158 * <i>This method is intended for {@link Attribute} sub classes, and is
1159 * normally not needed by class generators or adapters.</i>
1160 *
1161 * @param name
1162 * name of the invoked method.
1163 * @param desc
1164 * descriptor of the invoke method.
1165 * @param bsm
1166 * the bootstrap method.
1167 * @param bsmArgs
1168 * the bootstrap method constant arguments.
1169 *
1170 * @return a new or an already existing invokedynamic type reference item.
1171 */
1172 Item newInvokeDynamicItem(final String name, final String desc,
1173 final Handle bsm, final Object... bsmArgs) {
1174 // cache for performance
1175 ByteVector bootstrapMethods = this.bootstrapMethods;
1176 if (bootstrapMethods == null) {
1177 bootstrapMethods = this.bootstrapMethods = new ByteVector();
1178 }
1179
1180 int position = bootstrapMethods.length; // record current position
1181
1182 int hashCode = bsm.hashCode();
1183 bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name,
1184 bsm.desc));
1185
1186 int argsLength = bsmArgs.length;
1187 bootstrapMethods.putShort(argsLength);
1188
1189 for (int i = 0; i < argsLength; i++) {
1190 Object bsmArg = bsmArgs[i];
1191 hashCode ^= bsmArg.hashCode();
1192 bootstrapMethods.putShort(newConst(bsmArg));
1193 }
1194
1195 byte[] data = bootstrapMethods.data;
1196 int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments)
1197 hashCode &= 0x7FFFFFFF;
1198 Item result = items[hashCode % items.length];
1199 loop: while (result != null) {
1200 if (result.type != BSM || result.hashCode != hashCode) {
1201 result = result.next;
1202 continue;
1203 }
1204
1205 // because the data encode the size of the argument
1206 // we don't need to test if these size are equals
1207 int resultPosition = result.intVal;
1208 for (int p = 0; p < length; p++) {
1209 if (data[position + p] != data[resultPosition + p]) {
1210 result = result.next;
1211 continue loop;
1212 }
1213 }
1214 break;
1215 }
1216
1217 int bootstrapMethodIndex;
1218 if (result != null) {
1219 bootstrapMethodIndex = result.index;
1220 bootstrapMethods.length = position; // revert to old position
1221 } else {
1222 bootstrapMethodIndex = bootstrapMethodsCount++;
1223 result = new Item(bootstrapMethodIndex);
1224 result.set(position, hashCode);
1225 put(result);
1226 }
1227
1228 // now, create the InvokeDynamic constant
1229 key3.set(name, desc, bootstrapMethodIndex);
1230 result = get(key3);
1231 if (result == null) {
1232 put122(INDY, bootstrapMethodIndex, newNameType(name, desc));
1233 result = new Item(index++, key3);
1234 put(result);
1235 }
1236 return result;
1237 }
1238
1239 /**
1240 * Adds an invokedynamic reference to the constant pool of the class being
1241 * build. Does nothing if the constant pool already contains a similar item.
1242 * <i>This method is intended for {@link Attribute} sub classes, and is
1243 * normally not needed by class generators or adapters.</i>
1244 *
1245 * @param name
1246 * name of the invoked method.
1247 * @param desc
1248 * descriptor of the invoke method.
1249 * @param bsm
1250 * the bootstrap method.
1251 * @param bsmArgs
1252 * the bootstrap method constant arguments.
1253 *
1254 * @return the index of a new or already existing invokedynamic reference
1255 * item.
1256 */
1257 public int newInvokeDynamic(final String name, final String desc,
1258 final Handle bsm, final Object... bsmArgs) {
1259 return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index;
1260 }
1261
1262 /**
1263 * Adds a field reference to the constant pool of the class being build.
1264 * Does nothing if the constant pool already contains a similar item.
1265 *
1266 * @param owner
1267 * the internal name of the field's owner class.
1268 * @param name
1269 * the field's name.
1270 * @param desc
1271 * the field's descriptor.
1272 * @return a new or already existing field reference item.
1273 */
1274 Item newFieldItem(final String owner, final String name, final String desc) {
1275 key3.set(FIELD, owner, name, desc);
1276 Item result = get(key3);
1277 if (result == null) {
1278 put122(FIELD, newClass(owner), newNameType(name, desc));
1279 result = new Item(index++, key3);
1280 put(result);
1281 }
1282 return result;
1283 }
1284
1285 /**
1286 * Adds a field reference to the constant pool of the class being build.
1287 * Does nothing if the constant pool already contains a similar item.
1288 * <i>This method is intended for {@link Attribute} sub classes, and is
1289 * normally not needed by class generators or adapters.</i>
1290 *
1291 * @param owner
1292 * the internal name of the field's owner class.
1293 * @param name
1294 * the field's name.
1295 * @param desc
1296 * the field's descriptor.
1297 * @return the index of a new or already existing field reference item.
1298 */
1299 public int newField(final String owner, final String name, final String desc) {
1300 return newFieldItem(owner, name, desc).index;
1301 }
1302
1303 /**
1304 * Adds a method reference to the constant pool of the class being build.
1305 * Does nothing if the constant pool already contains a similar item.
1306 *
1307 * @param owner
1308 * the internal name of the method's owner class.
1309 * @param name
1310 * the method's name.
1311 * @param desc
1312 * the method's descriptor.
1313 * @param itf
1314 * <tt>true</tt> if <tt>owner</tt> is an interface.
1315 * @return a new or already existing method reference item.
1316 */
1317 Item newMethodItem(final String owner, final String name,
1318 final String desc, final boolean itf) {
1319 int type = itf ? IMETH : METH;
1320 key3.set(type, owner, name, desc);
1321 Item result = get(key3);
1322 if (result == null) {
1323 put122(type, newClass(owner), newNameType(name, desc));
1324 result = new Item(index++, key3);
1325 put(result);
1326 }
1327 return result;
1328 }
1329
1330 /**
1331 * Adds a method reference to the constant pool of the class being build.
1332 * Does nothing if the constant pool already contains a similar item.
1333 * <i>This method is intended for {@link Attribute} sub classes, and is
1334 * normally not needed by class generators or adapters.</i>
1335 *
1336 * @param owner
1337 * the internal name of the method's owner class.
1338 * @param name
1339 * the method's name.
1340 * @param desc
1341 * the method's descriptor.
1342 * @param itf
1343 * <tt>true</tt> if <tt>owner</tt> is an interface.
1344 * @return the index of a new or already existing method reference item.
1345 */
1346 public int newMethod(final String owner, final String name,
1347 final String desc, final boolean itf) {
1348 return newMethodItem(owner, name, desc, itf).index;
1349 }
1350
1351 /**
1352 * Adds an integer to the constant pool of the class being build. Does
1353 * nothing if the constant pool already contains a similar item.
1354 *
1355 * @param value
1356 * the int value.
1357 * @return a new or already existing int item.
1358 */
1359 Item newInteger(final int value) {
1360 key.set(value);
1361 Item result = get(key);
1362 if (result == null) {
1363 pool.putByte(INT).putInt(value);
1364 result = new Item(index++, key);
1365 put(result);
1366 }
1367 return result;
1368 }
1369
1370 /**
1371 * Adds a float to the constant pool of the class being build. Does nothing
1372 * if the constant pool already contains a similar item.
1373 *
1374 * @param value
1375 * the float value.
1376 * @return a new or already existing float item.
1377 */
1378 Item newFloat(final float value) {
1379 key.set(value);
1380 Item result = get(key);
1381 if (result == null) {
1382 pool.putByte(FLOAT).putInt(key.intVal);
1383 result = new Item(index++, key);
1384 put(result);
1385 }
1386 return result;
1387 }
1388
1389 /**
1390 * Adds a long to the constant pool of the class being build. Does nothing
1391 * if the constant pool already contains a similar item.
1392 *
1393 * @param value
1394 * the long value.
1395 * @return a new or already existing long item.
1396 */
1397 Item newLong(final long value) {
1398 key.set(value);
1399 Item result = get(key);
1400 if (result == null) {
1401 pool.putByte(LONG).putLong(value);
1402 result = new Item(index, key);
1403 index += 2;
1404 put(result);
1405 }
1406 return result;
1407 }
1408
1409 /**
1410 * Adds a double to the constant pool of the class being build. Does nothing
1411 * if the constant pool already contains a similar item.
1412 *
1413 * @param value
1414 * the double value.
1415 * @return a new or already existing double item.
1416 */
1417 Item newDouble(final double value) {
1418 key.set(value);
1419 Item result = get(key);
1420 if (result == null) {
1421 pool.putByte(DOUBLE).putLong(key.longVal);
1422 result = new Item(index, key);
1423 index += 2;
1424 put(result);
1425 }
1426 return result;
1427 }
1428
1429 /**
1430 * Adds a string to the constant pool of the class being build. Does nothing
1431 * if the constant pool already contains a similar item.
1432 *
1433 * @param value
1434 * the String value.
1435 * @return a new or already existing string item.
1436 */
1437 private Item newString(final String value) {
1438 key2.set(STR, value, null, null);
1439 Item result = get(key2);
1440 if (result == null) {
1441 pool.put12(STR, newUTF8(value));
1442 result = new Item(index++, key2);
1443 put(result);
1444 }
1445 return result;
1446 }
1447
1448 /**
1449 * Adds a name and type to the constant pool of the class being build. Does
1450 * nothing if the constant pool already contains a similar item. <i>This
1451 * method is intended for {@link Attribute} sub classes, and is normally not
1452 * needed by class generators or adapters.</i>
1453 *
1454 * @param name
1455 * a name.
1456 * @param desc
1457 * a type descriptor.
1458 * @return the index of a new or already existing name and type item.
1459 */
1460 public int newNameType(final String name, final String desc) {
1461 return newNameTypeItem(name, desc).index;
1462 }
1463
1464 /**
1465 * Adds a name and type to the constant pool of the class being build. Does
1466 * nothing if the constant pool already contains a similar item.
1467 *
1468 * @param name
1469 * a name.
1470 * @param desc
1471 * a type descriptor.
1472 * @return a new or already existing name and type item.
1473 */
1474 Item newNameTypeItem(final String name, final String desc) {
1475 key2.set(NAME_TYPE, name, desc, null);
1476 Item result = get(key2);
1477 if (result == null) {
1478 put122(NAME_TYPE, newUTF8(name), newUTF8(desc));
1479 result = new Item(index++, key2);
1480 put(result);
1481 }
1482 return result;
1483 }
1484
1485 /**
1486 * Adds the given internal name to {@link #typeTable} and returns its index.
1487 * Does nothing if the type table already contains this internal name.
1488 *
1489 * @param type
1490 * the internal name to be added to the type table.
1491 * @return the index of this internal name in the type table.
1492 */
1493 int addType(final String type) {
1494 key.set(TYPE_NORMAL, type, null, null);
1495 Item result = get(key);
1496 if (result == null) {
1497 result = addType(key);
1498 }
1499 return result.index;
1500 }
1501
1502 /**
1503 * Adds the given "uninitialized" type to {@link #typeTable} and returns its
1504 * index. This method is used for UNINITIALIZED types, made of an internal
1505 * name and a bytecode offset.
1506 *
1507 * @param type
1508 * the internal name to be added to the type table.
1509 * @param offset
1510 * the bytecode offset of the NEW instruction that created this
1511 * UNINITIALIZED type value.
1512 * @return the index of this internal name in the type table.
1513 */
1514 int addUninitializedType(final String type, final int offset) {
1515 key.type = TYPE_UNINIT;
1516 key.intVal = offset;
1517 key.strVal1 = type;
1518 key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset);
1519 Item result = get(key);
1520 if (result == null) {
1521 result = addType(key);
1522 }
1523 return result.index;
1524 }
1525
1526 /**
1527 * Adds the given Item to {@link #typeTable}.
1528 *
1529 * @param item
1530 * the value to be added to the type table.
1531 * @return the added Item, which a new Item instance with the same value as
1532 * the given Item.
1533 */
1534 private Item addType(final Item item) {
1535 ++typeCount;
1536 Item result = new Item(typeCount, key);
1537 put(result);
1538 if (typeTable == null) {
1539 typeTable = new Item[16];
1540 }
1541 if (typeCount == typeTable.length) {
1542 Item[] newTable = new Item[2 * typeTable.length];
1543 System.arraycopy(typeTable, 0, newTable, 0, typeTable.length);
1544 typeTable = newTable;
1545 }
1546 typeTable[typeCount] = result;
1547 return result;
1548 }
1549
1550 /**
1551 * Returns the index of the common super type of the two given types. This
1552 * method calls {@link #getCommonSuperClass} and caches the result in the
1553 * {@link #items} hash table to speedup future calls with the same
1554 * parameters.
1555 *
1556 * @param type1
1557 * index of an internal name in {@link #typeTable}.
1558 * @param type2
1559 * index of an internal name in {@link #typeTable}.
1560 * @return the index of the common super type of the two given types.
1561 */
1562 int getMergedType(final int type1, final int type2) {
1563 key2.type = TYPE_MERGED;
1564 key2.longVal = type1 | (((long) type2) << 32);
1565 key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2);
1566 Item result = get(key2);
1567 if (result == null) {
1568 String t = typeTable[type1].strVal1;
1569 String u = typeTable[type2].strVal1;
1570 key2.intVal = addType(getCommonSuperClass(t, u));
1571 result = new Item((short) 0, key2);
1572 put(result);
1573 }
1574 return result.intVal;
1575 }
1576
1577 /**
1578 * Returns the common super type of the two given types. The default
1579 * implementation of this method <i>loads<i> the two given classes and uses
1580 * the java.lang.Class methods to find the common super class. It can be
1581 * overridden to compute this common super type in other ways, in particular
1582 * without actually loading any class, or to take into account the class
1583 * that is currently being generated by this ClassWriter, which can of
1584 * course not be loaded since it is under construction.
1585 *
1586 * @param type1
1587 * the internal name of a class.
1588 * @param type2
1589 * the internal name of another class.
1590 * @return the internal name of the common super class of the two given
1591 * classes.
1592 */
1593 protected String getCommonSuperClass(final String type1, final String type2) {
1594 Class<?> c, d;
1595 ClassLoader classLoader = getClass().getClassLoader();
1596 try {
1597 c = Class.forName(type1.replace('/', '.'), false, classLoader);
1598 d = Class.forName(type2.replace('/', '.'), false, classLoader);
1599 } catch (Exception e) {
1600 throw new RuntimeException(e.toString());
1601 }
1602 if (c.isAssignableFrom(d)) {
1603 return type1;
1604 }
1605 if (d.isAssignableFrom(c)) {
1606 return type2;
1607 }
1608 if (c.isInterface() || d.isInterface()) {
1609 return "java/lang/Object";
1610 } else {
1611 do {
1612 c = c.getSuperclass();
1613 } while (!c.isAssignableFrom(d));
1614 return c.getName().replace('.', '/');
1615 }
1616 }
1617
1618 /**
1619 * Returns the constant pool's hash table item which is equal to the given
1620 * item.
1621 *
1622 * @param key
1623 * a constant pool item.
1624 * @return the constant pool's hash table item which is equal to the given
1625 * item, or <tt>null</tt> if there is no such item.
1626 */
1627 private Item get(final Item key) {
1628 Item i = items[key.hashCode % items.length];
1629 while (i != null && (i.type != key.type || !key.isEqualTo(i))) {
1630 i = i.next;
1631 }
1632 return i;
1633 }
1634
1635 /**
1636 * Puts the given item in the constant pool's hash table. The hash table
1637 * <i>must</i> not already contains this item.
1638 *
1639 * @param i
1640 * the item to be added to the constant pool's hash table.
1641 */
1642 private void put(final Item i) {
1643 if (index + typeCount > threshold) {
1644 int ll = items.length;
1645 int nl = ll * 2 + 1;
1646 Item[] newItems = new Item[nl];
1647 for (int l = ll - 1; l >= 0; --l) {
1648 Item j = items[l];
1649 while (j != null) {
1650 int index = j.hashCode % newItems.length;
1651 Item k = j.next;
1652 j.next = newItems[index];
1653 newItems[index] = j;
1654 j = k;
1655 }
1656 }
1657 items = newItems;
1658 threshold = (int) (nl * 0.75);
1659 }
1660 int index = i.hashCode % items.length;
1661 i.next = items[index];
1662 items[index] = i;
1663 }
1664
1665 /**
1666 * Puts one byte and two shorts into the constant pool.
1667 *
1668 * @param b
1669 * a byte.
1670 * @param s1
1671 * a short.
1672 * @param s2
1673 * another short.
1674 */
1675 private void put122(final int b, final int s1, final int s2) {
1676 pool.put12(b, s1).putShort(s2);
1677 }
1678
1679 /**
1680 * Puts two bytes and one short into the constant pool.
1681 *
1682 * @param b1
1683 * a byte.
1684 * @param b2
1685 * another byte.
1686 * @param s
1687 * a short.
1688 */
1689 private void put112(final int b1, final int b2, final int s) {
1690 pool.put11(b1, b2).putShort(s);
1691 }
1692 }
+0
-110
src/jvm/clojure/asm/Context.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 package clojure.asm;
31
32 /**
33 * Information about a class being parsed in a {@link ClassReader}.
34 *
35 * @author Eric Bruneton
36 */
37 class Context {
38
39 /**
40 * Prototypes of the attributes that must be parsed for this class.
41 */
42 Attribute[] attrs;
43
44 /**
45 * The {@link ClassReader} option flags for the parsing of this class.
46 */
47 int flags;
48
49 /**
50 * The buffer used to read strings.
51 */
52 char[] buffer;
53
54 /**
55 * The start index of each bootstrap method.
56 */
57 int[] bootstrapMethods;
58
59 /**
60 * The access flags of the method currently being parsed.
61 */
62 int access;
63
64 /**
65 * The name of the method currently being parsed.
66 */
67 String name;
68
69 /**
70 * The descriptor of the method currently being parsed.
71 */
72 String desc;
73
74 /**
75 * The offset of the latest stack map frame that has been parsed.
76 */
77 int offset;
78
79 /**
80 * The encoding of the latest stack map frame that has been parsed.
81 */
82 int mode;
83
84 /**
85 * The number of locals in the latest stack map frame that has been parsed.
86 */
87 int localCount;
88
89 /**
90 * The number locals in the latest stack map frame that has been parsed,
91 * minus the number of locals in the previous frame.
92 */
93 int localDiff;
94
95 /**
96 * The local values of the latest stack map frame that has been parsed.
97 */
98 Object[] local;
99
100 /**
101 * The stack size of the latest stack map frame that has been parsed.
102 */
103 int stackCount;
104
105 /**
106 * The stack values of the latest stack map frame that has been parsed.
107 */
108 Object[] stack;
109 }
+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-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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 static final 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 static final 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
-121
src/jvm/clojure/asm/FieldVisitor.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package clojure.asm;
30
31 /**
32 * A visitor to visit a Java field. The methods of this class must be called in
33 * the following order: ( <tt>visitAnnotation</tt> | <tt>visitAttribute</tt> )*
34 * <tt>visitEnd</tt>.
35 *
36 * @author Eric Bruneton
37 */
38 public abstract class FieldVisitor {
39
40 /**
41 * The ASM API version implemented by this visitor. The value of this field
42 * must be one of {@link Opcodes#ASM4}.
43 */
44 protected final int api;
45
46 /**
47 * The field visitor to which this visitor must delegate method calls. May
48 * be null.
49 */
50 protected FieldVisitor fv;
51
52 /**
53 * Constructs a new {@link FieldVisitor}.
54 *
55 * @param api
56 * the ASM API version implemented by this visitor. Must be one
57 * of {@link Opcodes#ASM4}.
58 */
59 public FieldVisitor(final int api) {
60 this(api, null);
61 }
62
63 /**
64 * Constructs a new {@link FieldVisitor}.
65 *
66 * @param api
67 * the ASM API version implemented by this visitor. Must be one
68 * of {@link Opcodes#ASM4}.
69 * @param fv
70 * the field visitor to which this visitor must delegate method
71 * calls. May be null.
72 */
73 public FieldVisitor(final int api, final FieldVisitor fv) {
74 if (api != Opcodes.ASM4) {
75 throw new IllegalArgumentException();
76 }
77 this.api = api;
78 this.fv = fv;
79 }
80
81 /**
82 * Visits an annotation of the field.
83 *
84 * @param desc
85 * the class descriptor of the annotation class.
86 * @param visible
87 * <tt>true</tt> if the annotation is visible at runtime.
88 * @return a visitor to visit the annotation values, or <tt>null</tt> if
89 * this visitor is not interested in visiting this annotation.
90 */
91 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
92 if (fv != null) {
93 return fv.visitAnnotation(desc, visible);
94 }
95 return null;
96 }
97
98 /**
99 * Visits a non standard attribute of the field.
100 *
101 * @param attr
102 * an attribute.
103 */
104 public void visitAttribute(Attribute attr) {
105 if (fv != null) {
106 fv.visitAttribute(attr);
107 }
108 }
109
110 /**
111 * Visits the end of the field. This method, which is the last one to be
112 * called, is used to inform the visitor that all the annotations and
113 * attributes of the field have been visited.
114 */
115 public void visitEnd() {
116 if (fv != null) {
117 fv.visitEnd();
118 }
119 }
120 }
+0
-273
src/jvm/clojure/asm/FieldWriter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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 extends FieldVisitor {
37
38 /**
39 * The class writer to which this field must be added.
40 */
41 private final ClassWriter cw;
42
43 /**
44 * Access flags of this field.
45 */
46 private final int access;
47
48 /**
49 * The index of the constant pool item that contains the name of this
50 * method.
51 */
52 private final int name;
53
54 /**
55 * The index of the constant pool item that contains the descriptor of this
56 * field.
57 */
58 private final int desc;
59
60 /**
61 * The index of the constant pool item that contains the signature of this
62 * field.
63 */
64 private int signature;
65
66 /**
67 * The index of the constant pool item that contains the constant value of
68 * this field.
69 */
70 private int value;
71
72 /**
73 * The runtime visible annotations of this field. May be <tt>null</tt>.
74 */
75 private AnnotationWriter anns;
76
77 /**
78 * The runtime invisible annotations of this field. May be <tt>null</tt>.
79 */
80 private AnnotationWriter ianns;
81
82 /**
83 * The non standard attributes of this field. May be <tt>null</tt>.
84 */
85 private Attribute attrs;
86
87 // ------------------------------------------------------------------------
88 // Constructor
89 // ------------------------------------------------------------------------
90
91 /**
92 * Constructs a new {@link FieldWriter}.
93 *
94 * @param cw
95 * the class writer to which this field must be added.
96 * @param access
97 * the field's access flags (see {@link Opcodes}).
98 * @param name
99 * the field's name.
100 * @param desc
101 * the field's descriptor (see {@link Type}).
102 * @param signature
103 * the field's signature. May be <tt>null</tt>.
104 * @param value
105 * the field's constant value. May be <tt>null</tt>.
106 */
107 FieldWriter(final ClassWriter cw, final int access, final String name,
108 final String desc, final String signature, final Object value) {
109 super(Opcodes.ASM4);
110 if (cw.firstField == null) {
111 cw.firstField = this;
112 } else {
113 cw.lastField.fv = this;
114 }
115 cw.lastField = this;
116 this.cw = cw;
117 this.access = access;
118 this.name = cw.newUTF8(name);
119 this.desc = cw.newUTF8(desc);
120 if (ClassReader.SIGNATURES && signature != null) {
121 this.signature = cw.newUTF8(signature);
122 }
123 if (value != null) {
124 this.value = cw.newConstItem(value).index;
125 }
126 }
127
128 // ------------------------------------------------------------------------
129 // Implementation of the FieldVisitor abstract class
130 // ------------------------------------------------------------------------
131
132 @Override
133 public AnnotationVisitor visitAnnotation(final String desc,
134 final boolean visible) {
135 if (!ClassReader.ANNOTATIONS) {
136 return null;
137 }
138 ByteVector bv = new ByteVector();
139 // write type, and reserve space for values count
140 bv.putShort(cw.newUTF8(desc)).putShort(0);
141 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
142 if (visible) {
143 aw.next = anns;
144 anns = aw;
145 } else {
146 aw.next = ianns;
147 ianns = aw;
148 }
149 return aw;
150 }
151
152 @Override
153 public void visitAttribute(final Attribute attr) {
154 attr.next = attrs;
155 attrs = attr;
156 }
157
158 @Override
159 public void visitEnd() {
160 }
161
162 // ------------------------------------------------------------------------
163 // Utility methods
164 // ------------------------------------------------------------------------
165
166 /**
167 * Returns the size of this field.
168 *
169 * @return the size of this field.
170 */
171 int getSize() {
172 int size = 8;
173 if (value != 0) {
174 cw.newUTF8("ConstantValue");
175 size += 8;
176 }
177 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
178 if ((cw.version & 0xFFFF) < Opcodes.V1_5
179 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
180 cw.newUTF8("Synthetic");
181 size += 6;
182 }
183 }
184 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
185 cw.newUTF8("Deprecated");
186 size += 6;
187 }
188 if (ClassReader.SIGNATURES && signature != 0) {
189 cw.newUTF8("Signature");
190 size += 8;
191 }
192 if (ClassReader.ANNOTATIONS && anns != null) {
193 cw.newUTF8("RuntimeVisibleAnnotations");
194 size += 8 + anns.getSize();
195 }
196 if (ClassReader.ANNOTATIONS && ianns != null) {
197 cw.newUTF8("RuntimeInvisibleAnnotations");
198 size += 8 + ianns.getSize();
199 }
200 if (attrs != null) {
201 size += attrs.getSize(cw, null, 0, -1, -1);
202 }
203 return size;
204 }
205
206 /**
207 * Puts the content of this field into the given byte vector.
208 *
209 * @param out
210 * where the content of this field must be put.
211 */
212 void put(final ByteVector out) {
213 final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
214 int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
215 | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
216 out.putShort(access & ~mask).putShort(name).putShort(desc);
217 int attributeCount = 0;
218 if (value != 0) {
219 ++attributeCount;
220 }
221 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
222 if ((cw.version & 0xFFFF) < Opcodes.V1_5
223 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
224 ++attributeCount;
225 }
226 }
227 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
228 ++attributeCount;
229 }
230 if (ClassReader.SIGNATURES && signature != 0) {
231 ++attributeCount;
232 }
233 if (ClassReader.ANNOTATIONS && anns != null) {
234 ++attributeCount;
235 }
236 if (ClassReader.ANNOTATIONS && ianns != null) {
237 ++attributeCount;
238 }
239 if (attrs != null) {
240 attributeCount += attrs.getCount();
241 }
242 out.putShort(attributeCount);
243 if (value != 0) {
244 out.putShort(cw.newUTF8("ConstantValue"));
245 out.putInt(2).putShort(value);
246 }
247 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
248 if ((cw.version & 0xFFFF) < Opcodes.V1_5
249 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
250 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
251 }
252 }
253 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
254 out.putShort(cw.newUTF8("Deprecated")).putInt(0);
255 }
256 if (ClassReader.SIGNATURES && signature != 0) {
257 out.putShort(cw.newUTF8("Signature"));
258 out.putInt(2).putShort(signature);
259 }
260 if (ClassReader.ANNOTATIONS && anns != null) {
261 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
262 anns.put(out);
263 }
264 if (ClassReader.ANNOTATIONS && ianns != null) {
265 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
266 ianns.put(out);
267 }
268 if (attrs != null) {
269 attrs.put(cw, null, 0, -1, -1, out);
270 }
271 }
272 }
+0
-1453
src/jvm/clojure/asm/Frame.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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 beginning 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
84 * operand stack. This is necessary to be able to simulate DUPx_y
85 * instructions, whose effect would be dependent on the actual type values
86 * if types were always represented by a single slot in the stack (and this
87 * is not possible, since actual type values are not always known - cf LOCAL
88 * and 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 static final int DIM = 0xF0000000;
96
97 /**
98 * Constant to be added to a type to get a type with one more dimension.
99 */
100 static final int ARRAY_OF = 0x10000000;
101
102 /**
103 * Constant to be added to a type to get a type with one less dimension.
104 */
105 static final 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 static final int KIND = 0xF000000;
115
116 /**
117 * Flag used for LOCAL and STACK types. Indicates that if this type happens
118 * to be a long or double type (during the computations of input frames),
119 * then it must be set to TOP because the second word of this value has been
120 * reused to store other data in the basic block. Hence the first word no
121 * longer stores a valid long or double value.
122 */
123 static final int TOP_IF_LONG_OR_DOUBLE = 0x800000;
124
125 /**
126 * Mask to get the value of a frame type.
127 */
128 static final int VALUE = 0x7FFFFF;
129
130 /**
131 * Mask to get the kind of base types.
132 */
133 static final int BASE_KIND = 0xFF00000;
134
135 /**
136 * Mask to get the value of base types.
137 */
138 static final int BASE_VALUE = 0xFFFFF;
139
140 /**
141 * Kind of the types that are not relative to an input stack map frame.
142 */
143 static final int BASE = 0x1000000;
144
145 /**
146 * Base kind of the base reference types. The BASE_VALUE of such types is an
147 * index into the type table.
148 */
149 static final int OBJECT = BASE | 0x700000;
150
151 /**
152 * Base kind of the uninitialized base types. The BASE_VALUE of such types
153 * in an index into the type table (the Item at that index contains both an
154 * instruction offset and an internal class name).
155 */
156 static final int UNINITIALIZED = BASE | 0x800000;
157
158 /**
159 * Kind of the types that are relative to the local variable types of an
160 * input stack map frame. The value of such types is a local variable index.
161 */
162 private static final int LOCAL = 0x2000000;
163
164 /**
165 * Kind of the the types that are relative to the stack of an input stack
166 * map frame. The value of such types is a position relatively to the top of
167 * this stack.
168 */
169 private static final int STACK = 0x3000000;
170
171 /**
172 * The TOP type. This is a BASE type.
173 */
174 static final int TOP = BASE | 0;
175
176 /**
177 * The BOOLEAN type. This is a BASE type mainly used for array types.
178 */
179 static final int BOOLEAN = BASE | 9;
180
181 /**
182 * The BYTE type. This is a BASE type mainly used for array types.
183 */
184 static final int BYTE = BASE | 10;
185
186 /**
187 * The CHAR type. This is a BASE type mainly used for array types.
188 */
189 static final int CHAR = BASE | 11;
190
191 /**
192 * The SHORT type. This is a BASE type mainly used for array types.
193 */
194 static final int SHORT = BASE | 12;
195
196 /**
197 * The INTEGER type. This is a BASE type.
198 */
199 static final int INTEGER = BASE | 1;
200
201 /**
202 * The FLOAT type. This is a BASE type.
203 */
204 static final int FLOAT = BASE | 2;
205
206 /**
207 * The DOUBLE type. This is a BASE type.
208 */
209 static final int DOUBLE = BASE | 3;
210
211 /**
212 * The LONG type. This is a BASE type.
213 */
214 static final int LONG = BASE | 4;
215
216 /**
217 * The NULL type. This is a BASE type.
218 */
219 static final int NULL = BASE | 5;
220
221 /**
222 * The UNINITIALIZED_THIS type. This is a BASE type.
223 */
224 static final int UNINITIALIZED_THIS = BASE | 6;
225
226 /**
227 * The stack size variation corresponding to each JVM instruction. This
228 * stack variation is equal to the size of the values produced by an
229 * instruction, minus the size of the values consumed by this instruction.
230 */
231 static final int[] SIZE;
232
233 /**
234 * Computes the stack size variation corresponding to each JVM instruction.
235 */
236 static {
237 int i;
238 int[] b = new int[202];
239 String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD"
240 + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD"
241 + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED"
242 + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
243 for (i = 0; i < b.length; ++i) {
244 b[i] = s.charAt(i) - 'E';
245 }
246 SIZE = b;
247
248 // code to generate the above string
249 //
250 // int NA = 0; // not applicable (unused opcode or variable size opcode)
251 //
252 // b = new int[] {
253 // 0, //NOP, // visitInsn
254 // 1, //ACONST_NULL, // -
255 // 1, //ICONST_M1, // -
256 // 1, //ICONST_0, // -
257 // 1, //ICONST_1, // -
258 // 1, //ICONST_2, // -
259 // 1, //ICONST_3, // -
260 // 1, //ICONST_4, // -
261 // 1, //ICONST_5, // -
262 // 2, //LCONST_0, // -
263 // 2, //LCONST_1, // -
264 // 1, //FCONST_0, // -
265 // 1, //FCONST_1, // -
266 // 1, //FCONST_2, // -
267 // 2, //DCONST_0, // -
268 // 2, //DCONST_1, // -
269 // 1, //BIPUSH, // visitIntInsn
270 // 1, //SIPUSH, // -
271 // 1, //LDC, // visitLdcInsn
272 // NA, //LDC_W, // -
273 // NA, //LDC2_W, // -
274 // 1, //ILOAD, // visitVarInsn
275 // 2, //LLOAD, // -
276 // 1, //FLOAD, // -
277 // 2, //DLOAD, // -
278 // 1, //ALOAD, // -
279 // NA, //ILOAD_0, // -
280 // NA, //ILOAD_1, // -
281 // NA, //ILOAD_2, // -
282 // NA, //ILOAD_3, // -
283 // NA, //LLOAD_0, // -
284 // NA, //LLOAD_1, // -
285 // NA, //LLOAD_2, // -
286 // NA, //LLOAD_3, // -
287 // NA, //FLOAD_0, // -
288 // NA, //FLOAD_1, // -
289 // NA, //FLOAD_2, // -
290 // NA, //FLOAD_3, // -
291 // NA, //DLOAD_0, // -
292 // NA, //DLOAD_1, // -
293 // NA, //DLOAD_2, // -
294 // NA, //DLOAD_3, // -
295 // NA, //ALOAD_0, // -
296 // NA, //ALOAD_1, // -
297 // NA, //ALOAD_2, // -
298 // NA, //ALOAD_3, // -
299 // -1, //IALOAD, // visitInsn
300 // 0, //LALOAD, // -
301 // -1, //FALOAD, // -
302 // 0, //DALOAD, // -
303 // -1, //AALOAD, // -
304 // -1, //BALOAD, // -
305 // -1, //CALOAD, // -
306 // -1, //SALOAD, // -
307 // -1, //ISTORE, // visitVarInsn
308 // -2, //LSTORE, // -
309 // -1, //FSTORE, // -
310 // -2, //DSTORE, // -
311 // -1, //ASTORE, // -
312 // NA, //ISTORE_0, // -
313 // NA, //ISTORE_1, // -
314 // NA, //ISTORE_2, // -
315 // NA, //ISTORE_3, // -
316 // NA, //LSTORE_0, // -
317 // NA, //LSTORE_1, // -
318 // NA, //LSTORE_2, // -
319 // NA, //LSTORE_3, // -
320 // NA, //FSTORE_0, // -
321 // NA, //FSTORE_1, // -
322 // NA, //FSTORE_2, // -
323 // NA, //FSTORE_3, // -
324 // NA, //DSTORE_0, // -
325 // NA, //DSTORE_1, // -
326 // NA, //DSTORE_2, // -
327 // NA, //DSTORE_3, // -
328 // NA, //ASTORE_0, // -
329 // NA, //ASTORE_1, // -
330 // NA, //ASTORE_2, // -
331 // NA, //ASTORE_3, // -
332 // -3, //IASTORE, // visitInsn
333 // -4, //LASTORE, // -
334 // -3, //FASTORE, // -
335 // -4, //DASTORE, // -
336 // -3, //AASTORE, // -
337 // -3, //BASTORE, // -
338 // -3, //CASTORE, // -
339 // -3, //SASTORE, // -
340 // -1, //POP, // -
341 // -2, //POP2, // -
342 // 1, //DUP, // -
343 // 1, //DUP_X1, // -
344 // 1, //DUP_X2, // -
345 // 2, //DUP2, // -
346 // 2, //DUP2_X1, // -
347 // 2, //DUP2_X2, // -
348 // 0, //SWAP, // -
349 // -1, //IADD, // -
350 // -2, //LADD, // -
351 // -1, //FADD, // -
352 // -2, //DADD, // -
353 // -1, //ISUB, // -
354 // -2, //LSUB, // -
355 // -1, //FSUB, // -
356 // -2, //DSUB, // -
357 // -1, //IMUL, // -
358 // -2, //LMUL, // -
359 // -1, //FMUL, // -
360 // -2, //DMUL, // -
361 // -1, //IDIV, // -
362 // -2, //LDIV, // -
363 // -1, //FDIV, // -
364 // -2, //DDIV, // -
365 // -1, //IREM, // -
366 // -2, //LREM, // -
367 // -1, //FREM, // -
368 // -2, //DREM, // -
369 // 0, //INEG, // -
370 // 0, //LNEG, // -
371 // 0, //FNEG, // -
372 // 0, //DNEG, // -
373 // -1, //ISHL, // -
374 // -1, //LSHL, // -
375 // -1, //ISHR, // -
376 // -1, //LSHR, // -
377 // -1, //IUSHR, // -
378 // -1, //LUSHR, // -
379 // -1, //IAND, // -
380 // -2, //LAND, // -
381 // -1, //IOR, // -
382 // -2, //LOR, // -
383 // -1, //IXOR, // -
384 // -2, //LXOR, // -
385 // 0, //IINC, // visitIincInsn
386 // 1, //I2L, // visitInsn
387 // 0, //I2F, // -
388 // 1, //I2D, // -
389 // -1, //L2I, // -
390 // -1, //L2F, // -
391 // 0, //L2D, // -
392 // 0, //F2I, // -
393 // 1, //F2L, // -
394 // 1, //F2D, // -
395 // -1, //D2I, // -
396 // 0, //D2L, // -
397 // -1, //D2F, // -
398 // 0, //I2B, // -
399 // 0, //I2C, // -
400 // 0, //I2S, // -
401 // -3, //LCMP, // -
402 // -1, //FCMPL, // -
403 // -1, //FCMPG, // -
404 // -3, //DCMPL, // -
405 // -3, //DCMPG, // -
406 // -1, //IFEQ, // visitJumpInsn
407 // -1, //IFNE, // -
408 // -1, //IFLT, // -
409 // -1, //IFGE, // -
410 // -1, //IFGT, // -
411 // -1, //IFLE, // -
412 // -2, //IF_ICMPEQ, // -
413 // -2, //IF_ICMPNE, // -
414 // -2, //IF_ICMPLT, // -
415 // -2, //IF_ICMPGE, // -
416 // -2, //IF_ICMPGT, // -
417 // -2, //IF_ICMPLE, // -
418 // -2, //IF_ACMPEQ, // -
419 // -2, //IF_ACMPNE, // -
420 // 0, //GOTO, // -
421 // 1, //JSR, // -
422 // 0, //RET, // visitVarInsn
423 // -1, //TABLESWITCH, // visiTableSwitchInsn
424 // -1, //LOOKUPSWITCH, // visitLookupSwitch
425 // -1, //IRETURN, // visitInsn
426 // -2, //LRETURN, // -
427 // -1, //FRETURN, // -
428 // -2, //DRETURN, // -
429 // -1, //ARETURN, // -
430 // 0, //RETURN, // -
431 // NA, //GETSTATIC, // visitFieldInsn
432 // NA, //PUTSTATIC, // -
433 // NA, //GETFIELD, // -
434 // NA, //PUTFIELD, // -
435 // NA, //INVOKEVIRTUAL, // visitMethodInsn
436 // NA, //INVOKESPECIAL, // -
437 // NA, //INVOKESTATIC, // -
438 // NA, //INVOKEINTERFACE, // -
439 // NA, //INVOKEDYNAMIC, // visitInvokeDynamicInsn
440 // 1, //NEW, // visitTypeInsn
441 // 0, //NEWARRAY, // visitIntInsn
442 // 0, //ANEWARRAY, // visitTypeInsn
443 // 0, //ARRAYLENGTH, // visitInsn
444 // NA, //ATHROW, // -
445 // 0, //CHECKCAST, // visitTypeInsn
446 // 0, //INSTANCEOF, // -
447 // -1, //MONITORENTER, // visitInsn
448 // -1, //MONITOREXIT, // -
449 // NA, //WIDE, // NOT VISITED
450 // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn
451 // -1, //IFNULL, // visitJumpInsn
452 // -1, //IFNONNULL, // -
453 // NA, //GOTO_W, // -
454 // NA, //JSR_W, // -
455 // };
456 // for (i = 0; i < b.length; ++i) {
457 // System.err.print((char)('E' + b[i]));
458 // }
459 // System.err.println();
460 }
461
462 /**
463 * The label (i.e. basic block) to which these input and output stack map
464 * frames correspond.
465 */
466 Label owner;
467
468 /**
469 * The input stack map frame locals.
470 */
471 int[] inputLocals;
472
473 /**
474 * The input stack map frame stack.
475 */
476 int[] inputStack;
477
478 /**
479 * The output stack map frame locals.
480 */
481 private int[] outputLocals;
482
483 /**
484 * The output stack map frame stack.
485 */
486 private int[] outputStack;
487
488 /**
489 * Relative size of the output stack. The exact semantics of this field
490 * depends on the algorithm that is used.
491 *
492 * When only the maximum stack size is computed, this field is the size of
493 * the output stack relatively to the top of the input stack.
494 *
495 * When the stack map frames are completely computed, this field is the
496 * actual number of types in {@link #outputStack}.
497 */
498 private int outputStackTop;
499
500 /**
501 * Number of types that are initialized in the basic block.
502 *
503 * @see #initializations
504 */
505 private int initializationCount;
506
507 /**
508 * The types that are initialized in the basic block. A constructor
509 * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace
510 * <i>every occurence</i> of this type in the local variables and in the
511 * operand stack. This cannot be done during the first phase of the
512 * algorithm since, during this phase, the local variables and the operand
513 * stack are not completely computed. It is therefore necessary to store the
514 * types on which constructors are invoked in the basic block, in order to
515 * do this replacement during the second phase of the algorithm, where the
516 * frames are fully computed. Note that this array can contain types that
517 * are relative to input locals or to the input stack (see below for the
518 * description of the algorithm).
519 */
520 private int[] initializations;
521
522 /**
523 * Returns the output frame local variable type at the given index.
524 *
525 * @param local
526 * the index of the local that must be returned.
527 * @return the output frame local variable type at the given index.
528 */
529 private int get(final int local) {
530 if (outputLocals == null || local >= outputLocals.length) {
531 // this local has never been assigned in this basic block,
532 // so it is still equal to its value in the input frame
533 return LOCAL | local;
534 } else {
535 int type = outputLocals[local];
536 if (type == 0) {
537 // this local has never been assigned in this basic block,
538 // so it is still equal to its value in the input frame
539 type = outputLocals[local] = LOCAL | local;
540 }
541 return type;
542 }
543 }
544
545 /**
546 * Sets the output frame local variable type at the given index.
547 *
548 * @param local
549 * the index of the local that must be set.
550 * @param type
551 * the value of the local that must be set.
552 */
553 private void set(final int local, final int type) {
554 // creates and/or resizes the output local variables array if necessary
555 if (outputLocals == null) {
556 outputLocals = new int[10];
557 }
558 int n = outputLocals.length;
559 if (local >= n) {
560 int[] t = new int[Math.max(local + 1, 2 * n)];
561 System.arraycopy(outputLocals, 0, t, 0, n);
562 outputLocals = t;
563 }
564 // sets the local variable
565 outputLocals[local] = type;
566 }
567
568 /**
569 * Pushes a new type onto the output frame stack.
570 *
571 * @param type
572 * the type that must be pushed.
573 */
574 private void push(final int type) {
575 // creates and/or resizes the output stack array if necessary
576 if (outputStack == null) {
577 outputStack = new int[10];
578 }
579 int n = outputStack.length;
580 if (outputStackTop >= n) {
581 int[] t = new int[Math.max(outputStackTop + 1, 2 * n)];
582 System.arraycopy(outputStack, 0, t, 0, n);
583 outputStack = t;
584 }
585 // pushes the type on the output stack
586 outputStack[outputStackTop++] = type;
587 // updates the maximun height reached by the output stack, if needed
588 int top = owner.inputStackTop + outputStackTop;
589 if (top > owner.outputStackMax) {
590 owner.outputStackMax = top;
591 }
592 }
593
594 /**
595 * Pushes a new type onto the output frame stack.
596 *
597 * @param cw
598 * the ClassWriter to which this label belongs.
599 * @param desc
600 * the descriptor of the type to be pushed. Can also be a method
601 * descriptor (in this case this method pushes its return type
602 * onto the output frame stack).
603 */
604 private void push(final ClassWriter cw, final String desc) {
605 int type = type(cw, desc);
606 if (type != 0) {
607 push(type);
608 if (type == LONG || type == DOUBLE) {
609 push(TOP);
610 }
611 }
612 }
613
614 /**
615 * Returns the int encoding of the given type.
616 *
617 * @param cw
618 * the ClassWriter to which this label belongs.
619 * @param desc
620 * a type descriptor.
621 * @return the int encoding of the given type.
622 */
623 private static int type(final ClassWriter cw, final String desc) {
624 String t;
625 int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
626 switch (desc.charAt(index)) {
627 case 'V':
628 return 0;
629 case 'Z':
630 case 'C':
631 case 'B':
632 case 'S':
633 case 'I':
634 return INTEGER;
635 case 'F':
636 return FLOAT;
637 case 'J':
638 return LONG;
639 case 'D':
640 return DOUBLE;
641 case 'L':
642 // stores the internal name, not the descriptor!
643 t = desc.substring(index + 1, desc.length() - 1);
644 return OBJECT | cw.addType(t);
645 // case '[':
646 default:
647 // extracts the dimensions and the element type
648 int data;
649 int dims = index + 1;
650 while (desc.charAt(dims) == '[') {
651 ++dims;
652 }
653 switch (desc.charAt(dims)) {
654 case 'Z':
655 data = BOOLEAN;
656 break;
657 case 'C':
658 data = CHAR;
659 break;
660 case 'B':
661 data = BYTE;
662 break;
663 case 'S':
664 data = SHORT;
665 break;
666 case 'I':
667 data = INTEGER;
668 break;
669 case 'F':
670 data = FLOAT;
671 break;
672 case 'J':
673 data = LONG;
674 break;
675 case 'D':
676 data = DOUBLE;
677 break;
678 // case 'L':
679 default:
680 // stores the internal name, not the descriptor
681 t = desc.substring(dims + 1, desc.length() - 1);
682 data = OBJECT | cw.addType(t);
683 }
684 return (dims - index) << 28 | data;
685 }
686 }
687
688 /**
689 * Pops a type from the output frame stack and returns its value.
690 *
691 * @return the type that has been popped from the output frame stack.
692 */
693 private int pop() {
694 if (outputStackTop > 0) {
695 return outputStack[--outputStackTop];
696 } else {
697 // if the output frame stack is empty, pops from the input stack
698 return STACK | -(--owner.inputStackTop);
699 }
700 }
701
702 /**
703 * Pops the given number of types from the output frame stack.
704 *
705 * @param elements
706 * the number of types that must be popped.
707 */
708 private void pop(final int elements) {
709 if (outputStackTop >= elements) {
710 outputStackTop -= elements;
711 } else {
712 // if the number of elements to be popped is greater than the number
713 // of elements in the output stack, clear it, and pops the remaining
714 // elements from the input stack.
715 owner.inputStackTop -= elements - outputStackTop;
716 outputStackTop = 0;
717 }
718 }
719
720 /**
721 * Pops a type from the output frame stack.
722 *
723 * @param desc
724 * the descriptor of the type to be popped. Can also be a method
725 * descriptor (in this case this method pops the types
726 * corresponding to the method arguments).
727 */
728 private void pop(final String desc) {
729 char c = desc.charAt(0);
730 if (c == '(') {
731 pop((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1);
732 } else if (c == 'J' || c == 'D') {
733 pop(2);
734 } else {
735 pop(1);
736 }
737 }
738
739 /**
740 * Adds a new type to the list of types on which a constructor is invoked in
741 * the basic block.
742 *
743 * @param var
744 * a type on a which a constructor is invoked.
745 */
746 private void init(final int var) {
747 // creates and/or resizes the initializations array if necessary
748 if (initializations == null) {
749 initializations = new int[2];
750 }
751 int n = initializations.length;
752 if (initializationCount >= n) {
753 int[] t = new int[Math.max(initializationCount + 1, 2 * n)];
754 System.arraycopy(initializations, 0, t, 0, n);
755 initializations = t;
756 }
757 // stores the type to be initialized
758 initializations[initializationCount++] = var;
759 }
760
761 /**
762 * Replaces the given type with the appropriate type if it is one of the
763 * types on which a constructor is invoked in the basic block.
764 *
765 * @param cw
766 * the ClassWriter to which this label belongs.
767 * @param t
768 * a type
769 * @return t or, if t is one of the types on which a constructor is invoked
770 * in the basic block, the type corresponding to this constructor.
771 */
772 private int init(final ClassWriter cw, final int t) {
773 int s;
774 if (t == UNINITIALIZED_THIS) {
775 s = OBJECT | cw.addType(cw.thisName);
776 } else if ((t & (DIM | BASE_KIND)) == UNINITIALIZED) {
777 String type = cw.typeTable[t & BASE_VALUE].strVal1;
778 s = OBJECT | cw.addType(type);
779 } else {
780 return t;
781 }
782 for (int j = 0; j < initializationCount; ++j) {
783 int u = initializations[j];
784 int dim = u & DIM;
785 int kind = u & KIND;
786 if (kind == LOCAL) {
787 u = dim + inputLocals[u & VALUE];
788 } else if (kind == STACK) {
789 u = dim + inputStack[inputStack.length - (u & VALUE)];
790 }
791 if (t == u) {
792 return s;
793 }
794 }
795 return t;
796 }
797
798 /**
799 * Initializes the input frame of the first basic block from the method
800 * descriptor.
801 *
802 * @param cw
803 * the ClassWriter to which this label belongs.
804 * @param access
805 * the access flags of the method to which this label belongs.
806 * @param args
807 * the formal parameter types of this method.
808 * @param maxLocals
809 * the maximum number of local variables of this method.
810 */
811 void initInputFrame(final ClassWriter cw, final int access,
812 final Type[] args, final int maxLocals) {
813 inputLocals = new int[maxLocals];
814 inputStack = new int[0];
815 int i = 0;
816 if ((access & Opcodes.ACC_STATIC) == 0) {
817 if ((access & MethodWriter.ACC_CONSTRUCTOR) == 0) {
818 inputLocals[i++] = OBJECT | cw.addType(cw.thisName);
819 } else {
820 inputLocals[i++] = UNINITIALIZED_THIS;
821 }
822 }
823 for (int j = 0; j < args.length; ++j) {
824 int t = type(cw, args[j].getDescriptor());
825 inputLocals[i++] = t;
826 if (t == LONG || t == DOUBLE) {
827 inputLocals[i++] = TOP;
828 }
829 }
830 while (i < maxLocals) {
831 inputLocals[i++] = TOP;
832 }
833 }
834
835 /**
836 * Simulates the action of the given instruction on the output stack frame.
837 *
838 * @param opcode
839 * the opcode of the instruction.
840 * @param arg
841 * the operand of the instruction, if any.
842 * @param cw
843 * the class writer to which this label belongs.
844 * @param item
845 * the operand of the instructions, if any.
846 */
847 void execute(final int opcode, final int arg, final ClassWriter cw,
848 final Item item) {
849 int t1, t2, t3, t4;
850 switch (opcode) {
851 case Opcodes.NOP:
852 case Opcodes.INEG:
853 case Opcodes.LNEG:
854 case Opcodes.FNEG:
855 case Opcodes.DNEG:
856 case Opcodes.I2B:
857 case Opcodes.I2C:
858 case Opcodes.I2S:
859 case Opcodes.GOTO:
860 case Opcodes.RETURN:
861 break;
862 case Opcodes.ACONST_NULL:
863 push(NULL);
864 break;
865 case Opcodes.ICONST_M1:
866 case Opcodes.ICONST_0:
867 case Opcodes.ICONST_1:
868 case Opcodes.ICONST_2:
869 case Opcodes.ICONST_3:
870 case Opcodes.ICONST_4:
871 case Opcodes.ICONST_5:
872 case Opcodes.BIPUSH:
873 case Opcodes.SIPUSH:
874 case Opcodes.ILOAD:
875 push(INTEGER);
876 break;
877 case Opcodes.LCONST_0:
878 case Opcodes.LCONST_1:
879 case Opcodes.LLOAD:
880 push(LONG);
881 push(TOP);
882 break;
883 case Opcodes.FCONST_0:
884 case Opcodes.FCONST_1:
885 case Opcodes.FCONST_2:
886 case Opcodes.FLOAD:
887 push(FLOAT);
888 break;
889 case Opcodes.DCONST_0:
890 case Opcodes.DCONST_1:
891 case Opcodes.DLOAD:
892 push(DOUBLE);
893 push(TOP);
894 break;
895 case Opcodes.LDC:
896 switch (item.type) {
897 case ClassWriter.INT:
898 push(INTEGER);
899 break;
900 case ClassWriter.LONG:
901 push(LONG);
902 push(TOP);
903 break;
904 case ClassWriter.FLOAT:
905 push(FLOAT);
906 break;
907 case ClassWriter.DOUBLE:
908 push(DOUBLE);
909 push(TOP);
910 break;
911 case ClassWriter.CLASS:
912 push(OBJECT | cw.addType("java/lang/Class"));
913 break;
914 case ClassWriter.STR:
915 push(OBJECT | cw.addType("java/lang/String"));
916 break;
917 case ClassWriter.MTYPE:
918 push(OBJECT | cw.addType("java/lang/invoke/MethodType"));
919 break;
920 // case ClassWriter.HANDLE_BASE + [1..9]:
921 default:
922 push(OBJECT | cw.addType("java/lang/invoke/MethodHandle"));
923 }
924 break;
925 case Opcodes.ALOAD:
926 push(get(arg));
927 break;
928 case Opcodes.IALOAD:
929 case Opcodes.BALOAD:
930 case Opcodes.CALOAD:
931 case Opcodes.SALOAD:
932 pop(2);
933 push(INTEGER);
934 break;
935 case Opcodes.LALOAD:
936 case Opcodes.D2L:
937 pop(2);
938 push(LONG);
939 push(TOP);
940 break;
941 case Opcodes.FALOAD:
942 pop(2);
943 push(FLOAT);
944 break;
945 case Opcodes.DALOAD:
946 case Opcodes.L2D:
947 pop(2);
948 push(DOUBLE);
949 push(TOP);
950 break;
951 case Opcodes.AALOAD:
952 pop(1);
953 t1 = pop();
954 push(ELEMENT_OF + t1);
955 break;
956 case Opcodes.ISTORE:
957 case Opcodes.FSTORE:
958 case Opcodes.ASTORE:
959 t1 = pop();
960 set(arg, t1);
961 if (arg > 0) {
962 t2 = get(arg - 1);
963 // if t2 is of kind STACK or LOCAL we cannot know its size!
964 if (t2 == LONG || t2 == DOUBLE) {
965 set(arg - 1, TOP);
966 } else if ((t2 & KIND) != BASE) {
967 set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE);
968 }
969 }
970 break;
971 case Opcodes.LSTORE:
972 case Opcodes.DSTORE:
973 pop(1);
974 t1 = pop();
975 set(arg, t1);
976 set(arg + 1, TOP);
977 if (arg > 0) {
978 t2 = get(arg - 1);
979 // if t2 is of kind STACK or LOCAL we cannot know its size!
980 if (t2 == LONG || t2 == DOUBLE) {
981 set(arg - 1, TOP);
982 } else if ((t2 & KIND) != BASE) {
983 set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE);
984 }
985 }
986 break;
987 case Opcodes.IASTORE:
988 case Opcodes.BASTORE:
989 case Opcodes.CASTORE:
990 case Opcodes.SASTORE:
991 case Opcodes.FASTORE:
992 case Opcodes.AASTORE:
993 pop(3);
994 break;
995 case Opcodes.LASTORE:
996 case Opcodes.DASTORE:
997 pop(4);
998 break;
999 case Opcodes.POP:
1000 case Opcodes.IFEQ:
1001 case Opcodes.IFNE:
1002 case Opcodes.IFLT:
1003 case Opcodes.IFGE:
1004 case Opcodes.IFGT:
1005 case Opcodes.IFLE:
1006 case Opcodes.IRETURN:
1007 case Opcodes.FRETURN:
1008 case Opcodes.ARETURN:
1009 case Opcodes.TABLESWITCH:
1010 case Opcodes.LOOKUPSWITCH:
1011 case Opcodes.ATHROW:
1012 case Opcodes.MONITORENTER:
1013 case Opcodes.MONITOREXIT:
1014 case Opcodes.IFNULL:
1015 case Opcodes.IFNONNULL:
1016 pop(1);
1017 break;
1018 case Opcodes.POP2:
1019 case Opcodes.IF_ICMPEQ:
1020 case Opcodes.IF_ICMPNE:
1021 case Opcodes.IF_ICMPLT:
1022 case Opcodes.IF_ICMPGE:
1023 case Opcodes.IF_ICMPGT:
1024 case Opcodes.IF_ICMPLE:
1025 case Opcodes.IF_ACMPEQ:
1026 case Opcodes.IF_ACMPNE:
1027 case Opcodes.LRETURN:
1028 case Opcodes.DRETURN:
1029 pop(2);
1030 break;
1031 case Opcodes.DUP:
1032 t1 = pop();
1033 push(t1);
1034 push(t1);
1035 break;
1036 case Opcodes.DUP_X1:
1037 t1 = pop();
1038 t2 = pop();
1039 push(t1);
1040 push(t2);
1041 push(t1);
1042 break;
1043 case Opcodes.DUP_X2:
1044 t1 = pop();
1045 t2 = pop();
1046 t3 = pop();
1047 push(t1);
1048 push(t3);
1049 push(t2);
1050 push(t1);
1051 break;
1052 case Opcodes.DUP2:
1053 t1 = pop();
1054 t2 = pop();
1055 push(t2);
1056 push(t1);
1057 push(t2);
1058 push(t1);
1059 break;
1060 case Opcodes.DUP2_X1:
1061 t1 = pop();
1062 t2 = pop();
1063 t3 = pop();
1064 push(t2);
1065 push(t1);
1066 push(t3);
1067 push(t2);
1068 push(t1);
1069 break;
1070 case Opcodes.DUP2_X2:
1071 t1 = pop();
1072 t2 = pop();
1073 t3 = pop();
1074 t4 = pop();
1075 push(t2);
1076 push(t1);
1077 push(t4);
1078 push(t3);
1079 push(t2);
1080 push(t1);
1081 break;
1082 case Opcodes.SWAP:
1083 t1 = pop();
1084 t2 = pop();
1085 push(t1);
1086 push(t2);
1087 break;
1088 case Opcodes.IADD:
1089 case Opcodes.ISUB:
1090 case Opcodes.IMUL:
1091 case Opcodes.IDIV:
1092 case Opcodes.IREM:
1093 case Opcodes.IAND:
1094 case Opcodes.IOR:
1095 case Opcodes.IXOR:
1096 case Opcodes.ISHL:
1097 case Opcodes.ISHR:
1098 case Opcodes.IUSHR:
1099 case Opcodes.L2I:
1100 case Opcodes.D2I:
1101 case Opcodes.FCMPL:
1102 case Opcodes.FCMPG:
1103 pop(2);
1104 push(INTEGER);
1105 break;
1106 case Opcodes.LADD:
1107 case Opcodes.LSUB:
1108 case Opcodes.LMUL:
1109 case Opcodes.LDIV:
1110 case Opcodes.LREM:
1111 case Opcodes.LAND:
1112 case Opcodes.LOR:
1113 case Opcodes.LXOR:
1114 pop(4);
1115 push(LONG);
1116 push(TOP);
1117 break;
1118 case Opcodes.FADD:
1119 case Opcodes.FSUB:
1120 case Opcodes.FMUL:
1121 case Opcodes.FDIV:
1122 case Opcodes.FREM:
1123 case Opcodes.L2F:
1124 case Opcodes.D2F:
1125 pop(2);
1126 push(FLOAT);
1127 break;
1128 case Opcodes.DADD:
1129 case Opcodes.DSUB:
1130 case Opcodes.DMUL:
1131 case Opcodes.DDIV:
1132 case Opcodes.DREM:
1133 pop(4);
1134 push(DOUBLE);
1135 push(TOP);
1136 break;
1137 case Opcodes.LSHL:
1138 case Opcodes.LSHR:
1139 case Opcodes.LUSHR:
1140 pop(3);
1141 push(LONG);
1142 push(TOP);
1143 break;
1144 case Opcodes.IINC:
1145 set(arg, INTEGER);
1146 break;
1147 case Opcodes.I2L:
1148 case Opcodes.F2L:
1149 pop(1);
1150 push(LONG);
1151 push(TOP);
1152 break;
1153 case Opcodes.I2F:
1154 pop(1);
1155 push(FLOAT);
1156 break;
1157 case Opcodes.I2D:
1158 case Opcodes.F2D:
1159 pop(1);
1160 push(DOUBLE);
1161 push(TOP);
1162 break;
1163 case Opcodes.F2I:
1164 case Opcodes.ARRAYLENGTH:
1165 case Opcodes.INSTANCEOF:
1166 pop(1);
1167 push(INTEGER);
1168 break;
1169 case Opcodes.LCMP:
1170 case Opcodes.DCMPL:
1171 case Opcodes.DCMPG:
1172 pop(4);
1173 push(INTEGER);
1174 break;
1175 case Opcodes.JSR:
1176 case Opcodes.RET:
1177 throw new RuntimeException(
1178 "JSR/RET are not supported with computeFrames option");
1179 case Opcodes.GETSTATIC:
1180 push(cw, item.strVal3);
1181 break;
1182 case Opcodes.PUTSTATIC:
1183 pop(item.strVal3);
1184 break;
1185 case Opcodes.GETFIELD:
1186 pop(1);
1187 push(cw, item.strVal3);
1188 break;
1189 case Opcodes.PUTFIELD:
1190 pop(item.strVal3);
1191 pop();
1192 break;
1193 case Opcodes.INVOKEVIRTUAL:
1194 case Opcodes.INVOKESPECIAL:
1195 case Opcodes.INVOKESTATIC:
1196 case Opcodes.INVOKEINTERFACE:
1197 pop(item.strVal3);
1198 if (opcode != Opcodes.INVOKESTATIC) {
1199 t1 = pop();
1200 if (opcode == Opcodes.INVOKESPECIAL
1201 && item.strVal2.charAt(0) == '<') {
1202 init(t1);
1203 }
1204 }
1205 push(cw, item.strVal3);
1206 break;
1207 case Opcodes.INVOKEDYNAMIC:
1208 pop(item.strVal2);
1209 push(cw, item.strVal2);
1210 break;
1211 case Opcodes.NEW:
1212 push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg));
1213 break;
1214 case Opcodes.NEWARRAY:
1215 pop();
1216 switch (arg) {
1217 case Opcodes.T_BOOLEAN:
1218 push(ARRAY_OF | BOOLEAN);
1219 break;
1220 case Opcodes.T_CHAR:
1221 push(ARRAY_OF | CHAR);
1222 break;
1223 case Opcodes.T_BYTE:
1224 push(ARRAY_OF | BYTE);
1225 break;
1226 case Opcodes.T_SHORT:
1227 push(ARRAY_OF | SHORT);
1228 break;
1229 case Opcodes.T_INT:
1230 push(ARRAY_OF | INTEGER);
1231 break;
1232 case Opcodes.T_FLOAT:
1233 push(ARRAY_OF | FLOAT);
1234 break;
1235 case Opcodes.T_DOUBLE:
1236 push(ARRAY_OF | DOUBLE);
1237 break;
1238 // case Opcodes.T_LONG:
1239 default:
1240 push(ARRAY_OF | LONG);
1241 break;
1242 }
1243 break;
1244 case Opcodes.ANEWARRAY:
1245 String s = item.strVal1;
1246 pop();
1247 if (s.charAt(0) == '[') {
1248 push(cw, '[' + s);
1249 } else {
1250 push(ARRAY_OF | OBJECT | cw.addType(s));
1251 }
1252 break;
1253 case Opcodes.CHECKCAST:
1254 s = item.strVal1;
1255 pop();
1256 if (s.charAt(0) == '[') {
1257 push(cw, s);
1258 } else {
1259 push(OBJECT | cw.addType(s));
1260 }
1261 break;
1262 // case Opcodes.MULTIANEWARRAY:
1263 default:
1264 pop(arg);
1265 push(cw, item.strVal1);
1266 break;
1267 }
1268 }
1269
1270 /**
1271 * Merges the input frame of the given basic block with the input and output
1272 * frames of this basic block. Returns <tt>true</tt> if the input frame of
1273 * the given label has been changed by this operation.
1274 *
1275 * @param cw
1276 * the ClassWriter to which this label belongs.
1277 * @param frame
1278 * the basic block whose input frame must be updated.
1279 * @param edge
1280 * the kind of the {@link Edge} between this label and 'label'.
1281 * See {@link Edge#info}.
1282 * @return <tt>true</tt> if the input frame of the given label has been
1283 * changed by this operation.
1284 */
1285 boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
1286 boolean changed = false;
1287 int i, s, dim, kind, t;
1288
1289 int nLocal = inputLocals.length;
1290 int nStack = inputStack.length;
1291 if (frame.inputLocals == null) {
1292 frame.inputLocals = new int[nLocal];
1293 changed = true;
1294 }
1295
1296 for (i = 0; i < nLocal; ++i) {
1297 if (outputLocals != null && i < outputLocals.length) {
1298 s = outputLocals[i];
1299 if (s == 0) {
1300 t = inputLocals[i];
1301 } else {
1302 dim = s & DIM;
1303 kind = s & KIND;
1304 if (kind == BASE) {
1305 t = s;
1306 } else {
1307 if (kind == LOCAL) {
1308 t = dim + inputLocals[s & VALUE];
1309 } else {
1310 t = dim + inputStack[nStack - (s & VALUE)];
1311 }
1312 if ((s & TOP_IF_LONG_OR_DOUBLE) != 0
1313 && (t == LONG || t == DOUBLE)) {
1314 t = TOP;
1315 }
1316 }
1317 }
1318 } else {
1319 t = inputLocals[i];
1320 }
1321 if (initializations != null) {
1322 t = init(cw, t);
1323 }
1324 changed |= merge(cw, t, frame.inputLocals, i);
1325 }
1326
1327 if (edge > 0) {
1328 for (i = 0; i < nLocal; ++i) {
1329 t = inputLocals[i];
1330 changed |= merge(cw, t, frame.inputLocals, i);
1331 }
1332 if (frame.inputStack == null) {
1333 frame.inputStack = new int[1];
1334 changed = true;
1335 }
1336 changed |= merge(cw, edge, frame.inputStack, 0);
1337 return changed;
1338 }
1339
1340 int nInputStack = inputStack.length + owner.inputStackTop;
1341 if (frame.inputStack == null) {
1342 frame.inputStack = new int[nInputStack + outputStackTop];
1343 changed = true;
1344 }
1345
1346 for (i = 0; i < nInputStack; ++i) {
1347 t = inputStack[i];
1348 if (initializations != null) {
1349 t = init(cw, t);
1350 }
1351 changed |= merge(cw, t, frame.inputStack, i);
1352 }
1353 for (i = 0; i < outputStackTop; ++i) {
1354 s = outputStack[i];
1355 dim = s & DIM;
1356 kind = s & KIND;
1357 if (kind == BASE) {
1358 t = s;
1359 } else {
1360 if (kind == LOCAL) {
1361 t = dim + inputLocals[s & VALUE];
1362 } else {
1363 t = dim + inputStack[nStack - (s & VALUE)];
1364 }
1365 if ((s & TOP_IF_LONG_OR_DOUBLE) != 0
1366 && (t == LONG || t == DOUBLE)) {
1367 t = TOP;
1368 }
1369 }
1370 if (initializations != null) {
1371 t = init(cw, t);
1372 }
1373 changed |= merge(cw, t, frame.inputStack, nInputStack + i);
1374 }
1375 return changed;
1376 }
1377
1378 /**
1379 * Merges the type at the given index in the given type array with the given
1380 * type. Returns <tt>true</tt> if the type array has been modified by this
1381 * operation.
1382 *
1383 * @param cw
1384 * the ClassWriter to which this label belongs.
1385 * @param t
1386 * the type with which the type array element must be merged.
1387 * @param types
1388 * an array of types.
1389 * @param index
1390 * the index of the type that must be merged in 'types'.
1391 * @return <tt>true</tt> if the type array has been modified by this
1392 * operation.
1393 */
1394 private static boolean merge(final ClassWriter cw, int t,
1395 final int[] types, final int index) {
1396 int u = types[index];
1397 if (u == t) {
1398 // if the types are equal, merge(u,t)=u, so there is no change
1399 return false;
1400 }
1401 if ((t & ~DIM) == NULL) {
1402 if (u == NULL) {
1403 return false;
1404 }
1405 t = NULL;
1406 }
1407 if (u == 0) {
1408 // if types[index] has never been assigned, merge(u,t)=t
1409 types[index] = t;
1410 return true;
1411 }
1412 int v;
1413 if ((u & BASE_KIND) == OBJECT || (u & DIM) != 0) {
1414 // if u is a reference type of any dimension
1415 if (t == NULL) {
1416 // if t is the NULL type, merge(u,t)=u, so there is no change
1417 return false;
1418 } else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) {
1419 if ((u & BASE_KIND) == OBJECT) {
1420 // if t is also a reference type, and if u and t have the
1421 // same dimension merge(u,t) = dim(t) | common parent of the
1422 // element types of u and t
1423 v = (t & DIM) | OBJECT
1424 | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE);
1425 } else {
1426 // if u and t are array types, but not with the same element
1427 // type, merge(u,t)=java/lang/Object
1428 v = OBJECT | cw.addType("java/lang/Object");
1429 }
1430 } else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) {
1431 // if t is any other reference or array type,
1432 // merge(u,t)=java/lang/Object
1433 v = OBJECT | cw.addType("java/lang/Object");
1434 } else {
1435 // if t is any other type, merge(u,t)=TOP
1436 v = TOP;
1437 }
1438 } else if (u == NULL) {
1439 // if u is the NULL type, merge(u,t)=t,
1440 // or TOP if t is not a reference type
1441 v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP;
1442 } else {
1443 // if u is any other type, merge(u,t)=TOP whatever t
1444 v = TOP;
1445 }
1446 if (u != v) {
1447 types[index] = v;
1448 return true;
1449 }
1450 return false;
1451 }
1452 }
+0
-167
src/jvm/clojure/asm/Handle.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 package clojure.asm;
31
32 /**
33 * A reference to a field or a method.
34 *
35 * @author Remi Forax
36 * @author Eric Bruneton
37 */
38 public final class Handle {
39
40 /**
41 * The kind of field or method designated by this Handle. Should be
42 * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
43 * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
44 * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
45 * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
46 * {@link Opcodes#H_INVOKEINTERFACE}.
47 */
48 final int tag;
49
50 /**
51 * The internal name of the field or method designed by this handle.
52 */
53 final String owner;
54
55 /**
56 * The name of the field or method designated by this handle.
57 */
58 final String name;
59
60 /**
61 * The descriptor of the field or method designated by this handle.
62 */
63 final String desc;
64
65 /**
66 * Constructs a new field or method handle.
67 *
68 * @param tag
69 * the kind of field or method designated by this Handle. Must be
70 * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
71 * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
72 * {@link Opcodes#H_INVOKEVIRTUAL},
73 * {@link Opcodes#H_INVOKESTATIC},
74 * {@link Opcodes#H_INVOKESPECIAL},
75 * {@link Opcodes#H_NEWINVOKESPECIAL} or
76 * {@link Opcodes#H_INVOKEINTERFACE}.
77 * @param owner
78 * the internal name of the field or method designed by this
79 * handle.
80 * @param name
81 * the name of the field or method designated by this handle.
82 * @param desc
83 * the descriptor of the field or method designated by this
84 * handle.
85 */
86 public Handle(int tag, String owner, String name, String desc) {
87 this.tag = tag;
88 this.owner = owner;
89 this.name = name;
90 this.desc = desc;
91 }
92
93 /**
94 * Returns the kind of field or method designated by this handle.
95 *
96 * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
97 * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
98 * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
99 * {@link Opcodes#H_INVOKESPECIAL},
100 * {@link Opcodes#H_NEWINVOKESPECIAL} or
101 * {@link Opcodes#H_INVOKEINTERFACE}.
102 */
103 public int getTag() {
104 return tag;
105 }
106
107 /**
108 * Returns the internal name of the field or method designed by this handle.
109 *
110 * @return the internal name of the field or method designed by this handle.
111 */
112 public String getOwner() {
113 return owner;
114 }
115
116 /**
117 * Returns the name of the field or method designated by this handle.
118 *
119 * @return the name of the field or method designated by this handle.
120 */
121 public String getName() {
122 return name;
123 }
124
125 /**
126 * Returns the descriptor of the field or method designated by this handle.
127 *
128 * @return the descriptor of the field or method designated by this handle.
129 */
130 public String getDesc() {
131 return desc;
132 }
133
134 @Override
135 public boolean equals(Object obj) {
136 if (obj == this) {
137 return true;
138 }
139 if (!(obj instanceof Handle)) {
140 return false;
141 }
142 Handle h = (Handle) obj;
143 return tag == h.tag && owner.equals(h.owner) && name.equals(h.name)
144 && desc.equals(h.desc);
145 }
146
147 @Override
148 public int hashCode() {
149 return tag + owner.hashCode() * name.hashCode() * desc.hashCode();
150 }
151
152 /**
153 * Returns the textual representation of this handle. The textual
154 * representation is:
155 *
156 * <pre>
157 * owner '.' name desc ' ' '(' tag ')'
158 * </pre>
159 *
160 * . As this format is unambiguous, it can be parsed if necessary.
161 */
162 @Override
163 public String toString() {
164 return owner + '.' + name + desc + " (" + tag + ')';
165 }
166 }
+0
-121
src/jvm/clojure/asm/Handler.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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
70 /**
71 * Removes the range between start and end from the given exception
72 * handlers.
73 *
74 * @param h
75 * an exception handler list.
76 * @param start
77 * the start of the range to be removed.
78 * @param end
79 * the end of the range to be removed. Maybe null.
80 * @return the exception handler list with the start-end range removed.
81 */
82 static Handler remove(Handler h, Label start, Label end) {
83 if (h == null) {
84 return null;
85 } else {
86 h.next = remove(h.next, start, end);
87 }
88 int hstart = h.start.position;
89 int hend = h.end.position;
90 int s = start.position;
91 int e = end == null ? Integer.MAX_VALUE : end.position;
92 // if [hstart,hend[ and [s,e[ intervals intersect...
93 if (s < hend && e > hstart) {
94 if (s <= hstart) {
95 if (e >= hend) {
96 // [hstart,hend[ fully included in [s,e[, h removed
97 h = h.next;
98 } else {
99 // [hstart,hend[ minus [s,e[ = [e,hend[
100 h.start = end;
101 }
102 } else if (e >= hend) {
103 // [hstart,hend[ minus [s,e[ = [hstart,s[
104 h.end = start;
105 } else {
106 // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
107 Handler g = new Handler();
108 g.start = end;
109 g.end = h.end;
110 g.handler = h.handler;
111 g.desc = h.desc;
112 g.type = h.type;
113 g.next = h.next;
114 h.end = start;
115 h.next = g;
116 }
117 }
118 return h;
119 }
120 }
+0
-311
src/jvm/clojure/asm/Item.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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 * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
54 *
55 * MethodHandle constant 9 variations are stored using a range of 9 values
56 * from {@link ClassWriter#HANDLE_BASE} + 1 to
57 * {@link ClassWriter#HANDLE_BASE} + 9.
58 *
59 * Special Item types are used for Items that are stored in the ClassWriter
60 * {@link ClassWriter#typeTable}, instead of the constant pool, in order to
61 * avoid clashes with normal constant pool items in the ClassWriter constant
62 * pool's hash table. These special item types are
63 * {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and
64 * {@link ClassWriter#TYPE_MERGED}.
65 */
66 int type;
67
68 /**
69 * Value of this item, for an integer item.
70 */
71 int intVal;
72
73 /**
74 * Value of this item, for a long item.
75 */
76 long longVal;
77
78 /**
79 * First part of the value of this item, for items that do not hold a
80 * primitive value.
81 */
82 String strVal1;
83
84 /**
85 * Second part of the value of this item, for items that do not hold a
86 * primitive value.
87 */
88 String strVal2;
89
90 /**
91 * Third part of the value of this item, for items that do not hold a
92 * primitive value.
93 */
94 String strVal3;
95
96 /**
97 * The hash code value of this constant pool item.
98 */
99 int hashCode;
100
101 /**
102 * Link to another constant pool item, used for collision lists in the
103 * constant pool's hash table.
104 */
105 Item next;
106
107 /**
108 * Constructs an uninitialized {@link Item}.
109 */
110 Item() {
111 }
112
113 /**
114 * Constructs an uninitialized {@link Item} for constant pool element at
115 * given position.
116 *
117 * @param index
118 * index of the item to be constructed.
119 */
120 Item(final int index) {
121 this.index = index;
122 }
123
124 /**
125 * Constructs a copy of the given item.
126 *
127 * @param index
128 * index of the item to be constructed.
129 * @param i
130 * the item that must be copied into the item to be constructed.
131 */
132 Item(final int index, final Item i) {
133 this.index = index;
134 type = i.type;
135 intVal = i.intVal;
136 longVal = i.longVal;
137 strVal1 = i.strVal1;
138 strVal2 = i.strVal2;
139 strVal3 = i.strVal3;
140 hashCode = i.hashCode;
141 }
142
143 /**
144 * Sets this item to an integer item.
145 *
146 * @param intVal
147 * the value of this item.
148 */
149 void set(final int intVal) {
150 this.type = ClassWriter.INT;
151 this.intVal = intVal;
152 this.hashCode = 0x7FFFFFFF & (type + intVal);
153 }
154
155 /**
156 * Sets this item to a long item.
157 *
158 * @param longVal
159 * the value of this item.
160 */
161 void set(final long longVal) {
162 this.type = ClassWriter.LONG;
163 this.longVal = longVal;
164 this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
165 }
166
167 /**
168 * Sets this item to a float item.
169 *
170 * @param floatVal
171 * the value of this item.
172 */
173 void set(final float floatVal) {
174 this.type = ClassWriter.FLOAT;
175 this.intVal = Float.floatToRawIntBits(floatVal);
176 this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
177 }
178
179 /**
180 * Sets this item to a double item.
181 *
182 * @param doubleVal
183 * the value of this item.
184 */
185 void set(final double doubleVal) {
186 this.type = ClassWriter.DOUBLE;
187 this.longVal = Double.doubleToRawLongBits(doubleVal);
188 this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
189 }
190
191 /**
192 * Sets this item to an item that do not hold a primitive value.
193 *
194 * @param type
195 * the type of this item.
196 * @param strVal1
197 * first part of the value of this item.
198 * @param strVal2
199 * second part of the value of this item.
200 * @param strVal3
201 * third part of the value of this item.
202 */
203 void set(final int type, final String strVal1, final String strVal2,
204 final String strVal3) {
205 this.type = type;
206 this.strVal1 = strVal1;
207 this.strVal2 = strVal2;
208 this.strVal3 = strVal3;
209 switch (type) {
210 case ClassWriter.UTF8:
211 case ClassWriter.STR:
212 case ClassWriter.CLASS:
213 case ClassWriter.MTYPE:
214 case ClassWriter.TYPE_NORMAL:
215 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
216 return;
217 case ClassWriter.NAME_TYPE: {
218 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
219 * strVal2.hashCode());
220 return;
221 }
222 // ClassWriter.FIELD:
223 // ClassWriter.METH:
224 // ClassWriter.IMETH:
225 // ClassWriter.HANDLE_BASE + 1..9
226 default:
227 hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
228 * strVal2.hashCode() * strVal3.hashCode());
229 }
230 }
231
232 /**
233 * Sets the item to an InvokeDynamic item.
234 *
235 * @param name
236 * invokedynamic's name.
237 * @param desc
238 * invokedynamic's desc.
239 * @param bsmIndex
240 * zero based index into the class attribute BootrapMethods.
241 */
242 void set(String name, String desc, int bsmIndex) {
243 this.type = ClassWriter.INDY;
244 this.longVal = bsmIndex;
245 this.strVal1 = name;
246 this.strVal2 = desc;
247 this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex
248 * strVal1.hashCode() * strVal2.hashCode());
249 }
250
251 /**
252 * Sets the item to a BootstrapMethod item.
253 *
254 * @param position
255 * position in byte in the class attribute BootrapMethods.
256 * @param hashCode
257 * hashcode of the item. This hashcode is processed from the
258 * hashcode of the bootstrap method and the hashcode of all
259 * bootstrap arguments.
260 */
261 void set(int position, int hashCode) {
262 this.type = ClassWriter.BSM;
263 this.intVal = position;
264 this.hashCode = hashCode;
265 }
266
267 /**
268 * Indicates if the given item is equal to this one. <i>This method assumes
269 * that the two items have the same {@link #type}</i>.
270 *
271 * @param i
272 * the item to be compared to this one. Both items must have the
273 * same {@link #type}.
274 * @return <tt>true</tt> if the given item if equal to this one,
275 * <tt>false</tt> otherwise.
276 */
277 boolean isEqualTo(final Item i) {
278 switch (type) {
279 case ClassWriter.UTF8:
280 case ClassWriter.STR:
281 case ClassWriter.CLASS:
282 case ClassWriter.MTYPE:
283 case ClassWriter.TYPE_NORMAL:
284 return i.strVal1.equals(strVal1);
285 case ClassWriter.TYPE_MERGED:
286 case ClassWriter.LONG:
287 case ClassWriter.DOUBLE:
288 return i.longVal == longVal;
289 case ClassWriter.INT:
290 case ClassWriter.FLOAT:
291 return i.intVal == intVal;
292 case ClassWriter.TYPE_UNINIT:
293 return i.intVal == intVal && i.strVal1.equals(strVal1);
294 case ClassWriter.NAME_TYPE:
295 return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
296 case ClassWriter.INDY: {
297 return i.longVal == longVal && i.strVal1.equals(strVal1)
298 && i.strVal2.equals(strVal2);
299 }
300 // case ClassWriter.FIELD:
301 // case ClassWriter.METH:
302 // case ClassWriter.IMETH:
303 // case ClassWriter.HANDLE_BASE + 1..9
304 default:
305 return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2)
306 && i.strVal3.equals(strVal3);
307 }
308 }
309
310 }
+0
-560
src/jvm/clojure/asm/Label.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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. A label
34 * designates the <i>instruction</i> that is just after. Note however that there
35 * can be other elements between a label and the instruction it designates (such
36 * as other labels, stack map frames, line numbers, etc.).
37 *
38 * @author Eric Bruneton
39 */
40 public class Label {
41
42 /**
43 * Indicates if this label is only used for debug attributes. Such a label
44 * is not the start of a basic block, the target of a jump instruction, or
45 * an exception handler. It can be safely ignored in control flow graph
46 * analysis algorithms (for optimization purposes).
47 */
48 static final int DEBUG = 1;
49
50 /**
51 * Indicates if the position of this label is known.
52 */
53 static final int RESOLVED = 2;
54
55 /**
56 * Indicates if this label has been updated, after instruction resizing.
57 */
58 static final int RESIZED = 4;
59
60 /**
61 * Indicates if this basic block has been pushed in the basic block stack.
62 * See {@link MethodWriter#visitMaxs visitMaxs}.
63 */
64 static final int PUSHED = 8;
65
66 /**
67 * Indicates if this label is the target of a jump instruction, or the start
68 * of an exception handler.
69 */
70 static final int TARGET = 16;
71
72 /**
73 * Indicates if a stack map frame must be stored for this label.
74 */
75 static final int STORE = 32;
76
77 /**
78 * Indicates if this label corresponds to a reachable basic block.
79 */
80 static final int REACHABLE = 64;
81
82 /**
83 * Indicates if this basic block ends with a JSR instruction.
84 */
85 static final int JSR = 128;
86
87 /**
88 * Indicates if this basic block ends with a RET instruction.
89 */
90 static final int RET = 256;
91
92 /**
93 * Indicates if this basic block is the start of a subroutine.
94 */
95 static final int SUBROUTINE = 512;
96
97 /**
98 * Indicates if this subroutine basic block has been visited by a
99 * visitSubroutine(null, ...) call.
100 */
101 static final int VISITED = 1024;
102
103 /**
104 * Indicates if this subroutine basic block has been visited by a
105 * visitSubroutine(!null, ...) call.
106 */
107 static final int VISITED2 = 2048;
108
109 /**
110 * Field used to associate user information to a label. Warning: this field
111 * is used by the ASM tree package. In order to use it with the ASM tree
112 * package you must override the
113 * {@link clojure.asm.tree.MethodNode#getLabelNode} method.
114 */
115 public Object info;
116
117 /**
118 * Flags that indicate the status of this label.
119 *
120 * @see #DEBUG
121 * @see #RESOLVED
122 * @see #RESIZED
123 * @see #PUSHED
124 * @see #TARGET
125 * @see #STORE
126 * @see #REACHABLE
127 * @see #JSR
128 * @see #RET
129 */
130 int status;
131
132 /**
133 * The line number corresponding to this label, if known.
134 */
135 int line;
136
137 /**
138 * The position of this label in the code, if known.
139 */
140 int position;
141
142 /**
143 * Number of forward references to this label, times two.
144 */
145 private int referenceCount;
146
147 /**
148 * Informations about forward references. Each forward reference is
149 * described by two consecutive integers in this array: the first one is the
150 * position of the first byte of the bytecode instruction that contains the
151 * forward reference, while the second is the position of the first byte of
152 * the forward reference itself. In fact the sign of the first integer
153 * indicates if this reference uses 2 or 4 bytes, and its absolute value
154 * gives the position of the bytecode instruction. This array is also used
155 * as a bitset to store the subroutines to which a basic block belongs. This
156 * information is needed in {@linked MethodWriter#visitMaxs}, after all
157 * forward references have been resolved. Hence the same array can be used
158 * for both purposes without problems.
159 */
160 private int[] srcAndRefPositions;
161
162 // ------------------------------------------------------------------------
163
164 /*
165 * Fields for the control flow and data flow graph analysis algorithms (used
166 * to compute the maximum stack size or the stack map frames). A control
167 * flow graph contains one node per "basic block", and one edge per "jump"
168 * from one basic block to another. Each node (i.e., each basic block) is
169 * represented by the Label object that corresponds to the first instruction
170 * of this basic block. Each node also stores the list of its successors in
171 * the graph, as a linked list of Edge objects.
172 *
173 * The control flow analysis algorithms used to compute the maximum stack
174 * size or the stack map frames are similar and use two steps. The first
175 * step, during the visit of each instruction, builds information about the
176 * state of the local variables and the operand stack at the end of each
177 * basic block, called the "output frame", <i>relatively</i> to the frame
178 * state at the beginning of the basic block, which is called the "input
179 * frame", and which is <i>unknown</i> during this step. The second step, in
180 * {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
181 * information about the input frame of each basic block, from the input
182 * state of the first basic block (known from the method signature), and by
183 * the using the previously computed relative output frames.
184 *
185 * The algorithm used to compute the maximum stack size only computes the
186 * relative output and absolute input stack heights, while the algorithm
187 * used to compute stack map frames computes relative output frames and
188 * absolute input frames.
189 */
190
191 /**
192 * Start of the output stack relatively to the input stack. The exact
193 * semantics of this field depends on the algorithm that is used.
194 *
195 * When only the maximum stack size is computed, this field is the number of
196 * elements in the input stack.
197 *
198 * When the stack map frames are completely computed, this field is the
199 * offset of the first output stack element relatively to the top of the
200 * input stack. This offset is always negative or null. A null offset means
201 * that the output stack must be appended to the input stack. A -n offset
202 * means that the first n output stack elements must replace the top n input
203 * stack elements, and that the other elements must be appended to the input
204 * stack.
205 */
206 int inputStackTop;
207
208 /**
209 * Maximum height reached by the output stack, relatively to the top of the
210 * input stack. This maximum is always positive or null.
211 */
212 int outputStackMax;
213
214 /**
215 * Information about the input and output stack map frames of this basic
216 * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES}
217 * option is used.
218 */
219 Frame frame;
220
221 /**
222 * The successor of this label, in the order they are visited. This linked
223 * list does not include labels used for debug info only. If
224 * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it
225 * does not contain successive labels that denote the same bytecode position
226 * (in this case only the first label appears in this list).
227 */
228 Label successor;
229
230 /**
231 * The successors of this node in the control flow graph. These successors
232 * are stored in a linked list of {@link Edge Edge} objects, linked to each
233 * other by their {@link Edge#next} field.
234 */
235 Edge successors;
236
237 /**
238 * The next basic block in the basic block stack. This stack is used in the
239 * main loop of the fix point algorithm used in the second step of the
240 * control flow analysis algorithms. It is also used in
241 * {@link #visitSubroutine} to avoid using a recursive method.
242 *
243 * @see MethodWriter#visitMaxs
244 */
245 Label next;
246
247 // ------------------------------------------------------------------------
248 // Constructor
249 // ------------------------------------------------------------------------
250
251 /**
252 * Constructs a new label.
253 */
254 public Label() {
255 }
256
257 // ------------------------------------------------------------------------
258 // Methods to compute offsets and to manage forward references
259 // ------------------------------------------------------------------------
260
261 /**
262 * Returns the offset corresponding to this label. This offset is computed
263 * from the start of the method's bytecode. <i>This method is intended for
264 * {@link Attribute} sub classes, and is normally not needed by class
265 * generators or adapters.</i>
266 *
267 * @return the offset corresponding to this label.
268 * @throws IllegalStateException
269 * if this label is not resolved yet.
270 */
271 public int getOffset() {
272 if ((status & RESOLVED) == 0) {
273 throw new IllegalStateException(
274 "Label offset position has not been resolved yet");
275 }
276 return position;
277 }
278
279 /**
280 * Puts a reference to this label in the bytecode of a method. If the
281 * position of the label is known, the offset is computed and written
282 * directly. Otherwise, a null offset is written and a new forward reference
283 * is declared for this label.
284 *
285 * @param owner
286 * the code writer that calls this method.
287 * @param out
288 * the bytecode of the method.
289 * @param source
290 * the position of first byte of the bytecode instruction that
291 * contains this label.
292 * @param wideOffset
293 * <tt>true</tt> if the reference must be stored in 4 bytes, or
294 * <tt>false</tt> if it must be stored with 2 bytes.
295 * @throws IllegalArgumentException
296 * if this label has not been created by the given code writer.
297 */
298 void put(final MethodWriter owner, final ByteVector out, final int source,
299 final boolean wideOffset) {
300 if ((status & RESOLVED) == 0) {
301 if (wideOffset) {
302 addReference(-1 - source, out.length);
303 out.putInt(-1);
304 } else {
305 addReference(source, out.length);
306 out.putShort(-1);
307 }
308 } else {
309 if (wideOffset) {
310 out.putInt(position - source);
311 } else {
312 out.putShort(position - source);
313 }
314 }
315 }
316
317 /**
318 * Adds a forward reference to this label. This method must be called only
319 * for a true forward reference, i.e. only if this label is not resolved
320 * yet. For backward references, the offset of the reference can be, and
321 * must be, computed and stored directly.
322 *
323 * @param sourcePosition
324 * the position of the referencing instruction. This position
325 * will be used to compute the offset of this forward reference.
326 * @param referencePosition
327 * the position where the offset for this forward reference must
328 * be stored.
329 */
330 private void addReference(final int sourcePosition,
331 final int referencePosition) {
332 if (srcAndRefPositions == null) {
333 srcAndRefPositions = new int[6];
334 }
335 if (referenceCount >= srcAndRefPositions.length) {
336 int[] a = new int[srcAndRefPositions.length + 6];
337 System.arraycopy(srcAndRefPositions, 0, a, 0,
338 srcAndRefPositions.length);
339 srcAndRefPositions = a;
340 }
341 srcAndRefPositions[referenceCount++] = sourcePosition;
342 srcAndRefPositions[referenceCount++] = referencePosition;
343 }
344
345 /**
346 * Resolves all forward references to this label. This method must be called
347 * when this label is added to the bytecode of the method, i.e. when its
348 * position becomes known. This method fills in the blanks that where left
349 * in the bytecode by each forward reference previously added to this label.
350 *
351 * @param owner
352 * the code writer that calls this method.
353 * @param position
354 * the position of this label in the bytecode.
355 * @param data
356 * the bytecode of the method.
357 * @return <tt>true</tt> if a blank that was left for this label was to
358 * small to store the offset. In such a case the corresponding jump
359 * instruction is replaced with a pseudo instruction (using unused
360 * opcodes) using an unsigned two bytes offset. These pseudo
361 * instructions will need to be replaced with true instructions with
362 * wider offsets (4 bytes instead of 2). This is done in
363 * {@link MethodWriter#resizeInstructions}.
364 * @throws IllegalArgumentException
365 * if this label has already been resolved, or if it has not
366 * been created by the given code writer.
367 */
368 boolean resolve(final MethodWriter owner, final int position,
369 final byte[] data) {
370 boolean needUpdate = false;
371 this.status |= RESOLVED;
372 this.position = position;
373 int i = 0;
374 while (i < referenceCount) {
375 int source = srcAndRefPositions[i++];
376 int reference = srcAndRefPositions[i++];
377 int offset;
378 if (source >= 0) {
379 offset = position - source;
380 if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
381 /*
382 * changes the opcode of the jump instruction, in order to
383 * be able to find it later (see resizeInstructions in
384 * MethodWriter). These temporary opcodes are similar to
385 * jump instruction opcodes, except that the 2 bytes offset
386 * is unsigned (and can therefore represent values from 0 to
387 * 65535, which is sufficient since the size of a method is
388 * limited to 65535 bytes).
389 */
390 int opcode = data[reference - 1] & 0xFF;
391 if (opcode <= Opcodes.JSR) {
392 // changes IFEQ ... JSR to opcodes 202 to 217
393 data[reference - 1] = (byte) (opcode + 49);
394 } else {
395 // changes IFNULL and IFNONNULL to opcodes 218 and 219
396 data[reference - 1] = (byte) (opcode + 20);
397 }
398 needUpdate = true;
399 }
400 data[reference++] = (byte) (offset >>> 8);
401 data[reference] = (byte) offset;
402 } else {
403 offset = position + source + 1;
404 data[reference++] = (byte) (offset >>> 24);
405 data[reference++] = (byte) (offset >>> 16);
406 data[reference++] = (byte) (offset >>> 8);
407 data[reference] = (byte) offset;
408 }
409 }
410 return needUpdate;
411 }
412
413 /**
414 * Returns the first label of the series to which this label belongs. For an
415 * isolated label or for the first label in a series of successive labels,
416 * this method returns the label itself. For other labels it returns the
417 * first label of the series.
418 *
419 * @return the first label of the series to which this label belongs.
420 */
421 Label getFirst() {
422 return !ClassReader.FRAMES || frame == null ? this : frame.owner;
423 }
424
425 // ------------------------------------------------------------------------
426 // Methods related to subroutines
427 // ------------------------------------------------------------------------
428
429 /**
430 * Returns true is this basic block belongs to the given subroutine.
431 *
432 * @param id
433 * a subroutine id.
434 * @return true is this basic block belongs to the given subroutine.
435 */
436 boolean inSubroutine(final long id) {
437 if ((status & Label.VISITED) != 0) {
438 return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
439 }
440 return false;
441 }
442
443 /**
444 * Returns true if this basic block and the given one belong to a common
445 * subroutine.
446 *
447 * @param block
448 * another basic block.
449 * @return true if this basic block and the given one belong to a common
450 * subroutine.
451 */
452 boolean inSameSubroutine(final Label block) {
453 if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
454 return false;
455 }
456 for (int i = 0; i < srcAndRefPositions.length; ++i) {
457 if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
458 return true;
459 }
460 }
461 return false;
462 }
463
464 /**
465 * Marks this basic block as belonging to the given subroutine.
466 *
467 * @param id
468 * a subroutine id.
469 * @param nbSubroutines
470 * the total number of subroutines in the method.
471 */
472 void addToSubroutine(final long id, final int nbSubroutines) {
473 if ((status & VISITED) == 0) {
474 status |= VISITED;
475 srcAndRefPositions = new int[(nbSubroutines - 1) / 32 + 1];
476 }
477 srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
478 }
479
480 /**
481 * Finds the basic blocks that belong to a given subroutine, and marks these
482 * blocks as belonging to this subroutine. This method follows the control
483 * flow graph to find all the blocks that are reachable from the current
484 * block WITHOUT following any JSR target.
485 *
486 * @param JSR
487 * a JSR block that jumps to this subroutine. If this JSR is not
488 * null it is added to the successor of the RET blocks found in
489 * the subroutine.
490 * @param id
491 * the id of this subroutine.
492 * @param nbSubroutines
493 * the total number of subroutines in the method.
494 */
495 void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
496 // user managed stack of labels, to avoid using a recursive method
497 // (recursivity can lead to stack overflow with very large methods)
498 Label stack = this;
499 while (stack != null) {
500 // removes a label l from the stack
501 Label l = stack;
502 stack = l.next;
503 l.next = null;
504
505 if (JSR != null) {
506 if ((l.status & VISITED2) != 0) {
507 continue;
508 }
509 l.status |= VISITED2;
510 // adds JSR to the successors of l, if it is a RET block
511 if ((l.status & RET) != 0) {
512 if (!l.inSameSubroutine(JSR)) {
513 Edge e = new Edge();
514 e.info = l.inputStackTop;
515 e.successor = JSR.successors.successor;
516 e.next = l.successors;
517 l.successors = e;
518 }
519 }
520 } else {
521 // if the l block already belongs to subroutine 'id', continue
522 if (l.inSubroutine(id)) {
523 continue;
524 }
525 // marks the l block as belonging to subroutine 'id'
526 l.addToSubroutine(id, nbSubroutines);
527 }
528 // pushes each successor of l on the stack, except JSR targets
529 Edge e = l.successors;
530 while (e != null) {
531 // if the l block is a JSR block, then 'l.successors.next' leads
532 // to the JSR target (see {@link #visitJumpInsn}) and must
533 // therefore not be followed
534 if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
535 // pushes e.successor on the stack if it not already added
536 if (e.successor.next == null) {
537 e.successor.next = stack;
538 stack = e.successor;
539 }
540 }
541 e = e.next;
542 }
543 }
544 }
545
546 // ------------------------------------------------------------------------
547 // Overriden Object methods
548 // ------------------------------------------------------------------------
549
550 /**
551 * Returns a string representation of this label.
552 *
553 * @return a string representation of this label.
554 */
555 @Override
556 public String toString() {
557 return "L" + System.identityHashCode(this);
558 }
559 }
+0
-662
src/jvm/clojure/asm/MethodVisitor.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package clojure.asm;
30
31 /**
32 * A visitor to visit a Java method. The methods of this class must be called in
33 * 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> |
37 * <tt>visitTryCatchBlock</tt> | <tt>visitLocalVariable</tt> |
38 * <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In
39 * addition, the <tt>visit</tt><i>X</i>Insn</tt> and <tt>visitLabel</tt> methods
40 * must be called in the sequential order of the bytecode instructions of the
41 * visited code, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
42 * labels passed as arguments have been visited, and the
43 * <tt>visitLocalVariable</tt> and <tt>visitLineNumber</tt> methods must be
44 * called <i>after</i> the labels passed as arguments have been visited.
45 *
46 * @author Eric Bruneton
47 */
48 public abstract class MethodVisitor {
49
50 /**
51 * The ASM API version implemented by this visitor. The value of this field
52 * must be one of {@link Opcodes#ASM4}.
53 */
54 protected final int api;
55
56 /**
57 * The method visitor to which this visitor must delegate method calls. May
58 * be null.
59 */
60 protected MethodVisitor mv;
61
62 /**
63 * Constructs a new {@link MethodVisitor}.
64 *
65 * @param api
66 * the ASM API version implemented by this visitor. Must be one
67 * of {@link Opcodes#ASM4}.
68 */
69 public MethodVisitor(final int api) {
70 this(api, null);
71 }
72
73 /**
74 * Constructs a new {@link MethodVisitor}.
75 *
76 * @param api
77 * the ASM API version implemented by this visitor. Must be one
78 * of {@link Opcodes#ASM4}.
79 * @param mv
80 * the method visitor to which this visitor must delegate method
81 * calls. May be null.
82 */
83 public MethodVisitor(final int api, final MethodVisitor mv) {
84 if (api != Opcodes.ASM4) {
85 throw new IllegalArgumentException();
86 }
87 this.api = api;
88 this.mv = mv;
89 }
90
91 // -------------------------------------------------------------------------
92 // Annotations and non standard attributes
93 // -------------------------------------------------------------------------
94
95 /**
96 * Visits the default value of this annotation interface method.
97 *
98 * @return a visitor to the visit the actual default value of this
99 * annotation interface method, or <tt>null</tt> if this visitor is
100 * not interested in visiting this default value. The 'name'
101 * parameters passed to the methods of this annotation visitor are
102 * ignored. Moreover, exacly one visit method must be called on this
103 * annotation visitor, followed by visitEnd.
104 */
105 public AnnotationVisitor visitAnnotationDefault() {
106 if (mv != null) {
107 return mv.visitAnnotationDefault();
108 }
109 return null;
110 }
111
112 /**
113 * Visits an annotation of this method.
114 *
115 * @param desc
116 * the class descriptor of the annotation class.
117 * @param visible
118 * <tt>true</tt> if the annotation is visible at runtime.
119 * @return a visitor to visit the annotation values, or <tt>null</tt> if
120 * this visitor is not interested in visiting this annotation.
121 */
122 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
123 if (mv != null) {
124 return mv.visitAnnotation(desc, visible);
125 }
126 return null;
127 }
128
129 /**
130 * Visits an annotation of a parameter this method.
131 *
132 * @param parameter
133 * the parameter index.
134 * @param desc
135 * the class descriptor of the annotation class.
136 * @param visible
137 * <tt>true</tt> if the annotation is visible at runtime.
138 * @return a visitor to visit the annotation values, or <tt>null</tt> if
139 * this visitor is not interested in visiting this annotation.
140 */
141 public AnnotationVisitor visitParameterAnnotation(int parameter,
142 String desc, boolean visible) {
143 if (mv != null) {
144 return mv.visitParameterAnnotation(parameter, desc, visible);
145 }
146 return null;
147 }
148
149 /**
150 * Visits a non standard attribute of this method.
151 *
152 * @param attr
153 * an attribute.
154 */
155 public void visitAttribute(Attribute attr) {
156 if (mv != null) {
157 mv.visitAttribute(attr);
158 }
159 }
160
161 /**
162 * Starts the visit of the method's code, if any (i.e. non abstract method).
163 */
164 public void visitCode() {
165 if (mv != null) {
166 mv.visitCode();
167 }
168 }
169
170 /**
171 * Visits the current state of the local variables and operand stack
172 * elements. This method must(*) be called <i>just before</i> any
173 * instruction <b>i</b> that follows an unconditional branch instruction
174 * such as GOTO or THROW, that is the target of a jump instruction, or that
175 * starts an exception handler block. The visited types must describe the
176 * values of the local variables and of the operand stack elements <i>just
177 * before</i> <b>i</b> is executed.<br>
178 * <br>
179 * (*) this is mandatory only for classes whose version is greater than or
180 * equal to {@link Opcodes#V1_6 V1_6}. <br>
181 * <br>
182 * The frames of a method must be given either in expanded form, or in
183 * compressed form (all frames must use the same format, i.e. you must not
184 * mix expanded and compressed frames within a single method):
185 * <ul>
186 * <li>In expanded form, all frames must have the F_NEW type.</li>
187 * <li>In compressed form, frames are basically "deltas" from the state of
188 * the previous frame:
189 * <ul>
190 * <li>{@link Opcodes#F_SAME} representing frame with exactly the same
191 * locals as the previous frame and with the empty stack.</li>
192 * <li>{@link Opcodes#F_SAME1} representing frame with exactly the same
193 * locals as the previous frame and with single value on the stack (
194 * <code>nStack</code> is 1 and <code>stack[0]</code> contains value for the
195 * type of the stack item).</li>
196 * <li>{@link Opcodes#F_APPEND} representing frame with current locals are
197 * the same as the locals in the previous frame, except that additional
198 * locals are defined (<code>nLocal</code> is 1, 2 or 3 and
199 * <code>local</code> elements contains values representing added types).</li>
200 * <li>{@link Opcodes#F_CHOP} representing frame with current locals are the
201 * same as the locals in the previous frame, except that the last 1-3 locals
202 * are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li>
203 * <li>{@link Opcodes#F_FULL} representing complete frame data.</li></li>
204 * </ul>
205 * </ul> <br>
206 * In both cases the first frame, corresponding to the method's parameters
207 * and access flags, is implicit and must not be visited. Also, it is
208 * illegal to visit two or more frames for the same code location (i.e., at
209 * least one instruction must be visited between two calls to visitFrame).
210 *
211 * @param type
212 * the type of this stack map frame. Must be
213 * {@link Opcodes#F_NEW} for expanded frames, or
214 * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
215 * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
216 * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for
217 * compressed frames.
218 * @param nLocal
219 * the number of local variables in the visited frame.
220 * @param local
221 * the local variable types in this frame. This array must not be
222 * modified. Primitive types are represented by
223 * {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
224 * {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
225 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
226 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are
227 * represented by a single element). Reference types are
228 * represented by String objects (representing internal names),
229 * and uninitialized types by Label objects (this label
230 * designates the NEW instruction that created this uninitialized
231 * value).
232 * @param nStack
233 * the number of operand stack elements in the visited frame.
234 * @param stack
235 * the operand stack types in this frame. This array must not be
236 * modified. Its content has the same format as the "local"
237 * array.
238 * @throws IllegalStateException
239 * if a frame is visited just after another one, without any
240 * instruction between the two (unless this frame is a
241 * Opcodes#F_SAME frame, in which case it is silently ignored).
242 */
243 public void visitFrame(int type, int nLocal, Object[] local, int nStack,
244 Object[] stack) {
245 if (mv != null) {
246 mv.visitFrame(type, nLocal, local, nStack, stack);
247 }
248 }
249
250 // -------------------------------------------------------------------------
251 // Normal instructions
252 // -------------------------------------------------------------------------
253
254 /**
255 * Visits a zero operand instruction.
256 *
257 * @param opcode
258 * the opcode of the instruction to be visited. This opcode is
259 * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
260 * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1,
261 * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD,
262 * LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
263 * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
264 * SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1,
265 * DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB,
266 * IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM,
267 * FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR,
268 * IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
269 * L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
270 * LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
271 * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
272 * or MONITOREXIT.
273 */
274 public void visitInsn(int opcode) {
275 if (mv != null) {
276 mv.visitInsn(opcode);
277 }
278 }
279
280 /**
281 * Visits an instruction with a single int operand.
282 *
283 * @param opcode
284 * the opcode of the instruction to be visited. This opcode is
285 * either BIPUSH, SIPUSH or NEWARRAY.
286 * @param operand
287 * the operand of the instruction to be visited.<br>
288 * When opcode is BIPUSH, operand value should be between
289 * Byte.MIN_VALUE and Byte.MAX_VALUE.<br>
290 * When opcode is SIPUSH, operand value should be between
291 * Short.MIN_VALUE and Short.MAX_VALUE.<br>
292 * When opcode is NEWARRAY, operand value should be one of
293 * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
294 * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE},
295 * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
296 * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
297 */
298 public void visitIntInsn(int opcode, int operand) {
299 if (mv != null) {
300 mv.visitIntInsn(opcode, operand);
301 }
302 }
303
304 /**
305 * Visits a local variable instruction. A local variable instruction is an
306 * instruction that loads or stores the value of a local variable.
307 *
308 * @param opcode
309 * the opcode of the local variable instruction to be visited.
310 * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD,
311 * ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
312 * @param var
313 * the operand of the instruction to be visited. This operand is
314 * the index of a local variable.
315 */
316 public void visitVarInsn(int opcode, int var) {
317 if (mv != null) {
318 mv.visitVarInsn(opcode, var);
319 }
320 }
321
322 /**
323 * Visits a type instruction. A type instruction is an instruction that
324 * takes the internal name of a class as parameter.
325 *
326 * @param opcode
327 * the opcode of the type instruction to be visited. This opcode
328 * is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
329 * @param type
330 * the operand of the instruction to be visited. This operand
331 * must be the internal name of an object or array class (see
332 * {@link Type#getInternalName() getInternalName}).
333 */
334 public void visitTypeInsn(int opcode, String type) {
335 if (mv != null) {
336 mv.visitTypeInsn(opcode, type);
337 }
338 }
339
340 /**
341 * Visits a field instruction. A field instruction is an instruction that
342 * loads or stores the value of a field of an object.
343 *
344 * @param opcode
345 * the opcode of the type instruction to be visited. This opcode
346 * is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
347 * @param owner
348 * the internal name of the field's owner class (see
349 * {@link Type#getInternalName() getInternalName}).
350 * @param name
351 * the field's name.
352 * @param desc
353 * the field's descriptor (see {@link Type Type}).
354 */
355 public void visitFieldInsn(int opcode, String owner, String name,
356 String desc) {
357 if (mv != null) {
358 mv.visitFieldInsn(opcode, owner, name, desc);
359 }
360 }
361
362 /**
363 * Visits a method instruction. A method instruction is an instruction that
364 * invokes a method.
365 *
366 * @param opcode
367 * the opcode of the type instruction to be visited. This opcode
368 * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
369 * INVOKEINTERFACE.
370 * @param owner
371 * the internal name of the method's owner class (see
372 * {@link Type#getInternalName() getInternalName}).
373 * @param name
374 * the method's name.
375 * @param desc
376 * the method's descriptor (see {@link Type Type}).
377 */
378 public void visitMethodInsn(int opcode, String owner, String name,
379 String desc) {
380 if (mv != null) {
381 mv.visitMethodInsn(opcode, owner, name, desc);
382 }
383 }
384
385 /**
386 * Visits an invokedynamic instruction.
387 *
388 * @param name
389 * the method's name.
390 * @param desc
391 * the method's descriptor (see {@link Type Type}).
392 * @param bsm
393 * the bootstrap method.
394 * @param bsmArgs
395 * the bootstrap method constant arguments. Each argument must be
396 * an {@link Integer}, {@link Float}, {@link Long},
397 * {@link Double}, {@link String}, {@link Type} or {@link Handle}
398 * value. This method is allowed to modify the content of the
399 * array so a caller should expect that this array may change.
400 */
401 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
402 Object... bsmArgs) {
403 if (mv != null) {
404 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
405 }
406 }
407
408 /**
409 * Visits a jump instruction. A jump instruction is an instruction that may
410 * jump to another instruction.
411 *
412 * @param opcode
413 * the opcode of the type instruction to be visited. This opcode
414 * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
415 * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
416 * IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
417 * @param label
418 * the operand of the instruction to be visited. This operand is
419 * a label that designates the instruction to which the jump
420 * instruction may jump.
421 */
422 public void visitJumpInsn(int opcode, Label label) {
423 if (mv != null) {
424 mv.visitJumpInsn(opcode, label);
425 }
426 }
427
428 /**
429 * Visits a label. A label designates the instruction that will be visited
430 * just after it.
431 *
432 * @param label
433 * a {@link Label Label} object.
434 */
435 public void visitLabel(Label label) {
436 if (mv != null) {
437 mv.visitLabel(label);
438 }
439 }
440
441 // -------------------------------------------------------------------------
442 // Special instructions
443 // -------------------------------------------------------------------------
444
445 /**
446 * Visits a LDC instruction. Note that new constant types may be added in
447 * future versions of the Java Virtual Machine. To easily detect new
448 * constant types, implementations of this method should check for
449 * unexpected constant types, like this:
450 *
451 * <pre>
452 * if (cst instanceof Integer) {
453 * // ...
454 * } else if (cst instanceof Float) {
455 * // ...
456 * } else if (cst instanceof Long) {
457 * // ...
458 * } else if (cst instanceof Double) {
459 * // ...
460 * } else if (cst instanceof String) {
461 * // ...
462 * } else if (cst instanceof Type) {
463 * int sort = ((Type) cst).getSort();
464 * if (sort == Type.OBJECT) {
465 * // ...
466 * } else if (sort == Type.ARRAY) {
467 * // ...
468 * } else if (sort == Type.METHOD) {
469 * // ...
470 * } else {
471 * // throw an exception
472 * }
473 * } else if (cst instanceof Handle) {
474 * // ...
475 * } else {
476 * // throw an exception
477 * }
478 * </pre>
479 *
480 * @param cst
481 * the constant to be loaded on the stack. This parameter must be
482 * a non null {@link Integer}, a {@link Float}, a {@link Long}, a
483 * {@link Double}, a {@link String}, a {@link Type} of OBJECT or
484 * ARRAY sort for <tt>.class</tt> constants, for classes whose
485 * version is 49.0, a {@link Type} of METHOD sort or a
486 * {@link Handle} for MethodType and MethodHandle constants, for
487 * classes whose version is 51.0.
488 */
489 public void visitLdcInsn(Object cst) {
490 if (mv != null) {
491 mv.visitLdcInsn(cst);
492 }
493 }
494
495 /**
496 * Visits an IINC instruction.
497 *
498 * @param var
499 * index of the local variable to be incremented.
500 * @param increment
501 * amount to increment the local variable by.
502 */
503 public void visitIincInsn(int var, int increment) {
504 if (mv != null) {
505 mv.visitIincInsn(var, increment);
506 }
507 }
508
509 /**
510 * Visits a TABLESWITCH instruction.
511 *
512 * @param min
513 * the minimum key value.
514 * @param max
515 * the maximum key value.
516 * @param dflt
517 * beginning of the default handler block.
518 * @param labels
519 * beginnings of the handler blocks. <tt>labels[i]</tt> is the
520 * beginning of the handler block for the <tt>min + i</tt> key.
521 */
522 public void visitTableSwitchInsn(int min, int max, Label dflt,
523 Label... labels) {
524 if (mv != null) {
525 mv.visitTableSwitchInsn(min, max, dflt, labels);
526 }
527 }
528
529 /**
530 * Visits a LOOKUPSWITCH instruction.
531 *
532 * @param dflt
533 * beginning of the default handler block.
534 * @param keys
535 * the values of the keys.
536 * @param labels
537 * beginnings of the handler blocks. <tt>labels[i]</tt> is the
538 * beginning of the handler block for the <tt>keys[i]</tt> key.
539 */
540 public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
541 if (mv != null) {
542 mv.visitLookupSwitchInsn(dflt, keys, labels);
543 }
544 }
545
546 /**
547 * Visits a MULTIANEWARRAY instruction.
548 *
549 * @param desc
550 * an array type descriptor (see {@link Type Type}).
551 * @param dims
552 * number of dimensions of the array to allocate.
553 */
554 public void visitMultiANewArrayInsn(String desc, int dims) {
555 if (mv != null) {
556 mv.visitMultiANewArrayInsn(desc, dims);
557 }
558 }
559
560 // -------------------------------------------------------------------------
561 // Exceptions table entries, debug information, max stack and max locals
562 // -------------------------------------------------------------------------
563
564 /**
565 * Visits a try catch block.
566 *
567 * @param start
568 * beginning of the exception handler's scope (inclusive).
569 * @param end
570 * end of the exception handler's scope (exclusive).
571 * @param handler
572 * beginning of the exception handler's code.
573 * @param type
574 * internal name of the type of exceptions handled by the
575 * handler, or <tt>null</tt> to catch any exceptions (for
576 * "finally" blocks).
577 * @throws IllegalArgumentException
578 * if one of the labels has already been visited by this visitor
579 * (by the {@link #visitLabel visitLabel} method).
580 */
581 public void visitTryCatchBlock(Label start, Label end, Label handler,
582 String type) {
583 if (mv != null) {
584 mv.visitTryCatchBlock(start, end, handler, type);
585 }
586 }
587
588 /**
589 * Visits a local variable declaration.
590 *
591 * @param name
592 * the name of a local variable.
593 * @param desc
594 * the type descriptor of this local variable.
595 * @param signature
596 * the type signature of this local variable. May be
597 * <tt>null</tt> if the local variable type does not use generic
598 * types.
599 * @param start
600 * the first instruction corresponding to the scope of this local
601 * variable (inclusive).
602 * @param end
603 * the last instruction corresponding to the scope of this local
604 * variable (exclusive).
605 * @param index
606 * the local variable's index.
607 * @throws IllegalArgumentException
608 * if one of the labels has not already been visited by this
609 * visitor (by the {@link #visitLabel visitLabel} method).
610 */
611 public void visitLocalVariable(String name, String desc, String signature,
612 Label start, Label end, int index) {
613 if (mv != null) {
614 mv.visitLocalVariable(name, desc, signature, start, end, index);
615 }
616 }
617
618 /**
619 * Visits a line number declaration.
620 *
621 * @param line
622 * a line number. This number refers to the source file from
623 * which the class was compiled.
624 * @param start
625 * the first instruction corresponding to this line number.
626 * @throws IllegalArgumentException
627 * if <tt>start</tt> has not already been visited by this
628 * visitor (by the {@link #visitLabel visitLabel} method).
629 */
630 public void visitLineNumber(int line, Label start) {
631 if (mv != null) {
632 mv.visitLineNumber(line, start);
633 }
634 }
635
636 /**
637 * Visits the maximum stack size and the maximum number of local variables
638 * of the method.
639 *
640 * @param maxStack
641 * maximum stack size of the method.
642 * @param maxLocals
643 * maximum number of local variables for the method.
644 */
645 public void visitMaxs(int maxStack, int maxLocals) {
646 if (mv != null) {
647 mv.visitMaxs(maxStack, maxLocals);
648 }
649 }
650
651 /**
652 * Visits the end of the method. This method, which is the last one to be
653 * called, is used to inform the visitor that all the annotations and
654 * attributes of the method have been visited.
655 */
656 public void visitEnd() {
657 if (mv != null) {
658 mv.visitEnd();
659 }
660 }
661 }
+0
-2685
src/jvm/clojure/asm/MethodWriter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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 extends MethodVisitor {
40
41 /**
42 * Pseudo access flag used to denote constructors.
43 */
44 static final int ACC_CONSTRUCTOR = 0x80000;
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 static final 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 static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
57
58 /**
59 * Reserved for future use
60 */
61 static final 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 static final 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 static final 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 static final 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 static final int APPEND_FRAME = 252; // to 254 // fc-fe
88
89 /**
90 * Full frame
91 */
92 static final 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 static final 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 static final int MAXS = 1;
110
111 /**
112 * Indicates that nothing must be automatically computed.
113 *
114 * @see #compute
115 */
116 private static final int NOTHING = 2;
117
118 /**
119 * The class writer to which this method must be added.
120 */
121 final ClassWriter cw;
122
123 /**
124 * Access flags of this method.
125 */
126 private int access;
127
128 /**
129 * The index of the constant pool item that contains the name of this
130 * method.
131 */
132 private final int name;
133
134 /**
135 * The index of the constant pool item that contains the descriptor of this
136 * method.
137 */
138 private final int desc;
139
140 /**
141 * The descriptor of this method.
142 */
143 private final String descriptor;
144
145 /**
146 * The signature of this method.
147 */
148 String signature;
149
150 /**
151 * If not zero, indicates that the code of this method must be copied from
152 * the ClassReader associated to this writer in <code>cw.cr</code>. More
153 * precisely, this field gives the index of the first byte to copied from
154 * <code>cw.cr.b</code>.
155 */
156 int classReaderOffset;
157
158 /**
159 * If not zero, indicates that the code of this method must be copied from
160 * the ClassReader associated to this writer in <code>cw.cr</code>. More
161 * precisely, this field gives the number of bytes to copied from
162 * <code>cw.cr.b</code>.
163 */
164 int classReaderLength;
165
166 /**
167 * Number of exceptions that can be thrown by this method.
168 */
169 int exceptionCount;
170
171 /**
172 * The exceptions that can be thrown by this method. More precisely, this
173 * array contains the indexes of the constant pool items that contain the
174 * internal names of these exception classes.
175 */
176 int[] exceptions;
177
178 /**
179 * The annotation default attribute of this method. May be <tt>null</tt>.
180 */
181 private ByteVector annd;
182
183 /**
184 * The runtime visible annotations of this method. May be <tt>null</tt>.
185 */
186 private AnnotationWriter anns;
187
188 /**
189 * The runtime invisible annotations of this method. May be <tt>null</tt>.
190 */
191 private AnnotationWriter ianns;
192
193 /**
194 * The runtime visible parameter annotations of this method. May be
195 * <tt>null</tt>.
196 */
197 private AnnotationWriter[] panns;
198
199 /**
200 * The runtime invisible parameter annotations of this method. May be
201 * <tt>null</tt>.
202 */
203 private AnnotationWriter[] ipanns;
204
205 /**
206 * The number of synthetic parameters of this method.
207 */
208 private int synthetics;
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 local variables in the current stack map frame.
232 */
233 private int currentLocals;
234
235 /**
236 * Number of stack map frames in the StackMapTable attribute.
237 */
238 private int frameCount;
239
240 /**
241 * The StackMapTable attribute.
242 */
243 private ByteVector stackMap;
244
245 /**
246 * The offset of the last frame that was written in the StackMapTable
247 * attribute.
248 */
249 private int previousFrameOffset;
250
251 /**
252 * The last frame that was written in the StackMapTable attribute.
253 *
254 * @see #frame
255 */
256 private int[] previousFrame;
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 * The number of subroutines in this method.
326 */
327 private int subroutines;
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 final 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 MethodVisitor#visitLabel}, and starting with the first basic
355 * block.
356 */
357 private Label labels;
358
359 /**
360 * The previous basic block.
361 */
362 private Label previousBlock;
363
364 /**
365 * The current basic block.
366 */
367 private Label currentBlock;
368
369 /**
370 * The (relative) stack size after the last visited instruction. This size
371 * is relative to the beginning of the current basic block, i.e., the true
372 * stack size after the last visited instruction is equal to the
373 * {@link Label#inputStackTop beginStackSize} of the current basic block
374 * plus <tt>stackSize</tt>.
375 */
376 private int stackSize;
377
378 /**
379 * The (relative) maximum stack size after the last visited instruction.
380 * This size is relative to the beginning of the current basic block, i.e.,
381 * the true maximum stack size after the last visited instruction is equal
382 * to the {@link Label#inputStackTop beginStackSize} of the current basic
383 * block plus <tt>stackSize</tt>.
384 */
385 private int maxStackSize;
386
387 // ------------------------------------------------------------------------
388 // Constructor
389 // ------------------------------------------------------------------------
390
391 /**
392 * Constructs a new {@link MethodWriter}.
393 *
394 * @param cw
395 * the class writer in which the method must be added.
396 * @param access
397 * the method's access flags (see {@link Opcodes}).
398 * @param name
399 * the method's name.
400 * @param desc
401 * the method's descriptor (see {@link Type}).
402 * @param signature
403 * the method's signature. May be <tt>null</tt>.
404 * @param exceptions
405 * the internal names of the method's exceptions. May be
406 * <tt>null</tt>.
407 * @param computeMaxs
408 * <tt>true</tt> if the maximum stack size and number of local
409 * variables must be automatically computed.
410 * @param computeFrames
411 * <tt>true</tt> if the stack map tables must be recomputed from
412 * scratch.
413 */
414 MethodWriter(final ClassWriter cw, final int access, final String name,
415 final String desc, final String signature,
416 final String[] exceptions, final boolean computeMaxs,
417 final boolean computeFrames) {
418 super(Opcodes.ASM4);
419 if (cw.firstMethod == null) {
420 cw.firstMethod = this;
421 } else {
422 cw.lastMethod.mv = this;
423 }
424 cw.lastMethod = this;
425 this.cw = cw;
426 this.access = access;
427 if ("<init>".equals(name)) {
428 this.access |= ACC_CONSTRUCTOR;
429 }
430 this.name = cw.newUTF8(name);
431 this.desc = cw.newUTF8(desc);
432 this.descriptor = desc;
433 if (ClassReader.SIGNATURES) {
434 this.signature = signature;
435 }
436 if (exceptions != null && exceptions.length > 0) {
437 exceptionCount = exceptions.length;
438 this.exceptions = new int[exceptionCount];
439 for (int i = 0; i < exceptionCount; ++i) {
440 this.exceptions[i] = cw.newClass(exceptions[i]);
441 }
442 }
443 this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING);
444 if (computeMaxs || computeFrames) {
445 // updates maxLocals
446 int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
447 if ((access & Opcodes.ACC_STATIC) != 0) {
448 --size;
449 }
450 maxLocals = size;
451 currentLocals = 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 abstract class
461 // ------------------------------------------------------------------------
462
463 @Override
464 public AnnotationVisitor visitAnnotationDefault() {
465 if (!ClassReader.ANNOTATIONS) {
466 return null;
467 }
468 annd = new ByteVector();
469 return new AnnotationWriter(cw, false, annd, null, 0);
470 }
471
472 @Override
473 public AnnotationVisitor visitAnnotation(final String desc,
474 final boolean visible) {
475 if (!ClassReader.ANNOTATIONS) {
476 return null;
477 }
478 ByteVector bv = new ByteVector();
479 // write type, and reserve space for values count
480 bv.putShort(cw.newUTF8(desc)).putShort(0);
481 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
482 if (visible) {
483 aw.next = anns;
484 anns = aw;
485 } else {
486 aw.next = ianns;
487 ianns = aw;
488 }
489 return aw;
490 }
491
492 @Override
493 public AnnotationVisitor visitParameterAnnotation(final int parameter,
494 final String desc, final boolean visible) {
495 if (!ClassReader.ANNOTATIONS) {
496 return null;
497 }
498 ByteVector bv = new ByteVector();
499 if ("Ljava/lang/Synthetic;".equals(desc)) {
500 // workaround for a bug in javac with synthetic parameters
501 // see ClassReader.readParameterAnnotations
502 synthetics = Math.max(synthetics, parameter + 1);
503 return new AnnotationWriter(cw, false, bv, null, 0);
504 }
505 // write type, and reserve space for values count
506 bv.putShort(cw.newUTF8(desc)).putShort(0);
507 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
508 if (visible) {
509 if (panns == null) {
510 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
511 }
512 aw.next = panns[parameter];
513 panns[parameter] = aw;
514 } else {
515 if (ipanns == null) {
516 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
517 }
518 aw.next = ipanns[parameter];
519 ipanns[parameter] = aw;
520 }
521 return aw;
522 }
523
524 @Override
525 public void visitAttribute(final Attribute attr) {
526 if (attr.isCodeAttribute()) {
527 attr.next = cattrs;
528 cattrs = attr;
529 } else {
530 attr.next = attrs;
531 attrs = attr;
532 }
533 }
534
535 @Override
536 public void visitCode() {
537 }
538
539 @Override
540 public void visitFrame(final int type, final int nLocal,
541 final Object[] local, final int nStack, final Object[] stack) {
542 if (!ClassReader.FRAMES || compute == FRAMES) {
543 return;
544 }
545
546 if (type == Opcodes.F_NEW) {
547 if (previousFrame == null) {
548 visitImplicitFirstFrame();
549 }
550 currentLocals = nLocal;
551 int frameIndex = startFrame(code.length, nLocal, nStack);
552 for (int i = 0; i < nLocal; ++i) {
553 if (local[i] instanceof String) {
554 frame[frameIndex++] = Frame.OBJECT
555 | cw.addType((String) local[i]);
556 } else if (local[i] instanceof Integer) {
557 frame[frameIndex++] = ((Integer) local[i]).intValue();
558 } else {
559 frame[frameIndex++] = Frame.UNINITIALIZED
560 | cw.addUninitializedType("",
561 ((Label) local[i]).position);
562 }
563 }
564 for (int i = 0; i < nStack; ++i) {
565 if (stack[i] instanceof String) {
566 frame[frameIndex++] = Frame.OBJECT
567 | cw.addType((String) stack[i]);
568 } else if (stack[i] instanceof Integer) {
569 frame[frameIndex++] = ((Integer) stack[i]).intValue();
570 } else {
571 frame[frameIndex++] = Frame.UNINITIALIZED
572 | cw.addUninitializedType("",
573 ((Label) stack[i]).position);
574 }
575 }
576 endFrame();
577 } else {
578 int delta;
579 if (stackMap == null) {
580 stackMap = new ByteVector();
581 delta = code.length;
582 } else {
583 delta = code.length - previousFrameOffset - 1;
584 if (delta < 0) {
585 if (type == Opcodes.F_SAME) {
586 return;
587 } else {
588 throw new IllegalStateException();
589 }
590 }
591 }
592
593 switch (type) {
594 case Opcodes.F_FULL:
595 currentLocals = nLocal;
596 stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal);
597 for (int i = 0; i < nLocal; ++i) {
598 writeFrameType(local[i]);
599 }
600 stackMap.putShort(nStack);
601 for (int i = 0; i < nStack; ++i) {
602 writeFrameType(stack[i]);
603 }
604 break;
605 case Opcodes.F_APPEND:
606 currentLocals += nLocal;
607 stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta);
608 for (int i = 0; i < nLocal; ++i) {
609 writeFrameType(local[i]);
610 }
611 break;
612 case Opcodes.F_CHOP:
613 currentLocals -= nLocal;
614 stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta);
615 break;
616 case Opcodes.F_SAME:
617 if (delta < 64) {
618 stackMap.putByte(delta);
619 } else {
620 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
621 }
622 break;
623 case Opcodes.F_SAME1:
624 if (delta < 64) {
625 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
626 } else {
627 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
628 .putShort(delta);
629 }
630 writeFrameType(stack[0]);
631 break;
632 }
633
634 previousFrameOffset = code.length;
635 ++frameCount;
636 }
637
638 maxStack = Math.max(maxStack, nStack);
639 maxLocals = Math.max(maxLocals, currentLocals);
640 }
641
642 @Override
643 public void visitInsn(final int opcode) {
644 // adds the instruction to the bytecode of the method
645 code.putByte(opcode);
646 // update currentBlock
647 // Label currentBlock = this.currentBlock;
648 if (currentBlock != null) {
649 if (compute == FRAMES) {
650 currentBlock.frame.execute(opcode, 0, null, null);
651 } else {
652 // updates current and max stack sizes
653 int size = stackSize + Frame.SIZE[opcode];
654 if (size > maxStackSize) {
655 maxStackSize = size;
656 }
657 stackSize = size;
658 }
659 // if opcode == ATHROW or xRETURN, ends current block (no successor)
660 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
661 || opcode == Opcodes.ATHROW) {
662 noSuccessor();
663 }
664 }
665 }
666
667 @Override
668 public void visitIntInsn(final int opcode, final int operand) {
669 // Label currentBlock = this.currentBlock;
670 if (currentBlock != null) {
671 if (compute == FRAMES) {
672 currentBlock.frame.execute(opcode, operand, null, null);
673 } else if (opcode != Opcodes.NEWARRAY) {
674 // updates current and max stack sizes only for NEWARRAY
675 // (stack size variation = 0 for BIPUSH or SIPUSH)
676 int size = stackSize + 1;
677 if (size > maxStackSize) {
678 maxStackSize = size;
679 }
680 stackSize = size;
681 }
682 }
683 // adds the instruction to the bytecode of the method
684 if (opcode == Opcodes.SIPUSH) {
685 code.put12(opcode, operand);
686 } else { // BIPUSH or NEWARRAY
687 code.put11(opcode, operand);
688 }
689 }
690
691 @Override
692 public void visitVarInsn(final int opcode, final int var) {
693 // Label currentBlock = this.currentBlock;
694 if (currentBlock != null) {
695 if (compute == FRAMES) {
696 currentBlock.frame.execute(opcode, var, null, null);
697 } else {
698 // updates current and max stack sizes
699 if (opcode == Opcodes.RET) {
700 // no stack change, but end of current block (no successor)
701 currentBlock.status |= Label.RET;
702 // save 'stackSize' here for future use
703 // (see {@link #findSubroutineSuccessors})
704 currentBlock.inputStackTop = stackSize;
705 noSuccessor();
706 } else { // xLOAD or xSTORE
707 int size = stackSize + Frame.SIZE[opcode];
708 if (size > maxStackSize) {
709 maxStackSize = size;
710 }
711 stackSize = size;
712 }
713 }
714 }
715 if (compute != NOTHING) {
716 // updates max locals
717 int n;
718 if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
719 || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) {
720 n = var + 2;
721 } else {
722 n = var + 1;
723 }
724 if (n > maxLocals) {
725 maxLocals = n;
726 }
727 }
728 // adds the instruction to the bytecode of the method
729 if (var < 4 && opcode != Opcodes.RET) {
730 int opt;
731 if (opcode < Opcodes.ISTORE) {
732 /* ILOAD_0 */
733 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
734 } else {
735 /* ISTORE_0 */
736 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
737 }
738 code.putByte(opt);
739 } else if (var >= 256) {
740 code.putByte(196 /* WIDE */).put12(opcode, var);
741 } else {
742 code.put11(opcode, var);
743 }
744 if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) {
745 visitLabel(new Label());
746 }
747 }
748
749 @Override
750 public void visitTypeInsn(final int opcode, final String type) {
751 Item i = cw.newClassItem(type);
752 // Label currentBlock = this.currentBlock;
753 if (currentBlock != null) {
754 if (compute == FRAMES) {
755 currentBlock.frame.execute(opcode, code.length, cw, i);
756 } else if (opcode == Opcodes.NEW) {
757 // updates current and max stack sizes only if opcode == NEW
758 // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
759 int size = stackSize + 1;
760 if (size > maxStackSize) {
761 maxStackSize = size;
762 }
763 stackSize = size;
764 }
765 }
766 // adds the instruction to the bytecode of the method
767 code.put12(opcode, i.index);
768 }
769
770 @Override
771 public void visitFieldInsn(final int opcode, final String owner,
772 final String name, final String desc) {
773 Item i = cw.newFieldItem(owner, name, desc);
774 // Label currentBlock = this.currentBlock;
775 if (currentBlock != null) {
776 if (compute == FRAMES) {
777 currentBlock.frame.execute(opcode, 0, cw, i);
778 } else {
779 int size;
780 // computes the stack size variation
781 char c = desc.charAt(0);
782 switch (opcode) {
783 case Opcodes.GETSTATIC:
784 size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
785 break;
786 case Opcodes.PUTSTATIC:
787 size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
788 break;
789 case Opcodes.GETFIELD:
790 size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
791 break;
792 // case Constants.PUTFIELD:
793 default:
794 size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
795 break;
796 }
797 // updates current and max stack sizes
798 if (size > maxStackSize) {
799 maxStackSize = size;
800 }
801 stackSize = size;
802 }
803 }
804 // adds the instruction to the bytecode of the method
805 code.put12(opcode, i.index);
806 }
807
808 @Override
809 public void visitMethodInsn(final int opcode, final String owner,
810 final String name, final String desc) {
811 boolean itf = opcode == Opcodes.INVOKEINTERFACE;
812 Item i = cw.newMethodItem(owner, name, desc, itf);
813 int argSize = i.intVal;
814 // Label currentBlock = this.currentBlock;
815 if (currentBlock != null) {
816 if (compute == FRAMES) {
817 currentBlock.frame.execute(opcode, 0, cw, i);
818 } else {
819 /*
820 * computes the stack size variation. In order not to recompute
821 * several times this variation for the same Item, we use the
822 * intVal field of this item to store this variation, once it
823 * has been computed. More precisely this intVal field stores
824 * the sizes of the arguments and of the return value
825 * corresponding to desc.
826 */
827 if (argSize == 0) {
828 // the above sizes have not been computed yet,
829 // so we compute them...
830 argSize = Type.getArgumentsAndReturnSizes(desc);
831 // ... and we save them in order
832 // not to recompute them in the future
833 i.intVal = argSize;
834 }
835 int size;
836 if (opcode == Opcodes.INVOKESTATIC) {
837 size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
838 } else {
839 size = stackSize - (argSize >> 2) + (argSize & 0x03);
840 }
841 // updates current and max stack sizes
842 if (size > maxStackSize) {
843 maxStackSize = size;
844 }
845 stackSize = size;
846 }
847 }
848 // adds the instruction to the bytecode of the method
849 if (itf) {
850 if (argSize == 0) {
851 argSize = Type.getArgumentsAndReturnSizes(desc);
852 i.intVal = argSize;
853 }
854 code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
855 } else {
856 code.put12(opcode, i.index);
857 }
858 }
859
860 @Override
861 public void visitInvokeDynamicInsn(final String name, final String desc,
862 final Handle bsm, final Object... bsmArgs) {
863 Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs);
864 int argSize = i.intVal;
865 // Label currentBlock = this.currentBlock;
866 if (currentBlock != null) {
867 if (compute == FRAMES) {
868 currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i);
869 } else {
870 /*
871 * computes the stack size variation. In order not to recompute
872 * several times this variation for the same Item, we use the
873 * intVal field of this item to store this variation, once it
874 * has been computed. More precisely this intVal field stores
875 * the sizes of the arguments and of the return value
876 * corresponding to desc.
877 */
878 if (argSize == 0) {
879 // the above sizes have not been computed yet,
880 // so we compute them...
881 argSize = Type.getArgumentsAndReturnSizes(desc);
882 // ... and we save them in order
883 // not to recompute them in the future
884 i.intVal = argSize;
885 }
886 int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
887
888 // updates current and max stack sizes
889 if (size > maxStackSize) {
890 maxStackSize = size;
891 }
892 stackSize = size;
893 }
894 }
895 // adds the instruction to the bytecode of the method
896 code.put12(Opcodes.INVOKEDYNAMIC, i.index);
897 code.putShort(0);
898 }
899
900 @Override
901 public void visitJumpInsn(final int opcode, final Label label) {
902 Label nextInsn = null;
903 // Label currentBlock = this.currentBlock;
904 if (currentBlock != null) {
905 if (compute == FRAMES) {
906 currentBlock.frame.execute(opcode, 0, null, null);
907 // 'label' is the target of a jump instruction
908 label.getFirst().status |= Label.TARGET;
909 // adds 'label' as a successor of this basic block
910 addSuccessor(Edge.NORMAL, label);
911 if (opcode != Opcodes.GOTO) {
912 // creates a Label for the next basic block
913 nextInsn = new Label();
914 }
915 } else {
916 if (opcode == Opcodes.JSR) {
917 if ((label.status & Label.SUBROUTINE) == 0) {
918 label.status |= Label.SUBROUTINE;
919 ++subroutines;
920 }
921 currentBlock.status |= Label.JSR;
922 addSuccessor(stackSize + 1, label);
923 // creates a Label for the next basic block
924 nextInsn = new Label();
925 /*
926 * note that, by construction in this method, a JSR block
927 * has at least two successors in the control flow graph:
928 * the first one leads the next instruction after the JSR,
929 * while the second one leads to the JSR target.
930 */
931 } else {
932 // updates current stack size (max stack size unchanged
933 // because stack size variation always negative in this
934 // case)
935 stackSize += Frame.SIZE[opcode];
936 addSuccessor(stackSize, label);
937 }
938 }
939 }
940 // adds the instruction to the bytecode of the method
941 if ((label.status & Label.RESOLVED) != 0
942 && label.position - code.length < Short.MIN_VALUE) {
943 /*
944 * case of a backward jump with an offset < -32768. In this case we
945 * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
946 * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
947 * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
948 * designates the instruction just after the GOTO_W.
949 */
950 if (opcode == Opcodes.GOTO) {
951 code.putByte(200); // GOTO_W
952 } else if (opcode == Opcodes.JSR) {
953 code.putByte(201); // JSR_W
954 } else {
955 // if the IF instruction is transformed into IFNOT GOTO_W the
956 // next instruction becomes the target of the IFNOT instruction
957 if (nextInsn != null) {
958 nextInsn.status |= Label.TARGET;
959 }
960 code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
961 : opcode ^ 1);
962 code.putShort(8); // jump offset
963 code.putByte(200); // GOTO_W
964 }
965 label.put(this, code, code.length - 1, true);
966 } else {
967 /*
968 * case of a backward jump with an offset >= -32768, or of a forward
969 * jump with, of course, an unknown offset. In these cases we store
970 * the offset in 2 bytes (which will be increased in
971 * resizeInstructions, if needed).
972 */
973 code.putByte(opcode);
974 label.put(this, code, code.length - 1, false);
975 }
976 if (currentBlock != null) {
977 if (nextInsn != null) {
978 // if the jump instruction is not a GOTO, the next instruction
979 // is also a successor of this instruction. Calling visitLabel
980 // adds the label of this next instruction as a successor of the
981 // current block, and starts a new basic block
982 visitLabel(nextInsn);
983 }
984 if (opcode == Opcodes.GOTO) {
985 noSuccessor();
986 }
987 }
988 }
989
990 @Override
991 public void visitLabel(final Label label) {
992 // resolves previous forward references to label, if any
993 resize |= label.resolve(this, code.length, code.data);
994 // updates currentBlock
995 if ((label.status & Label.DEBUG) != 0) {
996 return;
997 }
998 if (compute == FRAMES) {
999 if (currentBlock != null) {
1000 if (label.position == currentBlock.position) {
1001 // successive labels, do not start a new basic block
1002 currentBlock.status |= (label.status & Label.TARGET);
1003 label.frame = currentBlock.frame;
1004 return;
1005 }
1006 // ends current block (with one new successor)
1007 addSuccessor(Edge.NORMAL, label);
1008 }
1009 // begins a new current block
1010 currentBlock = label;
1011 if (label.frame == null) {
1012 label.frame = new Frame();
1013 label.frame.owner = label;
1014 }
1015 // updates the basic block list
1016 if (previousBlock != null) {
1017 if (label.position == previousBlock.position) {
1018 previousBlock.status |= (label.status & Label.TARGET);
1019 label.frame = previousBlock.frame;
1020 currentBlock = previousBlock;
1021 return;
1022 }
1023 previousBlock.successor = label;
1024 }
1025 previousBlock = label;
1026 } else if (compute == MAXS) {
1027 if (currentBlock != null) {
1028 // ends current block (with one new successor)
1029 currentBlock.outputStackMax = maxStackSize;
1030 addSuccessor(stackSize, label);
1031 }
1032 // begins a new current block
1033 currentBlock = label;
1034 // resets the relative current and max stack sizes
1035 stackSize = 0;
1036 maxStackSize = 0;
1037 // updates the basic block list
1038 if (previousBlock != null) {
1039 previousBlock.successor = label;
1040 }
1041 previousBlock = label;
1042 }
1043 }
1044
1045 @Override
1046 public void visitLdcInsn(final Object cst) {
1047 Item i = cw.newConstItem(cst);
1048 // Label currentBlock = this.currentBlock;
1049 if (currentBlock != null) {
1050 if (compute == FRAMES) {
1051 currentBlock.frame.execute(Opcodes.LDC, 0, cw, i);
1052 } else {
1053 int size;
1054 // computes the stack size variation
1055 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1056 size = stackSize + 2;
1057 } else {
1058 size = stackSize + 1;
1059 }
1060 // updates current and max stack sizes
1061 if (size > maxStackSize) {
1062 maxStackSize = size;
1063 }
1064 stackSize = size;
1065 }
1066 }
1067 // adds the instruction to the bytecode of the method
1068 int index = i.index;
1069 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1070 code.put12(20 /* LDC2_W */, index);
1071 } else if (index >= 256) {
1072 code.put12(19 /* LDC_W */, index);
1073 } else {
1074 code.put11(Opcodes.LDC, index);
1075 }
1076 }
1077
1078 @Override
1079 public void visitIincInsn(final int var, final int increment) {
1080 if (currentBlock != null) {
1081 if (compute == FRAMES) {
1082 currentBlock.frame.execute(Opcodes.IINC, var, null, null);
1083 }
1084 }
1085 if (compute != NOTHING) {
1086 // updates max locals
1087 int n = var + 1;
1088 if (n > maxLocals) {
1089 maxLocals = n;
1090 }
1091 }
1092 // adds the instruction to the bytecode of the method
1093 if ((var > 255) || (increment > 127) || (increment < -128)) {
1094 code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var)
1095 .putShort(increment);
1096 } else {
1097 code.putByte(Opcodes.IINC).put11(var, increment);
1098 }
1099 }
1100
1101 @Override
1102 public void visitTableSwitchInsn(final int min, final int max,
1103 final Label dflt, final Label... labels) {
1104 // adds the instruction to the bytecode of the method
1105 int source = code.length;
1106 code.putByte(Opcodes.TABLESWITCH);
1107 code.putByteArray(null, 0, (4 - code.length % 4) % 4);
1108 dflt.put(this, code, source, true);
1109 code.putInt(min).putInt(max);
1110 for (int i = 0; i < labels.length; ++i) {
1111 labels[i].put(this, code, source, true);
1112 }
1113 // updates currentBlock
1114 visitSwitchInsn(dflt, labels);
1115 }
1116
1117 @Override
1118 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
1119 final Label[] labels) {
1120 // adds the instruction to the bytecode of the method
1121 int source = code.length;
1122 code.putByte(Opcodes.LOOKUPSWITCH);
1123 code.putByteArray(null, 0, (4 - code.length % 4) % 4);
1124 dflt.put(this, code, source, true);
1125 code.putInt(labels.length);
1126 for (int i = 0; i < labels.length; ++i) {
1127 code.putInt(keys[i]);
1128 labels[i].put(this, code, source, true);
1129 }
1130 // updates currentBlock
1131 visitSwitchInsn(dflt, labels);
1132 }
1133
1134 private void visitSwitchInsn(final Label dflt, final Label[] labels) {
1135 // Label currentBlock = this.currentBlock;
1136 if (currentBlock != null) {
1137 if (compute == FRAMES) {
1138 currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
1139 // adds current block successors
1140 addSuccessor(Edge.NORMAL, dflt);
1141 dflt.getFirst().status |= Label.TARGET;
1142 for (int i = 0; i < labels.length; ++i) {
1143 addSuccessor(Edge.NORMAL, labels[i]);
1144 labels[i].getFirst().status |= Label.TARGET;
1145 }
1146 } else {
1147 // updates current stack size (max stack size unchanged)
1148 --stackSize;
1149 // adds current block successors
1150 addSuccessor(stackSize, dflt);
1151 for (int i = 0; i < labels.length; ++i) {
1152 addSuccessor(stackSize, labels[i]);
1153 }
1154 }
1155 // ends current block
1156 noSuccessor();
1157 }
1158 }
1159
1160 @Override
1161 public void visitMultiANewArrayInsn(final String desc, final int dims) {
1162 Item i = cw.newClassItem(desc);
1163 // Label currentBlock = this.currentBlock;
1164 if (currentBlock != null) {
1165 if (compute == FRAMES) {
1166 currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i);
1167 } else {
1168 // updates current stack size (max stack size unchanged because
1169 // stack size variation always negative or null)
1170 stackSize += 1 - dims;
1171 }
1172 }
1173 // adds the instruction to the bytecode of the method
1174 code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
1175 }
1176
1177 @Override
1178 public void visitTryCatchBlock(final Label start, final Label end,
1179 final Label handler, final String type) {
1180 ++handlerCount;
1181 Handler h = new Handler();
1182 h.start = start;
1183 h.end = end;
1184 h.handler = handler;
1185 h.desc = type;
1186 h.type = type != null ? cw.newClass(type) : 0;
1187 if (lastHandler == null) {
1188 firstHandler = h;
1189 } else {
1190 lastHandler.next = h;
1191 }
1192 lastHandler = h;
1193 }
1194
1195 @Override
1196 public void visitLocalVariable(final String name, final String desc,
1197 final String signature, final Label start, final Label end,
1198 final int index) {
1199 if (signature != null) {
1200 if (localVarType == null) {
1201 localVarType = new ByteVector();
1202 }
1203 ++localVarTypeCount;
1204 localVarType.putShort(start.position)
1205 .putShort(end.position - start.position)
1206 .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(signature))
1207 .putShort(index);
1208 }
1209 if (localVar == null) {
1210 localVar = new ByteVector();
1211 }
1212 ++localVarCount;
1213 localVar.putShort(start.position)
1214 .putShort(end.position - start.position)
1215 .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc))
1216 .putShort(index);
1217 if (compute != NOTHING) {
1218 // updates max locals
1219 char c = desc.charAt(0);
1220 int n = index + (c == 'J' || c == 'D' ? 2 : 1);
1221 if (n > maxLocals) {
1222 maxLocals = n;
1223 }
1224 }
1225 }
1226
1227 @Override
1228 public void visitLineNumber(final int line, final Label start) {
1229 if (lineNumber == null) {
1230 lineNumber = new ByteVector();
1231 }
1232 ++lineNumberCount;
1233 lineNumber.putShort(start.position);
1234 lineNumber.putShort(line);
1235 }
1236
1237 @Override
1238 public void visitMaxs(final int maxStack, final int maxLocals) {
1239 if (ClassReader.FRAMES && compute == FRAMES) {
1240 // completes the control flow graph with exception handler blocks
1241 Handler handler = firstHandler;
1242 while (handler != null) {
1243 Label l = handler.start.getFirst();
1244 Label h = handler.handler.getFirst();
1245 Label e = handler.end.getFirst();
1246 // computes the kind of the edges to 'h'
1247 String t = handler.desc == null ? "java/lang/Throwable"
1248 : handler.desc;
1249 int kind = Frame.OBJECT | cw.addType(t);
1250 // h is an exception handler
1251 h.status |= Label.TARGET;
1252 // adds 'h' as a successor of labels between 'start' and 'end'
1253 while (l != e) {
1254 // creates an edge to 'h'
1255 Edge b = new Edge();
1256 b.info = kind;
1257 b.successor = h;
1258 // adds it to the successors of 'l'
1259 b.next = l.successors;
1260 l.successors = b;
1261 // goes to the next label
1262 l = l.successor;
1263 }
1264 handler = handler.next;
1265 }
1266
1267 // creates and visits the first (implicit) frame
1268 Frame f = labels.frame;
1269 Type[] args = Type.getArgumentTypes(descriptor);
1270 f.initInputFrame(cw, access, args, this.maxLocals);
1271 visitFrame(f);
1272
1273 /*
1274 * fix point algorithm: mark the first basic block as 'changed'
1275 * (i.e. put it in the 'changed' list) and, while there are changed
1276 * basic blocks, choose one, mark it as unchanged, and update its
1277 * successors (which can be changed in the process).
1278 */
1279 int max = 0;
1280 Label changed = labels;
1281 while (changed != null) {
1282 // removes a basic block from the list of changed basic blocks
1283 Label l = changed;
1284 changed = changed.next;
1285 l.next = null;
1286 f = l.frame;
1287 // a reachable jump target must be stored in the stack map
1288 if ((l.status & Label.TARGET) != 0) {
1289 l.status |= Label.STORE;
1290 }
1291 // all visited labels are reachable, by definition
1292 l.status |= Label.REACHABLE;
1293 // updates the (absolute) maximum stack size
1294 int blockMax = f.inputStack.length + l.outputStackMax;
1295 if (blockMax > max) {
1296 max = blockMax;
1297 }
1298 // updates the successors of the current basic block
1299 Edge e = l.successors;
1300 while (e != null) {
1301 Label n = e.successor.getFirst();
1302 boolean change = f.merge(cw, n.frame, e.info);
1303 if (change && n.next == null) {
1304 // if n has changed and is not already in the 'changed'
1305 // list, adds it to this list
1306 n.next = changed;
1307 changed = n;
1308 }
1309 e = e.next;
1310 }
1311 }
1312
1313 // visits all the frames that must be stored in the stack map
1314 Label l = labels;
1315 while (l != null) {
1316 f = l.frame;
1317 if ((l.status & Label.STORE) != 0) {
1318 visitFrame(f);
1319 }
1320 if ((l.status & Label.REACHABLE) == 0) {
1321 // finds start and end of dead basic block
1322 Label k = l.successor;
1323 int start = l.position;
1324 int end = (k == null ? code.length : k.position) - 1;
1325 // if non empty basic block
1326 if (end >= start) {
1327 max = Math.max(max, 1);
1328 // replaces instructions with NOP ... NOP ATHROW
1329 for (int i = start; i < end; ++i) {
1330 code.data[i] = Opcodes.NOP;
1331 }
1332 code.data[end] = (byte) Opcodes.ATHROW;
1333 // emits a frame for this unreachable block
1334 int frameIndex = startFrame(start, 0, 1);
1335 frame[frameIndex] = Frame.OBJECT
1336 | cw.addType("java/lang/Throwable");
1337 endFrame();
1338 // removes the start-end range from the exception
1339 // handlers
1340 firstHandler = Handler.remove(firstHandler, l, k);
1341 }
1342 }
1343 l = l.successor;
1344 }
1345
1346 handler = firstHandler;
1347 handlerCount = 0;
1348 while (handler != null) {
1349 handlerCount += 1;
1350 handler = handler.next;
1351 }
1352
1353 this.maxStack = max;
1354 } else if (compute == MAXS) {
1355 // completes the control flow graph with exception handler blocks
1356 Handler handler = firstHandler;
1357 while (handler != null) {
1358 Label l = handler.start;
1359 Label h = handler.handler;
1360 Label e = handler.end;
1361 // adds 'h' as a successor of labels between 'start' and 'end'
1362 while (l != e) {
1363 // creates an edge to 'h'
1364 Edge b = new Edge();
1365 b.info = Edge.EXCEPTION;
1366 b.successor = h;
1367 // adds it to the successors of 'l'
1368 if ((l.status & Label.JSR) == 0) {
1369 b.next = l.successors;
1370 l.successors = b;
1371 } else {
1372 // if l is a JSR block, adds b after the first two edges
1373 // to preserve the hypothesis about JSR block successors
1374 // order (see {@link #visitJumpInsn})
1375 b.next = l.successors.next.next;
1376 l.successors.next.next = b;
1377 }
1378 // goes to the next label
1379 l = l.successor;
1380 }
1381 handler = handler.next;
1382 }
1383
1384 if (subroutines > 0) {
1385 // completes the control flow graph with the RET successors
1386 /*
1387 * first step: finds the subroutines. This step determines, for
1388 * each basic block, to which subroutine(s) it belongs.
1389 */
1390 // finds the basic blocks that belong to the "main" subroutine
1391 int id = 0;
1392 labels.visitSubroutine(null, 1, subroutines);
1393 // finds the basic blocks that belong to the real subroutines
1394 Label l = labels;
1395 while (l != null) {
1396 if ((l.status & Label.JSR) != 0) {
1397 // the subroutine is defined by l's TARGET, not by l
1398 Label subroutine = l.successors.next.successor;
1399 // if this subroutine has not been visited yet...
1400 if ((subroutine.status & Label.VISITED) == 0) {
1401 // ...assigns it a new id and finds its basic blocks
1402 id += 1;
1403 subroutine.visitSubroutine(null, (id / 32L) << 32
1404 | (1L << (id % 32)), subroutines);
1405 }
1406 }
1407 l = l.successor;
1408 }
1409 // second step: finds the successors of RET blocks
1410 l = labels;
1411 while (l != null) {
1412 if ((l.status & Label.JSR) != 0) {
1413 Label L = labels;
1414 while (L != null) {
1415 L.status &= ~Label.VISITED2;
1416 L = L.successor;
1417 }
1418 // the subroutine is defined by l's TARGET, not by l
1419 Label subroutine = l.successors.next.successor;
1420 subroutine.visitSubroutine(l, 0, subroutines);
1421 }
1422 l = l.successor;
1423 }
1424 }
1425
1426 /*
1427 * control flow analysis algorithm: while the block stack is not
1428 * empty, pop a block from this stack, update the max stack size,
1429 * compute the true (non relative) begin stack size of the
1430 * successors of this block, and push these successors onto the
1431 * stack (unless they have already been pushed onto the stack).
1432 * Note: by hypothesis, the {@link Label#inputStackTop} of the
1433 * blocks in the block stack are the true (non relative) beginning
1434 * stack sizes of these blocks.
1435 */
1436 int max = 0;
1437 Label stack = labels;
1438 while (stack != null) {
1439 // pops a block from the stack
1440 Label l = stack;
1441 stack = stack.next;
1442 // computes the true (non relative) max stack size of this block
1443 int start = l.inputStackTop;
1444 int blockMax = start + l.outputStackMax;
1445 // updates the global max stack size
1446 if (blockMax > max) {
1447 max = blockMax;
1448 }
1449 // analyzes the successors of the block
1450 Edge b = l.successors;
1451 if ((l.status & Label.JSR) != 0) {
1452 // ignores the first edge of JSR blocks (virtual successor)
1453 b = b.next;
1454 }
1455 while (b != null) {
1456 l = b.successor;
1457 // if this successor has not already been pushed...
1458 if ((l.status & Label.PUSHED) == 0) {
1459 // computes its true beginning stack size...
1460 l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start
1461 + b.info;
1462 // ...and pushes it onto the stack
1463 l.status |= Label.PUSHED;
1464 l.next = stack;
1465 stack = l;
1466 }
1467 b = b.next;
1468 }
1469 }
1470 this.maxStack = Math.max(maxStack, max);
1471 } else {
1472 this.maxStack = maxStack;
1473 this.maxLocals = maxLocals;
1474 }
1475 }
1476
1477 @Override
1478 public void visitEnd() {
1479 }
1480
1481 // ------------------------------------------------------------------------
1482 // Utility methods: control flow analysis algorithm
1483 // ------------------------------------------------------------------------
1484
1485 /**
1486 * Adds a successor to the {@link #currentBlock currentBlock} block.
1487 *
1488 * @param info
1489 * information about the control flow edge to be added.
1490 * @param successor
1491 * the successor block to be added to the current block.
1492 */
1493 private void addSuccessor(final int info, final Label successor) {
1494 // creates and initializes an Edge object...
1495 Edge b = new Edge();
1496 b.info = info;
1497 b.successor = successor;
1498 // ...and adds it to the successor list of the currentBlock block
1499 b.next = currentBlock.successors;
1500 currentBlock.successors = b;
1501 }
1502
1503 /**
1504 * Ends the current basic block. This method must be used in the case where
1505 * the current basic block does not have any successor.
1506 */
1507 private void noSuccessor() {
1508 if (compute == FRAMES) {
1509 Label l = new Label();
1510 l.frame = new Frame();
1511 l.frame.owner = l;
1512 l.resolve(this, code.length, code.data);
1513 previousBlock.successor = l;
1514 previousBlock = l;
1515 } else {
1516 currentBlock.outputStackMax = maxStackSize;
1517 }
1518 currentBlock = null;
1519 }
1520
1521 // ------------------------------------------------------------------------
1522 // Utility methods: stack map frames
1523 // ------------------------------------------------------------------------
1524
1525 /**
1526 * Visits a frame that has been computed from scratch.
1527 *
1528 * @param f
1529 * the frame that must be visited.
1530 */
1531 private void visitFrame(final Frame f) {
1532 int i, t;
1533 int nTop = 0;
1534 int nLocal = 0;
1535 int nStack = 0;
1536 int[] locals = f.inputLocals;
1537 int[] stacks = f.inputStack;
1538 // computes the number of locals (ignores TOP types that are just after
1539 // a LONG or a DOUBLE, and all trailing TOP types)
1540 for (i = 0; i < locals.length; ++i) {
1541 t = locals[i];
1542 if (t == Frame.TOP) {
1543 ++nTop;
1544 } else {
1545 nLocal += nTop + 1;
1546 nTop = 0;
1547 }
1548 if (t == Frame.LONG || t == Frame.DOUBLE) {
1549 ++i;
1550 }
1551 }
1552 // computes the stack size (ignores TOP types that are just after
1553 // a LONG or a DOUBLE)
1554 for (i = 0; i < stacks.length; ++i) {
1555 t = stacks[i];
1556 ++nStack;
1557 if (t == Frame.LONG || t == Frame.DOUBLE) {
1558 ++i;
1559 }
1560 }
1561 // visits the frame and its content
1562 int frameIndex = startFrame(f.owner.position, nLocal, nStack);
1563 for (i = 0; nLocal > 0; ++i, --nLocal) {
1564 t = locals[i];
1565 frame[frameIndex++] = t;
1566 if (t == Frame.LONG || t == Frame.DOUBLE) {
1567 ++i;
1568 }
1569 }
1570 for (i = 0; i < stacks.length; ++i) {
1571 t = stacks[i];
1572 frame[frameIndex++] = t;
1573 if (t == Frame.LONG || t == Frame.DOUBLE) {
1574 ++i;
1575 }
1576 }
1577 endFrame();
1578 }
1579
1580 /**
1581 * Visit the implicit first frame of this method.
1582 */
1583 private void visitImplicitFirstFrame() {
1584 // There can be at most descriptor.length() + 1 locals
1585 int frameIndex = startFrame(0, descriptor.length() + 1, 0);
1586 if ((access & Opcodes.ACC_STATIC) == 0) {
1587 if ((access & ACC_CONSTRUCTOR) == 0) {
1588 frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName);
1589 } else {
1590 frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS;
1591 }
1592 }
1593 int i = 1;
1594 loop: while (true) {
1595 int j = i;
1596 switch (descriptor.charAt(i++)) {
1597 case 'Z':
1598 case 'C':
1599 case 'B':
1600 case 'S':
1601 case 'I':
1602 frame[frameIndex++] = 1; // Opcodes.INTEGER;
1603 break;
1604 case 'F':
1605 frame[frameIndex++] = 2; // Opcodes.FLOAT;
1606 break;
1607 case 'J':
1608 frame[frameIndex++] = 4; // Opcodes.LONG;
1609 break;
1610 case 'D':
1611 frame[frameIndex++] = 3; // Opcodes.DOUBLE;
1612 break;
1613 case '[':
1614 while (descriptor.charAt(i) == '[') {
1615 ++i;
1616 }
1617 if (descriptor.charAt(i) == 'L') {
1618 ++i;
1619 while (descriptor.charAt(i) != ';') {
1620 ++i;
1621 }
1622 }
1623 frame[frameIndex++] = Frame.OBJECT
1624 | cw.addType(descriptor.substring(j, ++i));
1625 break;
1626 case 'L':
1627 while (descriptor.charAt(i) != ';') {
1628 ++i;
1629 }
1630 frame[frameIndex++] = Frame.OBJECT
1631 | cw.addType(descriptor.substring(j + 1, i++));
1632 break;
1633 default:
1634 break loop;
1635 }
1636 }
1637 frame[1] = frameIndex - 3;
1638 endFrame();
1639 }
1640
1641 /**
1642 * Starts the visit of a stack map frame.
1643 *
1644 * @param offset
1645 * the offset of the instruction to which the frame corresponds.
1646 * @param nLocal
1647 * the number of local variables in the frame.
1648 * @param nStack
1649 * the number of stack elements in the frame.
1650 * @return the index of the next element to be written in this frame.
1651 */
1652 private int startFrame(final int offset, final int nLocal, final int nStack) {
1653 int n = 3 + nLocal + nStack;
1654 if (frame == null || frame.length < n) {
1655 frame = new int[n];
1656 }
1657 frame[0] = offset;
1658 frame[1] = nLocal;
1659 frame[2] = nStack;
1660 return 3;
1661 }
1662
1663 /**
1664 * Checks if the visit of the current frame {@link #frame} is finished, and
1665 * if yes, write it in the StackMapTable attribute.
1666 */
1667 private void endFrame() {
1668 if (previousFrame != null) { // do not write the first frame
1669 if (stackMap == null) {
1670 stackMap = new ByteVector();
1671 }
1672 writeFrame();
1673 ++frameCount;
1674 }
1675 previousFrame = frame;
1676 frame = null;
1677 }
1678
1679 /**
1680 * Compress and writes the current frame {@link #frame} in the StackMapTable
1681 * attribute.
1682 */
1683 private void writeFrame() {
1684 int clocalsSize = frame[1];
1685 int cstackSize = frame[2];
1686 if ((cw.version & 0xFFFF) < Opcodes.V1_6) {
1687 stackMap.putShort(frame[0]).putShort(clocalsSize);
1688 writeFrameTypes(3, 3 + clocalsSize);
1689 stackMap.putShort(cstackSize);
1690 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
1691 return;
1692 }
1693 int localsSize = previousFrame[1];
1694 int type = FULL_FRAME;
1695 int k = 0;
1696 int delta;
1697 if (frameCount == 0) {
1698 delta = frame[0];
1699 } else {
1700 delta = frame[0] - previousFrame[0] - 1;
1701 }
1702 if (cstackSize == 0) {
1703 k = clocalsSize - localsSize;
1704 switch (k) {
1705 case -3:
1706 case -2:
1707 case -1:
1708 type = CHOP_FRAME;
1709 localsSize = clocalsSize;
1710 break;
1711 case 0:
1712 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
1713 break;
1714 case 1:
1715 case 2:
1716 case 3:
1717 type = APPEND_FRAME;
1718 break;
1719 }
1720 } else if (clocalsSize == localsSize && cstackSize == 1) {
1721 type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME
1722 : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
1723 }
1724 if (type != FULL_FRAME) {
1725 // verify if locals are the same
1726 int l = 3;
1727 for (int j = 0; j < localsSize; j++) {
1728 if (frame[l] != previousFrame[l]) {
1729 type = FULL_FRAME;
1730 break;
1731 }
1732 l++;
1733 }
1734 }
1735 switch (type) {
1736 case SAME_FRAME:
1737 stackMap.putByte(delta);
1738 break;
1739 case SAME_LOCALS_1_STACK_ITEM_FRAME:
1740 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
1741 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1742 break;
1743 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
1744 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort(
1745 delta);
1746 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1747 break;
1748 case SAME_FRAME_EXTENDED:
1749 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
1750 break;
1751 case CHOP_FRAME:
1752 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1753 break;
1754 case APPEND_FRAME:
1755 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1756 writeFrameTypes(3 + localsSize, 3 + clocalsSize);
1757 break;
1758 // case FULL_FRAME:
1759 default:
1760 stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize);
1761 writeFrameTypes(3, 3 + clocalsSize);
1762 stackMap.putShort(cstackSize);
1763 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
1764 }
1765 }
1766
1767 /**
1768 * Writes some types of the current frame {@link #frame} into the
1769 * StackMapTableAttribute. This method converts types from the format used
1770 * in {@link Label} to the format used in StackMapTable attributes. In
1771 * particular, it converts type table indexes to constant pool indexes.
1772 *
1773 * @param start
1774 * index of the first type in {@link #frame} to write.
1775 * @param end
1776 * index of last type in {@link #frame} to write (exclusive).
1777 */
1778 private void writeFrameTypes(final int start, final int end) {
1779 for (int i = start; i < end; ++i) {
1780 int t = frame[i];
1781 int d = t & Frame.DIM;
1782 if (d == 0) {
1783 int v = t & Frame.BASE_VALUE;
1784 switch (t & Frame.BASE_KIND) {
1785 case Frame.OBJECT:
1786 stackMap.putByte(7).putShort(
1787 cw.newClass(cw.typeTable[v].strVal1));
1788 break;
1789 case Frame.UNINITIALIZED:
1790 stackMap.putByte(8).putShort(cw.typeTable[v].intVal);
1791 break;
1792 default:
1793 stackMap.putByte(v);
1794 }
1795 } else {
1796 StringBuffer buf = new StringBuffer();
1797 d >>= 28;
1798 while (d-- > 0) {
1799 buf.append('[');
1800 }
1801 if ((t & Frame.BASE_KIND) == Frame.OBJECT) {
1802 buf.append('L');
1803 buf.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1);
1804 buf.append(';');
1805 } else {
1806 switch (t & 0xF) {
1807 case 1:
1808 buf.append('I');
1809 break;
1810 case 2:
1811 buf.append('F');
1812 break;
1813 case 3:
1814 buf.append('D');
1815 break;
1816 case 9:
1817 buf.append('Z');
1818 break;
1819 case 10:
1820 buf.append('B');
1821 break;
1822 case 11:
1823 buf.append('C');
1824 break;
1825 case 12:
1826 buf.append('S');
1827 break;
1828 default:
1829 buf.append('J');
1830 }
1831 }
1832 stackMap.putByte(7).putShort(cw.newClass(buf.toString()));
1833 }
1834 }
1835 }
1836
1837 private void writeFrameType(final Object type) {
1838 if (type instanceof String) {
1839 stackMap.putByte(7).putShort(cw.newClass((String) type));
1840 } else if (type instanceof Integer) {
1841 stackMap.putByte(((Integer) type).intValue());
1842 } else {
1843 stackMap.putByte(8).putShort(((Label) type).position);
1844 }
1845 }
1846
1847 // ------------------------------------------------------------------------
1848 // Utility methods: dump bytecode array
1849 // ------------------------------------------------------------------------
1850
1851 /**
1852 * Returns the size of the bytecode of this method.
1853 *
1854 * @return the size of the bytecode of this method.
1855 */
1856 final int getSize() {
1857 if (classReaderOffset != 0) {
1858 return 6 + classReaderLength;
1859 }
1860 if (resize) {
1861 // replaces the temporary jump opcodes introduced by Label.resolve.
1862 if (ClassReader.RESIZE) {
1863 resizeInstructions();
1864 } else {
1865 throw new RuntimeException("Method code too large!");
1866 }
1867 }
1868 int size = 8;
1869 if (code.length > 0) {
1870 if (code.length > 65536) {
1871 throw new RuntimeException("Method code too large!");
1872 }
1873 cw.newUTF8("Code");
1874 size += 18 + code.length + 8 * handlerCount;
1875 if (localVar != null) {
1876 cw.newUTF8("LocalVariableTable");
1877 size += 8 + localVar.length;
1878 }
1879 if (localVarType != null) {
1880 cw.newUTF8("LocalVariableTypeTable");
1881 size += 8 + localVarType.length;
1882 }
1883 if (lineNumber != null) {
1884 cw.newUTF8("LineNumberTable");
1885 size += 8 + lineNumber.length;
1886 }
1887 if (stackMap != null) {
1888 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
1889 cw.newUTF8(zip ? "StackMapTable" : "StackMap");
1890 size += 8 + stackMap.length;
1891 }
1892 if (cattrs != null) {
1893 size += cattrs.getSize(cw, code.data, code.length, maxStack,
1894 maxLocals);
1895 }
1896 }
1897 if (exceptionCount > 0) {
1898 cw.newUTF8("Exceptions");
1899 size += 8 + 2 * exceptionCount;
1900 }
1901 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
1902 if ((cw.version & 0xFFFF) < Opcodes.V1_5
1903 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
1904 cw.newUTF8("Synthetic");
1905 size += 6;
1906 }
1907 }
1908 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1909 cw.newUTF8("Deprecated");
1910 size += 6;
1911 }
1912 if (ClassReader.SIGNATURES && signature != null) {
1913 cw.newUTF8("Signature");
1914 cw.newUTF8(signature);
1915 size += 8;
1916 }
1917 if (ClassReader.ANNOTATIONS && annd != null) {
1918 cw.newUTF8("AnnotationDefault");
1919 size += 6 + annd.length;
1920 }
1921 if (ClassReader.ANNOTATIONS && anns != null) {
1922 cw.newUTF8("RuntimeVisibleAnnotations");
1923 size += 8 + anns.getSize();
1924 }
1925 if (ClassReader.ANNOTATIONS && ianns != null) {
1926 cw.newUTF8("RuntimeInvisibleAnnotations");
1927 size += 8 + ianns.getSize();
1928 }
1929 if (ClassReader.ANNOTATIONS && panns != null) {
1930 cw.newUTF8("RuntimeVisibleParameterAnnotations");
1931 size += 7 + 2 * (panns.length - synthetics);
1932 for (int i = panns.length - 1; i >= synthetics; --i) {
1933 size += panns[i] == null ? 0 : panns[i].getSize();
1934 }
1935 }
1936 if (ClassReader.ANNOTATIONS && ipanns != null) {
1937 cw.newUTF8("RuntimeInvisibleParameterAnnotations");
1938 size += 7 + 2 * (ipanns.length - synthetics);
1939 for (int i = ipanns.length - 1; i >= synthetics; --i) {
1940 size += ipanns[i] == null ? 0 : ipanns[i].getSize();
1941 }
1942 }
1943 if (attrs != null) {
1944 size += attrs.getSize(cw, null, 0, -1, -1);
1945 }
1946 return size;
1947 }
1948
1949 /**
1950 * Puts the bytecode of this method in the given byte vector.
1951 *
1952 * @param out
1953 * the byte vector into which the bytecode of this method must be
1954 * copied.
1955 */
1956 final void put(final ByteVector out) {
1957 final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
1958 int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED
1959 | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
1960 | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
1961 out.putShort(access & ~mask).putShort(name).putShort(desc);
1962 if (classReaderOffset != 0) {
1963 out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
1964 return;
1965 }
1966 int attributeCount = 0;
1967 if (code.length > 0) {
1968 ++attributeCount;
1969 }
1970 if (exceptionCount > 0) {
1971 ++attributeCount;
1972 }
1973 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
1974 if ((cw.version & 0xFFFF) < Opcodes.V1_5
1975 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
1976 ++attributeCount;
1977 }
1978 }
1979 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1980 ++attributeCount;
1981 }
1982 if (ClassReader.SIGNATURES && signature != null) {
1983 ++attributeCount;
1984 }
1985 if (ClassReader.ANNOTATIONS && annd != null) {
1986 ++attributeCount;
1987 }
1988 if (ClassReader.ANNOTATIONS && anns != null) {
1989 ++attributeCount;
1990 }
1991 if (ClassReader.ANNOTATIONS && ianns != null) {
1992 ++attributeCount;
1993 }
1994 if (ClassReader.ANNOTATIONS && panns != null) {
1995 ++attributeCount;
1996 }
1997 if (ClassReader.ANNOTATIONS && ipanns != null) {
1998 ++attributeCount;
1999 }
2000 if (attrs != null) {
2001 attributeCount += attrs.getCount();
2002 }
2003 out.putShort(attributeCount);
2004 if (code.length > 0) {
2005 int size = 12 + code.length + 8 * handlerCount;
2006 if (localVar != null) {
2007 size += 8 + localVar.length;
2008 }
2009 if (localVarType != null) {
2010 size += 8 + localVarType.length;
2011 }
2012 if (lineNumber != null) {
2013 size += 8 + lineNumber.length;
2014 }
2015 if (stackMap != null) {
2016 size += 8 + stackMap.length;
2017 }
2018 if (cattrs != null) {
2019 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2020 maxLocals);
2021 }
2022 out.putShort(cw.newUTF8("Code")).putInt(size);
2023 out.putShort(maxStack).putShort(maxLocals);
2024 out.putInt(code.length).putByteArray(code.data, 0, code.length);
2025 out.putShort(handlerCount);
2026 if (handlerCount > 0) {
2027 Handler h = firstHandler;
2028 while (h != null) {
2029 out.putShort(h.start.position).putShort(h.end.position)
2030 .putShort(h.handler.position).putShort(h.type);
2031 h = h.next;
2032 }
2033 }
2034 attributeCount = 0;
2035 if (localVar != null) {
2036 ++attributeCount;
2037 }
2038 if (localVarType != null) {
2039 ++attributeCount;
2040 }
2041 if (lineNumber != null) {
2042 ++attributeCount;
2043 }
2044 if (stackMap != null) {
2045 ++attributeCount;
2046 }
2047 if (cattrs != null) {
2048 attributeCount += cattrs.getCount();
2049 }
2050 out.putShort(attributeCount);
2051 if (localVar != null) {
2052 out.putShort(cw.newUTF8("LocalVariableTable"));
2053 out.putInt(localVar.length + 2).putShort(localVarCount);
2054 out.putByteArray(localVar.data, 0, localVar.length);
2055 }
2056 if (localVarType != null) {
2057 out.putShort(cw.newUTF8("LocalVariableTypeTable"));
2058 out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
2059 out.putByteArray(localVarType.data, 0, localVarType.length);
2060 }
2061 if (lineNumber != null) {
2062 out.putShort(cw.newUTF8("LineNumberTable"));
2063 out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
2064 out.putByteArray(lineNumber.data, 0, lineNumber.length);
2065 }
2066 if (stackMap != null) {
2067 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2068 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap"));
2069 out.putInt(stackMap.length + 2).putShort(frameCount);
2070 out.putByteArray(stackMap.data, 0, stackMap.length);
2071 }
2072 if (cattrs != null) {
2073 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
2074 }
2075 }
2076 if (exceptionCount > 0) {
2077 out.putShort(cw.newUTF8("Exceptions")).putInt(
2078 2 * exceptionCount + 2);
2079 out.putShort(exceptionCount);
2080 for (int i = 0; i < exceptionCount; ++i) {
2081 out.putShort(exceptions[i]);
2082 }
2083 }
2084 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2085 if ((cw.version & 0xFFFF) < Opcodes.V1_5
2086 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2087 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
2088 }
2089 }
2090 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2091 out.putShort(cw.newUTF8("Deprecated")).putInt(0);
2092 }
2093 if (ClassReader.SIGNATURES && signature != null) {
2094 out.putShort(cw.newUTF8("Signature")).putInt(2)
2095 .putShort(cw.newUTF8(signature));
2096 }
2097 if (ClassReader.ANNOTATIONS && annd != null) {
2098 out.putShort(cw.newUTF8("AnnotationDefault"));
2099 out.putInt(annd.length);
2100 out.putByteArray(annd.data, 0, annd.length);
2101 }
2102 if (ClassReader.ANNOTATIONS && anns != null) {
2103 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
2104 anns.put(out);
2105 }
2106 if (ClassReader.ANNOTATIONS && ianns != null) {
2107 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
2108 ianns.put(out);
2109 }
2110 if (ClassReader.ANNOTATIONS && panns != null) {
2111 out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
2112 AnnotationWriter.put(panns, synthetics, out);
2113 }
2114 if (ClassReader.ANNOTATIONS && ipanns != null) {
2115 out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
2116 AnnotationWriter.put(ipanns, synthetics, out);
2117 }
2118 if (attrs != null) {
2119 attrs.put(cw, null, 0, -1, -1, out);
2120 }
2121 }
2122
2123 // ------------------------------------------------------------------------
2124 // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
2125 // ------------------------------------------------------------------------
2126
2127 /**
2128 * Resizes and replaces the temporary instructions inserted by
2129 * {@link Label#resolve} for wide forward jumps, while keeping jump offsets
2130 * and instruction addresses consistent. This may require to resize other
2131 * existing instructions, or even to introduce new instructions: for
2132 * example, increasing the size of an instruction by 2 at the middle of a
2133 * method can increases the offset of an IFEQ instruction from 32766 to
2134 * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
2135 * 32765. This, in turn, may require to increase the size of another jump
2136 * instruction, and so on... All these operations are handled automatically
2137 * by this method.
2138 * <p>
2139 * <i>This method must be called after all the method that is being built
2140 * has been visited</i>. In particular, the {@link Label Label} objects used
2141 * to construct the method are no longer valid after this method has been
2142 * called.
2143 */
2144 private void resizeInstructions() {
2145 byte[] b = code.data; // bytecode of the method
2146 int u, v, label; // indexes in b
2147 int i, j; // loop indexes
2148 /*
2149 * 1st step: As explained above, resizing an instruction may require to
2150 * resize another one, which may require to resize yet another one, and
2151 * so on. The first step of the algorithm consists in finding all the
2152 * instructions that need to be resized, without modifying the code.
2153 * This is done by the following "fix point" algorithm:
2154 *
2155 * Parse the code to find the jump instructions whose offset will need
2156 * more than 2 bytes to be stored (the future offset is computed from
2157 * the current offset and from the number of bytes that will be inserted
2158 * or removed between the source and target instructions). For each such
2159 * instruction, adds an entry in (a copy of) the indexes and sizes
2160 * arrays (if this has not already been done in a previous iteration!).
2161 *
2162 * If at least one entry has been added during the previous step, go
2163 * back to the beginning, otherwise stop.
2164 *
2165 * In fact the real algorithm is complicated by the fact that the size
2166 * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
2167 * position in the bytecode (because of padding). In order to ensure the
2168 * convergence of the algorithm, the number of bytes to be added or
2169 * removed from these instructions is over estimated during the previous
2170 * loop, and computed exactly only after the loop is finished (this
2171 * requires another pass to parse the bytecode of the method).
2172 */
2173 int[] allIndexes = new int[0]; // copy of indexes
2174 int[] allSizes = new int[0]; // copy of sizes
2175 boolean[] resize; // instructions to be resized
2176 int newOffset; // future offset of a jump instruction
2177
2178 resize = new boolean[code.length];
2179
2180 // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
2181 int state = 3;
2182 do {
2183 if (state == 3) {
2184 state = 2;
2185 }
2186 u = 0;
2187 while (u < b.length) {
2188 int opcode = b[u] & 0xFF; // opcode of current instruction
2189 int insert = 0; // bytes to be added after this instruction
2190
2191 switch (ClassWriter.TYPE[opcode]) {
2192 case ClassWriter.NOARG_INSN:
2193 case ClassWriter.IMPLVAR_INSN:
2194 u += 1;
2195 break;
2196 case ClassWriter.LABEL_INSN:
2197 if (opcode > 201) {
2198 // converts temporary opcodes 202 to 217, 218 and
2199 // 219 to IFEQ ... JSR (inclusive), IFNULL and
2200 // IFNONNULL
2201 opcode = opcode < 218 ? opcode - 49 : opcode - 20;
2202 label = u + readUnsignedShort(b, u + 1);
2203 } else {
2204 label = u + readShort(b, u + 1);
2205 }
2206 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2207 if (newOffset < Short.MIN_VALUE
2208 || newOffset > Short.MAX_VALUE) {
2209 if (!resize[u]) {
2210 if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
2211 // two additional bytes will be required to
2212 // replace this GOTO or JSR instruction with
2213 // a GOTO_W or a JSR_W
2214 insert = 2;
2215 } else {
2216 // five additional bytes will be required to
2217 // replace this IFxxx <l> instruction with
2218 // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
2219 // is the "opposite" opcode of IFxxx (i.e.,
2220 // IFNE for IFEQ) and where <l'> designates
2221 // the instruction just after the GOTO_W.
2222 insert = 5;
2223 }
2224 resize[u] = true;
2225 }
2226 }
2227 u += 3;
2228 break;
2229 case ClassWriter.LABELW_INSN:
2230 u += 5;
2231 break;
2232 case ClassWriter.TABL_INSN:
2233 if (state == 1) {
2234 // true number of bytes to be added (or removed)
2235 // from this instruction = (future number of padding
2236 // bytes - current number of padding byte) -
2237 // previously over estimated variation =
2238 // = ((3 - newOffset%4) - (3 - u%4)) - u%4
2239 // = (-newOffset%4 + u%4) - u%4
2240 // = -(newOffset & 3)
2241 newOffset = getNewOffset(allIndexes, allSizes, 0, u);
2242 insert = -(newOffset & 3);
2243 } else if (!resize[u]) {
2244 // over estimation of the number of bytes to be
2245 // added to this instruction = 3 - current number
2246 // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
2247 insert = u & 3;
2248 resize[u] = true;
2249 }
2250 // skips instruction
2251 u = u + 4 - (u & 3);
2252 u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
2253 break;
2254 case ClassWriter.LOOK_INSN:
2255 if (state == 1) {
2256 // like TABL_INSN
2257 newOffset = getNewOffset(allIndexes, allSizes, 0, u);
2258 insert = -(newOffset & 3);
2259 } else if (!resize[u]) {
2260 // like TABL_INSN
2261 insert = u & 3;
2262 resize[u] = true;
2263 }
2264 // skips instruction
2265 u = u + 4 - (u & 3);
2266 u += 8 * readInt(b, u + 4) + 8;
2267 break;
2268 case ClassWriter.WIDE_INSN:
2269 opcode = b[u + 1] & 0xFF;
2270 if (opcode == Opcodes.IINC) {
2271 u += 6;
2272 } else {
2273 u += 4;
2274 }
2275 break;
2276 case ClassWriter.VAR_INSN:
2277 case ClassWriter.SBYTE_INSN:
2278 case ClassWriter.LDC_INSN:
2279 u += 2;
2280 break;
2281 case ClassWriter.SHORT_INSN:
2282 case ClassWriter.LDCW_INSN:
2283 case ClassWriter.FIELDORMETH_INSN:
2284 case ClassWriter.TYPE_INSN:
2285 case ClassWriter.IINC_INSN:
2286 u += 3;
2287 break;
2288 case ClassWriter.ITFMETH_INSN:
2289 case ClassWriter.INDYMETH_INSN:
2290 u += 5;
2291 break;
2292 // case ClassWriter.MANA_INSN:
2293 default:
2294 u += 4;
2295 break;
2296 }
2297 if (insert != 0) {
2298 // adds a new (u, insert) entry in the allIndexes and
2299 // allSizes arrays
2300 int[] newIndexes = new int[allIndexes.length + 1];
2301 int[] newSizes = new int[allSizes.length + 1];
2302 System.arraycopy(allIndexes, 0, newIndexes, 0,
2303 allIndexes.length);
2304 System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
2305 newIndexes[allIndexes.length] = u;
2306 newSizes[allSizes.length] = insert;
2307 allIndexes = newIndexes;
2308 allSizes = newSizes;
2309 if (insert > 0) {
2310 state = 3;
2311 }
2312 }
2313 }
2314 if (state < 3) {
2315 --state;
2316 }
2317 } while (state != 0);
2318
2319 // 2nd step:
2320 // copies the bytecode of the method into a new bytevector, updates the
2321 // offsets, and inserts (or removes) bytes as requested.
2322
2323 ByteVector newCode = new ByteVector(code.length);
2324
2325 u = 0;
2326 while (u < code.length) {
2327 int opcode = b[u] & 0xFF;
2328 switch (ClassWriter.TYPE[opcode]) {
2329 case ClassWriter.NOARG_INSN:
2330 case ClassWriter.IMPLVAR_INSN:
2331 newCode.putByte(opcode);
2332 u += 1;
2333 break;
2334 case ClassWriter.LABEL_INSN:
2335 if (opcode > 201) {
2336 // changes temporary opcodes 202 to 217 (inclusive), 218
2337 // and 219 to IFEQ ... JSR (inclusive), IFNULL and
2338 // IFNONNULL
2339 opcode = opcode < 218 ? opcode - 49 : opcode - 20;
2340 label = u + readUnsignedShort(b, u + 1);
2341 } else {
2342 label = u + readShort(b, u + 1);
2343 }
2344 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2345 if (resize[u]) {
2346 // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
2347 // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
2348 // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
2349 // and where <l'> designates the instruction just after
2350 // the GOTO_W.
2351 if (opcode == Opcodes.GOTO) {
2352 newCode.putByte(200); // GOTO_W
2353 } else if (opcode == Opcodes.JSR) {
2354 newCode.putByte(201); // JSR_W
2355 } else {
2356 newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
2357 : opcode ^ 1);
2358 newCode.putShort(8); // jump offset
2359 newCode.putByte(200); // GOTO_W
2360 // newOffset now computed from start of GOTO_W
2361 newOffset -= 3;
2362 }
2363 newCode.putInt(newOffset);
2364 } else {
2365 newCode.putByte(opcode);
2366 newCode.putShort(newOffset);
2367 }
2368 u += 3;
2369 break;
2370 case ClassWriter.LABELW_INSN:
2371 label = u + readInt(b, u + 1);
2372 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2373 newCode.putByte(opcode);
2374 newCode.putInt(newOffset);
2375 u += 5;
2376 break;
2377 case ClassWriter.TABL_INSN:
2378 // skips 0 to 3 padding bytes
2379 v = u;
2380 u = u + 4 - (v & 3);
2381 // reads and copies instruction
2382 newCode.putByte(Opcodes.TABLESWITCH);
2383 newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4);
2384 label = v + readInt(b, u);
2385 u += 4;
2386 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2387 newCode.putInt(newOffset);
2388 j = readInt(b, u);
2389 u += 4;
2390 newCode.putInt(j);
2391 j = readInt(b, u) - j + 1;
2392 u += 4;
2393 newCode.putInt(readInt(b, u - 4));
2394 for (; j > 0; --j) {
2395 label = v + readInt(b, u);
2396 u += 4;
2397 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2398 newCode.putInt(newOffset);
2399 }
2400 break;
2401 case ClassWriter.LOOK_INSN:
2402 // skips 0 to 3 padding bytes
2403 v = u;
2404 u = u + 4 - (v & 3);
2405 // reads and copies instruction
2406 newCode.putByte(Opcodes.LOOKUPSWITCH);
2407 newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4);
2408 label = v + readInt(b, u);
2409 u += 4;
2410 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2411 newCode.putInt(newOffset);
2412 j = readInt(b, u);
2413 u += 4;
2414 newCode.putInt(j);
2415 for (; j > 0; --j) {
2416 newCode.putInt(readInt(b, u));
2417 u += 4;
2418 label = v + readInt(b, u);
2419 u += 4;
2420 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2421 newCode.putInt(newOffset);
2422 }
2423 break;
2424 case ClassWriter.WIDE_INSN:
2425 opcode = b[u + 1] & 0xFF;
2426 if (opcode == Opcodes.IINC) {
2427 newCode.putByteArray(b, u, 6);
2428 u += 6;
2429 } else {
2430 newCode.putByteArray(b, u, 4);
2431 u += 4;
2432 }
2433 break;
2434 case ClassWriter.VAR_INSN:
2435 case ClassWriter.SBYTE_INSN:
2436 case ClassWriter.LDC_INSN:
2437 newCode.putByteArray(b, u, 2);
2438 u += 2;
2439 break;
2440 case ClassWriter.SHORT_INSN:
2441 case ClassWriter.LDCW_INSN:
2442 case ClassWriter.FIELDORMETH_INSN:
2443 case ClassWriter.TYPE_INSN:
2444 case ClassWriter.IINC_INSN:
2445 newCode.putByteArray(b, u, 3);
2446 u += 3;
2447 break;
2448 case ClassWriter.ITFMETH_INSN:
2449 case ClassWriter.INDYMETH_INSN:
2450 newCode.putByteArray(b, u, 5);
2451 u += 5;
2452 break;
2453 // case MANA_INSN:
2454 default:
2455 newCode.putByteArray(b, u, 4);
2456 u += 4;
2457 break;
2458 }
2459 }
2460
2461 // recomputes the stack map frames
2462 if (frameCount > 0) {
2463 if (compute == FRAMES) {
2464 frameCount = 0;
2465 stackMap = null;
2466 previousFrame = null;
2467 frame = null;
2468 Frame f = new Frame();
2469 f.owner = labels;
2470 Type[] args = Type.getArgumentTypes(descriptor);
2471 f.initInputFrame(cw, access, args, maxLocals);
2472 visitFrame(f);
2473 Label l = labels;
2474 while (l != null) {
2475 /*
2476 * here we need the original label position. getNewOffset
2477 * must therefore never have been called for this label.
2478 */
2479 u = l.position - 3;
2480 if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) {
2481 getNewOffset(allIndexes, allSizes, l);
2482 // TODO update offsets in UNINITIALIZED values
2483 visitFrame(l.frame);
2484 }
2485 l = l.successor;
2486 }
2487 } else {
2488 /*
2489 * Resizing an existing stack map frame table is really hard.
2490 * Not only the table must be parsed to update the offets, but
2491 * new frames may be needed for jump instructions that were
2492 * inserted by this method. And updating the offsets or
2493 * inserting frames can change the format of the following
2494 * frames, in case of packed frames. In practice the whole table
2495 * must be recomputed. For this the frames are marked as
2496 * potentially invalid. This will cause the whole class to be
2497 * reread and rewritten with the COMPUTE_FRAMES option (see the
2498 * ClassWriter.toByteArray method). This is not very efficient
2499 * but is much easier and requires much less code than any other
2500 * method I can think of.
2501 */
2502 cw.invalidFrames = true;
2503 }
2504 }
2505 // updates the exception handler block labels
2506 Handler h = firstHandler;
2507 while (h != null) {
2508 getNewOffset(allIndexes, allSizes, h.start);
2509 getNewOffset(allIndexes, allSizes, h.end);
2510 getNewOffset(allIndexes, allSizes, h.handler);
2511 h = h.next;
2512 }
2513 // updates the instructions addresses in the
2514 // local var and line number tables
2515 for (i = 0; i < 2; ++i) {
2516 ByteVector bv = i == 0 ? localVar : localVarType;
2517 if (bv != null) {
2518 b = bv.data;
2519 u = 0;
2520 while (u < bv.length) {
2521 label = readUnsignedShort(b, u);
2522 newOffset = getNewOffset(allIndexes, allSizes, 0, label);
2523 writeShort(b, u, newOffset);
2524 label += readUnsignedShort(b, u + 2);
2525 newOffset = getNewOffset(allIndexes, allSizes, 0, label)
2526 - newOffset;
2527 writeShort(b, u + 2, newOffset);
2528 u += 10;
2529 }
2530 }
2531 }
2532 if (lineNumber != null) {
2533 b = lineNumber.data;
2534 u = 0;
2535 while (u < lineNumber.length) {
2536 writeShort(
2537 b,
2538 u,
2539 getNewOffset(allIndexes, allSizes, 0,
2540 readUnsignedShort(b, u)));
2541 u += 4;
2542 }
2543 }
2544 // updates the labels of the other attributes
2545 Attribute attr = cattrs;
2546 while (attr != null) {
2547 Label[] labels = attr.getLabels();
2548 if (labels != null) {
2549 for (i = labels.length - 1; i >= 0; --i) {
2550 getNewOffset(allIndexes, allSizes, labels[i]);
2551 }
2552 }
2553 attr = attr.next;
2554 }
2555
2556 // replaces old bytecodes with new ones
2557 code = newCode;
2558 }
2559
2560 /**
2561 * Reads an unsigned short value in the given byte array.
2562 *
2563 * @param b
2564 * a byte array.
2565 * @param index
2566 * the start index of the value to be read.
2567 * @return the read value.
2568 */
2569 static int readUnsignedShort(final byte[] b, final int index) {
2570 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
2571 }
2572
2573 /**
2574 * Reads a signed short value in the given byte array.
2575 *
2576 * @param b
2577 * a byte array.
2578 * @param index
2579 * the start index of the value to be read.
2580 * @return the read value.
2581 */
2582 static short readShort(final byte[] b, final int index) {
2583 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
2584 }
2585
2586 /**
2587 * Reads a signed int value in the given byte array.
2588 *
2589 * @param b
2590 * a byte array.
2591 * @param index
2592 * the start index of the value to be read.
2593 * @return the read value.
2594 */
2595 static int readInt(final byte[] b, final int index) {
2596 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
2597 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
2598 }
2599
2600 /**
2601 * Writes a short value in the given byte array.
2602 *
2603 * @param b
2604 * a byte array.
2605 * @param index
2606 * where the first byte of the short value must be written.
2607 * @param s
2608 * the value to be written in the given byte array.
2609 */
2610 static void writeShort(final byte[] b, final int index, final int s) {
2611 b[index] = (byte) (s >>> 8);
2612 b[index + 1] = (byte) s;
2613 }
2614
2615 /**
2616 * Computes the future value of a bytecode offset.
2617 * <p>
2618 * Note: it is possible to have several entries for the same instruction in
2619 * the <tt>indexes</tt> and <tt>sizes</tt>: two entries (index=a,size=b) and
2620 * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b').
2621 *
2622 * @param indexes
2623 * current positions of the instructions to be resized. Each
2624 * instruction must be designated by the index of its <i>last</i>
2625 * byte, plus one (or, in other words, by the index of the
2626 * <i>first</i> byte of the <i>next</i> instruction).
2627 * @param sizes
2628 * the number of bytes to be <i>added</i> to the above
2629 * instructions. More precisely, for each i < <tt>len</tt>,
2630 * <tt>sizes</tt>[i] bytes will be added at the end of the
2631 * instruction designated by <tt>indexes</tt>[i] or, if
2632 * <tt>sizes</tt>[i] is negative, the <i>last</i> |
2633 * <tt>sizes[i]</tt>| bytes of the instruction will be removed
2634 * (the instruction size <i>must not</i> become negative or
2635 * null).
2636 * @param begin
2637 * index of the first byte of the source instruction.
2638 * @param end
2639 * index of the first byte of the target instruction.
2640 * @return the future value of the given bytecode offset.
2641 */
2642 static int getNewOffset(final int[] indexes, final int[] sizes,
2643 final int begin, final int end) {
2644 int offset = end - begin;
2645 for (int i = 0; i < indexes.length; ++i) {
2646 if (begin < indexes[i] && indexes[i] <= end) {
2647 // forward jump
2648 offset += sizes[i];
2649 } else if (end < indexes[i] && indexes[i] <= begin) {
2650 // backward jump
2651 offset -= sizes[i];
2652 }
2653 }
2654 return offset;
2655 }
2656
2657 /**
2658 * Updates the offset of the given label.
2659 *
2660 * @param indexes
2661 * current positions of the instructions to be resized. Each
2662 * instruction must be designated by the index of its <i>last</i>
2663 * byte, plus one (or, in other words, by the index of the
2664 * <i>first</i> byte of the <i>next</i> instruction).
2665 * @param sizes
2666 * the number of bytes to be <i>added</i> to the above
2667 * instructions. More precisely, for each i < <tt>len</tt>,
2668 * <tt>sizes</tt>[i] bytes will be added at the end of the
2669 * instruction designated by <tt>indexes</tt>[i] or, if
2670 * <tt>sizes</tt>[i] is negative, the <i>last</i> |
2671 * <tt>sizes[i]</tt>| bytes of the instruction will be removed
2672 * (the instruction size <i>must not</i> become negative or
2673 * null).
2674 * @param label
2675 * the label whose offset must be updated.
2676 */
2677 static void getNewOffset(final int[] indexes, final int[] sizes,
2678 final Label label) {
2679 if ((label.status & Label.RESIZED) == 0) {
2680 label.position = getNewOffset(indexes, sizes, 0, label.position);
2681 label.status |= Label.RESIZED;
2682 }
2683 }
2684 }
+0
-358
src/jvm/clojure/asm/Opcodes.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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 // ASM API versions
46
47 int ASM4 = 4 << 16 | 0 << 8 | 0;
48
49 // versions
50
51 int V1_1 = 3 << 16 | 45;
52 int V1_2 = 0 << 16 | 46;
53 int V1_3 = 0 << 16 | 47;
54 int V1_4 = 0 << 16 | 48;
55 int V1_5 = 0 << 16 | 49;
56 int V1_6 = 0 << 16 | 50;
57 int V1_7 = 0 << 16 | 51;
58
59 // access flags
60
61 int ACC_PUBLIC = 0x0001; // class, field, method
62 int ACC_PRIVATE = 0x0002; // class, field, method
63 int ACC_PROTECTED = 0x0004; // class, field, method
64 int ACC_STATIC = 0x0008; // field, method
65 int ACC_FINAL = 0x0010; // class, field, method
66 int ACC_SUPER = 0x0020; // class
67 int ACC_SYNCHRONIZED = 0x0020; // method
68 int ACC_VOLATILE = 0x0040; // field
69 int ACC_BRIDGE = 0x0040; // method
70 int ACC_VARARGS = 0x0080; // method
71 int ACC_TRANSIENT = 0x0080; // field
72 int ACC_NATIVE = 0x0100; // method
73 int ACC_INTERFACE = 0x0200; // class
74 int ACC_ABSTRACT = 0x0400; // class, method
75 int ACC_STRICT = 0x0800; // method
76 int ACC_SYNTHETIC = 0x1000; // class, field, method
77 int ACC_ANNOTATION = 0x2000; // class
78 int ACC_ENUM = 0x4000; // class(?) field inner
79
80 // ASM specific pseudo access flags
81
82 int ACC_DEPRECATED = 0x20000; // class, field, method
83
84 // types for NEWARRAY
85
86 int T_BOOLEAN = 4;
87 int T_CHAR = 5;
88 int T_FLOAT = 6;
89 int T_DOUBLE = 7;
90 int T_BYTE = 8;
91 int T_SHORT = 9;
92 int T_INT = 10;
93 int T_LONG = 11;
94
95 // tags for Handle
96
97 int H_GETFIELD = 1;
98 int H_GETSTATIC = 2;
99 int H_PUTFIELD = 3;
100 int H_PUTSTATIC = 4;
101 int H_INVOKEVIRTUAL = 5;
102 int H_INVOKESTATIC = 6;
103 int H_INVOKESPECIAL = 7;
104 int H_NEWINVOKESPECIAL = 8;
105 int H_INVOKEINTERFACE = 9;
106
107 // stack map frame types
108
109 /**
110 * Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}.
111 */
112 int F_NEW = -1;
113
114 /**
115 * Represents a compressed frame with complete frame data.
116 */
117 int F_FULL = 0;
118
119 /**
120 * Represents a compressed frame where locals are the same as the locals in
121 * the previous frame, except that additional 1-3 locals are defined, and
122 * with an empty stack.
123 */
124 int F_APPEND = 1;
125
126 /**
127 * Represents a compressed frame where locals are the same as the locals in
128 * the previous frame, except that the last 1-3 locals are absent and with
129 * an empty stack.
130 */
131 int F_CHOP = 2;
132
133 /**
134 * Represents a compressed frame with exactly the same locals as the
135 * previous frame and with an empty stack.
136 */
137 int F_SAME = 3;
138
139 /**
140 * Represents a compressed frame with exactly the same locals as the
141 * previous frame and with a single value on the stack.
142 */
143 int F_SAME1 = 4;
144
145 Integer TOP = new Integer(0);
146 Integer INTEGER = new Integer(1);
147 Integer FLOAT = new Integer(2);
148 Integer DOUBLE = new Integer(3);
149 Integer LONG = new Integer(4);
150 Integer NULL = new Integer(5);
151 Integer UNINITIALIZED_THIS = new Integer(6);
152
153 // opcodes // visit method (- = idem)
154
155 int NOP = 0; // visitInsn
156 int ACONST_NULL = 1; // -
157 int ICONST_M1 = 2; // -
158 int ICONST_0 = 3; // -
159 int ICONST_1 = 4; // -
160 int ICONST_2 = 5; // -
161 int ICONST_3 = 6; // -
162 int ICONST_4 = 7; // -
163 int ICONST_5 = 8; // -
164 int LCONST_0 = 9; // -
165 int LCONST_1 = 10; // -
166 int FCONST_0 = 11; // -
167 int FCONST_1 = 12; // -
168 int FCONST_2 = 13; // -
169 int DCONST_0 = 14; // -
170 int DCONST_1 = 15; // -
171 int BIPUSH = 16; // visitIntInsn
172 int SIPUSH = 17; // -
173 int LDC = 18; // visitLdcInsn
174 // int LDC_W = 19; // -
175 // int LDC2_W = 20; // -
176 int ILOAD = 21; // visitVarInsn
177 int LLOAD = 22; // -
178 int FLOAD = 23; // -
179 int DLOAD = 24; // -
180 int ALOAD = 25; // -
181 // int ILOAD_0 = 26; // -
182 // int ILOAD_1 = 27; // -
183 // int ILOAD_2 = 28; // -
184 // int ILOAD_3 = 29; // -
185 // int LLOAD_0 = 30; // -
186 // int LLOAD_1 = 31; // -
187 // int LLOAD_2 = 32; // -
188 // int LLOAD_3 = 33; // -
189 // int FLOAD_0 = 34; // -
190 // int FLOAD_1 = 35; // -
191 // int FLOAD_2 = 36; // -
192 // int FLOAD_3 = 37; // -
193 // int DLOAD_0 = 38; // -
194 // int DLOAD_1 = 39; // -
195 // int DLOAD_2 = 40; // -
196 // int DLOAD_3 = 41; // -
197 // int ALOAD_0 = 42; // -
198 // int ALOAD_1 = 43; // -
199 // int ALOAD_2 = 44; // -
200 // int ALOAD_3 = 45; // -
201 int IALOAD = 46; // visitInsn
202 int LALOAD = 47; // -
203 int FALOAD = 48; // -
204 int DALOAD = 49; // -
205 int AALOAD = 50; // -
206 int BALOAD = 51; // -
207 int CALOAD = 52; // -
208 int SALOAD = 53; // -
209 int ISTORE = 54; // visitVarInsn
210 int LSTORE = 55; // -
211 int FSTORE = 56; // -
212 int DSTORE = 57; // -
213 int ASTORE = 58; // -
214 // int ISTORE_0 = 59; // -
215 // int ISTORE_1 = 60; // -
216 // int ISTORE_2 = 61; // -
217 // int ISTORE_3 = 62; // -
218 // int LSTORE_0 = 63; // -
219 // int LSTORE_1 = 64; // -
220 // int LSTORE_2 = 65; // -
221 // int LSTORE_3 = 66; // -
222 // int FSTORE_0 = 67; // -
223 // int FSTORE_1 = 68; // -
224 // int FSTORE_2 = 69; // -
225 // int FSTORE_3 = 70; // -
226 // int DSTORE_0 = 71; // -
227 // int DSTORE_1 = 72; // -
228 // int DSTORE_2 = 73; // -
229 // int DSTORE_3 = 74; // -
230 // int ASTORE_0 = 75; // -
231 // int ASTORE_1 = 76; // -
232 // int ASTORE_2 = 77; // -
233 // int ASTORE_3 = 78; // -
234 int IASTORE = 79; // visitInsn
235 int LASTORE = 80; // -
236 int FASTORE = 81; // -
237 int DASTORE = 82; // -
238 int AASTORE = 83; // -
239 int BASTORE = 84; // -
240 int CASTORE = 85; // -
241 int SASTORE = 86; // -
242 int POP = 87; // -
243 int POP2 = 88; // -
244 int DUP = 89; // -
245 int DUP_X1 = 90; // -
246 int DUP_X2 = 91; // -
247 int DUP2 = 92; // -
248 int DUP2_X1 = 93; // -
249 int DUP2_X2 = 94; // -
250 int SWAP = 95; // -
251 int IADD = 96; // -
252 int LADD = 97; // -
253 int FADD = 98; // -
254 int DADD = 99; // -
255 int ISUB = 100; // -
256 int LSUB = 101; // -
257 int FSUB = 102; // -
258 int DSUB = 103; // -
259 int IMUL = 104; // -
260 int LMUL = 105; // -
261 int FMUL = 106; // -
262 int DMUL = 107; // -
263 int IDIV = 108; // -
264 int LDIV = 109; // -
265 int FDIV = 110; // -
266 int DDIV = 111; // -
267 int IREM = 112; // -
268 int LREM = 113; // -
269 int FREM = 114; // -
270 int DREM = 115; // -
271 int INEG = 116; // -
272 int LNEG = 117; // -
273 int FNEG = 118; // -
274 int DNEG = 119; // -
275 int ISHL = 120; // -
276 int LSHL = 121; // -
277 int ISHR = 122; // -
278 int LSHR = 123; // -
279 int IUSHR = 124; // -
280 int LUSHR = 125; // -
281 int IAND = 126; // -
282 int LAND = 127; // -
283 int IOR = 128; // -
284 int LOR = 129; // -
285 int IXOR = 130; // -
286 int LXOR = 131; // -
287 int IINC = 132; // visitIincInsn
288 int I2L = 133; // visitInsn
289 int I2F = 134; // -
290 int I2D = 135; // -
291 int L2I = 136; // -
292 int L2F = 137; // -
293 int L2D = 138; // -
294 int F2I = 139; // -
295 int F2L = 140; // -
296 int F2D = 141; // -
297 int D2I = 142; // -
298 int D2L = 143; // -
299 int D2F = 144; // -
300 int I2B = 145; // -
301 int I2C = 146; // -
302 int I2S = 147; // -
303 int LCMP = 148; // -
304 int FCMPL = 149; // -
305 int FCMPG = 150; // -
306 int DCMPL = 151; // -
307 int DCMPG = 152; // -
308 int IFEQ = 153; // visitJumpInsn
309 int IFNE = 154; // -
310 int IFLT = 155; // -
311 int IFGE = 156; // -
312 int IFGT = 157; // -
313 int IFLE = 158; // -
314 int IF_ICMPEQ = 159; // -
315 int IF_ICMPNE = 160; // -
316 int IF_ICMPLT = 161; // -
317 int IF_ICMPGE = 162; // -
318 int IF_ICMPGT = 163; // -
319 int IF_ICMPLE = 164; // -
320 int IF_ACMPEQ = 165; // -
321 int IF_ACMPNE = 166; // -
322 int GOTO = 167; // -
323 int JSR = 168; // -
324 int RET = 169; // visitVarInsn
325 int TABLESWITCH = 170; // visiTableSwitchInsn
326 int LOOKUPSWITCH = 171; // visitLookupSwitch
327 int IRETURN = 172; // visitInsn
328 int LRETURN = 173; // -
329 int FRETURN = 174; // -
330 int DRETURN = 175; // -
331 int ARETURN = 176; // -
332 int RETURN = 177; // -
333 int GETSTATIC = 178; // visitFieldInsn
334 int PUTSTATIC = 179; // -
335 int GETFIELD = 180; // -
336 int PUTFIELD = 181; // -
337 int INVOKEVIRTUAL = 182; // visitMethodInsn
338 int INVOKESPECIAL = 183; // -
339 int INVOKESTATIC = 184; // -
340 int INVOKEINTERFACE = 185; // -
341 int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
342 int NEW = 187; // visitTypeInsn
343 int NEWARRAY = 188; // visitIntInsn
344 int ANEWARRAY = 189; // visitTypeInsn
345 int ARRAYLENGTH = 190; // visitInsn
346 int ATHROW = 191; // -
347 int CHECKCAST = 192; // visitTypeInsn
348 int INSTANCEOF = 193; // -
349 int MONITORENTER = 194; // visitInsn
350 int MONITOREXIT = 195; // -
351 // int WIDE = 196; // NOT VISITED
352 int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
353 int IFNULL = 198; // visitJumpInsn
354 int IFNONNULL = 199; // -
355 // int GOTO_W = 200; // -
356 // int JSR_W = 201; // -
357 }
+0
-895
src/jvm/clojure/asm/Type.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package clojure.asm;
30
31 import java.lang.reflect.Constructor;
32 import java.lang.reflect.Method;
33
34 /**
35 * A Java field or method type. This class can be used to make it easier to
36 * manipulate type and 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 static final int VOID = 0;
47
48 /**
49 * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
50 */
51 public static final int BOOLEAN = 1;
52
53 /**
54 * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
55 */
56 public static final int CHAR = 2;
57
58 /**
59 * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
60 */
61 public static final int BYTE = 3;
62
63 /**
64 * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
65 */
66 public static final int SHORT = 4;
67
68 /**
69 * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
70 */
71 public static final int INT = 5;
72
73 /**
74 * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
75 */
76 public static final int FLOAT = 6;
77
78 /**
79 * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
80 */
81 public static final int LONG = 7;
82
83 /**
84 * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
85 */
86 public static final int DOUBLE = 8;
87
88 /**
89 * The sort of array reference types. See {@link #getSort getSort}.
90 */
91 public static final int ARRAY = 9;
92
93 /**
94 * The sort of object reference types. See {@link #getSort getSort}.
95 */
96 public static final int OBJECT = 10;
97
98 /**
99 * The sort of method types. See {@link #getSort getSort}.
100 */
101 public static final int METHOD = 11;
102
103 /**
104 * The <tt>void</tt> type.
105 */
106 public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
107 | (5 << 16) | (0 << 8) | 0, 1);
108
109 /**
110 * The <tt>boolean</tt> type.
111 */
112 public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
113 | (0 << 16) | (5 << 8) | 1, 1);
114
115 /**
116 * The <tt>char</tt> type.
117 */
118 public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
119 | (0 << 16) | (6 << 8) | 1, 1);
120
121 /**
122 * The <tt>byte</tt> type.
123 */
124 public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
125 | (0 << 16) | (5 << 8) | 1, 1);
126
127 /**
128 * The <tt>short</tt> type.
129 */
130 public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
131 | (0 << 16) | (7 << 8) | 1, 1);
132
133 /**
134 * The <tt>int</tt> type.
135 */
136 public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
137 | (0 << 16) | (0 << 8) | 1, 1);
138
139 /**
140 * The <tt>float</tt> type.
141 */
142 public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
143 | (2 << 16) | (2 << 8) | 1, 1);
144
145 /**
146 * The <tt>long</tt> type.
147 */
148 public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
149 | (1 << 16) | (1 << 8) | 2, 1);
150
151 /**
152 * The <tt>double</tt> type.
153 */
154 public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
155 | (3 << 16) | (3 << 8) | 2, 1);
156
157 // ------------------------------------------------------------------------
158 // Fields
159 // ------------------------------------------------------------------------
160
161 /**
162 * The sort of this Java type.
163 */
164 private final int sort;
165
166 /**
167 * A buffer containing the internal name of this Java type. This field is
168 * only used for reference types.
169 */
170 private final char[] buf;
171
172 /**
173 * The offset of the internal name of this Java type in {@link #buf buf} or,
174 * for primitive types, the size, descriptor and getOpcode offsets for this
175 * type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset
176 * for IALOAD or IASTORE, byte 3 the offset for all other instructions).
177 */
178 private final int off;
179
180 /**
181 * The length of the internal name of this Java type.
182 */
183 private final int len;
184
185 // ------------------------------------------------------------------------
186 // Constructors
187 // ------------------------------------------------------------------------
188
189 /**
190 * Constructs a reference type.
191 *
192 * @param sort
193 * the sort of the reference type to be constructed.
194 * @param buf
195 * a buffer containing the descriptor of the previous type.
196 * @param off
197 * the offset of this descriptor in the previous buffer.
198 * @param len
199 * the length of this descriptor.
200 */
201 private Type(final int sort, final char[] buf, final int off, final int len) {
202 this.sort = sort;
203 this.buf = buf;
204 this.off = off;
205 this.len = len;
206 }
207
208 /**
209 * Returns the Java type corresponding to the given type descriptor.
210 *
211 * @param typeDescriptor
212 * a field or method type descriptor.
213 * @return the Java type corresponding to the given type descriptor.
214 */
215 public static Type getType(final String typeDescriptor) {
216 return getType(typeDescriptor.toCharArray(), 0);
217 }
218
219 /**
220 * Returns the Java type corresponding to the given internal name.
221 *
222 * @param internalName
223 * an internal name.
224 * @return the Java type corresponding to the given internal name.
225 */
226 public static Type getObjectType(final String internalName) {
227 char[] buf = internalName.toCharArray();
228 return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
229 }
230
231 /**
232 * Returns the Java type corresponding to the given method descriptor.
233 * Equivalent to <code>Type.getType(methodDescriptor)</code>.
234 *
235 * @param methodDescriptor
236 * a method descriptor.
237 * @return the Java type corresponding to the given method descriptor.
238 */
239 public static Type getMethodType(final String methodDescriptor) {
240 return getType(methodDescriptor.toCharArray(), 0);
241 }
242
243 /**
244 * Returns the Java method type corresponding to the given argument and
245 * return types.
246 *
247 * @param returnType
248 * the return type of the method.
249 * @param argumentTypes
250 * the argument types of the method.
251 * @return the Java type corresponding to the given argument and return
252 * types.
253 */
254 public static Type getMethodType(final Type returnType,
255 final Type... argumentTypes) {
256 return getType(getMethodDescriptor(returnType, argumentTypes));
257 }
258
259 /**
260 * Returns the Java type corresponding to the given class.
261 *
262 * @param c
263 * a class.
264 * @return the Java type corresponding to the given class.
265 */
266 public static Type getType(final Class<?> c) {
267 if (c.isPrimitive()) {
268 if (c == Integer.TYPE) {
269 return INT_TYPE;
270 } else if (c == Void.TYPE) {
271 return VOID_TYPE;
272 } else if (c == Boolean.TYPE) {
273 return BOOLEAN_TYPE;
274 } else if (c == Byte.TYPE) {
275 return BYTE_TYPE;
276 } else if (c == Character.TYPE) {
277 return CHAR_TYPE;
278 } else if (c == Short.TYPE) {
279 return SHORT_TYPE;
280 } else if (c == Double.TYPE) {
281 return DOUBLE_TYPE;
282 } else if (c == Float.TYPE) {
283 return FLOAT_TYPE;
284 } else /* if (c == Long.TYPE) */{
285 return LONG_TYPE;
286 }
287 } else {
288 return getType(getDescriptor(c));
289 }
290 }
291
292 /**
293 * Returns the Java method type corresponding to the given constructor.
294 *
295 * @param c
296 * a {@link Constructor Constructor} object.
297 * @return the Java method type corresponding to the given constructor.
298 */
299 public static Type getType(final Constructor<?> c) {
300 return getType(getConstructorDescriptor(c));
301 }
302
303 /**
304 * Returns the Java method type corresponding to the given method.
305 *
306 * @param m
307 * a {@link Method Method} object.
308 * @return the Java method type corresponding to the given method.
309 */
310 public static Type getType(final Method m) {
311 return getType(getMethodDescriptor(m));
312 }
313
314 /**
315 * Returns the Java types corresponding to the argument types of the given
316 * method descriptor.
317 *
318 * @param methodDescriptor
319 * a method descriptor.
320 * @return the Java types corresponding to the argument types of the given
321 * method descriptor.
322 */
323 public static Type[] getArgumentTypes(final String methodDescriptor) {
324 char[] buf = methodDescriptor.toCharArray();
325 int off = 1;
326 int size = 0;
327 while (true) {
328 char car = buf[off++];
329 if (car == ')') {
330 break;
331 } else if (car == 'L') {
332 while (buf[off++] != ';') {
333 }
334 ++size;
335 } else if (car != '[') {
336 ++size;
337 }
338 }
339 Type[] args = new Type[size];
340 off = 1;
341 size = 0;
342 while (buf[off] != ')') {
343 args[size] = getType(buf, off);
344 off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
345 size += 1;
346 }
347 return args;
348 }
349
350 /**
351 * Returns the Java types corresponding to the argument types of the given
352 * method.
353 *
354 * @param method
355 * a method.
356 * @return the Java types corresponding to the argument types of the given
357 * method.
358 */
359 public static Type[] getArgumentTypes(final Method method) {
360 Class<?>[] classes = method.getParameterTypes();
361 Type[] types = new Type[classes.length];
362 for (int i = classes.length - 1; i >= 0; --i) {
363 types[i] = getType(classes[i]);
364 }
365 return types;
366 }
367
368 /**
369 * Returns the Java type corresponding to the return type of the given
370 * method descriptor.
371 *
372 * @param methodDescriptor
373 * a method descriptor.
374 * @return the Java type corresponding to the return type of the given
375 * method descriptor.
376 */
377 public static Type getReturnType(final String methodDescriptor) {
378 char[] buf = methodDescriptor.toCharArray();
379 return getType(buf, methodDescriptor.indexOf(')') + 1);
380 }
381
382 /**
383 * Returns the Java type corresponding to the return type of the given
384 * method.
385 *
386 * @param method
387 * a method.
388 * @return the Java type corresponding to the return type of the given
389 * method.
390 */
391 public static Type getReturnType(final Method method) {
392 return getType(method.getReturnType());
393 }
394
395 /**
396 * Computes the size of the arguments and of the return value of a method.
397 *
398 * @param desc
399 * the descriptor of a method.
400 * @return the size of the arguments of the method (plus one for the
401 * implicit this argument), argSize, and the size of its return
402 * value, retSize, packed into a single int i =
403 * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal to
404 * <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
405 */
406 public static int getArgumentsAndReturnSizes(final String desc) {
407 int n = 1;
408 int c = 1;
409 while (true) {
410 char car = desc.charAt(c++);
411 if (car == ')') {
412 car = desc.charAt(c);
413 return n << 2
414 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
415 } else if (car == 'L') {
416 while (desc.charAt(c++) != ';') {
417 }
418 n += 1;
419 } else if (car == '[') {
420 while ((car = desc.charAt(c)) == '[') {
421 ++c;
422 }
423 if (car == 'D' || car == 'J') {
424 n -= 1;
425 }
426 } else if (car == 'D' || car == 'J') {
427 n += 2;
428 } else {
429 n += 1;
430 }
431 }
432 }
433
434 /**
435 * Returns the Java type corresponding to the given type descriptor. For
436 * method descriptors, buf is supposed to contain nothing more than the
437 * descriptor itself.
438 *
439 * @param buf
440 * a buffer containing a type descriptor.
441 * @param off
442 * the offset of this descriptor in the previous buffer.
443 * @return the Java type corresponding to the given type descriptor.
444 */
445 private static Type getType(final char[] buf, final int off) {
446 int len;
447 switch (buf[off]) {
448 case 'V':
449 return VOID_TYPE;
450 case 'Z':
451 return BOOLEAN_TYPE;
452 case 'C':
453 return CHAR_TYPE;
454 case 'B':
455 return BYTE_TYPE;
456 case 'S':
457 return SHORT_TYPE;
458 case 'I':
459 return INT_TYPE;
460 case 'F':
461 return FLOAT_TYPE;
462 case 'J':
463 return LONG_TYPE;
464 case 'D':
465 return DOUBLE_TYPE;
466 case '[':
467 len = 1;
468 while (buf[off + len] == '[') {
469 ++len;
470 }
471 if (buf[off + len] == 'L') {
472 ++len;
473 while (buf[off + len] != ';') {
474 ++len;
475 }
476 }
477 return new Type(ARRAY, buf, off, len + 1);
478 case 'L':
479 len = 1;
480 while (buf[off + len] != ';') {
481 ++len;
482 }
483 return new Type(OBJECT, buf, off + 1, len - 1);
484 // case '(':
485 default:
486 return new Type(METHOD, buf, off, buf.length - off);
487 }
488 }
489
490 // ------------------------------------------------------------------------
491 // Accessors
492 // ------------------------------------------------------------------------
493
494 /**
495 * Returns the sort of this Java type.
496 *
497 * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR},
498 * {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT},
499 * {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE},
500 * {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD
501 * METHOD}.
502 */
503 public int getSort() {
504 return sort;
505 }
506
507 /**
508 * Returns the number of dimensions of this array type. This method should
509 * only be used for an array type.
510 *
511 * @return the number of dimensions of this array type.
512 */
513 public int getDimensions() {
514 int i = 1;
515 while (buf[off + i] == '[') {
516 ++i;
517 }
518 return i;
519 }
520
521 /**
522 * Returns the type of the elements of this array type. This method should
523 * only be used for an array type.
524 *
525 * @return Returns the type of the elements of this array type.
526 */
527 public Type getElementType() {
528 return getType(buf, off + getDimensions());
529 }
530
531 /**
532 * Returns the binary name of the class corresponding to this type. This
533 * method must not be used on method types.
534 *
535 * @return the binary name of the class corresponding to this type.
536 */
537 public String getClassName() {
538 switch (sort) {
539 case VOID:
540 return "void";
541 case BOOLEAN:
542 return "boolean";
543 case CHAR:
544 return "char";
545 case BYTE:
546 return "byte";
547 case SHORT:
548 return "short";
549 case INT:
550 return "int";
551 case FLOAT:
552 return "float";
553 case LONG:
554 return "long";
555 case DOUBLE:
556 return "double";
557 case ARRAY:
558 StringBuffer b = new StringBuffer(getElementType().getClassName());
559 for (int i = getDimensions(); i > 0; --i) {
560 b.append("[]");
561 }
562 return b.toString();
563 case OBJECT:
564 return new String(buf, off, len).replace('/', '.');
565 default:
566 return null;
567 }
568 }
569
570 /**
571 * Returns the internal name of the class corresponding to this object or
572 * array type. The internal name of a class is its fully qualified name (as
573 * returned by Class.getName(), where '.' are replaced by '/'. This method
574 * should only be used for an object or array type.
575 *
576 * @return the internal name of the class corresponding to this object type.
577 */
578 public String getInternalName() {
579 return new String(buf, off, len);
580 }
581
582 /**
583 * Returns the argument types of methods of this type. This method should
584 * only be used for method types.
585 *
586 * @return the argument types of methods of this type.
587 */
588 public Type[] getArgumentTypes() {
589 return getArgumentTypes(getDescriptor());
590 }
591
592 /**
593 * Returns the return type of methods of this type. This method should only
594 * be used for method types.
595 *
596 * @return the return type of methods of this type.
597 */
598 public Type getReturnType() {
599 return getReturnType(getDescriptor());
600 }
601
602 /**
603 * Returns the size of the arguments and of the return value of methods of
604 * this type. This method should only be used for method types.
605 *
606 * @return the size of the arguments (plus one for the implicit this
607 * argument), argSize, and the size of the return value, retSize,
608 * packed into a single int i = <tt>(argSize << 2) | retSize</tt>
609 * (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to
610 * <tt>i & 0x03</tt>).
611 */
612 public int getArgumentsAndReturnSizes() {
613 return getArgumentsAndReturnSizes(getDescriptor());
614 }
615
616 // ------------------------------------------------------------------------
617 // Conversion to type descriptors
618 // ------------------------------------------------------------------------
619
620 /**
621 * Returns the descriptor corresponding to this Java type.
622 *
623 * @return the descriptor corresponding to this Java type.
624 */
625 public String getDescriptor() {
626 StringBuffer buf = new StringBuffer();
627 getDescriptor(buf);
628 return buf.toString();
629 }
630
631 /**
632 * Returns the descriptor corresponding to the given argument and return
633 * types.
634 *
635 * @param returnType
636 * the return type of the method.
637 * @param argumentTypes
638 * the argument types of the method.
639 * @return the descriptor corresponding to the given argument and return
640 * types.
641 */
642 public static String getMethodDescriptor(final Type returnType,
643 final Type... argumentTypes) {
644 StringBuffer buf = new StringBuffer();
645 buf.append('(');
646 for (int i = 0; i < argumentTypes.length; ++i) {
647 argumentTypes[i].getDescriptor(buf);
648 }
649 buf.append(')');
650 returnType.getDescriptor(buf);
651 return buf.toString();
652 }
653
654 /**
655 * Appends the descriptor corresponding to this Java type to the given
656 * string buffer.
657 *
658 * @param buf
659 * the string buffer to which the descriptor must be appended.
660 */
661 private void getDescriptor(final StringBuffer buf) {
662 if (this.buf == null) {
663 // descriptor is in byte 3 of 'off' for primitive types (buf ==
664 // null)
665 buf.append((char) ((off & 0xFF000000) >>> 24));
666 } else if (sort == OBJECT) {
667 buf.append('L');
668 buf.append(this.buf, off, len);
669 buf.append(';');
670 } else { // sort == ARRAY || sort == METHOD
671 buf.append(this.buf, off, len);
672 }
673 }
674
675 // ------------------------------------------------------------------------
676 // Direct conversion from classes to type descriptors,
677 // without intermediate Type objects
678 // ------------------------------------------------------------------------
679
680 /**
681 * Returns the internal name of the given class. The internal name of a
682 * class is its fully qualified name, as returned by Class.getName(), where
683 * '.' are replaced by '/'.
684 *
685 * @param c
686 * an object or array class.
687 * @return the internal name of the given class.
688 */
689 public static String getInternalName(final Class<?> c) {
690 return c.getName().replace('.', '/');
691 }
692
693 /**
694 * Returns the descriptor corresponding to the given Java type.
695 *
696 * @param c
697 * an object class, a primitive class or an array class.
698 * @return the descriptor corresponding to the given class.
699 */
700 public static String getDescriptor(final Class<?> c) {
701 StringBuffer buf = new StringBuffer();
702 getDescriptor(buf, c);
703 return buf.toString();
704 }
705
706 /**
707 * Returns the descriptor corresponding to the given constructor.
708 *
709 * @param c
710 * a {@link Constructor Constructor} object.
711 * @return the descriptor of the given constructor.
712 */
713 public static String getConstructorDescriptor(final Constructor<?> c) {
714 Class<?>[] parameters = c.getParameterTypes();
715 StringBuffer buf = new StringBuffer();
716 buf.append('(');
717 for (int i = 0; i < parameters.length; ++i) {
718 getDescriptor(buf, parameters[i]);
719 }
720 return buf.append(")V").toString();
721 }
722
723 /**
724 * Returns the descriptor corresponding to the given method.
725 *
726 * @param m
727 * a {@link Method Method} object.
728 * @return the descriptor of the given method.
729 */
730 public static String getMethodDescriptor(final Method m) {
731 Class<?>[] parameters = m.getParameterTypes();
732 StringBuffer buf = new StringBuffer();
733 buf.append('(');
734 for (int i = 0; i < parameters.length; ++i) {
735 getDescriptor(buf, parameters[i]);
736 }
737 buf.append(')');
738 getDescriptor(buf, m.getReturnType());
739 return buf.toString();
740 }
741
742 /**
743 * Appends the descriptor of the given class to the given string buffer.
744 *
745 * @param buf
746 * the string buffer to which the descriptor must be appended.
747 * @param c
748 * the class whose descriptor must be computed.
749 */
750 private static void getDescriptor(final StringBuffer buf, final Class<?> c) {
751 Class<?> d = c;
752 while (true) {
753 if (d.isPrimitive()) {
754 char car;
755 if (d == Integer.TYPE) {
756 car = 'I';
757 } else if (d == Void.TYPE) {
758 car = 'V';
759 } else if (d == Boolean.TYPE) {
760 car = 'Z';
761 } else if (d == Byte.TYPE) {
762 car = 'B';
763 } else if (d == Character.TYPE) {
764 car = 'C';
765 } else if (d == Short.TYPE) {
766 car = 'S';
767 } else if (d == Double.TYPE) {
768 car = 'D';
769 } else if (d == Float.TYPE) {
770 car = 'F';
771 } else /* if (d == Long.TYPE) */{
772 car = 'J';
773 }
774 buf.append(car);
775 return;
776 } else if (d.isArray()) {
777 buf.append('[');
778 d = d.getComponentType();
779 } else {
780 buf.append('L');
781 String name = d.getName();
782 int len = name.length();
783 for (int i = 0; i < len; ++i) {
784 char car = name.charAt(i);
785 buf.append(car == '.' ? '/' : car);
786 }
787 buf.append(';');
788 return;
789 }
790 }
791 }
792
793 // ------------------------------------------------------------------------
794 // Corresponding size and opcodes
795 // ------------------------------------------------------------------------
796
797 /**
798 * Returns the size of values of this type. This method must not be used for
799 * method types.
800 *
801 * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
802 * <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
803 */
804 public int getSize() {
805 // the size is in byte 0 of 'off' for primitive types (buf == null)
806 return buf == null ? (off & 0xFF) : 1;
807 }
808
809 /**
810 * Returns a JVM instruction opcode adapted to this Java type. This method
811 * must not be used for method types.
812 *
813 * @param opcode
814 * a JVM instruction opcode. This opcode must be one of ILOAD,
815 * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
816 * ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
817 * @return an opcode that is similar to the given opcode, but adapted to
818 * this Java type. For example, if this type is <tt>float</tt> and
819 * <tt>opcode</tt> is IRETURN, this method returns FRETURN.
820 */
821 public int getOpcode(final int opcode) {
822 if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
823 // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
824 // primitive types (buf == null)
825 return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
826 } else {
827 // the offset for other instructions is in byte 2 of 'off' for
828 // primitive types (buf == null)
829 return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
830 }
831 }
832
833 // ------------------------------------------------------------------------
834 // Equals, hashCode and toString
835 // ------------------------------------------------------------------------
836
837 /**
838 * Tests if the given object is equal to this type.
839 *
840 * @param o
841 * the object to be compared to this type.
842 * @return <tt>true</tt> if the given object is equal to this type.
843 */
844 @Override
845 public boolean equals(final Object o) {
846 if (this == o) {
847 return true;
848 }
849 if (!(o instanceof Type)) {
850 return false;
851 }
852 Type t = (Type) o;
853 if (sort != t.sort) {
854 return false;
855 }
856 if (sort >= ARRAY) {
857 if (len != t.len) {
858 return false;
859 }
860 for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
861 if (buf[i] != t.buf[j]) {
862 return false;
863 }
864 }
865 }
866 return true;
867 }
868
869 /**
870 * Returns a hash code value for this type.
871 *
872 * @return a hash code value for this type.
873 */
874 @Override
875 public int hashCode() {
876 int hc = 13 * sort;
877 if (sort >= ARRAY) {
878 for (int i = off, end = i + len; i < end; i++) {
879 hc = 17 * (hc + buf[i]);
880 }
881 }
882 return hc;
883 }
884
885 /**
886 * Returns a string representation of this type.
887 *
888 * @return the descriptor of this type.
889 */
890 @Override
891 public String toString() {
892 return getDescriptor();
893 }
894 }
+0
-625
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-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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.Handle;
37 import clojure.asm.Label;
38 import clojure.asm.MethodVisitor;
39 import clojure.asm.Opcodes;
40 import clojure.asm.Type;
41
42 /**
43 * A {@link clojure.asm.MethodVisitor} to insert before, after and around
44 * advices in methods and constructors.
45 * <p>
46 * The behavior for constructors is like this:
47 * <ol>
48 *
49 * <li>as long as the INVOKESPECIAL for the object initialization has not been
50 * reached, every bytecode instruction is dispatched in the ctor code visitor</li>
51 *
52 * <li>when this one is reached, it is only added in the ctor code visitor and a
53 * JP invoke is added</li>
54 *
55 * <li>after that, only the other code visitor receives the instructions</li>
56 *
57 * </ol>
58 *
59 * @author Eugene Kuleshov
60 * @author Eric Bruneton
61 */
62 public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes {
63
64 private static final Object THIS = new Object();
65
66 private static final Object OTHER = new Object();
67
68 protected int methodAccess;
69
70 protected String methodDesc;
71
72 private boolean constructor;
73
74 private boolean superInitialized;
75
76 private List<Object> stackFrame;
77
78 private Map<Label, List<Object>> branches;
79
80 /**
81 * Creates a new {@link AdviceAdapter}.
82 *
83 * @param api
84 * the ASM API version implemented by this visitor. Must be one
85 * of {@link Opcodes#ASM4}.
86 * @param mv
87 * the method visitor to which this adapter delegates calls.
88 * @param access
89 * the method's access flags (see {@link Opcodes}).
90 * @param name
91 * the method's name.
92 * @param desc
93 * the method's descriptor (see {@link Type Type}).
94 */
95 protected AdviceAdapter(final int api, final MethodVisitor mv,
96 final int access, final String name, final String desc) {
97 super(api, mv, access, name, desc);
98 methodAccess = access;
99 methodDesc = desc;
100 constructor = "<init>".equals(name);
101 }
102
103 @Override
104 public void visitCode() {
105 mv.visitCode();
106 if (constructor) {
107 stackFrame = new ArrayList<Object>();
108 branches = new HashMap<Label, List<Object>>();
109 } else {
110 superInitialized = true;
111 onMethodEnter();
112 }
113 }
114
115 @Override
116 public void visitLabel(final Label label) {
117 mv.visitLabel(label);
118 if (constructor && branches != null) {
119 List<Object> frame = branches.get(label);
120 if (frame != null) {
121 stackFrame = frame;
122 branches.remove(label);
123 }
124 }
125 }
126
127 @Override
128 public void visitInsn(final int opcode) {
129 if (constructor) {
130 int s;
131 switch (opcode) {
132 case RETURN: // empty stack
133 onMethodExit(opcode);
134 break;
135 case IRETURN: // 1 before n/a after
136 case FRETURN: // 1 before n/a after
137 case ARETURN: // 1 before n/a after
138 case ATHROW: // 1 before n/a after
139 popValue();
140 onMethodExit(opcode);
141 break;
142 case LRETURN: // 2 before n/a after
143 case DRETURN: // 2 before n/a after
144 popValue();
145 popValue();
146 onMethodExit(opcode);
147 break;
148 case NOP:
149 case LALOAD: // remove 2 add 2
150 case DALOAD: // remove 2 add 2
151 case LNEG:
152 case DNEG:
153 case FNEG:
154 case INEG:
155 case L2D:
156 case D2L:
157 case F2I:
158 case I2B:
159 case I2C:
160 case I2S:
161 case I2F:
162 case ARRAYLENGTH:
163 break;
164 case ACONST_NULL:
165 case ICONST_M1:
166 case ICONST_0:
167 case ICONST_1:
168 case ICONST_2:
169 case ICONST_3:
170 case ICONST_4:
171 case ICONST_5:
172 case FCONST_0:
173 case FCONST_1:
174 case FCONST_2:
175 case F2L: // 1 before 2 after
176 case F2D:
177 case I2L:
178 case I2D:
179 pushValue(OTHER);
180 break;
181 case LCONST_0:
182 case LCONST_1:
183 case DCONST_0:
184 case DCONST_1:
185 pushValue(OTHER);
186 pushValue(OTHER);
187 break;
188 case IALOAD: // remove 2 add 1
189 case FALOAD: // remove 2 add 1
190 case AALOAD: // remove 2 add 1
191 case BALOAD: // remove 2 add 1
192 case CALOAD: // remove 2 add 1
193 case SALOAD: // remove 2 add 1
194 case POP:
195 case IADD:
196 case FADD:
197 case ISUB:
198 case LSHL: // 3 before 2 after
199 case LSHR: // 3 before 2 after
200 case LUSHR: // 3 before 2 after
201 case L2I: // 2 before 1 after
202 case L2F: // 2 before 1 after
203 case D2I: // 2 before 1 after
204 case D2F: // 2 before 1 after
205 case FSUB:
206 case FMUL:
207 case FDIV:
208 case FREM:
209 case FCMPL: // 2 before 1 after
210 case FCMPG: // 2 before 1 after
211 case IMUL:
212 case IDIV:
213 case IREM:
214 case ISHL:
215 case ISHR:
216 case IUSHR:
217 case IAND:
218 case IOR:
219 case IXOR:
220 case MONITORENTER:
221 case MONITOREXIT:
222 popValue();
223 break;
224 case POP2:
225 case LSUB:
226 case LMUL:
227 case LDIV:
228 case LREM:
229 case LADD:
230 case LAND:
231 case LOR:
232 case LXOR:
233 case DADD:
234 case DMUL:
235 case DSUB:
236 case DDIV:
237 case DREM:
238 popValue();
239 popValue();
240 break;
241 case IASTORE:
242 case FASTORE:
243 case AASTORE:
244 case BASTORE:
245 case CASTORE:
246 case SASTORE:
247 case LCMP: // 4 before 1 after
248 case DCMPL:
249 case DCMPG:
250 popValue();
251 popValue();
252 popValue();
253 break;
254 case LASTORE:
255 case DASTORE:
256 popValue();
257 popValue();
258 popValue();
259 popValue();
260 break;
261 case DUP:
262 pushValue(peekValue());
263 break;
264 case DUP_X1:
265 s = stackFrame.size();
266 stackFrame.add(s - 2, stackFrame.get(s - 1));
267 break;
268 case DUP_X2:
269 s = stackFrame.size();
270 stackFrame.add(s - 3, stackFrame.get(s - 1));
271 break;
272 case DUP2:
273 s = stackFrame.size();
274 stackFrame.add(s - 2, stackFrame.get(s - 1));
275 stackFrame.add(s - 2, stackFrame.get(s - 1));
276 break;
277 case DUP2_X1:
278 s = stackFrame.size();
279 stackFrame.add(s - 3, stackFrame.get(s - 1));
280 stackFrame.add(s - 3, stackFrame.get(s - 1));
281 break;
282 case DUP2_X2:
283 s = stackFrame.size();
284 stackFrame.add(s - 4, stackFrame.get(s - 1));
285 stackFrame.add(s - 4, stackFrame.get(s - 1));
286 break;
287 case SWAP:
288 s = stackFrame.size();
289 stackFrame.add(s - 2, stackFrame.get(s - 1));
290 stackFrame.remove(s);
291 break;
292 }
293 } else {
294 switch (opcode) {
295 case RETURN:
296 case IRETURN:
297 case FRETURN:
298 case ARETURN:
299 case LRETURN:
300 case DRETURN:
301 case ATHROW:
302 onMethodExit(opcode);
303 break;
304 }
305 }
306 mv.visitInsn(opcode);
307 }
308
309 @Override
310 public void visitVarInsn(final int opcode, final int var) {
311 super.visitVarInsn(opcode, var);
312 if (constructor) {
313 switch (opcode) {
314 case ILOAD:
315 case FLOAD:
316 pushValue(OTHER);
317 break;
318 case LLOAD:
319 case DLOAD:
320 pushValue(OTHER);
321 pushValue(OTHER);
322 break;
323 case ALOAD:
324 pushValue(var == 0 ? THIS : OTHER);
325 break;
326 case ASTORE:
327 case ISTORE:
328 case FSTORE:
329 popValue();
330 break;
331 case LSTORE:
332 case DSTORE:
333 popValue();
334 popValue();
335 break;
336 }
337 }
338 }
339
340 @Override
341 public void visitFieldInsn(final int opcode, final String owner,
342 final String name, final String desc) {
343 mv.visitFieldInsn(opcode, owner, name, desc);
344 if (constructor) {
345 char c = desc.charAt(0);
346 boolean longOrDouble = c == 'J' || c == 'D';
347 switch (opcode) {
348 case GETSTATIC:
349 pushValue(OTHER);
350 if (longOrDouble) {
351 pushValue(OTHER);
352 }
353 break;
354 case PUTSTATIC:
355 popValue();
356 if (longOrDouble) {
357 popValue();
358 }
359 break;
360 case PUTFIELD:
361 popValue();
362 if (longOrDouble) {
363 popValue();
364 popValue();
365 }
366 break;
367 // case GETFIELD:
368 default:
369 if (longOrDouble) {
370 pushValue(OTHER);
371 }
372 }
373 }
374 }
375
376 @Override
377 public void visitIntInsn(final int opcode, final int operand) {
378 mv.visitIntInsn(opcode, operand);
379 if (constructor && opcode != NEWARRAY) {
380 pushValue(OTHER);
381 }
382 }
383
384 @Override
385 public void visitLdcInsn(final Object cst) {
386 mv.visitLdcInsn(cst);
387 if (constructor) {
388 pushValue(OTHER);
389 if (cst instanceof Double || cst instanceof Long) {
390 pushValue(OTHER);
391 }
392 }
393 }
394
395 @Override
396 public void visitMultiANewArrayInsn(final String desc, final int dims) {
397 mv.visitMultiANewArrayInsn(desc, dims);
398 if (constructor) {
399 for (int i = 0; i < dims; i++) {
400 popValue();
401 }
402 pushValue(OTHER);
403 }
404 }
405
406 @Override
407 public void visitTypeInsn(final int opcode, final String type) {
408 mv.visitTypeInsn(opcode, type);
409 // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
410 if (constructor && opcode == NEW) {
411 pushValue(OTHER);
412 }
413 }
414
415 @Override
416 public void visitMethodInsn(final int opcode, final String owner,
417 final String name, final String desc) {
418 mv.visitMethodInsn(opcode, owner, name, desc);
419 if (constructor) {
420 Type[] types = Type.getArgumentTypes(desc);
421 for (int i = 0; i < types.length; i++) {
422 popValue();
423 if (types[i].getSize() == 2) {
424 popValue();
425 }
426 }
427 switch (opcode) {
428 // case INVOKESTATIC:
429 // break;
430 case INVOKEINTERFACE:
431 case INVOKEVIRTUAL:
432 popValue(); // objectref
433 break;
434 case INVOKESPECIAL:
435 Object type = popValue(); // objectref
436 if (type == THIS && !superInitialized) {
437 onMethodEnter();
438 superInitialized = true;
439 // once super has been initialized it is no longer
440 // necessary to keep track of stack state
441 constructor = false;
442 }
443 break;
444 }
445
446 Type returnType = Type.getReturnType(desc);
447 if (returnType != Type.VOID_TYPE) {
448 pushValue(OTHER);
449 if (returnType.getSize() == 2) {
450 pushValue(OTHER);
451 }
452 }
453 }
454 }
455
456 @Override
457 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
458 Object... bsmArgs) {
459 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
460 if (constructor) {
461 Type[] types = Type.getArgumentTypes(desc);
462 for (int i = 0; i < types.length; i++) {
463 popValue();
464 if (types[i].getSize() == 2) {
465 popValue();
466 }
467 }
468
469 Type returnType = Type.getReturnType(desc);
470 if (returnType != Type.VOID_TYPE) {
471 pushValue(OTHER);
472 if (returnType.getSize() == 2) {
473 pushValue(OTHER);
474 }
475 }
476 }
477 }
478
479 @Override
480 public void visitJumpInsn(final int opcode, final Label label) {
481 mv.visitJumpInsn(opcode, label);
482 if (constructor) {
483 switch (opcode) {
484 case IFEQ:
485 case IFNE:
486 case IFLT:
487 case IFGE:
488 case IFGT:
489 case IFLE:
490 case IFNULL:
491 case IFNONNULL:
492 popValue();
493 break;
494 case IF_ICMPEQ:
495 case IF_ICMPNE:
496 case IF_ICMPLT:
497 case IF_ICMPGE:
498 case IF_ICMPGT:
499 case IF_ICMPLE:
500 case IF_ACMPEQ:
501 case IF_ACMPNE:
502 popValue();
503 popValue();
504 break;
505 case JSR:
506 pushValue(OTHER);
507 break;
508 }
509 addBranch(label);
510 }
511 }
512
513 @Override
514 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
515 final Label[] labels) {
516 mv.visitLookupSwitchInsn(dflt, keys, labels);
517 if (constructor) {
518 popValue();
519 addBranches(dflt, labels);
520 }
521 }
522
523 @Override
524 public void visitTableSwitchInsn(final int min, final int max,
525 final Label dflt, final Label... labels) {
526 mv.visitTableSwitchInsn(min, max, dflt, labels);
527 if (constructor) {
528 popValue();
529 addBranches(dflt, labels);
530 }
531 }
532
533 @Override
534 public void visitTryCatchBlock(Label start, Label end, Label handler,
535 String type) {
536 super.visitTryCatchBlock(start, end, handler, type);
537 if (constructor && !branches.containsKey(handler)) {
538 List<Object> stackFrame = new ArrayList<Object>();
539 stackFrame.add(OTHER);
540 branches.put(handler, stackFrame);
541 }
542 }
543
544 private void addBranches(final Label dflt, final Label[] labels) {
545 addBranch(dflt);
546 for (int i = 0; i < labels.length; i++) {
547 addBranch(labels[i]);
548 }
549 }
550
551 private void addBranch(final Label label) {
552 if (branches.containsKey(label)) {
553 return;
554 }
555 branches.put(label, new ArrayList<Object>(stackFrame));
556 }
557
558 private Object popValue() {
559 return stackFrame.remove(stackFrame.size() - 1);
560 }
561
562 private Object peekValue() {
563 return stackFrame.get(stackFrame.size() - 1);
564 }
565
566 private void pushValue(final Object o) {
567 stackFrame.add(o);
568 }
569
570 /**
571 * Called at the beginning of the method or after super class class call in
572 * the constructor. <br>
573 * <br>
574 *
575 * <i>Custom code can use or change all the local variables, but should not
576 * change state of the stack.</i>
577 */
578 protected void onMethodEnter() {
579 }
580
581 /**
582 * Called before explicit exit from the method using either return or throw.
583 * Top element on the stack contains the return value or exception instance.
584 * For example:
585 *
586 * <pre>
587 * public void onMethodExit(int opcode) {
588 * if(opcode==RETURN) {
589 * visitInsn(ACONST_NULL);
590 * } else if(opcode==ARETURN || opcode==ATHROW) {
591 * dup();
592 * } else {
593 * if(opcode==LRETURN || opcode==DRETURN) {
594 * dup2();
595 * } else {
596 * dup();
597 * }
598 * box(Type.getReturnType(this.methodDesc));
599 * }
600 * visitIntInsn(SIPUSH, opcode);
601 * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
602 * }
603 *
604 * // an actual call back method
605 * public static void onExit(Object param, int opcode) {
606 * ...
607 * </pre>
608 *
609 * <br>
610 * <br>
611 *
612 * <i>Custom code can use or change all the local variables, but should not
613 * change state of the stack.</i>
614 *
615 * @param opcode
616 * one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN
617 * or ATHROW
618 *
619 */
620 protected void onMethodExit(int opcode) {
621 }
622
623 // TODO onException, onMethodCall
624 }
+0
-920
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-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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.Handle;
37 import clojure.asm.Label;
38 import clojure.asm.MethodVisitor;
39 import clojure.asm.Opcodes;
40 import clojure.asm.Type;
41
42 /**
43 * A {@link MethodVisitor} 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
47 * visit<i>X</i> instruction delegates to the next visitor in the chain, if any,
48 * and then simulates the effect of this instruction on the stack map frame,
49 * represented by {@link #locals} and {@link #stack}. The next visitor in the
50 * chain can get the state of the stack map frame <i>before</i> each instruction
51 * by reading the value of these fields in its visit<i>X</i> methods (this
52 * requires a reference to the AnalyzerAdapter that is before it in the chain).
53 * If this adapter is used with a class that does not contain stack map table
54 * attributes (i.e., pre Java 6 classes) then this adapter may not be able to
55 * compute the stack map frame for each instruction. In this case no exception
56 * is thrown but the {@link #locals} and {@link #stack} fields will be null for
57 * these instructions.
58 *
59 * @author Eric Bruneton
60 */
61 public class AnalyzerAdapter extends MethodVisitor {
62
63 /**
64 * <code>List</code> of the local variable slots for current execution
65 * frame. Primitive types are represented by {@link Opcodes#TOP},
66 * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
67 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
68 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by
69 * two elements, the second one being TOP). Reference types are represented
70 * by String objects (representing internal names), and uninitialized types
71 * by Label objects (this label designates the NEW instruction that created
72 * this uninitialized value). This field is <tt>null</tt> for unreachable
73 * instructions.
74 */
75 public List<Object> locals;
76
77 /**
78 * <code>List</code> of the operand stack slots for current execution frame.
79 * Primitive types are represented by {@link Opcodes#TOP},
80 * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
81 * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
82 * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by
83 * two elements, the second one being TOP). Reference types are represented
84 * by String objects (representing internal names), and uninitialized types
85 * by Label objects (this label designates the NEW instruction that created
86 * this uninitialized value). This field is <tt>null</tt> for unreachable
87 * instructions.
88 */
89 public List<Object> stack;
90
91 /**
92 * The labels that designate the next instruction to be visited. May be
93 * <tt>null</tt>.
94 */
95 private List<Label> labels;
96
97 /**
98 * Information about uninitialized types in the current execution frame.
99 * This map associates internal names to Label objects. Each label
100 * designates a NEW instruction that created the currently uninitialized
101 * types, and the associated internal name represents the NEW operand, i.e.
102 * the final, initialized type value.
103 */
104 public Map<Object, Object> uninitializedTypes;
105
106 /**
107 * The maximum stack size of this method.
108 */
109 private int maxStack;
110
111 /**
112 * The maximum number of local variables of this method.
113 */
114 private int maxLocals;
115
116 /**
117 * The owner's class name.
118 */
119 private String owner;
120
121 /**
122 * Creates a new {@link AnalyzerAdapter}. <i>Subclasses must not use this
123 * constructor</i>. Instead, they must use the
124 * {@link #AnalyzerAdapter(int, String, int, String, String, MethodVisitor)}
125 * version.
126 *
127 * @param owner
128 * the owner's class name.
129 * @param access
130 * the method's access flags (see {@link Opcodes}).
131 * @param name
132 * the method's name.
133 * @param desc
134 * the method's descriptor (see {@link Type Type}).
135 * @param mv
136 * the method visitor to which this adapter delegates calls. May
137 * be <tt>null</tt>.
138 */
139 public AnalyzerAdapter(final String owner, final int access,
140 final String name, final String desc, final MethodVisitor mv) {
141 this(Opcodes.ASM4, owner, access, name, desc, mv);
142 }
143
144 /**
145 * Creates a new {@link AnalyzerAdapter}.
146 *
147 * @param api
148 * the ASM API version implemented by this visitor. Must be one
149 * of {@link Opcodes#ASM4}.
150 * @param owner
151 * the owner's class name.
152 * @param access
153 * the method's access flags (see {@link Opcodes}).
154 * @param name
155 * the method's name.
156 * @param desc
157 * the method's descriptor (see {@link Type Type}).
158 * @param mv
159 * the method visitor to which this adapter delegates calls. May
160 * be <tt>null</tt>.
161 */
162 protected AnalyzerAdapter(final int api, final String owner,
163 final int access, final String name, final String desc,
164 final MethodVisitor mv) {
165 super(api, mv);
166 this.owner = owner;
167 locals = new ArrayList<Object>();
168 stack = new ArrayList<Object>();
169 uninitializedTypes = new HashMap<Object, Object>();
170
171 if ((access & Opcodes.ACC_STATIC) == 0) {
172 if ("<init>".equals(name)) {
173 locals.add(Opcodes.UNINITIALIZED_THIS);
174 } else {
175 locals.add(owner);
176 }
177 }
178 Type[] types = Type.getArgumentTypes(desc);
179 for (int i = 0; i < types.length; ++i) {
180 Type type = types[i];
181 switch (type.getSort()) {
182 case Type.BOOLEAN:
183 case Type.CHAR:
184 case Type.BYTE:
185 case Type.SHORT:
186 case Type.INT:
187 locals.add(Opcodes.INTEGER);
188 break;
189 case Type.FLOAT:
190 locals.add(Opcodes.FLOAT);
191 break;
192 case Type.LONG:
193 locals.add(Opcodes.LONG);
194 locals.add(Opcodes.TOP);
195 break;
196 case Type.DOUBLE:
197 locals.add(Opcodes.DOUBLE);
198 locals.add(Opcodes.TOP);
199 break;
200 case Type.ARRAY:
201 locals.add(types[i].getDescriptor());
202 break;
203 // case Type.OBJECT:
204 default:
205 locals.add(types[i].getInternalName());
206 }
207 }
208 }
209
210 @Override
211 public void visitFrame(final int type, final int nLocal,
212 final Object[] local, final int nStack, final Object[] stack) {
213 if (type != Opcodes.F_NEW) { // uncompressed frame
214 throw new IllegalStateException(
215 "ClassReader.accept() should be called with EXPAND_FRAMES flag");
216 }
217
218 if (mv != null) {
219 mv.visitFrame(type, nLocal, local, nStack, stack);
220 }
221
222 if (this.locals != null) {
223 this.locals.clear();
224 this.stack.clear();
225 } else {
226 this.locals = new ArrayList<Object>();
227 this.stack = new ArrayList<Object>();
228 }
229 visitFrameTypes(nLocal, local, this.locals);
230 visitFrameTypes(nStack, stack, this.stack);
231 maxStack = Math.max(maxStack, this.stack.size());
232 }
233
234 private static void visitFrameTypes(final int n, final Object[] types,
235 final List<Object> result) {
236 for (int i = 0; i < n; ++i) {
237 Object type = types[i];
238 result.add(type);
239 if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
240 result.add(Opcodes.TOP);
241 }
242 }
243 }
244
245 @Override
246 public void visitInsn(final int opcode) {
247 if (mv != null) {
248 mv.visitInsn(opcode);
249 }
250 execute(opcode, 0, null);
251 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
252 || opcode == Opcodes.ATHROW) {
253 this.locals = null;
254 this.stack = null;
255 }
256 }
257
258 @Override
259 public void visitIntInsn(final int opcode, final int operand) {
260 if (mv != null) {
261 mv.visitIntInsn(opcode, operand);
262 }
263 execute(opcode, operand, null);
264 }
265
266 @Override
267 public void visitVarInsn(final int opcode, final int var) {
268 if (mv != null) {
269 mv.visitVarInsn(opcode, var);
270 }
271 execute(opcode, var, null);
272 }
273
274 @Override
275 public void visitTypeInsn(final int opcode, final String type) {
276 if (opcode == Opcodes.NEW) {
277 if (labels == null) {
278 Label l = new Label();
279 labels = new ArrayList<Label>(3);
280 labels.add(l);
281 if (mv != null) {
282 mv.visitLabel(l);
283 }
284 }
285 for (int i = 0; i < labels.size(); ++i) {
286 uninitializedTypes.put(labels.get(i), type);
287 }
288 }
289 if (mv != null) {
290 mv.visitTypeInsn(opcode, type);
291 }
292 execute(opcode, 0, type);
293 }
294
295 @Override
296 public void visitFieldInsn(final int opcode, final String owner,
297 final String name, final String desc) {
298 if (mv != null) {
299 mv.visitFieldInsn(opcode, owner, name, desc);
300 }
301 execute(opcode, 0, desc);
302 }
303
304 @Override
305 public void visitMethodInsn(final int opcode, final String owner,
306 final String name, final String desc) {
307 if (mv != null) {
308 mv.visitMethodInsn(opcode, owner, name, desc);
309 }
310 if (this.locals == null) {
311 labels = null;
312 return;
313 }
314 pop(desc);
315 if (opcode != Opcodes.INVOKESTATIC) {
316 Object t = pop();
317 if (opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') {
318 Object u;
319 if (t == Opcodes.UNINITIALIZED_THIS) {
320 u = this.owner;
321 } else {
322 u = uninitializedTypes.get(t);
323 }
324 for (int i = 0; i < locals.size(); ++i) {
325 if (locals.get(i) == t) {
326 locals.set(i, u);
327 }
328 }
329 for (int i = 0; i < stack.size(); ++i) {
330 if (stack.get(i) == t) {
331 stack.set(i, u);
332 }
333 }
334 }
335 }
336 pushDesc(desc);
337 labels = null;
338 }
339
340 @Override
341 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
342 Object... bsmArgs) {
343 if (mv != null) {
344 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
345 }
346 if (this.locals == null) {
347 labels = null;
348 return;
349 }
350 pop(desc);
351 pushDesc(desc);
352 labels = null;
353 }
354
355 @Override
356 public void visitJumpInsn(final int opcode, final Label label) {
357 if (mv != null) {
358 mv.visitJumpInsn(opcode, label);
359 }
360 execute(opcode, 0, null);
361 if (opcode == Opcodes.GOTO) {
362 this.locals = null;
363 this.stack = null;
364 }
365 }
366
367 @Override
368 public void visitLabel(final Label label) {
369 if (mv != null) {
370 mv.visitLabel(label);
371 }
372 if (labels == null) {
373 labels = new ArrayList<Label>(3);
374 }
375 labels.add(label);
376 }
377
378 @Override
379 public void visitLdcInsn(final Object cst) {
380 if (mv != null) {
381 mv.visitLdcInsn(cst);
382 }
383 if (this.locals == null) {
384 labels = null;
385 return;
386 }
387 if (cst instanceof Integer) {
388 push(Opcodes.INTEGER);
389 } else if (cst instanceof Long) {
390 push(Opcodes.LONG);
391 push(Opcodes.TOP);
392 } else if (cst instanceof Float) {
393 push(Opcodes.FLOAT);
394 } else if (cst instanceof Double) {
395 push(Opcodes.DOUBLE);
396 push(Opcodes.TOP);
397 } else if (cst instanceof String) {
398 push("java/lang/String");
399 } else if (cst instanceof Type) {
400 int sort = ((Type) cst).getSort();
401 if (sort == Type.OBJECT || sort == Type.ARRAY) {
402 push("java/lang/Class");
403 } else if (sort == Type.METHOD) {
404 push("java/lang/invoke/MethodType");
405 } else {
406 throw new IllegalArgumentException();
407 }
408 } else if (cst instanceof Handle) {
409 push("java/lang/invoke/MethodHandle");
410 } else {
411 throw new IllegalArgumentException();
412 }
413 labels = null;
414 }
415
416 @Override
417 public void visitIincInsn(final int var, final int increment) {
418 if (mv != null) {
419 mv.visitIincInsn(var, increment);
420 }
421 execute(Opcodes.IINC, var, null);
422 }
423
424 @Override
425 public void visitTableSwitchInsn(final int min, final int max,
426 final Label dflt, final Label... labels) {
427 if (mv != null) {
428 mv.visitTableSwitchInsn(min, max, dflt, labels);
429 }
430 execute(Opcodes.TABLESWITCH, 0, null);
431 this.locals = null;
432 this.stack = null;
433 }
434
435 @Override
436 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
437 final Label[] labels) {
438 if (mv != null) {
439 mv.visitLookupSwitchInsn(dflt, keys, labels);
440 }
441 execute(Opcodes.LOOKUPSWITCH, 0, null);
442 this.locals = null;
443 this.stack = null;
444 }
445
446 @Override
447 public void visitMultiANewArrayInsn(final String desc, final int dims) {
448 if (mv != null) {
449 mv.visitMultiANewArrayInsn(desc, dims);
450 }
451 execute(Opcodes.MULTIANEWARRAY, dims, desc);
452 }
453
454 @Override
455 public void visitMaxs(final int maxStack, final int maxLocals) {
456 if (mv != null) {
457 this.maxStack = Math.max(this.maxStack, maxStack);
458 this.maxLocals = Math.max(this.maxLocals, maxLocals);
459 mv.visitMaxs(this.maxStack, this.maxLocals);
460 }
461 }
462
463 // ------------------------------------------------------------------------
464
465 private Object get(final int local) {
466 maxLocals = Math.max(maxLocals, local);
467 return local < locals.size() ? locals.get(local) : Opcodes.TOP;
468 }
469
470 private void set(final int local, final Object type) {
471 maxLocals = Math.max(maxLocals, local);
472 while (local >= locals.size()) {
473 locals.add(Opcodes.TOP);
474 }
475 locals.set(local, type);
476 }
477
478 private void push(final Object type) {
479 stack.add(type);
480 maxStack = Math.max(maxStack, stack.size());
481 }
482
483 private void pushDesc(final String desc) {
484 int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
485 switch (desc.charAt(index)) {
486 case 'V':
487 return;
488 case 'Z':
489 case 'C':
490 case 'B':
491 case 'S':
492 case 'I':
493 push(Opcodes.INTEGER);
494 return;
495 case 'F':
496 push(Opcodes.FLOAT);
497 return;
498 case 'J':
499 push(Opcodes.LONG);
500 push(Opcodes.TOP);
501 return;
502 case 'D':
503 push(Opcodes.DOUBLE);
504 push(Opcodes.TOP);
505 return;
506 case '[':
507 if (index == 0) {
508 push(desc);
509 } else {
510 push(desc.substring(index, desc.length()));
511 }
512 break;
513 // case 'L':
514 default:
515 if (index == 0) {
516 push(desc.substring(1, desc.length() - 1));
517 } else {
518 push(desc.substring(index + 1, desc.length() - 1));
519 }
520 }
521 }
522
523 private Object pop() {
524 return stack.remove(stack.size() - 1);
525 }
526
527 private void pop(final int n) {
528 int size = stack.size();
529 int end = size - n;
530 for (int i = size - 1; i >= end; --i) {
531 stack.remove(i);
532 }
533 }
534
535 private void pop(final String desc) {
536 char c = desc.charAt(0);
537 if (c == '(') {
538 int n = 0;
539 Type[] types = Type.getArgumentTypes(desc);
540 for (int i = 0; i < types.length; ++i) {
541 n += types[i].getSize();
542 }
543 pop(n);
544 } else if (c == 'J' || c == 'D') {
545 pop(2);
546 } else {
547 pop(1);
548 }
549 }
550
551 private void execute(final int opcode, final int iarg, final String sarg) {
552 if (this.locals == null) {
553 labels = null;
554 return;
555 }
556 Object t1, t2, t3, t4;
557 switch (opcode) {
558 case Opcodes.NOP:
559 case Opcodes.INEG:
560 case Opcodes.LNEG:
561 case Opcodes.FNEG:
562 case Opcodes.DNEG:
563 case Opcodes.I2B:
564 case Opcodes.I2C:
565 case Opcodes.I2S:
566 case Opcodes.GOTO:
567 case Opcodes.RETURN:
568 break;
569 case Opcodes.ACONST_NULL:
570 push(Opcodes.NULL);
571 break;
572 case Opcodes.ICONST_M1:
573 case Opcodes.ICONST_0:
574 case Opcodes.ICONST_1:
575 case Opcodes.ICONST_2:
576 case Opcodes.ICONST_3:
577 case Opcodes.ICONST_4:
578 case Opcodes.ICONST_5:
579 case Opcodes.BIPUSH:
580 case Opcodes.SIPUSH:
581 push(Opcodes.INTEGER);
582 break;
583 case Opcodes.LCONST_0:
584 case Opcodes.LCONST_1:
585 push(Opcodes.LONG);
586 push(Opcodes.TOP);
587 break;
588 case Opcodes.FCONST_0:
589 case Opcodes.FCONST_1:
590 case Opcodes.FCONST_2:
591 push(Opcodes.FLOAT);
592 break;
593 case Opcodes.DCONST_0:
594 case Opcodes.DCONST_1:
595 push(Opcodes.DOUBLE);
596 push(Opcodes.TOP);
597 break;
598 case Opcodes.ILOAD:
599 case Opcodes.FLOAD:
600 case Opcodes.ALOAD:
601 push(get(iarg));
602 break;
603 case Opcodes.LLOAD:
604 case Opcodes.DLOAD:
605 push(get(iarg));
606 push(Opcodes.TOP);
607 break;
608 case Opcodes.IALOAD:
609 case Opcodes.BALOAD:
610 case Opcodes.CALOAD:
611 case Opcodes.SALOAD:
612 pop(2);
613 push(Opcodes.INTEGER);
614 break;
615 case Opcodes.LALOAD:
616 case Opcodes.D2L:
617 pop(2);
618 push(Opcodes.LONG);
619 push(Opcodes.TOP);
620 break;
621 case Opcodes.FALOAD:
622 pop(2);
623 push(Opcodes.FLOAT);
624 break;
625 case Opcodes.DALOAD:
626 case Opcodes.L2D:
627 pop(2);
628 push(Opcodes.DOUBLE);
629 push(Opcodes.TOP);
630 break;
631 case Opcodes.AALOAD:
632 pop(1);
633 t1 = pop();
634 if (t1 instanceof String) {
635 pushDesc(((String) t1).substring(1));
636 } else {
637 push("java/lang/Object");
638 }
639 break;
640 case Opcodes.ISTORE:
641 case Opcodes.FSTORE:
642 case Opcodes.ASTORE:
643 t1 = pop();
644 set(iarg, t1);
645 if (iarg > 0) {
646 t2 = get(iarg - 1);
647 if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
648 set(iarg - 1, Opcodes.TOP);
649 }
650 }
651 break;
652 case Opcodes.LSTORE:
653 case Opcodes.DSTORE:
654 pop(1);
655 t1 = pop();
656 set(iarg, t1);
657 set(iarg + 1, Opcodes.TOP);
658 if (iarg > 0) {
659 t2 = get(iarg - 1);
660 if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
661 set(iarg - 1, Opcodes.TOP);
662 }
663 }
664 break;
665 case Opcodes.IASTORE:
666 case Opcodes.BASTORE:
667 case Opcodes.CASTORE:
668 case Opcodes.SASTORE:
669 case Opcodes.FASTORE:
670 case Opcodes.AASTORE:
671 pop(3);
672 break;
673 case Opcodes.LASTORE:
674 case Opcodes.DASTORE:
675 pop(4);
676 break;
677 case Opcodes.POP:
678 case Opcodes.IFEQ:
679 case Opcodes.IFNE:
680 case Opcodes.IFLT:
681 case Opcodes.IFGE:
682 case Opcodes.IFGT:
683 case Opcodes.IFLE:
684 case Opcodes.IRETURN:
685 case Opcodes.FRETURN:
686 case Opcodes.ARETURN:
687 case Opcodes.TABLESWITCH:
688 case Opcodes.LOOKUPSWITCH:
689 case Opcodes.ATHROW:
690 case Opcodes.MONITORENTER:
691 case Opcodes.MONITOREXIT:
692 case Opcodes.IFNULL:
693 case Opcodes.IFNONNULL:
694 pop(1);
695 break;
696 case Opcodes.POP2:
697 case Opcodes.IF_ICMPEQ:
698 case Opcodes.IF_ICMPNE:
699 case Opcodes.IF_ICMPLT:
700 case Opcodes.IF_ICMPGE:
701 case Opcodes.IF_ICMPGT:
702 case Opcodes.IF_ICMPLE:
703 case Opcodes.IF_ACMPEQ:
704 case Opcodes.IF_ACMPNE:
705 case Opcodes.LRETURN:
706 case Opcodes.DRETURN:
707 pop(2);
708 break;
709 case Opcodes.DUP:
710 t1 = pop();
711 push(t1);
712 push(t1);
713 break;
714 case Opcodes.DUP_X1:
715 t1 = pop();
716 t2 = pop();
717 push(t1);
718 push(t2);
719 push(t1);
720 break;
721 case Opcodes.DUP_X2:
722 t1 = pop();
723 t2 = pop();
724 t3 = pop();
725 push(t1);
726 push(t3);
727 push(t2);
728 push(t1);
729 break;
730 case Opcodes.DUP2:
731 t1 = pop();
732 t2 = pop();
733 push(t2);
734 push(t1);
735 push(t2);
736 push(t1);
737 break;
738 case Opcodes.DUP2_X1:
739 t1 = pop();
740 t2 = pop();
741 t3 = pop();
742 push(t2);
743 push(t1);
744 push(t3);
745 push(t2);
746 push(t1);
747 break;
748 case Opcodes.DUP2_X2:
749 t1 = pop();
750 t2 = pop();
751 t3 = pop();
752 t4 = pop();
753 push(t2);
754 push(t1);
755 push(t4);
756 push(t3);
757 push(t2);
758 push(t1);
759 break;
760 case Opcodes.SWAP:
761 t1 = pop();
762 t2 = pop();
763 push(t1);
764 push(t2);
765 break;
766 case Opcodes.IADD:
767 case Opcodes.ISUB:
768 case Opcodes.IMUL:
769 case Opcodes.IDIV:
770 case Opcodes.IREM:
771 case Opcodes.IAND:
772 case Opcodes.IOR:
773 case Opcodes.IXOR:
774 case Opcodes.ISHL:
775 case Opcodes.ISHR:
776 case Opcodes.IUSHR:
777 case Opcodes.L2I:
778 case Opcodes.D2I:
779 case Opcodes.FCMPL:
780 case Opcodes.FCMPG:
781 pop(2);
782 push(Opcodes.INTEGER);
783 break;
784 case Opcodes.LADD:
785 case Opcodes.LSUB:
786 case Opcodes.LMUL:
787 case Opcodes.LDIV:
788 case Opcodes.LREM:
789 case Opcodes.LAND:
790 case Opcodes.LOR:
791 case Opcodes.LXOR:
792 pop(4);
793 push(Opcodes.LONG);
794 push(Opcodes.TOP);
795 break;
796 case Opcodes.FADD:
797 case Opcodes.FSUB:
798 case Opcodes.FMUL:
799 case Opcodes.FDIV:
800 case Opcodes.FREM:
801 case Opcodes.L2F:
802 case Opcodes.D2F:
803 pop(2);
804 push(Opcodes.FLOAT);
805 break;
806 case Opcodes.DADD:
807 case Opcodes.DSUB:
808 case Opcodes.DMUL:
809 case Opcodes.DDIV:
810 case Opcodes.DREM:
811 pop(4);
812 push(Opcodes.DOUBLE);
813 push(Opcodes.TOP);
814 break;
815 case Opcodes.LSHL:
816 case Opcodes.LSHR:
817 case Opcodes.LUSHR:
818 pop(3);
819 push(Opcodes.LONG);
820 push(Opcodes.TOP);
821 break;
822 case Opcodes.IINC:
823 set(iarg, Opcodes.INTEGER);
824 break;
825 case Opcodes.I2L:
826 case Opcodes.F2L:
827 pop(1);
828 push(Opcodes.LONG);
829 push(Opcodes.TOP);
830 break;
831 case Opcodes.I2F:
832 pop(1);
833 push(Opcodes.FLOAT);
834 break;
835 case Opcodes.I2D:
836 case Opcodes.F2D:
837 pop(1);
838 push(Opcodes.DOUBLE);
839 push(Opcodes.TOP);
840 break;
841 case Opcodes.F2I:
842 case Opcodes.ARRAYLENGTH:
843 case Opcodes.INSTANCEOF:
844 pop(1);
845 push(Opcodes.INTEGER);
846 break;
847 case Opcodes.LCMP:
848 case Opcodes.DCMPL:
849 case Opcodes.DCMPG:
850 pop(4);
851 push(Opcodes.INTEGER);
852 break;
853 case Opcodes.JSR:
854 case Opcodes.RET:
855 throw new RuntimeException("JSR/RET are not supported");
856 case Opcodes.GETSTATIC:
857 pushDesc(sarg);
858 break;
859 case Opcodes.PUTSTATIC:
860 pop(sarg);
861 break;
862 case Opcodes.GETFIELD:
863 pop(1);
864 pushDesc(sarg);
865 break;
866 case Opcodes.PUTFIELD:
867 pop(sarg);
868 pop();
869 break;
870 case Opcodes.NEW:
871 push(labels.get(0));
872 break;
873 case Opcodes.NEWARRAY:
874 pop();
875 switch (iarg) {
876 case Opcodes.T_BOOLEAN:
877 pushDesc("[Z");
878 break;
879 case Opcodes.T_CHAR:
880 pushDesc("[C");
881 break;
882 case Opcodes.T_BYTE:
883 pushDesc("[B");
884 break;
885 case Opcodes.T_SHORT:
886 pushDesc("[S");
887 break;
888 case Opcodes.T_INT:
889 pushDesc("[I");
890 break;
891 case Opcodes.T_FLOAT:
892 pushDesc("[F");
893 break;
894 case Opcodes.T_DOUBLE:
895 pushDesc("[D");
896 break;
897 // case Opcodes.T_LONG:
898 default:
899 pushDesc("[J");
900 break;
901 }
902 break;
903 case Opcodes.ANEWARRAY:
904 pop();
905 pushDesc("[" + Type.getObjectType(sarg));
906 break;
907 case Opcodes.CHECKCAST:
908 pop();
909 pushDesc(Type.getObjectType(sarg).getDescriptor());
910 break;
911 // case Opcodes.MULTIANEWARRAY:
912 default:
913 pop(iarg);
914 pushDesc(sarg);
915 break;
916 }
917 labels = null;
918 }
919 }
+0
-217
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-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package clojure.asm.commons;
30
31 import clojure.asm.Handle;
32 import clojure.asm.Label;
33 import clojure.asm.MethodVisitor;
34 import clojure.asm.Opcodes;
35
36 /**
37 * A {@link MethodVisitor} that can be used to approximate method size.
38 *
39 * @author Eugene Kuleshov
40 */
41 public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
42
43 private int minSize;
44
45 private int maxSize;
46
47 public CodeSizeEvaluator(final MethodVisitor mv) {
48 this(Opcodes.ASM4, mv);
49 }
50
51 protected CodeSizeEvaluator(final int api, final MethodVisitor mv) {
52 super(api, mv);
53 }
54
55 public int getMinSize() {
56 return this.minSize;
57 }
58
59 public int getMaxSize() {
60 return this.maxSize;
61 }
62
63 @Override
64 public void visitInsn(final int opcode) {
65 minSize += 1;
66 maxSize += 1;
67 if (mv != null) {
68 mv.visitInsn(opcode);
69 }
70 }
71
72 @Override
73 public void visitIntInsn(final int opcode, final int operand) {
74 if (opcode == SIPUSH) {
75 minSize += 3;
76 maxSize += 3;
77 } else {
78 minSize += 2;
79 maxSize += 2;
80 }
81 if (mv != null) {
82 mv.visitIntInsn(opcode, operand);
83 }
84 }
85
86 @Override
87 public void visitVarInsn(final int opcode, final int var) {
88 if (var < 4 && opcode != RET) {
89 minSize += 1;
90 maxSize += 1;
91 } else if (var >= 256) {
92 minSize += 4;
93 maxSize += 4;
94 } else {
95 minSize += 2;
96 maxSize += 2;
97 }
98 if (mv != null) {
99 mv.visitVarInsn(opcode, var);
100 }
101 }
102
103 @Override
104 public void visitTypeInsn(final int opcode, final String type) {
105 minSize += 3;
106 maxSize += 3;
107 if (mv != null) {
108 mv.visitTypeInsn(opcode, type);
109 }
110 }
111
112 @Override
113 public void visitFieldInsn(final int opcode, final String owner,
114 final String name, final String desc) {
115 minSize += 3;
116 maxSize += 3;
117 if (mv != null) {
118 mv.visitFieldInsn(opcode, owner, name, desc);
119 }
120 }
121
122 @Override
123 public void visitMethodInsn(final int opcode, final String owner,
124 final String name, final String desc) {
125 if (opcode == INVOKEINTERFACE) {
126 minSize += 5;
127 maxSize += 5;
128 } else {
129 minSize += 3;
130 maxSize += 3;
131 }
132 if (mv != null) {
133 mv.visitMethodInsn(opcode, owner, name, desc);
134 }
135 }
136
137 @Override
138 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
139 Object... bsmArgs) {
140 minSize += 5;
141 maxSize += 5;
142 if (mv != null) {
143 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
144 }
145 }
146
147 @Override
148 public void visitJumpInsn(final int opcode, final Label label) {
149 minSize += 3;
150 if (opcode == GOTO || opcode == JSR) {
151 maxSize += 5;
152 } else {
153 maxSize += 8;
154 }
155 if (mv != null) {
156 mv.visitJumpInsn(opcode, label);
157 }
158 }
159
160 @Override
161 public void visitLdcInsn(final Object cst) {
162 if (cst instanceof Long || cst instanceof Double) {
163 minSize += 3;
164 maxSize += 3;
165 } else {
166 minSize += 2;
167 maxSize += 3;
168 }
169 if (mv != null) {
170 mv.visitLdcInsn(cst);
171 }
172 }
173
174 @Override
175 public void visitIincInsn(final int var, final int increment) {
176 if (var > 255 || increment > 127 || increment < -128) {
177 minSize += 6;
178 maxSize += 6;
179 } else {
180 minSize += 3;
181 maxSize += 3;
182 }
183 if (mv != null) {
184 mv.visitIincInsn(var, increment);
185 }
186 }
187
188 @Override
189 public void visitTableSwitchInsn(final int min, final int max,
190 final Label dflt, final Label... labels) {
191 minSize += 13 + labels.length * 4;
192 maxSize += 16 + labels.length * 4;
193 if (mv != null) {
194 mv.visitTableSwitchInsn(min, max, dflt, labels);
195 }
196 }
197
198 @Override
199 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
200 final Label[] labels) {
201 minSize += 9 + keys.length * 8;
202 maxSize += 12 + keys.length * 8;
203 if (mv != null) {
204 mv.visitLookupSwitchInsn(dflt, keys, labels);
205 }
206 }
207
208 @Override
209 public void visitMultiANewArrayInsn(final String desc, final int dims) {
210 minSize += 4;
211 maxSize += 4;
212 if (mv != null) {
213 mv.visitMultiANewArrayInsn(desc, dims);
214 }
215 }
216 }
+0
-1623
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-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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.Handle;
37 import clojure.asm.Label;
38 import clojure.asm.MethodVisitor;
39 import clojure.asm.Opcodes;
40 import clojure.asm.Type;
41
42 /**
43 * A {@link clojure.asm.MethodVisitor} with convenient methods to generate
44 * code. For example, using this adapter, the class below
45 *
46 * <pre>
47 * public class Example {
48 * public static void main(String[] args) {
49 * System.out.println(&quot;Hello world!&quot;);
50 * }
51 * }
52 * </pre>
53 *
54 * can be generated as follows:
55 *
56 * <pre>
57 * ClassWriter cw = new ClassWriter(true);
58 * cw.visit(V1_1, ACC_PUBLIC, &quot;Example&quot;, null, &quot;java/lang/Object&quot;, null);
59 *
60 * Method m = Method.getMethod(&quot;void &lt;init&gt; ()&quot;);
61 * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
62 * mg.loadThis();
63 * mg.invokeConstructor(Type.getType(Object.class), m);
64 * mg.returnValue();
65 * mg.endMethod();
66 *
67 * m = Method.getMethod(&quot;void main (String[])&quot;);
68 * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
69 * mg.getStatic(Type.getType(System.class), &quot;out&quot;, Type.getType(PrintStream.class));
70 * mg.push(&quot;Hello world!&quot;);
71 * mg.invokeVirtual(Type.getType(PrintStream.class),
72 * Method.getMethod(&quot;void println (String)&quot;));
73 * mg.returnValue();
74 * mg.endMethod();
75 *
76 * cw.visitEnd();
77 * </pre>
78 *
79 * @author Juozas Baliuka
80 * @author Chris Nokleberg
81 * @author Eric Bruneton
82 * @author Prashant Deva
83 */
84 public class GeneratorAdapter extends LocalVariablesSorter {
85
86 private static final String CLDESC = "Ljava/lang/Class;";
87
88 private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
89
90 private static final Type BOOLEAN_TYPE = Type
91 .getObjectType("java/lang/Boolean");
92
93 private static final Type SHORT_TYPE = Type
94 .getObjectType("java/lang/Short");
95
96 private static final Type CHARACTER_TYPE = Type
97 .getObjectType("java/lang/Character");
98
99 private static final Type INTEGER_TYPE = Type
100 .getObjectType("java/lang/Integer");
101
102 private static final Type FLOAT_TYPE = Type
103 .getObjectType("java/lang/Float");
104
105 private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long");
106
107 private static final Type DOUBLE_TYPE = Type
108 .getObjectType("java/lang/Double");
109
110 private static final Type NUMBER_TYPE = Type
111 .getObjectType("java/lang/Number");
112
113 private static final Type OBJECT_TYPE = Type
114 .getObjectType("java/lang/Object");
115
116 private static final Method BOOLEAN_VALUE = Method
117 .getMethod("boolean booleanValue()");
118
119 private static final Method CHAR_VALUE = Method
120 .getMethod("char charValue()");
121
122 private static final Method INT_VALUE = Method.getMethod("int intValue()");
123
124 private static final Method FLOAT_VALUE = Method
125 .getMethod("float floatValue()");
126
127 private static final Method LONG_VALUE = Method
128 .getMethod("long longValue()");
129
130 private static final Method DOUBLE_VALUE = Method
131 .getMethod("double doubleValue()");
132
133 /**
134 * Constant for the {@link #math math} method.
135 */
136 public static final int ADD = Opcodes.IADD;
137
138 /**
139 * Constant for the {@link #math math} method.
140 */
141 public static final int SUB = Opcodes.ISUB;
142
143 /**
144 * Constant for the {@link #math math} method.
145 */
146 public static final int MUL = Opcodes.IMUL;
147
148 /**
149 * Constant for the {@link #math math} method.
150 */
151 public static final int DIV = Opcodes.IDIV;
152
153 /**
154 * Constant for the {@link #math math} method.
155 */
156 public static final int REM = Opcodes.IREM;
157
158 /**
159 * Constant for the {@link #math math} method.
160 */
161 public static final int NEG = Opcodes.INEG;
162
163 /**
164 * Constant for the {@link #math math} method.
165 */
166 public static final int SHL = Opcodes.ISHL;
167
168 /**
169 * Constant for the {@link #math math} method.
170 */
171 public static final int SHR = Opcodes.ISHR;
172
173 /**
174 * Constant for the {@link #math math} method.
175 */
176 public static final int USHR = Opcodes.IUSHR;
177
178 /**
179 * Constant for the {@link #math math} method.
180 */
181 public static final int AND = Opcodes.IAND;
182
183 /**
184 * Constant for the {@link #math math} method.
185 */
186 public static final int OR = Opcodes.IOR;
187
188 /**
189 * Constant for the {@link #math math} method.
190 */
191 public static final int XOR = Opcodes.IXOR;
192
193 /**
194 * Constant for the {@link #ifCmp ifCmp} method.
195 */
196 public static final int EQ = Opcodes.IFEQ;
197
198 /**
199 * Constant for the {@link #ifCmp ifCmp} method.
200 */
201 public static final int NE = Opcodes.IFNE;
202
203 /**
204 * Constant for the {@link #ifCmp ifCmp} method.
205 */
206 public static final int LT = Opcodes.IFLT;
207
208 /**
209 * Constant for the {@link #ifCmp ifCmp} method.
210 */
211 public static final int GE = Opcodes.IFGE;
212
213 /**
214 * Constant for the {@link #ifCmp ifCmp} method.
215 */
216 public static final int GT = Opcodes.IFGT;
217
218 /**
219 * Constant for the {@link #ifCmp ifCmp} method.
220 */
221 public static final int LE = Opcodes.IFLE;
222
223 /**
224 * Access flags of the method visited by this adapter.
225 */
226 private final int access;
227
228 /**
229 * Return type of the method visited by this adapter.
230 */
231 private final Type returnType;
232
233 /**
234 * Argument types of the method visited by this adapter.
235 */
236 private final Type[] argumentTypes;
237
238 /**
239 * Types of the local variables of the method visited by this adapter.
240 */
241 private final List<Type> localTypes = new ArrayList<Type>();
242
243 /**
244 * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
245 * constructor</i>. Instead, they must use the
246 * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
247 * version.
248 *
249 * @param mv
250 * the method visitor to which this adapter delegates calls.
251 * @param access
252 * the method's access flags (see {@link Opcodes}).
253 * @param name
254 * the method's name.
255 * @param desc
256 * the method's descriptor (see {@link Type Type}).
257 */
258 public GeneratorAdapter(final MethodVisitor mv, final int access,
259 final String name, final String desc) {
260 this(Opcodes.ASM4, mv, access, name, desc);
261 }
262
263 /**
264 * Creates a new {@link GeneratorAdapter}.
265 *
266 * @param api
267 * the ASM API version implemented by this visitor. Must be one
268 * of {@link Opcodes#ASM4}.
269 * @param mv
270 * the method visitor to which this adapter delegates calls.
271 * @param access
272 * the method's access flags (see {@link Opcodes}).
273 * @param name
274 * the method's name.
275 * @param desc
276 * the method's descriptor (see {@link Type Type}).
277 */
278 protected GeneratorAdapter(final int api, final MethodVisitor mv,
279 final int access, final String name, final String desc) {
280 super(api, access, desc, mv);
281 this.access = access;
282 this.returnType = Type.getReturnType(desc);
283 this.argumentTypes = Type.getArgumentTypes(desc);
284 }
285
286 /**
287 * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
288 * constructor</i>. Instead, they must use the
289 * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
290 * version.
291 *
292 * @param access
293 * access flags of the adapted method.
294 * @param method
295 * the adapted method.
296 * @param mv
297 * the method visitor to which this adapter delegates calls.
298 */
299 public GeneratorAdapter(final int access, final Method method,
300 final MethodVisitor mv) {
301 this(mv, access, null, method.getDescriptor());
302 }
303
304 /**
305 * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this
306 * constructor</i>. Instead, they must use the
307 * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)}
308 * version.
309 *
310 * @param access
311 * access flags of the adapted method.
312 * @param method
313 * the adapted method.
314 * @param signature
315 * the signature of the adapted method (may be <tt>null</tt>).
316 * @param exceptions
317 * the exceptions thrown by the adapted method (may be
318 * <tt>null</tt>).
319 * @param cv
320 * the class visitor to which this adapter delegates calls.
321 */
322 public GeneratorAdapter(final int access, final Method method,
323 final String signature, final Type[] exceptions,
324 final ClassVisitor cv) {
325 this(access, method, cv
326 .visitMethod(access, method.getName(), method.getDescriptor(),
327 signature, getInternalNames(exceptions)));
328 }
329
330 /**
331 * Returns the internal names of the given types.
332 *
333 * @param types
334 * a set of types.
335 * @return the internal names of the given types.
336 */
337 private static String[] getInternalNames(final Type[] types) {
338 if (types == null) {
339 return null;
340 }
341 String[] names = new String[types.length];
342 for (int i = 0; i < names.length; ++i) {
343 names[i] = types[i].getInternalName();
344 }
345 return names;
346 }
347
348 // ------------------------------------------------------------------------
349 // Instructions to push constants on the stack
350 // ------------------------------------------------------------------------
351
352 /**
353 * Generates the instruction to push the given value on the stack.
354 *
355 * @param value
356 * the value to be pushed on the stack.
357 */
358 public void push(final boolean value) {
359 push(value ? 1 : 0);
360 }
361
362 /**
363 * Generates the instruction to push the given value on the stack.
364 *
365 * @param value
366 * the value to be pushed on the stack.
367 */
368 public void push(final int value) {
369 if (value >= -1 && value <= 5) {
370 mv.visitInsn(Opcodes.ICONST_0 + value);
371 } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
372 mv.visitIntInsn(Opcodes.BIPUSH, value);
373 } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
374 mv.visitIntInsn(Opcodes.SIPUSH, value);
375 } else {
376 mv.visitLdcInsn(new Integer(value));
377 }
378 }
379
380 /**
381 * Generates the instruction to push the given value on the stack.
382 *
383 * @param value
384 * the value to be pushed on the stack.
385 */
386 public void push(final long value) {
387 if (value == 0L || value == 1L) {
388 mv.visitInsn(Opcodes.LCONST_0 + (int) value);
389 } else {
390 mv.visitLdcInsn(new Long(value));
391 }
392 }
393
394 /**
395 * Generates the instruction to push the given value on the stack.
396 *
397 * @param value
398 * the value to be pushed on the stack.
399 */
400 public void push(final float value) {
401 int bits = Float.floatToIntBits(value);
402 if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
403 mv.visitInsn(Opcodes.FCONST_0 + (int) value);
404 } else {
405 mv.visitLdcInsn(new Float(value));
406 }
407 }
408
409 /**
410 * Generates the instruction to push the given value on the stack.
411 *
412 * @param value
413 * the value to be pushed on the stack.
414 */
415 public void push(final double value) {
416 long bits = Double.doubleToLongBits(value);
417 if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
418 mv.visitInsn(Opcodes.DCONST_0 + (int) value);
419 } else {
420 mv.visitLdcInsn(new Double(value));
421 }
422 }
423
424 /**
425 * Generates the instruction to push the given value on the stack.
426 *
427 * @param value
428 * the value to be pushed on the stack. May be <tt>null</tt>.
429 */
430 public void push(final String value) {
431 if (value == null) {
432 mv.visitInsn(Opcodes.ACONST_NULL);
433 } else {
434 mv.visitLdcInsn(value);
435 }
436 }
437
438 /**
439 * Generates the instruction to push the given value on the stack.
440 *
441 * @param value
442 * the value to be pushed on the stack.
443 */
444 public void push(final Type value) {
445 if (value == null) {
446 mv.visitInsn(Opcodes.ACONST_NULL);
447 } else {
448 switch (value.getSort()) {
449 case Type.BOOLEAN:
450 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean",
451 "TYPE", CLDESC);
452 break;
453 case Type.CHAR:
454 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character",
455 "TYPE", CLDESC);
456 break;
457 case Type.BYTE:
458 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE",
459 CLDESC);
460 break;
461 case Type.SHORT:
462 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE",
463 CLDESC);
464 break;
465 case Type.INT:
466 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer",
467 "TYPE", CLDESC);
468 break;
469 case Type.FLOAT:
470 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE",
471 CLDESC);
472 break;
473 case Type.LONG:
474 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE",
475 CLDESC);
476 break;
477 case Type.DOUBLE:
478 mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double",
479 "TYPE", CLDESC);
480 break;
481 default:
482 mv.visitLdcInsn(value);
483 }
484 }
485 }
486
487 /**
488 * Generates the instruction to push a handle on the stack.
489 *
490 * @param handle
491 * the handle to be pushed on the stack.
492 */
493 public void push(final Handle handle) {
494 mv.visitLdcInsn(handle);
495 }
496
497 // ------------------------------------------------------------------------
498 // Instructions to load and store method arguments
499 // ------------------------------------------------------------------------
500
501 /**
502 * Returns the index of the given method argument in the frame's local
503 * variables array.
504 *
505 * @param arg
506 * the index of a method argument.
507 * @return the index of the given method argument in the frame's local
508 * variables array.
509 */
510 private int getArgIndex(final int arg) {
511 int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
512 for (int i = 0; i < arg; i++) {
513 index += argumentTypes[i].getSize();
514 }
515 return index;
516 }
517
518 /**
519 * Generates the instruction to push a local variable on the stack.
520 *
521 * @param type
522 * the type of the local variable to be loaded.
523 * @param index
524 * an index in the frame's local variables array.
525 */
526 private void loadInsn(final Type type, final int index) {
527 mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
528 }
529
530 /**
531 * Generates the instruction to store the top stack value in a local
532 * variable.
533 *
534 * @param type
535 * the type of the local variable to be stored.
536 * @param index
537 * an index in the frame's local variables array.
538 */
539 private void storeInsn(final Type type, final int index) {
540 mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
541 }
542
543 /**
544 * Generates the instruction to load 'this' on the stack.
545 */
546 public void loadThis() {
547 if ((access & Opcodes.ACC_STATIC) != 0) {
548 throw new IllegalStateException(
549 "no 'this' pointer within static method");
550 }
551 mv.visitVarInsn(Opcodes.ALOAD, 0);
552 }
553
554 /**
555 * Generates the instruction to load the given method argument on the stack.
556 *
557 * @param arg
558 * the index of a method argument.
559 */
560 public void loadArg(final int arg) {
561 loadInsn(argumentTypes[arg], getArgIndex(arg));
562 }
563
564 /**
565 * Generates the instructions to load the given method arguments on the
566 * stack.
567 *
568 * @param arg
569 * the index of the first method argument to be loaded.
570 * @param count
571 * the number of method arguments to be loaded.
572 */
573 public void loadArgs(final int arg, final int count) {
574 int index = getArgIndex(arg);
575 for (int i = 0; i < count; ++i) {
576 Type t = argumentTypes[arg + i];
577 loadInsn(t, index);
578 index += t.getSize();
579 }
580 }
581
582 /**
583 * Generates the instructions to load all the method arguments on the stack.
584 */
585 public void loadArgs() {
586 loadArgs(0, argumentTypes.length);
587 }
588
589 /**
590 * Generates the instructions to load all the method arguments on the stack,
591 * as a single object array.
592 */
593 public void loadArgArray() {
594 push(argumentTypes.length);
595 newArray(OBJECT_TYPE);
596 for (int i = 0; i < argumentTypes.length; i++) {
597 dup();
598 push(i);
599 loadArg(i);
600 box(argumentTypes[i]);
601 arrayStore(OBJECT_TYPE);
602 }
603 }
604
605 /**
606 * Generates the instruction to store the top stack value in the given
607 * method argument.
608 *
609 * @param arg
610 * the index of a method argument.
611 */
612 public void storeArg(final int arg) {
613 storeInsn(argumentTypes[arg], getArgIndex(arg));
614 }
615
616 // ------------------------------------------------------------------------
617 // Instructions to load and store local variables
618 // ------------------------------------------------------------------------
619
620 /**
621 * Returns the type of the given local variable.
622 *
623 * @param local
624 * a local variable identifier, as returned by
625 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
626 * @return the type of the given local variable.
627 */
628 public Type getLocalType(final int local) {
629 return localTypes.get(local - firstLocal);
630 }
631
632 @Override
633 protected void setLocalType(final int local, final Type type) {
634 int index = local - firstLocal;
635 while (localTypes.size() < index + 1) {
636 localTypes.add(null);
637 }
638 localTypes.set(index, type);
639 }
640
641 /**
642 * Generates the instruction to load the given local variable on the stack.
643 *
644 * @param local
645 * a local variable identifier, as returned by
646 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
647 */
648 public void loadLocal(final int local) {
649 loadInsn(getLocalType(local), local);
650 }
651
652 /**
653 * Generates the instruction to load the given local variable on the stack.
654 *
655 * @param local
656 * a local variable identifier, as returned by
657 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
658 * @param type
659 * the type of this local variable.
660 */
661 public void loadLocal(final int local, final Type type) {
662 setLocalType(local, type);
663 loadInsn(type, local);
664 }
665
666 /**
667 * Generates the instruction to store the top stack value in the given local
668 * variable.
669 *
670 * @param local
671 * a local variable identifier, as returned by
672 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
673 */
674 public void storeLocal(final int local) {
675 storeInsn(getLocalType(local), local);
676 }
677
678 /**
679 * Generates the instruction to store the top stack value in the given local
680 * variable.
681 *
682 * @param local
683 * a local variable identifier, as returned by
684 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
685 * @param type
686 * the type of this local variable.
687 */
688 public void storeLocal(final int local, final Type type) {
689 setLocalType(local, type);
690 storeInsn(type, local);
691 }
692
693 /**
694 * Generates the instruction to load an element from an array.
695 *
696 * @param type
697 * the type of the array element to be loaded.
698 */
699 public void arrayLoad(final Type type) {
700 mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
701 }
702
703 /**
704 * Generates the instruction to store an element in an array.
705 *
706 * @param type
707 * the type of the array element to be stored.
708 */
709 public void arrayStore(final Type type) {
710 mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
711 }
712
713 // ------------------------------------------------------------------------
714 // Instructions to manage the stack
715 // ------------------------------------------------------------------------
716
717 /**
718 * Generates a POP instruction.
719 */
720 public void pop() {
721 mv.visitInsn(Opcodes.POP);
722 }
723
724 /**
725 * Generates a POP2 instruction.
726 */
727 public void pop2() {
728 mv.visitInsn(Opcodes.POP2);
729 }
730
731 /**
732 * Generates a DUP instruction.
733 */
734 public void dup() {
735 mv.visitInsn(Opcodes.DUP);
736 }
737
738 /**
739 * Generates a DUP2 instruction.
740 */
741 public void dup2() {
742 mv.visitInsn(Opcodes.DUP2);
743 }
744
745 /**
746 * Generates a DUP_X1 instruction.
747 */
748 public void dupX1() {
749 mv.visitInsn(Opcodes.DUP_X1);
750 }
751
752 /**
753 * Generates a DUP_X2 instruction.
754 */
755 public void dupX2() {
756 mv.visitInsn(Opcodes.DUP_X2);
757 }
758
759 /**
760 * Generates a DUP2_X1 instruction.
761 */
762 public void dup2X1() {
763 mv.visitInsn(Opcodes.DUP2_X1);
764 }
765
766 /**
767 * Generates a DUP2_X2 instruction.
768 */
769 public void dup2X2() {
770 mv.visitInsn(Opcodes.DUP2_X2);
771 }
772
773 /**
774 * Generates a SWAP instruction.
775 */
776 public void swap() {
777 mv.visitInsn(Opcodes.SWAP);
778 }
779
780 /**
781 * Generates the instructions to swap the top two stack values.
782 *
783 * @param prev
784 * type of the top - 1 stack value.
785 * @param type
786 * type of the top stack value.
787 */
788 public void swap(final Type prev, final Type type) {
789 if (type.getSize() == 1) {
790 if (prev.getSize() == 1) {
791 swap(); // same as dupX1(), pop();
792 } else {
793 dupX2();
794 pop();
795 }
796 } else {
797 if (prev.getSize() == 1) {
798 dup2X1();
799 pop2();
800 } else {
801 dup2X2();
802 pop2();
803 }
804 }
805 }
806
807 // ------------------------------------------------------------------------
808 // Instructions to do mathematical and logical operations
809 // ------------------------------------------------------------------------
810
811 /**
812 * Generates the instruction to do the specified mathematical or logical
813 * operation.
814 *
815 * @param op
816 * a mathematical or logical operation. Must be one of ADD, SUB,
817 * MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR.
818 * @param type
819 * the type of the operand(s) for this operation.
820 */
821 public void math(final int op, final Type type) {
822 mv.visitInsn(type.getOpcode(op));
823 }
824
825 /**
826 * Generates the instructions to compute the bitwise negation of the top
827 * stack value.
828 */
829 public void not() {
830 mv.visitInsn(Opcodes.ICONST_1);
831 mv.visitInsn(Opcodes.IXOR);
832 }
833
834 /**
835 * Generates the instruction to increment the given local variable.
836 *
837 * @param local
838 * the local variable to be incremented.
839 * @param amount
840 * the amount by which the local variable must be incremented.
841 */
842 public void iinc(final int local, final int amount) {
843 mv.visitIincInsn(local, amount);
844 }
845
846 /**
847 * Generates the instructions to cast a numerical value from one type to
848 * another.
849 *
850 * @param from
851 * the type of the top stack value
852 * @param to
853 * the type into which this value must be cast.
854 */
855 public void cast(final Type from, final Type to) {
856 if (from != to) {
857 if (from == Type.DOUBLE_TYPE) {
858 if (to == Type.FLOAT_TYPE) {
859 mv.visitInsn(Opcodes.D2F);
860 } else if (to == Type.LONG_TYPE) {
861 mv.visitInsn(Opcodes.D2L);
862 } else {
863 mv.visitInsn(Opcodes.D2I);
864 cast(Type.INT_TYPE, to);
865 }
866 } else if (from == Type.FLOAT_TYPE) {
867 if (to == Type.DOUBLE_TYPE) {
868 mv.visitInsn(Opcodes.F2D);
869 } else if (to == Type.LONG_TYPE) {
870 mv.visitInsn(Opcodes.F2L);
871 } else {
872 mv.visitInsn(Opcodes.F2I);
873 cast(Type.INT_TYPE, to);
874 }
875 } else if (from == Type.LONG_TYPE) {
876 if (to == Type.DOUBLE_TYPE) {
877 mv.visitInsn(Opcodes.L2D);
878 } else if (to == Type.FLOAT_TYPE) {
879 mv.visitInsn(Opcodes.L2F);
880 } else {
881 mv.visitInsn(Opcodes.L2I);
882 cast(Type.INT_TYPE, to);
883 }
884 } else {
885 if (to == Type.BYTE_TYPE) {
886 mv.visitInsn(Opcodes.I2B);
887 } else if (to == Type.CHAR_TYPE) {
888 mv.visitInsn(Opcodes.I2C);
889 } else if (to == Type.DOUBLE_TYPE) {
890 mv.visitInsn(Opcodes.I2D);
891 } else if (to == Type.FLOAT_TYPE) {
892 mv.visitInsn(Opcodes.I2F);
893 } else if (to == Type.LONG_TYPE) {
894 mv.visitInsn(Opcodes.I2L);
895 } else if (to == Type.SHORT_TYPE) {
896 mv.visitInsn(Opcodes.I2S);
897 }
898 }
899 }
900 }
901
902 // ------------------------------------------------------------------------
903 // Instructions to do boxing and unboxing operations
904 // ------------------------------------------------------------------------
905
906 private static Type getBoxedType(final Type type) {
907 switch (type.getSort()) {
908 case Type.BYTE:
909 return BYTE_TYPE;
910 case Type.BOOLEAN:
911 return BOOLEAN_TYPE;
912 case Type.SHORT:
913 return SHORT_TYPE;
914 case Type.CHAR:
915 return CHARACTER_TYPE;
916 case Type.INT:
917 return INTEGER_TYPE;
918 case Type.FLOAT:
919 return FLOAT_TYPE;
920 case Type.LONG:
921 return LONG_TYPE;
922 case Type.DOUBLE:
923 return DOUBLE_TYPE;
924 }
925 return type;
926 }
927
928 /**
929 * Generates the instructions to box the top stack value. This value is
930 * replaced by its boxed equivalent on top of the stack.
931 *
932 * @param type
933 * the type of the top stack value.
934 */
935 public void box(final Type type) {
936 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
937 return;
938 }
939 if (type == Type.VOID_TYPE) {
940 push((String) null);
941 } else {
942 Type boxed = getBoxedType(type);
943 newInstance(boxed);
944 if (type.getSize() == 2) {
945 // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
946 dupX2();
947 dupX2();
948 pop();
949 } else {
950 // p -> po -> opo -> oop -> o
951 dupX1();
952 swap();
953 }
954 invokeConstructor(boxed, new Method("<init>", Type.VOID_TYPE,
955 new Type[] { type }));
956 }
957 }
958
959 /**
960 * Generates the instructions to box the top stack value using Java 5's
961 * valueOf() method. This value is replaced by its boxed equivalent on top
962 * of the stack.
963 *
964 * @param type
965 * the type of the top stack value.
966 */
967 public void valueOf(final Type type) {
968 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
969 return;
970 }
971 if (type == Type.VOID_TYPE) {
972 push((String) null);
973 } else {
974 Type boxed = getBoxedType(type);
975 invokeStatic(boxed, new Method("valueOf", boxed,
976 new Type[] { type }));
977 }
978 }
979
980 /**
981 * Generates the instructions to unbox the top stack value. This value is
982 * replaced by its unboxed equivalent on top of the stack.
983 *
984 * @param type
985 * the type of the top stack value.
986 */
987 public void unbox(final Type type) {
988 Type t = NUMBER_TYPE;
989 Method sig = null;
990 switch (type.getSort()) {
991 case Type.VOID:
992 return;
993 case Type.CHAR:
994 t = CHARACTER_TYPE;
995 sig = CHAR_VALUE;
996 break;
997 case Type.BOOLEAN:
998 t = BOOLEAN_TYPE;
999 sig = BOOLEAN_VALUE;
1000 break;
1001 case Type.DOUBLE:
1002 sig = DOUBLE_VALUE;
1003 break;
1004 case Type.FLOAT:
1005 sig = FLOAT_VALUE;
1006 break;
1007 case Type.LONG:
1008 sig = LONG_VALUE;
1009 break;
1010 case Type.INT:
1011 case Type.SHORT:
1012 case Type.BYTE:
1013 sig = INT_VALUE;
1014 }
1015 if (sig == null) {
1016 checkCast(type);
1017 } else {
1018 checkCast(t);
1019 invokeVirtual(t, sig);
1020 }
1021 }
1022
1023 // ------------------------------------------------------------------------
1024 // Instructions to jump to other instructions
1025 // ------------------------------------------------------------------------
1026
1027 /**
1028 * Creates a new {@link Label}.
1029 *
1030 * @return a new {@link Label}.
1031 */
1032 public Label newLabel() {
1033 return new Label();
1034 }
1035
1036 /**
1037 * Marks the current code position with the given label.
1038 *
1039 * @param label
1040 * a label.
1041 */
1042 public void mark(final Label label) {
1043 mv.visitLabel(label);
1044 }
1045
1046 /**
1047 * Marks the current code position with a new label.
1048 *
1049 * @return the label that was created to mark the current code position.
1050 */
1051 public Label mark() {
1052 Label label = new Label();
1053 mv.visitLabel(label);
1054 return label;
1055 }
1056
1057 /**
1058 * Generates the instructions to jump to a label based on the comparison of
1059 * the top two stack values.
1060 *
1061 * @param type
1062 * the type of the top two stack values.
1063 * @param mode
1064 * how these values must be compared. One of EQ, NE, LT, GE, GT,
1065 * LE.
1066 * @param label
1067 * where to jump if the comparison result is <tt>true</tt>.
1068 */
1069 public void ifCmp(final Type type, final int mode, final Label label) {
1070 switch (type.getSort()) {
1071 case Type.LONG:
1072 mv.visitInsn(Opcodes.LCMP);
1073 break;
1074 case Type.DOUBLE:
1075 mv.visitInsn(mode == GE || mode == GT ? Opcodes.DCMPL
1076 : Opcodes.DCMPG);
1077 break;
1078 case Type.FLOAT:
1079 mv.visitInsn(mode == GE || mode == GT ? Opcodes.FCMPL
1080 : Opcodes.FCMPG);
1081 break;
1082 case Type.ARRAY:
1083 case Type.OBJECT:
1084 switch (mode) {
1085 case EQ:
1086 mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
1087 return;
1088 case NE:
1089 mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
1090 return;
1091 }
1092 throw new IllegalArgumentException("Bad comparison for type "
1093 + type);
1094 default:
1095 int intOp = -1;
1096 switch (mode) {
1097 case EQ:
1098 intOp = Opcodes.IF_ICMPEQ;
1099 break;
1100 case NE:
1101 intOp = Opcodes.IF_ICMPNE;
1102 break;
1103 case GE:
1104 intOp = Opcodes.IF_ICMPGE;
1105 break;
1106 case LT:
1107 intOp = Opcodes.IF_ICMPLT;
1108 break;
1109 case LE:
1110 intOp = Opcodes.IF_ICMPLE;
1111 break;
1112 case GT:
1113 intOp = Opcodes.IF_ICMPGT;
1114 break;
1115 }
1116 mv.visitJumpInsn(intOp, label);
1117 return;
1118 }
1119 mv.visitJumpInsn(mode, label);
1120 }
1121
1122 /**
1123 * Generates the instructions to jump to a label based on the comparison of
1124 * the top two integer stack values.
1125 *
1126 * @param mode
1127 * how these values must be compared. One of EQ, NE, LT, GE, GT,
1128 * LE.
1129 * @param label
1130 * where to jump if the comparison result is <tt>true</tt>.
1131 */
1132 public void ifICmp(final int mode, final Label label) {
1133 ifCmp(Type.INT_TYPE, mode, label);
1134 }
1135
1136 /**
1137 * Generates the instructions to jump to a label based on the comparison of
1138 * the top integer stack value with zero.
1139 *
1140 * @param mode
1141 * how these values must be compared. One of EQ, NE, LT, GE, GT,
1142 * LE.
1143 * @param label
1144 * where to jump if the comparison result is <tt>true</tt>.
1145 */
1146 public void ifZCmp(final int mode, final Label label) {
1147 mv.visitJumpInsn(mode, label);
1148 }
1149
1150 /**
1151 * Generates the instruction to jump to the given label if the top stack
1152 * value is null.
1153 *
1154 * @param label
1155 * where to jump if the condition is <tt>true</tt>.
1156 */
1157 public void ifNull(final Label label) {
1158 mv.visitJumpInsn(Opcodes.IFNULL, label);
1159 }
1160
1161 /**
1162 * Generates the instruction to jump to the given label if the top stack
1163 * value is not null.
1164 *
1165 * @param label
1166 * where to jump if the condition is <tt>true</tt>.
1167 */
1168 public void ifNonNull(final Label label) {
1169 mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1170 }
1171
1172 /**
1173 * Generates the instruction to jump to the given label.
1174 *
1175 * @param label
1176 * where to jump if the condition is <tt>true</tt>.
1177 */
1178 public void goTo(final Label label) {
1179 mv.visitJumpInsn(Opcodes.GOTO, label);
1180 }
1181
1182 /**
1183 * Generates a RET instruction.
1184 *
1185 * @param local
1186 * a local variable identifier, as returned by
1187 * {@link LocalVariablesSorter#newLocal(Type) newLocal()}.
1188 */
1189 public void ret(final int local) {
1190 mv.visitVarInsn(Opcodes.RET, local);
1191 }
1192
1193 /**
1194 * Generates the instructions for a switch statement.
1195 *
1196 * @param keys
1197 * the switch case keys.
1198 * @param generator
1199 * a generator to generate the code for the switch cases.
1200 */
1201 public void tableSwitch(final int[] keys,
1202 final TableSwitchGenerator generator) {
1203 float density;
1204 if (keys.length == 0) {
1205 density = 0;
1206 } else {
1207 density = (float) keys.length
1208 / (keys[keys.length - 1] - keys[0] + 1);
1209 }
1210 tableSwitch(keys, generator, density >= 0.5f);
1211 }
1212
1213 /**
1214 * Generates the instructions for a switch statement.
1215 *
1216 * @param keys
1217 * the switch case keys.
1218 * @param generator
1219 * a generator to generate the code for the switch cases.
1220 * @param useTable
1221 * <tt>true</tt> to use a TABLESWITCH instruction, or
1222 * <tt>false</tt> to use a LOOKUPSWITCH instruction.
1223 */
1224 public void tableSwitch(final int[] keys,
1225 final TableSwitchGenerator generator, final boolean useTable) {
1226 for (int i = 1; i < keys.length; ++i) {
1227 if (keys[i] < keys[i - 1]) {
1228 throw new IllegalArgumentException(
1229 "keys must be sorted ascending");
1230 }
1231 }
1232 Label def = newLabel();
1233 Label end = newLabel();
1234 if (keys.length > 0) {
1235 int len = keys.length;
1236 int min = keys[0];
1237 int max = keys[len - 1];
1238 int range = max - min + 1;
1239 if (useTable) {
1240 Label[] labels = new Label[range];
1241 Arrays.fill(labels, def);
1242 for (int i = 0; i < len; ++i) {
1243 labels[keys[i] - min] = newLabel();
1244 }
1245 mv.visitTableSwitchInsn(min, max, def, labels);
1246 for (int i = 0; i < range; ++i) {
1247 Label label = labels[i];
1248 if (label != def) {
1249 mark(label);
1250 generator.generateCase(i + min, end);
1251 }
1252 }
1253 } else {
1254 Label[] labels = new Label[len];
1255 for (int i = 0; i < len; ++i) {
1256 labels[i] = newLabel();
1257 }
1258 mv.visitLookupSwitchInsn(def, keys, labels);
1259 for (int i = 0; i < len; ++i) {
1260 mark(labels[i]);
1261 generator.generateCase(keys[i], end);
1262 }
1263 }
1264 }
1265 mark(def);
1266 generator.generateDefault();
1267 mark(end);
1268 }
1269
1270 /**
1271 * Generates the instruction to return the top stack value to the caller.
1272 */
1273 public void returnValue() {
1274 mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
1275 }
1276
1277 // ------------------------------------------------------------------------
1278 // Instructions to load and store fields
1279 // ------------------------------------------------------------------------
1280
1281 /**
1282 * Generates a get field or set field instruction.
1283 *
1284 * @param opcode
1285 * the instruction's opcode.
1286 * @param ownerType
1287 * the class in which the field is defined.
1288 * @param name
1289 * the name of the field.
1290 * @param fieldType
1291 * the type of the field.
1292 */
1293 private void fieldInsn(final int opcode, final Type ownerType,
1294 final String name, final Type fieldType) {
1295 mv.visitFieldInsn(opcode, ownerType.getInternalName(), name,
1296 fieldType.getDescriptor());
1297 }
1298
1299 /**
1300 * Generates the instruction to push the value of a static field on the
1301 * stack.
1302 *
1303 * @param owner
1304 * the class in which the field is defined.
1305 * @param name
1306 * the name of the field.
1307 * @param type
1308 * the type of the field.
1309 */
1310 public void getStatic(final Type owner, final String name, final Type type) {
1311 fieldInsn(Opcodes.GETSTATIC, owner, name, type);
1312 }
1313
1314 /**
1315 * Generates the instruction to store the top stack value in a static field.
1316 *
1317 * @param owner
1318 * the class in which the field is defined.
1319 * @param name
1320 * the name of the field.
1321 * @param type
1322 * the type of the field.
1323 */
1324 public void putStatic(final Type owner, final String name, final Type type) {
1325 fieldInsn(Opcodes.PUTSTATIC, owner, name, type);
1326 }
1327
1328 /**
1329 * Generates the instruction to push the value of a non static field on the
1330 * stack.
1331 *
1332 * @param owner
1333 * the class in which the field is defined.
1334 * @param name
1335 * the name of the field.
1336 * @param type
1337 * the type of the field.
1338 */
1339 public void getField(final Type owner, final String name, final Type type) {
1340 fieldInsn(Opcodes.GETFIELD, owner, name, type);
1341 }
1342
1343 /**
1344 * Generates the instruction to store the top stack value in a non static
1345 * field.
1346 *
1347 * @param owner
1348 * the class in which the field is defined.
1349 * @param name
1350 * the name of the field.
1351 * @param type
1352 * the type of the field.
1353 */
1354 public void putField(final Type owner, final String name, final Type type) {
1355 fieldInsn(Opcodes.PUTFIELD, owner, name, type);
1356 }
1357
1358 // ------------------------------------------------------------------------
1359 // Instructions to invoke methods
1360 // ------------------------------------------------------------------------
1361
1362 /**
1363 * Generates an invoke method instruction.
1364 *
1365 * @param opcode
1366 * the instruction's opcode.
1367 * @param type
1368 * the class in which the method is defined.
1369 * @param method
1370 * the method to be invoked.
1371 */
1372 private void invokeInsn(final int opcode, final Type type,
1373 final Method method) {
1374 String owner = type.getSort() == Type.ARRAY ? type.getDescriptor()
1375 : type.getInternalName();
1376 mv.visitMethodInsn(opcode, owner, method.getName(),
1377 method.getDescriptor());
1378 }
1379
1380 /**
1381 * Generates the instruction to invoke a normal method.
1382 *
1383 * @param owner
1384 * the class in which the method is defined.
1385 * @param method
1386 * the method to be invoked.
1387 */
1388 public void invokeVirtual(final Type owner, final Method method) {
1389 invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method);
1390 }
1391
1392 /**
1393 * Generates the instruction to invoke a constructor.
1394 *
1395 * @param type
1396 * the class in which the constructor is defined.
1397 * @param method
1398 * the constructor to be invoked.
1399 */
1400 public void invokeConstructor(final Type type, final Method method) {
1401 invokeInsn(Opcodes.INVOKESPECIAL, type, method);
1402 }
1403
1404 /**
1405 * Generates the instruction to invoke a static method.
1406 *
1407 * @param owner
1408 * the class in which the method is defined.
1409 * @param method
1410 * the method to be invoked.
1411 */
1412 public void invokeStatic(final Type owner, final Method method) {
1413 invokeInsn(Opcodes.INVOKESTATIC, owner, method);
1414 }
1415
1416 /**
1417 * Generates the instruction to invoke an interface method.
1418 *
1419 * @param owner
1420 * the class in which the method is defined.
1421 * @param method
1422 * the method to be invoked.
1423 */
1424 public void invokeInterface(final Type owner, final Method method) {
1425 invokeInsn(Opcodes.INVOKEINTERFACE, owner, method);
1426 }
1427
1428 /**
1429 * Generates an invokedynamic instruction.
1430 *
1431 * @param name
1432 * the method's name.
1433 * @param desc
1434 * the method's descriptor (see {@link Type Type}).
1435 * @param bsm
1436 * the bootstrap method.
1437 * @param bsmArgs
1438 * the bootstrap method constant arguments. Each argument must be
1439 * an {@link Integer}, {@link Float}, {@link Long},
1440 * {@link Double}, {@link String}, {@link Type} or {@link Handle}
1441 * value. This method is allowed to modify the content of the
1442 * array so a caller should expect that this array may change.
1443 */
1444 public void invokeDynamic(String name, String desc, Handle bsm,
1445 Object... bsmArgs) {
1446 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
1447 }
1448
1449 // ------------------------------------------------------------------------
1450 // Instructions to create objects and arrays
1451 // ------------------------------------------------------------------------
1452
1453 /**
1454 * Generates a type dependent instruction.
1455 *
1456 * @param opcode
1457 * the instruction's opcode.
1458 * @param type
1459 * the instruction's operand.
1460 */
1461 private void typeInsn(final int opcode, final Type type) {
1462 mv.visitTypeInsn(opcode, type.getInternalName());
1463 }
1464
1465 /**
1466 * Generates the instruction to create a new object.
1467 *
1468 * @param type
1469 * the class of the object to be created.
1470 */
1471 public void newInstance(final Type type) {
1472 typeInsn(Opcodes.NEW, type);
1473 }
1474
1475 /**
1476 * Generates the instruction to create a new array.
1477 *
1478 * @param type
1479 * the type of the array elements.
1480 */
1481 public void newArray(final Type type) {
1482 int typ;
1483 switch (type.getSort()) {
1484 case Type.BOOLEAN:
1485 typ = Opcodes.T_BOOLEAN;
1486 break;
1487 case Type.CHAR:
1488 typ = Opcodes.T_CHAR;
1489 break;
1490 case Type.BYTE:
1491 typ = Opcodes.T_BYTE;
1492 break;
1493 case Type.SHORT:
1494 typ = Opcodes.T_SHORT;
1495 break;
1496 case Type.INT:
1497 typ = Opcodes.T_INT;
1498 break;
1499 case Type.FLOAT:
1500 typ = Opcodes.T_FLOAT;
1501 break;
1502 case Type.LONG:
1503 typ = Opcodes.T_LONG;
1504 break;
1505 case Type.DOUBLE:
1506 typ = Opcodes.T_DOUBLE;
1507 break;
1508 default:
1509 typeInsn(Opcodes.ANEWARRAY, type);
1510 return;
1511 }
1512 mv.visitIntInsn(Opcodes.NEWARRAY, typ);
1513 }
1514
1515 // ------------------------------------------------------------------------
1516 // Miscelaneous instructions
1517 // ------------------------------------------------------------------------
1518
1519 /**
1520 * Generates the instruction to compute the length of an array.
1521 */
1522 public void arrayLength() {
1523 mv.visitInsn(Opcodes.ARRAYLENGTH);
1524 }
1525
1526 /**
1527 * Generates the instruction to throw an exception.
1528 */
1529 public void throwException() {
1530 mv.visitInsn(Opcodes.ATHROW);
1531 }
1532
1533 /**
1534 * Generates the instructions to create and throw an exception. The
1535 * exception class must have a constructor with a single String argument.
1536 *
1537 * @param type
1538 * the class of the exception to be thrown.
1539 * @param msg
1540 * the detailed message of the exception.
1541 */
1542 public void throwException(final Type type, final String msg) {
1543 newInstance(type);
1544 dup();
1545 push(msg);
1546 invokeConstructor(type, Method.getMethod("void <init> (String)"));
1547 throwException();
1548 }
1549
1550 /**
1551 * Generates the instruction to check that the top stack value is of the
1552 * given type.
1553 *
1554 * @param type
1555 * a class or interface type.
1556 */
1557 public void checkCast(final Type type) {
1558 if (!type.equals(OBJECT_TYPE)) {
1559 typeInsn(Opcodes.CHECKCAST, type);
1560 }
1561 }
1562
1563 /**
1564 * Generates the instruction to test if the top stack value is of the given
1565 * type.
1566 *
1567 * @param type
1568 * a class or interface type.
1569 */
1570 public void instanceOf(final Type type) {
1571 typeInsn(Opcodes.INSTANCEOF, type);
1572 }
1573
1574 /**
1575 * Generates the instruction to get the monitor of the top stack value.
1576 */
1577 public void monitorEnter() {
1578 mv.visitInsn(Opcodes.MONITORENTER);
1579 }
1580
1581 /**
1582 * Generates the instruction to release the monitor of the top stack value.
1583 */
1584 public void monitorExit() {
1585 mv.visitInsn(Opcodes.MONITOREXIT);
1586 }
1587
1588 // ------------------------------------------------------------------------
1589 // Non instructions
1590 // ------------------------------------------------------------------------
1591
1592 /**
1593 * Marks the end of the visited method.
1594 */
1595 public void endMethod() {
1596 if ((access & Opcodes.ACC_ABSTRACT) == 0) {
1597 mv.visitMaxs(0, 0);
1598 }
1599 mv.visitEnd();
1600 }
1601
1602 /**
1603 * Marks the start of an exception handler.
1604 *
1605 * @param start
1606 * beginning of the exception handler's scope (inclusive).
1607 * @param end
1608 * end of the exception handler's scope (exclusive).
1609 * @param exception
1610 * internal name of the type of exceptions handled by the
1611 * handler.
1612 */
1613 public void catchException(final Label start, final Label end,
1614 final Type exception) {
1615 if (exception == null) {
1616 mv.visitTryCatchBlock(start, end, mark(), null);
1617 } else {
1618 mv.visitTryCatchBlock(start, end, mark(),
1619 exception.getInternalName());
1620 }
1621 }
1622 }
+0
-1090
src/jvm/clojure/asm/commons/InstructionAdapter.java less more
0 /***
1 * ASM: a very small and fast Java bytecode manipulation framework
2 * Copyright (c) 2000-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 package clojure.asm.commons;
31
32 import clojure.asm.Handle;
33 import clojure.asm.Label;
34 import clojure.asm.MethodVisitor;
35 import clojure.asm.Opcodes;
36 import clojure.asm.Type;
37
38 /**
39 * A {@link MethodVisitor} providing a more detailed API to generate and
40 * transform instructions.
41 *
42 * @author Eric Bruneton
43 */
44 public class InstructionAdapter extends MethodVisitor {
45
46 public final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");
47
48 /**
49 * Creates a new {@link InstructionAdapter}. <i>Subclasses must not use this
50 * constructor</i>. Instead, they must use the
51 * {@link #InstructionAdapter(int, MethodVisitor)} version.
52 *
53 * @param mv
54 * the method visitor to which this adapter delegates calls.
55 */
56 public InstructionAdapter(final MethodVisitor mv) {
57 this(Opcodes.ASM4, mv);
58 }
59
60 /**
61 * Creates a new {@link InstructionAdapter}.
62 *
63 * @param api
64 * the ASM API version implemented by this visitor. Must be one
65 * of {@link Opcodes#ASM4}.
66 * @param mv
67 * the method visitor to which this adapter delegates calls.
68 */
69 protected InstructionAdapter(final int api, final MethodVisitor mv) {
70 super(api, mv);
71 }
72
73 @Override
74 public void visitInsn(final int opcode) {
75 switch (opcode) {
76 case Opcodes.NOP:
77 nop();
78 break;
79 case Opcodes.ACONST_NULL:
80 aconst(null);
81 break;
82 case Opcodes.ICONST_M1:
83 case Opcodes.ICONST_0:
84 case Opcodes.ICONST_1:
85 case Opcodes.ICONST_2:
86 case Opcodes.ICONST_3:
87 case Opcodes.ICONST_4:
88 case Opcodes.ICONST_5:
89 iconst(opcode - Opcodes.ICONST_0);
90 break;
91 case Opcodes.LCONST_0:
92 case Opcodes.LCONST_1:
93 lconst(opcode - Opcodes.LCONST_0);
94 break;
95 case Opcodes.FCONST_0:
96 case Opcodes.FCONST_1:
97 case Opcodes.FCONST_2:
98 fconst(opcode - Opcodes.FCONST_0);
99 break;
100 case Opcodes.DCONST_0:
101 case Opcodes.DCONST_1:
102 dconst(opcode - Opcodes.DCONST_0);
103 break;
104 case Opcodes.IALOAD:
105 aload(Type.INT_TYPE);
106 break;
107 case Opcodes.LALOAD:
108 aload(Type.LONG_TYPE);
109 break;
110 case Opcodes.FALOAD:
111 aload(Type.FLOAT_TYPE);
112 break;
113 case Opcodes.DALOAD:
114 aload(Type.DOUBLE_TYPE);
115 break;
116 case Opcodes.AALOAD:
117 aload(OBJECT_TYPE);
118 break;
119 case Opcodes.BALOAD:
120 aload(Type.BYTE_TYPE);
121 break;
122 case Opcodes.CALOAD:
123 aload(Type.CHAR_TYPE);
124 break;
125 case Opcodes.SALOAD:
126 aload(Type.SHORT_TYPE);
127 break;
128 case Opcodes.IASTORE:
129 astore(Type.INT_TYPE);
130 break;
131 case Opcodes.LASTORE:
132 astore(Type.LONG_TYPE);
133 break;
134 case Opcodes.FASTORE:
135 astore(Type.FLOAT_TYPE);
136 break;
137 case Opcodes.DASTORE:
138 astore(Type.DOUBLE_TYPE);
139 break;
140 case Opcodes.AASTORE:
141 astore(OBJECT_TYPE);
142 break;
143 case Opcodes.BASTORE:
144 astore(Type.BYTE_TYPE);
145 break;
146 case Opcodes.CASTORE:
147 astore(Type.CHAR_TYPE);
148 break;
149 case Opcodes.SASTORE:
150 astore(Type.SHORT_TYPE);
151 break;
152 case Opcodes.POP:
153 pop();
154 break;
155 case Opcodes.POP2:
156 pop2();
157 break;
158 case Opcodes.DUP:
159 dup();
160 break;
161 case Opcodes.DUP_X1:
162 dupX1();
163 break;
164 case Opcodes.DUP_X2:
165 dupX2();
166 break;
167 case Opcodes.DUP2:
168 dup2();
169 break;
170 case Opcodes.DUP2_X1:
171 dup2X1();
172 break;
173 case Opcodes.DUP2_X2:
174 dup2X2();
175 break;
176 case Opcodes.SWAP:
177 swap();
178 break;
179 case Opcodes.IADD:
180 add(Type.INT_TYPE);
181 break;
182 case Opcodes.LADD:
183 add(Type.LONG_TYPE);
184 break;
185 case Opcodes.FADD:
186 add(Type.FLOAT_TYPE);
187 break;
188 case Opcodes.DADD:
189 add(Type.DOUBLE_TYPE);
190 break;
191 case Opcodes.ISUB:
192 sub(Type.INT_TYPE);
193 break;
194 case Opcodes.LSUB:
195 sub(Type.LONG_TYPE);
196 break;
197 case Opcodes.FSUB:
198 sub(Type.FLOAT_TYPE);
199 break;
200 case Opcodes.DSUB:
201 sub(Type.DOUBLE_TYPE);
202 break;
203 case Opcodes.IMUL:
204 mul(Type.INT_TYPE);
205 break;
206 case Opcodes.LMUL:
207 mul(Type.LONG_TYPE);
208 break;
209 case Opcodes.FMUL:
210 mul(Type.FLOAT_TYPE);
211 break;
212 case Opcodes.DMUL:
213 mul(Type.DOUBLE_TYPE);
214 break;
215 case Opcodes.IDIV:
216 div(Type.INT_TYPE);
217 break;
218 case Opcodes.LDIV:
219 div(Type.LONG_TYPE);
220 break;
221 case Opcodes.FDIV:
222 div(Type.FLOAT_TYPE);
223 break;
224 case Opcodes.DDIV:
225 div(Type.DOUBLE_TYPE);
226 break;
227 case Opcodes.IREM:
228 rem(Type.INT_TYPE);
229 break;
230 case Opcodes.LREM:
231 rem(Type.LONG_TYPE);
232 break;
233 case Opcodes.FREM:
234 rem(Type.FLOAT_TYPE);
235 break;
236 case Opcodes.DREM:
237 rem(Type.DOUBLE_TYPE);
238 break;
239 case Opcodes.INEG:
240 neg(Type.INT_TYPE);
241 break;
242 case Opcodes.LNEG:
243 neg(Type.LONG_TYPE);
244 break;
245 case Opcodes.FNEG:
246 neg(Type.FLOAT_TYPE);
247 break;
248 case Opcodes.DNEG:
249 neg(Type.DOUBLE_TYPE);
250 break;
251 case Opcodes.ISHL:
252 shl(Type.INT_TYPE);
253 break;
254 case Opcodes.LSHL:
255 shl(Type.LONG_TYPE);
256 break;
257 case Opcodes.ISHR:
258 shr(Type.INT_TYPE);
259 break;
260 case Opcodes.LSHR:
261 shr(Type.LONG_TYPE);
262 break;
263 case Opcodes.IUSHR:
264 ushr(Type.INT_TYPE);
265 break;
266 case Opcodes.LUSHR:
267 ushr(Type.LONG_TYPE);
268 break;
269 case Opcodes.IAND:
270 and(Type.INT_TYPE);
271 break;
272 case Opcodes.LAND:
273 and(Type.LONG_TYPE);
274 break;
275 case Opcodes.IOR:
276 or(Type.INT_TYPE);
277 break;
278 case Opcodes.LOR:
279 or(Type.LONG_TYPE);
280 break;
281 case Opcodes.IXOR:
282 xor(Type.INT_TYPE);
283 break;
284 case Opcodes.LXOR:
285 xor(Type.LONG_TYPE);
286 break;
287 case Opcodes.I2L:
288 cast(Type.INT_TYPE, Type.LONG_TYPE);
289 break;
290 case Opcodes.I2F:
291 cast(Type.INT_TYPE, Type.FLOAT_TYPE);
292 break;
293 case Opcodes.I2D:
294 cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
295 break;
296 case Opcodes.L2I:
297 cast(Type.LONG_TYPE, Type.INT_TYPE);
298 break;
299 case Opcodes.L2F:
300 cast(Type.LONG_TYPE, Type.FLOAT_TYPE);
301 break;
302 case Opcodes.L2D:
303 cast(Type.LONG_TYPE, Type.DOUBLE_TYPE);
304 break;
305 case Opcodes.F2I:
306 cast(Type.FLOAT_TYPE, Type.INT_TYPE);
307 break;
308 case Opcodes.F2L:
309 cast(Type.FLOAT_TYPE, Type.LONG_TYPE);
310 break;
311 case Opcodes.F2D:
312 cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE);
313 break;
314 case Opcodes.D2I:
315 cast(Type.DOUBLE_TYPE, Type.INT_TYPE);
316 break;
317 case Opcodes.D2L:
318 cast(Type.DOUBLE_TYPE, Type.LONG_TYPE);
319 break;
320 case Opcodes.D2F:
321 cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE);
322 break;
323 case Opcodes.I2B:
324 cast(Type.INT_TYPE, Type.BYTE_TYPE);
325 break;
326 case Opcodes.I2C:
327 cast(Type.INT_TYPE, Type.CHAR_TYPE);
328 break;
329 case Opcodes.I2S:
330 cast(Type.INT_TYPE, Type.SHORT_TYPE);
331 break;
332 case Opcodes.LCMP:
333 lcmp();
334 break;
335 case Opcodes.FCMPL:
336 cmpl(Type.FLOAT_TYPE);
337 break;
338 case Opcodes.FCMPG:
339 cmpg(Type.FLOAT_TYPE);
340 break;
341 case Opcodes.DCMPL:
342 cmpl(Type.DOUBLE_TYPE);
343 break;
344 case Opcodes.DCMPG:
345 cmpg(Type.DOUBLE_TYPE);
346 break;
347 case Opcodes.IRETURN:
348 areturn(Type.INT_TYPE);
349 break;
350 case Opcodes.LRETURN:
351 areturn(Type.LONG_TYPE);
352 break;
353 case Opcodes.FRETURN:
354 areturn(Type.FLOAT_TYPE);
355 break;
356 case Opcodes.DRETURN:
357 areturn(Type.DOUBLE_TYPE);
358 break;
359 case Opcodes.ARETURN:
360 areturn(OBJECT_TYPE);
361 break;
362 case Opcodes.RETURN:
363 areturn(Type.VOID_TYPE);
364 break;
365 case Opcodes.ARRAYLENGTH:
366 arraylength();
367 break;
368 case Opcodes.ATHROW:
369 athrow();
370 break;
371 case Opcodes.MONITORENTER:
372 monitorenter();
373 break;
374 case Opcodes.MONITOREXIT:
375 monitorexit();
376 break;
377 default:
378 throw new IllegalArgumentException();
379 }
380 }
381
382 @Override
383 public void visitIntInsn(final int opcode, final int operand) {
384 switch (opcode) {
385 case Opcodes.BIPUSH:
386 iconst(operand);
387 break;
388 case Opcodes.SIPUSH:
389 iconst(operand);
390 break;
391 case Opcodes.NEWARRAY:
392 switch (operand) {
393 case Opcodes.T_BOOLEAN:
394 newarray(Type.BOOLEAN_TYPE);
395 break;
396 case Opcodes.T_CHAR:
397 newarray(Type.CHAR_TYPE);
398 break;
399 case Opcodes.T_BYTE:
400 newarray(Type.BYTE_TYPE);
401 break;
402 case Opcodes.T_SHORT:
403 newarray(Type.SHORT_TYPE);
404 break;
405 case Opcodes.T_INT:
406 newarray(Type.INT_TYPE);
407 break;
408 case Opcodes.T_FLOAT:
409 newarray(Type.FLOAT_TYPE);
410 break;
411 case Opcodes.T_LONG:
412 newarray(Type.LONG_TYPE);
413 break;
414 case Opcodes.T_DOUBLE:
415 newarray(Type.DOUBLE_TYPE);
416 break;
417 default:
418 throw new IllegalArgumentException();
419 }
420 break;
421 default:
422 throw new IllegalArgumentException();
423 }
424 }
425
426 @Override
427 public void visitVarInsn(final int opcode, final int var) {
428 switch (opcode) {
429 case Opcodes.ILOAD:
430 load(var, Type.INT_TYPE);
431 break;
432 case Opcodes.LLOAD:
433 load(var, Type.LONG_TYPE);
434 break;
435 case Opcodes.FLOAD:
436 load(var, Type.FLOAT_TYPE);
437 break;
438 case Opcodes.DLOAD:
439 load(var, Type.DOUBLE_TYPE);
440 break;
441 case Opcodes.ALOAD:
442 load(var, OBJECT_TYPE);
443 break;
444 case Opcodes.ISTORE:
445 store(var, Type.INT_TYPE);
446 break;
447 case Opcodes.LSTORE:
448 store(var, Type.LONG_TYPE);
449 break;
450 case Opcodes.FSTORE:
451 store(var, Type.FLOAT_TYPE);
452 break;
453 case Opcodes.DSTORE:
454 store(var, Type.DOUBLE_TYPE);
455 break;
456 case Opcodes.ASTORE:
457 store(var, OBJECT_TYPE);
458 break;
459 case Opcodes.RET:
460 ret(var);
461 break;
462 default:
463 throw new IllegalArgumentException();
464 }
465 }
466
467 @Override
468 public void visitTypeInsn(final int opcode, final String type) {
469 Type t = Type.getObjectType(type);
470 switch (opcode) {
471 case Opcodes.NEW:
472 anew(t);
473 break;
474 case Opcodes.ANEWARRAY:
475 newarray(t);
476 break;
477 case Opcodes.CHECKCAST:
478 checkcast(t);
479 break;
480 case Opcodes.INSTANCEOF:
481 instanceOf(t);
482 break;
483 default:
484 throw new IllegalArgumentException();
485 }
486 }
487
488 @Override
489 public void visitFieldInsn(final int opcode, final String owner,
490 final String name, final String desc) {
491 switch (opcode) {
492 case Opcodes.GETSTATIC:
493 getstatic(owner, name, desc);
494 break;
495 case Opcodes.PUTSTATIC:
496 putstatic(owner, name, desc);
497 break;
498 case Opcodes.GETFIELD:
499 getfield(owner, name, desc);
500 break;
501 case Opcodes.PUTFIELD:
502 putfield(owner, name, desc);
503 break;
504 default:
505 throw new IllegalArgumentException();
506 }
507 }
508
509 @Override
510 public void visitMethodInsn(final int opcode, final String owner,
511 final String name, final String desc) {
512 switch (opcode) {
513 case Opcodes.INVOKESPECIAL:
514 invokespecial(owner, name, desc);
515 break;
516 case Opcodes.INVOKEVIRTUAL:
517 invokevirtual(owner, name, desc);
518 break;
519 case Opcodes.INVOKESTATIC:
520 invokestatic(owner, name, desc);
521 break;
522 case Opcodes.INVOKEINTERFACE:
523 invokeinterface(owner, name, desc);
524 break;
525 default:
526 throw new IllegalArgumentException();
527 }
528 }
529
530 @Override
531 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
532 Object... bsmArgs) {
533 invokedynamic(name, desc, bsm, bsmArgs);
534 }
535
536 @Override
537 public void visitJumpInsn(final int opcode, final Label label) {
538 switch (opcode) {
539 case Opcodes.IFEQ:
540 ifeq(label);
541 break;
542 case Opcodes.IFNE:
543 ifne(label);
544 break;
545 case Opcodes.IFLT:
546 iflt(label);
547 break;
548 case Opcodes.IFGE:
549 ifge(label);
550 break;
551 case Opcodes.IFGT:
552 ifgt(label);
553 break;
554 case Opcodes.IFLE:
555 ifle(label);
556 break;
557 case Opcodes.IF_ICMPEQ:
558 ificmpeq(label);
559 break;
560 case Opcodes.IF_ICMPNE:
561 ificmpne(label);
562 break;
563 case Opcodes.IF_ICMPLT:
564 ificmplt(label);
565 break;
566 case Opcodes.IF_ICMPGE:
567 ificmpge(label);
568 break;
569 case Opcodes.IF_ICMPGT:
570 ificmpgt(label);
571 break;
572 case Opcodes.IF_ICMPLE:
573 ificmple(label);
574 break;
575 case Opcodes.IF_ACMPEQ:
576 ifacmpeq(label);
577 break;
578 case Opcodes.IF_ACMPNE:
579 ifacmpne(label);
580 break;
581 case Opcodes.GOTO:
582 goTo(label);
583 break;
584 case Opcodes.JSR:
585 jsr(label);
586 break;
587 case Opcodes.IFNULL:
588 ifnull(label);
589 break;
590 case Opcodes.IFNONNULL:
591 ifnonnull(label);
592 break;
593 default:
594 throw new IllegalArgumentException();
595 }
596 }
597
598 @Override
599 public void visitLabel(final Label label) {
600 mark(label);
601 }
602
603 @Override
604 public void visitLdcInsn(final Object cst) {
605 if (cst instanceof Integer) {
606 int val = ((Integer) cst).intValue();
607 iconst(val);
608 } else if (cst instanceof Byte) {
609 int val = ((Byte) cst).intValue();
610 iconst(val);
611 } else if (cst instanceof Character) {
612 int val = ((Character) cst).charValue();
613 iconst(val);
614 } else if (cst instanceof Short) {
615 int val = ((Short) cst).intValue();
616 iconst(val);
617 } else if (cst instanceof Boolean) {
618 int val = ((Boolean) cst).booleanValue() ? 1 : 0;
619 iconst(val);
620 } else if (cst instanceof Float) {
621 float val = ((Float) cst).floatValue();
622 fconst(val);
623 } else if (cst instanceof Long) {
624 long val = ((Long) cst).longValue();
625 lconst(val);
626 } else if (cst instanceof Double) {
627 double val = ((Double) cst).doubleValue();
628 dconst(val);
629 } else if (cst instanceof String) {
630 aconst(cst);
631 } else if (cst instanceof Type) {
632 tconst((Type) cst);
633 } else if (cst instanceof Handle) {
634 hconst((Handle) cst);
635 } else {
636 throw new IllegalArgumentException();
637 }
638 }
639
640 @Override
641 public void visitIincInsn(final int var, final int increment) {
642 iinc(var, increment);
643 }
644
645 @Override
646 public void visitTableSwitchInsn(final int min, final int max,
647 final Label dflt, final Label... labels) {
648 tableswitch(min, max, dflt, labels);
649 }
650
651 @Override
652 public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
653 final Label[] labels) {
654 lookupswitch(dflt, keys, labels);
655 }
656
657 @Override
658 public void visitMultiANewArrayInsn(final String desc, final int dims) {
659 multianewarray(desc, dims);
660 }
661
662 // -----------------------------------------------------------------------
663
664 public void nop() {
665 mv.visitInsn(Opcodes.NOP);
666 }
667
668 public void aconst(final Object cst) {
669 if (cst == null) {
670 mv.visitInsn(Opcodes.ACONST_NULL);
671 } else {
672 mv.visitLdcInsn(cst);
673 }
674 }
675
676 public void iconst(final int cst) {
677 if (cst >= -1 && cst <= 5) {
678 mv.visitInsn(Opcodes.ICONST_0 + cst);
679 } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
680 mv.visitIntInsn(Opcodes.BIPUSH, cst);
681 } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
682 mv.visitIntInsn(Opcodes.SIPUSH, cst);
683 } else {
684 mv.visitLdcInsn(new Integer(cst));
685 }
686 }
687
688 public void lconst(final long cst) {
689 if (cst == 0L || cst == 1L) {
690 mv.visitInsn(Opcodes.LCONST_0 + (int) cst);
691 } else {
692 mv.visitLdcInsn(new Long(cst));
693 }
694 }
695
696 public void fconst(final float cst) {
697 int bits = Float.floatToIntBits(cst);
698 if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
699 mv.visitInsn(Opcodes.FCONST_0 + (int) cst);
700 } else {
701 mv.visitLdcInsn(new Float(cst));
702 }
703 }
704
705 public void dconst(final double cst) {
706 long bits = Double.doubleToLongBits(cst);
707 if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
708 mv.visitInsn(Opcodes.DCONST_0 + (int) cst);
709 } else {
710 mv.visitLdcInsn(new Double(cst));
711 }
712 }
713
714 public void tconst(final Type type) {
715 mv.visitLdcInsn(type);
716 }
717
718 public void hconst(final Handle handle) {
719 mv.visitLdcInsn(handle);
720 }
721
722 public void load(final int var, final Type type) {
723 mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var);
724 }
725
726 public void aload(final Type type) {
727 mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
728 }
729
730 public void store(final int var, final Type type) {
731 mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), var);
732 }
733
734 public void astore(final Type type) {
735 mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
736 }
737
738 public void pop() {
739 mv.visitInsn(Opcodes.POP);
740 }
741
742 public void pop2() {
743 mv.visitInsn(Opcodes.POP2);
744 }
745
746 public void dup() {
747 mv.visitInsn(Opcodes.DUP);
748 }
749
750 public void dup2() {
751 mv.visitInsn(Opcodes.DUP2);
752 }
753
754 public void dupX1() {
755 mv.visitInsn(Opcodes.DUP_X1);
756 }
757
758 public void dupX2() {
759 mv.visitInsn(Opcodes.DUP_X2);
760 }
761
762 public void dup2X1() {
763 mv.visitInsn(Opcodes.DUP2_X1);
764 }
765
766 public void dup2X2() {
767 mv.visitInsn(Opcodes.DUP2_X2);
768 }
769
770 public void swap() {
771 mv.visitInsn(Opcodes.SWAP);
772 }
773
774 public void add(final Type type) {
775 mv.visitInsn(type.getOpcode(Opcodes.IADD));
776 }
777
778 public void sub(final Type type) {
779 mv.visitInsn(type.getOpcode(Opcodes.ISUB));
780 }
781
782 public void mul(final Type type) {
783 mv.visitInsn(type.getOpcode(Opcodes.IMUL));
784 }
785
786 public void div(final Type type) {
787 mv.visitInsn(type.getOpcode(Opcodes.IDIV));
788 }
789
790 public void rem(final Type type) {
791 mv.visitInsn(type.getOpcode(Opcodes.IREM));
792 }
793
794 public void neg(final Type type) {
795 mv.visitInsn(type.getOpcode(Opcodes.INEG));
796 }
797
798 public void shl(final Type type) {
799 mv.visitInsn(type.getOpcode(Opcodes.ISHL));
800 }
801
802 public void shr(final Type type) {
803 mv.visitInsn(type.getOpcode(Opcodes.ISHR));
804 }
805
806 public void ushr(final Type type) {
807 mv.visitInsn(type.getOpcode(Opcodes.IUSHR));
808 }
809
810 public void and(final Type type) {
811 mv.visitInsn(type.getOpcode(Opcodes.IAND));
812 }
813
814 public void or(final Type type) {
815 mv.visitInsn(type.getOpcode(Opcodes.IOR));
816 }
817
818 public void xor(final Type type) {
819 mv.visitInsn(type.getOpcode(Opcodes.IXOR));
820 }
821
822 public void iinc(final int var, final int increment) {
823 mv.visitIincInsn(var, increment);
824 }
825
826 public void cast(final Type from, final Type to) {
827 if (from != to) {
828 if (from == Type.DOUBLE_TYPE) {
829 if (to == Type.FLOAT_TYPE) {
830 mv.visitInsn(Opcodes.D2F);
831 } else if (to == Type.LONG_TYPE) {
832 mv.visitInsn(Opcodes.D2L);
833 } else {
834 mv.visitInsn(Opcodes.D2I);
835 cast(Type.INT_TYPE, to);
836 }
837 } else if (from == Type.FLOAT_TYPE) {
838 if (to == Type.DOUBLE_TYPE) {
839 mv.visitInsn(Opcodes.F2D);
840 } else if (to == Type.LONG_TYPE) {
841 mv.visitInsn(Opcodes.F2L);
842 } else {
843 mv.visitInsn(Opcodes.F2I);
844 cast(Type.INT_TYPE, to);
845 }
846 } else if (from == Type.LONG_TYPE) {
847 if (to == Type.DOUBLE_TYPE) {
848 mv.visitInsn(Opcodes.L2D);
849 } else if (to == Type.FLOAT_TYPE) {
850 mv.visitInsn(Opcodes.L2F);
851 } else {
852 mv.visitInsn(Opcodes.L2I);
853 cast(Type.INT_TYPE, to);
854 }
855 } else {
856 if (to == Type.BYTE_TYPE) {
857 mv.visitInsn(Opcodes.I2B);
858 } else if (to == Type.CHAR_TYPE) {
859 mv.visitInsn(Opcodes.I2C);
860 } else if (to == Type.DOUBLE_TYPE) {
861 mv.visitInsn(Opcodes.I2D);
862 } else if (to == Type.FLOAT_TYPE) {
863 mv.visitInsn(Opcodes.I2F);
864 } else if (to == Type.LONG_TYPE) {
865 mv.visitInsn(Opcodes.I2L);
866 } else if (to == Type.SHORT_TYPE) {
867 mv.visitInsn(Opcodes.I2S);
868 }
869 }
870 }
871 }
872
873 public void lcmp() {
874 mv.visitInsn(Opcodes.LCMP);
875 }
876
877 public void cmpl(final Type type) {
878 mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPL : Opcodes.DCMPL);
879 }
880
881 public void cmpg(final Type type) {
882 mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPG : Opcodes.DCMPG);
883 }
884
885 public void ifeq(final Label label) {
886 mv.visitJumpInsn(Opcodes.IFEQ, label);
887 }
888
889 public void ifne(final Label label) {
890 mv.visitJumpInsn(Opcodes.IFNE, label);
891 }
892
893 public void iflt(final Label label) {
894 mv.visitJumpInsn(Opcodes.IFLT, label);
895 }
896
897 public void ifge(final Label label) {
898 mv.visitJumpInsn(Opcodes.IFGE, label);
899 }
900
901 public void ifgt(final Label label) {
902 mv.visitJumpInsn(Opcodes.IFGT, label);
903 }
904
905 public void ifle(final Label label) {
906 mv.visitJumpInsn(Opcodes.IFLE, label);
907 }
908
909 public void ificmpeq(final Label label) {
910 mv.visitJumpInsn(Opcodes.IF_ICMPEQ, label);
911 }
912
913 public void ificmpne(final Label label) {
914 mv.visitJumpInsn(Opcodes.IF_ICMPNE, label);
915 }
916
917 public void ificmplt(final Label label) {
918 mv.visitJumpInsn(Opcodes.IF_ICMPLT, label);
919 }
920
921 public void ificmpge(final Label label) {
922 mv.visitJumpInsn(Opcodes.IF_ICMPGE, label);
923 }
924
925 public void ificmpgt(final Label label) {
926 mv.visitJumpInsn(Opcodes.IF_ICMPGT, label);
927 }
928
929 public void ificmple(final Label label) {
930 mv.visitJumpInsn(Opcodes.IF_ICMPLE, label);
931 }
932
933 public void ifacmpeq(final Label label) {
934 mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
935 }
936
937 public void ifacmpne(final Label label) {
938 mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
939 }
940
941 public void goTo(final Label label) {
942 mv.visitJumpInsn(Opcodes.GOTO, label);
943 }
944
945 public void jsr(final Label label) {
946 mv.visitJumpInsn(Opcodes.JSR, label);
947 }
948
949 public void ret(final int var) {
950 mv.visitVarInsn(Opcodes.RET, var);
951 }
952
953 public void tableswitch(final int min, final int max, final Label dflt,
954 final Label... labels) {
955 mv.visitTableSwitchInsn(min, max, dflt, labels);
956 }
957
958 public void lookupswitch(final Label dflt, final int[] keys,
959 final Label[] labels) {
960 mv.visitLookupSwitchInsn(dflt, keys, labels);
961 }
962
963 public void areturn(final Type t) {
964 mv.visitInsn(t.getOpcode(Opcodes.IRETURN));
965 }
966
967 public void getstatic(final String owner, final String name,
968 final String desc) {
969 mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, desc);
970 }
971
972 public void putstatic(final String owner, final String name,
973 final String desc) {
974 mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, desc);
975 }
976
977 public void getfield(final String owner, final String name,
978 final String desc) {
979 mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, desc);
980 }
981
982 public void putfield(final String owner, final String name,
983 final String desc) {
984 mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc);
985 }
986
987 public void invokevirtual(final String owner, final String name,
988 final String desc) {
989 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc);
990 }
991
992 public void invokespecial(final String owner, final String name,
993 final String desc) {
994 mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc);
995 }
996
997 public void invokestatic(final String owner, final String name,
998 final String desc) {
999 mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc);
1000 }
1001
1002 public void invokeinterface(final String owner, final String name,
1003 final String desc) {
1004 mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc);
1005 }
1006
1007 public void invokedynamic(String name, String desc, Handle bsm,
1008 Object[] bsmArgs) {
1009 mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
1010 }
1011
1012 public void anew(final Type type) {
1013 mv.visitTypeInsn(Opcodes.NEW, type.getInternalName());
1014 }
1015
1016 public void newarray(final Type type) {
1017 int typ;
1018 switch (type.getSort()) {
1019 case Type.BOOLEAN:
1020 typ = Opcodes.T_BOOLEAN;
1021 break;
1022 case Type.CHAR:
1023 typ = Opcodes.T_CHAR;
1024 break;
1025 case Type.BYTE:
1026 typ = Opcodes.T_BYTE;
1027 break;
1028 case Type.SHORT:
1029 typ = Opcodes.T_SHORT;
1030 break;
1031 case Type.INT:
1032 typ = Opcodes.T_INT;
1033 break;
1034 case Type.FLOAT:
1035 typ = Opcodes.T_FLOAT;
1036 break;
1037 case Type.LONG:
1038 typ = Opcodes.T_LONG;
1039 break;
1040 case Type.DOUBLE:
1041 typ = Opcodes.T_DOUBLE;
1042 break;
1043 default:
1044 mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
1045 return;
1046 }
1047 mv.visitIntInsn(Opcodes.NEWARRAY, typ);
1048 }
1049
1050 public void arraylength() {
1051 mv.visitInsn(Opcodes.ARRAYLENGTH);
1052 }
1053
1054 public void athrow() {
1055 mv.visitInsn(Opcodes.ATHROW);
1056 }
1057
1058 public void checkcast(final Type type) {
1059 mv.visitTypeInsn(Opcodes.CHECKCAST, type.getInternalName());
1060 }
1061
1062 public void instanceOf(final Type type) {
1063 mv.visitTypeInsn(Opcodes.INSTANCEOF, type.getInternalName());
1064 }
1065
1066 public void monitorenter() {
1067 mv.visitInsn(Opcodes.MONITORENTER);
1068 }
1069
1070 public void monitorexit() {
1071 mv.visitInsn(Opcodes.MONITOREXIT);
1072 }
1073
1074 public void multianewarray(final String desc, final int dims) {
1075 mv.visitMultiANewArrayInsn(desc, dims);
1076 }
1077
1078 public void ifnull(final Label label) {
1079 mv.visitJumpInsn(Opcodes.IFNULL, label);
1080 }
1081
1082 public void ifnonnull(final Label label) {
1083 mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1084 }
1085
1086 public void mark(final Label label) {
1087 mv.visitLabel(label);
1088 }
1089 }
+0
-360
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-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package clojure.asm.commons;
30
31 import clojure.asm.Label;
32 import clojure.asm.MethodVisitor;
33 import clojure.asm.Opcodes;
34 import clojure.asm.Type;
35
36 /**
37 * A {@link MethodVisitor} that renumbers local variables in their order of
38 * appearance. This adapter allows one to easily add new local variables to a
39 * method. It may be used by inheriting from this class, but the preferred way
40 * of using it is via delegation: the next visitor in the chain can indeed add
41 * new locals when needed by calling {@link #newLocal} on this adapter (this
42 * requires a reference back to this {@link LocalVariablesSorter}).
43 *
44 * @author Chris Nokleberg
45 * @author Eugene Kuleshov
46 * @author Eric Bruneton
47 */
48 public class LocalVariablesSorter extends MethodVisitor {
49
50 private static final Type OBJECT_TYPE = Type
51 .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}. <i>Subclasses must not use
82 * this constructor</i>. Instead, they must use the
83 * {@link #LocalVariablesSorter(int, int, String, MethodVisitor)} version.
84 *
85 * @param access
86 * access flags of the adapted method.
87 * @param desc
88 * the method's descriptor (see {@link Type Type}).
89 * @param mv
90 * the method visitor to which this adapter delegates calls.
91 */
92 public LocalVariablesSorter(final int access, final String desc,
93 final MethodVisitor mv) {
94 this(Opcodes.ASM4, access, desc, mv);
95 }
96
97 /**
98 * Creates a new {@link LocalVariablesSorter}.
99 *
100 * @param api
101 * the ASM API version implemented by this visitor. Must be one
102 * of {@link Opcodes#ASM4}.
103 * @param access
104 * access flags of the adapted method.
105 * @param desc
106 * the method's descriptor (see {@link Type Type}).
107 * @param mv
108 * the method visitor to which this adapter delegates calls.
109 */
110 protected LocalVariablesSorter(final int api, final int access,
111 final String desc, final MethodVisitor mv) {
112 super(api, mv);
113 Type[] args = Type.getArgumentTypes(desc);
114 nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
115 for (int i = 0; i < args.length; i++) {
116 nextLocal += args[i].getSize();
117 }
118 firstLocal = nextLocal;
119 }
120
121 @Override
122 public void visitVarInsn(final int opcode, final int var) {
123 Type type;
124 switch (opcode) {
125 case Opcodes.LLOAD:
126 case Opcodes.LSTORE:
127 type = Type.LONG_TYPE;
128 break;
129
130 case Opcodes.DLOAD:
131 case Opcodes.DSTORE:
132 type = Type.DOUBLE_TYPE;
133 break;
134
135 case Opcodes.FLOAD:
136 case Opcodes.FSTORE:
137 type = Type.FLOAT_TYPE;
138 break;
139
140 case Opcodes.ILOAD:
141 case Opcodes.ISTORE:
142 type = Type.INT_TYPE;
143 break;
144
145 default:
146 // case Opcodes.ALOAD:
147 // case Opcodes.ASTORE:
148 // case RET:
149 type = OBJECT_TYPE;
150 break;
151 }
152 mv.visitVarInsn(opcode, remap(var, type));
153 }
154
155 @Override
156 public void visitIincInsn(final int var, final int increment) {
157 mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);
158 }
159
160 @Override
161 public void visitMaxs(final int maxStack, final int maxLocals) {
162 mv.visitMaxs(maxStack, nextLocal);
163 }
164
165 @Override
166 public void visitLocalVariable(final String name, final String desc,
167 final String signature, final Label start, final Label end,
168 final int index) {
169 int newIndex = remap(index, Type.getType(desc));
170 mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
171 }
172
173 @Override
174 public void visitFrame(final int type, final int nLocal,
175 final Object[] local, final int nStack, final Object[] stack) {
176 if (type != Opcodes.F_NEW) { // uncompressed frame
177 throw new IllegalStateException(
178 "ClassReader.accept() should be called with EXPAND_FRAMES flag");
179 }
180
181 if (!changed) { // optimization for the case where mapping = identity
182 mv.visitFrame(type, nLocal, local, nStack, stack);
183 return;
184 }
185
186 // creates a copy of newLocals
187 Object[] oldLocals = new Object[newLocals.length];
188 System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);
189
190 updateNewLocals(newLocals);
191
192 // copies types from 'local' to 'newLocals'
193 // 'newLocals' already contains the variables added with 'newLocal'
194
195 int index = 0; // old local variable index
196 int number = 0; // old local variable number
197 for (; number < nLocal; ++number) {
198 Object t = local[number];
199 int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
200 if (t != Opcodes.TOP) {
201 Type typ = OBJECT_TYPE;
202 if (t == Opcodes.INTEGER) {
203 typ = Type.INT_TYPE;
204 } else if (t == Opcodes.FLOAT) {
205 typ = Type.FLOAT_TYPE;
206 } else if (t == Opcodes.LONG) {
207 typ = Type.LONG_TYPE;
208 } else if (t == Opcodes.DOUBLE) {
209 typ = Type.DOUBLE_TYPE;
210 } else if (t instanceof String) {
211 typ = Type.getObjectType((String) t);
212 }
213 setFrameLocal(remap(index, typ), t);
214 }
215 index += size;
216 }
217
218 // removes TOP after long and double types as well as trailing TOPs
219
220 index = 0;
221 number = 0;
222 for (int i = 0; index < newLocals.length; ++i) {
223 Object t = newLocals[index++];
224 if (t != null && t != Opcodes.TOP) {
225 newLocals[i] = t;
226 number = i + 1;
227 if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
228 index += 1;
229 }
230 } else {
231 newLocals[i] = Opcodes.TOP;
232 }
233 }
234
235 // visits remapped frame
236 mv.visitFrame(type, number, newLocals, nStack, stack);
237
238 // restores original value of 'newLocals'
239 newLocals = oldLocals;
240 }
241
242 // -------------
243
244 /**
245 * Creates a new local variable of the given type.
246 *
247 * @param type
248 * the type of the local variable to be created.
249 * @return the identifier of the newly created local variable.
250 */
251 public int newLocal(final Type type) {
252 Object t;
253 switch (type.getSort()) {
254 case Type.BOOLEAN:
255 case Type.CHAR:
256 case Type.BYTE:
257 case Type.SHORT:
258 case Type.INT:
259 t = Opcodes.INTEGER;
260 break;
261 case Type.FLOAT:
262 t = Opcodes.FLOAT;
263 break;
264 case Type.LONG:
265 t = Opcodes.LONG;
266 break;
267 case Type.DOUBLE:
268 t = Opcodes.DOUBLE;
269 break;
270 case Type.ARRAY:
271 t = type.getDescriptor();
272 break;
273 // case Type.OBJECT:
274 default:
275 t = type.getInternalName();
276 break;
277 }
278 int local = newLocalMapping(type);
279 setLocalType(local, type);
280 setFrameLocal(local, t);
281 return local;
282 }
283
284 /**
285 * Notifies subclasses that a new stack map frame is being visited. The
286 * array argument contains the stack map frame types corresponding to the
287 * local variables added with {@link #newLocal}. This method can update
288 * these types in place for the stack map frame being visited. The default
289 * implementation of this method does nothing, i.e. a local variable added
290 * with {@link #newLocal} will have the same type in all stack map frames.
291 * But this behavior is not always the desired one, for instance if a local
292 * variable is added in the middle of a try/catch block: the frame for the
293 * exception handler should have a TOP type for this new local.
294 *
295 * @param newLocals
296 * the stack map frame types corresponding to the local variables
297 * added with {@link #newLocal} (and null for the others). The
298 * format of this array is the same as in
299 * {@link MethodVisitor#visitFrame}, except that long and double
300 * types use two slots. The types for the current stack map frame
301 * must be updated in place in this array.
302 */
303 protected void updateNewLocals(Object[] newLocals) {
304 }
305
306 /**
307 * Notifies subclasses that a local variable has been added or remapped. The
308 * default implementation of this method does nothing.
309 *
310 * @param local
311 * a local variable identifier, as returned by {@link #newLocal
312 * newLocal()}.
313 * @param type
314 * the type of the value being stored in the local variable.
315 */
316 protected void setLocalType(final int local, final Type type) {
317 }
318
319 private void setFrameLocal(final int local, final Object type) {
320 int l = newLocals.length;
321 if (local >= l) {
322 Object[] a = new Object[Math.max(2 * l, local + 1)];
323 System.arraycopy(newLocals, 0, a, 0, l);
324 newLocals = a;
325 }
326 newLocals[local] = type;
327 }
328
329 private int remap(final int var, final Type type) {
330 if (var + type.getSize() <= firstLocal) {
331 return var;
332 }
333 int key = 2 * var + type.getSize() - 1;
334 int size = mapping.length;
335 if (key >= size) {
336 int[] newMapping = new int[Math.max(2 * size, key + 1)];
337 System.arraycopy(mapping, 0, newMapping, 0, size);
338 mapping = newMapping;
339 }
340 int value = mapping[key];
341 if (value == 0) {
342 value = newLocalMapping(type);
343 setLocalType(value, type);
344 mapping[key] = value + 1;
345 } else {
346 value--;
347 }
348 if (value != var) {
349 changed = true;
350 }
351 return value;
352 }
353
354 protected int newLocalMapping(final Type type) {
355 int local = nextLocal;
356 nextLocal += type.getSize();
357 return local;
358 }
359 }
+0
-282
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-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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 static final Map<String, String> DESCRIPTORS;
59
60 static {
61 DESCRIPTORS = new HashMap<String, String>();
62 DESCRIPTORS.put("void", "V");
63 DESCRIPTORS.put("byte", "B");
64 DESCRIPTORS.put("char", "C");
65 DESCRIPTORS.put("double", "D");
66 DESCRIPTORS.put("float", "F");
67 DESCRIPTORS.put("int", "I");
68 DESCRIPTORS.put("long", "J");
69 DESCRIPTORS.put("short", "S");
70 DESCRIPTORS.put("boolean", "Z");
71 }
72
73 /**
74 * Creates a new {@link Method}.
75 *
76 * @param name
77 * the method's name.
78 * @param desc
79 * the method's descriptor.
80 */
81 public Method(final String name, final String desc) {
82 this.name = name;
83 this.desc = desc;
84 }
85
86 /**
87 * Creates a new {@link Method}.
88 *
89 * @param name
90 * the method's name.
91 * @param returnType
92 * the method's return type.
93 * @param argumentTypes
94 * the method's argument types.
95 */
96 public Method(final String name, final Type returnType,
97 final Type[] argumentTypes) {
98 this(name, Type.getMethodDescriptor(returnType, argumentTypes));
99 }
100
101 /**
102 * Creates a new {@link Method}.
103 *
104 * @param m
105 * a java.lang.reflect method descriptor
106 * @return a {@link Method} corresponding to the given Java method
107 * declaration.
108 */
109 public static Method getMethod(java.lang.reflect.Method m) {
110 return new Method(m.getName(), Type.getMethodDescriptor(m));
111 }
112
113 /**
114 * Creates a new {@link Method}.
115 *
116 * @param c
117 * a java.lang.reflect constructor descriptor
118 * @return a {@link Method} corresponding to the given Java constructor
119 * declaration.
120 */
121 public static Method getMethod(java.lang.reflect.Constructor<?> c) {
122 return new Method("<init>", Type.getConstructorDescriptor(c));
123 }
124
125 /**
126 * Returns a {@link Method} corresponding to the given Java method
127 * declaration.
128 *
129 * @param method
130 * a Java method declaration, without argument names, of the form
131 * "returnType name (argumentType1, ... argumentTypeN)", where
132 * the types are in plain Java (e.g. "int", "float",
133 * "java.util.List", ...). Classes of the java.lang package can
134 * be specified by their unqualified name; all other classes
135 * names must be fully qualified.
136 * @return a {@link Method} corresponding to the given Java method
137 * declaration.
138 * @throws IllegalArgumentException
139 * if <code>method</code> could not get parsed.
140 */
141 public static Method getMethod(final String method)
142 throws IllegalArgumentException {
143 return getMethod(method, false);
144 }
145
146 /**
147 * Returns a {@link Method} corresponding to the given Java method
148 * declaration.
149 *
150 * @param method
151 * a Java method declaration, without argument names, of the form
152 * "returnType name (argumentType1, ... argumentTypeN)", where
153 * the types are in plain Java (e.g. "int", "float",
154 * "java.util.List", ...). Classes of the java.lang package may
155 * be specified by their unqualified name, depending on the
156 * defaultPackage argument; all other classes names must be fully
157 * qualified.
158 * @param defaultPackage
159 * true if unqualified class names belong to the default package,
160 * or false if they correspond to java.lang classes. For instance
161 * "Object" means "Object" if this option is true, or
162 * "java.lang.Object" otherwise.
163 * @return a {@link Method} corresponding to the given Java method
164 * declaration.
165 * @throws IllegalArgumentException
166 * if <code>method</code> could not get parsed.
167 */
168 public static Method getMethod(final String method,
169 final boolean defaultPackage) throws IllegalArgumentException {
170 int space = method.indexOf(' ');
171 int start = method.indexOf('(', space) + 1;
172 int end = method.indexOf(')', start);
173 if (space == -1 || start == -1 || end == -1) {
174 throw new IllegalArgumentException();
175 }
176 String returnType = method.substring(0, space);
177 String methodName = method.substring(space + 1, start - 1).trim();
178 StringBuffer sb = new StringBuffer();
179 sb.append('(');
180 int p;
181 do {
182 String s;
183 p = method.indexOf(',', start);
184 if (p == -1) {
185 s = map(method.substring(start, end).trim(), defaultPackage);
186 } else {
187 s = map(method.substring(start, p).trim(), defaultPackage);
188 start = p + 1;
189 }
190 sb.append(s);
191 } while (p != -1);
192 sb.append(')');
193 sb.append(map(returnType, defaultPackage));
194 return new Method(methodName, sb.toString());
195 }
196
197 private static String map(final String type, final boolean defaultPackage) {
198 if ("".equals(type)) {
199 return type;
200 }
201
202 StringBuffer sb = new StringBuffer();
203 int index = 0;
204 while ((index = type.indexOf("[]", index) + 1) > 0) {
205 sb.append('[');
206 }
207
208 String t = type.substring(0, type.length() - sb.length() * 2);
209 String desc = DESCRIPTORS.get(t);
210 if (desc != null) {
211 sb.append(desc);
212 } else {
213 sb.append('L');
214 if (t.indexOf('.') < 0) {
215 if (!defaultPackage) {
216 sb.append("java/lang/");
217 }
218 sb.append(t);
219 } else {
220 sb.append(t.replace('.', '/'));
221 }
222 sb.append(';');
223 }
224 return sb.toString();
225 }
226
227 /**
228 * Returns the name of the method described by this object.
229 *
230 * @return the name of the method described by this object.
231 */
232 public String getName() {
233 return name;
234 }
235
236 /**
237 * Returns the descriptor of the method described by this object.
238 *
239 * @return the descriptor of the method described by this object.
240 */
241 public String getDescriptor() {
242 return desc;
243 }
244
245 /**
246 * Returns the return type of the method described by this object.
247 *
248 * @return the return type of the method described by this object.
249 */
250 public Type getReturnType() {
251 return Type.getReturnType(desc);
252 }
253
254 /**
255 * Returns the argument types of the method described by this object.
256 *
257 * @return the argument types of the method described by this object.
258 */
259 public Type[] getArgumentTypes() {
260 return Type.getArgumentTypes(desc);
261 }
262
263 @Override
264 public String toString() {
265 return name + desc;
266 }
267
268 @Override
269 public boolean equals(final Object o) {
270 if (!(o instanceof Method)) {
271 return false;
272 }
273 Method other = (Method) o;
274 return name.equals(other.name) && desc.equals(other.desc);
275 }
276
277 @Override
278 public int hashCode() {
279 return name.hashCode() ^ desc.hashCode();
280 }
281 }
+0
-533
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-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package clojure.asm.commons;
30
31 import java.io.ByteArrayOutputStream;
32 import java.io.DataOutput;
33 import java.io.DataOutputStream;
34 import java.io.IOException;
35 import java.security.MessageDigest;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39
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 ClassVisitor} that adds a serial version unique identifier to a
47 * class if missing. Here is typical usage of this class:
48 *
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 *
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 *
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 *
69 * The sequence of items in the stream is as follows:
70 *
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 *
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 *
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 ClassVisitor {
113
114 /**
115 * Flag that indicates if we need to compute SVUID.
116 */
117 private boolean computeSVUID;
118
119 /**
120 * Set to true if the class already has SVUID.
121 */
122 private boolean hasSVUID;
123
124 /**
125 * Classes access flags.
126 */
127 private int access;
128
129 /**
130 * Internal name of the class
131 */
132 private String name;
133
134 /**
135 * Interfaces implemented by the class.
136 */
137 private String[] interfaces;
138
139 /**
140 * Collection of fields. (except private static and private transient
141 * fields)
142 */
143 private Collection<Item> svuidFields;
144
145 /**
146 * Set to true if the class has static initializer.
147 */
148 private boolean hasStaticInitializer;
149
150 /**
151 * Collection of non-private constructors.
152 */
153 private Collection<Item> svuidConstructors;
154
155 /**
156 * Collection of non-private methods.
157 */
158 private Collection<Item> svuidMethods;
159
160 /**
161 * Creates a new {@link SerialVersionUIDAdder}. <i>Subclasses must not use
162 * this constructor</i>. Instead, they must use the
163 * {@link #SerialVersionUIDAdder(int, ClassVisitor)} version.
164 *
165 * @param cv
166 * a {@link ClassVisitor} to which this visitor will delegate
167 * calls.
168 */
169 public SerialVersionUIDAdder(final ClassVisitor cv) {
170 this(Opcodes.ASM4, cv);
171 }
172
173 /**
174 * Creates a new {@link SerialVersionUIDAdder}.
175 *
176 * @param api
177 * the ASM API version implemented by this visitor. Must be one
178 * of {@link Opcodes#ASM4}.
179 * @param cv
180 * a {@link ClassVisitor} to which this visitor will delegate
181 * calls.
182 */
183 protected SerialVersionUIDAdder(final int api, final ClassVisitor cv) {
184 super(api, cv);
185 svuidFields = new ArrayList<Item>();
186 svuidConstructors = new ArrayList<Item>();
187 svuidMethods = new ArrayList<Item>();
188 }
189
190 // ------------------------------------------------------------------------
191 // Overriden methods
192 // ------------------------------------------------------------------------
193
194 /*
195 * Visit class header and get class name, access , and interfaces
196 * information (step 1,2, and 3) for SVUID computation.
197 */
198 @Override
199 public void visit(final int version, final int access, final String name,
200 final String signature, final String superName,
201 final String[] interfaces) {
202 computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0;
203
204 if (computeSVUID) {
205 this.name = name;
206 this.access = access;
207 this.interfaces = interfaces;
208 }
209
210 super.visit(version, access, name, signature, superName, interfaces);
211 }
212
213 /*
214 * Visit the methods and get constructor and method information (step 5 and
215 * 7). Also determine if there is a class initializer (step 6).
216 */
217 @Override
218 public MethodVisitor visitMethod(final int access, final String name,
219 final String desc, final String signature, final String[] exceptions) {
220 if (computeSVUID) {
221 if ("<clinit>".equals(name)) {
222 hasStaticInitializer = true;
223 }
224 /*
225 * Remembers non private constructors and methods for SVUID
226 * computation For constructor and method modifiers, only the
227 * ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,
228 * ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags
229 * are used.
230 */
231 int mods = access
232 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
233 | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
234 | Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED
235 | Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT);
236
237 // all non private methods
238 if ((access & Opcodes.ACC_PRIVATE) == 0) {
239 if ("<init>".equals(name)) {
240 svuidConstructors.add(new Item(name, mods, desc));
241 } else if (!"<clinit>".equals(name)) {
242 svuidMethods.add(new Item(name, mods, desc));
243 }
244 }
245 }
246
247 return super.visitMethod(access, name, desc, signature, exceptions);
248 }
249
250 /*
251 * Gets class field information for step 4 of the algorithm. Also determines
252 * if the class already has a SVUID.
253 */
254 @Override
255 public FieldVisitor visitField(final int access, final String name,
256 final String desc, final String signature, final Object value) {
257 if (computeSVUID) {
258 if ("serialVersionUID".equals(name)) {
259 // since the class already has SVUID, we won't be computing it.
260 computeSVUID = false;
261 hasSVUID = true;
262 }
263 /*
264 * Remember field for SVUID computation For field modifiers, only
265 * the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
266 * ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when
267 * computing serialVersionUID values.
268 */
269 if ((access & Opcodes.ACC_PRIVATE) == 0
270 || (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0) {
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 svuidFields.add(new Item(name, mods, desc));
276 }
277 }
278
279 return super.visitField(access, name, desc, signature, value);
280 }
281
282 /**
283 * Handle a bizarre special case. Nested classes (static classes declared
284 * inside another class) that are protected have their access bit set to
285 * public in their class files to deal with some odd reflection situation.
286 * Our SVUID computation must do as the JVM does and ignore access bits in
287 * the class file in favor of the access bits InnerClass attribute.
288 */
289 @Override
290 public void visitInnerClass(final String aname, final String outerName,
291 final String innerName, final int attr_access) {
292 if ((name != null) && name.equals(aname)) {
293 this.access = attr_access;
294 }
295 super.visitInnerClass(aname, outerName, innerName, attr_access);
296 }
297
298 /*
299 * Add the SVUID if class doesn't have one
300 */
301 @Override
302 public void visitEnd() {
303 // compute SVUID and add it to the class
304 if (computeSVUID && !hasSVUID) {
305 try {
306 addSVUID(computeSVUID());
307 } catch (Throwable e) {
308 throw new RuntimeException("Error while computing SVUID for "
309 + name, e);
310 }
311 }
312
313 super.visitEnd();
314 }
315
316 // ------------------------------------------------------------------------
317 // Utility methods
318 // ------------------------------------------------------------------------
319
320 /**
321 * Returns true if the class already has a SVUID field. The result of this
322 * method is only valid when visitEnd is or has been called.
323 *
324 * @return true if the class already has a SVUID field.
325 */
326 public boolean hasSVUID() {
327 return hasSVUID;
328 }
329
330 protected void addSVUID(long svuid) {
331 FieldVisitor fv = super.visitField(Opcodes.ACC_FINAL
332 + Opcodes.ACC_STATIC, "serialVersionUID", "J", null, new Long(
333 svuid));
334 if (fv != null) {
335 fv.visitEnd();
336 }
337 }
338
339 /**
340 * Computes and returns the value of SVUID.
341 *
342 * @return Returns the serial version UID
343 * @throws IOException
344 * if an I/O error occurs
345 */
346 protected long computeSVUID() throws IOException {
347 ByteArrayOutputStream bos;
348 DataOutputStream dos = null;
349 long svuid = 0;
350
351 try {
352 bos = new ByteArrayOutputStream();
353 dos = new DataOutputStream(bos);
354
355 /*
356 * 1. The class name written using UTF encoding.
357 */
358 dos.writeUTF(name.replace('/', '.'));
359
360 /*
361 * 2. The class modifiers written as a 32-bit integer.
362 */
363 dos.writeInt(access
364 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL
365 | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT));
366
367 /*
368 * 3. The name of each interface sorted by name written using UTF
369 * encoding.
370 */
371 Arrays.sort(interfaces);
372 for (int i = 0; i < interfaces.length; i++) {
373 dos.writeUTF(interfaces[i].replace('/', '.'));
374 }
375
376 /*
377 * 4. For each field of the class sorted by field name (except
378 * private static and private transient fields):
379 *
380 * 1. The name of the field in UTF encoding. 2. The modifiers of the
381 * field written as a 32-bit integer. 3. The descriptor of the field
382 * in UTF encoding
383 *
384 * Note that field signatures are not dot separated. Method and
385 * constructor signatures are dot separated. Go figure...
386 */
387 writeItems(svuidFields, dos, false);
388
389 /*
390 * 5. If a class initializer exists, write out the following: 1. The
391 * name of the method, <clinit>, in UTF encoding. 2. The modifier of
392 * the method, java.lang.reflect.Modifier.STATIC, written as a
393 * 32-bit integer. 3. The descriptor of the method, ()V, in UTF
394 * encoding.
395 */
396 if (hasStaticInitializer) {
397 dos.writeUTF("<clinit>");
398 dos.writeInt(Opcodes.ACC_STATIC);
399 dos.writeUTF("()V");
400 } // if..
401
402 /*
403 * 6. For each non-private constructor sorted by method name and
404 * signature: 1. The name of the method, <init>, in UTF encoding. 2.
405 * The modifiers of the method written as a 32-bit integer. 3. The
406 * descriptor of the method in UTF encoding.
407 */
408 writeItems(svuidConstructors, dos, true);
409
410 /*
411 * 7. For each non-private method sorted by method name and
412 * signature: 1. The name of the method in UTF encoding. 2. The
413 * modifiers of the method written as a 32-bit integer. 3. The
414 * descriptor of the method in UTF encoding.
415 */
416 writeItems(svuidMethods, dos, true);
417
418 dos.flush();
419
420 /*
421 * 8. The SHA-1 algorithm is executed on the stream of bytes
422 * produced by DataOutputStream and produces five 32-bit values
423 * sha[0..4].
424 */
425 byte[] hashBytes = computeSHAdigest(bos.toByteArray());
426
427 /*
428 * 9. The hash value is assembled from the first and second 32-bit
429 * values of the SHA-1 message digest. If the result of the message
430 * digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of
431 * five int values named sha, the hash value would be computed as
432 * follows:
433 *
434 * long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF)
435 * << 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) <<
436 * 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) <<
437 * 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) <<
438 * 56;
439 */
440 for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
441 svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
442 }
443 } finally {
444 // close the stream (if open)
445 if (dos != null) {
446 dos.close();
447 }
448 }
449
450 return svuid;
451 }
452
453 /**
454 * Returns the SHA-1 message digest of the given value.
455 *
456 * @param value
457 * the value whose SHA message digest must be computed.
458 * @return the SHA-1 message digest of the given value.
459 */
460 protected byte[] computeSHAdigest(final byte[] value) {
461 try {
462 return MessageDigest.getInstance("SHA").digest(value);
463 } catch (Exception e) {
464 throw new UnsupportedOperationException(e.toString());
465 }
466 }
467
468 /**
469 * Sorts the items in the collection and writes it to the data output stream
470 *
471 * @param itemCollection
472 * collection of items
473 * @param dos
474 * a <code>DataOutputStream</code> value
475 * @param dotted
476 * a <code>boolean</code> value
477 * @exception IOException
478 * if an error occurs
479 */
480 private static void writeItems(final Collection<Item> itemCollection,
481 final DataOutput dos, final boolean dotted) throws IOException {
482 int size = itemCollection.size();
483 Item[] items = itemCollection.toArray(new Item[size]);
484 Arrays.sort(items);
485 for (int i = 0; i < size; i++) {
486 dos.writeUTF(items[i].name);
487 dos.writeInt(items[i].access);
488 dos.writeUTF(dotted ? items[i].desc.replace('/', '.')
489 : items[i].desc);
490 }
491 }
492
493 // ------------------------------------------------------------------------
494 // Inner classes
495 // ------------------------------------------------------------------------
496
497 private static class Item implements Comparable<Item> {
498
499 final String name;
500
501 final int access;
502
503 final String desc;
504
505 Item(final String name, final int access, final String desc) {
506 this.name = name;
507 this.access = access;
508 this.desc = desc;
509 }
510
511 public int compareTo(final Item other) {
512 int retVal = name.compareTo(other.name);
513 if (retVal == 0) {
514 retVal = desc.compareTo(other.desc);
515 }
516 return retVal;
517 }
518
519 @Override
520 public boolean equals(final Object o) {
521 if (o instanceof Item) {
522 return compareTo((Item) o) == 0;
523 }
524 return false;
525 }
526
527 @Override
528 public int hashCode() {
529 return (name + desc).hashCode();
530 }
531 }
532 }
+0
-96
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-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 package clojure.asm.commons;
30
31 import clojure.asm.ClassVisitor;
32 import clojure.asm.MethodVisitor;
33 import clojure.asm.Opcodes;
34
35 /**
36 * A {@link ClassVisitor} that merges clinit methods into a single one.
37 *
38 * @author Eric Bruneton
39 */
40 public class StaticInitMerger extends ClassVisitor {
41
42 private String name;
43
44 private MethodVisitor clinit;
45
46 private final String prefix;
47
48 private int counter;
49
50 public StaticInitMerger(final String prefix, final ClassVisitor cv) {
51 this(Opcodes.ASM4, prefix, cv);
52 }
53
54 protected StaticInitMerger(final int api, final String prefix,
55 final ClassVisitor cv) {
56 super(api, cv);
57 this.prefix = prefix;
58 }
59
60 @Override
61 public void visit(final int version, final int access, final String name,
62 final String signature, final String superName,
63 final String[] interfaces) {
64 cv.visit(version, access, name, signature, superName, interfaces);
65 this.name = name;
66 }
67
68 @Override
69 public MethodVisitor visitMethod(final int access, final String name,
70 final String desc, final String signature, final String[] exceptions) {
71 MethodVisitor mv;
72 if ("<clinit>".equals(name)) {
73 int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
74 String n = prefix + counter++;
75 mv = cv.visitMethod(a, n, desc, signature, exceptions);
76
77 if (clinit == null) {
78 clinit = cv.visitMethod(a, name, desc, null, null);
79 }
80 clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc);
81 } else {
82 mv = cv.visitMethod(access, name, desc, signature, exceptions);
83 }
84 return mv;
85 }
86
87 @Override
88 public void visitEnd() {
89 if (clinit != null) {
90 clinit.visitInsn(Opcodes.RETURN);
91 clinit.visitMaxs(0, 0);
92 }
93 cv.visitEnd();
94 }
95 }
+0
-57
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-2011 INRIA, France Telecom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
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
46 * the switch case key.
47 * @param end
48 * a label that corresponds to the end of the switch statement.
49 */
50 void generateCase(int key, Label end);
51
52 /**
53 * Generates the code for the default switch case.
54 */
55 void generateDefault();
56 }
+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-2011 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-2011 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},
37 {@link clojure.asm.MethodVisitor MethodVisitor} and
38 {@link clojure.asm.AnnotationVisitor AnnotationVisitor} abstract classes,
39 which allow one to visit the fields, methods and annotations of a class,
40 including the bytecode instructions of each method.
41
42 <p>
43 In addition to these main abstract classes, ASM provides a {@link
44 clojure.asm.ClassReader ClassReader} class, that can parse an
45 existing class and make a given visitor visit it. ASM also provides
46 a {@link clojure.asm.ClassWriter ClassWriter} class, which is
47 a visitor that generates Java class files.
48
49 <p>
50 In order to generate a class from scratch, only the {@link
51 clojure.asm.ClassWriter ClassWriter} class is necessary. Indeed,
52 in order to generate a class, one must just call its visit<i>Xxx</i>
53 methods with the appropriate arguments to generate the desired fields
54 and methods. See the "helloworld" example in the ASM distribution for
55 more details about class generation.
56
57 <p>
58 In order to modify existing classes, one must use a {@link
59 clojure.asm.ClassReader ClassReader} class to analyze
60 the original class, a class modifier, and a {@link clojure.asm.ClassWriter
61 ClassWriter} to construct the modified class. The class modifier
62 is just a {@link clojure.asm.ClassVisitor ClassVisitor}
63 that delegates most of the work to another {@link clojure.asm.ClassVisitor
64 ClassVisitor}, but that sometimes changes some parameter values,
65 or call additional methods, in order to implement the desired
66 modification process. In order to make it easier to implement such
67 class modifiers, the {@link clojure.asm.ClassVisitor
68 ClassVisitor} and {@link clojure.asm.MethodVisitor MethodVisitor}
69 classes delegate by default all the method calls they receive to an
70 optional visitor. 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 45KB, 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>