View Javadoc
1   /*
2    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3    *
4    * This code is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU General Public License version 2 only, as
6    * published by the Free Software Foundation.  Oracle designates this
7    * particular file as subject to the "Classpath" exception as provided
8    * by Oracle in the LICENSE file that accompanied this code.
9    *
10   * This code is distributed in the hope that it will be useful, but WITHOUT
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13   * version 2 for more details (a copy is included in the LICENSE file that
14   * accompanied this code).
15   *
16   * You should have received a copy of the GNU General Public License version
17   * 2 along with this work; if not, write to the Free Software Foundation,
18   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19   *
20   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21   * or visit www.oracle.com if you need additional information or have any
22   * questions.
23   */
24  
25  /*
26   * This file is available under and governed by the GNU General Public
27   * License version 2 only, as published by the Free Software Foundation.
28   * However, the following notice accompanied the original version of this
29   * file:
30   *
31   * ASM: a very small and fast Java bytecode manipulation framework
32   * Copyright (c) 2000-2011 INRIA, France Telecom
33   * All rights reserved.
34   *
35   * Redistribution and use in source and binary forms, with or without
36   * modification, are permitted provided that the following conditions
37   * are met:
38   * 1. Redistributions of source code must retain the above copyright
39   *    notice, this list of conditions and the following disclaimer.
40   * 2. Redistributions in binary form must reproduce the above copyright
41   *    notice, this list of conditions and the following disclaimer in the
42   *    documentation and/or other materials provided with the distribution.
43   * 3. Neither the name of the copyright holders nor the names of its
44   *    contributors may be used to endorse or promote products derived from
45   *    this software without specific prior written permission.
46   *
47   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57   * THE POSSIBILITY OF SUCH DAMAGE.
58   */
59  package jdk.internal.org.objectweb.asm;
60  
61  /**
62   * An {@link AnnotationVisitor} that generates annotations in bytecode form.
63   *
64   * @author Eric Bruneton
65   * @author Eugene Kuleshov
66   */
67  final class AnnotationWriter extends AnnotationVisitor {
68  
69      /**
70       * The class writer to which this annotation must be added.
71       */
72      private final ClassWriter cw;
73  
74      /**
75       * The number of values in this annotation.
76       */
77      private int size;
78  
79      /**
80       * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
81       * writers used for annotation default and annotation arrays use unnamed
82       * values.
83       */
84      private final boolean named;
85  
86      /**
87       * The annotation values in bytecode form. This byte vector only contains
88       * the values themselves, i.e. the number of values must be stored as a
89       * unsigned short just before these bytes.
90       */
91      private final ByteVector bv;
92  
93      /**
94       * The byte vector to be used to store the number of values of this
95       * annotation. See {@link #bv}.
96       */
97      private final ByteVector parent;
98  
99      /**
100      * Where the number of values of this annotation must be stored in
101      * {@link #parent}.
102      */
103     private final int offset;
104 
105     /**
106      * Next annotation writer. This field is used to store annotation lists.
107      */
108     AnnotationWriter next;
109 
110     /**
111      * Previous annotation writer. This field is used to store annotation lists.
112      */
113     AnnotationWriter prev;
114 
115     // ------------------------------------------------------------------------
116     // Constructor
117     // ------------------------------------------------------------------------
118 
119     /**
120      * Constructs a new {@link AnnotationWriter}.
121      *
122      * @param cw
123      *            the class writer to which this annotation must be added.
124      * @param named
125      *            <tt>true<tt> if values are named, <tt>false</tt> otherwise.
126      * @param bv
127      *            where the annotation values must be stored.
128      * @param parent
129      *            where the number of annotation values must be stored.
130      * @param offset
131      *            where in <tt>parent</tt> the number of annotation values must
132      *            be stored.
133      */
134     AnnotationWriter(final ClassWriter cw, final boolean named,
135             final ByteVector bv, final ByteVector parent, final int offset) {
136         super(Opcodes.ASM5);
137         this.cw = cw;
138         this.named = named;
139         this.bv = bv;
140         this.parent = parent;
141         this.offset = offset;
142     }
143 
144     // ------------------------------------------------------------------------
145     // Implementation of the AnnotationVisitor abstract class
146     // ------------------------------------------------------------------------
147 
148     @Override
149     public void visit(final String name, final Object value) {
150         ++size;
151         if (named) {
152             bv.putShort(cw.newUTF8(name));
153         }
154         if (value instanceof String) {
155             bv.put12('s', cw.newUTF8((String) value));
156         } else if (value instanceof Byte) {
157             bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
158         } else if (value instanceof Boolean) {
159             int v = ((Boolean) value).booleanValue() ? 1 : 0;
160             bv.put12('Z', cw.newInteger(v).index);
161         } else if (value instanceof Character) {
162             bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
163         } else if (value instanceof Short) {
164             bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
165         } else if (value instanceof Type) {
166             bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
167         } else if (value instanceof byte[]) {
168             byte[] v = (byte[]) value;
169             bv.put12('[', v.length);
170             for (int i = 0; i < v.length; i++) {
171                 bv.put12('B', cw.newInteger(v[i]).index);
172             }
173         } else if (value instanceof boolean[]) {
174             boolean[] v = (boolean[]) value;
175             bv.put12('[', v.length);
176             for (int i = 0; i < v.length; i++) {
177                 bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
178             }
179         } else if (value instanceof short[]) {
180             short[] v = (short[]) value;
181             bv.put12('[', v.length);
182             for (int i = 0; i < v.length; i++) {
183                 bv.put12('S', cw.newInteger(v[i]).index);
184             }
185         } else if (value instanceof char[]) {
186             char[] v = (char[]) value;
187             bv.put12('[', v.length);
188             for (int i = 0; i < v.length; i++) {
189                 bv.put12('C', cw.newInteger(v[i]).index);
190             }
191         } else if (value instanceof int[]) {
192             int[] v = (int[]) value;
193             bv.put12('[', v.length);
194             for (int i = 0; i < v.length; i++) {
195                 bv.put12('I', cw.newInteger(v[i]).index);
196             }
197         } else if (value instanceof long[]) {
198             long[] v = (long[]) value;
199             bv.put12('[', v.length);
200             for (int i = 0; i < v.length; i++) {
201                 bv.put12('J', cw.newLong(v[i]).index);
202             }
203         } else if (value instanceof float[]) {
204             float[] v = (float[]) value;
205             bv.put12('[', v.length);
206             for (int i = 0; i < v.length; i++) {
207                 bv.put12('F', cw.newFloat(v[i]).index);
208             }
209         } else if (value instanceof double[]) {
210             double[] v = (double[]) value;
211             bv.put12('[', v.length);
212             for (int i = 0; i < v.length; i++) {
213                 bv.put12('D', cw.newDouble(v[i]).index);
214             }
215         } else {
216             Item i = cw.newConstItem(value);
217             bv.put12(".s.IFJDCS".charAt(i.type), i.index);
218         }
219     }
220 
221     @Override
222     public void visitEnum(final String name, final String desc,
223             final String value) {
224         ++size;
225         if (named) {
226             bv.putShort(cw.newUTF8(name));
227         }
228         bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
229     }
230 
231     @Override
232     public AnnotationVisitor visitAnnotation(final String name,
233             final String desc) {
234         ++size;
235         if (named) {
236             bv.putShort(cw.newUTF8(name));
237         }
238         // write tag and type, and reserve space for values count
239         bv.put12('@', cw.newUTF8(desc)).putShort(0);
240         return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
241     }
242 
243     @Override
244     public AnnotationVisitor visitArray(final String name) {
245         ++size;
246         if (named) {
247             bv.putShort(cw.newUTF8(name));
248         }
249         // write tag, and reserve space for array size
250         bv.put12('[', 0);
251         return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
252     }
253 
254     @Override
255     public void visitEnd() {
256         if (parent != null) {
257             byte[] data = parent.data;
258             data[offset] = (byte) (size >>> 8);
259             data[offset + 1] = (byte) size;
260         }
261     }
262 
263     // ------------------------------------------------------------------------
264     // Utility methods
265     // ------------------------------------------------------------------------
266 
267     /**
268      * Returns the size of this annotation writer list.
269      *
270      * @return the size of this annotation writer list.
271      */
272     int getSize() {
273         int size = 0;
274         AnnotationWriter aw = this;
275         while (aw != null) {
276             size += aw.bv.length;
277             aw = aw.next;
278         }
279         return size;
280     }
281 
282     /**
283      * Puts the annotations of this annotation writer list into the given byte
284      * vector.
285      *
286      * @param out
287      *            where the annotations must be put.
288      */
289     void put(final ByteVector out) {
290         int n = 0;
291         int size = 2;
292         AnnotationWriter aw = this;
293         AnnotationWriter last = null;
294         while (aw != null) {
295             ++n;
296             size += aw.bv.length;
297             aw.visitEnd(); // in case user forgot to call visitEnd
298             aw.prev = last;
299             last = aw;
300             aw = aw.next;
301         }
302         out.putInt(size);
303         out.putShort(n);
304         aw = last;
305         while (aw != null) {
306             out.putByteArray(aw.bv.data, 0, aw.bv.length);
307             aw = aw.prev;
308         }
309     }
310 
311     /**
312      * Puts the given annotation lists into the given byte vector.
313      *
314      * @param panns
315      *            an array of annotation writer lists.
316      * @param off
317      *            index of the first annotation to be written.
318      * @param out
319      *            where the annotations must be put.
320      */
321     static void put(final AnnotationWriter[] panns, final int off,
322             final ByteVector out) {
323         int size = 1 + 2 * (panns.length - off);
324         for (int i = off; i < panns.length; ++i) {
325             size += panns[i] == null ? 0 : panns[i].getSize();
326         }
327         out.putInt(size).putByte(panns.length - off);
328         for (int i = off; i < panns.length; ++i) {
329             AnnotationWriter aw = panns[i];
330             AnnotationWriter last = null;
331             int n = 0;
332             while (aw != null) {
333                 ++n;
334                 aw.visitEnd(); // in case user forgot to call visitEnd
335                 aw.prev = last;
336                 last = aw;
337                 aw = aw.next;
338             }
339             out.putShort(n);
340             aw = last;
341             while (aw != null) {
342                 out.putByteArray(aw.bv.data, 0, aw.bv.length);
343                 aw = aw.prev;
344             }
345         }
346     }
347 
348     /**
349      * Puts the given type reference and type path into the given bytevector.
350      * LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
351      *
352      * @param typeRef
353      *            a reference to the annotated type. See {@link TypeReference}.
354      * @param typePath
355      *            the path to the annotated type argument, wildcard bound, array
356      *            element type, or static inner type within 'typeRef'. May be
357      *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
358      * @param out
359      *            where the type reference and type path must be put.
360      */
361     static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
362         switch (typeRef >>> 24) {
363         case 0x00: // CLASS_TYPE_PARAMETER
364         case 0x01: // METHOD_TYPE_PARAMETER
365         case 0x16: // METHOD_FORMAL_PARAMETER
366             out.putShort(typeRef >>> 16);
367             break;
368         case 0x13: // FIELD
369         case 0x14: // METHOD_RETURN
370         case 0x15: // METHOD_RECEIVER
371             out.putByte(typeRef >>> 24);
372             break;
373         case 0x47: // CAST
374         case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
375         case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
376         case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
377         case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
378             out.putInt(typeRef);
379             break;
380         // case 0x10: // CLASS_EXTENDS
381         // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
382         // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
383         // case 0x17: // THROWS
384         // case 0x42: // EXCEPTION_PARAMETER
385         // case 0x43: // INSTANCEOF
386         // case 0x44: // NEW
387         // case 0x45: // CONSTRUCTOR_REFERENCE
388         // case 0x46: // METHOD_REFERENCE
389         default:
390             out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
391             break;
392         }
393         if (typePath == null) {
394             out.putByte(0);
395         } else {
396             int length = typePath.b[typePath.offset] * 2 + 1;
397             out.putByteArray(typePath.b, typePath.offset, length);
398         }
399     }
400 }