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