rlm@10
|
1 /***
|
rlm@10
|
2 * ASM: a very small and fast Java bytecode manipulation framework
|
rlm@10
|
3 * Copyright (c) 2000-2005 INRIA, France Telecom
|
rlm@10
|
4 * All rights reserved.
|
rlm@10
|
5 *
|
rlm@10
|
6 * Redistribution and use in source and binary forms, with or without
|
rlm@10
|
7 * modification, are permitted provided that the following conditions
|
rlm@10
|
8 * are met:
|
rlm@10
|
9 * 1. Redistributions of source code must retain the above copyright
|
rlm@10
|
10 * notice, this list of conditions and the following disclaimer.
|
rlm@10
|
11 * 2. Redistributions in binary form must reproduce the above copyright
|
rlm@10
|
12 * notice, this list of conditions and the following disclaimer in the
|
rlm@10
|
13 * documentation and/or other materials provided with the distribution.
|
rlm@10
|
14 * 3. Neither the name of the copyright holders nor the names of its
|
rlm@10
|
15 * contributors may be used to endorse or promote products derived from
|
rlm@10
|
16 * this software without specific prior written permission.
|
rlm@10
|
17 *
|
rlm@10
|
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
rlm@10
|
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
rlm@10
|
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
rlm@10
|
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
rlm@10
|
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
rlm@10
|
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
rlm@10
|
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
rlm@10
|
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
rlm@10
|
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
rlm@10
|
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
rlm@10
|
28 * THE POSSIBILITY OF SUCH DAMAGE.
|
rlm@10
|
29 */
|
rlm@10
|
30 package clojure.asm;
|
rlm@10
|
31
|
rlm@10
|
32 /**
|
rlm@10
|
33 * An {@link AnnotationVisitor} that generates annotations in bytecode form.
|
rlm@10
|
34 *
|
rlm@10
|
35 * @author Eric Bruneton
|
rlm@10
|
36 * @author Eugene Kuleshov
|
rlm@10
|
37 */
|
rlm@10
|
38 final class AnnotationWriter implements AnnotationVisitor{
|
rlm@10
|
39
|
rlm@10
|
40 /**
|
rlm@10
|
41 * The class writer to which this annotation must be added.
|
rlm@10
|
42 */
|
rlm@10
|
43 private final ClassWriter cw;
|
rlm@10
|
44
|
rlm@10
|
45 /**
|
rlm@10
|
46 * The number of values in this annotation.
|
rlm@10
|
47 */
|
rlm@10
|
48 private int size;
|
rlm@10
|
49
|
rlm@10
|
50 /**
|
rlm@10
|
51 * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
|
rlm@10
|
52 * writers used for annotation default and annotation arrays use unnamed
|
rlm@10
|
53 * values.
|
rlm@10
|
54 */
|
rlm@10
|
55 private final boolean named;
|
rlm@10
|
56
|
rlm@10
|
57 /**
|
rlm@10
|
58 * The annotation values in bytecode form. This byte vector only contains
|
rlm@10
|
59 * the values themselves, i.e. the number of values must be stored as a
|
rlm@10
|
60 * unsigned short just before these bytes.
|
rlm@10
|
61 */
|
rlm@10
|
62 private final ByteVector bv;
|
rlm@10
|
63
|
rlm@10
|
64 /**
|
rlm@10
|
65 * The byte vector to be used to store the number of values of this
|
rlm@10
|
66 * annotation. See {@link #bv}.
|
rlm@10
|
67 */
|
rlm@10
|
68 private final ByteVector parent;
|
rlm@10
|
69
|
rlm@10
|
70 /**
|
rlm@10
|
71 * Where the number of values of this annotation must be stored in
|
rlm@10
|
72 * {@link #parent}.
|
rlm@10
|
73 */
|
rlm@10
|
74 private final int offset;
|
rlm@10
|
75
|
rlm@10
|
76 /**
|
rlm@10
|
77 * Next annotation writer. This field is used to store annotation lists.
|
rlm@10
|
78 */
|
rlm@10
|
79 AnnotationWriter next;
|
rlm@10
|
80
|
rlm@10
|
81 /**
|
rlm@10
|
82 * Previous annotation writer. This field is used to store annotation lists.
|
rlm@10
|
83 */
|
rlm@10
|
84 AnnotationWriter prev;
|
rlm@10
|
85
|
rlm@10
|
86 // ------------------------------------------------------------------------
|
rlm@10
|
87 // Constructor
|
rlm@10
|
88 // ------------------------------------------------------------------------
|
rlm@10
|
89
|
rlm@10
|
90 /**
|
rlm@10
|
91 * Constructs a new {@link AnnotationWriter}.
|
rlm@10
|
92 *
|
rlm@10
|
93 * @param cw the class writer to which this annotation must be added.
|
rlm@10
|
94 * @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise.
|
rlm@10
|
95 * @param bv where the annotation values must be stored.
|
rlm@10
|
96 * @param parent where the number of annotation values must be stored.
|
rlm@10
|
97 * @param offset where in <tt>parent</tt> the number of annotation values must
|
rlm@10
|
98 * be stored.
|
rlm@10
|
99 */
|
rlm@10
|
100 AnnotationWriter(
|
rlm@10
|
101 final ClassWriter cw,
|
rlm@10
|
102 final boolean named,
|
rlm@10
|
103 final ByteVector bv,
|
rlm@10
|
104 final ByteVector parent,
|
rlm@10
|
105 final int offset){
|
rlm@10
|
106 this.cw = cw;
|
rlm@10
|
107 this.named = named;
|
rlm@10
|
108 this.bv = bv;
|
rlm@10
|
109 this.parent = parent;
|
rlm@10
|
110 this.offset = offset;
|
rlm@10
|
111 }
|
rlm@10
|
112
|
rlm@10
|
113 // ------------------------------------------------------------------------
|
rlm@10
|
114 // Implementation of the AnnotationVisitor interface
|
rlm@10
|
115 // ------------------------------------------------------------------------
|
rlm@10
|
116
|
rlm@10
|
117 public void visit(final String name, final Object value){
|
rlm@10
|
118 ++size;
|
rlm@10
|
119 if(named)
|
rlm@10
|
120 {
|
rlm@10
|
121 bv.putShort(cw.newUTF8(name));
|
rlm@10
|
122 }
|
rlm@10
|
123 if(value instanceof String)
|
rlm@10
|
124 {
|
rlm@10
|
125 bv.put12('s', cw.newUTF8((String) value));
|
rlm@10
|
126 }
|
rlm@10
|
127 else if(value instanceof Byte)
|
rlm@10
|
128 {
|
rlm@10
|
129 bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
|
rlm@10
|
130 }
|
rlm@10
|
131 else if(value instanceof Boolean)
|
rlm@10
|
132 {
|
rlm@10
|
133 int v = ((Boolean) value).booleanValue() ? 1 : 0;
|
rlm@10
|
134 bv.put12('Z', cw.newInteger(v).index);
|
rlm@10
|
135 }
|
rlm@10
|
136 else if(value instanceof Character)
|
rlm@10
|
137 {
|
rlm@10
|
138 bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
|
rlm@10
|
139 }
|
rlm@10
|
140 else if(value instanceof Short)
|
rlm@10
|
141 {
|
rlm@10
|
142 bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
|
rlm@10
|
143 }
|
rlm@10
|
144 else if(value instanceof Type)
|
rlm@10
|
145 {
|
rlm@10
|
146 bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
|
rlm@10
|
147 }
|
rlm@10
|
148 else if(value instanceof byte[])
|
rlm@10
|
149 {
|
rlm@10
|
150 byte[] v = (byte[]) value;
|
rlm@10
|
151 bv.put12('[', v.length);
|
rlm@10
|
152 for(int i = 0; i < v.length; i++)
|
rlm@10
|
153 {
|
rlm@10
|
154 bv.put12('B', cw.newInteger(v[i]).index);
|
rlm@10
|
155 }
|
rlm@10
|
156 }
|
rlm@10
|
157 else if(value instanceof boolean[])
|
rlm@10
|
158 {
|
rlm@10
|
159 boolean[] v = (boolean[]) value;
|
rlm@10
|
160 bv.put12('[', v.length);
|
rlm@10
|
161 for(int i = 0; i < v.length; i++)
|
rlm@10
|
162 {
|
rlm@10
|
163 bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
|
rlm@10
|
164 }
|
rlm@10
|
165 }
|
rlm@10
|
166 else if(value instanceof short[])
|
rlm@10
|
167 {
|
rlm@10
|
168 short[] v = (short[]) value;
|
rlm@10
|
169 bv.put12('[', v.length);
|
rlm@10
|
170 for(int i = 0; i < v.length; i++)
|
rlm@10
|
171 {
|
rlm@10
|
172 bv.put12('S', cw.newInteger(v[i]).index);
|
rlm@10
|
173 }
|
rlm@10
|
174 }
|
rlm@10
|
175 else if(value instanceof char[])
|
rlm@10
|
176 {
|
rlm@10
|
177 char[] v = (char[]) value;
|
rlm@10
|
178 bv.put12('[', v.length);
|
rlm@10
|
179 for(int i = 0; i < v.length; i++)
|
rlm@10
|
180 {
|
rlm@10
|
181 bv.put12('C', cw.newInteger(v[i]).index);
|
rlm@10
|
182 }
|
rlm@10
|
183 }
|
rlm@10
|
184 else if(value instanceof int[])
|
rlm@10
|
185 {
|
rlm@10
|
186 int[] v = (int[]) value;
|
rlm@10
|
187 bv.put12('[', v.length);
|
rlm@10
|
188 for(int i = 0; i < v.length; i++)
|
rlm@10
|
189 {
|
rlm@10
|
190 bv.put12('I', cw.newInteger(v[i]).index);
|
rlm@10
|
191 }
|
rlm@10
|
192 }
|
rlm@10
|
193 else if(value instanceof long[])
|
rlm@10
|
194 {
|
rlm@10
|
195 long[] v = (long[]) value;
|
rlm@10
|
196 bv.put12('[', v.length);
|
rlm@10
|
197 for(int i = 0; i < v.length; i++)
|
rlm@10
|
198 {
|
rlm@10
|
199 bv.put12('J', cw.newLong(v[i]).index);
|
rlm@10
|
200 }
|
rlm@10
|
201 }
|
rlm@10
|
202 else if(value instanceof float[])
|
rlm@10
|
203 {
|
rlm@10
|
204 float[] v = (float[]) value;
|
rlm@10
|
205 bv.put12('[', v.length);
|
rlm@10
|
206 for(int i = 0; i < v.length; i++)
|
rlm@10
|
207 {
|
rlm@10
|
208 bv.put12('F', cw.newFloat(v[i]).index);
|
rlm@10
|
209 }
|
rlm@10
|
210 }
|
rlm@10
|
211 else if(value instanceof double[])
|
rlm@10
|
212 {
|
rlm@10
|
213 double[] v = (double[]) value;
|
rlm@10
|
214 bv.put12('[', v.length);
|
rlm@10
|
215 for(int i = 0; i < v.length; i++)
|
rlm@10
|
216 {
|
rlm@10
|
217 bv.put12('D', cw.newDouble(v[i]).index);
|
rlm@10
|
218 }
|
rlm@10
|
219 }
|
rlm@10
|
220 else
|
rlm@10
|
221 {
|
rlm@10
|
222 Item i = cw.newConstItem(value);
|
rlm@10
|
223 bv.put12(".s.IFJDCS".charAt(i.type), i.index);
|
rlm@10
|
224 }
|
rlm@10
|
225 }
|
rlm@10
|
226
|
rlm@10
|
227 public void visitEnum(
|
rlm@10
|
228 final String name,
|
rlm@10
|
229 final String desc,
|
rlm@10
|
230 final String value){
|
rlm@10
|
231 ++size;
|
rlm@10
|
232 if(named)
|
rlm@10
|
233 {
|
rlm@10
|
234 bv.putShort(cw.newUTF8(name));
|
rlm@10
|
235 }
|
rlm@10
|
236 bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
|
rlm@10
|
237 }
|
rlm@10
|
238
|
rlm@10
|
239 public AnnotationVisitor visitAnnotation(
|
rlm@10
|
240 final String name,
|
rlm@10
|
241 final String desc){
|
rlm@10
|
242 ++size;
|
rlm@10
|
243 if(named)
|
rlm@10
|
244 {
|
rlm@10
|
245 bv.putShort(cw.newUTF8(name));
|
rlm@10
|
246 }
|
rlm@10
|
247 // write tag and type, and reserve space for values count
|
rlm@10
|
248 bv.put12('@', cw.newUTF8(desc)).putShort(0);
|
rlm@10
|
249 return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
|
rlm@10
|
250 }
|
rlm@10
|
251
|
rlm@10
|
252 public AnnotationVisitor visitArray(final String name){
|
rlm@10
|
253 ++size;
|
rlm@10
|
254 if(named)
|
rlm@10
|
255 {
|
rlm@10
|
256 bv.putShort(cw.newUTF8(name));
|
rlm@10
|
257 }
|
rlm@10
|
258 // write tag, and reserve space for array size
|
rlm@10
|
259 bv.put12('[', 0);
|
rlm@10
|
260 return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
|
rlm@10
|
261 }
|
rlm@10
|
262
|
rlm@10
|
263 public void visitEnd(){
|
rlm@10
|
264 if(parent != null)
|
rlm@10
|
265 {
|
rlm@10
|
266 byte[] data = parent.data;
|
rlm@10
|
267 data[offset] = (byte) (size >>> 8);
|
rlm@10
|
268 data[offset + 1] = (byte) size;
|
rlm@10
|
269 }
|
rlm@10
|
270 }
|
rlm@10
|
271
|
rlm@10
|
272 // ------------------------------------------------------------------------
|
rlm@10
|
273 // Utility methods
|
rlm@10
|
274 // ------------------------------------------------------------------------
|
rlm@10
|
275
|
rlm@10
|
276 /**
|
rlm@10
|
277 * Returns the size of this annotation writer list.
|
rlm@10
|
278 *
|
rlm@10
|
279 * @return the size of this annotation writer list.
|
rlm@10
|
280 */
|
rlm@10
|
281 int getSize(){
|
rlm@10
|
282 int size = 0;
|
rlm@10
|
283 AnnotationWriter aw = this;
|
rlm@10
|
284 while(aw != null)
|
rlm@10
|
285 {
|
rlm@10
|
286 size += aw.bv.length;
|
rlm@10
|
287 aw = aw.next;
|
rlm@10
|
288 }
|
rlm@10
|
289 return size;
|
rlm@10
|
290 }
|
rlm@10
|
291
|
rlm@10
|
292 /**
|
rlm@10
|
293 * Puts the annotations of this annotation writer list into the given byte
|
rlm@10
|
294 * vector.
|
rlm@10
|
295 *
|
rlm@10
|
296 * @param out where the annotations must be put.
|
rlm@10
|
297 */
|
rlm@10
|
298 void put(final ByteVector out){
|
rlm@10
|
299 int n = 0;
|
rlm@10
|
300 int size = 2;
|
rlm@10
|
301 AnnotationWriter aw = this;
|
rlm@10
|
302 AnnotationWriter last = null;
|
rlm@10
|
303 while(aw != null)
|
rlm@10
|
304 {
|
rlm@10
|
305 ++n;
|
rlm@10
|
306 size += aw.bv.length;
|
rlm@10
|
307 aw.visitEnd(); // in case user forgot to call visitEnd
|
rlm@10
|
308 aw.prev = last;
|
rlm@10
|
309 last = aw;
|
rlm@10
|
310 aw = aw.next;
|
rlm@10
|
311 }
|
rlm@10
|
312 out.putInt(size);
|
rlm@10
|
313 out.putShort(n);
|
rlm@10
|
314 aw = last;
|
rlm@10
|
315 while(aw != null)
|
rlm@10
|
316 {
|
rlm@10
|
317 out.putByteArray(aw.bv.data, 0, aw.bv.length);
|
rlm@10
|
318 aw = aw.prev;
|
rlm@10
|
319 }
|
rlm@10
|
320 }
|
rlm@10
|
321
|
rlm@10
|
322 /**
|
rlm@10
|
323 * Puts the given annotation lists into the given byte vector.
|
rlm@10
|
324 *
|
rlm@10
|
325 * @param panns an array of annotation writer lists.
|
rlm@10
|
326 * @param out where the annotations must be put.
|
rlm@10
|
327 */
|
rlm@10
|
328 static void put(final AnnotationWriter[] panns, final ByteVector out){
|
rlm@10
|
329 int size = 1 + 2 * panns.length;
|
rlm@10
|
330 for(int i = 0; i < panns.length; ++i)
|
rlm@10
|
331 {
|
rlm@10
|
332 size += panns[i] == null ? 0 : panns[i].getSize();
|
rlm@10
|
333 }
|
rlm@10
|
334 out.putInt(size).putByte(panns.length);
|
rlm@10
|
335 for(int i = 0; i < panns.length; ++i)
|
rlm@10
|
336 {
|
rlm@10
|
337 AnnotationWriter aw = panns[i];
|
rlm@10
|
338 AnnotationWriter last = null;
|
rlm@10
|
339 int n = 0;
|
rlm@10
|
340 while(aw != null)
|
rlm@10
|
341 {
|
rlm@10
|
342 ++n;
|
rlm@10
|
343 aw.visitEnd(); // in case user forgot to call visitEnd
|
rlm@10
|
344 aw.prev = last;
|
rlm@10
|
345 last = aw;
|
rlm@10
|
346 aw = aw.next;
|
rlm@10
|
347 }
|
rlm@10
|
348 out.putShort(n);
|
rlm@10
|
349 aw = last;
|
rlm@10
|
350 while(aw != null)
|
rlm@10
|
351 {
|
rlm@10
|
352 out.putByteArray(aw.bv.data, 0, aw.bv.length);
|
rlm@10
|
353 aw = aw.prev;
|
rlm@10
|
354 }
|
rlm@10
|
355 }
|
rlm@10
|
356 }
|
rlm@10
|
357 }
|