1 /*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2007 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.mockito.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 */ AnnotationWriter( final ClassWriter cw, final boolean named, final ByteVector bv, final ByteVector parent, final int offset)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 visit(final String name, final Object value)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 visitEnum( final String name, final String desc, final String value)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 visitAnnotation( final String name, final String desc)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 visitArray(final String name)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 visitEnd()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 */ getSize()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 */ put(final ByteVector out)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 off index of the first annotation to be written. 285 * @param out where the annotations must be put. 286 */ put( final AnnotationWriter[] panns, final int off, final ByteVector out)287 static void put( 288 final AnnotationWriter[] panns, 289 final int off, 290 final ByteVector out) 291 { 292 int size = 1 + 2 * (panns.length - off); 293 for (int i = off; i < panns.length; ++i) { 294 size += panns[i] == null ? 0 : panns[i].getSize(); 295 } 296 out.putInt(size).putByte(panns.length - off); 297 for (int i = off; i < panns.length; ++i) { 298 AnnotationWriter aw = panns[i]; 299 AnnotationWriter last = null; 300 int n = 0; 301 while (aw != null) { 302 ++n; 303 aw.visitEnd(); // in case user forgot to call visitEnd 304 aw.prev = last; 305 last = aw; 306 aw = aw.next; 307 } 308 out.putShort(n); 309 aw = last; 310 while (aw != null) { 311 out.putByteArray(aw.bv.data, 0, aw.bv.length); 312 aw = aw.prev; 313 } 314 } 315 } 316 } 317