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 }