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