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 */
59package 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 */
67final 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}
401