8311102: Write annotations in the classfile dumped by SA

Reviewed-by: cjplummer, stuefe
This commit is contained in:
Ashutosh Mehra 2023-07-13 17:14:30 +00:00 committed by Thomas Stuefe
parent 61932f49a5
commit c710e71178
9 changed files with 421 additions and 18 deletions

View File

@ -41,6 +41,7 @@ typedef Array<u1> AnnotationArray;
// a type_annotation instance.
class Annotations: public MetaspaceObj {
friend class VMStructs;
friend class JVMCIVMStructs;
// If you add a new field that points to any metaspace object, you

View File

@ -325,6 +325,10 @@
nonstatic_field(Symbol, _body[0], u1) \
nonstatic_field(TypeArrayKlass, _max_length, jint) \
nonstatic_field(OopHandle, _obj, oop*) \
nonstatic_field(Annotations, _class_annotations, Array<u1>*) \
nonstatic_field(Annotations, _fields_annotations, Array<Array<u1>*>*) \
nonstatic_field(Annotations, _class_type_annotations, Array<u1>*) \
nonstatic_field(Annotations, _fields_type_annotations, Array<Array<u1>*>*) \
\
/***********************/ \
/* Constant Pool Cache */ \
@ -965,6 +969,7 @@
unchecked_nonstatic_field(Array<Method*>, _data, sizeof(Method*)) \
unchecked_nonstatic_field(Array<Klass*>, _data, sizeof(Klass*)) \
unchecked_nonstatic_field(Array<ResolvedIndyEntry>, _data, sizeof(ResolvedIndyEntry)) \
unchecked_nonstatic_field(Array<Array<u1>*>, _data, sizeof(Array<u1>*)) \
\
/*********************************/ \
/* java_lang_Class fields */ \
@ -1171,6 +1176,7 @@
declare_type(Method, Metadata) \
declare_type(MethodCounters, MetaspaceObj) \
declare_type(ConstMethod, MetaspaceObj) \
declare_type(Annotations, MetaspaceObj) \
\
declare_toplevel_type(MethodData::CompilerCounters) \
\
@ -1894,6 +1900,7 @@
declare_type(Array<Klass*>, MetaspaceObj) \
declare_type(Array<Method*>, MetaspaceObj) \
declare_type(Array<ResolvedIndyEntry>, MetaspaceObj) \
declare_type(Array<Array<u1>*>, MetaspaceObj) \
\
declare_toplevel_type(BitMap) \
declare_type(BitMapView, BitMap) \

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* 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 sun.jvm.hotspot.oops;
import java.io.*;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.interpreter.Bytecodes;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;
import sun.jvm.hotspot.utilities.Observable;
import sun.jvm.hotspot.utilities.Observer;
// An Annotation is an oop containing annotations as described in the class file
public class Annotations extends Metadata {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private ArrayOfU1Array fieldAnnotationsArray;
private ArrayOfU1Array fieldTypeAnnotationsArray;
public Annotations(Address addr) {
super(addr);
}
public boolean isAnnotations() { return true; }
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
Type type = db.lookupType("Annotations");
classAnnotations = type.getAddressField("_class_annotations");
fieldsAnnotations = type.getAddressField("_fields_annotations");
classTypeAnnotations = type.getAddressField("_class_type_annotations");
fieldsTypeAnnotations = type.getAddressField("_fields_type_annotations");
}
private static AddressField classAnnotations;
private static AddressField fieldsAnnotations;
private static AddressField classTypeAnnotations;
private static AddressField fieldsTypeAnnotations;
public U1Array getClassAnnotations() {
Address addr = classAnnotations.getValue(getAddress());
return VMObjectFactory.newObject(U1Array.class, addr);
}
public U1Array getFieldAnnotations(int fieldIndex) {
if (fieldAnnotationsArray == null) {
Address addr = fieldsAnnotations.getValue(getAddress());
fieldAnnotationsArray = VMObjectFactory.newObject(ArrayOfU1Array.class, addr);
}
if (fieldAnnotationsArray != null) {
Address addr = fieldAnnotationsArray.at(fieldIndex);
return VMObjectFactory.newObject(U1Array.class, addr);
} else {
return null;
}
}
public U1Array getClassTypeAnnotations() {
Address addr = classTypeAnnotations.getValue(getAddress());
return VMObjectFactory.newObject(U1Array.class, addr);
}
public U1Array getFieldTypeAnnotations(int fieldIndex) {
if (fieldTypeAnnotationsArray == null) {
Address addr = fieldsTypeAnnotations.getValue(getAddress());
fieldTypeAnnotationsArray = VMObjectFactory.newObject(ArrayOfU1Array.class, addr);
}
if (fieldTypeAnnotationsArray != null) {
Address addr = fieldTypeAnnotationsArray.at(fieldIndex);
return VMObjectFactory.newObject(U1Array.class, addr);
} else {
return null;
}
}
public void printValueOn(PrintStream tty) {
tty.print("Annotations" + "@" + getAddress());
}
}

