From c710e711780b3c334fdb9e1299b3c39a2b48649e Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Thu, 13 Jul 2023 17:14:30 +0000 Subject: [PATCH] 8311102: Write annotations in the classfile dumped by SA Reviewed-by: cjplummer, stuefe --- src/hotspot/share/oops/annotations.hpp | 1 + src/hotspot/share/runtime/vmStructs.cpp | 7 ++ .../sun/jvm/hotspot/oops/Annotations.java | 109 +++++++++++++++++ .../sun/jvm/hotspot/oops/ConstMethod.java | 111 +++++++++++++++--- .../sun/jvm/hotspot/oops/InstanceKlass.java | 43 ++++++- .../sun/jvm/hotspot/oops/Metadata.java | 1 + .../classes/sun/jvm/hotspot/oops/Method.java | 17 +++ .../jvm/hotspot/tools/jcore/ClassWriter.java | 85 ++++++++++++++ .../jvm/hotspot/utilities/ArrayOfU1Array.java | 65 ++++++++++ 9 files changed, 421 insertions(+), 18 deletions(-) create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotations.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ArrayOfU1Array.java diff --git a/src/hotspot/share/oops/annotations.hpp b/src/hotspot/share/oops/annotations.hpp index c7919ff0ff9..0260de2d8d4 100644 --- a/src/hotspot/share/oops/annotations.hpp +++ b/src/hotspot/share/oops/annotations.hpp @@ -41,6 +41,7 @@ typedef Array 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 diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index dd7ed0e8a42..0dd92c8b436 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -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*) \ + nonstatic_field(Annotations, _fields_annotations, Array*>*) \ + nonstatic_field(Annotations, _class_type_annotations, Array*) \ + nonstatic_field(Annotations, _fields_type_annotations, Array*>*) \ \ /***********************/ \ /* Constant Pool Cache */ \ @@ -965,6 +969,7 @@ unchecked_nonstatic_field(Array, _data, sizeof(Method*)) \ unchecked_nonstatic_field(Array, _data, sizeof(Klass*)) \ unchecked_nonstatic_field(Array, _data, sizeof(ResolvedIndyEntry)) \ + unchecked_nonstatic_field(Array*>, _data, sizeof(Array*)) \ \ /*********************************/ \ /* 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, MetaspaceObj) \ declare_type(Array, MetaspaceObj) \ declare_type(Array, MetaspaceObj) \ + declare_type(Array*>, MetaspaceObj) \ \ declare_toplevel_type(BitMap) \ declare_type(BitMapView, BitMap) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotations.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotations.java new file mode 100644 index 00000000000..cdc755362bf --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotations.java @@ -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()); + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstMethod.java index 9933d57efc4..4bd2c9d3cbd 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstMethod.java @@ -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; + } + } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index 06eac193933..fba4f890dca 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -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 // diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java index e84542bfcf6..ece6bf157b7 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java @@ -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) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Method.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Method.java index 1786f7c7029..ca7329ad6c9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Method.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Method.java @@ -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(); + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java index 5dfa7eec30a..6b05bd836db 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java @@ -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)); + } } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ArrayOfU1Array.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ArrayOfU1Array.java new file mode 100644 index 00000000000..f3b817b9fb7 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ArrayOfU1Array.java @@ -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*"); + + Type type = db.lookupType("Array*>"); + 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; + } +}