1 /* 2 * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.asmtools.jdis; 24 25 import static java.lang.String.format; 26 import static org.openjdk.asmtools.jasm.Tables.*; 27 import java.io.DataInputStream; 28 import java.io.IOException; 29 import java.io.PrintWriter; 30 import java.util.ArrayList; 31 32 /** 33 * Base class of all AnnotationElement entries 34 */ 35 public class AnnotationElement { 36 37 /** 38 * 39 * CPX_AnnotElem 40 * 41 * base class for an annotation value. 42 * 43 */ 44 public static class AnnotValue { 45 46 /** 47 * tag the descriptor for the constant 48 */ 49 public AnnotElemType tag; 50 51 // internal references 52 protected ClassData cls; 53 54 public AnnotValue(AnnotElemType tagval, ClassData cls) { 55 tag = tagval; 56 this.cls = cls; 57 } 58 59 public String stringVal() { 60 return ""; 61 } 62 63 public void print(PrintWriter out, String tab) { 64 out.print(tag.val() + " "); 65 } 66 67 @Override 68 public String toString() { 69 return "<AnnotValue " + tag.printval() + " " + stringVal() + ">"; 70 } 71 } 72 73 /** 74 * 75 * CPX_AnnotElem 76 * 77 * Annotation value which is described by a single CPX entry (ie. String, byte, char, 78 * int, short, boolean, float, long, double, class reference). 79 * 80 */ 81 public static class CPX_AnnotValue extends AnnotValue { 82 83 /** 84 * tag the descriptor for the constant 85 */ 86 public int cpx; 87 88 public CPX_AnnotValue(AnnotElemType tag, ClassData cls, int cpx) { 89 super(tag, cls); 90 this.cpx = cpx; 91 } 92 93 @Override 94 public String stringVal() { 95 StringBuilder sb = new StringBuilder(); 96 switch (tag) { 97 case AE_STRING: // String 98 sb.append('"' + cls.pool.getString(cpx) + '"'); 99 break; 100 case AE_BYTE: // Byte 101 sb.append("byte " + cls.pool.getConst(cpx).stringVal()); 102 break; 103 case AE_CHAR: // Char 104 sb.append("char " + cls.pool.getConst(cpx).stringVal()); 105 break; 106 case AE_INT: // Int (no need to add keyword) 107 sb.append(cls.pool.getConst(cpx).stringVal()); 108 break; 109 case AE_SHORT: // Short 110 sb.append("short " + cls.pool.getConst(cpx).stringVal()); 111 break; 112 case AE_BOOLEAN: // Boolean 113 ConstantPool.CP_Int cns = (ConstantPool.CP_Int) cls.pool.getConst(cpx); 114 sb.append("boolean " + (cns.value == 0 ? "false" : "true")); 115 break; 116 case AE_FLOAT: // Float 117 sb.append(cls.pool.getConst(cpx).stringVal()); // + "f"); 118 break; 119 case AE_DOUBLE: // Double 120 sb.append(cls.pool.getConst(cpx).stringVal()); // + "d"); 121 break; 122 case AE_LONG: // Long 123 sb.append(cls.pool.getConst(cpx).stringVal()); // + "l"); 124 break; 125 case AE_CLASS: // Class 126 sb.append("class " + cls.pool.decodeClassDescriptor(cpx)); 127 break; 128 default: 129 break; 130 } 131 return sb.toString(); 132 } 133 134 @Override 135 public void print(PrintWriter out, String tab) { 136 out.print(tab + stringVal()); 137 } 138 139 @Override 140 public String toString() { 141 return "<CPX_AnnotValue tag: '" + tag + "' stringVal=" + this.stringVal() + ">"; 142 } 143 } 144 145 /** 146 * 147 * CPX_AnnotElem 148 * 149 * AnnotElements that contain 2 cpx indices (ie. enums). 150 * 151 */ 152 public static class CPX2_AnnotValue extends AnnotValue { 153 154 /** 155 * tag the descriptor for the constant 156 */ 157 public int cpx1; 158 public int cpx2; 159 160 public CPX2_AnnotValue(AnnotElemType tag, ClassData cls, int cpx1, int cpx2) { 161 super(tag, cls); 162 this.cpx1 = cpx1; 163 this.cpx2 = cpx2; 164 } 165 166 @Override 167 public String stringVal() { 168 StringBuilder sb = new StringBuilder(); 169 switch (tag) { 170 171 case AE_ENUM: // Enum 172 // print the enum type and constant name 173 sb.append("enum " + cls.pool.decodeClassDescriptor(cpx1) 174 + " " + cls.pool.getName(cpx2)); 175 break; 176 default: 177 break; 178 } 179 return sb.toString(); 180 } 181 182 @Override 183 public void print(PrintWriter out, String tab) { 184 out.print(tab + stringVal()); 185 } 186 187 @Override 188 public String toString() { 189 return "<CPX2_AnnotValue tag: '" + tag + "' stringVal=" + this.stringVal() + ">"; 190 } 191 } 192 193 /** 194 * 195 * Array_AnnotElem 196 * 197 * Annotation value that is an array of annotation elements. 198 * 199 */ 200 public static class Array_AnnotValue extends AnnotValue { 201 202 /** 203 * tag the descriptor for the constant 204 */ 205 public ArrayList<AnnotValue> array = new ArrayList<>(); 206 207 public Array_AnnotValue(AnnotElemType tagval, ClassData cls) { 208 super(tagval, cls); 209 } 210 211 @Override 212 public String stringVal() { 213 StringBuilder sb = new StringBuilder(); 214 sb.append(super.stringVal() + " = "); 215 sb.append("{"); 216 int i = 0; 217 int cnt = array.size(); 218 for (AnnotValue arrayelem : array) { 219 sb.append(arrayelem.toString()); 220 if (i < cnt - 1) { 221 sb.append(","); 222 } 223 } 224 sb.append("}"); 225 return sb.toString(); 226 } 227 228 public void add(AnnotValue elem) { 229 array.add(elem); 230 } 231 232 @Override 233 public void print(PrintWriter out, String tab) { 234 out.println("{"); 235 int i = 0; 236 int cnt = array.size(); 237 for (AnnotValue arrayelem : array) { 238 arrayelem.print(out, tab + " "); 239 if (i < cnt - 1) { 240 out.println(","); 241 } 242 i += 1; 243 } 244 out.println("}"); 245 } 246 247 @Override 248 public String toString() { 249 return "<Array_AnnotValue " + tag + " " + stringVal() + ">"; 250 } 251 } 252 253 /** 254 * 255 * Annot_AnnotValue 256 * 257 * Annotation value that is a reference to an annotation. 258 * 259 */ 260 public static class Annot_AnnotValue extends AnnotValue { 261 262 /** 263 * tag the descriptor for the constant 264 */ 265 AnnotationData annot; 266 267 public Annot_AnnotValue(AnnotElemType tagval, ClassData cls, AnnotationData annot) { 268 super(tagval, cls); 269 this.annot = annot; 270 } 271 272 @Override 273 public String stringVal() { 274 return annot.toString(); 275 } 276 277 @Override 278 public void print(PrintWriter out, String tab) { 279 // out.print(tag + "\t"); 280 annot.print(out, tab); 281 } 282 283 @Override 284 public String toString() { 285 return "<Annot_AnnotValue " + tag + " " + stringVal() + ">"; 286 } 287 } 288 289 /*========================================================*/ 290 /* Factory Method */ 291 /** 292 * 293 * read 294 * 295 * Static factory - creates Annotation Elements. 296 * 297 */ 298 public static AnnotValue readValue(DataInputStream in, ClassData cls, boolean invisible) throws IOException { 299 AnnotValue val = null; 300 char tg = (char) in.readByte(); 301 AnnotElemType tag = annotElemType(tg); 302 303 switch (tag) { 304 case AE_STRING: // String 305 case AE_BYTE: // Byte 306 case AE_CHAR: // Char 307 case AE_INT: // Int (no need to add keyword) 308 case AE_SHORT: // Short 309 case AE_BOOLEAN: // Boolean 310 case AE_FLOAT: // Float 311 case AE_DOUBLE: // Double 312 case AE_LONG: // Long 313 case AE_CLASS: // Class 314 // CPX based Annotation 315 int CPX = in.readShort(); 316 val = new CPX_AnnotValue(tag, cls, CPX); 317 break; 318 case AE_ENUM: // Enum 319 // CPX2 based Annotation 320 int CPX1 = in.readShort(); 321 int CPX2 = in.readShort(); 322 val = new CPX2_AnnotValue(tag, cls, CPX1, CPX2); 323 break; 324 case AE_ANNOTATION: // Annotation 325 AnnotationData ad = new AnnotationData(invisible, cls); 326 ad.read(in); 327 val = new Annot_AnnotValue(tag, cls, ad); 328 break; 329 case AE_ARRAY: // Array 330 Array_AnnotValue aelem = new Array_AnnotValue(tag, cls); 331 val = aelem; 332 int cnt = in.readShort(); 333 for (int i = 0; i < cnt; i++) { 334 aelem.add(readValue(in, cls, invisible)); 335 } 336 break; 337 default: 338 throw new IOException("Unknown tag in annotation '" + tg + "' [" + Integer.toHexString(tg) + "]"); 339 } 340 341 return val; 342 } 343 344 /*========================================================*/ 345 346 /*-------------------------------------------------------- */ 347 /* AnnotElem Fields */ 348 /** 349 * constant pool index for the name of the Annotation Element 350 */ 351 public int name_cpx; 352 353 public AnnotValue value = null; 354 355 // internal references 356 protected ClassData cls; 357 /*-------------------------------------------------------- */ 358 359 public AnnotationElement(ClassData cls) { 360 this.cls = cls; 361 } 362 363 /** 364 * 365 * read 366 * 367 * read and resolve the method data called from ClassData. precondition: NumFields has 368 * already been read from the stream. 369 * 370 */ 371 public void read(DataInputStream in, boolean invisible) throws IOException { 372 name_cpx = in.readShort(); 373 value = readValue(in, cls, invisible); 374 TraceUtils.traceln(format(" AnnotElem: name[%d]=%s value=%s", name_cpx, cls.pool.getString(name_cpx), value.toString())); 375 } 376 377 public String stringVal() { 378 return cls.pool.getName(name_cpx); 379 } 380 381 public void print(PrintWriter out, String tab) { 382 out.print(stringVal() + " = "); 383 value.print(out, ""); 384 } 385 386 @Override 387 public String toString() { 388 return "<AnnotElem " + stringVal() + " = " + value.toString() + ">"; 389 } 390 }