Home | History | Annotate | Download | only in asm
      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 org.objectweb.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     {
    107         this.cw = cw;
    108         this.named = named;
    109         this.bv = bv;
    110         this.parent = parent;
    111         this.offset = offset;
    112     }
    113 
    114     // ------------------------------------------------------------------------
    115     // Implementation of the AnnotationVisitor interface
    116     // ------------------------------------------------------------------------
    117 
    118     public void visit(final String name, final Object value) {
    119         ++size;
    120         if (named) {
    121             bv.putShort(cw.newUTF8(name));
    122         }
    123         if (value instanceof String) {
    124             bv.put12('s', cw.newUTF8((String) value));
    125         } else if (value instanceof Byte) {
    126             bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
    127         } else if (value instanceof Boolean) {
    128             int v = ((Boolean) value).booleanValue() ? 1 : 0;
    129             bv.put12('Z', cw.newInteger(v).index);
    130         } else if (value instanceof Character) {
    131             bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
    132         } else if (value instanceof Short) {
    133             bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
    134         } else if (value instanceof Type) {
    135             bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
    136         } else if (value instanceof byte[]) {
    137             byte[] v = (byte[]) value;
    138             bv.put12('[', v.length);
    139             for (int i = 0; i < v.length; i++) {
    140                 bv.put12('B', cw.newInteger(v[i]).index);
    141             }
    142         } else if (value instanceof boolean[]) {
    143             boolean[] v = (boolean[]) value;
    144             bv.put12('[', v.length);
    145             for (int i = 0; i < v.length; i++) {
    146                 bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
    147             }
    148         } else if (value instanceof short[]) {
    149             short[] v = (short[]) value;
    150             bv.put12('[', v.length);
    151             for (int i = 0; i < v.length; i++) {
    152                 bv.put12('S', cw.newInteger(v[i]).index);
    153             }
    154         } else if (value instanceof char[]) {
    155             char[] v = (char[]) value;
    156             bv.put12('[', v.length);
    157             for (int i = 0; i < v.length; i++) {
    158                 bv.put12('C', cw.newInteger(v[i]).index);
    159             }
    160         } else if (value instanceof int[]) {
    161             int[] v = (int[]) value;
    162             bv.put12('[', v.length);
    163             for (int i = 0; i < v.length; i++) {
    164                 bv.put12('I', cw.newInteger(v[i]).index);
    165             }
    166         } else if (value instanceof long[]) {
    167             long[] v = (long[]) value;
    168             bv.put12('[', v.length);
    169             for (int i = 0; i < v.length; i++) {
    170                 bv.put12('J', cw.newLong(v[i]).index);
    171             }
    172         } else if (value instanceof float[]) {
    173             float[] v = (float[]) value;
    174             bv.put12('[', v.length);
    175             for (int i = 0; i < v.length; i++) {
    176                 bv.put12('F', cw.newFloat(v[i]).index);
    177             }
    178         } else if (value instanceof double[]) {
    179             double[] v = (double[]) value;
    180             bv.put12('[', v.length);
    181             for (int i = 0; i < v.length; i++) {
    182                 bv.put12('D', cw.newDouble(v[i]).index);
    183             }
    184         } else {
    185             Item i = cw.newConstItem(value);
    186             bv.put12(".s.IFJDCS".charAt(i.type), i.index);
    187         }
    188     }
    189 
    190     public void visitEnum(
    191         final String name,
    192         final String desc,
    193         final String value)
    194     {
    195         ++size;
    196         if (named) {
    197             bv.putShort(cw.newUTF8(name));
    198         }
    199         bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
    200     }
    201 
    202     public AnnotationVisitor visitAnnotation(
    203         final String name,
    204         final String desc)
    205     {
    206         ++size;
    207         if (named) {
    208             bv.putShort(cw.newUTF8(name));
    209         }
    210         // write tag and type, and reserve space for values count
    211         bv.put12('@', cw.newUTF8(desc)).putShort(0);
    212         return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
    213     }
    214 
    215     public AnnotationVisitor visitArray(final String name) {
    216         ++size;
    217         if (named) {
    218             bv.putShort(cw.newUTF8(name));
    219         }
    220         // write tag, and reserve space for array size
    221         bv.put12('[', 0);
    222         return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
    223     }
    224 
    225     public void visitEnd() {
    226         if (parent != null) {
    227             byte[] data = parent.data;
    228             data[offset] = (byte) (size >>> 8);
    229             data[offset + 1] = (byte) size;
    230         }
    231     }
    232 
    233     // ------------------------------------------------------------------------
    234     // Utility methods
    235     // ------------------------------------------------------------------------
    236 
    237     /**
    238      * Returns the size of this annotation writer list.
    239      *
    240      * @return the size of this annotation writer list.
    241      */
    242     int getSize() {
    243         int size = 0;
    244         AnnotationWriter aw = this;
    245         while (aw != null) {
    246             size += aw.bv.length;
    247             aw = aw.next;
    248         }
    249         return size;
    250     }
    251 
    252     /**
    253      * Puts the annotations of this annotation writer list into the given byte
    254      * vector.
    255      *
    256      * @param out where the annotations must be put.
    257      */
    258     void put(final ByteVector out) {
    259         int n = 0;
    260         int size = 2;
    261         AnnotationWriter aw = this;
    262         AnnotationWriter last = null;
    263         while (aw != null) {
    264             ++n;
    265             size += aw.bv.length;
    266             aw.visitEnd(); // in case user forgot to call visitEnd
    267             aw.prev = last;
    268             last = aw;
    269             aw = aw.next;
    270         }
    271         out.putInt(size);
    272         out.putShort(n);
    273         aw = last;
    274         while (aw != null) {
    275             out.putByteArray(aw.bv.data, 0, aw.bv.length);
    276             aw = aw.prev;
    277         }
    278     }
    279 
    280     /**
    281      * Puts the given annotation lists into the given byte vector.
    282      *
    283      * @param panns an array of annotation writer lists.
    284      * @param out where the annotations must be put.
    285      */
    286     static void put(final AnnotationWriter[] panns, final ByteVector out) {
    287         int size = 1 + 2 * panns.length;
    288         for (int i = 0; i < panns.length; ++i) {
    289             size += panns[i] == null ? 0 : panns[i].getSize();
    290         }
    291         out.putInt(size).putByte(panns.length);
    292         for (int i = 0; i < panns.length; ++i) {
    293             AnnotationWriter aw = panns[i];
    294             AnnotationWriter last = null;
    295             int n = 0;
    296             while (aw != null) {
    297                 ++n;
    298                 aw.visitEnd(); // in case user forgot to call visitEnd
    299                 aw.prev = last;
    300                 last = aw;
    301                 aw = aw.next;
    302             }
    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