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