annotate src/clojure/asm/AnnotationWriter.java @ 10:ef7dbbd6452c

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