2014-12-18 21:56:02 +00:00
|
|
|
/*
|
2020-04-02 23:02:32 +00:00
|
|
|
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
|
2014-12-18 21:56:02 +00:00
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
|
*
|
|
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
|
|
* accompanied this code).
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License version
|
|
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*
|
|
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
|
|
* questions.
|
|
|
|
*/
|
|
|
|
package org.openjdk.asmtools.jdis;
|
|
|
|
|
2020-04-02 23:02:32 +00:00
|
|
|
import static java.lang.String.format;
|
2014-12-18 21:56:02 +00:00
|
|
|
import static org.openjdk.asmtools.jasm.Tables.*;
|
|
|
|
import java.io.DataInputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.PrintWriter;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Base class of all AnnotationElement entries
|
|
|
|
*/
|
2020-04-02 23:02:32 +00:00
|
|
|
public class AnnotationElement {
|
2014-12-18 21:56:02 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* CPX_AnnotElem
|
|
|
|
*
|
|
|
|
* base class for an annotation value.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static class AnnotValue {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* tag the descriptor for the constant
|
|
|
|
*/
|
|
|
|
public AnnotElemType tag;
|
|
|
|
|
|
|
|
// internal references
|
|
|
|
protected ClassData cls;
|
|
|
|
|
|
|
|
public AnnotValue(AnnotElemType tagval, ClassData cls) {
|
|
|
|
tag = tagval;
|
|
|
|
this.cls = cls;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String stringVal() {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
public void print(PrintWriter out, String tab) {
|
2020-04-02 23:02:32 +00:00
|
|
|
out.print(tag.val() + " ");
|
2014-12-18 21:56:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "<AnnotValue " + tag.printval() + " " + stringVal() + ">";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* CPX_AnnotElem
|
|
|
|
*
|
|
|
|
* Annotation value which is described by a single CPX entry (ie. String, byte, char,
|
|
|
|
* int, short, boolean, float, long, double, class reference).
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static class CPX_AnnotValue extends AnnotValue {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* tag the descriptor for the constant
|
|
|
|
*/
|
|
|
|
public int cpx;
|
|
|
|
|
|
|
|
public CPX_AnnotValue(AnnotElemType tag, ClassData cls, int cpx) {
|
|
|
|
super(tag, cls);
|
|
|
|
this.cpx = cpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String stringVal() {
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
switch (tag) {
|
|
|
|
case AE_STRING: // String
|
|
|
|
sb.append('"' + cls.pool.getString(cpx) + '"');
|
|
|
|
break;
|
|
|
|
case AE_BYTE: // Byte
|
|
|
|
sb.append("byte " + cls.pool.getConst(cpx).stringVal());
|
|
|
|
break;
|
|
|
|
case AE_CHAR: // Char
|
|
|
|
sb.append("char " + cls.pool.getConst(cpx).stringVal());
|
|
|
|
break;
|
|
|
|
case AE_INT: // Int (no need to add keyword)
|
|
|
|
sb.append(cls.pool.getConst(cpx).stringVal());
|
|
|
|
break;
|
|
|
|
case AE_SHORT: // Short
|
|
|
|
sb.append("short " + cls.pool.getConst(cpx).stringVal());
|
|
|
|
break;
|
|
|
|
case AE_BOOLEAN: // Boolean
|
|
|
|
ConstantPool.CP_Int cns = (ConstantPool.CP_Int) cls.pool.getConst(cpx);
|
|
|
|
sb.append("boolean " + (cns.value == 0 ? "false" : "true"));
|
|
|
|
break;
|
|
|
|
case AE_FLOAT: // Float
|
|
|
|
sb.append(cls.pool.getConst(cpx).stringVal()); // + "f");
|
|
|
|
break;
|
|
|
|
case AE_DOUBLE: // Double
|
|
|
|
sb.append(cls.pool.getConst(cpx).stringVal()); // + "d");
|
|
|
|
break;
|
|
|
|
case AE_LONG: // Long
|
|
|
|
sb.append(cls.pool.getConst(cpx).stringVal()); // + "l");
|
|
|
|
break;
|
|
|
|
case AE_CLASS: // Class
|
|
|
|
sb.append("class " + cls.pool.decodeClassDescriptor(cpx));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return sb.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void print(PrintWriter out, String tab) {
|
|
|
|
out.print(tab + stringVal());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "<CPX_AnnotValue tag: '" + tag + "' stringVal=" + this.stringVal() + ">";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* CPX_AnnotElem
|
|
|
|
*
|
|
|
|
* AnnotElements that contain 2 cpx indices (ie. enums).
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static class CPX2_AnnotValue extends AnnotValue {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* tag the descriptor for the constant
|
|
|
|
*/
|
|
|
|
public int cpx1;
|
|
|
|
public int cpx2;
|
|
|
|
|
|
|
|
public CPX2_AnnotValue(AnnotElemType tag, ClassData cls, int cpx1, int cpx2) {
|
|
|
|
super(tag, cls);
|
|
|
|
this.cpx1 = cpx1;
|
|
|
|
this.cpx2 = cpx2;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String stringVal() {
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
switch (tag) {
|
|
|
|
|
|
|
|
case AE_ENUM: // Enum
|
|
|
|
// print the enum type and constant name
|
|
|
|
sb.append("enum " + cls.pool.decodeClassDescriptor(cpx1)
|
|
|
|
+ " " + cls.pool.getName(cpx2));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return sb.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void print(PrintWriter out, String tab) {
|
|
|
|
out.print(tab + stringVal());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "<CPX2_AnnotValue tag: '" + tag + "' stringVal=" + this.stringVal() + ">";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Array_AnnotElem
|
|
|
|
*
|
|
|
|
* Annotation value that is an array of annotation elements.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static class Array_AnnotValue extends AnnotValue {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* tag the descriptor for the constant
|
|
|
|
*/
|
|
|
|
public ArrayList<AnnotValue> array = new ArrayList<>();
|
|
|
|
|
|
|
|
public Array_AnnotValue(AnnotElemType tagval, ClassData cls) {
|
|
|
|
super(tagval, cls);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String stringVal() {
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
sb.append(super.stringVal() + " = ");
|
|
|
|
sb.append("{");
|
|
|
|
int i = 0;
|
|
|
|
int cnt = array.size();
|
|
|
|
for (AnnotValue arrayelem : array) {
|
|
|
|
sb.append(arrayelem.toString());
|
|
|
|
if (i < cnt - 1) {
|
|
|
|
sb.append(",");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sb.append("}");
|
|
|
|
return sb.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void add(AnnotValue elem) {
|
|
|
|
array.add(elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void print(PrintWriter out, String tab) {
|
|
|
|
out.println("{");
|
|
|
|
int i = 0;
|
|
|
|
int cnt = array.size();
|
|
|
|
for (AnnotValue arrayelem : array) {
|
|
|
|
arrayelem.print(out, tab + " ");
|
|
|
|
if (i < cnt - 1) {
|
|
|
|
out.println(",");
|
|
|
|
}
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
out.println("}");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "<Array_AnnotValue " + tag + " " + stringVal() + ">";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Annot_AnnotValue
|
|
|
|
*
|
|
|
|
* Annotation value that is a reference to an annotation.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static class Annot_AnnotValue extends AnnotValue {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* tag the descriptor for the constant
|
|
|
|
*/
|
|
|
|
AnnotationData annot;
|
|
|
|
|
|
|
|
public Annot_AnnotValue(AnnotElemType tagval, ClassData cls, AnnotationData annot) {
|
|
|
|
super(tagval, cls);
|
|
|
|
this.annot = annot;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String stringVal() {
|
|
|
|
return annot.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void print(PrintWriter out, String tab) {
|
|
|
|
// out.print(tag + "\t");
|
|
|
|
annot.print(out, tab);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "<Annot_AnnotValue " + tag + " " + stringVal() + ">";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*========================================================*/
|
|
|
|
/* Factory Method */
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* read
|
|
|
|
*
|
|
|
|
* Static factory - creates Annotation Elements.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static AnnotValue readValue(DataInputStream in, ClassData cls, boolean invisible) throws IOException {
|
|
|
|
AnnotValue val = null;
|
|
|
|
char tg = (char) in.readByte();
|
|
|
|
AnnotElemType tag = annotElemType(tg);
|
|
|
|
|
|
|
|
switch (tag) {
|
|
|
|
case AE_STRING: // String
|
|
|
|
case AE_BYTE: // Byte
|
|
|
|
case AE_CHAR: // Char
|
|
|
|
case AE_INT: // Int (no need to add keyword)
|
|
|
|
case AE_SHORT: // Short
|
|
|
|
case AE_BOOLEAN: // Boolean
|
|
|
|
case AE_FLOAT: // Float
|
|
|
|
case AE_DOUBLE: // Double
|
|
|
|
case AE_LONG: // Long
|
|
|
|
case AE_CLASS: // Class
|
|
|
|
// CPX based Annotation
|
|
|
|
int CPX = in.readShort();
|
|
|
|
val = new CPX_AnnotValue(tag, cls, CPX);
|
|
|
|
break;
|
|
|
|
case AE_ENUM: // Enum
|
|
|
|
// CPX2 based Annotation
|
|
|
|
int CPX1 = in.readShort();
|
|
|
|
int CPX2 = in.readShort();
|
|
|
|
val = new CPX2_AnnotValue(tag, cls, CPX1, CPX2);
|
|
|
|
break;
|
|
|
|
case AE_ANNOTATION: // Annotation
|
|
|
|
AnnotationData ad = new AnnotationData(invisible, cls);
|
|
|
|
ad.read(in);
|
|
|
|
val = new Annot_AnnotValue(tag, cls, ad);
|
|
|
|
break;
|
|
|
|
case AE_ARRAY: // Array
|
|
|
|
Array_AnnotValue aelem = new Array_AnnotValue(tag, cls);
|
|
|
|
val = aelem;
|
|
|
|
int cnt = in.readShort();
|
|
|
|
for (int i = 0; i < cnt; i++) {
|
|
|
|
aelem.add(readValue(in, cls, invisible));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new IOException("Unknown tag in annotation '" + tg + "' [" + Integer.toHexString(tg) + "]");
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*========================================================*/
|
|
|
|
|
|
|
|
/*-------------------------------------------------------- */
|
|
|
|
/* AnnotElem Fields */
|
|
|
|
/**
|
|
|
|
* constant pool index for the name of the Annotation Element
|
|
|
|
*/
|
|
|
|
public int name_cpx;
|
|
|
|
|
|
|
|
public AnnotValue value = null;
|
|
|
|
|
|
|
|
// internal references
|
|
|
|
protected ClassData cls;
|
|
|
|
/*-------------------------------------------------------- */
|
|
|
|
|
2020-04-02 23:02:32 +00:00
|
|
|
public AnnotationElement(ClassData cls) {
|
2014-12-18 21:56:02 +00:00
|
|
|
this.cls = cls;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* read
|
|
|
|
*
|
|
|
|
* read and resolve the method data called from ClassData. precondition: NumFields has
|
|
|
|
* already been read from the stream.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public void read(DataInputStream in, boolean invisible) throws IOException {
|
|
|
|
name_cpx = in.readShort();
|
|
|
|
value = readValue(in, cls, invisible);
|
2020-04-02 23:02:32 +00:00
|
|
|
TraceUtils.traceln(format(" AnnotElem: name[%d]=%s value=%s", name_cpx, cls.pool.getString(name_cpx), value.toString()));
|
2014-12-18 21:56:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public String stringVal() {
|
|
|
|
return cls.pool.getName(name_cpx);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void print(PrintWriter out, String tab) {
|
|
|
|
out.print(stringVal() + " = ");
|
2020-04-02 23:02:32 +00:00
|
|
|
value.print(out, "");
|
2014-12-18 21:56:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "<AnnotElem " + stringVal() + " = " + value.toString() + ">";
|
|
|
|
}
|
|
|
|
}
|