View File

@ -417,31 +417,42 @@ public class ConstMethod extends Metadata {
return ret;
}
private boolean hasMethodParameters() {
return (getFlags() & HAS_METHOD_PARAMETERS) != 0;
public U1Array getMethodAnnotations() {
if (hasMethodAnnotations()) {
Address addr = getAddressAtOffset(getSize() - getMethodAnnotationsOffset());
return VMObjectFactory.newObject(U1Array.class, addr);
} else {
return null;
}
}
private boolean hasGenericSignature() {
return (getFlags() & HAS_GENERIC_SIGNATURE) != 0;
public U1Array getParameterAnnotations() {
if (hasParameterAnnotations()) {
Address addr = getAddressAtOffset(getSize() - getParameterAnnotationsOffset());
return VMObjectFactory.newObject(U1Array.class, addr);
} else {
return null;
}
}
private boolean hasMethodAnnotations() {
return (getFlags() & HAS_METHOD_ANNOTATIONS) != 0;
public U1Array getTypeAnnotations() {
if (hasTypeAnnotations()) {
Address addr = getAddressAtOffset(getSize() - getTypeAnnotationsOffset());
return VMObjectFactory.newObject(U1Array.class, addr);
} else {
return null;
}
}
private boolean hasParameterAnnotations() {
return (getFlags() & HAS_PARAMETER_ANNOTATIONS) != 0;
public U1Array getDefaultAnnotations() {
if (hasDefaultAnnotations()) {
Address addr = getAddressAtOffset(getSize() - getDefaultAnnotationsOffset());
return VMObjectFactory.newObject(U1Array.class, addr);
} else {
return null;
}
}
private boolean hasDefaultAnnotations() {
return (getFlags() & HAS_DEFAULT_ANNOTATIONS) != 0;
}
private boolean hasTypeAnnotations() {
return (getFlags() & HAS_TYPE_ANNOTATIONS) != 0;
}
//---------------------------------------------------------------------------
// Internals only below this point
//
@ -610,4 +621,70 @@ public class ConstMethod extends Metadata {
return offset;
}
private boolean hasMethodParameters() {
return (getFlags() & HAS_METHOD_PARAMETERS) != 0;
}
private boolean hasGenericSignature() {
return (getFlags() & HAS_GENERIC_SIGNATURE) != 0;
}
private Address getAddressAtOffset(long offsetInWords) {
return getAddress().getAddressAt(offsetInWords * VM.getVM().getAddressSize());
}
// Pointers to annotations are stored towards the end of the ConstMethod in following format.
// Each of the pointer may or may not be present.
//
// |<-------------- getSize() -----------------|
// start of ConstMethod end of ConstMethod
// | |
// V V
// | ... | default | type | parameter | method |
//
// These methods return the offset of the pointer to the requested annotation from the end of ConstMethod.
private int getMethodAnnotationsOffset() {
return 1;
}
private int getParameterAnnotationsOffset() {
int offset = 1;
if (hasMethodAnnotations()) {
offset += getMethodAnnotationsOffset();
}
return offset;
}
private int getTypeAnnotationsOffset() {
int offset = 1;
if (hasParameterAnnotations()) {
offset += getParameterAnnotationsOffset();
}
return offset;
}
private int getDefaultAnnotationsOffset() {
int offset = 1;
if (hasTypeAnnotations()) {
offset += getTypeAnnotationsOffset();
}
return offset;
}
private boolean hasMethodAnnotations() {
return (getFlags() & HAS_METHOD_ANNOTATIONS) != 0;
}
private boolean hasParameterAnnotations() {
return (getFlags() & HAS_PARAMETER_ANNOTATIONS) != 0;
}
private boolean hasTypeAnnotations() {
return (getFlags() & HAS_TYPE_ANNOTATIONS) != 0;
}
private boolean hasDefaultAnnotations() {
return (getFlags() & HAS_DEFAULT_ANNOTATIONS) != 0;
}
}

View File

@ -66,6 +66,7 @@ public class InstanceKlass extends Klass {
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
Type type = db.lookupType("InstanceKlass");
annotations = type.getAddressField("_annotations");
arrayKlasses = new MetadataField(type.getAddressField("_array_klasses"), 0);
methods = type.getAddressField("_methods");
defaultMethods = type.getAddressField("_default_methods");
@ -130,6 +131,7 @@ public class InstanceKlass extends Klass {
}
}
private static AddressField annotations;
private static MetadataField arrayKlasses;
private static AddressField methods;
private static AddressField defaultMethods;
@ -375,7 +377,6 @@ public class InstanceKlass extends Klass {
public long majorVersion() { return getConstants().majorVersion(); }
public long minorVersion() { return getConstants().minorVersion(); }
public Symbol getGenericSignature() { return getConstants().getGenericSignature(); }
// "size helper" == instance size in words
public long getSizeHelper() {
int lh = getLayoutHelper();
@ -384,6 +385,10 @@ public class InstanceKlass extends Klass {
}
return lh / VM.getVM().getAddressSize();
}
public Annotations getAnnotations() {
Address addr = annotations.getValue(getAddress());
return VMObjectFactory.newObject(Annotations.class, addr);
}
// same as enum InnerClassAttributeOffset in VM code.
private static class InnerClassAttributeOffset {
@ -859,6 +864,42 @@ public class InstanceKlass extends Klass {
return VMObjectFactory.newObject(U2Array.class, addr);
}
public U1Array getClassAnnotations() {
Annotations annotations = getAnnotations();
if (annotations != null) {
return annotations.getClassAnnotations();
} else {
return null;
}
}
public U1Array getClassTypeAnnotations() {
Annotations annotations = getAnnotations();
if (annotations != null) {
return annotations.getClassTypeAnnotations();
} else {
return null;
}
}
public U1Array getFieldAnnotations(int fieldIndex) {
Annotations annotations = getAnnotations();
if (annotations != null) {
return annotations.getFieldAnnotations(fieldIndex);
} else {
return null;
}
}
public U1Array getFieldTypeAnnotations(int fieldIndex) {
Annotations annotations = getAnnotations();
if (annotations != null) {
return annotations.getFieldTypeAnnotations(fieldIndex);
} else {
return null;
}
}
//----------------------------------------------------------------------
// Internals only below this point
//

View File

@ -71,6 +71,7 @@ public abstract class Metadata extends VMObject {
metadataConstructor.addMapping("ConstMethod", ConstMethod.class);
metadataConstructor.addMapping("ConstantPool", ConstantPool.class);
metadataConstructor.addMapping("ConstantPoolCache", ConstantPoolCache.class);
metadataConstructor.addMapping("Annotations", Annotations.class);
}
public static Metadata instantiateWrapperFor(Address addr) {

View File

@ -40,6 +40,7 @@ import sun.jvm.hotspot.types.Type;
import sun.jvm.hotspot.types.TypeDataBase;
import sun.jvm.hotspot.types.WrongTypeException;
import sun.jvm.hotspot.utilities.Assert;
import sun.jvm.hotspot.utilities.U1Array;
// A Method represents a Java method
@ -376,4 +377,20 @@ public class Method extends Metadata {
OopUtilities.escapeString(getName().asString()) + " " +
getSignature().asString();
}
public U1Array getAnnotations() {
return getConstMethod().getMethodAnnotations();
}
public U1Array getParameterAnnotations() {
return getConstMethod().getParameterAnnotations();
}
public U1Array getTypeAnnotations() {
return getConstMethod().getTypeAnnotations();
}
public U1Array getAnnotationDefault() {
return getConstMethod().getDefaultAnnotations();
}
}

View File

@ -406,6 +406,16 @@ public class ClassWriter implements /* imports */ ClassConstants
if (genSigIndex != 0)
fieldAttributeCount++;
U1Array fieldAnnotations = klass.getFieldAnnotations(index);
if (fieldAnnotations != null) {
fieldAttributeCount++;
}
U1Array fieldTypeAnnotations = klass.getFieldTypeAnnotations(index);
if (fieldTypeAnnotations != null) {
fieldAttributeCount++;
}
dos.writeShort(fieldAttributeCount);
// write synthetic, if applicable
@ -425,6 +435,14 @@ public class ClassWriter implements /* imports */ ClassConstants
dos.writeShort(genSigIndex);
if (DEBUG) debugMessage("\tfield generic signature index " + genSigIndex);
}
if (fieldAnnotations != null) {
writeAnnotationAttribute("RuntimeVisibleAnnotations", fieldAnnotations);
}
if (fieldTypeAnnotations != null) {
writeAnnotationAttribute("RuntimeVisibleTypeAnnotations", fieldTypeAnnotations);
}
}
}
@ -492,6 +510,26 @@ public class ClassWriter implements /* imports */ ClassConstants
if (isGeneric)
methodAttributeCount++;
final U1Array annotations = m.getAnnotations();
if (annotations != null) {
methodAttributeCount++;
}
final U1Array parameterAnnotations = m.getParameterAnnotations();
if (parameterAnnotations != null) {
methodAttributeCount++;
}
final U1Array typeAnnotations = m.getTypeAnnotations();
if (typeAnnotations != null) {
methodAttributeCount++;
}
final U1Array annotationDefault = m.getAnnotationDefault();
if (annotationDefault != null) {
methodAttributeCount++;
}
dos.writeShort(methodAttributeCount);
if (DEBUG) debugMessage("\tmethod attribute count = " + methodAttributeCount);
@ -687,6 +725,22 @@ public class ClassWriter implements /* imports */ ClassConstants
if (isGeneric) {
writeGenericSignature(m.getGenericSignature().asString());
}
if (annotationDefault != null) {
writeAnnotationAttribute("AnnotationDefault", annotationDefault);
}
if (annotations != null) {
writeAnnotationAttribute("RuntimeVisibleAnnotations", annotations);
}
if (parameterAnnotations != null) {
writeAnnotationAttribute("RuntimeVisibleParameterAnnotations", parameterAnnotations);
}
if (typeAnnotations != null) {
writeAnnotationAttribute("RuntimeVisibleTypeAnnotations", typeAnnotations);
}
}
protected void rewriteByteCode(Method m, byte[] code) {
@ -731,6 +785,16 @@ public class ClassWriter implements /* imports */ ClassConstants
classAttributeCount++;
}
U1Array classAnnotations = klass.getClassAnnotations();
if (classAnnotations != null) {
classAttributeCount++;
}
U1Array classTypeAnnotations = klass.getClassTypeAnnotations();
if (classTypeAnnotations != null) {
classAttributeCount++;
}
dos.writeShort(classAttributeCount);
if (DEBUG) debugMessage("class attribute count = " + classAttributeCount);
@ -792,5 +856,26 @@ public class ClassWriter implements /* imports */ ClassConstants
}
}
}
if (classAnnotations != null) {
writeAnnotationAttribute("RuntimeVisibleAnnotations", classAnnotations);
}
if (classTypeAnnotations != null) {
writeAnnotationAttribute("RuntimeVisibleTypeAnnotations", classTypeAnnotations);
}
}
protected void writeAnnotationAttribute(String annotationName, U1Array annotation) throws IOException {
int length = annotation.length();
Short annotationNameIndex = utf8ToIndex.get(annotationName);
if (Assert.ASSERTS_ENABLED) {
Assert.that(annotationNameIndex != null, "should not be null");
}
writeIndex(annotationNameIndex.shortValue());
dos.writeInt(length);
for (int index = 0; index < length; index++) {
dos.writeByte(annotation.at(index));
}
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* 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 sun.jvm.hotspot.utilities;
import sun.jvm.hotspot.debugger.Address;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.types.Type;
import sun.jvm.hotspot.types.TypeDataBase;
import sun.jvm.hotspot.types.WrongTypeException;
import sun.jvm.hotspot.utilities.Observable;
import sun.jvm.hotspot.utilities.Observer;
public class ArrayOfU1Array extends GenericArray {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
elemType = db.lookupType("Array<u1>*");
Type type = db.lookupType("Array<Array<u1>*>");
dataFieldOffset = type.getAddressField("_data").getOffset();
}
private static long dataFieldOffset;
protected static Type elemType;
public ArrayOfU1Array(Address addr) {
super(addr, dataFieldOffset);
}
public Address at(int i) {
return getAddressAt(i);
}
public Type getElemType() {
return elemType;
}
}