001: /***
002: * ASM: a very small and fast Java bytecode manipulation framework
003: * Copyright (c) 2000-2005 INRIA, France Telecom
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: * 2. Redistributions in binary form must reproduce the above copyright
012: * notice, this list of conditions and the following disclaimer in the
013: * documentation and/or other materials provided with the distribution.
014: * 3. Neither the name of the copyright holders nor the names of its
015: * contributors may be used to endorse or promote products derived from
016: * this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028: * THE POSSIBILITY OF SUCH DAMAGE.
029: */package org.drools.asm;
030:
031: /**
032: * An {@link AnnotationVisitor} that generates annotations in bytecode form.
033: *
034: * @author Eric Bruneton
035: * @author Eugene Kuleshov
036: */
037: final class AnnotationWriter implements AnnotationVisitor {
038:
039: /**
040: * The class writer to which this annotation must be added.
041: */
042: private final ClassWriter cw;
043:
044: /**
045: * The number of values in this annotation.
046: */
047: private int size;
048:
049: /**
050: * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
051: * writers used for annotation default and annotation arrays use unnamed
052: * values.
053: */
054: private final boolean named;
055:
056: /**
057: * The annotation values in bytecode form. This byte vector only contains
058: * the values themselves, i.e. the number of values must be stored as a
059: * unsigned short just before these bytes.
060: */
061: private final ByteVector bv;
062:
063: /**
064: * The byte vector to be used to store the number of values of this
065: * annotation. See {@link #bv}.
066: */
067: private final ByteVector parent;
068:
069: /**
070: * Where the number of values of this annotation must be stored in
071: * {@link #parent}.
072: */
073: private final int offset;
074:
075: /**
076: * Next annotation writer. This field is used to store annotation lists.
077: */
078: AnnotationWriter next;
079:
080: /**
081: * Previous annotation writer. This field is used to store annotation lists.
082: */
083: AnnotationWriter prev;
084:
085: // ------------------------------------------------------------------------
086: // Constructor
087: // ------------------------------------------------------------------------
088:
089: /**
090: * Constructs a new {@link AnnotationWriter}.
091: *
092: * @param cw the class writer to which this annotation must be added.
093: * @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise.
094: * @param bv where the annotation values must be stored.
095: * @param parent where the number of annotation values must be stored.
096: * @param offset where in <tt>parent</tt> the number of annotation values must
097: * be stored.
098: */
099: AnnotationWriter(final ClassWriter cw, final boolean named,
100: final ByteVector bv, final ByteVector parent,
101: final int offset) {
102: this .cw = cw;
103: this .named = named;
104: this .bv = bv;
105: this .parent = parent;
106: this .offset = offset;
107: }
108:
109: // ------------------------------------------------------------------------
110: // Implementation of the AnnotationVisitor interface
111: // ------------------------------------------------------------------------
112:
113: public void visit(final String name, final Object value) {
114: ++this .size;
115: if (this .named) {
116: this .bv.putShort(this .cw.newUTF8(name));
117: }
118: if (value instanceof String) {
119: this .bv.put12('s', this .cw.newUTF8((String) value));
120: } else if (value instanceof Byte) {
121: this .bv.put12('B', this .cw.newInteger(((Byte) value)
122: .byteValue()).index);
123: } else if (value instanceof Boolean) {
124: final int v = ((Boolean) value).booleanValue() ? 1 : 0;
125: this .bv.put12('Z', this .cw.newInteger(v).index);
126: } else if (value instanceof Character) {
127: this .bv.put12('C', this .cw.newInteger(((Character) value)
128: .charValue()).index);
129: } else if (value instanceof Short) {
130: this .bv.put12('S', this .cw.newInteger(((Short) value)
131: .shortValue()).index);
132: } else if (value instanceof Type) {
133: this .bv.put12('c', this .cw.newUTF8(((Type) value)
134: .getDescriptor()));
135: } else if (value instanceof byte[]) {
136: final byte[] v = (byte[]) value;
137: this .bv.put12('[', v.length);
138: for (int i = 0; i < v.length; i++) {
139: this .bv.put12('B', this .cw.newInteger(v[i]).index);
140: }
141: } else if (value instanceof boolean[]) {
142: final boolean[] v = (boolean[]) value;
143: this .bv.put12('[', v.length);
144: for (int i = 0; i < v.length; i++) {
145: this .bv.put12('Z',
146: this .cw.newInteger(v[i] ? 1 : 0).index);
147: }
148: } else if (value instanceof short[]) {
149: final short[] v = (short[]) value;
150: this .bv.put12('[', v.length);
151: for (int i = 0; i < v.length; i++) {
152: this .bv.put12('S', this .cw.newInteger(v[i]).index);
153: }
154: } else if (value instanceof char[]) {
155: final char[] v = (char[]) value;
156: this .bv.put12('[', v.length);
157: for (int i = 0; i < v.length; i++) {
158: this .bv.put12('C', this .cw.newInteger(v[i]).index);
159: }
160: } else if (value instanceof int[]) {
161: final int[] v = (int[]) value;
162: this .bv.put12('[', v.length);
163: for (int i = 0; i < v.length; i++) {
164: this .bv.put12('I', this .cw.newInteger(v[i]).index);
165: }
166: } else if (value instanceof long[]) {
167: final long[] v = (long[]) value;
168: this .bv.put12('[', v.length);
169: for (int i = 0; i < v.length; i++) {
170: this .bv.put12('J', this .cw.newLong(v[i]).index);
171: }
172: } else if (value instanceof float[]) {
173: final float[] v = (float[]) value;
174: this .bv.put12('[', v.length);
175: for (int i = 0; i < v.length; i++) {
176: this .bv.put12('F', this .cw.newFloat(v[i]).index);
177: }
178: } else if (value instanceof double[]) {
179: final double[] v = (double[]) value;
180: this .bv.put12('[', v.length);
181: for (int i = 0; i < v.length; i++) {
182: this .bv.put12('D', this .cw.newDouble(v[i]).index);
183: }
184: } else {
185: final Item i = this .cw.newConstItem(value);
186: this .bv.put12(".s.IFJDCS".charAt(i.type), i.index);
187: }
188: }
189:
190: public void visitEnum(final String name, final String desc,
191: final String value) {
192: ++this .size;
193: if (this .named) {
194: this .bv.putShort(this .cw.newUTF8(name));
195: }
196: this .bv.put12('e', this .cw.newUTF8(desc)).putShort(
197: this .cw.newUTF8(value));
198: }
199:
200: public AnnotationVisitor visitAnnotation(final String name,
201: final String desc) {
202: ++this .size;
203: if (this .named) {
204: this .bv.putShort(this .cw.newUTF8(name));
205: }
206: // write tag and type, and reserve space for values count
207: this .bv.put12('@', this .cw.newUTF8(desc)).putShort(0);
208: return new AnnotationWriter(this .cw, true, this .bv, this .bv,
209: this .bv.length - 2);
210: }
211:
212: public AnnotationVisitor visitArray(final String name) {
213: ++this .size;
214: if (this .named) {
215: this .bv.putShort(this .cw.newUTF8(name));
216: }
217: // write tag, and reserve space for array size
218: this .bv.put12('[', 0);
219: return new AnnotationWriter(this .cw, false, this .bv, this .bv,
220: this .bv.length - 2);
221: }
222:
223: public void visitEnd() {
224: if (this .parent != null) {
225: final byte[] data = this .parent.data;
226: data[this .offset] = (byte) (this .size >>> 8);
227: data[this .offset + 1] = (byte) this .size;
228: }
229: }
230:
231: // ------------------------------------------------------------------------
232: // Utility methods
233: // ------------------------------------------------------------------------
234:
235: /**
236: * Returns the size of this annotation writer list.
237: *
238: * @return the size of this annotation writer list.
239: */
240: int getSize() {
241: int size = 0;
242: AnnotationWriter aw = this ;
243: while (aw != null) {
244: size += aw.bv.length;
245: aw = aw.next;
246: }
247: return size;
248: }
249:
250: /**
251: * Puts the annotations of this annotation writer list into the given byte
252: * vector.
253: *
254: * @param out where the annotations must be put.
255: */
256: void put(final ByteVector out) {
257: int n = 0;
258: int size = 2;
259: AnnotationWriter aw = this ;
260: AnnotationWriter last = null;
261: while (aw != null) {
262: ++n;
263: size += aw.bv.length;
264: aw.visitEnd(); // in case user forgot to call visitEnd
265: aw.prev = last;
266: last = aw;
267: aw = aw.next;
268: }
269: out.putInt(size);
270: out.putShort(n);
271: aw = last;
272: while (aw != null) {
273: out.putByteArray(aw.bv.data, 0, aw.bv.length);
274: aw = aw.prev;
275: }
276: }
277:
278: /**
279: * Puts the given annotation lists into the given byte vector.
280: *
281: * @param panns an array of annotation writer lists.
282: * @param out where the annotations must be put.
283: */
284: static void put(final AnnotationWriter[] panns, final ByteVector out) {
285: int size = 1 + 2 * panns.length;
286: for (int i = 0; i < panns.length; ++i) {
287: size += panns[i] == null ? 0 : panns[i].getSize();
288: }
289: out.putInt(size).putByte(panns.length);
290: for (int i = 0; i < panns.length; ++i) {
291: AnnotationWriter aw = panns[i];
292: AnnotationWriter last = null;
293: int n = 0;
294: while (aw != null) {
295: ++n;
296: aw.visitEnd(); // in case user forgot to call visitEnd
297: aw.prev = last;
298: last = aw;
299: aw = aw.next;
300: }
301: out.putShort(n);
302: aw = last;
303: while (aw != null) {
304: out.putByteArray(aw.bv.data, 0, aw.bv.length);
305: aw = aw.prev;
306: }
307: }
308: }
309: }
|