From ea46d61d4ef8d519b3281b2ce32ae8f0df9c9d9b Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Mon, 21 Jul 2025 15:42:37 +0200 Subject: [PATCH 01/20] add support for lazily clinit of enum classes used in annotations --- .../classes/java/lang/reflect/Method.java | 22 ++-- .../java/lang/reflect/ReflectAccess.java | 4 + .../access/JavaLangReflectAccess.java | 3 + .../classes/jdk/internal/vm/VMSupport.java | 56 +++++++-- .../AnnotationInvocationHandler.java | 2 +- .../reflect/annotation/AnnotationParser.java | 101 +++++++++++----- .../reflect/annotation/AnnotationType.java | 15 ++- .../sun/reflect/annotation/EnumValue.java | 98 +++++++++++++++ .../reflect/annotation/EnumValueArray.java | 112 ++++++++++++++++++ .../reflect/annotation/ResolvableValue.java | 58 +++++++++ .../annotation/TypeAnnotationParser.java | 2 +- .../vm/ci/hotspot/AnnotationDataDecoder.java | 31 ++--- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 8 +- .../HotSpotResolvedJavaMethodImpl.java | 8 +- .../HotSpotResolvedObjectTypeImpl.java | 8 +- .../hotspot/HotSpotResolvedPrimitiveType.java | 4 +- .../classes/jdk/vm/ci/meta/Annotated.java | 23 ++-- .../jdk/vm/ci/meta/AnnotationData.java | 46 ++++--- .../classes/jdk/vm/ci/meta/EnumArrayData.java | 62 ++++++++++ .../classes/jdk/vm/ci/meta/EnumData.java | 32 ++--- .../jdk/vm/ci/meta/UnresolvedJavaType.java | 6 +- .../runtime/test/TestResolvedJavaMethod.java | 8 +- .../ci/runtime/test/TestResolvedJavaType.java | 51 ++++---- .../TestAnnotationEncodingDecoding.java | 85 ++++++++----- 24 files changed, 646 insertions(+), 199 deletions(-) create mode 100644 src/java.base/share/classes/sun/reflect/annotation/EnumValue.java create mode 100644 src/java.base/share/classes/sun/reflect/annotation/EnumValueArray.java create mode 100644 src/java.base/share/classes/sun/reflect/annotation/ResolvableValue.java create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumArrayData.java diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java index 07616206075e7..dae3e729e5209 100644 --- a/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/src/java.base/share/classes/java/lang/reflect/Method.java @@ -43,6 +43,8 @@ import sun.reflect.generics.scope.MethodScope; import sun.reflect.annotation.AnnotationType; import sun.reflect.annotation.AnnotationParser; +import sun.reflect.annotation.EnumValue; +import sun.reflect.annotation.EnumValueArray; import java.lang.annotation.Annotation; import java.lang.annotation.AnnotationFormatError; import java.nio.ByteBuffer; @@ -197,6 +199,10 @@ byte[] getAnnotationBytes() { return annotations; } + byte[] getAnnotationDefaultBytes() { + return annotationDefault; + } + /** * Returns the {@code Class} object representing the class or interface * that declares the method represented by this object. @@ -750,22 +756,10 @@ void setMethodAccessor(MethodAccessor accessor) { * @jls 9.6.2 Defaults for Annotation Interface Elements */ public Object getDefaultValue() { - if (annotationDefault == null) + if (annotationDefault == null) { return null; - Class memberType = AnnotationType.invocationHandlerReturnType( - getReturnType()); - Object result = AnnotationParser.parseMemberValue( - memberType, ByteBuffer.wrap(annotationDefault), - SharedSecrets.getJavaLangAccess(). - getConstantPool(getDeclaringClass()), - getDeclaringClass()); - if (result instanceof ExceptionProxy) { - if (result instanceof TypeNotPresentExceptionProxy proxy) { - throw new TypeNotPresentException(proxy.typeName(), proxy.getCause()); - } - throw new AnnotationFormatError("Invalid default: " + this); } - return result; + return AnnotationParser.parseAnnotationDefault(this, annotationDefault, true); } /** diff --git a/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java b/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java index 835ffef616efd..5a65e7698b553 100644 --- a/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java +++ b/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java @@ -48,6 +48,10 @@ public Class[] getExecutableSharedExceptionTypes(Executable ex) { return ex.getSharedExceptionTypes(); } + public byte[] getAnnotationDefaultBytes(Method arg) { + return arg.getAnnotationDefaultBytes(); + } + // // Copying routines, needed to quickly fabricate new Field, // Method, and Constructor objects from templates diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java index d0c415d2dc61b..ddacb1eeefe07 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java @@ -46,6 +46,9 @@ public interface JavaLangReflectAccess { /** Gets the shared array of exception types of an Executable. */ public Class[] getExecutableSharedExceptionTypes(Executable ex); + /** Gets the value of Method.defaultAnnotation */ + public byte[] getAnnotationDefaultBytes(Method arg); + // Copying routines, needed to quickly fabricate new Field, // Method, and Constructor objects from templates diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index 197da0d456c4b..cb2f789e5f7a7 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -48,6 +48,9 @@ import java.util.Set; import java.util.List; +import sun.reflect.annotation.EnumValue; +import sun.reflect.annotation.EnumValueArray; + /* * Support class used by JVMCI, JVMTI and VM attach mechanism. */ @@ -200,7 +203,7 @@ public static byte[] encodeAnnotations(byte[] rawAnnotations, } } Map, Annotation> annotations = - AnnotationParser.parseSelectAnnotations(rawAnnotations, cp, declaringClass, selectAnnotationClasses); + AnnotationParser.parseSelectAnnotations(rawAnnotations, cp, declaringClass, false, selectAnnotationClasses); if (forClass && annotations.size() != selectAnnotationClasses.length) { Class superClass = declaringClass.getSuperclass(); nextSuperClass: @@ -211,6 +214,7 @@ public static byte[] encodeAnnotations(byte[] rawAnnotations, jla.getRawClassAnnotations(superClass), jla.getConstantPool(superClass), superClass, + false, selectAnnotationClasses); for (Map.Entry, Annotation> e : superAnnotations.entrySet()) { @@ -295,6 +299,21 @@ private static void encodeAnnotation(DataOutputStream dos, Annotation a) throws } else if (valueType == Class.class) { dos.writeByte('c'); dos.writeUTF(((Class) value).getName()); + } else if (valueType == EnumValue.class) { + EnumValue enumValue = (EnumValue) value; + dos.writeByte('e'); + dos.writeUTF(enumValue.enumType.getName()); + dos.writeUTF(enumValue.constName); + } else if (valueType == EnumValueArray.class) { + EnumValueArray enumValueArray = (EnumValueArray) value; + List array = enumValueArray.constNames; + dos.writeByte('['); + dos.writeByte('e'); + dos.writeUTF(enumValueArray.enumType.getName()); + writeLength(dos, array.size()); + for (String s : array) { + dos.writeUTF(s); + } } else if (valueType.isEnum()) { dos.writeByte('e'); dos.writeUTF(valueType.getName()); @@ -418,9 +437,10 @@ private static void encodeAnnotation(DataOutputStream dos, Annotation a) throws * @param type to which a type name is {@linkplain #resolveType(String) resolved} * @param type of the object representing a decoded annotation * @param type of the object representing a decoded enum constant + * @param type of the object representing a decoded array of enum constants * @param type of the object representing a decoded error */ - public interface AnnotationDecoder { + public interface AnnotationDecoder { /** * Resolves a name in {@link Class#getName()} format to an object of type {@code T}. */ @@ -442,6 +462,14 @@ public interface AnnotationDecoder { */ E newEnumValue(T enumType, String name); + /** + * Creates an object representing a decoded enum constant. + * + * @param enumType the enum type + * @param name the name of the enum constant + */ + EA newEnumValueArray(T enumType, List names); + /** * Creates an object representing a decoded error value. * @@ -460,7 +488,7 @@ public interface AnnotationDecoder { * @return an immutable list of {@code A} objects */ @SuppressWarnings("unchecked") - public static List decodeAnnotations(byte[] encoded, AnnotationDecoder decoder) { + public static List decodeAnnotations(byte[] encoded, AnnotationDecoder decoder) { try { ByteArrayInputStream bais = new ByteArrayInputStream(encoded); DataInputStream dis = new DataInputStream(bais); @@ -471,7 +499,7 @@ public static List decodeAnnotations(byte[] encoded, AnnotationD } @SuppressWarnings({"rawtypes", "unchecked"}) - private static A decodeAnnotation(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + private static A decodeAnnotation(DataInputStream dis, AnnotationDecoder decoder) throws IOException { String typeName = dis.readUTF(); T type = decoder.resolveType(typeName); int n = readLength(dis); @@ -504,7 +532,7 @@ interface IOReader { Object read() throws IOException; } - private static Object decodeArray(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + private static Object decodeArray(DataInputStream dis, AnnotationDecoder decoder) throws IOException { byte componentTag = dis.readByte(); return switch (componentTag) { case 'B' -> readArray(dis, dis::readByte); @@ -519,7 +547,7 @@ private static Object decodeArray(DataInputStream dis, AnnotationDe case 'c' -> readArray(dis, () -> readClass(dis, decoder)); case 'e' -> { T enumType = decoder.resolveType(dis.readUTF()); - yield readArray(dis, () -> readEnum(dis, decoder, enumType)); + yield readEnumArray(dis, decoder, enumType); } case '@' -> readArray(dis, () -> decodeAnnotation(dis, decoder)); default -> throw new InternalError("Unsupported component tag: " + componentTag); @@ -530,15 +558,25 @@ private static Object decodeArray(DataInputStream dis, AnnotationDe * Reads an enum encoded at the current read position of {@code dis} and * returns it as an object of type {@code E}. */ - private static E readEnum(DataInputStream dis, AnnotationDecoder decoder, T enumType) throws IOException { + private static E readEnum(DataInputStream dis, AnnotationDecoder decoder, T enumType) throws IOException { return decoder.newEnumValue(enumType, dis.readUTF()); } + /** + * Reads an enum encoded at the current read position of {@code dis} and + * returns it as an object of type {@code E}. + */ + @SuppressWarnings("unchecked") + private static EA readEnumArray(DataInputStream dis, AnnotationDecoder decoder, T enumType) throws IOException { + List names = (List) readArray(dis, dis::readUTF); + return decoder.newEnumValueArray(enumType, names); + } + /** * Reads a class encoded at the current read position of {@code dis} and * returns it as an object of type {@code T}. */ - private static T readClass(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + private static T readClass(DataInputStream dis, AnnotationDecoder decoder) throws IOException { return decoder.resolveType(dis.readUTF()); } @@ -549,7 +587,7 @@ private static T readClass(DataInputStream dis, AnnotationDecoder readArray(DataInputStream dis, IOReader reader) throws IOException { + private static List readArray(DataInputStream dis, IOReader reader) throws IOException { Object[] array = new Object[readLength(dis)]; for (int i = 0; i < array.length; i++) { array[i] = reader.read(); diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java index fcee641458e62..d61b1d8923d4d 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java @@ -78,7 +78,7 @@ public Object invoke(Object proxy, Method method, Object[] args) { } // Handle annotation member accessors - Object result = memberValues.get(member); + Object result = ResolvableValue.resolved(memberValues.get(member)); if (result == null) throw new IncompleteAnnotationException(type, member); diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java index 82751e3fcd293..9567c1d099c5b 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java @@ -33,6 +33,7 @@ import java.util.function.Supplier; import jdk.internal.reflect.ConstantPool; +import jdk.internal.access.SharedSecrets; import sun.reflect.generics.parser.SignatureParser; import sun.reflect.generics.tree.TypeSignature; @@ -69,7 +70,7 @@ public static Map, Annotation> parseAnnotations( return Collections.emptyMap(); try { - return parseAnnotations2(rawAnnotations, constPool, container, null); + return parseAnnotations2(rawAnnotations, constPool, container, true, null); } catch(BufferUnderflowException e) { throw new AnnotationFormatError("Unexpected end of annotations."); } catch(IllegalArgumentException e) { @@ -93,12 +94,13 @@ public static Map, Annotation> parseSelectAnnotation byte[] rawAnnotations, ConstantPool constPool, Class container, + boolean eagerResolution, Class ... selectAnnotationClasses) { if (rawAnnotations == null) return Collections.emptyMap(); try { - return parseAnnotations2(rawAnnotations, constPool, container, selectAnnotationClasses); + return parseAnnotations2(rawAnnotations, constPool, container, eagerResolution, selectAnnotationClasses); } catch(BufferUnderflowException e) { throw new AnnotationFormatError("Unexpected end of annotations."); } catch(IllegalArgumentException e) { @@ -111,22 +113,23 @@ private static Map, Annotation> parseAnnotations2( byte[] rawAnnotations, ConstantPool constPool, Class container, + boolean eagerResolution, Class[] selectAnnotationClasses) { Map, Annotation> result = new LinkedHashMap, Annotation>(); ByteBuffer buf = ByteBuffer.wrap(rawAnnotations); int numAnnotations = buf.getShort() & 0xFFFF; for (int i = 0; i < numAnnotations; i++) { - Annotation a = parseAnnotation2(buf, constPool, container, false, selectAnnotationClasses); + Annotation a = parseAnnotation2(buf, constPool, container, eagerResolution, false, selectAnnotationClasses); if (a != null) { Class klass = a.annotationType(); if (AnnotationType.getInstance(klass).retention() == RetentionPolicy.RUNTIME && result.put(klass, a) != null) { throw new AnnotationFormatError( "Duplicate annotation " + klass + " in " + container); + } } } - } return result; } @@ -158,7 +161,7 @@ public static Annotation[][] parseParameterAnnotations( ConstantPool constPool, Class container) { try { - return parseParameterAnnotations2(rawAnnotations, constPool, container); + return parseParameterAnnotations2(rawAnnotations, constPool, container, true); } catch(BufferUnderflowException e) { throw new AnnotationFormatError( "Unexpected end of parameter annotations."); @@ -168,10 +171,32 @@ public static Annotation[][] parseParameterAnnotations( } } + /** + * Parses the annotation member value in {@code annotationDefault} which is + * the default value for the annotation member represented by {@code method}. + */ + public static Object parseAnnotationDefault(Method method, byte[] annotationDefault, boolean eagerResolution) { + Class memberType = AnnotationType.invocationHandlerReturnType(method.getReturnType()); + Object result = parseMemberValue( + memberType, ByteBuffer.wrap(annotationDefault), + SharedSecrets.getJavaLangAccess(). + getConstantPool(method.getDeclaringClass()), + method.getDeclaringClass(), + eagerResolution); + if (result instanceof ExceptionProxy) { + if (result instanceof TypeNotPresentExceptionProxy proxy) { + throw new TypeNotPresentException(proxy.typeName(), proxy.getCause()); + } + throw new AnnotationFormatError("Invalid default: " + method); + } + return result; + } + private static Annotation[][] parseParameterAnnotations2( byte[] rawAnnotations, ConstantPool constPool, - Class container) { + Class container, + boolean eagerResolution) { ByteBuffer buf = ByteBuffer.wrap(rawAnnotations); int numParameters = buf.get() & 0xFF; Annotation[][] result = new Annotation[numParameters][]; @@ -181,7 +206,7 @@ private static Annotation[][] parseParameterAnnotations2( List annotations = new ArrayList(numAnnotations); for (int j = 0; j < numAnnotations; j++) { - Annotation a = parseAnnotation(buf, constPool, container, false); + Annotation a = parseAnnotation(buf, constPool, container, eagerResolution, false); if (a != null) { AnnotationType type = AnnotationType.getInstance( a.annotationType()); @@ -222,14 +247,16 @@ private static Annotation[][] parseParameterAnnotations2( static Annotation parseAnnotation(ByteBuffer buf, ConstantPool constPool, Class container, + boolean eagerResolution, boolean exceptionOnMissingAnnotationClass) { - return parseAnnotation2(buf, constPool, container, exceptionOnMissingAnnotationClass, null); + return parseAnnotation2(buf, constPool, container, eagerResolution, exceptionOnMissingAnnotationClass, null); } @SuppressWarnings("unchecked") private static Annotation parseAnnotation2(ByteBuffer buf, ConstantPool constPool, Class container, + boolean eagerResolution, boolean exceptionOnMissingAnnotationClass, Class[] selectAnnotationClasses) { int typeIndex = buf.getShort() & 0xFFFF; @@ -265,8 +292,11 @@ private static Annotation parseAnnotation2(ByteBuffer buf, } Map> memberTypes = type.memberTypes(); - Map memberValues = - new LinkedHashMap(type.memberDefaults()); + Map memberValues = new LinkedHashMap<>(); + for (var e : type.memberDefaults().entrySet()) { + Object value = e.getValue(); + memberValues.put(e.getKey(), eagerResolution ? ResolvableValue.resolved(value) : value); + } int numMembers = buf.getShort() & 0xFFFF; for (int i = 0; i < numMembers; i++) { @@ -278,7 +308,7 @@ private static Annotation parseAnnotation2(ByteBuffer buf, // Member is no longer present in annotation type; ignore it skipMemberValue(buf); } else { - Object value = parseMemberValue(memberType, buf, constPool, container); + Object value = parseMemberValue(memberType, buf, constPool, container, eagerResolution); if (value instanceof AnnotationTypeMismatchExceptionProxy exceptProxy) exceptProxy.setMember(type.members().get(memberName)); memberValues.put(memberName, value); @@ -326,26 +356,28 @@ public static Annotation annotationForMap(final Class type * The member must be of the indicated type. If it is not, this * method returns an AnnotationTypeMismatchExceptionProxy. */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "rawtypes"}) public static Object parseMemberValue(Class memberType, ByteBuffer buf, ConstantPool constPool, - Class container) { + Class container, + boolean eagerResolution) { // Note that VMSupport.encodeAnnotation (used by JVMCI) may need to // be updated if new annotation member types are added. Object result = null; int tag = buf.get(); switch(tag) { case 'e': - return parseEnumValue((Class>)memberType, buf, constPool, container); + Class enumType = (Class>) memberType; + return parseEnumValue(enumType, buf, constPool, container, eagerResolution); case 'c': result = parseClassValue(buf, constPool, container); break; case '@': - result = parseAnnotation(buf, constPool, container, true); + result = parseAnnotation(buf, constPool, container, eagerResolution, true); break; case '[': - return parseArray(memberType, buf, constPool, container); + return parseArray(memberType, buf, constPool, container, eagerResolution); default: result = parseConst(tag, buf, constPool); } @@ -455,11 +487,15 @@ static Class toClass(Type o) { * u2 type_name_index; * u2 const_name_index; * } enum_const_value; + * + * @param resolve if false, the name of the enum constant is returned + * instead of a resolved enum constant */ @SuppressWarnings({"rawtypes", "unchecked"}) private static Object parseEnumValue(Class enumType, ByteBuffer buf, ConstantPool constPool, - Class container) { + Class container, + boolean resolve) { int typeNameIndex = buf.getShort() & 0xFFFF; String typeName = constPool.getUTF8At(typeNameIndex); int constNameIndex = buf.getShort() & 0xFFFF; @@ -468,9 +504,11 @@ private static Object parseEnumValue(Class enumType, ByteBuffer return new AnnotationTypeMismatchExceptionProxy( typeName.substring(1, typeName.length() - 1).replace('/', '.') + "." + constName); } - + if (!resolve) { + return new EnumValue(enumType, constName); + } try { - return Enum.valueOf(enumType, constName); + return Enum.valueOf(enumType, constName); } catch(IllegalArgumentException e) { return new EnumConstantNotPresentExceptionProxy( (Class>)enumType, constName); @@ -495,7 +533,8 @@ private static Object parseEnumValue(Class enumType, ByteBuffer private static Object parseArray(Class arrayType, ByteBuffer buf, ConstantPool constPool, - Class container) { + Class container, + boolean eagerResolution) { int length = buf.getShort() & 0xFFFF; // Number of array components if (!arrayType.isArray()) { return parseUnknownArray(length, buf); @@ -524,10 +563,10 @@ private static Object parseArray(Class arrayType, return parseClassArray(length, buf, constPool, container); } else if (componentType.isEnum()) { return parseEnumArray(length, (Class>)componentType, buf, - constPool, container); + constPool, container, eagerResolution); } else if (componentType.isAnnotation()) { return parseAnnotationArray(length, (Class )componentType, buf, - constPool, container); + constPool, container, eagerResolution); } else { return parseUnknownArray(length, buf); } @@ -715,18 +754,26 @@ private static Object parseClassArray(int length, private static Object parseEnumArray(int length, Class> enumType, ByteBuffer buf, ConstantPool constPool, - Class container) { - return parseArrayElements((Object[]) Array.newInstance(enumType, length), - buf, 'e', () -> parseEnumValue(enumType, buf, constPool, container)); + Class container, + boolean resolve) { + if (resolve) { + return parseArrayElements((Object[]) Array.newInstance(enumType, length), + buf, 'e', () -> parseEnumValue(enumType, buf, constPool, container, true)); + } + String[] constNames = new String[length]; + parseArrayElements(constNames, + buf, 'e', () -> ((EnumValue) parseEnumValue(enumType, buf, constPool, container, false)).constName); + return new EnumValueArray(enumType, Collections.unmodifiableList(Arrays.asList(constNames))); } private static Object parseAnnotationArray(int length, Class annotationType, ByteBuffer buf, ConstantPool constPool, - Class container) { + Class container, + boolean eagerResolution) { return parseArrayElements((Object[]) Array.newInstance(annotationType, length), - buf, '@', () -> parseAnnotation(buf, constPool, container, true)); + buf, '@', () -> parseAnnotation(buf, constPool, container, eagerResolution, true)); } private static Object parseArrayElements(Object[] result, diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java index 3a4bd80b0149e..a8f9014a51669 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java @@ -123,9 +123,12 @@ private AnnotationType(final Class annotationClass) { memberTypes.put(name, invocationHandlerReturnType(type)); members.put(name, method); - Object defaultValue = method.getDefaultValue(); - if (defaultValue != null) { - memberDefaults.put(name, defaultValue); + byte[] annotationDefault = SharedSecrets.getJavaLangReflectAccess().getAnnotationDefaultBytes(method); + if (annotationDefault != null) { + Object defaultValue = AnnotationParser.parseAnnotationDefault(method, annotationDefault, false); + if (defaultValue != null) { + memberDefaults.put(name, defaultValue); + } } } } @@ -140,6 +143,7 @@ private AnnotationType(final Class annotationClass) { jla.getRawClassAnnotations(annotationClass), jla.getConstantPool(annotationClass), annotationClass, + true, Retention.class, Inherited.class ); Retention ret = (Retention) metaAnnotations.get(Retention.class); @@ -199,7 +203,10 @@ public Map members() { /** * Returns the default values for this annotation type - * (Member name {@literal ->} default value mapping). + * (Member name {@literal ->} default value mapping). The values in this + * map might be {@linkplain ResolvableValue#isResolved unresolved} + * so should be passed through {@link ResolvableValue#resolved} in + * contexts where resolved values are required. */ public Map memberDefaults() { return memberDefaults; diff --git a/src/java.base/share/classes/sun/reflect/annotation/EnumValue.java b/src/java.base/share/classes/sun/reflect/annotation/EnumValue.java new file mode 100644 index 0000000000000..96e1a6b3715cf --- /dev/null +++ b/src/java.base/share/classes/sun/reflect/annotation/EnumValue.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.reflect.annotation; + +/** + * An instance of this class is stored in an AnnotationInvocationHandler's + * "memberValues" map to defer reification of an enum constant until the + * dynamic proxy is queried for the enum member. + */ +public final class EnumValue implements java.io.Serializable, ResolvableValue { + + /** + * The type of the enum constant. + */ + @SuppressWarnings("rawtypes") + public final Class enumType; + + /** + * The name of the enum constant. + */ + public final String constName; + + /** + * The lazily retrived value of the enum constant. + */ + transient Object constValue; + + @SuppressWarnings("rawtypes") + public EnumValue(Class enumType, String constName) { + this.enumType = enumType; + this.constName = constName; + } + + /** + * Gets the enum constant. + */ + @SuppressWarnings("unchecked") + public Object get() { + if (constValue == null) { + try { + constValue = Enum.valueOf(enumType, constName); + } catch (IllegalArgumentException e) { + throw new EnumConstantNotPresentException(enumType, constName); + } + } + return constValue; + } + + @Override + public boolean isResolved() { + return constValue != null; + } + + @Override + public String toString() { + return constName; + } + + @Override + public int hashCode() { + return constName.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof EnumValue ev) { + return this.constName.equals(ev.constName) && + this.enumType.equals(ev.enumType); + } + return false; + } + + @java.io.Serial + private static final long serialVersionUID = 5762566221979761881L; +} diff --git a/src/java.base/share/classes/sun/reflect/annotation/EnumValueArray.java b/src/java.base/share/classes/sun/reflect/annotation/EnumValueArray.java new file mode 100644 index 0000000000000..3923aeccd2e4b --- /dev/null +++ b/src/java.base/share/classes/sun/reflect/annotation/EnumValueArray.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2025, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.reflect.annotation; + +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +/** + * An instance of this class is stored in an AnnotationInvocationHandler's + * "memberValues" map to defer reification of an enum constant until the + * dynamic proxy is queried for the enum member. + */ +public final class EnumValueArray implements java.io.Serializable, ResolvableValue { + + /** + * The type of the enum constant. + */ + @SuppressWarnings("rawtypes") + public final Class enumType; + + /** + * The names of the enum constants. + */ + @SuppressWarnings("serial") + public final List constNames; + + /** + * The lazily resolved array of enum constants. + */ + transient Object[] constValues; + + @SuppressWarnings("rawtypes") + EnumValueArray(Class enumType, List constNames) { + if (!(constNames instanceof Serializable)) { + throw new IllegalArgumentException(constNames.getClass() + " is not serializable"); + } + this.enumType = enumType; + this.constNames = constNames; + } + + /** + * Gets the array of enum constants. + */ + @SuppressWarnings("unchecked") + public Object get() { + if (constValues == null) { + int length = constNames.size(); + constValues = (Object[]) Array.newInstance(enumType, length); + for (int i = 0; i < length; i++) { + try { + constValues[i] = Enum.valueOf(enumType, constNames.get(i)); + } catch (IllegalArgumentException e) { + throw new EnumConstantNotPresentException(enumType, constNames.get(i)); + } + } + } + return constValues.length == 0 ? constValues : constValues.clone(); + } + + @Override + public boolean isResolved() { + return constValues != null; + } + + @Override + public String toString() { + return constNames.toString(); + } + + @Override + public int hashCode() { + return constNames.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof EnumValueArray eva) { + return this.enumType.equals(eva.enumType) && + this.constNames.equals(eva.constNames); + } + return false; + } + + @java.io.Serial + private static final long serialVersionUID = 5762566221979761881L; +} diff --git a/src/java.base/share/classes/sun/reflect/annotation/ResolvableValue.java b/src/java.base/share/classes/sun/reflect/annotation/ResolvableValue.java new file mode 100644 index 0000000000000..331a01ea7c7f9 --- /dev/null +++ b/src/java.base/share/classes/sun/reflect/annotation/ResolvableValue.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.reflect.annotation; + +/** + * Denotes a parsed annotation element value that is not fully resolved to the + * value returned by the annotation interface method for the element. + * This is used for example to defer resolving enum constants which is important + * in contexts where class initialization of the enum types should not be + * triggered by annotation parsing. + */ +public interface ResolvableValue { + + /** + * Gets resolved value, performing resolution first if necessary. + */ + @SuppressWarnings("unchecked") + Object get(); + + /** + * Determines if this value has been resolved. + */ + boolean isResolved(); + + /** + * Gets the resolved value of {@code memberValue}, performing + * resolution first if necessary. + */ + static Object resolved(Object memberValue) { + if (memberValue instanceof ResolvableValue rv) { + return rv.get(); + } + return memberValue; + } +} diff --git a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java index 30f9434d6b770..e5b0da3be84a4 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java +++ b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java @@ -420,7 +420,7 @@ private static TypeAnnotation parseTypeAnnotation(ByteBuffer buf, try { TypeAnnotationTargetInfo ti = parseTargetInfo(buf); LocationInfo locationInfo = LocationInfo.parseLocationInfo(buf); - Annotation a = AnnotationParser.parseAnnotation(buf, cp, container, false); + Annotation a = AnnotationParser.parseAnnotation(buf, cp, container, true, false); if (ti == null) // Inside a method for example return null; return new TypeAnnotation(ti, locationInfo, a, baseDecl); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationDataDecoder.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationDataDecoder.java index 9cc33a395fc52..785d8e15785e4 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationDataDecoder.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationDataDecoder.java @@ -23,9 +23,11 @@ package jdk.vm.ci.hotspot; import java.util.Map; +import java.util.List; import jdk.internal.vm.VMSupport.AnnotationDecoder; import jdk.vm.ci.meta.AnnotationData; +import jdk.vm.ci.meta.EnumArrayData; import jdk.vm.ci.meta.EnumData; import jdk.vm.ci.meta.ErrorData; import jdk.vm.ci.meta.JavaType; @@ -38,36 +40,37 @@ * and employs {@link AnnotationData} and {@link EnumData} to represent decoded annotations and enum * constants respectively. */ -final class AnnotationDataDecoder implements AnnotationDecoder { +final class AnnotationDataDecoder implements AnnotationDecoder { - static final AnnotationDataDecoder INSTANCE = new AnnotationDataDecoder(); + private final HotSpotResolvedJavaType accessingClass; + + AnnotationDataDecoder(HotSpotResolvedJavaType accessingClass) { + this.accessingClass = accessingClass; + } @Override - public JavaType resolveType(String name) { + public ResolvedJavaType resolveType(String name) { String internalName = MetaUtil.toInternalName(name); - return UnresolvedJavaType.create(internalName); + return UnresolvedJavaType.create(internalName).resolve(accessingClass); } @Override - public AnnotationData newAnnotation(JavaType type, Map.Entry[] elements) { + public AnnotationData newAnnotation(ResolvedJavaType type, Map.Entry[] elements) { return new AnnotationData(type, elements); } @Override - public EnumData newEnumValue(JavaType enumType, String name) { + public EnumData newEnumValue(ResolvedJavaType enumType, String name) { return new EnumData(enumType, name); } @Override - public ErrorData newErrorValue(String description) { - return new ErrorData(description); + public EnumArrayData newEnumValueArray(ResolvedJavaType enumType, List names) { + return new EnumArrayData(enumType, names); } - static ResolvedJavaType[] asArray(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { - ResolvedJavaType[] filter = new ResolvedJavaType[2 + types.length]; - filter[0] = type1; - filter[1] = type2; - System.arraycopy(types, 0, filter, 2, types.length); - return filter; + @Override + public ErrorData newErrorValue(String description) { + return new ErrorData(description); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index b75edb9df08c2..cb382b0ccb2a3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -244,18 +244,16 @@ public AnnotationData getAnnotationData(ResolvedJavaType annotationType) { } @Override - public List getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { - checkIsAnnotation(type1); - checkIsAnnotation(type2); + public List getSelectedAnnotationData(ResolvedJavaType... types) { checkAreAnnotations(types); if (!hasAnnotations()) { return List.of(); } - return getAnnotationData0(AnnotationDataDecoder.asArray(type1, type2, types)); + return getAnnotationData0(types); } private List getAnnotationData0(ResolvedJavaType... filter) { byte[] encoded = compilerToVM().getEncodedFieldAnnotationData(holder, index, filter); - return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE); + return VMSupport.decodeAnnotations(encoded, new AnnotationDataDecoder(getDeclaringClass())); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 224e8b1a070e2..e93a907571b23 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -785,19 +785,17 @@ public AnnotationData getAnnotationData(ResolvedJavaType type) { } @Override - public List getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { - checkIsAnnotation(type1); - checkIsAnnotation(type2); + public List getSelectedAnnotationData(ResolvedJavaType... types) { checkAreAnnotations(types); if (!hasAnnotations()) { return List.of(); } - return getAnnotationData0(AnnotationDataDecoder.asArray(type1, type2, types)); + return getAnnotationData0(types); } private List getAnnotationData0(ResolvedJavaType... filter) { byte[] encoded = compilerToVM().getEncodedExecutableAnnotationData(this, filter); - return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE); + return VMSupport.decodeAnnotations(encoded, new AnnotationDataDecoder(getDeclaringClass())); } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 46e53411deef7..aaa5c191dc417 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -1127,18 +1127,16 @@ public AnnotationData getAnnotationData(ResolvedJavaType annotationType) { } @Override - public List getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { + public List getSelectedAnnotationData(ResolvedJavaType... types) { if (!mayHaveAnnotations(true)) { - checkIsAnnotation(type1); - checkIsAnnotation(type2); checkAreAnnotations(types); return List.of(); } - return getAnnotationData0(AnnotationDataDecoder.asArray(type1, type2, types)); + return getAnnotationData0(types); } private List getAnnotationData0(ResolvedJavaType... filter) { byte[] encoded = compilerToVM().getEncodedClassAnnotationData(this, filter); - return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE); + return VMSupport.decodeAnnotations(encoded, new AnnotationDataDecoder(this)); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index 9da92713be489..c1e38fa5a05a2 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -348,9 +348,7 @@ public AnnotationData getAnnotationData(ResolvedJavaType type) { } @Override - public List getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { - checkIsAnnotation(type1); - checkIsAnnotation(type2); + public List getSelectedAnnotationData(ResolvedJavaType... types) { checkAreAnnotations(types); return List.of(); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java index 666e1181cb113..513945093a1e5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java @@ -32,31 +32,28 @@ public interface Annotated { /** - * Constructs the annotations present on this element whose types are in the set composed of {@code type1}, - * {@code type2} and {@code types}. All enum types referenced by the returned annotation are - * initialized. Class initialization is not triggered for enum types referenced by other - * annotations of this element. + * Gets the annotations present on this element whose types are in {@code types}. + * Class initialization is not triggered for enum types referenced by the returned + * annotations or any other annotations of this element. * * If this element is a class, then {@link Inherited} annotations are included in the set of * annotations considered. * * See {@link java.lang.reflect.AnnotatedElement} for the definition of present. * - * @param type1 an annotation type - * @param type2 an annotation type - * @param types more annotation types - * @return an immutable list of the annotations present on this element that match one of the - * given types - * @throws IllegalArgumentException if any type in the set composed of {@code type1}, - * {@code type2} and {@code types} is not an annotation interface type + * @param types annotation types to select + * @return an immutable list of the annotations present on this element that match one {@code types} + * @throws IllegalArgumentException if any type in {@code types} is not an annotation interface type * @throws UnsupportedOperationException if this operation is not supported */ - default List getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { + default List getSelectedAnnotationData(ResolvedJavaType... types) { throw new UnsupportedOperationException(); } /** - * Constructs the annotation present on this element of type {@code type}. + * Gets the annotation present on this element of type {@code type}. + * Class initialization is not triggered for enum types referenced by the returned + * annotation. * * See {@link java.lang.reflect.AnnotatedElement} for the definition of present. * diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationData.java index 76edb8c83a77e..c5c98ba409a3b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationData.java @@ -23,6 +23,7 @@ package jdk.vm.ci.meta; import java.lang.annotation.Annotation; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -39,7 +40,7 @@ */ public final class AnnotationData { - private final JavaType type; + private final ResolvedJavaType type; private final Map elements; private static final Set> ELEMENT_TYPES = Set.of( @@ -52,13 +53,15 @@ public final class AnnotationData { Long.class, Double.class, String.class, + ErrorData.class, + EnumArrayData.class, EnumData.class, AnnotationData.class); /** * Creates an annotation. * - * @param type the annotation interface of this annotation, represented as a {@link JavaType} + * @param type the annotation interface of this annotation, represented as a {@link ResolvedJavaType} * @param elements the names and values of this annotation's element values. Each value's type * must be one of the {@code AnnotationData} types described {@linkplain #get here} * or it must be a {@link ErrorData} object whose {@code toString()} value describes @@ -69,24 +72,36 @@ public final class AnnotationData { * @throws NullPointerException if any of the above parameters is null or any entry in * {@code elements} is null */ - public AnnotationData(JavaType type, Map.Entry[] elements) { + public AnnotationData(ResolvedJavaType type, Map.Entry[] elements) { this.type = Objects.requireNonNull(type); for (Map.Entry e : elements) { - Object value = e.getValue(); - if (!(value instanceof ErrorData) && - !(value instanceof JavaType) && - !(value instanceof List) && - !ELEMENT_TYPES.contains(value.getClass())) { - throw new IllegalArgumentException("illegal type for element " + e.getKey() + ": " + value.getClass().getName()); - } + checkEntry(e); } this.elements = Map.ofEntries(elements); } + private static void checkEntry(Map.Entry e) { + Object value = e.getValue(); + Class valueClass = value.getClass(); + boolean illegalEnumType = false; + if (valueClass.isArray()) { + valueClass = valueClass.getComponentType(); + if (valueClass == EnumData.class || valueClass == EnumArrayData.class) { + illegalEnumType = true; + } + } + if (illegalEnumType || + (!ResolvedJavaType.class.isAssignableFrom(valueClass) && + !(value instanceof List) && + !ELEMENT_TYPES.contains(valueClass))) { + throw new IllegalArgumentException("illegal type for element " + e.getKey() + ": " + value.getClass().getName()); + } + } + /** - * @return the annotation interface of this annotation, represented as a {@link JavaType} + * @return the annotation interface of this annotation, represented as a {@link ResolvedJavaType} */ - public JavaType getAnnotationType() { + public ResolvedJavaType getAnnotationType() { return type; } @@ -108,10 +123,11 @@ public JavaType getAnnotationType() { * long Long * double Double * String String - * Class JavaType + * Class ResolvedJavaType * Enum EnumData + * Enum[] EnumArrayData * Annotation AnnotationData - * []immutable List<T> where T is one of the above types + * []T[] where T is one of the above types except for EnumData or EnumArrayData * * * @@ -138,7 +154,7 @@ public V get(String name, Class elementType) { @Override public String toString() { - return "@" + type.getName() + "(" + elements + ")"; + return "@" + type.toClassName() + "(" + elements + ")"; } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumArrayData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumArrayData.java new file mode 100644 index 0000000000000..600283bc8ca82 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumArrayData.java @@ -0,0 +1,62 @@ +/* + * 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 jdk.vm.ci.meta; + +import java.util.List; + +/** + * Represents an array of enum constants within {@link AnnotationData}. + */ +public final class EnumArrayData { + public final ResolvedJavaType enumType; + public final List names; + + /** + * Creates an array of enum constants. + * + * @param type the {@linkplain Enum enum type} + * @param name the names of the enum constants + */ + public EnumArrayData(ResolvedJavaType enumType, List names) { + this.enumType = enumType; + this.names = names; + } + + @Override + public String toString() { + return names.toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof EnumArrayData that) { + return this.enumType.equals(that.enumType) && this.names.equals(that.names); + } + return false; + } + + @Override + public int hashCode() { + return this.enumType.hashCode() ^ this.names.hashCode(); + } +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java index 4e8fc3a8ab774..31f87ec5b6ec5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java @@ -26,8 +26,8 @@ * Represents an enum constant within {@link AnnotationData}. */ public final class EnumData { - private final JavaType type; - private final String name; + public final ResolvedJavaType enumType; + public final String name; /** * Creates an enum constant. @@ -35,25 +35,11 @@ public final class EnumData { * @param type the {@linkplain Enum enum type} * @param name the {@linkplain Enum#name() name} of the enum */ - public EnumData(JavaType type, String name) { - this.type = type; + public EnumData(ResolvedJavaType enumType, String name) { + this.enumType = enumType; this.name = name; } - /** - * Gets the {@linkplain Enum enum type}. - */ - public JavaType getEnumType() { - return type; - } - - /** - * Gets the {@linkplain Enum#name() name} of the enum. - */ - public String getName() { - return name; - } - @Override public String toString() { return name; @@ -61,18 +47,14 @@ public String toString() { @Override public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof EnumData) { - EnumData that = (EnumData) obj; - return this.type.equals(that.type) && this.name.equals(that.name); + if (obj instanceof EnumData that) { + return this.enumType.equals(that.enumType) && this.name.equals(that.name); } return false; } @Override public int hashCode() { - return this.type.hashCode() ^ this.name.hashCode(); + return this.enumType.hashCode() ^ this.name.hashCode(); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaType.java index 1740744b4b1fd..ee7373219e2c6 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaType.java @@ -107,6 +107,10 @@ public String toString() { @Override public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { - return accessingClass.lookupType(this, true); + ResolvedJavaType type = accessingClass.lookupType(this, true); + if (type == null) { + throw new NoClassDefFoundError(toClassName()); + } + return type; } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 6151ae68ce7ab..c1d34e5228e6a 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -613,11 +613,11 @@ public void getAnnotationDataTest() throws Exception { // Ensure NumbersDE is not initialized before Annotation2 is requested Assert.assertFalse(numbersDEType.isInitialized()); - Assert.assertEquals(2, m.getAnnotationData(a1, a3).size()); + Assert.assertEquals(2, m.getSelectedAnnotationData(a1, a3).size()); - // Ensure NumbersDE is initialized after Annotation2 is requested + // Ensure NumbersDE is not initialized after Annotation2 is requested Assert.assertNotNull(m.getAnnotationData(a2)); - Assert.assertTrue(numbersDEType.isInitialized()); + Assert.assertFalse(numbersDEType.isInitialized()); } private static ClassModel readClassfile(Class c) throws Exception { @@ -691,7 +691,7 @@ private static Map buildMethodMap(ResolvedJavaType t return methodMap; } - @Test + //@Test public void getOopMapAtTest() throws Exception { Collection> allClasses = new ArrayList<>(classes); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index 6501d0820754a..a0407b2ddeb5d 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -94,6 +94,7 @@ import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Annotated; import jdk.vm.ci.meta.AnnotationData; +import jdk.vm.ci.meta.EnumArrayData; import jdk.vm.ci.meta.EnumData; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.JavaConstant; @@ -1261,7 +1262,7 @@ public void getAnnotationDataTest() throws Exception { ResolvedJavaType type = metaAccess.lookupJavaType(c); AnnotationData ad = type.getAnnotationData(overrideType); Assert.assertNull(String.valueOf(ad), ad); - List adArray = type.getAnnotationData(overrideType, overrideType); + List adArray = type.getSelectedAnnotationData(overrideType, overrideType); Assert.assertEquals(0, adArray.size()); } @@ -1325,8 +1326,7 @@ private static void getAnnotationDataExpectedToFail(Annotated annotated, Resolve if (annotationTypes.length == 1) { annotated.getAnnotationData(annotationTypes[0]); } else { - var tail = Arrays.copyOfRange(annotationTypes, 2, annotationTypes.length); - annotated.getAnnotationData(annotationTypes[0], annotationTypes[1], tail); + annotated.getSelectedAnnotationData(annotationTypes); } String s = Stream.of(annotationTypes).map(ResolvedJavaType::toJavaName).collect(Collectors.joining(", ")); throw new AssertionError("Expected IllegalArgumentException for retrieving (" + s + " from " + annotated); @@ -1352,9 +1352,9 @@ public static void getAnnotationDataTest(AnnotatedElement annotatedElement) thro // Check that querying a missing annotation returns null or an empty list assertNull(annotated.getAnnotationData(suppressWarningsType)); - List data = annotated.getAnnotationData(suppressWarningsType, suppressWarningsType); + List data = annotated.getSelectedAnnotationData(suppressWarningsType, suppressWarningsType); assertTrue(data.toString(), data.isEmpty()); - data = annotated.getAnnotationData(suppressWarningsType, suppressWarningsType, suppressWarningsType, suppressWarningsType); + data = annotated.getSelectedAnnotationData(suppressWarningsType, suppressWarningsType, suppressWarningsType, suppressWarningsType); assertTrue(data.toString(), data.isEmpty()); testGetAnnotationData(annotatedElement, annotated, List.of(annotatedElement.getAnnotations())); @@ -1371,22 +1371,18 @@ private static void testGetAnnotationData(AnnotatedElement annotatedElement, Ann AnnotationData ad2 = annotated.getAnnotationData(annotationType); assertEquals(ad, ad2); - List annotationData = annotated.getAnnotationData(annotationType, suppressWarningsType, suppressWarningsType); + List annotationData = annotated.getSelectedAnnotationData(annotationType, suppressWarningsType, suppressWarningsType); assertEquals(1, annotationData.size()); } if (annotations.size() < 2) { return; } - ResolvedJavaType type1 = metaAccess.lookupJavaType(annotations.get(0).annotationType()); - ResolvedJavaType type2 = metaAccess.lookupJavaType(annotations.get(1).annotationType()); - for (int i = 2; i < annotations.size(); i++) { - + for (int i = 0; i < annotations.size(); i++) { ResolvedJavaType[] types = annotations.// - subList(2, i + 1).// stream().map(a -> metaAccess.lookupJavaType(a.annotationType())).// toArray(ResolvedJavaType[]::new); - List annotationData = annotated.getAnnotationData(type1, type2, types); - assertEquals(2 + types.length, annotationData.size()); + List annotationData = annotated.getSelectedAnnotationData(types); + assertEquals(types.length, annotationData.size()); for (int j = 0; j < annotationData.size(); j++) { Annotation a = annotations.get(j); @@ -1434,17 +1430,29 @@ private static void assertAnnotationsEquals(Annotation a, AnnotationData ad) { private static void assertAnnotationElementsEqual(Object aValue, Object adValue) { Class valueType = aValue.getClass(); if (valueType.isEnum()) { - assertEnumObjectsEquals(aValue, adValue); + String adEnumName = ((EnumData) adValue).name; + String aEnumName = ((Enum) aValue).name(); + assertEquals(adEnumName, aEnumName); } else if (aValue instanceof Class) { assertClassObjectsEquals(aValue, adValue); } else if (aValue instanceof Annotation) { assertAnnotationObjectsEquals(aValue, adValue); } else if (valueType.isArray()) { - List adList = (List) adValue; int length = Array.getLength(aValue); - assertEquals(length, adList.size()); - for (int i = 0; i < length; i++) { - assertAnnotationElementsEqual(Array.get(aValue, i), adList.get(i)); + if (valueType.getComponentType().isEnum()) { + EnumArrayData array = (EnumArrayData) adValue; + assertEquals(length, array.names.size()); + for (int i = 0; i < length; i++) { + String adEnumName = array.names.get(i); + String aEnumName = ((Enum) Array.get(aValue, i)).name(); + assertEquals(adEnumName, aEnumName); + } + } else { + List adList = (List) adValue; + assertEquals(length, adList.size()); + for (int i = 0; i < length; i++) { + assertAnnotationElementsEqual(Array.get(aValue, i), adList.get(i)); + } } } else { assertEquals(aValue.getClass(), adValue.getClass()); @@ -1458,13 +1466,6 @@ private static void assertClassObjectsEquals(Object aValue, Object adValue) { assertEquals(aName, adName); } - private static void assertEnumObjectsEquals(Object aValue, Object adValue) { - EnumData adEnum = (EnumData) adValue; - String adEnumName = adEnum.getName(); - String aEnumName = ((Enum) aValue).name(); - assertEquals(adEnumName, aEnumName); - } - private static void assertAnnotationObjectsEquals(Object aValue, Object adValue) { Annotation aAnnotation = (Annotation) aValue; AnnotationData adAnnotation = (AnnotationData) adValue; diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java index 64e559a571332..b78264df7d666 100644 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java @@ -36,20 +36,14 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.util.LinkedHashMap; -import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.TreeMap; import org.testng.Assert; import org.testng.annotations.Test; import sun.reflect.annotation.AnnotationSupport; -import sun.reflect.annotation.AnnotationParser; import sun.reflect.annotation.ExceptionProxy; import jdk.internal.vm.VMSupport; @@ -59,15 +53,15 @@ public class TestAnnotationEncodingDecoding { @Test public void encodeDecodeTest() throws Exception { - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredField("annotatedField")); - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); - checkDecodedEqualsEncoded(AnnotationTestInput.AnnotatedClass.class); - - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingAnnotation")); - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingNestedAnnotation"), true); - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingTypeOfClassMember"), false); - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingMember")); - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("changeTypeOfMember"), false); + checkDecodedEqualsEncoded(jdk.internal.vm.test.AnnotationTestInput.class.getDeclaredField("annotatedField")); + checkDecodedEqualsEncoded(jdk.internal.vm.test.AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); + checkDecodedEqualsEncoded(jdk.internal.vm.test.AnnotationTestInput.AnnotatedClass.class); + + checkDecodedEqualsEncoded(jdk.internal.vm.test.AnnotationTestInput.class.getDeclaredMethod("missingAnnotation")); + checkDecodedEqualsEncoded(jdk.internal.vm.test.AnnotationTestInput.class.getDeclaredMethod("missingNestedAnnotation"), true); + checkDecodedEqualsEncoded(jdk.internal.vm.test.AnnotationTestInput.class.getDeclaredMethod("missingTypeOfClassMember"), false); + checkDecodedEqualsEncoded(jdk.internal.vm.test.AnnotationTestInput.class.getDeclaredMethod("missingMember")); + checkDecodedEqualsEncoded(jdk.internal.vm.test.AnnotationTestInput.class.getDeclaredMethod("changeTypeOfMember"), false); } private void checkDecodedEqualsEncoded(AnnotatedElement annotated) { @@ -120,6 +114,7 @@ public static final class AnnotationConst { this.elements = Map.ofEntries(elements); } + @SuppressWarnings({"rawtypes", "unchecked"}) AnnotationConst(Annotation a) { Map values = AnnotationSupport.memberValues(a); this.type = a.annotationType(); @@ -133,8 +128,7 @@ public static final class AnnotationConst { @Override public boolean equals(Object obj) { - if (obj instanceof AnnotationConst) { - AnnotationConst that = (AnnotationConst) obj; + if (obj instanceof AnnotationConst that) { return this.type.equals(that.type) && this.elements.equals(that.elements); } @@ -148,10 +142,17 @@ public String toString() { private Object decodeValue(Object value) { Class valueType = value.getClass(); - if (value instanceof Enum) { - return new EnumConst(valueType, ((Enum) value).name()); - } else if (value instanceof Annotation) { - return new AnnotationConst((Annotation) value); + if (value instanceof Enum e) { + return new EnumConst(valueType, e.name()); + } else if (value instanceof Annotation a) { + return new AnnotationConst(a); + } else if (value instanceof Enum[] ea) { + int len = ea.length; + String[] arr = new String[len]; + for (int i = 0; i < len; i++) { + arr[i] = ea[i].name(); + } + return new EnumArrayConst(valueType.getComponentType(), List.of(arr)); } else if (valueType.isArray()) { int len = Array.getLength(value); Object[] arr = new Object[len]; @@ -207,8 +208,7 @@ public EnumConst(Class type, String name) { @Override public boolean equals(Object obj) { - if (obj instanceof EnumConst) { - EnumConst that = (EnumConst) obj; + if (obj instanceof EnumConst that) { return this.type.equals(that.type) && this.name.equals(that.name); } @@ -220,16 +220,40 @@ public String toString() { return type.getName() + "." + name; } - public Class getEnumType() { - return type; - } - public String getName() { return name; } } - static class MyDecoder implements AnnotationDecoder, AnnotationConst, EnumConst, ErrorConst> { + public static final class EnumArrayConst { + final Class type; + final List names; + + public EnumArrayConst(Class type, List names) { + this.type = type; + this.names = names; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof EnumArrayConst that) { + return this.type.equals(that.type) && + this.names.equals(that.names); + } + return false; + } + + @Override + public String toString() { + return type.getName() + "." + names; + } + + public List getNames() { + return names; + } + } + + static class MyDecoder implements AnnotationDecoder, AnnotationConst, EnumConst, EnumArrayConst, ErrorConst> { @Override public Class resolveType(String name) { try { @@ -249,6 +273,11 @@ public EnumConst newEnumValue(Class enumType, String name) { return new EnumConst(enumType, name); } + @Override + public EnumArrayConst newEnumValueArray(Class enumType, List names) { + return new EnumArrayConst(enumType, names); + } + @Override public ErrorConst newErrorValue(String description) { return new ErrorConst(description); From b09707b4894b966672e432f267470b0d16c23d24 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 11:29:13 +0200 Subject: [PATCH 02/20] rename AnnotationData to AnnotationValue --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 20 +-- .../reflect/annotation/AnnotationParser.java | 5 +- ...coder.java => AnnotationValueDecoder.java} | 12 +- .../jdk/vm/ci/hotspot/CompilerToVM.java | 24 +-- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 17 +- .../HotSpotResolvedJavaMethodImpl.java | 18 +- .../ci/hotspot/HotSpotResolvedJavaType.java | 4 +- .../HotSpotResolvedObjectTypeImpl.java | 19 +- .../hotspot/HotSpotResolvedPrimitiveType.java | 7 +- .../classes/jdk/vm/ci/meta/Annotated.java | 8 +- ...notationData.java => AnnotationValue.java} | 33 ++-- .../classes/jdk/vm/ci/meta/EnumArrayData.java | 13 +- .../classes/jdk/vm/ci/meta/EnumData.java | 11 +- .../classes/jdk/vm/ci/meta/ErrorData.java | 6 +- .../runtime/test/TestResolvedJavaField.java | 6 +- .../runtime/test/TestResolvedJavaMethod.java | 40 ++--- .../ci/runtime/test/TestResolvedJavaType.java | 164 +++++++++--------- .../AnnotationTestInput.java | 3 + 18 files changed, 208 insertions(+), 202 deletions(-) rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/{AnnotationDataDecoder.java => AnnotationValueDecoder.java} (82%) rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/{AnnotationData.java => AnnotationValue.java} (87%) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index e4900249dbd0a..36d04c4f7fa31 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -3014,7 +3014,7 @@ C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAI return JNIHandles::make_local(THREAD, reflected); C2V_END -static jbyteArray get_encoded_annotation_data(InstanceKlass* holder, AnnotationArray* annotations_array, bool for_class, +static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, AnnotationArray* annotations_array, bool for_class, jint filter_length, jlong filter_klass_pointers, JavaThread* THREAD, JVMCI_TRAPS) { // Get a ConstantPool object for annotation parsing @@ -3077,26 +3077,26 @@ static jbyteArray get_encoded_annotation_data(InstanceKlass* holder, AnnotationA return JVMCIENV->get_jbyteArray(ba_dest); } -C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), +C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jobject filter, jint filter_length, jlong filter_klass_pointers)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support InstanceKlass* holder = InstanceKlass::cast(UNPACK_PAIR(Klass, klass)); - return get_encoded_annotation_data(holder, holder->class_annotations(), true, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + return get_encoded_annotation_values(holder, holder->class_annotations(), true, filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END -C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), +C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), jobject filter, jint filter_length, jlong filter_klass_pointers)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support methodHandle method(THREAD, UNPACK_PAIR(Method, method)); - return get_encoded_annotation_data(method->method_holder(), method->annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + return get_encoded_annotation_values(method->method_holder(), method->annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END -C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, +C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, jobject filter, jint filter_length, jlong filter_klass_pointers)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support InstanceKlass* holder = check_field(InstanceKlass::cast(UNPACK_PAIR(Klass, klass)), index, JVMCI_CHECK_NULL); fieldDescriptor fd(holder, index); - return get_encoded_annotation_data(holder, fd.annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + return get_encoded_annotation_values(holder, fd.annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_NULL(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current)) @@ -3440,9 +3440,9 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)}, {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" REFLECTION_EXECUTABLE, FN_PTR(asReflectionExecutable)}, {CC "asReflectionField", CC "(" HS_KLASS2 "I)" REFLECTION_FIELD, FN_PTR(asReflectionField)}, - {CC "getEncodedClassAnnotationData", CC "(" HS_KLASS2 OBJECT "IJ)[B", FN_PTR(getEncodedClassAnnotationData)}, - {CC "getEncodedExecutableAnnotationData", CC "(" HS_METHOD2 OBJECT "IJ)[B", FN_PTR(getEncodedExecutableAnnotationData)}, - {CC "getEncodedFieldAnnotationData", CC "(" HS_KLASS2 "I" OBJECT "IJ)[B", FN_PTR(getEncodedFieldAnnotationData)}, + {CC "getEncodedClassAnnotationValues", CC "(" HS_KLASS2 OBJECT "IJ)[B", FN_PTR(getEncodedClassAnnotationValues)}, + {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 OBJECT "IJ)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, + {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "I" OBJECT "IJ)[B", FN_PTR(getEncodedFieldAnnotationValues)}, {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, {CC "getFailedSpeculationsAddress", CC "(" HS_METHOD2 ")J", FN_PTR(getFailedSpeculationsAddress)}, {CC "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)}, diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java index 9567c1d099c5b..04b8a62bd2073 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java @@ -80,7 +80,7 @@ public static Map, Annotation> parseAnnotations( } /** - * Like {@link #parseAnnotations(byte[], sun.reflect.ConstantPool, Class)} + * Like {@link #parseAnnotations(byte[], jdk.internal.reflect.ConstantPool, Class)} * with an additional parameter {@code selectAnnotationClasses} which selects the * annotation types to parse (other than selected are quickly skipped).

* This method is used to parse select meta annotations in the construction @@ -115,8 +115,7 @@ private static Map, Annotation> parseAnnotations2( Class container, boolean eagerResolution, Class[] selectAnnotationClasses) { - Map, Annotation> result = - new LinkedHashMap, Annotation>(); + Map, Annotation> result = new LinkedHashMap<>(); ByteBuffer buf = ByteBuffer.wrap(rawAnnotations); int numAnnotations = buf.getShort() & 0xFFFF; for (int i = 0; i < numAnnotations; i++) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationDataDecoder.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java similarity index 82% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationDataDecoder.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java index 785d8e15785e4..a6dca140ebb0a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationDataDecoder.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java @@ -26,7 +26,7 @@ import java.util.List; import jdk.internal.vm.VMSupport.AnnotationDecoder; -import jdk.vm.ci.meta.AnnotationData; +import jdk.vm.ci.meta.AnnotationValue; import jdk.vm.ci.meta.EnumArrayData; import jdk.vm.ci.meta.EnumData; import jdk.vm.ci.meta.ErrorData; @@ -37,14 +37,14 @@ /** * Implementation of {@link AnnotationDecoder} that resolves type names to {@link JavaType} values - * and employs {@link AnnotationData} and {@link EnumData} to represent decoded annotations and enum + * and employs {@link AnnotationValue} and {@link EnumData} to represent decoded annotations and enum * constants respectively. */ -final class AnnotationDataDecoder implements AnnotationDecoder { +final class AnnotationValueDecoder implements AnnotationDecoder { private final HotSpotResolvedJavaType accessingClass; - AnnotationDataDecoder(HotSpotResolvedJavaType accessingClass) { + AnnotationValueDecoder(HotSpotResolvedJavaType accessingClass) { this.accessingClass = accessingClass; } @@ -55,8 +55,8 @@ public ResolvedJavaType resolveType(String name) { } @Override - public AnnotationData newAnnotation(ResolvedJavaType type, Map.Entry[] elements) { - return new AnnotationData(type, elements); + public AnnotationValue newAnnotation(ResolvedJavaType type, Map.Entry[] elements) { + return new AnnotationValue(type, elements); } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index b25f7a092560c..e797ce43b8c00 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -1447,43 +1447,43 @@ native void notifyCompilerInliningEvent(int compileId, HotSpotResolvedJavaMethod * Gets the serialized annotation info for {@code type} by calling * {@code VMSupport.encodeAnnotations} in the HotSpot heap. */ - byte[] getEncodedClassAnnotationData(HotSpotResolvedObjectTypeImpl type, ResolvedJavaType[] filter) { + byte[] getEncodedClassAnnotationValues(HotSpotResolvedObjectTypeImpl type, ResolvedJavaType[] filter) { try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedClassAnnotationData(type, type.getKlassPointer(), + return getEncodedClassAnnotationValues(type, type.getKlassPointer(), a.types, a.types.length, a.buffer()); } } - native byte[] getEncodedClassAnnotationData(HotSpotResolvedObjectTypeImpl type, long klassPointer, - Object filter, int filterLength, long filterKlassPointers); + native byte[] getEncodedClassAnnotationValues(HotSpotResolvedObjectTypeImpl type, long klassPointer, + Object filter, int filterLength, long filterKlassPointers); /** * Gets the serialized annotation info for {@code method} by calling * {@code VMSupport.encodeAnnotations} in the HotSpot heap. */ - byte[] getEncodedExecutableAnnotationData(HotSpotResolvedJavaMethodImpl method, ResolvedJavaType[] filter) { + byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, ResolvedJavaType[] filter) { try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedExecutableAnnotationData(method, method.getMethodPointer(), + return getEncodedExecutableAnnotationValues(method, method.getMethodPointer(), a.types, a.types.length, a.buffer()); } } - native byte[] getEncodedExecutableAnnotationData(HotSpotResolvedJavaMethodImpl method, long methodPointer, - Object filter, int filterLength, long filterKlassPointers); + native byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, long methodPointer, + Object filter, int filterLength, long filterKlassPointers); /** * Gets the serialized annotation info for the field denoted by {@code holder} and * {@code fieldIndex} by calling {@code VMSupport.encodeAnnotations} in the HotSpot heap. */ - byte[] getEncodedFieldAnnotationData(HotSpotResolvedObjectTypeImpl holder, int fieldIndex, ResolvedJavaType[] filter) { + byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, int fieldIndex, ResolvedJavaType[] filter) { try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedFieldAnnotationData(holder, holder.getKlassPointer(), fieldIndex, + return getEncodedFieldAnnotationValues(holder, holder.getKlassPointer(), fieldIndex, a.types, a.types.length, a.buffer()); } } - native byte[] getEncodedFieldAnnotationData(HotSpotResolvedObjectTypeImpl holder, long klassPointer, int fieldIndex, - Object filterTypes, int filterLength, long filterKlassPointers); + native byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, long klassPointer, int fieldIndex, + Object filterTypes, int filterLength, long filterKlassPointers); /** * Helper for passing {@Klass*} values to native code. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index cb382b0ccb2a3..3976727b2127a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -32,11 +32,10 @@ import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; import java.lang.annotation.Annotation; -import java.util.Collections; import java.util.List; import jdk.internal.vm.VMSupport; -import jdk.vm.ci.meta.AnnotationData; +import jdk.vm.ci.meta.AnnotationValue; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaType; @@ -235,25 +234,25 @@ public JavaConstant getConstantValue() { } @Override - public AnnotationData getAnnotationData(ResolvedJavaType annotationType) { + public AnnotationValue getAnnotationValue(ResolvedJavaType annotationType) { if (!hasAnnotations()) { checkIsAnnotation(annotationType); return null; } - return getFirstAnnotationOrNull(getAnnotationData0(annotationType)); + return getFirstAnnotationOrNull(getAnnotationValues0(annotationType)); } @Override - public List getSelectedAnnotationData(ResolvedJavaType... types) { + public List getAnnotationValues(ResolvedJavaType... types) { checkAreAnnotations(types); if (!hasAnnotations()) { return List.of(); } - return getAnnotationData0(types); + return getAnnotationValues0(types); } - private List getAnnotationData0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedFieldAnnotationData(holder, index, filter); - return VMSupport.decodeAnnotations(encoded, new AnnotationDataDecoder(getDeclaringClass())); + private List getAnnotationValues0(ResolvedJavaType... filter) { + byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, filter); + return VMSupport.decodeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index e93a907571b23..a142aa19b26d1 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -39,14 +39,12 @@ import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.BitSet; -import java.util.Collections; import java.util.List; -import java.util.Objects; import jdk.internal.vm.VMSupport; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; -import jdk.vm.ci.meta.AnnotationData; +import jdk.vm.ci.meta.AnnotationValue; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.DefaultProfilingInfo; @@ -776,26 +774,26 @@ public int methodIdnum() { } @Override - public AnnotationData getAnnotationData(ResolvedJavaType type) { + public AnnotationValue getAnnotationValue(ResolvedJavaType type) { if (!hasAnnotations()) { checkIsAnnotation(type); return null; } - return getFirstAnnotationOrNull(getAnnotationData0(type)); + return getFirstAnnotationOrNull(getAnnotationValues0(type)); } @Override - public List getSelectedAnnotationData(ResolvedJavaType... types) { + public List getAnnotationValues(ResolvedJavaType... types) { checkAreAnnotations(types); if (!hasAnnotations()) { return List.of(); } - return getAnnotationData0(types); + return getAnnotationValues0(types); } - private List getAnnotationData0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedExecutableAnnotationData(this, filter); - return VMSupport.decodeAnnotations(encoded, new AnnotationDataDecoder(getDeclaringClass())); + private List getAnnotationValues0(ResolvedJavaType... filter) { + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, filter); + return VMSupport.decodeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index ab634568a84f0..db63b67f442fc 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -24,7 +24,7 @@ import java.util.List; -import jdk.vm.ci.meta.AnnotationData; +import jdk.vm.ci.meta.AnnotationValue; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaType; @@ -83,7 +83,7 @@ static void checkAreAnnotations(ResolvedJavaType... types) { } } - static AnnotationData getFirstAnnotationOrNull(List list) { + static AnnotationValue getFirstAnnotationOrNull(List list) { return list.isEmpty() ? null : list.get(0); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index aaa5c191dc417..9b3c2f524af6b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -34,15 +34,12 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.nio.ByteOrder; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import jdk.internal.vm.VMSupport; import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.AnnotationData; +import jdk.vm.ci.meta.AnnotationValue; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.Assumptions.ConcreteMethod; import jdk.vm.ci.meta.Assumptions.ConcreteSubtype; @@ -1118,25 +1115,25 @@ public boolean isCloneableWithAllocation() { } @Override - public AnnotationData getAnnotationData(ResolvedJavaType annotationType) { + public AnnotationValue getAnnotationValue(ResolvedJavaType annotationType) { if (!mayHaveAnnotations(true)) { checkIsAnnotation(annotationType); return null; } - return getFirstAnnotationOrNull(getAnnotationData0(annotationType)); + return getFirstAnnotationOrNull(getAnnotationValues0(annotationType)); } @Override - public List getSelectedAnnotationData(ResolvedJavaType... types) { + public List getAnnotationValues(ResolvedJavaType... types) { if (!mayHaveAnnotations(true)) { checkAreAnnotations(types); return List.of(); } - return getAnnotationData0(types); + return getAnnotationValues0(types); } - private List getAnnotationData0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedClassAnnotationData(this, filter); - return VMSupport.decodeAnnotations(encoded, new AnnotationDataDecoder(this)); + private List getAnnotationValues0(ResolvedJavaType... filter) { + byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, filter); + return VMSupport.decodeAnnotations(encoded, new AnnotationValueDecoder(this)); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index c1e38fa5a05a2..039edf9555e2d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -27,11 +27,10 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Modifier; -import java.util.Collections; import java.util.List; import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.AnnotationData; +import jdk.vm.ci.meta.AnnotationValue; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -342,13 +341,13 @@ public JavaConstant getJavaMirror() { } @Override - public AnnotationData getAnnotationData(ResolvedJavaType type) { + public AnnotationValue getAnnotationValue(ResolvedJavaType type) { checkIsAnnotation(type); return null; } @Override - public List getSelectedAnnotationData(ResolvedJavaType... types) { + public List getAnnotationValues(ResolvedJavaType... types) { checkAreAnnotations(types); return List.of(); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java index 513945093a1e5..4301d14a38a23 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java @@ -46,8 +46,8 @@ public interface Annotated { * @throws IllegalArgumentException if any type in {@code types} is not an annotation interface type * @throws UnsupportedOperationException if this operation is not supported */ - default List getSelectedAnnotationData(ResolvedJavaType... types) { - throw new UnsupportedOperationException(); + default List getAnnotationValues(ResolvedJavaType... types) { + throw new UnsupportedOperationException(this.getClass().getName()); } /** @@ -63,7 +63,7 @@ default List getSelectedAnnotationData(ResolvedJavaType... types * @throws IllegalArgumentException if {@code type} is not an annotation interface type * @throws UnsupportedOperationException if this operation is not supported */ - default AnnotationData getAnnotationData(ResolvedJavaType type) { - throw new UnsupportedOperationException(); + default AnnotationValue getAnnotationValue(ResolvedJavaType type) { + throw new UnsupportedOperationException(this.getClass().getName()); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationValue.java similarity index 87% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationData.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationValue.java index c5c98ba409a3b..1b21cc6eb137d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationValue.java @@ -23,7 +23,6 @@ package jdk.vm.ci.meta; import java.lang.annotation.Annotation; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -31,14 +30,14 @@ /** * Represents an annotation where element values are represented with the types described - * {@linkplain #get here}. - * + * {@linkplain #get here}. This is the JVMCI analog of an {@link Annotation} object. + *

* In contrast to the standard annotation API based on {@link Annotation}, use of - * {@link AnnotationData} allows annotations to be queried without the JVMCI runtime having to + * {@link AnnotationValue} allows annotations to be queried without the JVMCI runtime having to * support dynamic loading of arbitrary {@link Annotation} classes. Such support is impossible in a - * closed world, ahead-of-time compiled environment such as libgraal. + * closed world, ahead-of-time compiled environment such as Native Image. */ -public final class AnnotationData { +public final class AnnotationValue { private final ResolvedJavaType type; private final Map elements; @@ -56,14 +55,14 @@ public final class AnnotationData { ErrorData.class, EnumArrayData.class, EnumData.class, - AnnotationData.class); + AnnotationValue.class); /** * Creates an annotation. * * @param type the annotation interface of this annotation, represented as a {@link ResolvedJavaType} * @param elements the names and values of this annotation's element values. Each value's type - * must be one of the {@code AnnotationData} types described {@linkplain #get here} + * must be one of the {@code AnnotationValue} types described {@linkplain #get here} * or it must be a {@link ErrorData} object whose {@code toString()} value describes * the error raised while parsing the element. There is no distinction between a * value explicitly present in the annotation and an element's default value. @@ -72,7 +71,7 @@ public final class AnnotationData { * @throws NullPointerException if any of the above parameters is null or any entry in * {@code elements} is null */ - public AnnotationData(ResolvedJavaType type, Map.Entry[] elements) { + public AnnotationValue(ResolvedJavaType type, Map.Entry[] elements) { this.type = Objects.requireNonNull(type); for (Map.Entry e : elements) { checkEntry(e); @@ -99,7 +98,10 @@ private static void checkEntry(Map.Entry e) { } /** - * @return the annotation interface of this annotation, represented as a {@link ResolvedJavaType} + * Gets the annotation interface of this annotation, represented as + * a {@link ResolvedJavaType}. + * + * @see Annotation#annotationType() */ public ResolvedJavaType getAnnotationType() { return type; @@ -112,7 +114,7 @@ public ResolvedJavaType getAnnotationType() { * interface and the type of value returned by this method: * * - * + * * * * @@ -126,12 +128,12 @@ public ResolvedJavaType getAnnotationType() { * * * - * + * * * *
Annotation AnnotationData
Annotation AnnotationValue
boolean Boolean
byte Byte
Class ResolvedJavaType
Enum EnumData
Enum[] EnumArrayData
Annotation AnnotationData
Annotation AnnotationValue
[]T[] where T is one of the above types except for EnumData or EnumArrayData
* - * @param the type of the element as per the {@code AnnotationData} column in the above + * @param the type of the element as per the {@code AnnotationValue} column in the above * table or {@link Object} * @param elementType the class for the type of the element * @return the annotation element denoted by {@code name} @@ -145,7 +147,7 @@ public V get(String name, Class elementType) { if (val == null) { throw new IllegalArgumentException("no element named " + name); } - Class valClass = val.getClass(); + Class valClass = val.getClass(); if (valClass == ErrorData.class) { throw new IllegalArgumentException(val.toString()); } @@ -162,8 +164,7 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (obj instanceof AnnotationData) { - AnnotationData that = (AnnotationData) obj; + if (obj instanceof AnnotationValue that) { return this.type.equals(that.type) && this.elements.equals(that.elements); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumArrayData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumArrayData.java index 600283bc8ca82..f21708c978b64 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumArrayData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumArrayData.java @@ -25,17 +25,24 @@ import java.util.List; /** - * Represents an array of enum constants within {@link AnnotationData}. + * Represents an array of enum constants within an {@link AnnotationValue}. */ public final class EnumArrayData { + /** + * The type of the enum. + */ public final ResolvedJavaType enumType; + + /** + * The names of the enum constants. + */ public final List names; /** * Creates an array of enum constants. * - * @param type the {@linkplain Enum enum type} - * @param name the names of the enum constants + * @param enumType the {@linkplain Enum enum type} + * @param names the names of the enum constants */ public EnumArrayData(ResolvedJavaType enumType, List names) { this.enumType = enumType; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java index 31f87ec5b6ec5..9d3eedc49f96d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java @@ -23,16 +23,23 @@ package jdk.vm.ci.meta; /** - * Represents an enum constant within {@link AnnotationData}. + * Represents an enum constant within an {@link AnnotationValue}. */ public final class EnumData { + /** + * The type of the enum. + */ public final ResolvedJavaType enumType; + + /** + * The name of the enum constants. + */ public final String name; /** * Creates an enum constant. * - * @param type the {@linkplain Enum enum type} + * @param enumType the {@linkplain Enum enum type} * @param name the {@linkplain Enum#name() name} of the enum */ public EnumData(ResolvedJavaType enumType, String name) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ErrorData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ErrorData.java index 72177ddcbbcb4..9014b010cf5ad 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ErrorData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ErrorData.java @@ -23,9 +23,9 @@ package jdk.vm.ci.meta; /** - * Represents an error constant within {@link AnnotationData}. - * - * Similar to {@code sun.reflect.annotation.ExceptionProxy}. + * Represents an error constant within an {@link AnnotationValue}. + *

+ * Similar to {@link sun.reflect.annotation.ExceptionProxy}. */ public final class ErrorData { private final String description; diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java index 8e9be9eda37d1..7742103f8b81f 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java @@ -194,10 +194,10 @@ private Method findTestMethod(Method apiMethod) { } @Test - public void getAnnotationDataTest() throws Exception { - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredField("annotatedField")); + public void getAnnotationValueTest() throws Exception { + TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredField("annotatedField")); for (Field f : fields.keySet()) { - TestResolvedJavaType.getAnnotationDataTest(f); + TestResolvedJavaType.getAnnotationValueTest(f); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index c1d34e5228e6a..1d7940947ab39 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -51,7 +51,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import java.io.DataInputStream; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -66,8 +65,6 @@ import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -90,7 +87,6 @@ import java.lang.classfile.CodeElement; import java.lang.classfile.MethodModel; import java.lang.classfile.Instruction; -import java.lang.classfile.attribute.CodeAttribute; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ExceptionHandler; @@ -99,10 +95,10 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.Annotation1; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.Annotation2; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.Annotation3; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.NumbersDE; +import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.Annotation1; +import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.Annotation2; +import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.Annotation3; +import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.NumbersDE; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; /** @@ -544,9 +540,9 @@ public void testVirtualMethodTableAccess() { } /** - * Encapsulates input for {@link TestResolvedJavaMethod#getAnnotationDataTest}. + * Encapsulates input for {@link TestResolvedJavaMethod#getAnnotationValueTest}. */ - static class AnnotationDataTest { + static class AnnotationValueTest { public enum NumbersEN { One, @@ -587,36 +583,36 @@ static void methodWithThreeAnnotations() { } @Test - public void getAnnotationDataTest() throws Exception { - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingAnnotation")); + public void getAnnotationValueTest() throws Exception { + TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); + TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("missingAnnotation")); try { - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingNestedAnnotation")); + TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("missingNestedAnnotation")); throw new AssertionError("expected " + NoClassDefFoundError.class.getName()); } catch (NoClassDefFoundError e) { Assert.assertEquals("jdk/internal/vm/test/AnnotationTestInput$Missing", e.getMessage()); } - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingTypeOfClassMember")); - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingMember")); - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("changeTypeOfMember")); + TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("missingTypeOfClassMember")); + TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("missingMember")); + TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("changeTypeOfMember")); for (Method m : methods.keySet()) { - TestResolvedJavaType.getAnnotationDataTest(m); + TestResolvedJavaType.getAnnotationValueTest(m); } - ResolvedJavaMethod m = metaAccess.lookupJavaMethod(AnnotationDataTest.class.getDeclaredMethod("methodWithThreeAnnotations")); + ResolvedJavaMethod m = metaAccess.lookupJavaMethod(AnnotationValueTest.class.getDeclaredMethod("methodWithThreeAnnotations")); ResolvedJavaType a1 = metaAccess.lookupJavaType(Annotation1.class); ResolvedJavaType a2 = metaAccess.lookupJavaType(Annotation2.class); ResolvedJavaType a3 = metaAccess.lookupJavaType(Annotation3.class); - ResolvedJavaType a4 = metaAccess.lookupJavaType(AnnotationDataTest.class); + ResolvedJavaType a4 = metaAccess.lookupJavaType(AnnotationValueTest.class); ResolvedJavaType numbersDEType = metaAccess.lookupJavaType(NumbersDE.class); // Ensure NumbersDE is not initialized before Annotation2 is requested Assert.assertFalse(numbersDEType.isInitialized()); - Assert.assertEquals(2, m.getSelectedAnnotationData(a1, a3).size()); + Assert.assertEquals(2, m.getAnnotationValues(a1, a3).size()); // Ensure NumbersDE is not initialized after Annotation2 is requested - Assert.assertNotNull(m.getAnnotationData(a2)); + Assert.assertNotNull(m.getAnnotationValue(a2)); Assert.assertFalse(numbersDEType.isInitialized()); } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index a0407b2ddeb5d..9f07b303d1538 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -93,7 +93,7 @@ import jdk.internal.vm.test.AnnotationTestInput; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Annotated; -import jdk.vm.ci.meta.AnnotationData; +import jdk.vm.ci.meta.AnnotationValue; import jdk.vm.ci.meta.EnumArrayData; import jdk.vm.ci.meta.EnumData; import jdk.vm.ci.meta.Assumptions.AssumptionResult; @@ -1245,12 +1245,12 @@ private Method findTestMethod(Method apiMethod) { } @Test - public void getAnnotationDataTest() throws Exception { - getAnnotationDataTest(AnnotationTestInput.AnnotatedClass.class); - getAnnotationDataTest(int.class); - getAnnotationDataTest(void.class); + public void getAnnotationValueTest() throws Exception { + getAnnotationValueTest(AnnotationTestInput.AnnotatedClass.class); + getAnnotationValueTest(int.class); + getAnnotationValueTest(void.class); for (Class c : classes) { - getAnnotationDataTest(c); + getAnnotationValueTest(c); } // Primitive classes have no annotations but we cannot directly @@ -1260,22 +1260,22 @@ public void getAnnotationDataTest() throws Exception { ResolvedJavaType overrideType = metaAccess.lookupJavaType(Override.class); for (Class c : prims) { ResolvedJavaType type = metaAccess.lookupJavaType(c); - AnnotationData ad = type.getAnnotationData(overrideType); - Assert.assertNull(String.valueOf(ad), ad); - List adArray = type.getSelectedAnnotationData(overrideType, overrideType); - Assert.assertEquals(0, adArray.size()); + AnnotationValue av = type.getAnnotationValue(overrideType); + Assert.assertNull(String.valueOf(av), av); + List avArray = type.getAnnotationValues(overrideType, overrideType); + Assert.assertEquals(0, avArray.size()); } // Test that inherited annotations are handled properly. ResolvedJavaType namedType = metaAccess.lookupJavaType(AnnotationTestInput.Named.class); - AnnotationData ad = metaAccess.lookupJavaType(AnnotationTestInput.OwnName.class).getAnnotationData(namedType); - Assert.assertEquals("NonInheritedValue", ad.get("value", String.class)); - ad = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName1.class).getAnnotationData(namedType); - Assert.assertEquals("Super1", ad.get("value", String.class)); - ad = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName2.class).getAnnotationData(namedType); - Assert.assertEquals("Super2", ad.get("value", String.class)); - ad = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName3.class).getAnnotationData(namedType); - Assert.assertEquals("Super1", ad.get("value", String.class)); + AnnotationValue av = metaAccess.lookupJavaType(AnnotationTestInput.OwnName.class).getAnnotationValue(namedType); + Assert.assertEquals("NonInheritedValue", av.get("value", String.class)); + av = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName1.class).getAnnotationValue(namedType); + Assert.assertEquals("Super1", av.get("value", String.class)); + av = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName2.class).getAnnotationValue(namedType); + Assert.assertEquals("Super2", av.get("value", String.class)); + av = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName3.class).getAnnotationValue(namedType); + Assert.assertEquals("Super1", av.get("value", String.class)); } // @formatter:off @@ -1321,12 +1321,12 @@ private static boolean isSignaturePolymorphic(ResolvedJavaMethod method) { return method.getAnnotation(SIGNATURE_POLYMORPHIC_CLASS) != null; } - private static void getAnnotationDataExpectedToFail(Annotated annotated, ResolvedJavaType... annotationTypes) { + private static void getAnnotationValueExpectedToFail(Annotated annotated, ResolvedJavaType... annotationTypes) { try { if (annotationTypes.length == 1) { - annotated.getAnnotationData(annotationTypes[0]); + annotated.getAnnotationValue(annotationTypes[0]); } else { - annotated.getSelectedAnnotationData(annotationTypes); + annotated.getAnnotationValues(annotationTypes); } String s = Stream.of(annotationTypes).map(ResolvedJavaType::toJavaName).collect(Collectors.joining(", ")); throw new AssertionError("Expected IllegalArgumentException for retrieving (" + s + " from " + annotated); @@ -1336,43 +1336,43 @@ private static void getAnnotationDataExpectedToFail(Annotated annotated, Resolve } /** - * Tests that {@link AnnotationData} obtained from a {@link Class}, {@link Method} or + * Tests that {@link AnnotationValue} obtained from a {@link Class}, {@link Method} or * {@link Field} matches {@link AnnotatedElement#getAnnotations()} for the corresponding JVMCI * object. * * @param annotatedElement a {@link Class}, {@link Method} or {@link Field} object */ - public static void getAnnotationDataTest(AnnotatedElement annotatedElement) throws Exception { + public static void getAnnotationValueTest(AnnotatedElement annotatedElement) throws Exception { Annotated annotated = toAnnotated(annotatedElement); ResolvedJavaType objectType = metaAccess.lookupJavaType(Object.class); ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); - getAnnotationDataExpectedToFail(annotated, objectType); - getAnnotationDataExpectedToFail(annotated, suppressWarningsType, objectType); - getAnnotationDataExpectedToFail(annotated, suppressWarningsType, suppressWarningsType, objectType); + getAnnotationValueExpectedToFail(annotated, objectType); + getAnnotationValueExpectedToFail(annotated, suppressWarningsType, objectType); + getAnnotationValueExpectedToFail(annotated, suppressWarningsType, suppressWarningsType, objectType); // Check that querying a missing annotation returns null or an empty list - assertNull(annotated.getAnnotationData(suppressWarningsType)); - List data = annotated.getSelectedAnnotationData(suppressWarningsType, suppressWarningsType); - assertTrue(data.toString(), data.isEmpty()); - data = annotated.getSelectedAnnotationData(suppressWarningsType, suppressWarningsType, suppressWarningsType, suppressWarningsType); - assertTrue(data.toString(), data.isEmpty()); + assertNull(annotated.getAnnotationValue(suppressWarningsType)); + List values = annotated.getAnnotationValues(suppressWarningsType, suppressWarningsType); + assertTrue(values.toString(), values.isEmpty()); + values = annotated.getAnnotationValues(suppressWarningsType, suppressWarningsType, suppressWarningsType, suppressWarningsType); + assertTrue(values.toString(), values.isEmpty()); - testGetAnnotationData(annotatedElement, annotated, List.of(annotatedElement.getAnnotations())); + testGetAnnotationValue(annotatedElement, annotated, List.of(annotatedElement.getAnnotations())); } - private static void testGetAnnotationData(AnnotatedElement annotatedElement, Annotated annotated, List annotations) throws AssertionError { + private static void testGetAnnotationValue(AnnotatedElement annotatedElement, Annotated annotated, List annotations) throws AssertionError { ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); for (Annotation a : annotations) { var annotationType = metaAccess.lookupJavaType(a.annotationType()); - AnnotationData ad = annotated.getAnnotationData(annotationType); - assertAnnotationsEquals(a, ad); + AnnotationValue av = annotated.getAnnotationValue(annotationType); + assertAnnotationsEquals(a, av); // Check that encoding/decoding produces a stable result - AnnotationData ad2 = annotated.getAnnotationData(annotationType); - assertEquals(ad, ad2); + AnnotationValue av2 = annotated.getAnnotationValue(annotationType); + assertEquals(av, av2); - List annotationData = annotated.getSelectedAnnotationData(annotationType, suppressWarningsType, suppressWarningsType); - assertEquals(1, annotationData.size()); + List annotationValues = annotated.getAnnotationValues(annotationType, suppressWarningsType, suppressWarningsType); + assertEquals(1, annotationValues.size()); } if (annotations.size() < 2) { return; @@ -1381,13 +1381,13 @@ private static void testGetAnnotationData(AnnotatedElement annotatedElement, Ann ResolvedJavaType[] types = annotations.// stream().map(a -> metaAccess.lookupJavaType(a.annotationType())).// toArray(ResolvedJavaType[]::new); - List annotationData = annotated.getSelectedAnnotationData(types); - assertEquals(types.length, annotationData.size()); + List annotationValues = annotated.getAnnotationValues(types); + assertEquals(types.length, annotationValues.size()); - for (int j = 0; j < annotationData.size(); j++) { + for (int j = 0; j < annotationValues.size(); j++) { Annotation a = annotations.get(j); - AnnotationData ad = annotationData.get(j); - assertAnnotationsEquals(a, ad); + AnnotationValue av = annotationValues.get(j); + assertAnnotationsEquals(a, av); } } } @@ -1407,76 +1407,76 @@ private static UnresolvedJavaType asType(Class valueType) { return UnresolvedJavaType.create(MetaUtil.toInternalName(valueType.getName())); } - private static void assertAnnotationsEquals(Annotation a, AnnotationData ad) { + private static void assertAnnotationsEquals(Annotation a, AnnotationValue av) { Map values = AnnotationSupport.memberValues(a); for (Map.Entry e : values.entrySet()) { String name = e.getKey(); - Object aValue = e.getValue(); - Object adValue; + Object aElement = e.getValue(); + Object avElement; try { - adValue = ad.get(name, Object.class); + avElement = av.get(name, Object.class); } catch (IllegalArgumentException ex) { - assertEquals(aValue.toString(), ex.getMessage()); + assertEquals(aElement.toString(), ex.getMessage()); continue; } try { - assertAnnotationElementsEqual(aValue, adValue); + assertAnnotationElementsEqual(aElement, avElement); } catch (ClassCastException ex) { - throw new AssertionError(a.getClass().getName() + "." + name + " has wrong type: " + adValue.getClass().getName(), ex); + throw new AssertionError(a.getClass().getName() + "." + name + " has wrong type: " + avElement.getClass().getName(), ex); } } } - private static void assertAnnotationElementsEqual(Object aValue, Object adValue) { - Class valueType = aValue.getClass(); + private static void assertAnnotationElementsEqual(Object aElement, Object avElement) { + Class valueType = aElement.getClass(); if (valueType.isEnum()) { - String adEnumName = ((EnumData) adValue).name; - String aEnumName = ((Enum) aValue).name(); - assertEquals(adEnumName, aEnumName); - } else if (aValue instanceof Class) { - assertClassObjectsEquals(aValue, adValue); - } else if (aValue instanceof Annotation) { - assertAnnotationObjectsEquals(aValue, adValue); + String avEnumName = ((EnumData) avElement).name; + String aEnumName = ((Enum) aElement).name(); + assertEquals(avEnumName, aEnumName); + } else if (aElement instanceof Class) { + assertClassObjectsEquals(aElement, avElement); + } else if (aElement instanceof Annotation) { + assertAnnotationObjectsEquals(aElement, avElement); } else if (valueType.isArray()) { - int length = Array.getLength(aValue); + int length = Array.getLength(aElement); if (valueType.getComponentType().isEnum()) { - EnumArrayData array = (EnumArrayData) adValue; + EnumArrayData array = (EnumArrayData) avElement; assertEquals(length, array.names.size()); for (int i = 0; i < length; i++) { - String adEnumName = array.names.get(i); - String aEnumName = ((Enum) Array.get(aValue, i)).name(); - assertEquals(adEnumName, aEnumName); + String avEnumName = array.names.get(i); + String aEnumName = ((Enum) Array.get(aElement, i)).name(); + assertEquals(avEnumName, aEnumName); } } else { - List adList = (List) adValue; - assertEquals(length, adList.size()); + List avList = (List) avElement; + assertEquals(length, avList.size()); for (int i = 0; i < length; i++) { - assertAnnotationElementsEqual(Array.get(aValue, i), adList.get(i)); + assertAnnotationElementsEqual(Array.get(aElement, i), avList.get(i)); } } } else { - assertEquals(aValue.getClass(), adValue.getClass()); - assertEquals(aValue, adValue); + assertEquals(aElement.getClass(), avElement.getClass()); + assertEquals(aElement, avElement); } } - private static void assertClassObjectsEquals(Object aValue, Object adValue) { - String aName = ((Class) aValue).getName(); - String adName = ((JavaType) adValue).toClassName(); - assertEquals(aName, adName); + private static void assertClassObjectsEquals(Object aElement, Object avElement) { + String aName = ((Class) aElement).getName(); + String avName = ((JavaType) avElement).toClassName(); + assertEquals(aName, avName); } - private static void assertAnnotationObjectsEquals(Object aValue, Object adValue) { - Annotation aAnnotation = (Annotation) aValue; - AnnotationData adAnnotation = (AnnotationData) adValue; - assertAnnotationsEquals(aAnnotation, adAnnotation); + private static void assertAnnotationObjectsEquals(Object aElement, Object avElement) { + Annotation aAnnotation = (Annotation) aElement; + AnnotationValue avAnnotation = (AnnotationValue) avElement; + assertAnnotationsEquals(aAnnotation, avAnnotation); } - private static void assertArraysEqual(Object aValue, Object adValue, int length, BiConsumer assertEqualty) { - Object[] aArray = (Object[]) aValue; - Object[] adArray = (Object[]) adValue; + private static void assertArraysEqual(Object aElement, Object avElement, int length, BiConsumer assertEqualty) { + Object[] aArray = (Object[]) aElement; + Object[] avArray = (Object[]) avElement; for (int i = 0; i < length; i++) { - assertEqualty.accept(aArray[i], adArray[i]); + assertEqualty.accept(aArray[i], avArray[i]); } } } diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java index 446fb891ac445..760a720f208c1 100644 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java @@ -324,6 +324,9 @@ public static class AnnotatedClass {} Single[] value(); } + /** + * The class file for this class should be removed by a `@clean` jtreg command. + */ @Retention(RetentionPolicy.RUNTIME) public @interface Missing {} From 991624cfd0ea9c801673d4590a9a3c53c347fab8 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 11:59:44 +0200 Subject: [PATCH 03/20] removed unused code --- .../ci/runtime/test/TestResolvedJavaType.java | 51 +------------------ 1 file changed, 2 insertions(+), 49 deletions(-) diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index 9f07b303d1538..e0ac6948654fc 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -46,10 +46,7 @@ package jdk.vm.ci.runtime.test; import static java.lang.reflect.Modifier.isAbstract; -import static java.lang.reflect.Modifier.isFinal; import static java.lang.reflect.Modifier.isPrivate; -import static java.lang.reflect.Modifier.isProtected; -import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; import static jdk.vm.ci.meta.MetaUtil.internalNameToJava; import static jdk.vm.ci.meta.MetaUtil.toInternalName; @@ -75,8 +72,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.function.BiConsumer; import java.util.function.Supplier; import java.util.HashMap; import java.util.HashSet; @@ -710,40 +705,6 @@ public void getArrayClassTest() { } } - static class Declarations { - - final Method implementation; - final Set declarations; - - Declarations(Method impl) { - this.implementation = impl; - declarations = new HashSet<>(); - } - } - - /** - * See Method - * overriding. - */ - static boolean isOverriderOf(Method impl, Method m) { - if (!isPrivate(m.getModifiers()) && !isFinal(m.getModifiers())) { - if (m.getName().equals(impl.getName())) { - if (m.getReturnType() == impl.getReturnType()) { - if (Arrays.equals(m.getParameterTypes(), impl.getParameterTypes())) { - if (isPublic(m.getModifiers()) || isProtected(m.getModifiers())) { - // m is public or protected - return isPublic(impl.getModifiers()) || isProtected(impl.getModifiers()); - } else { - // m is package-private - return impl.getDeclaringClass().getPackage() == m.getDeclaringClass().getPackage(); - } - } - } - } - } - return false; - } - static final Map, VTable> vtables = new HashMap<>(); static class VTable { @@ -1245,7 +1206,7 @@ private Method findTestMethod(Method apiMethod) { } @Test - public void getAnnotationValueTest() throws Exception { + public void getAnnotationValueTest() { getAnnotationValueTest(AnnotationTestInput.AnnotatedClass.class); getAnnotationValueTest(int.class); getAnnotationValueTest(void.class); @@ -1342,7 +1303,7 @@ private static void getAnnotationValueExpectedToFail(Annotated annotated, Resolv * * @param annotatedElement a {@link Class}, {@link Method} or {@link Field} object */ - public static void getAnnotationValueTest(AnnotatedElement annotatedElement) throws Exception { + public static void getAnnotationValueTest(AnnotatedElement annotatedElement) { Annotated annotated = toAnnotated(annotatedElement); ResolvedJavaType objectType = metaAccess.lookupJavaType(Object.class); ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); @@ -1471,12 +1432,4 @@ private static void assertAnnotationObjectsEquals(Object aElement, Object avElem AnnotationValue avAnnotation = (AnnotationValue) avElement; assertAnnotationsEquals(aAnnotation, avAnnotation); } - - private static void assertArraysEqual(Object aElement, Object avElement, int length, BiConsumer assertEqualty) { - Object[] aArray = (Object[]) aElement; - Object[] avArray = (Object[]) avElement; - for (int i = 0; i < length; i++) { - assertEqualty.accept(aArray[i], avArray[i]); - } - } } From 27f393cc0c7e07fafbef6052094962a6d669e43e Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 15:54:01 +0200 Subject: [PATCH 04/20] extra JVMCI annotation testing --- .../runtime/test/TestResolvedJavaMethod.java | 13 +++++++- .../ci/runtime/test/TestResolvedJavaType.java | 12 ++++--- .../AnnotationTestInput.java | 17 ++++++++++ .../MemberAdded.java | 31 ++++++++++++++++++ .../alt/MemberAdded.java | 32 +++++++++++++++++++ 5 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberAdded.java create mode 100644 test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 1d7940947ab39..52d56e18f4717 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -27,10 +27,12 @@ * @library ../../../../../ * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java + * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java * TestResolvedJavaType.java * @clean jdk.internal.vm.test.AnnotationTestInput$Missing * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java + * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules jdk.internal.vm.ci/jdk.vm.ci.meta * jdk.internal.vm.ci/jdk.vm.ci.runtime @@ -77,10 +79,12 @@ import java.util.Objects; import java.util.Set; +import jdk.vm.ci.meta.AnnotationValue; import org.junit.Assert; import org.junit.Test; import jdk.internal.vm.test.AnnotationTestInput; +import jdk.internal.vm.test.MemberAdded; import java.lang.classfile.Attributes; import java.lang.classfile.ClassFile; import java.lang.classfile.ClassModel; @@ -593,8 +597,15 @@ public void getAnnotationValueTest() throws Exception { Assert.assertEquals("jdk/internal/vm/test/AnnotationTestInput$Missing", e.getMessage()); } TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("missingTypeOfClassMember")); - TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("missingMember")); TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("changeTypeOfMember")); + TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("missingMember")); + List avList = TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("addedMember")); + try { + avList.getFirst().get("addedElement", Integer.class); + throw new AssertionError("expected " + IllegalArgumentException.class.getName()); + } catch (IllegalArgumentException e) { + Assert.assertEquals("jdk.internal.vm.test.MemberAdded missing element addedElement", e.getMessage()); + } for (Method m : methods.keySet()) { TestResolvedJavaType.getAnnotationValueTest(m); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index e0ac6948654fc..ff51f357f7b97 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -1303,7 +1303,7 @@ private static void getAnnotationValueExpectedToFail(Annotated annotated, Resolv * * @param annotatedElement a {@link Class}, {@link Method} or {@link Field} object */ - public static void getAnnotationValueTest(AnnotatedElement annotatedElement) { + public static List getAnnotationValueTest(AnnotatedElement annotatedElement) { Annotated annotated = toAnnotated(annotatedElement); ResolvedJavaType objectType = metaAccess.lookupJavaType(Object.class); ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); @@ -1318,11 +1318,12 @@ public static void getAnnotationValueTest(AnnotatedElement annotatedElement) { values = annotated.getAnnotationValues(suppressWarningsType, suppressWarningsType, suppressWarningsType, suppressWarningsType); assertTrue(values.toString(), values.isEmpty()); - testGetAnnotationValue(annotatedElement, annotated, List.of(annotatedElement.getAnnotations())); + return testGetAnnotationValue(annotatedElement, annotated, List.of(annotatedElement.getAnnotations())); } - private static void testGetAnnotationValue(AnnotatedElement annotatedElement, Annotated annotated, List annotations) throws AssertionError { + private static List testGetAnnotationValue(AnnotatedElement annotatedElement, Annotated annotated, List annotations) throws AssertionError { ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); + List res = new ArrayList<>(annotations.size()); for (Annotation a : annotations) { var annotationType = metaAccess.lookupJavaType(a.annotationType()); AnnotationValue av = annotated.getAnnotationValue(annotationType); @@ -1334,9 +1335,11 @@ private static void testGetAnnotationValue(AnnotatedElement annotatedElement, An List annotationValues = annotated.getAnnotationValues(annotationType, suppressWarningsType, suppressWarningsType); assertEquals(1, annotationValues.size()); + + res.add(av); } if (annotations.size() < 2) { - return; + return res; } for (int i = 0; i < annotations.size(); i++) { ResolvedJavaType[] types = annotations.// @@ -1351,6 +1354,7 @@ private static void testGetAnnotationValue(AnnotatedElement annotatedElement, An assertAnnotationsEquals(a, av); } } + return res; } private static Annotated toAnnotated(AnnotatedElement element) { diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java index 760a720f208c1..3a16d53abaa28 100644 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java @@ -27,6 +27,7 @@ import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; public class AnnotationTestInput { @@ -366,6 +367,13 @@ public void missingTypeOfClassMember() {} @MemberDeleted(value = "evolving", retained = -34, deleted = 56) public void missingMember() {} + /** + * Method with an annotation that has a member + * added in a newer version of the annotation. + */ + @MemberAdded(value = "evolving") + public void addedMember() {} + /** * Method with an annotation that has a member named "any" * whose type is changed from int to String in a newer version @@ -374,5 +382,14 @@ public void missingMember() {} @MemberTypeChanged(value = "evolving", retained = -34, any = 56) public void changeTypeOfMember() {} + /** + * Tries to get the {@code added} element from the {@link MemberAdded} + * annotation on {@link #addedMember()} + * + * @param missingMember the Method object for {@link #addedMember()} + */ + public static MemberAdded getAddedElement(Method method) { + return method.getAnnotation(MemberAdded.class); + } } diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberAdded.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberAdded.java new file mode 100644 index 0000000000000..ecac36785051c --- /dev/null +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberAdded.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025, 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 jdk.internal.vm.test; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface MemberAdded { + String value(); +} diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java new file mode 100644 index 0000000000000..d2b8c0be19ddd --- /dev/null +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025, 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 jdk.internal.vm.test; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface MemberAdded { + String value(); + int addedElement(); +} From 61f61a7ea3634ae06a0269f7fb1190d29ad558da Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 16:08:08 +0200 Subject: [PATCH 05/20] model precise annotation parsing error types --- .../classes/jdk/internal/vm/VMSupport.java | 66 ++++++++++-------- .../AnnotationTypeMismatchExceptionProxy.java | 6 +- .../vm/ci/hotspot/AnnotationValueDecoder.java | 16 +++-- .../jdk/vm/ci/meta/AnnotationValue.java | 23 ++++--- .../jdk/vm/ci/meta/ElementTypeMismatch.java | 68 +++++++++++++++++++ .../meta/{ErrorData.java => MissingType.java} | 35 ++++++---- .../runtime/test/TestResolvedJavaField.java | 4 +- .../runtime/test/TestResolvedJavaMethod.java | 2 +- .../ci/runtime/test/TestResolvedJavaType.java | 57 +++++++++++++--- 9 files changed, 204 insertions(+), 73 deletions(-) create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ElementTypeMismatch.java rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/{ErrorData.java => MissingType.java} (61%) diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index cb2f789e5f7a7..f7fc41023792f 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -25,7 +25,6 @@ package jdk.internal.vm; import jdk.internal.misc.Unsafe; -import jdk.internal.misc.VM; import jdk.internal.access.SharedSecrets; import jdk.internal.access.JavaLangAccess; import jdk.internal.reflect.ConstantPool; @@ -39,7 +38,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.lang.annotation.Annotation; -import java.lang.annotation.IncompleteAnnotationException; +import java.lang.annotation.AnnotationTypeMismatchException; import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.LinkedHashMap; @@ -48,8 +47,10 @@ import java.util.Set; import java.util.List; +import sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy; import sun.reflect.annotation.EnumValue; import sun.reflect.annotation.EnumValueArray; +import sun.reflect.annotation.TypeNotPresentExceptionProxy; /* * Support class used by JVMCI, JVMTI and VM attach mechanism. @@ -263,8 +264,6 @@ private static void encodeAnnotation(DataOutputStream dos, Annotation a) throws Object value = e.getValue(); if (value == null) { // IncompleteAnnotationException - dos.writeByte('x'); - dos.writeUTF(new IncompleteAnnotationException(type, e.getKey()).toString()); continue; } Class valueType = value.getClass(); @@ -419,13 +418,16 @@ private static void encodeAnnotation(DataOutputStream dos, Annotation a) throws encodeAnnotation(dos, annotation); } } else { - dos.writeByte('x'); - dos.writeUTF(value.toString()); + throw new InternalError("Unsupported annotation element component type " + componentType); } - - } else { + } else if (value instanceof TypeNotPresentExceptionProxy proxy) { dos.writeByte('x'); - dos.writeUTF(value.toString()); + dos.writeUTF(proxy.typeName()); + } else if (value instanceof AnnotationTypeMismatchExceptionProxy proxy) { + dos.writeByte('y'); + dos.writeUTF(proxy.foundType()); + } else { + throw new InternalError("Unsupported annotation element type " + valueType); } } } @@ -438,9 +440,10 @@ private static void encodeAnnotation(DataOutputStream dos, Annotation a) throws * @param type of the object representing a decoded annotation * @param type of the object representing a decoded enum constant * @param type of the object representing a decoded array of enum constants - * @param type of the object representing a decoded error + * @param type of the object representing a missing type + * @param type of the object representing a decoded element type mismatch */ - public interface AnnotationDecoder { + public interface AnnotationDecoder { /** * Resolves a name in {@link Class#getName()} format to an object of type {@code T}. */ @@ -466,16 +469,25 @@ public interface AnnotationDecoder { * Creates an object representing a decoded enum constant. * * @param enumType the enum type - * @param name the name of the enum constant + * @param names the name of the enum constant */ EA newEnumValueArray(T enumType, List names); /** - * Creates an object representing a decoded error value. + * Creates an object representing a missing type. + * + * @param typeName see {@link TypeNotPresentException#typeName()} + */ + MT newMissingType(String typeName); + + /** + * Creates an object representing element of an annotation whose type + * has changed after the annotation was compiled. * - * @param description of the error + * @param foundType see {@link AnnotationTypeMismatchException#foundType()} */ - X newErrorValue(String description); + ETM newElementTypeMismatch(String foundType); + } /** @@ -484,11 +496,12 @@ public interface AnnotationDecoder { * @param type to which a type name is resolved * @param type of the object representing a decoded annotation * @param type of the object representing a decoded enum constant - * @param type of the object representing a decoded error + * @param type of the object representing a missing type + * @param type of the object representing a decoded element type mismatch * @return an immutable list of {@code A} objects */ @SuppressWarnings("unchecked") - public static List decodeAnnotations(byte[] encoded, AnnotationDecoder decoder) { + public static List decodeAnnotations(byte[] encoded, AnnotationDecoder decoder) { try { ByteArrayInputStream bais = new ByteArrayInputStream(encoded); DataInputStream dis = new DataInputStream(bais); @@ -499,7 +512,7 @@ public static List decodeAnnotations(byte[] encoded, Annotat } @SuppressWarnings({"rawtypes", "unchecked"}) - private static A decodeAnnotation(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + private static A decodeAnnotation(DataInputStream dis, AnnotationDecoder decoder) throws IOException { String typeName = dis.readUTF(); T type = decoder.resolveType(typeName); int n = readLength(dis); @@ -521,7 +534,8 @@ private static A decodeAnnotation(DataInputStream dis, Annotati case 'e' -> decoder.newEnumValue(decoder.resolveType(dis.readUTF()), dis.readUTF()); case '@' -> decodeAnnotation(dis, decoder); case '[' -> decodeArray(dis, decoder); - case 'x' -> decoder.newErrorValue(dis.readUTF()); + case 'x' -> decoder.newMissingType(dis.readUTF()); + case 'y' -> decoder.newElementTypeMismatch(dis.readUTF()); default -> throw new InternalError("Unsupported tag: " + tag); }); } @@ -532,7 +546,7 @@ interface IOReader { Object read() throws IOException; } - private static Object decodeArray(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + private static Object decodeArray(DataInputStream dis, AnnotationDecoder decoder) throws IOException { byte componentTag = dis.readByte(); return switch (componentTag) { case 'B' -> readArray(dis, dis::readByte); @@ -554,20 +568,12 @@ private static Object decodeArray(DataInputStream dis, Annotati }; } - /** - * Reads an enum encoded at the current read position of {@code dis} and - * returns it as an object of type {@code E}. - */ - private static E readEnum(DataInputStream dis, AnnotationDecoder decoder, T enumType) throws IOException { - return decoder.newEnumValue(enumType, dis.readUTF()); - } - /** * Reads an enum encoded at the current read position of {@code dis} and * returns it as an object of type {@code E}. */ @SuppressWarnings("unchecked") - private static EA readEnumArray(DataInputStream dis, AnnotationDecoder decoder, T enumType) throws IOException { + private static EA readEnumArray(DataInputStream dis, AnnotationDecoder decoder, T enumType) throws IOException { List names = (List) readArray(dis, dis::readUTF); return decoder.newEnumValueArray(enumType, names); } @@ -576,7 +582,7 @@ private static EA readEnumArray(DataInputStream dis, Annotation * Reads a class encoded at the current read position of {@code dis} and * returns it as an object of type {@code T}. */ - private static T readClass(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + private static T readClass(DataInputStream dis, AnnotationDecoder decoder) throws IOException { return decoder.resolveType(dis.readUTF()); } diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationTypeMismatchExceptionProxy.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationTypeMismatchExceptionProxy.java index 3daec7b0380c4..2e56c1f74e436 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationTypeMismatchExceptionProxy.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationTypeMismatchExceptionProxy.java @@ -33,7 +33,7 @@ * @author Josh Bloch * @since 1.5 */ -class AnnotationTypeMismatchExceptionProxy extends ExceptionProxy { +public class AnnotationTypeMismatchExceptionProxy extends ExceptionProxy { @java.io.Serial private static final long serialVersionUID = 7844069490309503934L; @SuppressWarnings("serial") // Not statically typed as Serializable @@ -59,6 +59,10 @@ protected RuntimeException generateException() { return new AnnotationTypeMismatchException(member, foundType); } + public String foundType() { + return foundType; + } + @Override public String toString() { return "/* Warning type mismatch! \"" + foundType + "\" */" ; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java index a6dca140ebb0a..a286e0f4aabd0 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java @@ -26,21 +26,22 @@ import java.util.List; import jdk.internal.vm.VMSupport.AnnotationDecoder; +import jdk.vm.ci.meta.ElementTypeMismatch; import jdk.vm.ci.meta.AnnotationValue; import jdk.vm.ci.meta.EnumArrayData; import jdk.vm.ci.meta.EnumData; -import jdk.vm.ci.meta.ErrorData; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.MissingType; import jdk.vm.ci.meta.UnresolvedJavaType; /** * Implementation of {@link AnnotationDecoder} that resolves type names to {@link JavaType} values - * and employs {@link AnnotationValue} and {@link EnumData} to represent decoded annotations and enum + * and employs {@link AnnotationValue} to represent decoded annotations and enum * constants respectively. */ -final class AnnotationValueDecoder implements AnnotationDecoder { +final class AnnotationValueDecoder implements AnnotationDecoder { private final HotSpotResolvedJavaType accessingClass; @@ -70,7 +71,12 @@ public EnumArrayData newEnumValueArray(ResolvedJavaType enumType, List n } @Override - public ErrorData newErrorValue(String description) { - return new ErrorData(description); + public MissingType newMissingType(String typeName) { + return new MissingType(typeName); + } + + @Override + public ElementTypeMismatch newElementTypeMismatch(String foundType) { + return new ElementTypeMismatch(foundType); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationValue.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationValue.java index 1b21cc6eb137d..20e657eb310cc 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationValue.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationValue.java @@ -52,7 +52,8 @@ public final class AnnotationValue { Long.class, Double.class, String.class, - ErrorData.class, + MissingType.class, + ElementTypeMismatch.class, EnumArrayData.class, EnumData.class, AnnotationValue.class); @@ -63,8 +64,8 @@ public final class AnnotationValue { * @param type the annotation interface of this annotation, represented as a {@link ResolvedJavaType} * @param elements the names and values of this annotation's element values. Each value's type * must be one of the {@code AnnotationValue} types described {@linkplain #get here} - * or it must be a {@link ErrorData} object whose {@code toString()} value describes - * the error raised while parsing the element. There is no distinction between a + * or it must be a {@link MissingType} or {@link ElementTypeMismatch} object for + * an error seen while parsing the element. There is no distinction between a * value explicitly present in the annotation and an element's default value. * @throws IllegalArgumentException if the value of an entry in {@code elements} is not of an * accepted type @@ -129,26 +130,26 @@ public ResolvedJavaType getAnnotationType() { * Enum EnumData * Enum[] EnumArrayData * Annotation AnnotationValue - * []T[] where T is one of the above types except for EnumData or EnumArrayData + * []List<T> where T is one of the above types except for EnumData or EnumArrayData * * * * @param the type of the element as per the {@code AnnotationValue} column in the above * table or {@link Object} - * @param elementType the class for the type of the element + * @param elementType the class for the type of the element or {@code Object.class} * @return the annotation element denoted by {@code name} - * @throws ClassCastException if the element is not of type {@code V} - * @throws IllegalArgumentException if this annotation has no element named {@code name} or if - * there was an error parsing or creating the element value + * @throws ClassCastException if the element is not of type {@code elementType} + * @throws IllegalArgumentException if this annotation has no element named {@code name} + * if {@code elementType != Object.class} and the element is of type + * {@link MissingType} or {@link ElementTypeMismatch} */ // @formatter:on public V get(String name, Class elementType) { Object val = elements.get(name); if (val == null) { - throw new IllegalArgumentException("no element named " + name); + throw new IllegalArgumentException(type.toJavaName() + " missing element " + name); } - Class valClass = val.getClass(); - if (valClass == ErrorData.class) { + if (elementType != Object.class && (val instanceof MissingType || val instanceof ElementTypeMismatch)) { throw new IllegalArgumentException(val.toString()); } return elementType.cast(val); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ElementTypeMismatch.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ElementTypeMismatch.java new file mode 100644 index 0000000000000..995c48f7635ed --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ElementTypeMismatch.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025, 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 jdk.vm.ci.meta; + +/** + * Represents a deferred {@link java.lang.annotation.AnnotationTypeMismatchException} within an {@link AnnotationValue}. + *

+ * Similar to {@code AnnotationTypeMismatchExceptionProxy}. + */ +public final class ElementTypeMismatch { + private final String foundType; + + /** + * @param foundType see {@link java.lang.annotation.AnnotationTypeMismatchException#foundType()} + */ + public ElementTypeMismatch(String foundType) { + this.foundType = foundType; + } + + @Override + public String toString() { + // Same value as AnnotationTypeMismatchExceptionProxy.toString() + return "/* Warning type mismatch! \"" + foundType + "\" */"; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ElementTypeMismatch that) { + return this.foundType.equals(that.foundType); + } + return false; + } + + @Override + public int hashCode() { + return foundType.hashCode(); + } + + /** + * @see java.lang.annotation.AnnotationTypeMismatchException#foundType() + */ + public String getFoundType() { + return foundType; + } +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ErrorData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MissingType.java similarity index 61% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ErrorData.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MissingType.java index 9014b010cf5ad..e535ecca28d38 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ErrorData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MissingType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 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 @@ -23,25 +23,24 @@ package jdk.vm.ci.meta; /** - * Represents an error constant within an {@link AnnotationValue}. + * Represents a deferred {@link TypeNotPresentException} within an {@link AnnotationValue}. *

- * Similar to {@link sun.reflect.annotation.ExceptionProxy}. + * Similar to {@code TypeNotPresentExceptionProxy}. */ -public final class ErrorData { - private final String description; +public final class MissingType { + private final String typeName; /** - * Creates an error constant. - * - * @param description description of the error + * @param typeName see {@link TypeNotPresentException#typeName()} */ - public ErrorData(String description) { - this.description = description; + public MissingType(String typeName) { + this.typeName = typeName; } @Override public String toString() { - return description; + // Same value as TypeNotPresentExceptionProxy.toString() + return typeName + ".class /* Warning: type not present! */"; } @Override @@ -49,15 +48,21 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (obj instanceof ErrorData) { - ErrorData that = (ErrorData) obj; - return this.description.equals(that.description); + if (obj instanceof MissingType that) { + return this.typeName.equals(that.typeName); } return false; } @Override public int hashCode() { - return description.hashCode(); + return typeName.hashCode(); + } + + /** + * @see TypeNotPresentException#typeName() + */ + public String getTypeName() { + return typeName; } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java index 7742103f8b81f..1df157f4e9d95 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -27,10 +27,12 @@ * @library ../../../../../ * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java + * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java * TestResolvedJavaType.java * @clean jdk.internal.vm.test.AnnotationTestInput$Missing * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java + * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules jdk.internal.vm.ci/jdk.vm.ci.meta * jdk.internal.vm.ci/jdk.vm.ci.hotspot diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 52d56e18f4717..048367faf3e3c 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index ff51f357f7b97..cf155c4791649 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -28,9 +28,11 @@ * @library /testlibrary/asm * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java + * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java * @clean jdk.internal.vm.test.AnnotationTestInput$Missing * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java + * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules java.base/jdk.internal.reflect * jdk.internal.vm.ci/jdk.vm.ci.meta @@ -81,6 +83,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.vm.ci.meta.ElementTypeMismatch; +import jdk.vm.ci.meta.MissingType; import org.junit.Assert; import org.junit.Test; @@ -102,6 +106,9 @@ import jdk.vm.ci.meta.UnresolvedJavaType; import sun.reflect.annotation.AnnotationSupport; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import sun.reflect.annotation.ExceptionProxy; +import sun.reflect.annotation.TypeNotPresentExceptionProxy; +import sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy; /** * Tests for {@link ResolvedJavaType}. @@ -1318,10 +1325,10 @@ public static List getAnnotationValueTest(AnnotatedElement anno values = annotated.getAnnotationValues(suppressWarningsType, suppressWarningsType, suppressWarningsType, suppressWarningsType); assertTrue(values.toString(), values.isEmpty()); - return testGetAnnotationValue(annotatedElement, annotated, List.of(annotatedElement.getAnnotations())); + return testGetAnnotationValue(annotated, List.of(annotatedElement.getAnnotations())); } - private static List testGetAnnotationValue(AnnotatedElement annotatedElement, Annotated annotated, List annotations) throws AssertionError { + private static List testGetAnnotationValue(Annotated annotated, List annotations) throws AssertionError { ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); List res = new ArrayList<>(annotations.size()); for (Annotation a : annotations) { @@ -1377,19 +1384,43 @@ private static void assertAnnotationsEquals(Annotation a, AnnotationValue av) { for (Map.Entry e : values.entrySet()) { String name = e.getKey(); Object aElement = e.getValue(); - Object avElement; - try { - avElement = av.get(name, Object.class); - } catch (IllegalArgumentException ex) { - assertEquals(aElement.toString(), ex.getMessage()); - continue; - } + Object avElement = av.get(name, Object.class); try { assertAnnotationElementsEqual(aElement, avElement); } catch (ClassCastException ex) { throw new AssertionError(a.getClass().getName() + "." + name + " has wrong type: " + avElement.getClass().getName(), ex); } + + if (!(aElement instanceof ExceptionProxy)) { + Class elementType = toAnnotationValueElementType(aElement.getClass()); + av.get(name, elementType); + } + } + } + + /** + * Gets the type of an element in {@link AnnotationValue} for {@code type}. + * + * @param type the type of an annotation element as returned by + * {@code AnnotationInvocationHandler} + */ + public static Class toAnnotationValueElementType(Class type) { + if (type == Class.class) { + return ResolvedJavaType.class; + } + if (Enum.class.isAssignableFrom(type)) { + return EnumData.class; + } + if (Enum[].class.isAssignableFrom(type)) { + return EnumArrayData.class; + } + if (Annotation.class.isAssignableFrom(type)) { + return AnnotationValue.class; + } + if (type.isArray()) { + return List.class; } + return type; } private static void assertAnnotationElementsEqual(Object aElement, Object avElement) { @@ -1402,6 +1433,14 @@ private static void assertAnnotationElementsEqual(Object aElement, Object avElem assertClassObjectsEquals(aElement, avElement); } else if (aElement instanceof Annotation) { assertAnnotationObjectsEquals(aElement, avElement); + } else if (aElement instanceof TypeNotPresentExceptionProxy proxy) { + assertTrue(avElement.toString(), avElement instanceof MissingType); + MissingType mt = (MissingType) avElement; + assertEquals(proxy.typeName(), mt.getTypeName()); + } else if (aElement instanceof AnnotationTypeMismatchExceptionProxy proxy) { + assertTrue(avElement.toString(), avElement instanceof ElementTypeMismatch); + ElementTypeMismatch etm = (ElementTypeMismatch) avElement; + assertEquals(proxy.foundType(), etm.getFoundType()); } else if (valueType.isArray()) { int length = Array.getLength(aElement); if (valueType.getComponentType().isEnum()) { From 931f71031326932e1f38f80b06908ab348bfacaa Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 19:49:58 +0200 Subject: [PATCH 06/20] moved JVMCI annotation classes into annotation package --- .../jdk/vm/ci/hotspot/AnnotationValueDecoder.java | 10 +++++----- .../vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java | 2 +- .../ci/hotspot/HotSpotResolvedJavaMethodImpl.java | 2 +- .../jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java | 2 +- .../ci/hotspot/HotSpotResolvedObjectTypeImpl.java | 2 +- .../vm/ci/hotspot/HotSpotResolvedPrimitiveType.java | 2 +- .../classes/jdk/vm/ci/meta/ResolvedJavaField.java | 2 ++ .../classes/jdk/vm/ci/meta/ResolvedJavaMethod.java | 3 ++- .../classes/jdk/vm/ci/meta/ResolvedJavaType.java | 1 + .../jdk/vm/ci/meta/{ => annotation}/Annotated.java | 4 +++- .../ci/meta/{ => annotation}/AnnotationValue.java | 4 +++- .../meta/{ => annotation}/ElementTypeMismatch.java | 2 +- .../vm/ci/meta/{ => annotation}/EnumArrayData.java | 4 +++- .../jdk/vm/ci/meta/{ => annotation}/EnumData.java | 4 +++- .../vm/ci/meta/{ => annotation}/MissingType.java | 2 +- .../vm/ci/runtime/test/TestResolvedJavaField.java | 1 + .../vm/ci/runtime/test/TestResolvedJavaMethod.java | 3 ++- .../vm/ci/runtime/test/TestResolvedJavaType.java | 13 +++++++------ 18 files changed, 39 insertions(+), 24 deletions(-) rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/{ => annotation}/Annotated.java (97%) rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/{ => annotation}/AnnotationValue.java (99%) rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/{ => annotation}/ElementTypeMismatch.java (98%) rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/{ => annotation}/EnumArrayData.java (96%) rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/{ => annotation}/EnumData.java (96%) rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/{ => annotation}/MissingType.java (98%) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java index a286e0f4aabd0..62b579b4b7e16 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java @@ -26,14 +26,14 @@ import java.util.List; import jdk.internal.vm.VMSupport.AnnotationDecoder; -import jdk.vm.ci.meta.ElementTypeMismatch; -import jdk.vm.ci.meta.AnnotationValue; -import jdk.vm.ci.meta.EnumArrayData; -import jdk.vm.ci.meta.EnumData; +import jdk.vm.ci.meta.annotation.ElementTypeMismatch; +import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.EnumArrayData; +import jdk.vm.ci.meta.annotation.EnumData; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.MissingType; +import jdk.vm.ci.meta.annotation.MissingType; import jdk.vm.ci.meta.UnresolvedJavaType; /** diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 3976727b2127a..e76c0271a3ad7 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -35,7 +35,7 @@ import java.util.List; import jdk.internal.vm.VMSupport; -import jdk.vm.ci.meta.AnnotationValue; +import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaType; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index a142aa19b26d1..b1a31a995e246 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -44,7 +44,7 @@ import jdk.internal.vm.VMSupport; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; -import jdk.vm.ci.meta.AnnotationValue; +import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.DefaultProfilingInfo; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index db63b67f442fc..eaeb41f2cb2f8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -24,7 +24,7 @@ import java.util.List; -import jdk.vm.ci.meta.AnnotationValue; +import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaType; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 9b3c2f524af6b..27155bd97eb98 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -39,7 +39,7 @@ import jdk.internal.vm.VMSupport; import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.AnnotationValue; +import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.Assumptions.ConcreteMethod; import jdk.vm.ci.meta.Assumptions.ConcreteSubtype; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index 039edf9555e2d..06f1fc8160727 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -30,7 +30,7 @@ import java.util.List; import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.AnnotationValue; +import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index cb891ab2e1ba1..0de311571e31f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -22,6 +22,8 @@ */ package jdk.vm.ci.meta; +import jdk.vm.ci.meta.annotation.Annotated; + import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Modifier; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index f401bc30f83ee..743df269c33a7 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -22,13 +22,14 @@ */ package jdk.vm.ci.meta; +import jdk.vm.ci.meta.annotation.Annotated; + import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; -import java.util.BitSet; /** * Represents a resolved Java method. Methods, like fields and types, are resolved through diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index cdb24c5f1adbf..eb3f8da62be67 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -26,6 +26,7 @@ import java.util.List; import jdk.vm.ci.meta.Assumptions.AssumptionResult; +import jdk.vm.ci.meta.annotation.Annotated; /** * Represents a resolved Java type. Types include primitives, objects, {@code void}, and arrays diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java similarity index 97% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java index 4301d14a38a23..474bba52e9e6e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java @@ -20,7 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.vm.ci.meta; +package jdk.vm.ci.meta.annotation; + +import jdk.vm.ci.meta.ResolvedJavaType; import java.lang.annotation.Inherited; import java.util.List; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationValue.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValue.java similarity index 99% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationValue.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValue.java index 20e657eb310cc..0df8b139e4bcf 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationValue.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValue.java @@ -20,7 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.vm.ci.meta; +package jdk.vm.ci.meta.annotation; + +import jdk.vm.ci.meta.ResolvedJavaType; import java.lang.annotation.Annotation; import java.util.List; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ElementTypeMismatch.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ElementTypeMismatch.java similarity index 98% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ElementTypeMismatch.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ElementTypeMismatch.java index 995c48f7635ed..14d48fbe92ad6 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ElementTypeMismatch.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ElementTypeMismatch.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.vm.ci.meta; +package jdk.vm.ci.meta.annotation; /** * Represents a deferred {@link java.lang.annotation.AnnotationTypeMismatchException} within an {@link AnnotationValue}. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumArrayData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumArrayData.java similarity index 96% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumArrayData.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumArrayData.java index f21708c978b64..d4e9f9d4acb3f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumArrayData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumArrayData.java @@ -20,7 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.vm.ci.meta; +package jdk.vm.ci.meta.annotation; + +import jdk.vm.ci.meta.ResolvedJavaType; import java.util.List; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumData.java similarity index 96% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumData.java index 9d3eedc49f96d..2f3e666f1f2ec 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumData.java @@ -20,7 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.vm.ci.meta; +package jdk.vm.ci.meta.annotation; + +import jdk.vm.ci.meta.ResolvedJavaType; /** * Represents an enum constant within an {@link AnnotationValue}. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MissingType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/MissingType.java similarity index 98% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MissingType.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/MissingType.java index e535ecca28d38..ab58260a301cf 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MissingType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/MissingType.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.vm.ci.meta; +package jdk.vm.ci.meta.annotation; /** * Represents a deferred {@link TypeNotPresentException} within an {@link AnnotationValue}. diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java index 1df157f4e9d95..95f8b4022dc5d 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java @@ -35,6 +35,7 @@ * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules jdk.internal.vm.ci/jdk.vm.ci.meta + * jdk.internal.vm.ci/jdk.vm.ci.meta.annotation * jdk.internal.vm.ci/jdk.vm.ci.hotspot * jdk.internal.vm.ci/jdk.vm.ci.runtime * jdk.internal.vm.ci/jdk.vm.ci.common diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 048367faf3e3c..3b32d1b57ad47 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -35,6 +35,7 @@ * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules jdk.internal.vm.ci/jdk.vm.ci.meta + * jdk.internal.vm.ci/jdk.vm.ci.meta.annotation * jdk.internal.vm.ci/jdk.vm.ci.runtime * jdk.internal.vm.ci/jdk.vm.ci.common * jdk.internal.vm.ci/jdk.vm.ci.hotspot @@ -79,7 +80,7 @@ import java.util.Objects; import java.util.Set; -import jdk.vm.ci.meta.AnnotationValue; +import jdk.vm.ci.meta.annotation.AnnotationValue; import org.junit.Assert; import org.junit.Test; diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index cf155c4791649..e45e15f5374f9 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -36,6 +36,7 @@ * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules java.base/jdk.internal.reflect * jdk.internal.vm.ci/jdk.vm.ci.meta + * jdk.internal.vm.ci/jdk.vm.ci.meta.annotation * jdk.internal.vm.ci/jdk.vm.ci.hotspot * jdk.internal.vm.ci/jdk.vm.ci.runtime * jdk.internal.vm.ci/jdk.vm.ci.common @@ -83,18 +84,18 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.vm.ci.meta.ElementTypeMismatch; -import jdk.vm.ci.meta.MissingType; +import jdk.vm.ci.meta.annotation.ElementTypeMismatch; +import jdk.vm.ci.meta.annotation.MissingType; import org.junit.Assert; import org.junit.Test; import jdk.internal.reflect.ConstantPool; import jdk.internal.vm.test.AnnotationTestInput; import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.Annotated; -import jdk.vm.ci.meta.AnnotationValue; -import jdk.vm.ci.meta.EnumArrayData; -import jdk.vm.ci.meta.EnumData; +import jdk.vm.ci.meta.annotation.Annotated; +import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.EnumArrayData; +import jdk.vm.ci.meta.annotation.EnumData; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; From 7234ca811d4f665506989a6a0051acb7db74020b Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 20:36:02 +0200 Subject: [PATCH 07/20] added base class for parsing error elements and enum elements to have Element suffix instead of Data --- .../classes/jdk/internal/vm/VMSupport.java | 14 +++---- .../vm/ci/hotspot/AnnotationValueDecoder.java | 14 +++---- .../ci/meta/annotation/AnnotationValue.java | 20 +++++----- .../meta/annotation/ElementTypeMismatch.java | 9 +++-- ...umArrayData.java => EnumArrayElement.java} | 8 ++-- .../{EnumData.java => EnumElement.java} | 8 ++-- .../vm/ci/meta/annotation/ErrorElement.java | 40 +++++++++++++++++++ .../vm/ci/meta/annotation/MissingType.java | 5 ++- .../ci/runtime/test/TestResolvedJavaType.java | 12 +++--- .../TestAnnotationEncodingDecoding.java | 33 ++++++++------- 10 files changed, 106 insertions(+), 57 deletions(-) rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/{EnumArrayData.java => EnumArrayElement.java} (89%) rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/{EnumData.java => EnumElement.java} (90%) create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ErrorElement.java diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index f7fc41023792f..aa8d34ccfba34 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -458,20 +458,20 @@ public interface AnnotationDecoder { A newAnnotation(T type, Map.Entry[] elements); /** - * Creates an object representing a decoded enum constant. + * Creates an object representing a decoded enum. * * @param enumType the enum type * @param name the name of the enum constant */ - E newEnumValue(T enumType, String name); + E newEnum(T enumType, String name); /** - * Creates an object representing a decoded enum constant. + * Creates an object representing a decoded enum array. * * @param enumType the enum type - * @param names the name of the enum constant + * @param names the names of the enum constants */ - EA newEnumValueArray(T enumType, List names); + EA newEnumArray(T enumType, List names); /** * Creates an object representing a missing type. @@ -531,7 +531,7 @@ private static A decodeAnnotation(DataInputStream dis, An case 'Z' -> dis.readBoolean(); case 's' -> dis.readUTF(); case 'c' -> decoder.resolveType(dis.readUTF()); - case 'e' -> decoder.newEnumValue(decoder.resolveType(dis.readUTF()), dis.readUTF()); + case 'e' -> decoder.newEnum(decoder.resolveType(dis.readUTF()), dis.readUTF()); case '@' -> decodeAnnotation(dis, decoder); case '[' -> decodeArray(dis, decoder); case 'x' -> decoder.newMissingType(dis.readUTF()); @@ -575,7 +575,7 @@ private static Object decodeArray(DataInputStream dis, An @SuppressWarnings("unchecked") private static EA readEnumArray(DataInputStream dis, AnnotationDecoder decoder, T enumType) throws IOException { List names = (List) readArray(dis, dis::readUTF); - return decoder.newEnumValueArray(enumType, names); + return decoder.newEnumArray(enumType, names); } /** diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java index 62b579b4b7e16..7e0b0d4d88a41 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java @@ -28,8 +28,8 @@ import jdk.internal.vm.VMSupport.AnnotationDecoder; import jdk.vm.ci.meta.annotation.ElementTypeMismatch; import jdk.vm.ci.meta.annotation.AnnotationValue; -import jdk.vm.ci.meta.annotation.EnumArrayData; -import jdk.vm.ci.meta.annotation.EnumData; +import jdk.vm.ci.meta.annotation.EnumArrayElement; +import jdk.vm.ci.meta.annotation.EnumElement; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaType; @@ -41,7 +41,7 @@ * and employs {@link AnnotationValue} to represent decoded annotations and enum * constants respectively. */ -final class AnnotationValueDecoder implements AnnotationDecoder { +final class AnnotationValueDecoder implements AnnotationDecoder { private final HotSpotResolvedJavaType accessingClass; @@ -61,13 +61,13 @@ public AnnotationValue newAnnotation(ResolvedJavaType type, Map.Entry names) { - return new EnumArrayData(enumType, names); + public EnumArrayElement newEnumArray(ResolvedJavaType enumType, List names) { + return new EnumArrayElement(enumType, names); } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValue.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValue.java index 0df8b139e4bcf..ac35b894176e4 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValue.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValue.java @@ -56,8 +56,8 @@ public final class AnnotationValue { String.class, MissingType.class, ElementTypeMismatch.class, - EnumArrayData.class, - EnumData.class, + EnumArrayElement.class, + EnumElement.class, AnnotationValue.class); /** @@ -66,7 +66,7 @@ public final class AnnotationValue { * @param type the annotation interface of this annotation, represented as a {@link ResolvedJavaType} * @param elements the names and values of this annotation's element values. Each value's type * must be one of the {@code AnnotationValue} types described {@linkplain #get here} - * or it must be a {@link MissingType} or {@link ElementTypeMismatch} object for + * or it must be a {@link ErrorElement} object for * an error seen while parsing the element. There is no distinction between a * value explicitly present in the annotation and an element's default value. * @throws IllegalArgumentException if the value of an entry in {@code elements} is not of an @@ -88,7 +88,7 @@ private static void checkEntry(Map.Entry e) { boolean illegalEnumType = false; if (valueClass.isArray()) { valueClass = valueClass.getComponentType(); - if (valueClass == EnumData.class || valueClass == EnumArrayData.class) { + if (valueClass == EnumElement.class || valueClass == EnumArrayElement.class) { illegalEnumType = true; } } @@ -129,10 +129,10 @@ public ResolvedJavaType getAnnotationType() { * double Double * String String * Class ResolvedJavaType - * Enum EnumData - * Enum[] EnumArrayData + * Enum EnumElement + * Enum[] EnumArrayElement * Annotation AnnotationValue - * []List<T> where T is one of the above types except for EnumData or EnumArrayData + * []List<T> where T is one of the above types except for EnumElement or EnumArrayElement * * * @@ -143,7 +143,7 @@ public ResolvedJavaType getAnnotationType() { * @throws ClassCastException if the element is not of type {@code elementType} * @throws IllegalArgumentException if this annotation has no element named {@code name} * if {@code elementType != Object.class} and the element is of type - * {@link MissingType} or {@link ElementTypeMismatch} + * {@link ErrorElement} */ // @formatter:on public V get(String name, Class elementType) { @@ -151,8 +151,8 @@ public V get(String name, Class elementType) { if (val == null) { throw new IllegalArgumentException(type.toJavaName() + " missing element " + name); } - if (elementType != Object.class && (val instanceof MissingType || val instanceof ElementTypeMismatch)) { - throw new IllegalArgumentException(val.toString()); + if (elementType != Object.class && val instanceof ErrorElement ee) { + throw ee.generateException(); } return elementType.cast(val); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ElementTypeMismatch.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ElementTypeMismatch.java index 14d48fbe92ad6..99db829463b8a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ElementTypeMismatch.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ElementTypeMismatch.java @@ -22,8 +22,11 @@ */ package jdk.vm.ci.meta.annotation; +import java.lang.annotation.AnnotationTypeMismatchException; + /** - * Represents a deferred {@link java.lang.annotation.AnnotationTypeMismatchException} within an {@link AnnotationValue}. + * Represents a deferred {@link AnnotationTypeMismatchException} for an element + * within an {@link AnnotationValue}. *

* Similar to {@code AnnotationTypeMismatchExceptionProxy}. */ @@ -31,7 +34,7 @@ public final class ElementTypeMismatch { private final String foundType; /** - * @param foundType see {@link java.lang.annotation.AnnotationTypeMismatchException#foundType()} + * @param foundType see {@link AnnotationTypeMismatchException#foundType()} */ public ElementTypeMismatch(String foundType) { this.foundType = foundType; @@ -60,7 +63,7 @@ public int hashCode() { } /** - * @see java.lang.annotation.AnnotationTypeMismatchException#foundType() + * @see AnnotationTypeMismatchException#foundType() */ public String getFoundType() { return foundType; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumArrayData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumArrayElement.java similarity index 89% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumArrayData.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumArrayElement.java index d4e9f9d4acb3f..747bafe46b45f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumArrayData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumArrayElement.java @@ -27,9 +27,9 @@ import java.util.List; /** - * Represents an array of enum constants within an {@link AnnotationValue}. + * Represents an enum array element within an {@link AnnotationValue}. */ -public final class EnumArrayData { +public final class EnumArrayElement { /** * The type of the enum. */ @@ -46,7 +46,7 @@ public final class EnumArrayData { * @param enumType the {@linkplain Enum enum type} * @param names the names of the enum constants */ - public EnumArrayData(ResolvedJavaType enumType, List names) { + public EnumArrayElement(ResolvedJavaType enumType, List names) { this.enumType = enumType; this.names = names; } @@ -58,7 +58,7 @@ public String toString() { @Override public boolean equals(Object obj) { - if (obj instanceof EnumArrayData that) { + if (obj instanceof EnumArrayElement that) { return this.enumType.equals(that.enumType) && this.names.equals(that.names); } return false; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumElement.java similarity index 90% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumData.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumElement.java index 2f3e666f1f2ec..a1454d0de8bc5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/EnumElement.java @@ -25,9 +25,9 @@ import jdk.vm.ci.meta.ResolvedJavaType; /** - * Represents an enum constant within an {@link AnnotationValue}. + * Represents an enum element within an {@link AnnotationValue}. */ -public final class EnumData { +public final class EnumElement { /** * The type of the enum. */ @@ -44,7 +44,7 @@ public final class EnumData { * @param enumType the {@linkplain Enum enum type} * @param name the {@linkplain Enum#name() name} of the enum */ - public EnumData(ResolvedJavaType enumType, String name) { + public EnumElement(ResolvedJavaType enumType, String name) { this.enumType = enumType; this.name = name; } @@ -56,7 +56,7 @@ public String toString() { @Override public boolean equals(Object obj) { - if (obj instanceof EnumData that) { + if (obj instanceof EnumElement that) { return this.enumType.equals(that.enumType) && this.name.equals(that.name); } return false; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ErrorElement.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ErrorElement.java new file mode 100644 index 0000000000000..7522f7e92a5a2 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ErrorElement.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, 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 jdk.vm.ci.meta.annotation; + +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Represents an element within an {@link AnnotationValue} that had a parsing error. + *

+ * Similar to {@code ExceptionProxy}. + */ +public abstract class ErrorElement { + /** + * Returns an {@link IllegalArgumentException} whose message describes the + * parsing error represented by this object. + */ + protected IllegalArgumentException generateException() { + return new IllegalArgumentException(toString()); + } +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/MissingType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/MissingType.java index ab58260a301cf..bb5099c72363f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/MissingType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/MissingType.java @@ -23,11 +23,12 @@ package jdk.vm.ci.meta.annotation; /** - * Represents a deferred {@link TypeNotPresentException} within an {@link AnnotationValue}. + * Represents a deferred {@link TypeNotPresentException} for an element + * within an {@link AnnotationValue}. *

* Similar to {@code TypeNotPresentExceptionProxy}. */ -public final class MissingType { +public final class MissingType extends ErrorElement { private final String typeName; /** diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index e45e15f5374f9..f56c3cc7f1792 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -85,6 +85,7 @@ import java.util.stream.Stream; import jdk.vm.ci.meta.annotation.ElementTypeMismatch; +import jdk.vm.ci.meta.annotation.EnumElement; import jdk.vm.ci.meta.annotation.MissingType; import org.junit.Assert; import org.junit.Test; @@ -94,8 +95,7 @@ import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.annotation.Annotated; import jdk.vm.ci.meta.annotation.AnnotationValue; -import jdk.vm.ci.meta.annotation.EnumArrayData; -import jdk.vm.ci.meta.annotation.EnumData; +import jdk.vm.ci.meta.annotation.EnumArrayElement; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -1410,10 +1410,10 @@ public static Class toAnnotationValueElementType(Class type) { return ResolvedJavaType.class; } if (Enum.class.isAssignableFrom(type)) { - return EnumData.class; + return EnumElement.class; } if (Enum[].class.isAssignableFrom(type)) { - return EnumArrayData.class; + return EnumArrayElement.class; } if (Annotation.class.isAssignableFrom(type)) { return AnnotationValue.class; @@ -1427,7 +1427,7 @@ public static Class toAnnotationValueElementType(Class type) { private static void assertAnnotationElementsEqual(Object aElement, Object avElement) { Class valueType = aElement.getClass(); if (valueType.isEnum()) { - String avEnumName = ((EnumData) avElement).name; + String avEnumName = ((EnumElement) avElement).name; String aEnumName = ((Enum) aElement).name(); assertEquals(avEnumName, aEnumName); } else if (aElement instanceof Class) { @@ -1445,7 +1445,7 @@ private static void assertAnnotationElementsEqual(Object aElement, Object avElem } else if (valueType.isArray()) { int length = Array.getLength(aElement); if (valueType.getComponentType().isEnum()) { - EnumArrayData array = (EnumArrayData) avElement; + EnumArrayElement array = (EnumArrayElement) avElement; assertEquals(length, array.names.size()); for (int i = 0; i < length; i++) { String avEnumName = array.names.get(i); diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java index b78264df7d666..cc727b95640dc 100644 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java @@ -23,7 +23,7 @@ /* * @test - * @compile AnnotationTestInput.java MemberDeleted.java MemberTypeChanged.java + * @compile AnnotationTestInput.java MemberAdded.java MemberDeleted.java MemberTypeChanged.java * @modules java.base/jdk.internal.vm * java.base/sun.reflect.annotation * @clean jdk.internal.vm.test.AnnotationTestInput$Missing @@ -33,6 +33,14 @@ */ package jdk.internal.vm.test; +import jdk.internal.vm.VMSupport; +import jdk.internal.vm.VMSupport.AnnotationDecoder; +import org.testng.Assert; +import org.testng.annotations.Test; +import sun.reflect.annotation.AnnotationSupport; +import sun.reflect.annotation.ExceptionProxy; +import sun.reflect.annotation.TypeNotPresentExceptionProxy; + import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; @@ -40,15 +48,6 @@ import java.util.Map; import java.util.Objects; -import org.testng.Assert; -import org.testng.annotations.Test; - -import sun.reflect.annotation.AnnotationSupport; -import sun.reflect.annotation.ExceptionProxy; - -import jdk.internal.vm.VMSupport; -import jdk.internal.vm.VMSupport.AnnotationDecoder; - public class TestAnnotationEncodingDecoding { @Test @@ -253,7 +252,7 @@ public List getNames() { } } - static class MyDecoder implements AnnotationDecoder, AnnotationConst, EnumConst, EnumArrayConst, ErrorConst> { + static class MyDecoder implements AnnotationDecoder, AnnotationConst, EnumConst, EnumArrayConst, ErrorConst, ErrorConst> { @Override public Class resolveType(String name) { try { @@ -269,18 +268,24 @@ public AnnotationConst newAnnotation(Class type, Map.Entry[] } @Override - public EnumConst newEnumValue(Class enumType, String name) { + public EnumConst newEnum(Class enumType, String name) { return new EnumConst(enumType, name); } @Override - public EnumArrayConst newEnumValueArray(Class enumType, List names) { + public EnumArrayConst newEnumArray(Class enumType, List names) { return new EnumArrayConst(enumType, names); } @Override - public ErrorConst newErrorValue(String description) { + public ErrorConst newMissingType(String typeName) { + String description = new TypeNotPresentExceptionProxy(typeName, null).toString(); return new ErrorConst(description); } + + @Override + public ErrorConst newElementTypeMismatch(String foundType) { + return new ErrorConst("/* Warning type mismatch! \"" + foundType + "\" */"); + } } } From 045bb76e2a2399adf03619ad8a2167928f610cee Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 14 Aug 2025 14:41:17 +0200 Subject: [PATCH 08/20] JVMCI annotation API only supports declared annotations --- src/hotspot/share/classfile/vmSymbols.hpp | 2 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 9 +- .../classes/jdk/internal/vm/VMSupport.java | 52 +------- .../vm/ci/hotspot/AnnotationValueDecoder.java | 24 ++-- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 34 +++-- .../HotSpotResolvedJavaMethodImpl.java | 52 ++++---- .../ci/hotspot/HotSpotResolvedJavaType.java | 7 - .../HotSpotResolvedObjectTypeImpl.java | 46 +++---- .../hotspot/HotSpotResolvedPrimitiveType.java | 23 ++-- .../jdk/vm/ci/meta/annotation/Annotated.java | 37 +++--- .../runtime/test/TestResolvedJavaMethod.java | 4 +- .../ci/runtime/test/TestResolvedJavaType.java | 125 +++++++++--------- 12 files changed, 184 insertions(+), 231 deletions(-) diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 06f27f09c5c01..7a3076509365b 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -706,7 +706,7 @@ class SerializeClosure; template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \ template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \ template(encodeAnnotations_name, "encodeAnnotations") \ - template(encodeAnnotations_signature, "([BLjava/lang/Class;Ljdk/internal/reflect/ConstantPool;Z[Ljava/lang/Class;)[B")\ + template(encodeAnnotations_signature, "([BLjava/lang/Class;Ljdk/internal/reflect/ConstantPool;[Ljava/lang/Class;)[B")\ template(decodeAndThrowThrowable_signature, "(IJZZ)V") \ template(classRedefinedCount_name, "classRedefinedCount") \ template(classLoader_name, "classLoader") \ diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 36d04c4f7fa31..06d89d7a1f4b6 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -3014,7 +3014,7 @@ C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAI return JNIHandles::make_local(THREAD, reflected); C2V_END -static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, AnnotationArray* annotations_array, bool for_class, +static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, AnnotationArray* annotations_array, jint filter_length, jlong filter_klass_pointers, JavaThread* THREAD, JVMCI_TRAPS) { // Get a ConstantPool object for annotation parsing @@ -3048,7 +3048,6 @@ static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, Annotatio args.push_oop(annotations); args.push_oop(Handle(THREAD, holder->java_mirror())); args.push_oop(jcp); - args.push_int(for_class); args.push_oop(filter_classes); Symbol* signature = vmSymbols::encodeAnnotations_signature(); JavaCalls::call_static(&result, @@ -3081,14 +3080,14 @@ C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationValues, (JNIEnv* env, jobj jobject filter, jint filter_length, jlong filter_klass_pointers)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support InstanceKlass* holder = InstanceKlass::cast(UNPACK_PAIR(Klass, klass)); - return get_encoded_annotation_values(holder, holder->class_annotations(), true, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + return get_encoded_annotation_values(holder, holder->class_annotations(), filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), jobject filter, jint filter_length, jlong filter_klass_pointers)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support methodHandle method(THREAD, UNPACK_PAIR(Method, method)); - return get_encoded_annotation_values(method->method_holder(), method->annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + return get_encoded_annotation_values(method->method_holder(), method->annotations(), filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, @@ -3096,7 +3095,7 @@ C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobj CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support InstanceKlass* holder = check_field(InstanceKlass::cast(UNPACK_PAIR(Klass, klass)), index, JVMCI_CHECK_NULL); fieldDescriptor fd(holder, index); - return get_encoded_annotation_values(holder, fd.annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + return get_encoded_annotation_values(holder, fd.annotations(), filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_NULL(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current)) diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index aa8d34ccfba34..22b7d7a3c679c 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -25,12 +25,13 @@ package jdk.internal.vm; import jdk.internal.misc.Unsafe; -import jdk.internal.access.SharedSecrets; -import jdk.internal.access.JavaLangAccess; import jdk.internal.reflect.ConstantPool; import sun.reflect.annotation.AnnotationParser; import sun.reflect.annotation.AnnotationSupport; -import sun.reflect.annotation.AnnotationType; +import sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy; +import sun.reflect.annotation.EnumValue; +import sun.reflect.annotation.EnumValueArray; +import sun.reflect.annotation.TypeNotPresentExceptionProxy; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -41,16 +42,10 @@ import java.lang.annotation.AnnotationTypeMismatchException; import java.nio.charset.StandardCharsets; import java.util.Collection; -import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; -import java.util.List; - -import sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy; -import sun.reflect.annotation.EnumValue; -import sun.reflect.annotation.EnumValueArray; -import sun.reflect.annotation.TypeNotPresentExceptionProxy; /* * Support class used by JVMCI, JVMTI and VM attach mechanism. @@ -195,46 +190,13 @@ public static int encodeThrowable(Throwable throwable, long buffer, int bufferSi public static byte[] encodeAnnotations(byte[] rawAnnotations, Class declaringClass, ConstantPool cp, - boolean forClass, - Class[] selectAnnotationClasses) - { + Class[] selectAnnotationClasses) { for (Class c : selectAnnotationClasses) { if (!c.isAnnotation()) { throw new IllegalArgumentException(c + " is not an annotation interface"); } } - Map, Annotation> annotations = - AnnotationParser.parseSelectAnnotations(rawAnnotations, cp, declaringClass, false, selectAnnotationClasses); - if (forClass && annotations.size() != selectAnnotationClasses.length) { - Class superClass = declaringClass.getSuperclass(); - nextSuperClass: - while (superClass != null) { - JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); - Map, Annotation> superAnnotations = - AnnotationParser.parseSelectAnnotations( - jla.getRawClassAnnotations(superClass), - jla.getConstantPool(superClass), - superClass, - false, - selectAnnotationClasses); - - for (Map.Entry, Annotation> e : superAnnotations.entrySet()) { - Class annotationClass = e.getKey(); - if (!annotations.containsKey(annotationClass) && AnnotationType.getInstance(annotationClass).isInherited()) { - if (annotations.isEmpty()) { - // An empty map might be unmodifiable (e.g. Collections.emptyMap()). - annotations = new LinkedHashMap, Annotation>(); - } - annotations.put(annotationClass, e.getValue()); - if (annotations.size() == selectAnnotationClasses.length) { - break nextSuperClass; - } - } - } - superClass = superClass.getSuperclass(); - } - } - return encodeAnnotations(annotations.values()); + return encodeAnnotations(AnnotationParser.parseSelectAnnotations(rawAnnotations, cp, declaringClass, false, selectAnnotationClasses).values()); } /** diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java index 7e0b0d4d88a41..9a0dd110c9dad 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java @@ -22,19 +22,22 @@ */ package jdk.vm.ci.hotspot; -import java.util.Map; -import java.util.List; - +import jdk.internal.vm.VMSupport; import jdk.internal.vm.VMSupport.AnnotationDecoder; -import jdk.vm.ci.meta.annotation.ElementTypeMismatch; -import jdk.vm.ci.meta.annotation.AnnotationValue; -import jdk.vm.ci.meta.annotation.EnumArrayElement; -import jdk.vm.ci.meta.annotation.EnumElement; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.annotation.MissingType; import jdk.vm.ci.meta.UnresolvedJavaType; +import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.ElementTypeMismatch; +import jdk.vm.ci.meta.annotation.EnumArrayElement; +import jdk.vm.ci.meta.annotation.EnumElement; +import jdk.vm.ci.meta.annotation.MissingType; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; /** * Implementation of {@link AnnotationDecoder} that resolves type names to {@link JavaType} values @@ -45,6 +48,11 @@ final class AnnotationValueDecoder implements AnnotationDecoder decode(byte[] encoded) { + List annotationValues = VMSupport.decodeAnnotations(encoded, this); + return annotationValues.stream().collect(Collectors.toMap(AnnotationValue::getAnnotationType, Function.identity())); + } + AnnotationValueDecoder(HotSpotResolvedJavaType accessingClass) { this.accessingClass = accessingClass; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index e76c0271a3ad7..4cfa2aeecaf20 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -22,25 +22,23 @@ */ package jdk.vm.ci.hotspot; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.UnresolvedJavaType; +import jdk.vm.ci.meta.annotation.AnnotationValue; + +import java.lang.annotation.Annotation; +import java.util.Map; + import static jdk.internal.misc.Unsafe.ADDRESS_SIZE; import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkAreAnnotations; import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkIsAnnotation; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.getFirstAnnotationOrNull; import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; -import java.lang.annotation.Annotation; -import java.util.List; - -import jdk.internal.vm.VMSupport; -import jdk.vm.ci.meta.annotation.AnnotationValue; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.UnresolvedJavaType; - /** * Represents a field in a HotSpot type. */ @@ -186,7 +184,7 @@ public boolean isSynthetic() { */ @Override public boolean isStable() { - return (1 << (config().jvmFieldFlagStableShift ) & internalFlags) != 0; + return (1 << (config().jvmFieldFlagStableShift) & internalFlags) != 0; } private boolean hasAnnotations() { @@ -234,25 +232,25 @@ public JavaConstant getConstantValue() { } @Override - public AnnotationValue getAnnotationValue(ResolvedJavaType annotationType) { + public AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType annotationType) { if (!hasAnnotations()) { checkIsAnnotation(annotationType); return null; } - return getFirstAnnotationOrNull(getAnnotationValues0(annotationType)); + return getAnnotationValues0(annotationType).get(annotationType); } @Override - public List getAnnotationValues(ResolvedJavaType... types) { + public Map getDeclaredAnnotationValues(ResolvedJavaType... types) { checkAreAnnotations(types); if (!hasAnnotations()) { - return List.of(); + return Map.of(); } return getAnnotationValues0(types); } - private List getAnnotationValues0(ResolvedJavaType... filter) { + private Map getAnnotationValues0(ResolvedJavaType... filter) { byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, filter); - return VMSupport.decodeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); + return new AnnotationValueDecoder(getDeclaringClass()).decode(encoded); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index b1a31a995e246..c0e9e391615c9 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -22,29 +22,8 @@ */ package jdk.vm.ci.hotspot; -import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; -import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; -import static jdk.vm.ci.hotspot.HotSpotModifiers.BRIDGE; -import static jdk.vm.ci.hotspot.HotSpotModifiers.SYNTHETIC; -import static jdk.vm.ci.hotspot.HotSpotModifiers.VARARGS; -import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmMethodModifiers; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkAreAnnotations; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkIsAnnotation; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.getFirstAnnotationOrNull; -import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; -import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Executable; -import java.lang.reflect.Modifier; -import java.lang.reflect.Type; -import java.util.BitSet; -import java.util.List; - -import jdk.internal.vm.VMSupport; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; -import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.DefaultProfilingInfo; @@ -59,6 +38,25 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.SpeculationLog; import jdk.vm.ci.meta.TriState; +import jdk.vm.ci.meta.annotation.AnnotationValue; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Executable; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.BitSet; +import java.util.Map; + +import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; +import static jdk.vm.ci.hotspot.HotSpotModifiers.BRIDGE; +import static jdk.vm.ci.hotspot.HotSpotModifiers.SYNTHETIC; +import static jdk.vm.ci.hotspot.HotSpotModifiers.VARARGS; +import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmMethodModifiers; +import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkAreAnnotations; +import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkIsAnnotation; +import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; /** * Implementation of {@link JavaMethod} for resolved HotSpot methods. @@ -774,26 +772,26 @@ public int methodIdnum() { } @Override - public AnnotationValue getAnnotationValue(ResolvedJavaType type) { + public AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType type) { if (!hasAnnotations()) { checkIsAnnotation(type); return null; } - return getFirstAnnotationOrNull(getAnnotationValues0(type)); + return getAnnotationValues0(type).get(type); } @Override - public List getAnnotationValues(ResolvedJavaType... types) { + public Map getDeclaredAnnotationValues(ResolvedJavaType... types) { checkAreAnnotations(types); if (!hasAnnotations()) { - return List.of(); + return Map.of(); } return getAnnotationValues0(types); } - private List getAnnotationValues0(ResolvedJavaType... filter) { + private Map getAnnotationValues0(ResolvedJavaType... filter) { byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, filter); - return VMSupport.decodeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); + return new AnnotationValueDecoder(getDeclaringClass()).decode(encoded); } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index eaeb41f2cb2f8..9323925150662 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -22,9 +22,6 @@ */ package jdk.vm.ci.hotspot; -import java.util.List; - -import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaType; @@ -82,8 +79,4 @@ static void checkAreAnnotations(ResolvedJavaType... types) { checkIsAnnotation(type); } } - - static AnnotationValue getFirstAnnotationOrNull(List list) { - return list.isEmpty() ? null : list.get(0); - } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 27155bd97eb98..88bbab2a75b9a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -22,24 +22,7 @@ */ package jdk.vm.ci.hotspot; -import static java.util.Objects.requireNonNull; -import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; -import static jdk.vm.ci.hotspot.HotSpotConstantPool.isSignaturePolymorphicHolder; -import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; -import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmClassModifiers; -import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; -import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.nio.ByteOrder; -import java.util.HashMap; -import java.util.List; - -import jdk.internal.vm.VMSupport; import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.Assumptions.ConcreteMethod; import jdk.vm.ci.meta.Assumptions.ConcreteSubtype; @@ -54,6 +37,23 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.UnresolvedJavaField; import jdk.vm.ci.meta.UnresolvedJavaType; +import jdk.vm.ci.meta.annotation.AnnotationValue; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.ByteOrder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.util.Objects.requireNonNull; +import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; +import static jdk.vm.ci.hotspot.HotSpotConstantPool.isSignaturePolymorphicHolder; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; +import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmClassModifiers; +import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; /** * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. This class is not @@ -1115,25 +1115,25 @@ public boolean isCloneableWithAllocation() { } @Override - public AnnotationValue getAnnotationValue(ResolvedJavaType annotationType) { + public AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType annotationType) { if (!mayHaveAnnotations(true)) { checkIsAnnotation(annotationType); return null; } - return getFirstAnnotationOrNull(getAnnotationValues0(annotationType)); + return getAnnotationValues0(annotationType).get(annotationType); } @Override - public List getAnnotationValues(ResolvedJavaType... types) { + public Map getDeclaredAnnotationValues(ResolvedJavaType... types) { if (!mayHaveAnnotations(true)) { checkAreAnnotations(types); - return List.of(); + return Map.of(); } return getAnnotationValues0(types); } - private List getAnnotationValues0(ResolvedJavaType... filter) { + private Map getAnnotationValues0(ResolvedJavaType... filter) { byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, filter); - return VMSupport.decodeAnnotations(encoded, new AnnotationValueDecoder(this)); + return new AnnotationValueDecoder(this).decode(encoded); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index 06f1fc8160727..2386f6b1ba6c5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -22,15 +22,7 @@ */ package jdk.vm.ci.hotspot; -import static java.util.Objects.requireNonNull; -import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Modifier; -import java.util.List; - import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -38,6 +30,15 @@ import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.AnnotationValue; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Modifier; +import java.util.List; +import java.util.Map; + +import static java.util.Objects.requireNonNull; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; /** * Implementation of {@link JavaType} for primitive HotSpot types. @@ -341,14 +342,14 @@ public JavaConstant getJavaMirror() { } @Override - public AnnotationValue getAnnotationValue(ResolvedJavaType type) { + public AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType type) { checkIsAnnotation(type); return null; } @Override - public List getAnnotationValues(ResolvedJavaType... types) { + public Map getDeclaredAnnotationValues(ResolvedJavaType... types) { checkAreAnnotations(types); - return List.of(); + return Map.of(); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java index 474bba52e9e6e..8b49952b01807 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java @@ -24,48 +24,43 @@ import jdk.vm.ci.meta.ResolvedJavaType; -import java.lang.annotation.Inherited; -import java.util.List; +import java.lang.reflect.AnnotatedElement; +import java.util.Map; /** * Represents a program element such as a method, constructor, field or class for which annotations - * may be present. + * may be directly present. This API is analogous to {@link java.lang.reflect.AnnotatedElement} + * except that it only supports {@linkplain AnnotatedElement#getDeclaredAnnotations() declared annotations}. */ public interface Annotated { /** - * Gets the annotations present on this element whose types are in {@code types}. + * Gets the annotations directly present on this element whose types are in {@code types}. * Class initialization is not triggered for enum types referenced by the returned - * annotations or any other annotations of this element. - * - * If this element is a class, then {@link Inherited} annotations are included in the set of - * annotations considered. - * - * See {@link java.lang.reflect.AnnotatedElement} for the definition of present. + * annotation. This method ignores inherited annotations. * * @param types annotation types to select - * @return an immutable list of the annotations present on this element that match one {@code types} - * @throws IllegalArgumentException if any type in {@code types} is not an annotation interface type + * @return an immutable map from annotation type to annotation of the annotations directly present + * on this element that match {@code types} + * @throws IllegalArgumentException if any type in {@code types} is not an annotation interface type * @throws UnsupportedOperationException if this operation is not supported */ - default List getAnnotationValues(ResolvedJavaType... types) { + default Map getDeclaredAnnotationValues(ResolvedJavaType... types) { throw new UnsupportedOperationException(this.getClass().getName()); } /** - * Gets the annotation present on this element of type {@code type}. + * Gets the annotation directly present on this element whose type is {@code type}. * Class initialization is not triggered for enum types referenced by the returned - * annotation. - * - * See {@link java.lang.reflect.AnnotatedElement} for the definition of present. + * annotation. This method ignores inherited annotations. * * @param type the type object corresponding to the annotation interface type - * @return this element's annotation for the specified annotation type if present on this - * element, else null - * @throws IllegalArgumentException if {@code type} is not an annotation interface type + * @return this element's annotation for the specified annotation type if directly present on this + * element, else null + * @throws IllegalArgumentException if {@code type} is not an annotation interface type * @throws UnsupportedOperationException if this operation is not supported */ - default AnnotationValue getAnnotationValue(ResolvedJavaType type) { + default AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType type) { throw new UnsupportedOperationException(this.getClass().getName()); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 3b32d1b57ad47..c7518cb2e3e7f 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -621,10 +621,10 @@ public void getAnnotationValueTest() throws Exception { // Ensure NumbersDE is not initialized before Annotation2 is requested Assert.assertFalse(numbersDEType.isInitialized()); - Assert.assertEquals(2, m.getAnnotationValues(a1, a3).size()); + Assert.assertEquals(2, m.getDeclaredAnnotationValues(a1, a3).size()); // Ensure NumbersDE is not initialized after Annotation2 is requested - Assert.assertNotNull(m.getAnnotationValue(a2)); + Assert.assertNotNull(m.getDeclaredAnnotationValue(a2)); Assert.assertFalse(numbersDEType.isInitialized()); } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index f56c3cc7f1792..5dc3df9ec4254 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -48,17 +48,31 @@ package jdk.vm.ci.runtime.test; -import static java.lang.reflect.Modifier.isAbstract; -import static java.lang.reflect.Modifier.isPrivate; -import static java.lang.reflect.Modifier.isStatic; -import static jdk.vm.ci.meta.MetaUtil.internalNameToJava; -import static jdk.vm.ci.meta.MetaUtil.toInternalName; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import jdk.internal.reflect.ConstantPool; +import jdk.internal.vm.test.AnnotationTestInput; +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.meta.Assumptions.AssumptionResult; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaUtil; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.UnresolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; +import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.ElementTypeMismatch; +import jdk.vm.ci.meta.annotation.EnumArrayElement; +import jdk.vm.ci.meta.annotation.EnumElement; +import jdk.vm.ci.meta.annotation.MissingType; +import org.junit.Assert; +import org.junit.Test; +import sun.reflect.annotation.AnnotationSupport; +import sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy; +import sun.reflect.annotation.ExceptionProxy; +import sun.reflect.annotation.TypeNotPresentExceptionProxy; import java.io.DataInputStream; import java.io.IOException; @@ -75,41 +89,26 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.function.Supplier; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.vm.ci.meta.annotation.ElementTypeMismatch; -import jdk.vm.ci.meta.annotation.EnumElement; -import jdk.vm.ci.meta.annotation.MissingType; -import org.junit.Assert; -import org.junit.Test; - -import jdk.internal.reflect.ConstantPool; -import jdk.internal.vm.test.AnnotationTestInput; -import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.annotation.Annotated; -import jdk.vm.ci.meta.annotation.AnnotationValue; -import jdk.vm.ci.meta.annotation.EnumArrayElement; -import jdk.vm.ci.meta.Assumptions.AssumptionResult; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.MetaUtil; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.UnresolvedJavaType; -import sun.reflect.annotation.AnnotationSupport; -import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; -import sun.reflect.annotation.ExceptionProxy; -import sun.reflect.annotation.TypeNotPresentExceptionProxy; -import sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy; +import static java.lang.reflect.Modifier.isAbstract; +import static java.lang.reflect.Modifier.isPrivate; +import static java.lang.reflect.Modifier.isStatic; +import static jdk.vm.ci.meta.MetaUtil.internalNameToJava; +import static jdk.vm.ci.meta.MetaUtil.toInternalName; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; /** * Tests for {@link ResolvedJavaType}. @@ -1229,22 +1228,22 @@ public void getAnnotationValueTest() { ResolvedJavaType overrideType = metaAccess.lookupJavaType(Override.class); for (Class c : prims) { ResolvedJavaType type = metaAccess.lookupJavaType(c); - AnnotationValue av = type.getAnnotationValue(overrideType); + AnnotationValue av = type.getDeclaredAnnotationValue(overrideType); Assert.assertNull(String.valueOf(av), av); - List avArray = type.getAnnotationValues(overrideType, overrideType); - Assert.assertEquals(0, avArray.size()); + Map avMap = type.getDeclaredAnnotationValues(overrideType, overrideType); + Assert.assertEquals(0, avMap.size()); } // Test that inherited annotations are handled properly. ResolvedJavaType namedType = metaAccess.lookupJavaType(AnnotationTestInput.Named.class); - AnnotationValue av = metaAccess.lookupJavaType(AnnotationTestInput.OwnName.class).getAnnotationValue(namedType); + AnnotationValue av = metaAccess.lookupJavaType(AnnotationTestInput.OwnName.class).getDeclaredAnnotationValue(namedType); Assert.assertEquals("NonInheritedValue", av.get("value", String.class)); - av = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName1.class).getAnnotationValue(namedType); - Assert.assertEquals("Super1", av.get("value", String.class)); - av = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName2.class).getAnnotationValue(namedType); - Assert.assertEquals("Super2", av.get("value", String.class)); - av = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName3.class).getAnnotationValue(namedType); - Assert.assertEquals("Super1", av.get("value", String.class)); + av = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName1.class).getDeclaredAnnotationValue(namedType); + Assert.assertNull(av); + av = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName2.class).getDeclaredAnnotationValue(namedType); + Assert.assertNull(av); + av = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName3.class).getDeclaredAnnotationValue(namedType); + Assert.assertNull(av); } // @formatter:off @@ -1293,9 +1292,9 @@ private static boolean isSignaturePolymorphic(ResolvedJavaMethod method) { private static void getAnnotationValueExpectedToFail(Annotated annotated, ResolvedJavaType... annotationTypes) { try { if (annotationTypes.length == 1) { - annotated.getAnnotationValue(annotationTypes[0]); + annotated.getDeclaredAnnotationValue(annotationTypes[0]); } else { - annotated.getAnnotationValues(annotationTypes); + annotated.getDeclaredAnnotationValues(annotationTypes); } String s = Stream.of(annotationTypes).map(ResolvedJavaType::toJavaName).collect(Collectors.joining(", ")); throw new AssertionError("Expected IllegalArgumentException for retrieving (" + s + " from " + annotated); @@ -1305,8 +1304,8 @@ private static void getAnnotationValueExpectedToFail(Annotated annotated, Resolv } /** - * Tests that {@link AnnotationValue} obtained from a {@link Class}, {@link Method} or - * {@link Field} matches {@link AnnotatedElement#getAnnotations()} for the corresponding JVMCI + * Tests that {@link AnnotationValue}s obtained from a {@link Class}, {@link Method} or + * {@link Field} matches {@link AnnotatedElement#getDeclaredAnnotations()} for the corresponding JVMCI * object. * * @param annotatedElement a {@link Class}, {@link Method} or {@link Field} object @@ -1320,13 +1319,13 @@ public static List getAnnotationValueTest(AnnotatedElement anno getAnnotationValueExpectedToFail(annotated, suppressWarningsType, suppressWarningsType, objectType); // Check that querying a missing annotation returns null or an empty list - assertNull(annotated.getAnnotationValue(suppressWarningsType)); - List values = annotated.getAnnotationValues(suppressWarningsType, suppressWarningsType); + assertNull(annotated.getDeclaredAnnotationValue(suppressWarningsType)); + Map values = annotated.getDeclaredAnnotationValues(suppressWarningsType, suppressWarningsType); assertTrue(values.toString(), values.isEmpty()); - values = annotated.getAnnotationValues(suppressWarningsType, suppressWarningsType, suppressWarningsType, suppressWarningsType); + values = annotated.getDeclaredAnnotationValues(suppressWarningsType, suppressWarningsType, suppressWarningsType, suppressWarningsType); assertTrue(values.toString(), values.isEmpty()); - return testGetAnnotationValue(annotated, List.of(annotatedElement.getAnnotations())); + return testGetAnnotationValue(annotated, List.of(annotatedElement.getDeclaredAnnotations())); } private static List testGetAnnotationValue(Annotated annotated, List annotations) throws AssertionError { @@ -1334,14 +1333,14 @@ private static List testGetAnnotationValue(Annotated annotated, List res = new ArrayList<>(annotations.size()); for (Annotation a : annotations) { var annotationType = metaAccess.lookupJavaType(a.annotationType()); - AnnotationValue av = annotated.getAnnotationValue(annotationType); + AnnotationValue av = annotated.getDeclaredAnnotationValue(annotationType); assertAnnotationsEquals(a, av); // Check that encoding/decoding produces a stable result - AnnotationValue av2 = annotated.getAnnotationValue(annotationType); + AnnotationValue av2 = annotated.getDeclaredAnnotationValue(annotationType); assertEquals(av, av2); - List annotationValues = annotated.getAnnotationValues(annotationType, suppressWarningsType, suppressWarningsType); + Map annotationValues = annotated.getDeclaredAnnotationValues(annotationType, suppressWarningsType, suppressWarningsType); assertEquals(1, annotationValues.size()); res.add(av); @@ -1351,14 +1350,14 @@ private static List testGetAnnotationValue(Annotated annotated, } for (int i = 0; i < annotations.size(); i++) { ResolvedJavaType[] types = annotations.// - stream().map(a -> metaAccess.lookupJavaType(a.annotationType())).// - toArray(ResolvedJavaType[]::new); - List annotationValues = annotated.getAnnotationValues(types); + stream().map(a -> metaAccess.lookupJavaType(a.annotationType())).// + toArray(ResolvedJavaType[]::new); + Map annotationValues = annotated.getDeclaredAnnotationValues(types); assertEquals(types.length, annotationValues.size()); for (int j = 0; j < annotationValues.size(); j++) { Annotation a = annotations.get(j); - AnnotationValue av = annotationValues.get(j); + AnnotationValue av = annotationValues.get(metaAccess.lookupJavaType(a.annotationType())); assertAnnotationsEquals(a, av); } } From e45c4483bb91b0844dba5a2079be1f17e2699051 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 14 Aug 2025 21:38:49 +0200 Subject: [PATCH 09/20] add support for retrieving all annotations on an element --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 17 ++++++----- .../classes/jdk/internal/vm/VMSupport.java | 11 +++++-- .../jdk/vm/ci/hotspot/CompilerToVM.java | 30 +++++++++++-------- .../jdk/vm/ci/meta/annotation/Annotated.java | 4 +-- .../ci/runtime/test/TestResolvedJavaType.java | 9 +++++- 5 files changed, 45 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 06d89d7a1f4b6..12f89f12acdd1 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -3033,13 +3033,16 @@ static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, Annotatio typeArrayOop annotations_oop = Annotations::make_java_array(annotations_array, CHECK_NULL); typeArrayHandle annotations = typeArrayHandle(THREAD, annotations_oop); - InstanceKlass** filter = filter_length == 1 ? - (InstanceKlass**) &filter_klass_pointers: - (InstanceKlass**) filter_klass_pointers; - objArrayOop filter_oop = oopFactory::new_objArray(vmClasses::Class_klass(), filter_length, CHECK_NULL); - objArrayHandle filter_classes(THREAD, filter_oop); - for (int i = 0; i < filter_length; i++) { - filter_classes->obj_at_put(i, filter[i]->java_mirror()); + objArrayHandle filter_classes; + if (filter_length != 0) { + InstanceKlass** filter = filter_length == 1 ? + (InstanceKlass**) &filter_klass_pointers: + (InstanceKlass**) filter_klass_pointers; + objArrayOop filter_oop = oopFactory::new_objArray(vmClasses::Class_klass(), filter_length, CHECK_NULL); + filter_classes = objArrayHandle(THREAD, filter_oop); + for (int i = 0; i < filter_length; i++) { + filter_classes->obj_at_put(i, filter[i]->java_mirror()); + } } // invoke VMSupport.encodeAnnotations diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index 22b7d7a3c679c..4d3c1edf92ced 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -191,9 +191,14 @@ public static byte[] encodeAnnotations(byte[] rawAnnotations, Class declaringClass, ConstantPool cp, Class[] selectAnnotationClasses) { - for (Class c : selectAnnotationClasses) { - if (!c.isAnnotation()) { - throw new IllegalArgumentException(c + " is not an annotation interface"); + if (selectAnnotationClasses != null) { + if (selectAnnotationClasses.length == 0) { + throw new IllegalArgumentException("annotation class selection must be null or non-empty"); + } + for (Class c : selectAnnotationClasses) { + if (!c.isAnnotation()) { + throw new IllegalArgumentException(c + " is not an annotation interface"); + } } } return encodeAnnotations(AnnotationParser.parseSelectAnnotations(rawAnnotations, cp, declaringClass, false, selectAnnotationClasses).values()); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index e797ce43b8c00..fff327a6d59d7 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -23,19 +23,14 @@ package jdk.vm.ci.hotspot; -import java.lang.reflect.Executable; -import java.lang.reflect.Field; - import jdk.internal.misc.Unsafe; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.code.InvalidInstalledCodeException; import jdk.vm.ci.code.stack.InspectedFrameVisitor; import jdk.vm.ci.common.InitTimer; -import static jdk.vm.ci.common.InitTimer.timer; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; -import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; @@ -44,6 +39,12 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; + +import static jdk.vm.ci.common.InitTimer.timer; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; + /** * Calls from Java into HotSpot. The behavior of all the methods in this class that take a native * pointer as an argument (e.g., {@link #getSymbol(long)}) is undefined if the argument does not @@ -1486,7 +1487,7 @@ native byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl hold Object filterTypes, int filterLength, long filterKlassPointers); /** - * Helper for passing {@Klass*} values to native code. + * Helper for passing {@code Klass*} values to native code. */ static final class KlassPointers implements AutoCloseable { final ResolvedJavaType[] types; @@ -1498,20 +1499,23 @@ static final class KlassPointers implements AutoCloseable { } /** - * Gets the buffer in which to pass the {@Klass*} values to JNI. + * Gets the buffer in which to pass the {@code Klass*} values to JNI. * - * @return a {@Klass*} value if {@code types.length == 1} otherwise the address of a native - * buffer holding an array of {@Klass*} values + * @return 0L if {@code types.length == 0}, a {@code Klass*} value if {@code types.length == 1} + * otherwise the address of a native buffer holding an array of {@code Klass*} values */ long buffer() { - int length = types.length; + long length = types.length; + if (length == 0) { + return 0L; + } if (length == 1) { return ((HotSpotResolvedObjectTypeImpl) types[0]).getKlassPointer(); } else { pointersArray = unsafe.allocateMemory(length * Long.BYTES); long pos = pointersArray; - for (int i = 0; i < types.length; i++) { - HotSpotResolvedObjectTypeImpl hsType = (HotSpotResolvedObjectTypeImpl) types[i]; + for (ResolvedJavaType type : types) { + HotSpotResolvedObjectTypeImpl hsType = (HotSpotResolvedObjectTypeImpl) type; unsafe.putLong(pos, hsType.getKlassPointer()); pos += Long.BYTES; } @@ -1521,7 +1525,7 @@ long buffer() { @Override public void close() { - if (types.length != 1 && pointersArray != 0) { + if (types.length > 1 && pointersArray != 0) { unsafe.freeMemory(pointersArray); pointersArray = 0; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java index 8b49952b01807..f3c3996ad9b14 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java @@ -39,9 +39,9 @@ public interface Annotated { * Class initialization is not triggered for enum types referenced by the returned * annotation. This method ignores inherited annotations. * - * @param types annotation types to select + * @param types annotation types to select. If empty, then all declared annotations are returned. * @return an immutable map from annotation type to annotation of the annotations directly present - * on this element that match {@code types} + * on this element selected by {@code types} * @throws IllegalArgumentException if any type in {@code types} is not an annotation interface type * @throws UnsupportedOperationException if this operation is not supported */ diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index 5dc3df9ec4254..db6f17784b97c 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -1305,7 +1305,7 @@ private static void getAnnotationValueExpectedToFail(Annotated annotated, Resolv /** * Tests that {@link AnnotationValue}s obtained from a {@link Class}, {@link Method} or - * {@link Field} matches {@link AnnotatedElement#getDeclaredAnnotations()} for the corresponding JVMCI + * {@link Field} match {@link AnnotatedElement#getDeclaredAnnotations()} for the corresponding JVMCI * object. * * @param annotatedElement a {@link Class}, {@link Method} or {@link Field} object @@ -1331,6 +1331,10 @@ public static List getAnnotationValueTest(AnnotatedElement anno private static List testGetAnnotationValue(Annotated annotated, List annotations) throws AssertionError { ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); List res = new ArrayList<>(annotations.size()); + + Map allAnnotationValues = annotated.getDeclaredAnnotationValues(); + assertEquals(annotations.size(), allAnnotationValues.size()); + for (Annotation a : annotations) { var annotationType = metaAccess.lookupJavaType(a.annotationType()); AnnotationValue av = annotated.getDeclaredAnnotationValue(annotationType); @@ -1340,6 +1344,9 @@ private static List testGetAnnotationValue(Annotated annotated, AnnotationValue av2 = annotated.getDeclaredAnnotationValue(annotationType); assertEquals(av, av2); + av2 = allAnnotationValues.get(annotationType); + assertAnnotationsEquals(a, av2); + Map annotationValues = annotated.getDeclaredAnnotationValues(annotationType, suppressWarningsType, suppressWarningsType); assertEquals(1, annotationValues.size()); From 44724b51a28623fd5a9265344df9546b814819ca Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Mon, 18 Aug 2025 23:02:35 +0200 Subject: [PATCH 10/20] added JVMCI support for type annotations --- src/hotspot/share/classfile/vmSymbols.hpp | 2 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 23 ++-- .../classes/jdk/internal/vm/VMSupport.java | 112 ++++++++++++++++-- src/java.base/share/classes/module-info.java | 3 +- .../reflect/annotation/TypeAnnotation.java | 20 +++- .../annotation/TypeAnnotationParser.java | 28 +++-- .../vm/ci/hotspot/AnnotationValueDecoder.java | 9 +- .../jdk/vm/ci/hotspot/CompilerToVM.java | 32 ++--- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 11 +- .../HotSpotResolvedJavaMethodImpl.java | 11 +- .../HotSpotResolvedObjectTypeImpl.java | 13 +- .../hotspot/HotSpotResolvedPrimitiveType.java | 6 + .../jdk/vm/ci/meta/ResolvedJavaField.java | 13 ++ .../jdk/vm/ci/meta/ResolvedJavaMethod.java | 13 ++ .../jdk/vm/ci/meta/ResolvedJavaType.java | 17 ++- .../meta/annotation/TypeAnnotationValue.java | 98 +++++++++++++++ .../runtime/test/TestResolvedJavaField.java | 75 ++++++++---- .../runtime/test/TestResolvedJavaMethod.java | 109 ++++++++++------- .../ci/runtime/test/TestResolvedJavaType.java | 74 +++++++++--- .../jdk/vm/ci/runtime/test/TypeUniverse.java | 55 +++++++-- .../AnnotationTestInput.java | 21 +++- .../TestAnnotationEncodingDecoding.java | 35 +++++- 22 files changed, 628 insertions(+), 152 deletions(-) create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/TypeAnnotationValue.java diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 7a3076509365b..0288c7d80698c 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -706,7 +706,7 @@ class SerializeClosure; template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \ template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \ template(encodeAnnotations_name, "encodeAnnotations") \ - template(encodeAnnotations_signature, "([BLjava/lang/Class;Ljdk/internal/reflect/ConstantPool;[Ljava/lang/Class;)[B")\ + template(encodeAnnotations_signature, "([BZLjava/lang/Class;Ljdk/internal/reflect/ConstantPool;[Ljava/lang/Class;)[B")\ template(decodeAndThrowThrowable_signature, "(IJZZ)V") \ template(classRedefinedCount_name, "classRedefinedCount") \ template(classLoader_name, "classLoader") \ diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 12f89f12acdd1..31b39573e7b64 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -3015,6 +3015,7 @@ C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAI C2V_END static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, AnnotationArray* annotations_array, + jboolean is_type_annotations, jint filter_length, jlong filter_klass_pointers, JavaThread* THREAD, JVMCI_TRAPS) { // Get a ConstantPool object for annotation parsing @@ -3049,6 +3050,7 @@ static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, Annotatio JavaValue result(T_OBJECT); JavaCallArguments args; args.push_oop(annotations); + args.push_int(is_type_annotations); args.push_oop(Handle(THREAD, holder->java_mirror())); args.push_oop(jcp); args.push_oop(filter_classes); @@ -3079,26 +3081,29 @@ static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, Annotatio return JVMCIENV->get_jbyteArray(ba_dest); } -C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), +C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jboolean is_type_annotations, jobject filter, jint filter_length, jlong filter_klass_pointers)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support InstanceKlass* holder = InstanceKlass::cast(UNPACK_PAIR(Klass, klass)); - return get_encoded_annotation_values(holder, holder->class_annotations(), filter_length, filter_klass_pointers, THREAD, JVMCIENV); + AnnotationArray* raw_annotations = is_type_annotations ? holder->class_type_annotations() : holder->class_annotations(); + return get_encoded_annotation_values(holder, raw_annotations, is_type_annotations, filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END -C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), +C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), jboolean is_type_annotations, jobject filter, jint filter_length, jlong filter_klass_pointers)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support methodHandle method(THREAD, UNPACK_PAIR(Method, method)); - return get_encoded_annotation_values(method->method_holder(), method->annotations(), filter_length, filter_klass_pointers, THREAD, JVMCIENV); + AnnotationArray* raw_annotations = is_type_annotations ? method->type_annotations() : method->annotations(); + return get_encoded_annotation_values(method->method_holder(), raw_annotations, is_type_annotations, filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END -C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, +C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, jboolean is_type_annotations, jobject filter, jint filter_length, jlong filter_klass_pointers)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support InstanceKlass* holder = check_field(InstanceKlass::cast(UNPACK_PAIR(Klass, klass)), index, JVMCI_CHECK_NULL); fieldDescriptor fd(holder, index); - return get_encoded_annotation_values(holder, fd.annotations(), filter_length, filter_klass_pointers, THREAD, JVMCIENV); + AnnotationArray* raw_annotations = is_type_annotations ? fd.type_annotations() : fd.annotations(); + return get_encoded_annotation_values(holder, raw_annotations, is_type_annotations, filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_NULL(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current)) @@ -3442,9 +3447,9 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)}, {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" REFLECTION_EXECUTABLE, FN_PTR(asReflectionExecutable)}, {CC "asReflectionField", CC "(" HS_KLASS2 "I)" REFLECTION_FIELD, FN_PTR(asReflectionField)}, - {CC "getEncodedClassAnnotationValues", CC "(" HS_KLASS2 OBJECT "IJ)[B", FN_PTR(getEncodedClassAnnotationValues)}, - {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 OBJECT "IJ)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, - {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "I" OBJECT "IJ)[B", FN_PTR(getEncodedFieldAnnotationValues)}, + {CC "getEncodedClassAnnotationValues", CC "(" HS_KLASS2 "Z" OBJECT "IJ)[B", FN_PTR(getEncodedClassAnnotationValues)}, + {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 "Z" OBJECT "IJ)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, + {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "IZ" OBJECT "IJ)[B", FN_PTR(getEncodedFieldAnnotationValues)}, {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, {CC "getFailedSpeculationsAddress", CC "(" HS_METHOD2 ")J", FN_PTR(getFailedSpeculationsAddress)}, {CC "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)}, diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index 4d3c1edf92ced..0402a767469cd 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -31,6 +31,8 @@ import sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy; import sun.reflect.annotation.EnumValue; import sun.reflect.annotation.EnumValueArray; +import sun.reflect.annotation.TypeAnnotation; +import sun.reflect.annotation.TypeAnnotationParser; import sun.reflect.annotation.TypeNotPresentExceptionProxy; import java.io.ByteArrayInputStream; @@ -184,14 +186,17 @@ public static int encodeThrowable(Throwable throwable, long buffer, int bufferSi } /** - * Parses {@code rawAnnotations} into a list of {@link Annotation}s and then - * serializes them to a byte array with {@link #encodeAnnotations(Collection)}. + * Parses {@code rawAnnotations} into a list of {@link Annotation}s (isTypeAnnotations == false) + * or {@link TypeAnnotation}s (isTypeAnnotations == true) and then + * serializes them to a byte array with {@link #encodeAnnotations(Collection)} or + * {@link #encodeTypeAnnotations(TypeAnnotation[])}. */ public static byte[] encodeAnnotations(byte[] rawAnnotations, + boolean isTypeAnnotations, Class declaringClass, ConstantPool cp, Class[] selectAnnotationClasses) { - if (selectAnnotationClasses != null) { + if (!isTypeAnnotations && selectAnnotationClasses != null) { if (selectAnnotationClasses.length == 0) { throw new IllegalArgumentException("annotation class selection must be null or non-empty"); } @@ -201,7 +206,11 @@ public static byte[] encodeAnnotations(byte[] rawAnnotations, } } } - return encodeAnnotations(AnnotationParser.parseSelectAnnotations(rawAnnotations, cp, declaringClass, false, selectAnnotationClasses).values()); + if (isTypeAnnotations) { + return encodeTypeAnnotations(TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, declaringClass)); + } else { + return encodeAnnotations(AnnotationParser.parseSelectAnnotations(rawAnnotations, cp, declaringClass, false, selectAnnotationClasses).values()); + } } /** @@ -399,18 +408,54 @@ private static void encodeAnnotation(DataOutputStream dos, Annotation a) throws } } + /** + * Encodes typeAnnotations to a byte array. The byte array can be decoded with {@link #decodeAnnotations(byte[], AnnotationDecoder)}. + */ + public static byte[] encodeTypeAnnotations(TypeAnnotation[] typeAnnotations) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(128); + try (DataOutputStream dos = new DataOutputStream(baos)) { + writeLength(dos, typeAnnotations.length); + for (TypeAnnotation ta : typeAnnotations) { + encodeTypeAnnotation(dos, ta); + } + } + return baos.toByteArray(); + } catch (Exception e) { + throw new InternalError(e); + } + } + + private static void encodeTypeAnnotation(DataOutputStream dos, TypeAnnotation ta) throws Exception { + TypeAnnotation.TypeAnnotationTargetInfo ti = ta.getTargetInfo(); + TypeAnnotation.TypeAnnotationTarget target = ti.getTarget(); + dos.writeUTF(target.name()); + dos.writeInt(ti.getCount()); + dos.writeInt(ti.getSecondaryIndex()); + TypeAnnotation.LocationInfo li = ta.getLocationInfo(); + int depth = li.getDepth(); + dos.writeInt(depth); + for (int i = 0; i < depth; i++) { + TypeAnnotation.LocationInfo.Location loc = li.getLocationAt(i); + dos.write(loc.tag); + dos.writeShort(loc.index); + } + encodeAnnotation(dos, ta.getAnnotation()); + } + /** * Helper for {@link #decodeAnnotations(byte[], AnnotationDecoder)} to convert a byte * array (ostensibly produced by {@link VMSupport#encodeAnnotations}) into objects. * * @param type to which a type name is {@linkplain #resolveType(String) resolved} * @param type of the object representing a decoded annotation + * @param type of the object representing a decoded type annotation * @param type of the object representing a decoded enum constant * @param type of the object representing a decoded array of enum constants * @param type of the object representing a missing type * @param type of the object representing a decoded element type mismatch */ - public interface AnnotationDecoder { + public interface AnnotationDecoder { /** * Resolves a name in {@link Class#getName()} format to an object of type {@code T}. */ @@ -424,6 +469,11 @@ public interface AnnotationDecoder { */ A newAnnotation(T type, Map.Entry[] elements); + /** + * Creates an object representing a decoded type annotation. + */ + TA newTypeAnnotation(TypeAnnotation.TypeAnnotationTargetInfo targetInfo, TypeAnnotation.LocationInfo locationInfo, A annotation); + /** * Creates an object representing a decoded enum. * @@ -468,7 +518,7 @@ public interface AnnotationDecoder { * @return an immutable list of {@code A} objects */ @SuppressWarnings("unchecked") - public static List decodeAnnotations(byte[] encoded, AnnotationDecoder decoder) { + public static List decodeAnnotations(byte[] encoded, AnnotationDecoder decoder) { try { ByteArrayInputStream bais = new ByteArrayInputStream(encoded); DataInputStream dis = new DataInputStream(bais); @@ -479,7 +529,7 @@ public static List decodeAnnotations(byte[] encoded, A } @SuppressWarnings({"rawtypes", "unchecked"}) - private static A decodeAnnotation(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + private static A decodeAnnotation(DataInputStream dis, AnnotationDecoder decoder) throws IOException { String typeName = dis.readUTF(); T type = decoder.resolveType(typeName); int n = readLength(dis); @@ -508,12 +558,13 @@ private static A decodeAnnotation(DataInputStream dis, An } return decoder.newAnnotation(type, (Map.Entry[]) elements); } + @FunctionalInterface interface IOReader { Object read() throws IOException; } - private static Object decodeArray(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + private static Object decodeArray(DataInputStream dis, AnnotationDecoder decoder) throws IOException { byte componentTag = dis.readByte(); return switch (componentTag) { case 'B' -> readArray(dis, dis::readByte); @@ -540,7 +591,7 @@ private static Object decodeArray(DataInputStream dis, An * returns it as an object of type {@code E}. */ @SuppressWarnings("unchecked") - private static EA readEnumArray(DataInputStream dis, AnnotationDecoder decoder, T enumType) throws IOException { + private static EA readEnumArray(DataInputStream dis, AnnotationDecoder decoder, T enumType) throws IOException { List names = (List) readArray(dis, dis::readUTF); return decoder.newEnumArray(enumType, names); } @@ -549,7 +600,7 @@ private static EA readEnumArray(DataInputStream dis, Anno * Reads a class encoded at the current read position of {@code dis} and * returns it as an object of type {@code T}. */ - private static T readClass(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + private static T readClass(DataInputStream dis, AnnotationDecoder decoder) throws IOException { return decoder.resolveType(dis.readUTF()); } @@ -594,4 +645,45 @@ private static int readLength(DataInputStream dis) throws IOException { } return length; } + + /** + * Decodes type annotations serialized in {@code encoded} to objects. + * + * @param type to which a type name is resolved + * @param type of the object representing a decoded annotation + * @param type of the object representing a decoded enum constant + * @param type of the object representing a missing type + * @param type of the object representing a decoded element type mismatch + * @return an immutable list of {@code A} objects + */ + @SuppressWarnings("unchecked") + public static List decodeTypeAnnotations(byte[] encoded, AnnotationDecoder decoder) { + try { + ByteArrayInputStream bais = new ByteArrayInputStream(encoded); + DataInputStream dis = new DataInputStream(bais); + return (List) readArray(dis, () -> decodeTypeAnnotation(dis, decoder)); + } catch (Exception e) { + throw new InternalError(e); + } + } + + private static TA decodeTypeAnnotation(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + TypeAnnotation.TypeAnnotationTarget target = TypeAnnotation.TypeAnnotationTarget.valueOf(dis.readUTF()); + int count = dis.readInt(); + int secondaryIndex = dis.readInt(); + TypeAnnotation.TypeAnnotationTargetInfo ti = new TypeAnnotation.TypeAnnotationTargetInfo(target, count, secondaryIndex); + int depth = dis.readInt(); + TypeAnnotation.LocationInfo li; + if (depth == 0) { + li = TypeAnnotation.LocationInfo.BASE_LOCATION; + } else { + TypeAnnotation.LocationInfo.Location[] locs = new TypeAnnotation.LocationInfo.Location[depth]; + for (int i = 0; i != depth; i++) { + locs[i] = new TypeAnnotation.LocationInfo.Location(dis.readByte(), dis.readShort()); + } + li = new TypeAnnotation.LocationInfo(depth, locs); + } + A annotation = decodeAnnotation(dis, decoder); + return decoder.newTypeAnnotation(ti, li, annotation); + } } diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 2a51a0af38de2..c411679b8c100 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -300,7 +300,8 @@ exports sun.nio.fs to jdk.net; exports sun.reflect.annotation to - jdk.compiler; + jdk.compiler, + jdk.internal.vm.ci; exports sun.reflect.generics.reflectiveObjects to java.desktop; exports sun.reflect.misc to diff --git a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java index bcd0761dfa693..7cabd4988e1ba 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java +++ b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java @@ -36,9 +36,9 @@ * annotations on declarations in the class file to actual Annotations in * AnnotatedType instances. * - * TypeAnnotaions contain a base Annotation, location info (which lets you + * TypeAnnotations contain a base Annotation, location info (which lets you * distinguish between '@A Inner.@B Outer' in for example nested types), - * target info and the declaration the TypeAnnotaiton was parsed from. + * target info and the declaration the TypeAnnotation was parsed from. */ public final class TypeAnnotation { private final TypeAnnotationTargetInfo targetInfo; @@ -143,11 +143,19 @@ public static final class LocationInfo { private LocationInfo() { this(0, new Location[0]); } - private LocationInfo(int depth, Location[] locations) { + public LocationInfo(int depth, Location[] locations) { this.depth = depth; this.locations = locations; } + public int getDepth() { + return depth; + } + + public Location getLocationAt(int index) { + return locations[index]; + } + public static final LocationInfo BASE_LOCATION = new LocationInfo(); public static LocationInfo parseLocationInfo(ByteBuffer buf) { @@ -239,8 +247,8 @@ public Location(byte tag, short index) { @Override public String toString() { - return annotation.toString() + " with Targetnfo: " + - targetInfo.toString() + " on base declaration: " + - baseDeclaration.toString(); + return annotation + " with TargetInfo: " + + targetInfo + " on base declaration: " + + baseDeclaration; } } diff --git a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java index e5b0da3be84a4..0248e4fa7cf30 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java +++ b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java @@ -66,7 +66,7 @@ public static AnnotatedType buildAnnotatedType(byte[] rawAnnotations, Type type, TypeAnnotationTarget filter) { TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations, - cp, decl, container); + cp, decl, false, container); List l = new ArrayList<>(tas.length); for (TypeAnnotation t : tas) { @@ -107,7 +107,7 @@ public static AnnotatedType[] buildAnnotatedTypes(byte[] rawAnnotations, ArrayList[] l = new ArrayList[size]; // array of ArrayList TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations, - cp, decl, container); + cp, decl, false, container); for (TypeAnnotation t : tas) { TypeAnnotationTargetInfo ti = t.getTargetInfo(); @@ -342,14 +342,15 @@ static TypeAnnotation[] parseAllTypeAnnotations(AnnotatedElement decl) { return EMPTY_TYPE_ANNOTATION_ARRAY; } return parseTypeAnnotations(rawBytes, javaLangAccess.getConstantPool(container), - decl, container); + decl, false, container); } /* Parse type annotations encoded as an array of bytes */ - private static TypeAnnotation[] parseTypeAnnotations(byte[] rawAnnotations, - ConstantPool cp, - AnnotatedElement baseDecl, - Class container) { + public static TypeAnnotation[] parseTypeAnnotations(byte[] rawAnnotations, + ConstantPool cp, + AnnotatedElement baseDecl, + boolean eagerResolution, + Class container) { if (rawAnnotations == null) return EMPTY_TYPE_ANNOTATION_ARRAY; @@ -359,7 +360,7 @@ private static TypeAnnotation[] parseTypeAnnotations(byte[] rawAnnotations, // Parse each TypeAnnotation for (int i = 0; i < annotationCount; i++) { - TypeAnnotation ta = parseTypeAnnotation(buf, cp, baseDecl, container); + TypeAnnotation ta = parseTypeAnnotation(buf, cp, baseDecl, eagerResolution, container); if (ta != null) typeAnnotations.add(ta); } @@ -413,14 +414,15 @@ static Map, Annotation> mapTypeAnnotations(TypeAnnot private static final byte CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = (byte)0x4A; private static final byte METHOD_REFERENCE_TYPE_ARGUMENT = (byte)0x4B; - private static TypeAnnotation parseTypeAnnotation(ByteBuffer buf, - ConstantPool cp, - AnnotatedElement baseDecl, - Class container) { + public static TypeAnnotation parseTypeAnnotation(ByteBuffer buf, + ConstantPool cp, + AnnotatedElement baseDecl, + boolean eagerResolution, + Class container) { try { TypeAnnotationTargetInfo ti = parseTargetInfo(buf); LocationInfo locationInfo = LocationInfo.parseLocationInfo(buf); - Annotation a = AnnotationParser.parseAnnotation(buf, cp, container, true, false); + Annotation a = AnnotationParser.parseAnnotation(buf, cp, container, eagerResolution, false); if (ti == null) // Inside a method for example return null; return new TypeAnnotation(ti, locationInfo, a, baseDecl); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java index 9a0dd110c9dad..d61be7de14de7 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java @@ -33,6 +33,8 @@ import jdk.vm.ci.meta.annotation.EnumArrayElement; import jdk.vm.ci.meta.annotation.EnumElement; import jdk.vm.ci.meta.annotation.MissingType; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; +import sun.reflect.annotation.TypeAnnotation; import java.util.List; import java.util.Map; @@ -44,7 +46,7 @@ * and employs {@link AnnotationValue} to represent decoded annotations and enum * constants respectively. */ -final class AnnotationValueDecoder implements AnnotationDecoder { +final class AnnotationValueDecoder implements AnnotationDecoder { private final HotSpotResolvedJavaType accessingClass; @@ -68,6 +70,11 @@ public AnnotationValue newAnnotation(ResolvedJavaType type, Map.Entry 1 && pointersArray != 0) { + if (pointersArray != 0) { unsafe.freeMemory(pointersArray); pointersArray = 0; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 4cfa2aeecaf20..c74ae0ba0f87c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -22,13 +22,16 @@ */ package jdk.vm.ci.hotspot; +import jdk.internal.vm.VMSupport; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.UnresolvedJavaType; import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import java.lang.annotation.Annotation; +import java.util.List; import java.util.Map; import static jdk.internal.misc.Unsafe.ADDRESS_SIZE; @@ -250,7 +253,13 @@ public Map getDeclaredAnnotationValues(Resolv } private Map getAnnotationValues0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, filter); + byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, false, filter); return new AnnotationValueDecoder(getDeclaringClass()).decode(encoded); } + + @Override + public List getTypeAnnotationValues() { + byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, true, null); + return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index c0e9e391615c9..5f59eec058d7e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -22,6 +22,7 @@ */ package jdk.vm.ci.hotspot; +import jdk.internal.vm.VMSupport; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; import jdk.vm.ci.meta.Constant; @@ -39,12 +40,14 @@ import jdk.vm.ci.meta.SpeculationLog; import jdk.vm.ci.meta.TriState; import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import java.lang.annotation.Annotation; import java.lang.reflect.Executable; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.BitSet; +import java.util.List; import java.util.Map; import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; @@ -790,10 +793,16 @@ public Map getDeclaredAnnotationValues(Resolv } private Map getAnnotationValues0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, filter); + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, false, filter); return new AnnotationValueDecoder(getDeclaringClass()).decode(encoded); } + @Override + public List getTypeAnnotationValues() { + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, true, null); + return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); + } + @Override public BitSet getOopMapAt(int bci) { if (getCodeSize() == 0) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 88bbab2a75b9a..fad6743781b66 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -22,6 +22,7 @@ */ package jdk.vm.ci.hotspot; +import jdk.internal.vm.VMSupport; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.Assumptions.ConcreteMethod; @@ -38,6 +39,7 @@ import jdk.vm.ci.meta.UnresolvedJavaField; import jdk.vm.ci.meta.UnresolvedJavaType; import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import java.lang.annotation.Annotation; import java.lang.reflect.Field; @@ -1133,7 +1135,16 @@ public Map getDeclaredAnnotationValues(Resolv } private Map getAnnotationValues0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, filter); + byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, false, filter); return new AnnotationValueDecoder(this).decode(encoded); } + + @Override + public List getTypeAnnotationValues() { + if (isArray()) { + return List.of(); + } + byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, true, null); + return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(this)); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index 2386f6b1ba6c5..fbc94b4d5e974 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -31,6 +31,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import java.lang.annotation.Annotation; import java.lang.reflect.Modifier; @@ -352,4 +353,9 @@ public Map getDeclaredAnnotationValues(Resolv checkAreAnnotations(types); return Map.of(); } + + @Override + public List getTypeAnnotationValues() { + return List.of(); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index 0de311571e31f..43e02dd98b394 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -23,9 +23,12 @@ package jdk.vm.ci.meta; import jdk.vm.ci.meta.annotation.Annotated; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.util.List; /** * Represents a reference to a resolved Java field. Fields, like methods and types, are resolved @@ -80,4 +83,14 @@ default boolean isFinal() { default JavaConstant getConstantValue() { throw new UnsupportedOperationException(); } + + /** + * Gets the type annotations for this field that backs the implementation + * of {@link Field#getAnnotatedType()}. + * + * @throws UnsupportedOperationException if this operation is not supported + */ + default List getTypeAnnotationValues() { + throw new UnsupportedOperationException(getClass().getName()); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index 743df269c33a7..83609ed5ef6e5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -23,6 +23,7 @@ package jdk.vm.ci.meta; import jdk.vm.ci.meta.annotation.Annotated; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; @@ -30,6 +31,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; +import java.util.List; /** * Represents a resolved Java method. Methods, like fields and types, are resolved through @@ -487,4 +489,15 @@ default boolean isScoped() { * responsibility to ensure the same speculation log is used throughout a compilation. */ SpeculationLog getSpeculationLog(); + + /** + * Gets the type annotations for this method that back the implementation + * of {@link Method#getAnnotatedReturnType()}, {@link Method#getAnnotatedReceiverType()}, + * {@link Method#getAnnotatedExceptionTypes()} and {@link Method#getAnnotatedParameterTypes()}. + * + * @throws UnsupportedOperationException if this operation is not supported + */ + default List getTypeAnnotationValues() { + throw new UnsupportedOperationException(getClass().getName()); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index eb3f8da62be67..c09517318d1f7 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -22,11 +22,12 @@ */ package jdk.vm.ci.meta; -import java.lang.reflect.AnnotatedElement; -import java.util.List; - import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.annotation.Annotated; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; + +import java.lang.reflect.AnnotatedElement; +import java.util.List; /** * Represents a resolved Java type. Types include primitives, objects, {@code void}, and arrays @@ -426,4 +427,14 @@ default ResolvedJavaField resolveField(UnresolvedJavaField unresolvedJavaField, default boolean isConcrete() { return isArray() || !isAbstract(); } + + /** + * Gets the type annotations for this type that back the implementation + * of {@link Class#getAnnotatedSuperclass()} and {@link Class#getAnnotatedInterfaces()}. + * + * @throws UnsupportedOperationException if this operation is not supported + */ + default List getTypeAnnotationValues() { + throw new UnsupportedOperationException(getClass().getName()); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/TypeAnnotationValue.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/TypeAnnotationValue.java new file mode 100644 index 0000000000000..6bf98cd326f96 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/TypeAnnotationValue.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025, 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 jdk.vm.ci.meta.annotation; + +import sun.reflect.annotation.TypeAnnotation; + +public final class TypeAnnotationValue { + + private final TypeAnnotation.TypeAnnotationTargetInfo targetInfo; + private final TypeAnnotation.LocationInfo locationInfo; + private final AnnotationValue annotation; + + public TypeAnnotationValue(TypeAnnotation.TypeAnnotationTargetInfo targetInfo, + TypeAnnotation.LocationInfo locationInfo, + AnnotationValue annotation) { + this.targetInfo = targetInfo; + this.locationInfo = locationInfo; + this.annotation = annotation; + } + + public AnnotationValue getAnnotation() { + return annotation; + } + + public TypeAnnotation.TypeAnnotationTargetInfo getTargetInfo() { + return targetInfo; + } + + public TypeAnnotation.LocationInfo getLocationInfo() { + return locationInfo; + } + + @Override + public String toString() { + return annotation + ""; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TypeAnnotationValue that) { + return equal(this.targetInfo, that.targetInfo) && + equal(this.locationInfo, that.locationInfo) && + this.annotation.equals(that.annotation); + } + return false; + } + + @Override + public int hashCode() { + return 13 ^ targetInfo.getCount() ^ + targetInfo.getSecondaryIndex() ^ + targetInfo.getTarget().hashCode() ^ + locationInfo.getDepth() ^ + annotation.hashCode(); + } + + public static boolean equal(TypeAnnotation.TypeAnnotationTargetInfo left, TypeAnnotation.TypeAnnotationTargetInfo right) { + return left.getTarget() == right.getTarget() && + left.getCount() == right.getCount() && + left.getSecondaryIndex() == right.getSecondaryIndex(); + } + + public static boolean equal(TypeAnnotation.LocationInfo left, TypeAnnotation.LocationInfo right) { + if (left.getDepth() != right.getDepth()) { + return false; + } + for (int i = 0; i < left.getDepth(); i++) { + if (!equal(left.getLocationAt(i), right.getLocationAt(i))) { + return false; + } + } + return true; + } + + public static boolean equal(TypeAnnotation.LocationInfo.Location left, TypeAnnotation.LocationInfo.Location right) { + return left.tag == right.tag && left.index == right.index; + } +} diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java index 95f8b4022dc5d..c57b14edc872b 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java @@ -35,6 +35,8 @@ * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules jdk.internal.vm.ci/jdk.vm.ci.meta + * java.base/java.lang:open + * java.base/java.lang.reflect:open * jdk.internal.vm.ci/jdk.vm.ci.meta.annotation * jdk.internal.vm.ci/jdk.vm.ci.hotspot * jdk.internal.vm.ci/jdk.vm.ci.runtime @@ -48,12 +50,19 @@ package jdk.vm.ci.runtime.test; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import jdk.internal.vm.test.AnnotationTestInput; +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; +import jdk.vm.ci.runtime.test.TestResolvedJavaField.TestClassLoader; +import org.junit.Assert; +import org.junit.Test; +import sun.reflect.annotation.TypeAnnotation; +import sun.reflect.annotation.TypeAnnotationParser; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -68,17 +77,12 @@ import java.util.Map; import java.util.Set; -import org.junit.Assert; -import org.junit.Test; - -import jdk.internal.vm.test.AnnotationTestInput; -import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.runtime.test.TestResolvedJavaField.TestClassLoader; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; /** * Tests for {@link ResolvedJavaField}. @@ -196,11 +200,42 @@ private Method findTestMethod(Method apiMethod) { return null; } + /** + * Tests that {@link TypeAnnotation}s obtained from {@code field} + * match {@link TypeAnnotationValue}s for the corresponding {@link ResolvedJavaField}. + */ + private static void getTypeAnnotationValuesTest(Field field) { + ResolvedJavaField javaField = metaAccess.lookupJavaField(field); + TestResolvedJavaType.assertTypeAnnotationsEquals(getTypeAnnotations(field), javaField.getTypeAnnotationValues()); + } + + private static final Method fieldGetTypeAnnotationBytes = lookupMethod(Field.class, "getTypeAnnotationBytes0"); + private static final Method classGetConstantPool = lookupMethod(Class.class, "getConstantPool"); + + private static TypeAnnotation[] getTypeAnnotations(Field f) { + byte[] rawAnnotations = invokeMethod(fieldGetTypeAnnotationBytes, f); + Class container = f.getDeclaringClass(); + jdk.internal.reflect.ConstantPool cp = invokeMethod(classGetConstantPool, container); + return TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, container); + } + @Test - public void getAnnotationValueTest() throws Exception { - TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredField("annotatedField")); + public void getTypeAnnotationValuesTest() throws Exception { + for (Field f : AnnotationTestInput.class.getDeclaredFields()) { + getTypeAnnotationValuesTest(f); + } + for (Field f : fields.keySet()) { + getTypeAnnotationValuesTest(f); + } + } + + @Test + public void getAnnotationValuesTest() throws Exception { + for (Field f : AnnotationTestInput.class.getDeclaredFields()) { + TestResolvedJavaType.getAnnotationValuesTest(f); + } for (Field f : fields.keySet()) { - TestResolvedJavaType.getAnnotationValueTest(f); + TestResolvedJavaType.getAnnotationValuesTest(f); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index c7518cb2e3e7f..20c04865188c7 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -35,6 +35,8 @@ * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules jdk.internal.vm.ci/jdk.vm.ci.meta + * java.base/java.lang:open + * java.base/java.lang.reflect:open * jdk.internal.vm.ci/jdk.vm.ci.meta.annotation * jdk.internal.vm.ci/jdk.vm.ci.runtime * jdk.internal.vm.ci/jdk.vm.ci.common @@ -48,17 +50,37 @@ package jdk.vm.ci.runtime.test; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import jdk.internal.vm.test.AnnotationTestInput; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ConstantPool; +import jdk.vm.ci.meta.ExceptionHandler; +import jdk.vm.ci.meta.Local; +import jdk.vm.ci.meta.LocalVariableTable; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; +import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.Annotation1; +import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.Annotation2; +import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.Annotation3; +import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.NumbersDE; +import org.junit.Assert; +import org.junit.Test; +import sun.reflect.annotation.TypeAnnotation; +import sun.reflect.annotation.TypeAnnotationParser; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.classfile.CodeElement; +import java.lang.classfile.Instruction; +import java.lang.classfile.MethodModel; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Member; @@ -80,31 +102,11 @@ import java.util.Objects; import java.util.Set; -import jdk.vm.ci.meta.annotation.AnnotationValue; -import org.junit.Assert; -import org.junit.Test; - -import jdk.internal.vm.test.AnnotationTestInput; -import jdk.internal.vm.test.MemberAdded; -import java.lang.classfile.Attributes; -import java.lang.classfile.ClassFile; -import java.lang.classfile.ClassModel; -import java.lang.classfile.CodeElement; -import java.lang.classfile.MethodModel; -import java.lang.classfile.Instruction; - -import jdk.vm.ci.meta.ConstantPool; -import jdk.vm.ci.meta.ExceptionHandler; -import jdk.vm.ci.meta.Local; -import jdk.vm.ci.meta.LocalVariableTable; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.Annotation1; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.Annotation2; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.Annotation3; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.NumbersDE; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** * Tests for {@link ResolvedJavaMethod}. @@ -545,7 +547,7 @@ public void testVirtualMethodTableAccess() { } /** - * Encapsulates input for {@link TestResolvedJavaMethod#getAnnotationValueTest}. + * Encapsulates input for {@link TestResolvedJavaMethod#getAnnotationValuesTest}. */ static class AnnotationValueTest { @@ -587,20 +589,47 @@ static void methodWithThreeAnnotations() { } } + /** + * Tests that {@link TypeAnnotation}s obtained from {@code executable} + * match {@link TypeAnnotationValue}s for the corresponding {@link ResolvedJavaMethod}. + */ + private static void getTypeAnnotationValuesTest(Executable executable) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(executable); + TestResolvedJavaType.assertTypeAnnotationsEquals(getTypeAnnotations(executable), method.getTypeAnnotationValues()); + } + + private static final Method executableGetTypeAnnotationBytes = lookupMethod(Executable.class, "getTypeAnnotationBytes"); + private static final Method classGetConstantPool = lookupMethod(Class.class, "getConstantPool"); + + private static TypeAnnotation[] getTypeAnnotations(Executable e) { + byte[] rawAnnotations = invokeMethod(executableGetTypeAnnotationBytes, e); + Class container = e.getDeclaringClass(); + jdk.internal.reflect.ConstantPool cp = invokeMethod(classGetConstantPool, container); + return TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, container); + } + + @Test + public void getTypeAnnotationValuesTest() throws Exception { + getTypeAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); + for (Method m : methods.keySet()) { + getTypeAnnotationValuesTest(m); + } + } + @Test - public void getAnnotationValueTest() throws Exception { - TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); - TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("missingAnnotation")); + public void getAnnotationValuesTest() throws Exception { + TestResolvedJavaType.getAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); + TestResolvedJavaType.getAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("missingAnnotation")); try { - TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("missingNestedAnnotation")); + TestResolvedJavaType.getAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("missingNestedAnnotation")); throw new AssertionError("expected " + NoClassDefFoundError.class.getName()); } catch (NoClassDefFoundError e) { Assert.assertEquals("jdk/internal/vm/test/AnnotationTestInput$Missing", e.getMessage()); } - TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("missingTypeOfClassMember")); - TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("changeTypeOfMember")); - TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("missingMember")); - List avList = TestResolvedJavaType.getAnnotationValueTest(AnnotationTestInput.class.getDeclaredMethod("addedMember")); + TestResolvedJavaType.getAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("missingTypeOfClassMember")); + TestResolvedJavaType.getAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("changeTypeOfMember")); + TestResolvedJavaType.getAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("missingMember")); + List avList = TestResolvedJavaType.getAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("addedMember")); try { avList.getFirst().get("addedElement", Integer.class); throw new AssertionError("expected " + IllegalArgumentException.class.getName()); @@ -609,7 +638,7 @@ public void getAnnotationValueTest() throws Exception { } for (Method m : methods.keySet()) { - TestResolvedJavaType.getAnnotationValueTest(m); + TestResolvedJavaType.getAnnotationValuesTest(m); } ResolvedJavaMethod m = metaAccess.lookupJavaMethod(AnnotationValueTest.class.getDeclaredMethod("methodWithThreeAnnotations")); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index db6f17784b97c..81c8f7cb6ad12 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -35,6 +35,7 @@ * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules java.base/jdk.internal.reflect + * java.base/java.lang:open * jdk.internal.vm.ci/jdk.vm.ci.meta * jdk.internal.vm.ci/jdk.vm.ci.meta.annotation * jdk.internal.vm.ci/jdk.vm.ci.hotspot @@ -56,22 +57,23 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.UnresolvedJavaType; import jdk.vm.ci.meta.annotation.Annotated; import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.annotation.ElementTypeMismatch; import jdk.vm.ci.meta.annotation.EnumArrayElement; import jdk.vm.ci.meta.annotation.EnumElement; import jdk.vm.ci.meta.annotation.MissingType; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import org.junit.Assert; import org.junit.Test; import sun.reflect.annotation.AnnotationSupport; import sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy; import sun.reflect.annotation.ExceptionProxy; +import sun.reflect.annotation.TypeAnnotation; +import sun.reflect.annotation.TypeAnnotationParser; import sun.reflect.annotation.TypeNotPresentExceptionProxy; import java.io.DataInputStream; @@ -1213,12 +1215,40 @@ private Method findTestMethod(Method apiMethod) { } @Test - public void getAnnotationValueTest() { - getAnnotationValueTest(AnnotationTestInput.AnnotatedClass.class); - getAnnotationValueTest(int.class); - getAnnotationValueTest(void.class); + public void getTypeAnnotationValuesTest() { + getTypeAnnotationValuesTest(AnnotationTestInput.AnnotatedClass.class); + getTypeAnnotationValuesTest(int.class); + getTypeAnnotationValuesTest(void.class); for (Class c : classes) { - getAnnotationValueTest(c); + getTypeAnnotationValuesTest(c); + } + } + + /** + * Tests that {@link TypeAnnotation}s obtained from {@code cls} + * match {@link TypeAnnotationValue}s for the corresponding {@link ResolvedJavaType}. + */ + private static void getTypeAnnotationValuesTest(Class cls) { + ResolvedJavaType rt = metaAccess.lookupJavaType(cls); + assertTypeAnnotationsEquals(getTypeAnnotations(cls), rt.getTypeAnnotationValues()); + } + + private static final Method classGetRawTypeAnnotations = lookupMethod(Class.class, "getRawTypeAnnotations"); + private static final Method classGetConstantPool = lookupMethod(Class.class, "getConstantPool"); + + private static TypeAnnotation[] getTypeAnnotations(Class c) { + byte[] rawAnnotations = invokeMethod(classGetRawTypeAnnotations, c); + ConstantPool cp = invokeMethod(classGetConstantPool, c); + return TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, c); + } + + @Test + public void getAnnotationValuesTest() { + getAnnotationValuesTest(AnnotationTestInput.AnnotatedClass.class); + getAnnotationValuesTest(int.class); + getAnnotationValuesTest(void.class); + for (Class c : classes) { + getAnnotationValuesTest(c); } // Primitive classes have no annotations but we cannot directly @@ -1310,7 +1340,7 @@ private static void getAnnotationValueExpectedToFail(Annotated annotated, Resolv * * @param annotatedElement a {@link Class}, {@link Method} or {@link Field} object */ - public static List getAnnotationValueTest(AnnotatedElement annotatedElement) { + public static List getAnnotationValuesTest(AnnotatedElement annotatedElement) { Annotated annotated = toAnnotated(annotatedElement); ResolvedJavaType objectType = metaAccess.lookupJavaType(Object.class); ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); @@ -1325,10 +1355,21 @@ public static List getAnnotationValueTest(AnnotatedElement anno values = annotated.getDeclaredAnnotationValues(suppressWarningsType, suppressWarningsType, suppressWarningsType, suppressWarningsType); assertTrue(values.toString(), values.isEmpty()); - return testGetAnnotationValue(annotated, List.of(annotatedElement.getDeclaredAnnotations())); + return testGetAnnotationValues(annotated, List.of(annotatedElement.getDeclaredAnnotations())); } - private static List testGetAnnotationValue(Annotated annotated, List annotations) throws AssertionError { + public static void assertTypeAnnotationsEquals( + TypeAnnotation[] typeAnnotations, + List typeAnnotationValues) throws AssertionError { + assertEquals(typeAnnotations.length, typeAnnotationValues.size()); + for (int i = 0; i < typeAnnotations.length; i++) { + TypeAnnotation typeAnnotation = typeAnnotations[i]; + TypeAnnotationValue typeAnnotationValue = typeAnnotationValues.get(i); + assertTypeAnnotationEquals(typeAnnotation, typeAnnotationValue); + } + } + + private static List testGetAnnotationValues(Annotated annotated, List annotations) throws AssertionError { ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); List res = new ArrayList<>(annotations.size()); @@ -1382,10 +1423,6 @@ private static Annotated toAnnotated(AnnotatedElement element) { } } - private static UnresolvedJavaType asType(Class valueType) { - return UnresolvedJavaType.create(MetaUtil.toInternalName(valueType.getName())); - } - private static void assertAnnotationsEquals(Annotation a, AnnotationValue av) { Map values = AnnotationSupport.memberValues(a); for (Map.Entry e : values.entrySet()) { @@ -1404,6 +1441,15 @@ private static void assertAnnotationsEquals(Annotation a, AnnotationValue av) { } } } + private static void assertTypeAnnotationEquals(TypeAnnotation ta, TypeAnnotationValue tav) { + TypeAnnotation.TypeAnnotationTargetInfo tiLeft = ta.getTargetInfo(); + TypeAnnotation.TypeAnnotationTargetInfo tiRight = tav.getTargetInfo(); + assertTrue(tiLeft + " != " + tiRight, TypeAnnotationValue.equal(tiLeft, tiRight)); + TypeAnnotation.LocationInfo liLeft = ta.getLocationInfo(); + TypeAnnotation.LocationInfo liRight = tav.getLocationInfo(); + assertTrue(liLeft + " != " + liRight, TypeAnnotationValue.equal(liLeft, liRight)); + assertAnnotationsEquals(ta.getAnnotation(), tav.getAnnotation()); + } /** * Gets the type of an element in {@link AnnotationValue} for {@code type}. diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java index 28ba77fa6b0a3..3efe7ba8b4c02 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java @@ -22,12 +22,20 @@ */ package jdk.vm.ci.runtime.test; -import static java.lang.reflect.Modifier.isFinal; -import static java.lang.reflect.Modifier.isStatic; +import jdk.internal.misc.ScopedMemoryAccess; +import jdk.internal.misc.Unsafe; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.runtime.JVMCI; +import org.junit.Test; import java.io.Serializable; import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.AbstractCollection; import java.util.AbstractList; @@ -48,16 +56,8 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -import org.junit.Test; - -import jdk.internal.misc.Unsafe; -import jdk.internal.misc.ScopedMemoryAccess; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.runtime.JVMCI; +import static java.lang.reflect.Modifier.isFinal; +import static java.lang.reflect.Modifier.isStatic; /** * Context for type related tests. @@ -249,4 +249,35 @@ private static void addClass(Class c) { } } } + + public static Method lookupMethod(Class declaringClass, String methodName, Class... parameterTypes) { + try { + Method result = declaringClass.getDeclaredMethod(methodName, parameterTypes); + result.setAccessible(true); + return result; + } catch (ReflectiveOperationException | LinkageError cause) { + throw new AssertionError(cause); + } + } + + @SuppressWarnings("unchecked") + public static RuntimeException rethrow(Throwable ex) throws E { + throw (E) ex; + } + + @SuppressWarnings("unchecked") + public static T invokeMethod(Method method, Object receiver, Object... arguments) { + try { + method.setAccessible(true); + return (T) method.invoke(receiver, arguments); + } catch (InvocationTargetException ex) { + Throwable cause = ex.getCause(); + if (cause != null) { + throw rethrow(cause); + } + throw new AssertionError(ex); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } } diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java index 3a16d53abaa28..370c5f22d87d0 100644 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java @@ -22,11 +22,13 @@ */ package jdk.internal.vm.test; -import java.lang.annotation.Annotation; +import java.io.Serializable; +import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.lang.reflect.Method; public class AnnotationTestInput { @@ -108,7 +110,7 @@ public static class Super2 extends Super1 {} public static class Super3 extends Super1 {} @Named("NonInheritedValue") - public static class OwnName extends Super1 {} + public static class OwnName extends @TypeQualifier Super1 {} public static class InheritedName1 extends Super1 {} public static class InheritedName2 extends Super2 {} @@ -173,7 +175,7 @@ public static class InheritedName3 extends Super3 {} nestedArray = {@NestedAnno("nested11"), @NestedAnno("nested12")}) @Deprecated @SuppressWarnings({"rawtypes", "all"}) - public static class AnnotatedClass {} + public static class AnnotatedClass extends @TypeQualifier Thread implements @TypeQualifier Serializable {} @Single(string = "a", stringArray = {"a", "b"}, @@ -231,7 +233,18 @@ public static class AnnotatedClass {} moodArray = {Mood.SAD, Mood.CONFUSED}, nested = @NestedAnno("nested15"), nestedArray = {@NestedAnno("nested16"), @NestedAnno("nested17")}) - private static final int annotatedField = 45; + private static final @TypeQualifier(comment = "annotatedField comment") int annotatedField = 45; + + public @TypeQualifier String[][] s1; // Annotates the class type String + public String @TypeQualifier [][] s2; // Annotates the array type String[][] + public String[] @TypeQualifier [] s3; // Annotates the array type String[] + + // Define a type-use annotation + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + @interface TypeQualifier{ + String comment() default ""; + } @Retention(RetentionPolicy.RUNTIME) public @interface NestedAnno { diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java index cc727b95640dc..43f4896d60005 100644 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java @@ -39,6 +39,7 @@ import org.testng.annotations.Test; import sun.reflect.annotation.AnnotationSupport; import sun.reflect.annotation.ExceptionProxy; +import sun.reflect.annotation.TypeAnnotation; import sun.reflect.annotation.TypeNotPresentExceptionProxy; import java.lang.annotation.Annotation; @@ -171,6 +172,33 @@ public Class getType() { } } + public static final class TypeAnnotationConst { + final TypeAnnotation.TypeAnnotationTargetInfo targetInfo; + final TypeAnnotation.LocationInfo locationInfo; + final AnnotationConst annotation; + + TypeAnnotationConst(TypeAnnotation.TypeAnnotationTargetInfo targetInfo, TypeAnnotation.LocationInfo locationInfo, AnnotationConst annotation) { + this.targetInfo = targetInfo; + this.locationInfo = locationInfo; + this.annotation = annotation; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TypeAnnotationConst that) { + return this.targetInfo.equals(that.targetInfo) && + this.locationInfo.equals(that.locationInfo) && + this.annotation.equals(that.annotation); + } + return false; + } + + @Override + public String toString() { + return "{" + targetInfo + ";" + locationInfo + "}" + annotation; + } + } + public static final class ErrorConst { final String desc; public ErrorConst(String desc) { @@ -252,7 +280,7 @@ public List getNames() { } } - static class MyDecoder implements AnnotationDecoder, AnnotationConst, EnumConst, EnumArrayConst, ErrorConst, ErrorConst> { + static class MyDecoder implements AnnotationDecoder, AnnotationConst, TypeAnnotationConst, EnumConst, EnumArrayConst, ErrorConst, ErrorConst> { @Override public Class resolveType(String name) { try { @@ -267,6 +295,11 @@ public AnnotationConst newAnnotation(Class type, Map.Entry[] return new AnnotationConst(type, elements); } + @Override + public TypeAnnotationConst newTypeAnnotation(TypeAnnotation.TypeAnnotationTargetInfo targetInfo, TypeAnnotation.LocationInfo locationInfo, AnnotationConst annotation) { + return new TypeAnnotationConst(targetInfo, locationInfo, annotation); + } + @Override public EnumConst newEnum(Class enumType, String name) { return new EnumConst(enumType, name); From e9fdde68543020a923ac159fa308a59aa15cf059 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Wed, 20 Aug 2025 18:04:21 +0200 Subject: [PATCH 11/20] added hashCode and equals to TypeAnnotationTargetInfo, LocationInfo, and Location removed redundant LocationInfo.depth field --- .../reflect/annotation/TypeAnnotation.java | 72 +++++++++++++++---- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java index 7cabd4988e1ba..a8973916b8f84 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java +++ b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java @@ -29,7 +29,10 @@ import java.lang.reflect.AnnotatedElement; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Objects; /** * A TypeAnnotation contains all the information needed to transform type @@ -130,6 +133,22 @@ public int getSecondaryIndex() { return secondaryIndex; } + @Override + public boolean equals(Object obj) { + if (obj instanceof TypeAnnotationTargetInfo that) { + return target == that.target && + count == that.count && + secondaryIndex == that.secondaryIndex; + + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(target, count, secondaryIndex); + } + @Override public String toString() { return "" + target + ": " + count + ", " + secondaryIndex; @@ -137,23 +156,33 @@ public String toString() { } public static final class LocationInfo { - private final int depth; private final Location[] locations; private LocationInfo() { - this(0, new Location[0]); + this(new Location[0]); } - public LocationInfo(int depth, Location[] locations) { - this.depth = depth; + public LocationInfo(Location[] locations) { this.locations = locations; } - public int getDepth() { - return depth; + /** + * Gets an immutable view on the locations. + */ + public List getLocations() { + return Collections.unmodifiableList(Arrays.asList(locations)); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof LocationInfo that) { + return Arrays.equals(locations, that.locations); + } + return false; } - public Location getLocationAt(int index) { - return locations[index]; + @Override + public int hashCode() { + return Arrays.hashCode(locations); } public static final LocationInfo BASE_LOCATION = new LocationInfo(); @@ -172,7 +201,7 @@ public static LocationInfo parseLocationInfo(ByteBuffer buf) { throw new AnnotationFormatError("Bad Location encoding in Type Annotation"); locations[i] = new Location(tag, index); } - return new LocationInfo(depth, locations); + return new LocationInfo(locations); } public LocationInfo pushArray() { @@ -192,11 +221,12 @@ public LocationInfo pushTypeArg(short index) { } public LocationInfo pushLocation(byte tag, short index) { - int newDepth = this.depth + 1; + int depth = this.locations.length; + int newDepth = depth + 1; Location[] res = new Location[newDepth]; System.arraycopy(this.locations, 0, res, 0, depth); res[newDepth - 1] = new Location(tag, (short)(index & 0xFF)); - return new LocationInfo(newDepth, res); + return new LocationInfo(res); } /** @@ -204,12 +234,13 @@ public LocationInfo pushLocation(byte tag, short index) { * if no matching location was found. */ public LocationInfo popLocation(byte tag) { + int depth = locations.length; if (depth == 0 || locations[depth - 1].tag != tag) { return null; } Location[] res = new Location[depth - 1]; System.arraycopy(locations, 0, res, 0, depth - 1); - return new LocationInfo(depth - 1, res); + return new LocationInfo(res); } public TypeAnnotation[] filter(TypeAnnotation[] ta) { @@ -222,9 +253,9 @@ public TypeAnnotation[] filter(TypeAnnotation[] ta) { } boolean isSameLocationInfo(LocationInfo other) { - if (depth != other.depth) + if (locations.length != other.locations.length) return false; - for (int i = 0; i < depth; i++) + for (int i = 0; i < locations.length; i++) if (!locations[i].isSameLocation(other.locations[i])) return false; return true; @@ -238,6 +269,19 @@ boolean isSameLocation(Location other) { return tag == other.tag && index == other.index; } + @Override + public boolean equals(Object obj) { + if (obj instanceof Location that) { + return isSameLocation(that); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(tag, index); + } + public Location(byte tag, short index) { this.tag = tag; this.index = index; From 390ef130be486277c8b018f53c024322cccff81f Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Wed, 20 Aug 2025 18:13:23 +0200 Subject: [PATCH 12/20] added JVMCI support for parameter annotations --- src/hotspot/share/classfile/vmSymbols.hpp | 2 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 53 ++++++-- src/hotspot/share/jvmci/jvmciCompilerToVM.hpp | 5 + src/hotspot/share/jvmci/jvmciJavaClasses.cpp | 4 +- src/hotspot/share/jvmci/jvmciRuntime.cpp | 7 +- src/hotspot/share/prims/nativeLookup.cpp | 2 +- .../classes/jdk/internal/vm/VMSupport.java | 123 ++++++++++++++---- .../jdk/vm/ci/hotspot/CompilerToVM.java | 23 ++-- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 4 +- .../HotSpotResolvedJavaMethodImpl.java | 19 ++- .../HotSpotResolvedObjectTypeImpl.java | 4 +- .../jdk/vm/ci/meta/ResolvedJavaMethod.java | 15 +++ .../meta/annotation/TypeAnnotationValue.java | 38 ++---- .../runtime/test/TestResolvedJavaField.java | 5 +- .../runtime/test/TestResolvedJavaMethod.java | 48 ++++++- .../ci/runtime/test/TestResolvedJavaType.java | 6 +- .../jdk/vm/ci/runtime/test/TypeUniverse.java | 48 ++++++- 17 files changed, 309 insertions(+), 97 deletions(-) diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 0288c7d80698c..a98a56c861225 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -706,7 +706,7 @@ class SerializeClosure; template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \ template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \ template(encodeAnnotations_name, "encodeAnnotations") \ - template(encodeAnnotations_signature, "([BZLjava/lang/Class;Ljdk/internal/reflect/ConstantPool;[Ljava/lang/Class;)[B")\ + template(encodeAnnotations_signature, "([BILjava/lang/Class;Ljdk/internal/reflect/ConstantPool;[Ljava/lang/Class;)[B")\ template(decodeAndThrowThrowable_signature, "(IJZZ)V") \ template(classRedefinedCount_name, "classRedefinedCount") \ template(classLoader_name, "classLoader") \ diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 31b39573e7b64..c3b73f254c3ca 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -3015,7 +3015,7 @@ C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAI C2V_END static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, AnnotationArray* annotations_array, - jboolean is_type_annotations, + jint category, jint filter_length, jlong filter_klass_pointers, JavaThread* THREAD, JVMCI_TRAPS) { // Get a ConstantPool object for annotation parsing @@ -3050,7 +3050,7 @@ static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, Annotatio JavaValue result(T_OBJECT); JavaCallArguments args; args.push_oop(annotations); - args.push_int(is_type_annotations); + args.push_int(category); args.push_oop(Handle(THREAD, holder->java_mirror())); args.push_oop(jcp); args.push_oop(filter_classes); @@ -3081,29 +3081,54 @@ static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, Annotatio return JVMCIENV->get_jbyteArray(ba_dest); } -C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jboolean is_type_annotations, +C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint category, jobject filter, jint filter_length, jlong filter_klass_pointers)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support InstanceKlass* holder = InstanceKlass::cast(UNPACK_PAIR(Klass, klass)); - AnnotationArray* raw_annotations = is_type_annotations ? holder->class_type_annotations() : holder->class_annotations(); - return get_encoded_annotation_values(holder, raw_annotations, is_type_annotations, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + AnnotationArray* raw_annotations; + if (category == CompilerToVM::DECLARED_ANNOTATIONS) { + raw_annotations = holder->class_annotations(); + } else if (category == CompilerToVM::TYPE_ANNOTATIONS) { + raw_annotations = holder->class_type_annotations(); + } else { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%d", category)); + } + return get_encoded_annotation_values(holder, raw_annotations, category, filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END -C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), jboolean is_type_annotations, +C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), jint category, jobject filter, jint filter_length, jlong filter_klass_pointers)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support methodHandle method(THREAD, UNPACK_PAIR(Method, method)); - AnnotationArray* raw_annotations = is_type_annotations ? method->type_annotations() : method->annotations(); - return get_encoded_annotation_values(method->method_holder(), raw_annotations, is_type_annotations, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + AnnotationArray* raw_annotations; + if (category == CompilerToVM::DECLARED_ANNOTATIONS) { + raw_annotations = method->annotations(); + } else if (category == CompilerToVM::PARAMETER_ANNOTATIONS) { + raw_annotations = method->parameter_annotations(); + } else if (category == CompilerToVM::TYPE_ANNOTATIONS) { + raw_annotations = method->type_annotations(); + } else { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), err_msg("%d", category)); + } + return get_encoded_annotation_values(method->method_holder(), raw_annotations, category, filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END -C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, jboolean is_type_annotations, +C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, jint category, jobject filter, jint filter_length, jlong filter_klass_pointers)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support InstanceKlass* holder = check_field(InstanceKlass::cast(UNPACK_PAIR(Klass, klass)), index, JVMCI_CHECK_NULL); fieldDescriptor fd(holder, index); - AnnotationArray* raw_annotations = is_type_annotations ? fd.type_annotations() : fd.annotations(); - return get_encoded_annotation_values(holder, raw_annotations, is_type_annotations, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + AnnotationArray* raw_annotations; + if (category == CompilerToVM::DECLARED_ANNOTATIONS) { + raw_annotations = fd.annotations(); + } else if (category == CompilerToVM::TYPE_ANNOTATIONS) { + raw_annotations = fd.type_annotations(); + } else { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%d", category)); + } + return get_encoded_annotation_values(holder, raw_annotations, category, filter_length, filter_klass_pointers, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_NULL(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current)) @@ -3447,9 +3472,9 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)}, {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" REFLECTION_EXECUTABLE, FN_PTR(asReflectionExecutable)}, {CC "asReflectionField", CC "(" HS_KLASS2 "I)" REFLECTION_FIELD, FN_PTR(asReflectionField)}, - {CC "getEncodedClassAnnotationValues", CC "(" HS_KLASS2 "Z" OBJECT "IJ)[B", FN_PTR(getEncodedClassAnnotationValues)}, - {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 "Z" OBJECT "IJ)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, - {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "IZ" OBJECT "IJ)[B", FN_PTR(getEncodedFieldAnnotationValues)}, + {CC "getEncodedClassAnnotationValues", CC "(" HS_KLASS2 "I" OBJECT "IJ)[B", FN_PTR(getEncodedClassAnnotationValues)}, + {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 "I" OBJECT "IJ)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, + {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "II" OBJECT "IJ)[B", FN_PTR(getEncodedFieldAnnotationValues)}, {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, {CC "getFailedSpeculationsAddress", CC "(" HS_METHOD2 ")J", FN_PTR(getFailedSpeculationsAddress)}, {CC "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)}, diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index f06ee667ff26e..1c9850273e2d2 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -35,6 +35,11 @@ class JVMCIObjectArray; class CompilerToVM { public: + // Keep in sync with constants in VMSupport.java + static const int DECLARED_ANNOTATIONS = 0; + static const int PARAMETER_ANNOTATIONS = 1; + static const int TYPE_ANNOTATIONS = 2; + class Data { friend class JVMCIVMStructs; diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp index e5c0017129c17..bda4b515ccb3f 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp @@ -403,7 +403,7 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz, GET_JNI_CONSTRUCTOR(className, signature) extern "C" { - void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass); + void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass, jint declaredAnnotations, jint parameterAnnotations, jint typeAnnotations); jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); jlong JNICALL JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets_handle); } @@ -564,7 +564,7 @@ static void register_natives_for_class(JNIEnv* env, jclass clazz, const char* na void JNIJVMCI::register_natives(JNIEnv* env) { if (env != JavaThread::current()->jni_environment()) { - JNINativeMethod CompilerToVM_nmethods[] = {{ CC"registerNatives", CC"()V", FN_PTR(JVM_RegisterJVMCINatives) }}; + JNINativeMethod CompilerToVM_nmethods[] = {{ CC"registerNatives", CC"(III)V", FN_PTR(JVM_RegisterJVMCINatives) }}; JNINativeMethod JVMCI_nmethods[] = {{ CC"initializeRuntime", CC"()Ljdk/vm/ci/runtime/JVMCIRuntime;", FN_PTR(JVM_GetJVMCIRuntime) }}; JNINativeMethod Services_nmethods[] = {{ CC"readSystemPropertiesInfo", CC"([I)J", FN_PTR(JVM_ReadSystemPropertiesInfo) }}; diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index c0335e7c67ed2..a20877628e56d 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -1512,9 +1512,14 @@ JVMCIObject JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_TRAPS) { // Implementation of CompilerToVM.registerNatives() // When called from libjvmci, `libjvmciOrHotspotEnv` is a libjvmci env so use JVM_ENTRY_NO_ENV. -JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *libjvmciOrHotspotEnv, jclass c2vmClass)) +JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *libjvmciOrHotspotEnv, jclass c2vmClass, + jint declaredAnnotations, jint parameterAnnotations, jint typeAnnotations)) JVMCIENV_FROM_JNI(thread, libjvmciOrHotspotEnv); + assert(CompilerToVM::DECLARED_ANNOTATIONS == declaredAnnotations, "%d != %d", CompilerToVM::DECLARED_ANNOTATIONS, declaredAnnotations); + assert(CompilerToVM::PARAMETER_ANNOTATIONS == parameterAnnotations, "%d != %d", CompilerToVM::PARAMETER_ANNOTATIONS, parameterAnnotations); + assert(CompilerToVM::TYPE_ANNOTATIONS == typeAnnotations, "%d != %d", CompilerToVM::TYPE_ANNOTATIONS, typeAnnotations); + if (!EnableJVMCI) { JVMCI_THROW_MSG(InternalError, JVMCI_NOT_ENABLED_ERROR_MESSAGE); } diff --git a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp index 8c8d8510dfca2..3018a509ffee8 100644 --- a/src/hotspot/share/prims/nativeLookup.cpp +++ b/src/hotspot/share/prims/nativeLookup.cpp @@ -210,7 +210,7 @@ extern "C" { #if INCLUDE_JVMCI jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); jlong JNICALL JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets); - void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass); + void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass, jint declaredAnnotations, jint parameterAnnotations, jint typeAnnotations); #endif } diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index 0402a767469cd..e35ef970460c1 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -186,31 +186,58 @@ public static int encodeThrowable(Throwable throwable, long buffer, int bufferSi } /** - * Parses {@code rawAnnotations} into a list of {@link Annotation}s (isTypeAnnotations == false) - * or {@link TypeAnnotation}s (isTypeAnnotations == true) and then - * serializes them to a byte array with {@link #encodeAnnotations(Collection)} or - * {@link #encodeTypeAnnotations(TypeAnnotation[])}. + * Denotes a byte array that is parsed into a {@code Annotations[]}. + */ + public static final int DECLARED_ANNOTATIONS = 0; + + /** + * Denotes a byte array that is parsed into a {@code Annotations[][]}. + */ + public static final int PARAMETER_ANNOTATIONS = 1; + + /** + * Denotes a byte array that is parsed into a {@code TypeAnnotations[]}. + */ + public static final int TYPE_ANNOTATIONS = 2; + + /** + * Parses {@code rawAnnotations} according to {@code category} and returns the parse + * result encoded as a byte array. + *

+     *     category              | parse result type   | decoding method
+     *     ----------------------|--------------------|------------------------------------------
+     *     DECLARED_ANNOTATIONS  | Annotation[]        | {@link #decodeAnnotations(byte[], AnnotationDecoder)}
+     *     PARAMETER_ANNOTATIONS | Annotation[][]      | {@link #decodeAnnotations(byte[], AnnotationDecoder)}
+     *     TYPE_ANNOTATIONS      | TypeAnnotation[]    | {@link #decodeTypeAnnotations(byte[], AnnotationDecoder)}
+     * 
+ * + * @param category {@link #DECLARED_ANNOTATIONS}, {@link #PARAMETER_ANNOTATIONS} or {@link #TYPE_ANNOTATIONS} */ public static byte[] encodeAnnotations(byte[] rawAnnotations, - boolean isTypeAnnotations, + int category, Class declaringClass, ConstantPool cp, Class[] selectAnnotationClasses) { - if (!isTypeAnnotations && selectAnnotationClasses != null) { - if (selectAnnotationClasses.length == 0) { - throw new IllegalArgumentException("annotation class selection must be null or non-empty"); - } - for (Class c : selectAnnotationClasses) { - if (!c.isAnnotation()) { - throw new IllegalArgumentException(c + " is not an annotation interface"); + return switch (category) { + case DECLARED_ANNOTATIONS -> { + if (selectAnnotationClasses != null) { + if (selectAnnotationClasses.length == 0) { + throw new IllegalArgumentException("annotation class selection must be null or non-empty"); + } + for (Class c : selectAnnotationClasses) { + if (!c.isAnnotation()) { + throw new IllegalArgumentException(c + " is not an annotation interface"); + } + } } + yield encodeAnnotations(AnnotationParser.parseSelectAnnotations(rawAnnotations, cp, declaringClass, false, selectAnnotationClasses).values()); } - } - if (isTypeAnnotations) { - return encodeTypeAnnotations(TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, declaringClass)); - } else { - return encodeAnnotations(AnnotationParser.parseSelectAnnotations(rawAnnotations, cp, declaringClass, false, selectAnnotationClasses).values()); - } + case PARAMETER_ANNOTATIONS -> + encodeParameterAnnotations(AnnotationParser.parseParameterAnnotations(rawAnnotations, cp, declaringClass)); + case TYPE_ANNOTATIONS -> + encodeTypeAnnotations(TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, declaringClass)); + default -> throw new IllegalArgumentException("illegal category: " + category); + }; } /** @@ -231,6 +258,27 @@ public static byte[] encodeAnnotations(Collection annotations) { } } + /** + * Encodes parameter annotations to a byte array. The byte array can be decoded with {@link #decodeParameterAnnotations(byte[], AnnotationDecoder)}. + */ + public static byte[] encodeParameterAnnotations(Annotation[][] parameterAnnotations) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(128); + try (DataOutputStream dos = new DataOutputStream(baos)) { + writeLength(dos, parameterAnnotations.length); + for (Annotation[] annotations : parameterAnnotations) { + writeLength(dos, annotations.length); + for (Annotation a : annotations) { + encodeAnnotation(dos, a); + } + } + } + return baos.toByteArray(); + } catch (Exception e) { + throw new InternalError(e); + } + } + private static void encodeAnnotation(DataOutputStream dos, Annotation a) throws Exception { Class type = a.annotationType(); Map values = AnnotationSupport.memberValues(a); @@ -433,10 +481,9 @@ private static void encodeTypeAnnotation(DataOutputStream dos, TypeAnnotation ta dos.writeInt(ti.getCount()); dos.writeInt(ti.getSecondaryIndex()); TypeAnnotation.LocationInfo li = ta.getLocationInfo(); - int depth = li.getDepth(); - dos.writeInt(depth); - for (int i = 0; i < depth; i++) { - TypeAnnotation.LocationInfo.Location loc = li.getLocationAt(i); + List locs = li.getLocations(); + dos.writeInt(locs.size()); + for (TypeAnnotation.LocationInfo.Location loc : locs) { dos.write(loc.tag); dos.writeShort(loc.index); } @@ -528,12 +575,40 @@ public static List decodeAnnotations(byte[] encode } } + /** + * Decodes parameter annotations serialized in {@code encoded} to objects. + * + * @param type to which a type name is resolved + * @param type of the object representing a decoded annotation + * @param type of the object representing a decoded enum constant + * @param type of the object representing a missing type + * @param type of the object representing a decoded element type mismatch + * @return an immutable list of immutable lists of {@code A} objects + */ + @SuppressWarnings("unchecked") + public static List> decodeParameterAnnotations(byte[] encoded, AnnotationDecoder decoder) { + try { + ByteArrayInputStream bais = new ByteArrayInputStream(encoded); + DataInputStream dis = new DataInputStream(bais); + return (List>) readArray(dis, () -> decodeAnnotations(dis, decoder)); + } catch (Exception e) { + throw new InternalError(e); + } + } + @SuppressWarnings({"unchecked"}) + private static List decodeAnnotations(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + return (List) readArray(dis, () -> decodeAnnotation(dis, decoder)); + } + + @SuppressWarnings("rawtypes") + private static final Map.Entry[] NO_ELEMENTS = {}; + @SuppressWarnings({"rawtypes", "unchecked"}) private static A decodeAnnotation(DataInputStream dis, AnnotationDecoder decoder) throws IOException { String typeName = dis.readUTF(); T type = decoder.resolveType(typeName); int n = readLength(dis); - Map.Entry[] elements = new Map.Entry[n]; + Map.Entry[] elements = n == 0 ? NO_ELEMENTS : new Map.Entry[n]; for (int i = 0; i < n; i++) { String name = dis.readUTF(); byte tag = dis.readByte(); @@ -681,7 +756,7 @@ private static TA decodeTypeAnnotation(DataInputStrea for (int i = 0; i != depth; i++) { locs[i] = new TypeAnnotation.LocationInfo.Location(dis.readByte(), dis.readShort()); } - li = new TypeAnnotation.LocationInfo(depth, locs); + li = new TypeAnnotation.LocationInfo(locs); } A annotation = decodeAnnotation(dis, decoder); return decoder.newTypeAnnotation(ti, li, annotation); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index cda2bf892b72d..2f64e6f2533fa 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -24,6 +24,7 @@ package jdk.vm.ci.hotspot; import jdk.internal.misc.Unsafe; +import jdk.internal.vm.VMSupport; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.code.InvalidInstalledCodeException; @@ -60,7 +61,7 @@ final class CompilerToVM { /** * Initializes the native part of the JVMCI runtime. */ - private static native void registerNatives(); + private static native void registerNatives(int declaredAnnotations, int parameterAnnotations, int typeAnnotations); /** * These values mirror the equivalent values from {@code Unsafe} but are appropriate for the JVM @@ -88,7 +89,7 @@ final class CompilerToVM { @SuppressWarnings("try") CompilerToVM() { try (InitTimer t = timer("CompilerToVM.registerNatives")) { - registerNatives(); + registerNatives(VMSupport.DECLARED_ANNOTATIONS, VMSupport.PARAMETER_ANNOTATIONS, VMSupport.TYPE_ANNOTATIONS); ARRAY_BOOLEAN_BASE_OFFSET = arrayBaseOffset(JavaKind.Boolean.getTypeChar()); ARRAY_BYTE_BASE_OFFSET = arrayBaseOffset(JavaKind.Byte.getTypeChar()); ARRAY_SHORT_BASE_OFFSET = arrayBaseOffset(JavaKind.Short.getTypeChar()); @@ -1448,42 +1449,42 @@ native void notifyCompilerInliningEvent(int compileId, HotSpotResolvedJavaMethod * Gets the serialized annotation info for {@code type} by calling * {@code VMSupport.encodeAnnotations} in the HotSpot heap. */ - byte[] getEncodedClassAnnotationValues(HotSpotResolvedObjectTypeImpl type, boolean isTypeAnnotations, ResolvedJavaType[] filter) { + byte[] getEncodedClassAnnotationValues(HotSpotResolvedObjectTypeImpl type, int category, ResolvedJavaType[] filter) { try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedClassAnnotationValues(type, type.getKlassPointer(), isTypeAnnotations, + return getEncodedClassAnnotationValues(type, type.getKlassPointer(), category, a.types, a.length(), a.buffer()); } } - native byte[] getEncodedClassAnnotationValues(HotSpotResolvedObjectTypeImpl type, long klassPointer, boolean isTypeAnnotations, + native byte[] getEncodedClassAnnotationValues(HotSpotResolvedObjectTypeImpl type, long klassPointer, int category, Object filter, int filterLength, long filterKlassPointers); /** * Gets the serialized annotation info for {@code method} by calling * {@code VMSupport.encodeAnnotations} in the HotSpot heap. */ - byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, boolean isTypeAnnotations, ResolvedJavaType[] filter) { + byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, int category, ResolvedJavaType[] filter) { try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedExecutableAnnotationValues(method, method.getMethodPointer(), isTypeAnnotations, + return getEncodedExecutableAnnotationValues(method, method.getMethodPointer(), category, a.types, a.length(), a.buffer()); } } - native byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, long methodPointer, boolean isTypeAnnotations, + native byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, long methodPointer, int category, Object filter, int filterLength, long filterKlassPointers); /** * Gets the serialized annotation info for the field denoted by {@code holder} and * {@code fieldIndex} by calling {@code VMSupport.encodeAnnotations} in the HotSpot heap. */ - byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, int fieldIndex, boolean isTypeAnnotations, ResolvedJavaType[] filter) { + byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, int fieldIndex, int category, ResolvedJavaType[] filter) { try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedFieldAnnotationValues(holder, holder.getKlassPointer(), fieldIndex, isTypeAnnotations, + return getEncodedFieldAnnotationValues(holder, holder.getKlassPointer(), fieldIndex, category, a.types, a.length(), a.buffer()); } } - native byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, long klassPointer, int fieldIndex, boolean isTypeAnnotations, + native byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, long klassPointer, int fieldIndex, int category, Object filterTypes, int filterLength, long filterKlassPointers); /** diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index c74ae0ba0f87c..2d9bd3e834a48 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -253,13 +253,13 @@ public Map getDeclaredAnnotationValues(Resolv } private Map getAnnotationValues0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, false, filter); + byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, VMSupport.DECLARED_ANNOTATIONS, filter); return new AnnotationValueDecoder(getDeclaringClass()).decode(encoded); } @Override public List getTypeAnnotationValues() { - byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, true, null); + byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, VMSupport.TYPE_ANNOTATIONS, null); return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 5f59eec058d7e..2988b330d5978 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -516,12 +516,16 @@ public Parameter[] getParameters() { @Override public Annotation[][] getParameterAnnotations() { - if ((getConstMethodFlags() & config().constMethodHasParameterAnnotations) == 0 || isClassInitializer()) { + if (!hasParameterAnnotations() || isClassInitializer()) { return new Annotation[signature.getParameterCount(false)][0]; } return runtime().reflection.getParameterAnnotations(this); } + private boolean hasParameterAnnotations() { + return (getConstMethodFlags() & HotSpotVMConfig.config().constMethodHasParameterAnnotations) != 0; + } + @Override public Annotation[] getAnnotations() { if (!hasAnnotations()) { @@ -793,13 +797,22 @@ public Map getDeclaredAnnotationValues(Resolv } private Map getAnnotationValues0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, false, filter); + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.DECLARED_ANNOTATIONS, filter); return new AnnotationValueDecoder(getDeclaringClass()).decode(encoded); } + @Override + public List> getParameterAnnotationValues() { + if (!hasParameterAnnotations()) { + return null; + } + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.PARAMETER_ANNOTATIONS, null); + return VMSupport.decodeParameterAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); + } + @Override public List getTypeAnnotationValues() { - byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, true, null); + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.TYPE_ANNOTATIONS, null); return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index fad6743781b66..dae3b73b66f27 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -1135,7 +1135,7 @@ public Map getDeclaredAnnotationValues(Resolv } private Map getAnnotationValues0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, false, filter); + byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, VMSupport.DECLARED_ANNOTATIONS, filter); return new AnnotationValueDecoder(this).decode(encoded); } @@ -1144,7 +1144,7 @@ public List getTypeAnnotationValues() { if (isArray()) { return List.of(); } - byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, true, null); + byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, VMSupport.TYPE_ANNOTATIONS, null); return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(this)); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index 83609ed5ef6e5..fce8d5a05913a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -23,6 +23,7 @@ package jdk.vm.ci.meta; import jdk.vm.ci.meta.annotation.Annotated; +import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import java.lang.annotation.Annotation; @@ -500,4 +501,18 @@ default boolean isScoped() { default List getTypeAnnotationValues() { throw new UnsupportedOperationException(getClass().getName()); } + + /** + * Returns a list of lists of {@code AnnotationValue}s that represents the + * {@code RuntimeVisibleParameterAnnotations} for the method represented by + * this object. Note that this differs from {@link Method#getParameterAnnotations()} + * in that it excludes entries for synthetic and mandated parameters. + * + * @return null if there are no parameter annotations for this method otherwise + * an immutable list of immutable lists of parameter annotations + * @jvms 4.7.18 + */ + default List> getParameterAnnotationValues() { + throw new UnsupportedOperationException(getClass().getName()); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/TypeAnnotationValue.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/TypeAnnotationValue.java index 6bf98cd326f96..8076b92f5d631 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/TypeAnnotationValue.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/TypeAnnotationValue.java @@ -24,6 +24,9 @@ import sun.reflect.annotation.TypeAnnotation; +import java.util.Objects; +import java.util.stream.Collectors; + public final class TypeAnnotationValue { private final TypeAnnotation.TypeAnnotationTargetInfo targetInfo; @@ -52,14 +55,15 @@ public TypeAnnotation.LocationInfo getLocationInfo() { @Override public String toString() { - return annotation + ""; + String li = locationInfo.getLocations().stream().map(loc -> loc.tag + "@" + loc.index).collect(Collectors.joining(", ")); + return annotation + ""; } @Override public boolean equals(Object obj) { if (obj instanceof TypeAnnotationValue that) { - return equal(this.targetInfo, that.targetInfo) && - equal(this.locationInfo, that.locationInfo) && + return this.targetInfo.equals(that.targetInfo) && + this.locationInfo.equals(that.locationInfo) && this.annotation.equals(that.annotation); } return false; @@ -67,32 +71,6 @@ public boolean equals(Object obj) { @Override public int hashCode() { - return 13 ^ targetInfo.getCount() ^ - targetInfo.getSecondaryIndex() ^ - targetInfo.getTarget().hashCode() ^ - locationInfo.getDepth() ^ - annotation.hashCode(); - } - - public static boolean equal(TypeAnnotation.TypeAnnotationTargetInfo left, TypeAnnotation.TypeAnnotationTargetInfo right) { - return left.getTarget() == right.getTarget() && - left.getCount() == right.getCount() && - left.getSecondaryIndex() == right.getSecondaryIndex(); - } - - public static boolean equal(TypeAnnotation.LocationInfo left, TypeAnnotation.LocationInfo right) { - if (left.getDepth() != right.getDepth()) { - return false; - } - for (int i = 0; i < left.getDepth(); i++) { - if (!equal(left.getLocationAt(i), right.getLocationAt(i))) { - return false; - } - } - return true; - } - - public static boolean equal(TypeAnnotation.LocationInfo.Location left, TypeAnnotation.LocationInfo.Location right) { - return left.tag == right.tag && left.index == right.index; + return Objects.hash(targetInfo, locationInfo, annotation); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java index c57b14edc872b..87cee916f5ec1 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java @@ -74,6 +74,7 @@ import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -206,7 +207,9 @@ private Method findTestMethod(Method apiMethod) { */ private static void getTypeAnnotationValuesTest(Field field) { ResolvedJavaField javaField = metaAccess.lookupJavaField(field); - TestResolvedJavaType.assertTypeAnnotationsEquals(getTypeAnnotations(field), javaField.getTypeAnnotationValues()); + TypeAnnotation[] typeAnnotations = getTypeAnnotations(field); + List typeAnnotationValues = javaField.getTypeAnnotationValues(); + TestResolvedJavaType.assertTypeAnnotationsEquals(typeAnnotations, typeAnnotationValues); } private static final Method fieldGetTypeAnnotationBytes = lookupMethod(Field.class, "getTypeAnnotationBytes0"); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 20c04865188c7..299d0b299e4bd 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -595,7 +595,45 @@ static void methodWithThreeAnnotations() { */ private static void getTypeAnnotationValuesTest(Executable executable) { ResolvedJavaMethod method = metaAccess.lookupJavaMethod(executable); - TestResolvedJavaType.assertTypeAnnotationsEquals(getTypeAnnotations(executable), method.getTypeAnnotationValues()); + TypeAnnotation[] typeAnnotations = getTypeAnnotations(executable); + List typeAnnotationValues = method.getTypeAnnotationValues(); + TestResolvedJavaType.assertTypeAnnotationsEquals(typeAnnotations, typeAnnotationValues); + } + + /** + * Tests that {@link TypeAnnotation}s obtained from {@code executable} + * match {@link TypeAnnotationValue}s for the corresponding {@link ResolvedJavaMethod}. + */ + private static void getParameterAnnotationValuesTest(Executable executable) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(executable); + Annotation[][] parameterAnnotations = executable.getParameterAnnotations(); + List> parameterAnnotationValues = method.getParameterAnnotationValues(); + if (parameterAnnotationValues != null) { + int parsedAnnotations = parameterAnnotationValues.size(); + if (parsedAnnotations != parameterAnnotations.length) { + // Remove slots injected for implicit leading parameters + parameterAnnotations = Arrays.copyOfRange(parameterAnnotations, parameterAnnotations.length - parsedAnnotations, parameterAnnotations.length); + } + assertParameterAnnotationsEquals(parameterAnnotations, parameterAnnotationValues); + } else { + for (Annotation[] annotations : parameterAnnotations) { + Assert.assertEquals(0, annotations.length); + } + } + } + + public static void assertParameterAnnotationsEquals( + Annotation[][] parameterAnnotations, + List> parameterAnnotationValues) throws AssertionError { + assertEquals(parameterAnnotations.length, parameterAnnotationValues.size()); + for (int i = 0; i < parameterAnnotations.length; i++) { + Annotation[] annotations = parameterAnnotations[i]; + List annotationValues = parameterAnnotationValues.get(i); + assertEquals(annotations.length, annotationValues.size()); + for (int j = 0; j < annotations.length; j++) { + TestResolvedJavaType.assertAnnotationsEquals(annotations[j], annotationValues.get(j)); + } + } } private static final Method executableGetTypeAnnotationBytes = lookupMethod(Executable.class, "getTypeAnnotationBytes"); @@ -610,6 +648,14 @@ private static TypeAnnotation[] getTypeAnnotations(Executable e) { @Test public void getTypeAnnotationValuesTest() throws Exception { + getParameterAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); + for (Method m : methods.keySet()) { + getParameterAnnotationValuesTest(m); + } + } + + @Test + public void getParameterAnnotationValuesTest() throws Exception { getTypeAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); for (Method m : methods.keySet()) { getTypeAnnotationValuesTest(m); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index 81c8f7cb6ad12..bb2c5fd6f1b4f 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -1423,7 +1423,7 @@ private static Annotated toAnnotated(AnnotatedElement element) { } } - private static void assertAnnotationsEquals(Annotation a, AnnotationValue av) { + public static void assertAnnotationsEquals(Annotation a, AnnotationValue av) { Map values = AnnotationSupport.memberValues(a); for (Map.Entry e : values.entrySet()) { String name = e.getKey(); @@ -1444,10 +1444,10 @@ private static void assertAnnotationsEquals(Annotation a, AnnotationValue av) { private static void assertTypeAnnotationEquals(TypeAnnotation ta, TypeAnnotationValue tav) { TypeAnnotation.TypeAnnotationTargetInfo tiLeft = ta.getTargetInfo(); TypeAnnotation.TypeAnnotationTargetInfo tiRight = tav.getTargetInfo(); - assertTrue(tiLeft + " != " + tiRight, TypeAnnotationValue.equal(tiLeft, tiRight)); + assertEquals(tiLeft, tiRight); TypeAnnotation.LocationInfo liLeft = ta.getLocationInfo(); TypeAnnotation.LocationInfo liRight = tav.getLocationInfo(); - assertTrue(liLeft + " != " + liRight, TypeAnnotationValue.equal(liLeft, liRight)); + assertEquals(liLeft, liRight); assertAnnotationsEquals(ta.getAnnotation(), tav.getAnnotation()); } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java index 3efe7ba8b4c02..2e969b24a44d4 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java @@ -33,6 +33,10 @@ import org.junit.Test; import java.io.Serializable; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -76,8 +80,25 @@ public class TypeUniverse { private static List constants; - public class InnerClass { + // Define a type-use annotation + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + @interface TypeQualifier { + String comment() default ""; + int id() default -1; + } + // Define a parameter annotation + @Target(ElementType.PARAMETER) + @Retention(RetentionPolicy.RUNTIME) + @interface ParameterQualifier { + String value() default ""; + int tag() default -1; + } + + public class InnerClass { + public class InnerInnerClass { + } } public static class InnerStaticClass { @@ -208,6 +229,28 @@ public static List readConstants(Class fromClass) { } } + // Annotates the class type String + public @TypeQualifier String[][] typeAnnotatedField1; + // Annotates the array type String[][] + public String @TypeQualifier [][] typeAnnotatedField2; + // Annotates the array type String[] + String[] @TypeQualifier [] typeAnnotatedField3; + + public @TypeQualifier(comment = "comment1", id = 42) TypeUniverse.InnerClass.InnerInnerClass typeAnnotatedField4; + public TypeUniverse.@TypeQualifier InnerClass.InnerInnerClass typeAnnotatedField5; + public TypeUniverse.InnerClass.@TypeQualifier(comment = "47", id = -10) InnerInnerClass typeAnnotatedField6; + + public @TypeQualifier(comment = "comment2", id = 52) TypeUniverse.InnerClass.InnerInnerClass typeAnnotatedMethod1() { return null; } + public TypeUniverse.@TypeQualifier InnerClass.InnerInnerClass typeAnnotatedMethod2() { return null; } + public TypeUniverse.InnerClass.@TypeQualifier(comment = "57", id = -20) InnerInnerClass typeAnnotatedMethod3() { return null; } + + public void annotatedParameters1( + @TypeQualifier(comment = "comment3", id = 62) TypeUniverse this, + @TypeQualifier(comment = "comment4", id = 72) @ParameterQualifier String annotatedParam1, + int notAnnotatedParam2, + @ParameterQualifier(value = "foo", tag = 123) Thread annotatedParam3) { + } + public synchronized Class getArrayClass(Class componentType) { Class arrayClass = arrayClasses.get(componentType); if (arrayClass == null) { @@ -232,6 +275,9 @@ private static void addClass(Class c) { for (Class sc : c.getInterfaces()) { addClass(sc); } + for (Class enclosing = c.getEnclosingClass(); enclosing != null; enclosing = enclosing.getEnclosingClass()) { + addClass(enclosing); + } for (Class dc : c.getDeclaredClasses()) { addClass(dc); } From 67ce9bd0e0002501ae89245e8f87068f482bb5a5 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Wed, 20 Aug 2025 23:21:59 +0200 Subject: [PATCH 13/20] removed types parameter from Annotated.getDeclaredAnnotationValues() --- src/hotspot/share/classfile/vmSymbols.hpp | 2 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 38 +++------ .../share/classes/java/lang/Class.java | 2 +- .../classes/java/lang/reflect/Executable.java | 4 +- .../classes/java/lang/reflect/Field.java | 2 +- .../java/lang/reflect/RecordComponent.java | 2 +- .../classes/jdk/internal/vm/VMSupport.java | 18 +---- .../reflect/annotation/AnnotationParser.java | 7 +- .../jdk/vm/ci/hotspot/CompilerToVM.java | 80 +++---------------- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 16 ++-- .../HotSpotResolvedJavaMethodImpl.java | 18 ++--- .../ci/hotspot/HotSpotResolvedJavaType.java | 6 -- .../HotSpotResolvedObjectTypeImpl.java | 15 ++-- .../hotspot/HotSpotResolvedPrimitiveType.java | 5 +- .../jdk/vm/ci/meta/annotation/Annotated.java | 8 +- .../runtime/test/TestResolvedJavaMethod.java | 8 +- .../ci/runtime/test/TestResolvedJavaType.java | 39 ++------- 17 files changed, 71 insertions(+), 199 deletions(-) diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index a98a56c861225..35c93c70ce3f8 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -706,7 +706,7 @@ class SerializeClosure; template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \ template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \ template(encodeAnnotations_name, "encodeAnnotations") \ - template(encodeAnnotations_signature, "([BILjava/lang/Class;Ljdk/internal/reflect/ConstantPool;[Ljava/lang/Class;)[B")\ + template(encodeAnnotations_signature, "([BILjava/lang/Class;Ljdk/internal/reflect/ConstantPool;)[B")\ template(decodeAndThrowThrowable_signature, "(IJZZ)V") \ template(classRedefinedCount_name, "classRedefinedCount") \ template(classLoader_name, "classLoader") \ diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index c3b73f254c3ca..5aba057c72991 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -3014,9 +3014,7 @@ C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAI return JNIHandles::make_local(THREAD, reflected); C2V_END -static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, AnnotationArray* annotations_array, - jint category, - jint filter_length, jlong filter_klass_pointers, +static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, AnnotationArray* annotations_array, jint category, JavaThread* THREAD, JVMCI_TRAPS) { // Get a ConstantPool object for annotation parsing Handle jcp = reflect_ConstantPool::create(CHECK_NULL); @@ -3034,18 +3032,6 @@ static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, Annotatio typeArrayOop annotations_oop = Annotations::make_java_array(annotations_array, CHECK_NULL); typeArrayHandle annotations = typeArrayHandle(THREAD, annotations_oop); - objArrayHandle filter_classes; - if (filter_length != 0) { - InstanceKlass** filter = filter_length == 1 ? - (InstanceKlass**) &filter_klass_pointers: - (InstanceKlass**) filter_klass_pointers; - objArrayOop filter_oop = oopFactory::new_objArray(vmClasses::Class_klass(), filter_length, CHECK_NULL); - filter_classes = objArrayHandle(THREAD, filter_oop); - for (int i = 0; i < filter_length; i++) { - filter_classes->obj_at_put(i, filter[i]->java_mirror()); - } - } - // invoke VMSupport.encodeAnnotations JavaValue result(T_OBJECT); JavaCallArguments args; @@ -3053,7 +3039,6 @@ static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, Annotatio args.push_int(category); args.push_oop(Handle(THREAD, holder->java_mirror())); args.push_oop(jcp); - args.push_oop(filter_classes); Symbol* signature = vmSymbols::encodeAnnotations_signature(); JavaCalls::call_static(&result, vm_support, @@ -3081,8 +3066,7 @@ static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, Annotatio return JVMCIENV->get_jbyteArray(ba_dest); } -C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint category, - jobject filter, jint filter_length, jlong filter_klass_pointers)) +C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint category)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support InstanceKlass* holder = InstanceKlass::cast(UNPACK_PAIR(Klass, klass)); AnnotationArray* raw_annotations; @@ -3094,11 +3078,10 @@ C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationValues, (JNIEnv* env, jobj THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), err_msg("%d", category)); } - return get_encoded_annotation_values(holder, raw_annotations, category, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + return get_encoded_annotation_values(holder, raw_annotations, category, THREAD, JVMCIENV); C2V_END -C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), jint category, - jobject filter, jint filter_length, jlong filter_klass_pointers)) +C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), jint category)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support methodHandle method(THREAD, UNPACK_PAIR(Method, method)); AnnotationArray* raw_annotations; @@ -3111,11 +3094,10 @@ C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, } else { THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), err_msg("%d", category)); } - return get_encoded_annotation_values(method->method_holder(), raw_annotations, category, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + return get_encoded_annotation_values(method->method_holder(), raw_annotations, category, THREAD, JVMCIENV); C2V_END -C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, jint category, - jobject filter, jint filter_length, jlong filter_klass_pointers)) +C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, jint category)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support InstanceKlass* holder = check_field(InstanceKlass::cast(UNPACK_PAIR(Klass, klass)), index, JVMCI_CHECK_NULL); fieldDescriptor fd(holder, index); @@ -3128,7 +3110,7 @@ C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobj THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), err_msg("%d", category)); } - return get_encoded_annotation_values(holder, raw_annotations, category, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + return get_encoded_annotation_values(holder, raw_annotations, category, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_NULL(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current)) @@ -3472,9 +3454,9 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)}, {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" REFLECTION_EXECUTABLE, FN_PTR(asReflectionExecutable)}, {CC "asReflectionField", CC "(" HS_KLASS2 "I)" REFLECTION_FIELD, FN_PTR(asReflectionField)}, - {CC "getEncodedClassAnnotationValues", CC "(" HS_KLASS2 "I" OBJECT "IJ)[B", FN_PTR(getEncodedClassAnnotationValues)}, - {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 "I" OBJECT "IJ)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, - {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "II" OBJECT "IJ)[B", FN_PTR(getEncodedFieldAnnotationValues)}, + {CC "getEncodedClassAnnotationValues", CC "(" HS_KLASS2 "I)[B", FN_PTR(getEncodedClassAnnotationValues)}, + {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 "I)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, + {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "II)[B", FN_PTR(getEncodedFieldAnnotationValues)}, {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, {CC "getFailedSpeculationsAddress", CC "(" HS_METHOD2 ")J", FN_PTR(getFailedSpeculationsAddress)}, {CC "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)}, diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index dfdf515f424c7..7b23a2ab75afe 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -3674,7 +3674,7 @@ private AnnotationData annotationData() { private AnnotationData createAnnotationData(int classRedefinedCount) { Map, Annotation> declaredAnnotations = - AnnotationParser.parseAnnotations(getRawAnnotations(), getConstantPool(), this); + AnnotationParser.parseAnnotations(getRawAnnotations(), getConstantPool(), this, true); Class superClass = getSuperclass(); Map, Annotation> annotations = null; if (superClass != null) { diff --git a/src/java.base/share/classes/java/lang/reflect/Executable.java b/src/java.base/share/classes/java/lang/reflect/Executable.java index 2f6f6cca89f04..dffe34b3a0a91 100644 --- a/src/java.base/share/classes/java/lang/reflect/Executable.java +++ b/src/java.base/share/classes/java/lang/reflect/Executable.java @@ -669,8 +669,8 @@ private Map, Annotation> declaredAnnotations() { getAnnotationBytes(), SharedSecrets.getJavaLangAccess(). getConstantPool(getDeclaringClass()), - getDeclaringClass() - ); + getDeclaringClass(), + true); } declaredAnnotations = declAnnos; } diff --git a/src/java.base/share/classes/java/lang/reflect/Field.java b/src/java.base/share/classes/java/lang/reflect/Field.java index e26d8b03ff8aa..d7e387c954ca5 100644 --- a/src/java.base/share/classes/java/lang/reflect/Field.java +++ b/src/java.base/share/classes/java/lang/reflect/Field.java @@ -1277,7 +1277,7 @@ private Map, Annotation> declaredAnnotations() { annotations, SharedSecrets.getJavaLangAccess() .getConstantPool(getDeclaringClass()), - getDeclaringClass()); + getDeclaringClass(), true); } declaredAnnotations = declAnnos; } diff --git a/src/java.base/share/classes/java/lang/reflect/RecordComponent.java b/src/java.base/share/classes/java/lang/reflect/RecordComponent.java index 5ce7f9bf95d1a..499c1efebee23 100644 --- a/src/java.base/share/classes/java/lang/reflect/RecordComponent.java +++ b/src/java.base/share/classes/java/lang/reflect/RecordComponent.java @@ -198,7 +198,7 @@ private Map, Annotation> declaredAnnotations() { annotations, SharedSecrets.getJavaLangAccess() .getConstantPool(getDeclaringRecord()), - getDeclaringRecord()); + getDeclaringRecord(), true); } declaredAnnotations = declAnnos; } diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index e35ef970460c1..5adde84b088cb 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -216,22 +216,10 @@ public static int encodeThrowable(Throwable throwable, long buffer, int bufferSi public static byte[] encodeAnnotations(byte[] rawAnnotations, int category, Class declaringClass, - ConstantPool cp, - Class[] selectAnnotationClasses) { + ConstantPool cp) { return switch (category) { - case DECLARED_ANNOTATIONS -> { - if (selectAnnotationClasses != null) { - if (selectAnnotationClasses.length == 0) { - throw new IllegalArgumentException("annotation class selection must be null or non-empty"); - } - for (Class c : selectAnnotationClasses) { - if (!c.isAnnotation()) { - throw new IllegalArgumentException(c + " is not an annotation interface"); - } - } - } - yield encodeAnnotations(AnnotationParser.parseSelectAnnotations(rawAnnotations, cp, declaringClass, false, selectAnnotationClasses).values()); - } + case DECLARED_ANNOTATIONS -> + encodeAnnotations(AnnotationParser.parseAnnotations(rawAnnotations, cp, declaringClass, false).values()); case PARAMETER_ANNOTATIONS -> encodeParameterAnnotations(AnnotationParser.parseParameterAnnotations(rawAnnotations, cp, declaringClass)); case TYPE_ANNOTATIONS -> diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java index 04b8a62bd2073..fbbeec988cb05 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java @@ -65,12 +65,13 @@ public class AnnotationParser { public static Map, Annotation> parseAnnotations( byte[] rawAnnotations, ConstantPool constPool, - Class container) { + Class container, + boolean eagerResolution) { if (rawAnnotations == null) return Collections.emptyMap(); try { - return parseAnnotations2(rawAnnotations, constPool, container, true, null); + return parseAnnotations2(rawAnnotations, constPool, container, eagerResolution, null); } catch(BufferUnderflowException e) { throw new AnnotationFormatError("Unexpected end of annotations."); } catch(IllegalArgumentException e) { @@ -80,7 +81,7 @@ public static Map, Annotation> parseAnnotations( } /** - * Like {@link #parseAnnotations(byte[], jdk.internal.reflect.ConstantPool, Class)} + * Like {@link #parseAnnotations(byte[], jdk.internal.reflect.ConstantPool, Class, boolean)} * with an additional parameter {@code selectAnnotationClasses} which selects the * annotation types to parse (other than selected are quickly skipped).

* This method is used to parse select meta annotations in the construction diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index 2f64e6f2533fa..c463d2616493d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -1449,93 +1449,31 @@ native void notifyCompilerInliningEvent(int compileId, HotSpotResolvedJavaMethod * Gets the serialized annotation info for {@code type} by calling * {@code VMSupport.encodeAnnotations} in the HotSpot heap. */ - byte[] getEncodedClassAnnotationValues(HotSpotResolvedObjectTypeImpl type, int category, ResolvedJavaType[] filter) { - try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedClassAnnotationValues(type, type.getKlassPointer(), category, - a.types, a.length(), a.buffer()); - } + byte[] getEncodedClassAnnotationValues(HotSpotResolvedObjectTypeImpl type, int category) { + return getEncodedClassAnnotationValues(type, type.getKlassPointer(), category); } - native byte[] getEncodedClassAnnotationValues(HotSpotResolvedObjectTypeImpl type, long klassPointer, int category, - Object filter, int filterLength, long filterKlassPointers); + native byte[] getEncodedClassAnnotationValues(HotSpotResolvedObjectTypeImpl type, long klassPointer, int category); /** * Gets the serialized annotation info for {@code method} by calling * {@code VMSupport.encodeAnnotations} in the HotSpot heap. */ - byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, int category, ResolvedJavaType[] filter) { - try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedExecutableAnnotationValues(method, method.getMethodPointer(), category, - a.types, a.length(), a.buffer()); - } + byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, int category) { + return getEncodedExecutableAnnotationValues(method, method.getMethodPointer(), category); } - native byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, long methodPointer, int category, - Object filter, int filterLength, long filterKlassPointers); + native byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, long methodPointer, int category); /** * Gets the serialized annotation info for the field denoted by {@code holder} and * {@code fieldIndex} by calling {@code VMSupport.encodeAnnotations} in the HotSpot heap. */ - byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, int fieldIndex, int category, ResolvedJavaType[] filter) { - try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedFieldAnnotationValues(holder, holder.getKlassPointer(), fieldIndex, category, - a.types, a.length(), a.buffer()); - } + byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, int fieldIndex, int category) { + return getEncodedFieldAnnotationValues(holder, holder.getKlassPointer(), fieldIndex, category); } - native byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, long klassPointer, int fieldIndex, int category, - Object filterTypes, int filterLength, long filterKlassPointers); - - /** - * Helper for passing {@code Klass*} values to native code. - */ - static final class KlassPointers implements AutoCloseable { - final ResolvedJavaType[] types; - long pointersArray; - final Unsafe unsafe = UnsafeAccess.UNSAFE; - - KlassPointers(ResolvedJavaType[] types) { - this.types = types; - } - - int length() { - return types == null ? 0 : types.length; - } - - /** - * Gets the buffer in which to pass the {@code Klass*} values to JNI. - * - * @return 0L if {@code types.length == 0}, a {@code Klass*} value if {@code types.length == 1} - * otherwise the address of a native buffer holding an array of {@code Klass*} values - */ - long buffer() { - long length = length(); - if (length == 0) { - return 0L; - } - if (length == 1) { - return ((HotSpotResolvedObjectTypeImpl) types[0]).getKlassPointer(); - } else { - pointersArray = unsafe.allocateMemory(length * Long.BYTES); - long pos = pointersArray; - for (ResolvedJavaType type : types) { - HotSpotResolvedObjectTypeImpl hsType = (HotSpotResolvedObjectTypeImpl) type; - unsafe.putLong(pos, hsType.getKlassPointer()); - pos += Long.BYTES; - } - } - return pointersArray; - } - - @Override - public void close() { - if (pointersArray != 0) { - unsafe.freeMemory(pointersArray); - pointersArray = 0; - } - } - } + native byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, long klassPointer, int fieldIndex, int category); /** * @see HotSpotResolvedJavaMethod#getOopMapAt diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 2d9bd3e834a48..74a98e273ee78 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -37,7 +37,6 @@ import static jdk.internal.misc.Unsafe.ADDRESS_SIZE; import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkAreAnnotations; import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkIsAnnotation; import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; @@ -236,30 +235,29 @@ public JavaConstant getConstantValue() { @Override public AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType annotationType) { + checkIsAnnotation(annotationType); if (!hasAnnotations()) { - checkIsAnnotation(annotationType); return null; } - return getAnnotationValues0(annotationType).get(annotationType); + return getAnnotationValues0().get(annotationType); } @Override - public Map getDeclaredAnnotationValues(ResolvedJavaType... types) { - checkAreAnnotations(types); + public Map getDeclaredAnnotationValues() { if (!hasAnnotations()) { return Map.of(); } - return getAnnotationValues0(types); + return getAnnotationValues0(); } - private Map getAnnotationValues0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, VMSupport.DECLARED_ANNOTATIONS, filter); + private Map getAnnotationValues0() { + byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, VMSupport.DECLARED_ANNOTATIONS); return new AnnotationValueDecoder(getDeclaringClass()).decode(encoded); } @Override public List getTypeAnnotationValues() { - byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, VMSupport.TYPE_ANNOTATIONS, null); + byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, VMSupport.TYPE_ANNOTATIONS); return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 2988b330d5978..523f4bc910d26 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -56,7 +56,6 @@ import static jdk.vm.ci.hotspot.HotSpotModifiers.SYNTHETIC; import static jdk.vm.ci.hotspot.HotSpotModifiers.VARARGS; import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmMethodModifiers; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkAreAnnotations; import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkIsAnnotation; import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; @@ -780,24 +779,23 @@ public int methodIdnum() { @Override public AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType type) { + checkIsAnnotation(type); if (!hasAnnotations()) { - checkIsAnnotation(type); return null; } - return getAnnotationValues0(type).get(type); + return getAnnotationValues0().get(type); } @Override - public Map getDeclaredAnnotationValues(ResolvedJavaType... types) { - checkAreAnnotations(types); + public Map getDeclaredAnnotationValues() { if (!hasAnnotations()) { return Map.of(); } - return getAnnotationValues0(types); + return getAnnotationValues0(); } - private Map getAnnotationValues0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.DECLARED_ANNOTATIONS, filter); + private Map getAnnotationValues0() { + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.DECLARED_ANNOTATIONS); return new AnnotationValueDecoder(getDeclaringClass()).decode(encoded); } @@ -806,13 +804,13 @@ public List> getParameterAnnotationValues() { if (!hasParameterAnnotations()) { return null; } - byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.PARAMETER_ANNOTATIONS, null); + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.PARAMETER_ANNOTATIONS); return VMSupport.decodeParameterAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); } @Override public List getTypeAnnotationValues() { - byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.TYPE_ANNOTATIONS, null); + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.TYPE_ANNOTATIONS); return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index 9323925150662..41e87eb9da7a9 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -73,10 +73,4 @@ static void checkIsAnnotation(ResolvedJavaType type) { throw new IllegalArgumentException(type.toJavaName() + " is not an annotation interface"); } } - - static void checkAreAnnotations(ResolvedJavaType... types) { - for (ResolvedJavaType type : types) { - checkIsAnnotation(type); - } - } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index dae3b73b66f27..e40594cabc08d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -1118,24 +1118,23 @@ public boolean isCloneableWithAllocation() { @Override public AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType annotationType) { + checkIsAnnotation(annotationType); if (!mayHaveAnnotations(true)) { - checkIsAnnotation(annotationType); return null; } - return getAnnotationValues0(annotationType).get(annotationType); + return getAnnotationValues0().get(annotationType); } @Override - public Map getDeclaredAnnotationValues(ResolvedJavaType... types) { + public Map getDeclaredAnnotationValues() { if (!mayHaveAnnotations(true)) { - checkAreAnnotations(types); return Map.of(); } - return getAnnotationValues0(types); + return getAnnotationValues0(); } - private Map getAnnotationValues0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, VMSupport.DECLARED_ANNOTATIONS, filter); + private Map getAnnotationValues0() { + byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, VMSupport.DECLARED_ANNOTATIONS); return new AnnotationValueDecoder(this).decode(encoded); } @@ -1144,7 +1143,7 @@ public List getTypeAnnotationValues() { if (isArray()) { return List.of(); } - byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, VMSupport.TYPE_ANNOTATIONS, null); + byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, VMSupport.TYPE_ANNOTATIONS); return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(this)); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index fbc94b4d5e974..ef994f2a610e8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -48,7 +48,7 @@ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType static HotSpotResolvedPrimitiveType[] primitives; - private JavaKind kind; + private final JavaKind kind; HotSpotObjectConstantImpl mirror; /** @@ -349,8 +349,7 @@ public AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType type) { } @Override - public Map getDeclaredAnnotationValues(ResolvedJavaType... types) { - checkAreAnnotations(types); + public Map getDeclaredAnnotationValues() { return Map.of(); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java index f3c3996ad9b14..1ed5471bfb501 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java @@ -35,17 +35,15 @@ public interface Annotated { /** - * Gets the annotations directly present on this element whose types are in {@code types}. + * Gets the annotations directly present on this element. * Class initialization is not triggered for enum types referenced by the returned * annotation. This method ignores inherited annotations. * - * @param types annotation types to select. If empty, then all declared annotations are returned. * @return an immutable map from annotation type to annotation of the annotations directly present - * on this element selected by {@code types} - * @throws IllegalArgumentException if any type in {@code types} is not an annotation interface type + * on this element * @throws UnsupportedOperationException if this operation is not supported */ - default Map getDeclaredAnnotationValues(ResolvedJavaType... types) { + default Map getDeclaredAnnotationValues() { throw new UnsupportedOperationException(this.getClass().getName()); } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 299d0b299e4bd..cbc6c26ede957 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -691,12 +691,16 @@ public void getAnnotationValuesTest() throws Exception { ResolvedJavaType a1 = metaAccess.lookupJavaType(Annotation1.class); ResolvedJavaType a2 = metaAccess.lookupJavaType(Annotation2.class); ResolvedJavaType a3 = metaAccess.lookupJavaType(Annotation3.class); - ResolvedJavaType a4 = metaAccess.lookupJavaType(AnnotationValueTest.class); ResolvedJavaType numbersDEType = metaAccess.lookupJavaType(NumbersDE.class); // Ensure NumbersDE is not initialized before Annotation2 is requested Assert.assertFalse(numbersDEType.isInitialized()); - Assert.assertEquals(2, m.getDeclaredAnnotationValues(a1, a3).size()); + + Map declaredAnnotationValues = m.getDeclaredAnnotationValues(); + Assert.assertEquals(3, declaredAnnotationValues.size()); + Assert.assertNotNull(declaredAnnotationValues.get(a1)); + Assert.assertNotNull(declaredAnnotationValues.get(a2)); + Assert.assertNotNull(declaredAnnotationValues.get(a3)); // Ensure NumbersDE is not initialized after Annotation2 is requested Assert.assertNotNull(m.getDeclaredAnnotationValue(a2)); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index bb2c5fd6f1b4f..6d2fe6d49f7d3 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -1260,7 +1260,7 @@ public void getAnnotationValuesTest() { ResolvedJavaType type = metaAccess.lookupJavaType(c); AnnotationValue av = type.getDeclaredAnnotationValue(overrideType); Assert.assertNull(String.valueOf(av), av); - Map avMap = type.getDeclaredAnnotationValues(overrideType, overrideType); + Map avMap = type.getDeclaredAnnotationValues(); Assert.assertEquals(0, avMap.size()); } @@ -1319,14 +1319,10 @@ private static boolean isSignaturePolymorphic(ResolvedJavaMethod method) { return method.getAnnotation(SIGNATURE_POLYMORPHIC_CLASS) != null; } - private static void getAnnotationValueExpectedToFail(Annotated annotated, ResolvedJavaType... annotationTypes) { + private static void getAnnotationValueExpectedToFail(Annotated annotated, ResolvedJavaType annotationType) { try { - if (annotationTypes.length == 1) { - annotated.getDeclaredAnnotationValue(annotationTypes[0]); - } else { - annotated.getDeclaredAnnotationValues(annotationTypes); - } - String s = Stream.of(annotationTypes).map(ResolvedJavaType::toJavaName).collect(Collectors.joining(", ")); + annotated.getDeclaredAnnotationValue(annotationType); + String s = annotationType.toJavaName(); throw new AssertionError("Expected IllegalArgumentException for retrieving (" + s + " from " + annotated); } catch (IllegalArgumentException iae) { assertTrue(iae.getMessage(), iae.getMessage().contains("not an annotation interface")); @@ -1345,15 +1341,11 @@ public static List getAnnotationValuesTest(AnnotatedElement ann ResolvedJavaType objectType = metaAccess.lookupJavaType(Object.class); ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); getAnnotationValueExpectedToFail(annotated, objectType); - getAnnotationValueExpectedToFail(annotated, suppressWarningsType, objectType); - getAnnotationValueExpectedToFail(annotated, suppressWarningsType, suppressWarningsType, objectType); // Check that querying a missing annotation returns null or an empty list assertNull(annotated.getDeclaredAnnotationValue(suppressWarningsType)); - Map values = annotated.getDeclaredAnnotationValues(suppressWarningsType, suppressWarningsType); - assertTrue(values.toString(), values.isEmpty()); - values = annotated.getDeclaredAnnotationValues(suppressWarningsType, suppressWarningsType, suppressWarningsType, suppressWarningsType); - assertTrue(values.toString(), values.isEmpty()); + Map values = annotated.getDeclaredAnnotationValues(); + assertNull(values.toString(), values.get(suppressWarningsType)); return testGetAnnotationValues(annotated, List.of(annotatedElement.getDeclaredAnnotations())); } @@ -1388,27 +1380,8 @@ private static List testGetAnnotationValues(Annotated annotated av2 = allAnnotationValues.get(annotationType); assertAnnotationsEquals(a, av2); - Map annotationValues = annotated.getDeclaredAnnotationValues(annotationType, suppressWarningsType, suppressWarningsType); - assertEquals(1, annotationValues.size()); - res.add(av); } - if (annotations.size() < 2) { - return res; - } - for (int i = 0; i < annotations.size(); i++) { - ResolvedJavaType[] types = annotations.// - stream().map(a -> metaAccess.lookupJavaType(a.annotationType())).// - toArray(ResolvedJavaType[]::new); - Map annotationValues = annotated.getDeclaredAnnotationValues(types); - assertEquals(types.length, annotationValues.size()); - - for (int j = 0; j < annotationValues.size(); j++) { - Annotation a = annotations.get(j); - AnnotationValue av = annotationValues.get(metaAccess.lookupJavaType(a.annotationType())); - assertAnnotationsEquals(a, av); - } - } return res; } From c5466b0a898722e6dab0041df0d3c1fa4f651fd2 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 26 Aug 2025 08:18:07 +0200 Subject: [PATCH 14/20] added support for annotation member default values --- src/hotspot/share/classfile/vmSymbols.hpp | 2 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 24 +- src/hotspot/share/jvmci/jvmciCompilerToVM.hpp | 1 + src/hotspot/share/jvmci/jvmciJavaClasses.cpp | 4 +- src/hotspot/share/jvmci/jvmciJavaClasses.hpp | 4 + src/hotspot/share/jvmci/jvmciRuntime.cpp | 17 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + src/hotspot/share/prims/nativeLookup.cpp | 2 +- .../classes/jdk/internal/vm/VMSupport.java | 481 ++++++++++-------- .../reflect/annotation/AnnotationType.java | 6 + .../jdk/vm/ci/hotspot/CompilerToVM.java | 16 +- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 14 +- .../HotSpotResolvedJavaMethodImpl.java | 40 +- .../HotSpotResolvedObjectTypeImpl.java | 14 +- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 1 + .../jdk/vm/ci/meta/ResolvedJavaMethod.java | 20 + .../jdk/vm/ci/meta/annotation/Annotated.java | 5 +- .../annotation}/AnnotationValueDecoder.java | 16 +- .../runtime/test/TestResolvedJavaMethod.java | 40 +- .../ci/runtime/test/TestResolvedJavaType.java | 3 +- .../AnnotationTestInput.java | 15 + .../TestAnnotationEncodingDecoding.java | 11 +- 22 files changed, 433 insertions(+), 304 deletions(-) rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/{hotspot => meta/annotation}/AnnotationValueDecoder.java (81%) diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 35c93c70ce3f8..085e3e69ce717 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -706,7 +706,7 @@ class SerializeClosure; template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \ template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \ template(encodeAnnotations_name, "encodeAnnotations") \ - template(encodeAnnotations_signature, "([BILjava/lang/Class;Ljdk/internal/reflect/ConstantPool;)[B")\ + template(encodeAnnotations_signature, "([BILjava/lang/Class;Ljdk/internal/reflect/ConstantPool;Ljava/lang/Class;)[B")\ template(decodeAndThrowThrowable_signature, "(IJZZ)V") \ template(classRedefinedCount_name, "classRedefinedCount") \ template(classLoader_name, "classLoader") \ diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 5aba057c72991..ee4c0eeae629e 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -3014,8 +3014,9 @@ C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAI return JNIHandles::make_local(THREAD, reflected); C2V_END -static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, AnnotationArray* annotations_array, jint category, - JavaThread* THREAD, JVMCI_TRAPS) { +static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, AnnotationArray* annotations_array, + jint category, Klass* memberType, + JavaThread* THREAD, JVMCI_TRAPS) { // Get a ConstantPool object for annotation parsing Handle jcp = reflect_ConstantPool::create(CHECK_NULL); reflect_ConstantPool::set_cp(jcp(), holder->constants()); @@ -3031,6 +3032,10 @@ static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, Annotatio typeArrayOop annotations_oop = Annotations::make_java_array(annotations_array, CHECK_NULL); typeArrayHandle annotations = typeArrayHandle(THREAD, annotations_oop); + Handle memberTypeMirror; + if (memberType != nullptr) { + memberTypeMirror = Handle(THREAD, memberType->java_mirror()); + } // invoke VMSupport.encodeAnnotations JavaValue result(T_OBJECT); @@ -3039,6 +3044,7 @@ static jbyteArray get_encoded_annotation_values(InstanceKlass* holder, Annotatio args.push_int(category); args.push_oop(Handle(THREAD, holder->java_mirror())); args.push_oop(jcp); + args.push_oop(memberTypeMirror); Symbol* signature = vmSymbols::encodeAnnotations_signature(); JavaCalls::call_static(&result, vm_support, @@ -3078,23 +3084,27 @@ C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationValues, (JNIEnv* env, jobj THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), err_msg("%d", category)); } - return get_encoded_annotation_values(holder, raw_annotations, category, THREAD, JVMCIENV); + return get_encoded_annotation_values(holder, raw_annotations, category, nullptr, THREAD, JVMCIENV); C2V_END -C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), jint category)) +C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), ARGUMENT_PAIR(memberTypeKlass), jint category)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support methodHandle method(THREAD, UNPACK_PAIR(Method, method)); AnnotationArray* raw_annotations; + Klass* memberType = nullptr; if (category == CompilerToVM::DECLARED_ANNOTATIONS) { raw_annotations = method->annotations(); } else if (category == CompilerToVM::PARAMETER_ANNOTATIONS) { raw_annotations = method->parameter_annotations(); } else if (category == CompilerToVM::TYPE_ANNOTATIONS) { raw_annotations = method->type_annotations(); + } else if (category == CompilerToVM::ANNOTATION_MEMBER_VALUE) { + raw_annotations = method->annotation_default(); + memberType = UNPACK_PAIR(Klass, memberTypeKlass); } else { THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), err_msg("%d", category)); } - return get_encoded_annotation_values(method->method_holder(), raw_annotations, category, THREAD, JVMCIENV); + return get_encoded_annotation_values(method->method_holder(), raw_annotations, category, memberType, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, jint category)) @@ -3110,7 +3120,7 @@ C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobj THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), err_msg("%d", category)); } - return get_encoded_annotation_values(holder, raw_annotations, category, THREAD, JVMCIENV); + return get_encoded_annotation_values(holder, raw_annotations, category, nullptr, THREAD, JVMCIENV); C2V_END C2V_VMENTRY_NULL(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current)) @@ -3455,7 +3465,7 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" REFLECTION_EXECUTABLE, FN_PTR(asReflectionExecutable)}, {CC "asReflectionField", CC "(" HS_KLASS2 "I)" REFLECTION_FIELD, FN_PTR(asReflectionField)}, {CC "getEncodedClassAnnotationValues", CC "(" HS_KLASS2 "I)[B", FN_PTR(getEncodedClassAnnotationValues)}, - {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 "I)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, + {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 HS_KLASS2 "I)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "II)[B", FN_PTR(getEncodedFieldAnnotationValues)}, {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, {CC "getFailedSpeculationsAddress", CC "(" HS_METHOD2 ")J", FN_PTR(getFailedSpeculationsAddress)}, diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index 1c9850273e2d2..f0cb15ed2f9bb 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -39,6 +39,7 @@ class CompilerToVM { static const int DECLARED_ANNOTATIONS = 0; static const int PARAMETER_ANNOTATIONS = 1; static const int TYPE_ANNOTATIONS = 2; + static const int ANNOTATION_MEMBER_VALUE = 3; class Data { friend class JVMCIVMStructs; diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp index bda4b515ccb3f..e5c0017129c17 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp @@ -403,7 +403,7 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz, GET_JNI_CONSTRUCTOR(className, signature) extern "C" { - void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass, jint declaredAnnotations, jint parameterAnnotations, jint typeAnnotations); + void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass); jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); jlong JNICALL JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets_handle); } @@ -564,7 +564,7 @@ static void register_natives_for_class(JNIEnv* env, jclass clazz, const char* na void JNIJVMCI::register_natives(JNIEnv* env) { if (env != JavaThread::current()->jni_environment()) { - JNINativeMethod CompilerToVM_nmethods[] = {{ CC"registerNatives", CC"(III)V", FN_PTR(JVM_RegisterJVMCINatives) }}; + JNINativeMethod CompilerToVM_nmethods[] = {{ CC"registerNatives", CC"()V", FN_PTR(JVM_RegisterJVMCINatives) }}; JNINativeMethod JVMCI_nmethods[] = {{ CC"initializeRuntime", CC"()Ljdk/vm/ci/runtime/JVMCIRuntime;", FN_PTR(JVM_GetJVMCIRuntime) }}; JNINativeMethod Services_nmethods[] = {{ CC"readSystemPropertiesInfo", CC"([I)J", FN_PTR(JVM_ReadSystemPropertiesInfo) }}; diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp index 8bd34f52def7d..9abf3b4241a08 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp @@ -233,6 +233,10 @@ start_class(VMSupport, jdk_internal_vm_VMSupport) \ jvmci_method(CallStaticIntMethod, GetStaticMethodID, call_static, int, VMSupport, encodeThrowable, encodeThrowable_signature) \ jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, VMSupport, decodeAndThrowThrowable, decodeAndThrowThrowable_signature) \ + static_int_field(VMSupport, DECLARED_ANNOTATIONS) \ + static_int_field(VMSupport, PARAMETER_ANNOTATIONS) \ + static_int_field(VMSupport, TYPE_ANNOTATIONS) \ + static_int_field(VMSupport, ANNOTATION_MEMBER_VALUE) \ end_class \ start_class(ArrayIndexOutOfBoundsException, java_lang_ArrayIndexOutOfBoundsException) \ jvmci_constructor(ArrayIndexOutOfBoundsException, "(Ljava/lang/String;)V") \ diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index a20877628e56d..a8b89d149f75f 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -1510,15 +1510,22 @@ JVMCIObject JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_TRAPS) { return _HotSpotJVMCIRuntime_instance; } +#ifdef ASSERT +static void assert_equals(const char* desc, int expect, int actual) { + assert(expect == actual, "%s: %d != %d", desc, expect, actual); + +} +#endif + // Implementation of CompilerToVM.registerNatives() // When called from libjvmci, `libjvmciOrHotspotEnv` is a libjvmci env so use JVM_ENTRY_NO_ENV. -JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *libjvmciOrHotspotEnv, jclass c2vmClass, - jint declaredAnnotations, jint parameterAnnotations, jint typeAnnotations)) +JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *libjvmciOrHotspotEnv, jclass c2vmClass)) JVMCIENV_FROM_JNI(thread, libjvmciOrHotspotEnv); - assert(CompilerToVM::DECLARED_ANNOTATIONS == declaredAnnotations, "%d != %d", CompilerToVM::DECLARED_ANNOTATIONS, declaredAnnotations); - assert(CompilerToVM::PARAMETER_ANNOTATIONS == parameterAnnotations, "%d != %d", CompilerToVM::PARAMETER_ANNOTATIONS, parameterAnnotations); - assert(CompilerToVM::TYPE_ANNOTATIONS == typeAnnotations, "%d != %d", CompilerToVM::TYPE_ANNOTATIONS, typeAnnotations); + DEBUG_ONLY(assert_equals("DECLARED_ANNOTATIONS", CompilerToVM::DECLARED_ANNOTATIONS, JVMCIENV->get_VMSupport_DECLARED_ANNOTATIONS())); + DEBUG_ONLY(assert_equals("PARAMETER_ANNOTATIONS", CompilerToVM::PARAMETER_ANNOTATIONS, JVMCIENV->get_VMSupport_PARAMETER_ANNOTATIONS())); + DEBUG_ONLY(assert_equals("TYPE_ANNOTATIONS", CompilerToVM::TYPE_ANNOTATIONS, JVMCIENV->get_VMSupport_TYPE_ANNOTATIONS())); + DEBUG_ONLY(assert_equals("ANNOTATION_MEMBER_VALUE", CompilerToVM::ANNOTATION_MEMBER_VALUE, JVMCIENV->get_VMSupport_ANNOTATION_MEMBER_VALUE())); if (!EnableJVMCI) { JVMCI_THROW_MSG(InternalError, JVMCI_NOT_ENABLED_ERROR_MESSAGE); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 737718096c5fc..78c8f00cc2076 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -710,6 +710,7 @@ declare_constant(ConstMethodFlags::_misc_has_exception_table) \ declare_constant(ConstMethodFlags::_misc_has_method_annotations) \ declare_constant(ConstMethodFlags::_misc_has_parameter_annotations) \ + declare_constant(ConstMethodFlags::_misc_has_default_annotations) \ declare_constant(ConstMethodFlags::_misc_caller_sensitive) \ declare_constant(ConstMethodFlags::_misc_is_hidden) \ declare_constant(ConstMethodFlags::_misc_intrinsic_candidate) \ diff --git a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp index 3018a509ffee8..8c8d8510dfca2 100644 --- a/src/hotspot/share/prims/nativeLookup.cpp +++ b/src/hotspot/share/prims/nativeLookup.cpp @@ -210,7 +210,7 @@ extern "C" { #if INCLUDE_JVMCI jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); jlong JNICALL JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets); - void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass, jint declaredAnnotations, jint parameterAnnotations, jint typeAnnotations); + void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass); #endif } diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index 5adde84b088cb..4fc290a7a7c2c 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -42,6 +42,7 @@ import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.annotation.AnnotationTypeMismatchException; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.List; @@ -200,15 +201,22 @@ public static int encodeThrowable(Throwable throwable, long buffer, int bufferSi */ public static final int TYPE_ANNOTATIONS = 2; + /** + * Denotes a byte array that is parsed into an {@code Object} by + * {@link AnnotationParser#parseMemberValue}. + */ + public static final int ANNOTATION_MEMBER_VALUE = 3; + /** * Parses {@code rawAnnotations} according to {@code category} and returns the parse * result encoded as a byte array. *

-     *     category              | parse result type   | decoding method
-     *     ----------------------|--------------------|------------------------------------------
-     *     DECLARED_ANNOTATIONS  | Annotation[]        | {@link #decodeAnnotations(byte[], AnnotationDecoder)}
-     *     PARAMETER_ANNOTATIONS | Annotation[][]      | {@link #decodeAnnotations(byte[], AnnotationDecoder)}
-     *     TYPE_ANNOTATIONS      | TypeAnnotation[]    | {@link #decodeTypeAnnotations(byte[], AnnotationDecoder)}
+     *     category                | parse result type   | decoding method
+     *     ------------------------|---------------------|------------------------------------------
+     *     DECLARED_ANNOTATIONS    | Annotation[]        | {@link #decodeAnnotations(byte[], AnnotationDecoder)}
+     *     PARAMETER_ANNOTATIONS   | Annotation[][]      | {@link #decodeParameterAnnotations(byte[], AnnotationDecoder)}
+     *     TYPE_ANNOTATIONS        | TypeAnnotation[]    | {@link #decodeTypeAnnotations(byte[], AnnotationDecoder)}
+     *     ANNOTATION_MEMBER_VALUE | Object              | {@link #decodeAnnotationMemberValue(byte[], AnnotationDecoder)}
      * 
* * @param category {@link #DECLARED_ANNOTATIONS}, {@link #PARAMETER_ANNOTATIONS} or {@link #TYPE_ANNOTATIONS} @@ -216,58 +224,57 @@ public static int encodeThrowable(Throwable throwable, long buffer, int bufferSi public static byte[] encodeAnnotations(byte[] rawAnnotations, int category, Class declaringClass, - ConstantPool cp) { - return switch (category) { - case DECLARED_ANNOTATIONS -> - encodeAnnotations(AnnotationParser.parseAnnotations(rawAnnotations, cp, declaringClass, false).values()); - case PARAMETER_ANNOTATIONS -> - encodeParameterAnnotations(AnnotationParser.parseParameterAnnotations(rawAnnotations, cp, declaringClass)); - case TYPE_ANNOTATIONS -> - encodeTypeAnnotations(TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, declaringClass)); - default -> throw new IllegalArgumentException("illegal category: " + category); - }; + ConstantPool cp, + Class memberType) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(128); + try (DataOutputStream dos = new DataOutputStream(baos)) { + switch (category) { + case DECLARED_ANNOTATIONS -> + encodeAnnotations(dos, AnnotationParser.parseAnnotations(rawAnnotations, cp, declaringClass, false).values()); + case PARAMETER_ANNOTATIONS -> + encodeParameterAnnotations(dos, AnnotationParser.parseParameterAnnotations(rawAnnotations, cp, declaringClass)); + case TYPE_ANNOTATIONS -> + encodeTypeAnnotations(dos, TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, declaringClass)); + case ANNOTATION_MEMBER_VALUE -> + encodeMemberValue(dos, AnnotationParser.parseMemberValue(memberType, ByteBuffer.wrap(rawAnnotations), cp, declaringClass, false)); + default -> throw new IllegalArgumentException("illegal category: " + category); + }; + return baos.toByteArray(); + } catch (IOException ioe) { + throw new InternalError(ioe); + } } /** - * Encodes annotations to a byte array. The byte array can be decoded with {@link #decodeAnnotations(byte[], AnnotationDecoder)}. + * Encodes {@code annotations} to a byte array. The byte array can be decoded + * with {@link #decodeAnnotations(byte[], AnnotationDecoder)}. + * + * @param dos stream for assembling the byte array */ - public static byte[] encodeAnnotations(Collection annotations) { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(128); - try (DataOutputStream dos = new DataOutputStream(baos)) { - writeLength(dos, annotations.size()); - for (Annotation a : annotations) { - encodeAnnotation(dos, a); - } - } - return baos.toByteArray(); - } catch (Exception e) { - throw new InternalError(e); + public static void encodeAnnotations(DataOutputStream dos, Collection annotations) throws IOException { + writeLength(dos, annotations.size()); + for (Annotation a : annotations) { + encodeAnnotation(dos, a); } } /** - * Encodes parameter annotations to a byte array. The byte array can be decoded with {@link #decodeParameterAnnotations(byte[], AnnotationDecoder)}. + * Encodes {@code parameterAnnotations} to a byte array. The byte array can be decoded + * with {@link #decodeParameterAnnotations(byte[], AnnotationDecoder)}. + * + * @param dos stream for assembling the byte array */ - public static byte[] encodeParameterAnnotations(Annotation[][] parameterAnnotations) { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(128); - try (DataOutputStream dos = new DataOutputStream(baos)) { - writeLength(dos, parameterAnnotations.length); - for (Annotation[] annotations : parameterAnnotations) { - writeLength(dos, annotations.length); - for (Annotation a : annotations) { - encodeAnnotation(dos, a); - } - } + public static void encodeParameterAnnotations(DataOutputStream dos, Annotation[][] parameterAnnotations) throws IOException { + writeLength(dos, parameterAnnotations.length); + for (Annotation[] annotations : parameterAnnotations) { + writeLength(dos, annotations.length); + for (Annotation a : annotations) { + encodeAnnotation(dos, a); } - return baos.toByteArray(); - } catch (Exception e) { - throw new InternalError(e); } } - private static void encodeAnnotation(DataOutputStream dos, Annotation a) throws Exception { + private static void encodeAnnotation(DataOutputStream dos, Annotation a) throws IOException { Class type = a.annotationType(); Map values = AnnotationSupport.memberValues(a); dos.writeUTF(type.getName()); @@ -278,191 +285,196 @@ private static void encodeAnnotation(DataOutputStream dos, Annotation a) throws // IncompleteAnnotationException continue; } - Class valueType = value.getClass(); dos.writeUTF(e.getKey()); - if (valueType == Byte.class) { + encodeMemberValue(dos, value); + } + } + + /** + * Encodes {@code value} to a byte array. The byte array can be decoded + * with {@link #decodeAnnotationMemberValue(byte[], AnnotationDecoder)}. + * + * @param dos stream for assembling the byte array + */ + private static void encodeMemberValue(DataOutputStream dos, Object value) throws IOException { + Class valueType = value.getClass(); + if (valueType == Byte.class) { + dos.writeByte('B'); + dos.writeByte((byte) value); + } else if (valueType == Character.class) { + dos.writeByte('C'); + dos.writeChar((char) value); + } else if (valueType == Double.class) { + dos.writeByte('D'); + dos.writeDouble((double) value); + } else if (valueType == Float.class) { + dos.writeByte('F'); + dos.writeFloat((float) value); + } else if (valueType == Integer.class) { + dos.writeByte('I'); + dos.writeInt((int) value); + } else if (valueType == Long.class) { + dos.writeByte('J'); + dos.writeLong((long) value); + } else if (valueType == Short.class) { + dos.writeByte('S'); + dos.writeShort((short) value); + } else if (valueType == Boolean.class) { + dos.writeByte('Z'); + dos.writeBoolean((boolean) value); + } else if (valueType == String.class) { + dos.writeByte('s'); + dos.writeUTF((String) value); + } else if (valueType == Class.class) { + dos.writeByte('c'); + dos.writeUTF(((Class) value).getName()); + } else if (valueType == EnumValue.class) { + EnumValue enumValue = (EnumValue) value; + dos.writeByte('e'); + dos.writeUTF(enumValue.enumType.getName()); + dos.writeUTF(enumValue.constName); + } else if (valueType == EnumValueArray.class) { + EnumValueArray enumValueArray = (EnumValueArray) value; + List array = enumValueArray.constNames; + dos.writeByte('['); + dos.writeByte('e'); + dos.writeUTF(enumValueArray.enumType.getName()); + writeLength(dos, array.size()); + for (String s : array) { + dos.writeUTF(s); + } + } else if (valueType.isEnum()) { + dos.writeByte('e'); + dos.writeUTF(valueType.getName()); + dos.writeUTF(((Enum) value).name()); + } else if (value instanceof Annotation) { + dos.writeByte('@'); + encodeAnnotation(dos, (Annotation) value); + } else if (valueType.isArray()) { + Class componentType = valueType.getComponentType(); + if (componentType == byte.class) { + byte[] array = (byte[]) value; + dos.writeByte('['); dos.writeByte('B'); - dos.writeByte((byte) value); - } else if (valueType == Character.class) { + writeLength(dos, array.length); + dos.write(array); + } else if (componentType == char.class) { + char[] array = (char[]) value; + dos.writeByte('['); dos.writeByte('C'); - dos.writeChar((char) value); - } else if (valueType == Double.class) { + writeLength(dos, array.length); + for (char c : array) { + dos.writeChar(c); + } + } else if (componentType == double.class) { + double[] array = (double[]) value; + dos.writeByte('['); dos.writeByte('D'); - dos.writeDouble((double) value); - } else if (valueType == Float.class) { + writeLength(dos, array.length); + for (double v : array) { + dos.writeDouble(v); + } + } else if (componentType == float.class) { + float[] array = (float[]) value; + dos.writeByte('['); dos.writeByte('F'); - dos.writeFloat((float) value); - } else if (valueType == Integer.class) { + writeLength(dos, array.length); + for (float v : array) { + dos.writeFloat(v); + } + } else if (componentType == int.class) { + int[] array = (int[]) value; + dos.writeByte('['); dos.writeByte('I'); - dos.writeInt((int) value); - } else if (valueType == Long.class) { + writeLength(dos, array.length); + for (int j : array) { + dos.writeInt(j); + } + } else if (componentType == long.class) { + long[] array = (long[]) value; + dos.writeByte('['); dos.writeByte('J'); - dos.writeLong((long) value); - } else if (valueType == Short.class) { + writeLength(dos, array.length); + for (long l : array) { + dos.writeLong(l); + } + } else if (componentType == short.class) { + short[] array = (short[]) value; + dos.writeByte('['); dos.writeByte('S'); - dos.writeShort((short) value); - } else if (valueType == Boolean.class) { + writeLength(dos, array.length); + for (short item : array) { + dos.writeShort(item); + } + } else if (componentType == boolean.class) { + boolean[] array = (boolean[]) value; + dos.writeByte('['); dos.writeByte('Z'); - dos.writeBoolean((boolean) value); - } else if (valueType == String.class) { - dos.writeByte('s'); - dos.writeUTF((String) value); - } else if (valueType == Class.class) { - dos.writeByte('c'); - dos.writeUTF(((Class) value).getName()); - } else if (valueType == EnumValue.class) { - EnumValue enumValue = (EnumValue) value; - dos.writeByte('e'); - dos.writeUTF(enumValue.enumType.getName()); - dos.writeUTF(enumValue.constName); - } else if (valueType == EnumValueArray.class) { - EnumValueArray enumValueArray = (EnumValueArray) value; - List array = enumValueArray.constNames; + writeLength(dos, array.length); + for (boolean b : array) { + dos.writeBoolean(b); + } + } else if (componentType == String.class) { + String[] array = (String[]) value; dos.writeByte('['); - dos.writeByte('e'); - dos.writeUTF(enumValueArray.enumType.getName()); - writeLength(dos, array.size()); + dos.writeByte('s'); + writeLength(dos, array.length); for (String s : array) { dos.writeUTF(s); } - } else if (valueType.isEnum()) { + } else if (componentType == Class.class) { + Class[] array = (Class[]) value; + dos.writeByte('['); + dos.writeByte('c'); + writeLength(dos, array.length); + for (Class aClass : array) { + dos.writeUTF(aClass.getName()); + } + } else if (componentType.isEnum()) { + Enum[] array = (Enum[]) value; + dos.writeByte('['); dos.writeByte('e'); - dos.writeUTF(valueType.getName()); - dos.writeUTF(((Enum) value).name()); - } else if (value instanceof Annotation) { + dos.writeUTF(componentType.getName()); + writeLength(dos, array.length); + for (Enum anEnum : array) { + dos.writeUTF(anEnum.name()); + } + } else if (componentType.isAnnotation()) { + Annotation[] array = (Annotation[]) value; + dos.writeByte('['); dos.writeByte('@'); - encodeAnnotation(dos, (Annotation) value); - } else if (valueType.isArray()) { - Class componentType = valueType.getComponentType(); - if (componentType == byte.class) { - byte[] array = (byte[]) value; - dos.writeByte('['); - dos.writeByte('B'); - writeLength(dos, array.length); - dos.write(array); - } else if (componentType == char.class) { - char[] array = (char[]) value; - dos.writeByte('['); - dos.writeByte('C'); - writeLength(dos, array.length); - for (char c : array) { - dos.writeChar(c); - } - } else if (componentType == double.class) { - double[] array = (double[]) value; - dos.writeByte('['); - dos.writeByte('D'); - writeLength(dos, array.length); - for (double v : array) { - dos.writeDouble(v); - } - } else if (componentType == float.class) { - float[] array = (float[]) value; - dos.writeByte('['); - dos.writeByte('F'); - writeLength(dos, array.length); - for (float v : array) { - dos.writeFloat(v); - } - } else if (componentType == int.class) { - int[] array = (int[]) value; - dos.writeByte('['); - dos.writeByte('I'); - writeLength(dos, array.length); - for (int j : array) { - dos.writeInt(j); - } - } else if (componentType == long.class) { - long[] array = (long[]) value; - dos.writeByte('['); - dos.writeByte('J'); - writeLength(dos, array.length); - for (long l : array) { - dos.writeLong(l); - } - } else if (componentType == short.class) { - short[] array = (short[]) value; - dos.writeByte('['); - dos.writeByte('S'); - writeLength(dos, array.length); - for (short item : array) { - dos.writeShort(item); - } - } else if (componentType == boolean.class) { - boolean[] array = (boolean[]) value; - dos.writeByte('['); - dos.writeByte('Z'); - writeLength(dos, array.length); - for (boolean b : array) { - dos.writeBoolean(b); - } - } else if (componentType == String.class) { - String[] array = (String[]) value; - dos.writeByte('['); - dos.writeByte('s'); - writeLength(dos, array.length); - for (String s : array) { - dos.writeUTF(s); - } - } else if (componentType == Class.class) { - Class[] array = (Class[]) value; - dos.writeByte('['); - dos.writeByte('c'); - writeLength(dos, array.length); - for (Class aClass : array) { - dos.writeUTF(aClass.getName()); - } - } else if (componentType.isEnum()) { - Enum[] array = (Enum[]) value; - dos.writeByte('['); - dos.writeByte('e'); - dos.writeUTF(componentType.getName()); - writeLength(dos, array.length); - for (Enum anEnum : array) { - dos.writeUTF(anEnum.name()); - } - } else if (componentType.isAnnotation()) { - Annotation[] array = (Annotation[]) value; - dos.writeByte('['); - dos.writeByte('@'); - writeLength(dos, array.length); - for (Annotation annotation : array) { - encodeAnnotation(dos, annotation); - } - } else { - throw new InternalError("Unsupported annotation element component type " + componentType); + writeLength(dos, array.length); + for (Annotation annotation : array) { + encodeAnnotation(dos, annotation); } - } else if (value instanceof TypeNotPresentExceptionProxy proxy) { - dos.writeByte('x'); - dos.writeUTF(proxy.typeName()); - } else if (value instanceof AnnotationTypeMismatchExceptionProxy proxy) { - dos.writeByte('y'); - dos.writeUTF(proxy.foundType()); } else { - throw new InternalError("Unsupported annotation element type " + valueType); + throw new InternalError("Unsupported annotation element component type " + componentType); } + } else if (value instanceof TypeNotPresentExceptionProxy proxy) { + dos.writeByte('x'); + dos.writeUTF(proxy.typeName()); + } else if (value instanceof AnnotationTypeMismatchExceptionProxy proxy) { + dos.writeByte('y'); + dos.writeUTF(proxy.foundType()); + } else { + throw new InternalError("Unsupported annotation element type " + valueType); } } /** - * Encodes typeAnnotations to a byte array. The byte array can be decoded with {@link #decodeAnnotations(byte[], AnnotationDecoder)}. + * Encodes {@code typeAnnotations} to a byte array. The byte array can be decoded + * with {@link #decodeAnnotations(byte[], AnnotationDecoder)}. + * + * @param dos stream for assembling the byte array */ - public static byte[] encodeTypeAnnotations(TypeAnnotation[] typeAnnotations) { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(128); - try (DataOutputStream dos = new DataOutputStream(baos)) { - writeLength(dos, typeAnnotations.length); - for (TypeAnnotation ta : typeAnnotations) { - encodeTypeAnnotation(dos, ta); - } - } - return baos.toByteArray(); - } catch (Exception e) { - throw new InternalError(e); + public static void encodeTypeAnnotations(DataOutputStream dos, TypeAnnotation[] typeAnnotations) throws IOException { + writeLength(dos, typeAnnotations.length); + for (TypeAnnotation ta : typeAnnotations) { + encodeTypeAnnotation(dos, ta); } } - private static void encodeTypeAnnotation(DataOutputStream dos, TypeAnnotation ta) throws Exception { + private static void encodeTypeAnnotation(DataOutputStream dos, TypeAnnotation ta) throws IOException { TypeAnnotation.TypeAnnotationTargetInfo ti = ta.getTargetInfo(); TypeAnnotation.TypeAnnotationTarget target = ti.getTarget(); dos.writeUTF(target.name()); @@ -563,6 +575,26 @@ public static List
decodeAnnotations(byte[] encode } } + /** + * Decodes an annotation member value serialized in {@code encoded} to an object. + * + * @param type to which a type name is resolved + * @param type of the object representing a decoded annotation + * @param type of the object representing a decoded enum constant + * @param type of the object representing a missing type + * @param type of the object representing a decoded element type mismatch + * @return the decoded object value of a type matching the objects returned by {@link jdk.vm.ci.meta.annotation.AnnotationValue#get(String, Class)} + */ + public static Object decodeAnnotationMemberValue(byte[] encoded, AnnotationDecoder decoder) { + try { + ByteArrayInputStream bais = new ByteArrayInputStream(encoded); + DataInputStream dis = new DataInputStream(bais); + return decodeMemberValue(dis, decoder); + } catch (Exception e) { + throw new InternalError(e); + } + } + /** * Decodes parameter annotations serialized in {@code encoded} to objects. * @@ -599,29 +631,34 @@ private static A decodeAnnotation(DataInputStream dis Map.Entry[] elements = n == 0 ? NO_ELEMENTS : new Map.Entry[n]; for (int i = 0; i < n; i++) { String name = dis.readUTF(); - byte tag = dis.readByte(); - elements[i] = Map.entry(name, switch (tag) { - case 'B' -> dis.readByte(); - case 'C' -> dis.readChar(); - case 'D' -> dis.readDouble(); - case 'F' -> dis.readFloat(); - case 'I' -> dis.readInt(); - case 'J' -> dis.readLong(); - case 'S' -> dis.readShort(); - case 'Z' -> dis.readBoolean(); - case 's' -> dis.readUTF(); - case 'c' -> decoder.resolveType(dis.readUTF()); - case 'e' -> decoder.newEnum(decoder.resolveType(dis.readUTF()), dis.readUTF()); - case '@' -> decodeAnnotation(dis, decoder); - case '[' -> decodeArray(dis, decoder); - case 'x' -> decoder.newMissingType(dis.readUTF()); - case 'y' -> decoder.newElementTypeMismatch(dis.readUTF()); - default -> throw new InternalError("Unsupported tag: " + tag); - }); + Object value = decodeMemberValue(dis, decoder); + elements[i] = Map.entry(name, value); } return decoder.newAnnotation(type, (Map.Entry[]) elements); } + private static Object decodeMemberValue(DataInputStream dis, AnnotationDecoder decoder) throws IOException { + byte tag = dis.readByte(); + return switch (tag) { + case 'B' -> dis.readByte(); + case 'C' -> dis.readChar(); + case 'D' -> dis.readDouble(); + case 'F' -> dis.readFloat(); + case 'I' -> dis.readInt(); + case 'J' -> dis.readLong(); + case 'S' -> dis.readShort(); + case 'Z' -> dis.readBoolean(); + case 's' -> dis.readUTF(); + case 'c' -> decoder.resolveType(dis.readUTF()); + case 'e' -> decoder.newEnum(decoder.resolveType(dis.readUTF()), dis.readUTF()); + case '@' -> decodeAnnotation(dis, decoder); + case '[' -> decodeArray(dis, decoder); + case 'x' -> decoder.newMissingType(dis.readUTF()); + case 'y' -> decoder.newElementTypeMismatch(dis.readUTF()); + default -> throw new InternalError("Unsupported tag: " + tag); + }; + } + @FunctionalInterface interface IOReader { Object read() throws IOException; diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java index a8f9014a51669..2de70f4cb81cd 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java @@ -125,6 +125,12 @@ private AnnotationType(final Class annotationClass) { byte[] annotationDefault = SharedSecrets.getJavaLangReflectAccess().getAnnotationDefaultBytes(method); if (annotationDefault != null) { + // Pass eagerResolution==false to support the + // context where eager resolution is not desired. + // All uses of defaultValue will use + // sun.reflect.annotation.ResolvableValue.resolved + // to ensure only resolved values are seen by + // users of the standard annotation API. Object defaultValue = AnnotationParser.parseAnnotationDefault(method, annotationDefault, false); if (defaultValue != null) { memberDefaults.put(name, defaultValue); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index c463d2616493d..c47461de4ac2f 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -23,7 +23,6 @@ package jdk.vm.ci.hotspot; -import jdk.internal.misc.Unsafe; import jdk.internal.vm.VMSupport; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.InstalledCode; @@ -61,7 +60,7 @@ final class CompilerToVM { /** * Initializes the native part of the JVMCI runtime. */ - private static native void registerNatives(int declaredAnnotations, int parameterAnnotations, int typeAnnotations); + private static native void registerNatives(); /** * These values mirror the equivalent values from {@code Unsafe} but are appropriate for the JVM @@ -88,8 +87,8 @@ final class CompilerToVM { @SuppressWarnings("try") CompilerToVM() { - try (InitTimer t = timer("CompilerToVM.registerNatives")) { - registerNatives(VMSupport.DECLARED_ANNOTATIONS, VMSupport.PARAMETER_ANNOTATIONS, VMSupport.TYPE_ANNOTATIONS); + try (InitTimer _ = timer("CompilerToVM.registerNatives")) { + registerNatives(); ARRAY_BOOLEAN_BASE_OFFSET = arrayBaseOffset(JavaKind.Boolean.getTypeChar()); ARRAY_BYTE_BASE_OFFSET = arrayBaseOffset(JavaKind.Byte.getTypeChar()); ARRAY_SHORT_BASE_OFFSET = arrayBaseOffset(JavaKind.Short.getTypeChar()); @@ -1459,11 +1458,14 @@ byte[] getEncodedClassAnnotationValues(HotSpotResolvedObjectTypeImpl type, int c * Gets the serialized annotation info for {@code method} by calling * {@code VMSupport.encodeAnnotations} in the HotSpot heap. */ - byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, int category) { - return getEncodedExecutableAnnotationValues(method, method.getMethodPointer(), category); + byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, HotSpotResolvedObjectTypeImpl memberType, int category) { + long memberTypePointer = memberType == null ? 0L: memberType.getKlassPointer(); + return getEncodedExecutableAnnotationValues(method, method.getMethodPointer(), + memberType, memberTypePointer, category); } - native byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, long methodPointer, int category); + native byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl method, long methodPointer, + HotSpotResolvedObjectTypeImpl memberType, long klassPointer, int category); /** * Gets the serialized annotation info for the field denoted by {@code holder} and diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 74a98e273ee78..fc589ad236592 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -28,6 +28,7 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.UnresolvedJavaType; import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.AnnotationValueDecoder; import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import java.lang.annotation.Annotation; @@ -233,24 +234,11 @@ public JavaConstant getConstantValue() { return holder.getFieldInfo(index).getConstantValue(holder); } - @Override - public AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType annotationType) { - checkIsAnnotation(annotationType); - if (!hasAnnotations()) { - return null; - } - return getAnnotationValues0().get(annotationType); - } - @Override public Map getDeclaredAnnotationValues() { if (!hasAnnotations()) { return Map.of(); } - return getAnnotationValues0(); - } - - private Map getAnnotationValues0() { byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, VMSupport.DECLARED_ANNOTATIONS); return new AnnotationValueDecoder(getDeclaringClass()).decode(encoded); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 523f4bc910d26..7eacee224b782 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -40,6 +40,7 @@ import jdk.vm.ci.meta.SpeculationLog; import jdk.vm.ci.meta.TriState; import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.AnnotationValueDecoder; import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import java.lang.annotation.Annotation; @@ -56,7 +57,6 @@ import static jdk.vm.ci.hotspot.HotSpotModifiers.SYNTHETIC; import static jdk.vm.ci.hotspot.HotSpotModifiers.VARARGS; import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmMethodModifiers; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkIsAnnotation; import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; @@ -777,25 +777,12 @@ public int methodIdnum() { return UNSAFE.getChar(getConstMethod() + config().constMethodMethodIdnumOffset); } - @Override - public AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType type) { - checkIsAnnotation(type); - if (!hasAnnotations()) { - return null; - } - return getAnnotationValues0().get(type); - } - @Override public Map getDeclaredAnnotationValues() { if (!hasAnnotations()) { return Map.of(); } - return getAnnotationValues0(); - } - - private Map getAnnotationValues0() { - byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.DECLARED_ANNOTATIONS); + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, null, VMSupport.DECLARED_ANNOTATIONS); return new AnnotationValueDecoder(getDeclaringClass()).decode(encoded); } @@ -804,16 +791,35 @@ public List> getParameterAnnotationValues() { if (!hasParameterAnnotations()) { return null; } - byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.PARAMETER_ANNOTATIONS); + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, null, VMSupport.PARAMETER_ANNOTATIONS); return VMSupport.decodeParameterAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); } @Override public List getTypeAnnotationValues() { - byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, VMSupport.TYPE_ANNOTATIONS); + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, null, VMSupport.TYPE_ANNOTATIONS); return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); } + private boolean hasDefaultAnnotations() { + return (getConstMethodFlags() & HotSpotVMConfig.config().constMethodHasDefaultAnnotations) != 0; + } + + @Override + public Object getAnnotationDefaultValue() { + if (!hasDefaultAnnotations()) { + return null; + } + HotSpotResolvedObjectTypeImpl declaringClass = getDeclaringClass(); + ResolvedJavaType type = this.getSignature().getReturnType(declaringClass).resolve(declaringClass); + if (type.getJavaKind().isPrimitive()) { + type = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaType(type.getJavaKind().toBoxedJavaClass()); + } + HotSpotResolvedObjectTypeImpl memberType = (HotSpotResolvedObjectTypeImpl) type; + byte[] encoded = compilerToVM().getEncodedExecutableAnnotationValues(this, memberType, VMSupport.ANNOTATION_MEMBER_VALUE); + return VMSupport.decodeAnnotationMemberValue(encoded, new AnnotationValueDecoder(declaringClass)); + } + @Override public BitSet getOopMapAt(int bci) { if (getCodeSize() == 0) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index e40594cabc08d..79af586b8e994 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -39,6 +39,7 @@ import jdk.vm.ci.meta.UnresolvedJavaField; import jdk.vm.ci.meta.UnresolvedJavaType; import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.AnnotationValueDecoder; import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import java.lang.annotation.Annotation; @@ -1116,24 +1117,11 @@ public boolean isCloneableWithAllocation() { return (getMiscFlags() & config().jvmAccIsCloneableFast) != 0; } - @Override - public AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType annotationType) { - checkIsAnnotation(annotationType); - if (!mayHaveAnnotations(true)) { - return null; - } - return getAnnotationValues0().get(annotationType); - } - @Override public Map getDeclaredAnnotationValues() { if (!mayHaveAnnotations(true)) { return Map.of(); } - return getAnnotationValues0(); - } - - private Map getAnnotationValues0() { byte[] encoded = compilerToVM().getEncodedClassAnnotationValues(this, VMSupport.DECLARED_ANNOTATIONS); return new AnnotationValueDecoder(this).decode(encoded); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 449b315e46716..85b1a44565524 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -203,6 +203,7 @@ long prototypeMarkWord() { final int constMethodHasLocalVariableTable = getConstant("ConstMethodFlags::_misc_has_localvariable_table", Integer.class); final int constMethodHasMethodAnnotations = getConstant("ConstMethodFlags::_misc_has_method_annotations", Integer.class); final int constMethodHasParameterAnnotations = getConstant("ConstMethodFlags::_misc_has_parameter_annotations", Integer.class); + final int constMethodHasDefaultAnnotations = getConstant("ConstMethodFlags::_misc_has_default_annotations", Integer.class); final int constMethodHasExceptionTable = getConstant("ConstMethodFlags::_misc_has_exception_table", Integer.class); final int exceptionTableElementSize = getFieldValue("CompilerToVM::Data::sizeof_ExceptionTableElement", Integer.class, "int"); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index fce8d5a05913a..9384e7cab4a3e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -510,9 +510,29 @@ default List getTypeAnnotationValues() { * * @return null if there are no parameter annotations for this method otherwise * an immutable list of immutable lists of parameter annotations + * @throws UnsupportedOperationException if this operation is not supported * @jvms 4.7.18 */ default List> getParameterAnnotationValues() { throw new UnsupportedOperationException(getClass().getName()); } + + /** + * Returns the default value for the annotation member represented by + * this {@code ResolvedJavaMethod} instance. Returns + * null if no default is associated with the member, or if the method + * instance does not represent a declared member of an annotation type. + * + * @see Method#getDefaultValue() + * @return the default value for the annotation member represented + * by this object. The type of the returned value is specified + * by {@link AnnotationValue#get} + * @throws TypeNotPresentException if the annotation member is of type + * {@link Class} and no definition can be found for the + * default class value. + * @throws UnsupportedOperationException if this operation is not supported + */ + default Object getAnnotationDefaultValue() { + throw new UnsupportedOperationException(getClass().getName()); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java index 1ed5471bfb501..6dd375438a41d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java @@ -59,6 +59,9 @@ default Map getDeclaredAnnotationValues() { * @throws UnsupportedOperationException if this operation is not supported */ default AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType type) { - throw new UnsupportedOperationException(this.getClass().getName()); + if (!type.isAnnotation()) { + throw new IllegalArgumentException(type.toJavaName() + " is not an annotation interface"); + } + return getDeclaredAnnotationValues().get(type); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValueDecoder.java similarity index 81% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValueDecoder.java index d61be7de14de7..df316e0395009 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationValueDecoder.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValueDecoder.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.vm.ci.hotspot; +package jdk.vm.ci.meta.annotation; import jdk.internal.vm.VMSupport; import jdk.internal.vm.VMSupport.AnnotationDecoder; @@ -28,12 +28,6 @@ import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.UnresolvedJavaType; -import jdk.vm.ci.meta.annotation.AnnotationValue; -import jdk.vm.ci.meta.annotation.ElementTypeMismatch; -import jdk.vm.ci.meta.annotation.EnumArrayElement; -import jdk.vm.ci.meta.annotation.EnumElement; -import jdk.vm.ci.meta.annotation.MissingType; -import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import sun.reflect.annotation.TypeAnnotation; import java.util.List; @@ -46,16 +40,16 @@ * and employs {@link AnnotationValue} to represent decoded annotations and enum * constants respectively. */ -final class AnnotationValueDecoder implements AnnotationDecoder { +public final class AnnotationValueDecoder implements AnnotationDecoder { - private final HotSpotResolvedJavaType accessingClass; + private final ResolvedJavaType accessingClass; - Map decode(byte[] encoded) { + public Map decode(byte[] encoded) { List annotationValues = VMSupport.decodeAnnotations(encoded, this); return annotationValues.stream().collect(Collectors.toMap(AnnotationValue::getAnnotationType, Function.identity())); } - AnnotationValueDecoder(HotSpotResolvedJavaType accessingClass) { + public AnnotationValueDecoder(ResolvedJavaType accessingClass) { this.accessingClass = accessingClass; } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index cbc6c26ede957..ea85f8f48f2d6 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -67,6 +67,7 @@ import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationValueTest.NumbersDE; import org.junit.Assert; import org.junit.Test; + import sun.reflect.annotation.TypeAnnotation; import sun.reflect.annotation.TypeAnnotationParser; @@ -106,6 +107,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** @@ -371,9 +373,11 @@ public void getAnnotationsTest() throws NoSuchMethodException { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) @interface Special { + String elementWithDefault() default "NO_NAME"; + long elementWithoutDefault(); } - private static native void methodWithAnnotatedParameters(@NonNull HashMap p1, @Special @NonNull Class p2); + private static native void methodWithAnnotatedParameters(@NonNull HashMap p1, @Special(elementWithoutDefault = 42) @NonNull Class p2); @Test public void getParameterAnnotationsTest() throws NoSuchMethodException { @@ -559,6 +563,10 @@ public enum NumbersEN { public enum NumbersDE { Eins, Zwei; + + static { + Assert.fail("NumbersDE. should not be called"); + } } public enum NumbersUA { @@ -622,6 +630,30 @@ private static void getParameterAnnotationValuesTest(Executable executable) { } } + @Test + public void getAnnotationDefaultValueTest() throws NoSuchMethodException { + getAnnotationDefaultValueTest(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + getAnnotationDefaultValueTest(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); + for (Method m : methods.keySet()) { + getAnnotationDefaultValueTest(m); + } + } + + /** + * Tests that {@link TypeAnnotation}s obtained from {@code executable} + * match {@link TypeAnnotationValue}s for the corresponding {@link ResolvedJavaMethod}. + */ + private static void getAnnotationDefaultValueTest(Method executable) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(executable); + Object defaultValue = executable.getDefaultValue(); + Object annotationDefaultValue = method.getAnnotationDefaultValue(); + if (defaultValue == null) { + assertNull(annotationDefaultValue); + } else { + TestResolvedJavaType.assertAnnotationElementsEqual(defaultValue, annotationDefaultValue); + } + } + public static void assertParameterAnnotationsEquals( Annotation[][] parameterAnnotations, List> parameterAnnotationValues) throws AssertionError { @@ -666,6 +698,12 @@ public void getParameterAnnotationValuesTest() throws Exception { public void getAnnotationValuesTest() throws Exception { TestResolvedJavaType.getAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); TestResolvedJavaType.getAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("missingAnnotation")); + try { + TestResolvedJavaType.getAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("missingElementTypeAnnotation")); + throw new AssertionError("expected " + TypeNotPresentException.class.getName()); + } catch (TypeNotPresentException e) { + Assert.assertEquals("Type jdk.internal.vm.test.AnnotationTestInput$Missing not present", e.getMessage()); + } try { TestResolvedJavaType.getAnnotationValuesTest(AnnotationTestInput.class.getDeclaredMethod("missingNestedAnnotation")); throw new AssertionError("expected " + NoClassDefFoundError.class.getName()); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index 6d2fe6d49f7d3..ea7012ab36bfc 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -1362,7 +1362,6 @@ public static void assertTypeAnnotationsEquals( } private static List testGetAnnotationValues(Annotated annotated, List annotations) throws AssertionError { - ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); List res = new ArrayList<>(annotations.size()); Map allAnnotationValues = annotated.getDeclaredAnnotationValues(); @@ -1449,7 +1448,7 @@ public static Class toAnnotationValueElementType(Class type) { return type; } - private static void assertAnnotationElementsEqual(Object aElement, Object avElement) { + public static void assertAnnotationElementsEqual(Object aElement, Object avElement) { Class valueType = aElement.getClass(); if (valueType.isEnum()) { String avEnumName = ((EnumElement) avElement).name; diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java index 370c5f22d87d0..8bedb677c905f 100644 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java @@ -354,6 +354,21 @@ public static class AnnotatedClass extends @TypeQualifier Thread implements @Typ Class value(); } + /** + * Annotation with an element of type {@link Class} whose default + * value is {@link Missing}. + */ + @Retention(RetentionPolicy.RUNTIME) + public @interface MissingElementType { + Class classValueOfMissingType() default Missing.class; + } + + /** + * Method with a directly missing annotation. + */ + @MissingElementType + public void missingElementTypeAnnotation() {} + /** * Method with a directly missing annotation. */ diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java index 43f4896d60005..d9a5069789a81 100644 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java @@ -42,6 +42,9 @@ import sun.reflect.annotation.TypeAnnotation; import sun.reflect.annotation.TypeNotPresentExceptionProxy; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; @@ -74,7 +77,13 @@ private void checkDecodedEqualsEncoded(AnnotatedElement annotated, boolean expec return; } - byte[] encoded = VMSupport.encodeAnnotations(List.of(annotations)); + ByteArrayOutputStream baos = new ByteArrayOutputStream(128); + try (DataOutputStream dos = new DataOutputStream(baos)) { + VMSupport.encodeAnnotations(dos, List.of(annotations)); + } catch (IOException e) { + throw new AssertionError(e); + } + byte[] encoded = baos.toByteArray(); MyDecoder decoder = new MyDecoder(); List decoded = VMSupport.decodeAnnotations(encoded, decoder); int i = 0; From 1e2b5dd937ff4e4aeca691bbff5d906a524f330b Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 26 Aug 2025 16:24:38 +0200 Subject: [PATCH 15/20] rename: eagerResolution -> allowEnumClinit --- .../reflect/annotation/AnnotationParser.java | 91 ++++++++++++------- .../reflect/annotation/AnnotationType.java | 10 +- .../sun/reflect/annotation/EnumValue.java | 5 +- .../reflect/annotation/EnumValueArray.java | 5 +- .../reflect/annotation/ResolvableValue.java | 5 +- .../annotation/TypeAnnotationParser.java | 17 +++- .../ci/meta/annotation/AnnotationValue.java | 8 ++ .../meta/annotation/ElementTypeMismatch.java | 2 +- 8 files changed, 95 insertions(+), 48 deletions(-) diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java index fbbeec988cb05..c24b84c5808f5 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java @@ -45,6 +45,11 @@ /** * Parser for Java programming language annotations. Translates * annotation byte streams emitted by compiler into annotation objects. + *

+ * Standard annotation parsing will trigger class initialization for + * enum classes when {@linkplain #parseEnumValue parsing enum member values}. + * This can be avoided by passing {@code false} for the + * {@code allowEnumClinit} parameter to the methods that define it. * * @author Josh Bloch * @since 1.5 @@ -59,6 +64,7 @@ public class AnnotationParser { * u2 num_annotations; * annotation annotations[num_annotations]; * + * @param allowEnumClinit described in {@link AnnotationParser} * @throws AnnotationFormatError if an annotation is found to be * malformed. */ @@ -66,12 +72,12 @@ public static Map, Annotation> parseAnnotations( byte[] rawAnnotations, ConstantPool constPool, Class container, - boolean eagerResolution) { + boolean allowEnumClinit) { if (rawAnnotations == null) return Collections.emptyMap(); try { - return parseAnnotations2(rawAnnotations, constPool, container, eagerResolution, null); + return parseAnnotations2(rawAnnotations, constPool, container, allowEnumClinit, null); } catch(BufferUnderflowException e) { throw new AnnotationFormatError("Unexpected end of annotations."); } catch(IllegalArgumentException e) { @@ -87,6 +93,7 @@ public static Map, Annotation> parseAnnotations( * This method is used to parse select meta annotations in the construction * phase of {@link AnnotationType} instances to prevent infinite recursion. * + * @param allowEnumClinit described in {@link AnnotationParser} * @param selectAnnotationClasses an array of annotation types to select when parsing */ @SafeVarargs @@ -95,13 +102,13 @@ public static Map, Annotation> parseSelectAnnotation byte[] rawAnnotations, ConstantPool constPool, Class container, - boolean eagerResolution, + boolean allowEnumClinit, Class ... selectAnnotationClasses) { if (rawAnnotations == null) return Collections.emptyMap(); try { - return parseAnnotations2(rawAnnotations, constPool, container, eagerResolution, selectAnnotationClasses); + return parseAnnotations2(rawAnnotations, constPool, container, allowEnumClinit, selectAnnotationClasses); } catch(BufferUnderflowException e) { throw new AnnotationFormatError("Unexpected end of annotations."); } catch(IllegalArgumentException e) { @@ -110,17 +117,20 @@ public static Map, Annotation> parseSelectAnnotation } } + /** + * @param allowEnumClinit described in {@link AnnotationParser} + */ private static Map, Annotation> parseAnnotations2( byte[] rawAnnotations, ConstantPool constPool, Class container, - boolean eagerResolution, + boolean allowEnumClinit, Class[] selectAnnotationClasses) { Map, Annotation> result = new LinkedHashMap<>(); ByteBuffer buf = ByteBuffer.wrap(rawAnnotations); int numAnnotations = buf.getShort() & 0xFFFF; for (int i = 0; i < numAnnotations; i++) { - Annotation a = parseAnnotation2(buf, constPool, container, eagerResolution, false, selectAnnotationClasses); + Annotation a = parseAnnotation2(buf, constPool, container, allowEnumClinit, false, selectAnnotationClasses); if (a != null) { Class klass = a.annotationType(); if (AnnotationType.getInstance(klass).retention() == RetentionPolicy.RUNTIME && @@ -174,15 +184,17 @@ public static Annotation[][] parseParameterAnnotations( /** * Parses the annotation member value in {@code annotationDefault} which is * the default value for the annotation member represented by {@code method}. + * + * @param allowEnumClinit described in {@link AnnotationParser} */ - public static Object parseAnnotationDefault(Method method, byte[] annotationDefault, boolean eagerResolution) { + public static Object parseAnnotationDefault(Method method, byte[] annotationDefault, boolean allowEnumClinit) { Class memberType = AnnotationType.invocationHandlerReturnType(method.getReturnType()); Object result = parseMemberValue( memberType, ByteBuffer.wrap(annotationDefault), SharedSecrets.getJavaLangAccess(). getConstantPool(method.getDeclaringClass()), method.getDeclaringClass(), - eagerResolution); + allowEnumClinit); if (result instanceof ExceptionProxy) { if (result instanceof TypeNotPresentExceptionProxy proxy) { throw new TypeNotPresentException(proxy.typeName(), proxy.getCause()); @@ -192,11 +204,14 @@ public static Object parseAnnotationDefault(Method method, byte[] annotationDefa return result; } + /** + * @param allowEnumClinit described in {@link AnnotationParser} + */ private static Annotation[][] parseParameterAnnotations2( byte[] rawAnnotations, ConstantPool constPool, Class container, - boolean eagerResolution) { + boolean allowEnumClinit) { ByteBuffer buf = ByteBuffer.wrap(rawAnnotations); int numParameters = buf.get() & 0xFF; Annotation[][] result = new Annotation[numParameters][]; @@ -206,7 +221,7 @@ private static Annotation[][] parseParameterAnnotations2( List annotations = new ArrayList(numAnnotations); for (int j = 0; j < numAnnotations; j++) { - Annotation a = parseAnnotation(buf, constPool, container, eagerResolution, false); + Annotation a = parseAnnotation(buf, constPool, container, allowEnumClinit, false); if (a != null) { AnnotationType type = AnnotationType.getInstance( a.annotationType()); @@ -240,6 +255,7 @@ private static Annotation[][] parseParameterAnnotations2( * Returns the annotation, or null if the annotation's type cannot * be found by the VM, or is not a valid annotation type. * + * @param allowEnumClinit described in {@link AnnotationParser} * @param exceptionOnMissingAnnotationClass if true, throw * TypeNotPresentException if a referenced annotation type is not * available at runtime @@ -247,16 +263,19 @@ private static Annotation[][] parseParameterAnnotations2( static Annotation parseAnnotation(ByteBuffer buf, ConstantPool constPool, Class container, - boolean eagerResolution, + boolean allowEnumClinit, boolean exceptionOnMissingAnnotationClass) { - return parseAnnotation2(buf, constPool, container, eagerResolution, exceptionOnMissingAnnotationClass, null); + return parseAnnotation2(buf, constPool, container, allowEnumClinit, exceptionOnMissingAnnotationClass, null); } + /** + * @param allowEnumClinit described in {@link AnnotationParser} + */ @SuppressWarnings("unchecked") private static Annotation parseAnnotation2(ByteBuffer buf, ConstantPool constPool, Class container, - boolean eagerResolution, + boolean allowEnumClinit, boolean exceptionOnMissingAnnotationClass, Class[] selectAnnotationClasses) { int typeIndex = buf.getShort() & 0xFFFF; @@ -295,7 +314,7 @@ private static Annotation parseAnnotation2(ByteBuffer buf, Map memberValues = new LinkedHashMap<>(); for (var e : type.memberDefaults().entrySet()) { Object value = e.getValue(); - memberValues.put(e.getKey(), eagerResolution ? ResolvableValue.resolved(value) : value); + memberValues.put(e.getKey(), allowEnumClinit ? ResolvableValue.resolved(value) : value); } int numMembers = buf.getShort() & 0xFFFF; @@ -308,7 +327,7 @@ private static Annotation parseAnnotation2(ByteBuffer buf, // Member is no longer present in annotation type; ignore it skipMemberValue(buf); } else { - Object value = parseMemberValue(memberType, buf, constPool, container, eagerResolution); + Object value = parseMemberValue(memberType, buf, constPool, container, allowEnumClinit); if (value instanceof AnnotationTypeMismatchExceptionProxy exceptProxy) exceptProxy.setMember(type.members().get(memberName)); memberValues.put(memberName, value); @@ -355,13 +374,15 @@ public static Annotation annotationForMap(final Class type * * The member must be of the indicated type. If it is not, this * method returns an AnnotationTypeMismatchExceptionProxy. + * + * @param allowEnumClinit described in {@link AnnotationParser} */ @SuppressWarnings({"unchecked", "rawtypes"}) public static Object parseMemberValue(Class memberType, ByteBuffer buf, ConstantPool constPool, Class container, - boolean eagerResolution) { + boolean allowEnumClinit) { // Note that VMSupport.encodeAnnotation (used by JVMCI) may need to // be updated if new annotation member types are added. Object result = null; @@ -369,15 +390,15 @@ public static Object parseMemberValue(Class memberType, switch(tag) { case 'e': Class enumType = (Class>) memberType; - return parseEnumValue(enumType, buf, constPool, container, eagerResolution); + return parseEnumValue(enumType, buf, constPool, container, allowEnumClinit); case 'c': result = parseClassValue(buf, constPool, container); break; case '@': - result = parseAnnotation(buf, constPool, container, eagerResolution, true); + result = parseAnnotation(buf, constPool, container, allowEnumClinit, true); break; case '[': - return parseArray(memberType, buf, constPool, container, eagerResolution); + return parseArray(memberType, buf, constPool, container, allowEnumClinit); default: result = parseConst(tag, buf, constPool); } @@ -488,14 +509,14 @@ static Class toClass(Type o) { * u2 const_name_index; * } enum_const_value; * - * @param resolve if false, the name of the enum constant is returned + * @param allowEnumClinit if false, an {@link EnumValue} is returned * instead of a resolved enum constant */ @SuppressWarnings({"rawtypes", "unchecked"}) - private static Object parseEnumValue(Class enumType, ByteBuffer buf, + static Object parseEnumValue(Class enumType, ByteBuffer buf, ConstantPool constPool, Class container, - boolean resolve) { + boolean allowEnumClinit) { int typeNameIndex = buf.getShort() & 0xFFFF; String typeName = constPool.getUTF8At(typeNameIndex); int constNameIndex = buf.getShort() & 0xFFFF; @@ -504,7 +525,7 @@ private static Object parseEnumValue(Class enumType, ByteBuffer return new AnnotationTypeMismatchExceptionProxy( typeName.substring(1, typeName.length() - 1).replace('/', '.') + "." + constName); } - if (!resolve) { + if (!allowEnumClinit) { return new EnumValue(enumType, constName); } try { @@ -528,13 +549,15 @@ private static Object parseEnumValue(Class enumType, ByteBuffer * * If the array values do not match arrayType, an * AnnotationTypeMismatchExceptionProxy will be returned. + * + * @param allowEnumClinit described in {@link AnnotationParser} */ @SuppressWarnings("unchecked") private static Object parseArray(Class arrayType, ByteBuffer buf, ConstantPool constPool, Class container, - boolean eagerResolution) { + boolean allowEnumClinit) { int length = buf.getShort() & 0xFFFF; // Number of array components if (!arrayType.isArray()) { return parseUnknownArray(length, buf); @@ -563,10 +586,10 @@ private static Object parseArray(Class arrayType, return parseClassArray(length, buf, constPool, container); } else if (componentType.isEnum()) { return parseEnumArray(length, (Class>)componentType, buf, - constPool, container, eagerResolution); + constPool, container, allowEnumClinit); } else if (componentType.isAnnotation()) { return parseAnnotationArray(length, (Class )componentType, buf, - constPool, container, eagerResolution); + constPool, container, allowEnumClinit); } else { return parseUnknownArray(length, buf); } @@ -751,12 +774,15 @@ private static Object parseClassArray(int length, buf, 'c', () -> parseClassValue(buf, constPool, container)); } - private static Object parseEnumArray(int length, Class> enumType, + /** + * @param allowEnumClinit described in {@link AnnotationParser} + */ + static Object parseEnumArray(int length, Class> enumType, ByteBuffer buf, ConstantPool constPool, Class container, - boolean resolve) { - if (resolve) { + boolean allowEnumClinit) { + if (allowEnumClinit) { return parseArrayElements((Object[]) Array.newInstance(enumType, length), buf, 'e', () -> parseEnumValue(enumType, buf, constPool, container, true)); } @@ -766,14 +792,17 @@ private static Object parseEnumArray(int length, Class> enumTy return new EnumValueArray(enumType, Collections.unmodifiableList(Arrays.asList(constNames))); } + /** + * @param allowEnumClinit described in {@link AnnotationParser} + */ private static Object parseAnnotationArray(int length, Class annotationType, ByteBuffer buf, ConstantPool constPool, Class container, - boolean eagerResolution) { + boolean allowEnumClinit) { return parseArrayElements((Object[]) Array.newInstance(annotationType, length), - buf, '@', () -> parseAnnotation(buf, constPool, container, eagerResolution, true)); + buf, '@', () -> parseAnnotation(buf, constPool, container, allowEnumClinit, true)); } private static Object parseArrayElements(Object[] result, diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java index 2de70f4cb81cd..7b1fbba0e7c38 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationType.java @@ -125,12 +125,12 @@ private AnnotationType(final Class annotationClass) { byte[] annotationDefault = SharedSecrets.getJavaLangReflectAccess().getAnnotationDefaultBytes(method); if (annotationDefault != null) { - // Pass eagerResolution==false to support the - // context where eager resolution is not desired. - // All uses of defaultValue will use + // Pass allowEnumClinit == false to avoid + // enum class initialization. + // All accesses of defaultValue use // sun.reflect.annotation.ResolvableValue.resolved - // to ensure only resolved values are seen by - // users of the standard annotation API. + // to ensure enum constants values are seen via + // the standard annotation API. Object defaultValue = AnnotationParser.parseAnnotationDefault(method, annotationDefault, false); if (defaultValue != null) { memberDefaults.put(name, defaultValue); diff --git a/src/java.base/share/classes/sun/reflect/annotation/EnumValue.java b/src/java.base/share/classes/sun/reflect/annotation/EnumValue.java index 96e1a6b3715cf..193ff81965cc4 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/EnumValue.java +++ b/src/java.base/share/classes/sun/reflect/annotation/EnumValue.java @@ -29,6 +29,9 @@ * An instance of this class is stored in an AnnotationInvocationHandler's * "memberValues" map to defer reification of an enum constant until the * dynamic proxy is queried for the enum member. + *

+ * Instances of this object are created when the {@code allowEnumClinit} + * argument to {@link AnnotationParser#parseEnumValue} is {@code false}. */ public final class EnumValue implements java.io.Serializable, ResolvableValue { @@ -44,7 +47,7 @@ public final class EnumValue implements java.io.Serializable, ResolvableValue { public final String constName; /** - * The lazily retrived value of the enum constant. + * The lazily resolved value of the enum constant. */ transient Object constValue; diff --git a/src/java.base/share/classes/sun/reflect/annotation/EnumValueArray.java b/src/java.base/share/classes/sun/reflect/annotation/EnumValueArray.java index 3923aeccd2e4b..fa609a7f20cf9 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/EnumValueArray.java +++ b/src/java.base/share/classes/sun/reflect/annotation/EnumValueArray.java @@ -27,14 +27,15 @@ import java.io.Serializable; import java.lang.reflect.Array; -import java.util.Arrays; import java.util.List; -import java.util.Objects; /** * An instance of this class is stored in an AnnotationInvocationHandler's * "memberValues" map to defer reification of an enum constant until the * dynamic proxy is queried for the enum member. + *

+ * Instances of this object are created when the {@code allowEnumClinit} + * argument to {@link AnnotationParser#parseEnumArray} is {@code false}. */ public final class EnumValueArray implements java.io.Serializable, ResolvableValue { diff --git a/src/java.base/share/classes/sun/reflect/annotation/ResolvableValue.java b/src/java.base/share/classes/sun/reflect/annotation/ResolvableValue.java index 331a01ea7c7f9..148b5a3f2a8b9 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/ResolvableValue.java +++ b/src/java.base/share/classes/sun/reflect/annotation/ResolvableValue.java @@ -28,9 +28,8 @@ /** * Denotes a parsed annotation element value that is not fully resolved to the * value returned by the annotation interface method for the element. - * This is used for example to defer resolving enum constants which is important - * in contexts where class initialization of the enum types should not be - * triggered by annotation parsing. + * This is used, for example, to avoid enum class initialization when + * parsing enum annotation elements. */ public interface ResolvableValue { diff --git a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java index 0248e4fa7cf30..84ce3fa2d1127 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java +++ b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotationParser.java @@ -345,11 +345,15 @@ static TypeAnnotation[] parseAllTypeAnnotations(AnnotatedElement decl) { decl, false, container); } - /* Parse type annotations encoded as an array of bytes */ + /** + * Parses types annotations encoded as an array of bytes. + * + * @param allowEnumClinit described in {@link AnnotationParser} + */ public static TypeAnnotation[] parseTypeAnnotations(byte[] rawAnnotations, ConstantPool cp, AnnotatedElement baseDecl, - boolean eagerResolution, + boolean allowEnumClinit, Class container) { if (rawAnnotations == null) return EMPTY_TYPE_ANNOTATION_ARRAY; @@ -360,7 +364,7 @@ public static TypeAnnotation[] parseTypeAnnotations(byte[] rawAnnotations, // Parse each TypeAnnotation for (int i = 0; i < annotationCount; i++) { - TypeAnnotation ta = parseTypeAnnotation(buf, cp, baseDecl, eagerResolution, container); + TypeAnnotation ta = parseTypeAnnotation(buf, cp, baseDecl, allowEnumClinit, container); if (ta != null) typeAnnotations.add(ta); } @@ -414,15 +418,18 @@ static Map, Annotation> mapTypeAnnotations(TypeAnnot private static final byte CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = (byte)0x4A; private static final byte METHOD_REFERENCE_TYPE_ARGUMENT = (byte)0x4B; + /** + * @param allowEnumClinit described in {@link AnnotationParser} + */ public static TypeAnnotation parseTypeAnnotation(ByteBuffer buf, ConstantPool cp, AnnotatedElement baseDecl, - boolean eagerResolution, + boolean allowEnumClinit, Class container) { try { TypeAnnotationTargetInfo ti = parseTargetInfo(buf); LocationInfo locationInfo = LocationInfo.parseLocationInfo(buf); - Annotation a = AnnotationParser.parseAnnotation(buf, cp, container, eagerResolution, false); + Annotation a = AnnotationParser.parseAnnotation(buf, cp, container, allowEnumClinit, false); if (ti == null) // Inside a method for example return null; return new TypeAnnotation(ti, locationInfo, a, baseDecl); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValue.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValue.java index ac35b894176e4..5e85b434f63df 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValue.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValue.java @@ -157,6 +157,14 @@ public V get(String name, Class elementType) { return elementType.cast(val); } + /** + * Gets an unmodifiable view of the elements in this annotation value. + * The type for each value in the returned map is specified by {@link #get(String, Class)}. + */ + public Map getElements() { + return elements; + } + @Override public String toString() { return "@" + type.toClassName() + "(" + elements + ")"; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ElementTypeMismatch.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ElementTypeMismatch.java index 99db829463b8a..79cb53a912109 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ElementTypeMismatch.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/ElementTypeMismatch.java @@ -30,7 +30,7 @@ *

* Similar to {@code AnnotationTypeMismatchExceptionProxy}. */ -public final class ElementTypeMismatch { +public final class ElementTypeMismatch extends ErrorElement { private final String foundType; /** From 7aaea3436c1fded9c57d908060549da6fae313bc Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 28 Aug 2025 12:13:22 +0200 Subject: [PATCH 16/20] added ResolvedJavaRecordComponent --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 73 ++++++-- src/hotspot/share/jvmci/jvmciEnv.cpp | 25 +++ src/hotspot/share/jvmci/jvmciEnv.hpp | 1 + src/hotspot/share/jvmci/jvmciJavaClasses.hpp | 5 + src/hotspot/share/jvmci/jvmciRuntime.cpp | 24 +-- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + src/hotspot/share/jvmci/vmSymbols_jvmci.hpp | 3 + .../jdk/vm/ci/hotspot/CompilerToVM.java | 22 ++- .../vm/ci/hotspot/HotSpotJVMCIRuntime.java | 8 + .../ci/hotspot/HotSpotMetaAccessProvider.java | 2 - .../hotspot/HotSpotResolvedJavaFieldImpl.java | 11 +- .../HotSpotResolvedJavaRecordComponent.java | 110 +++++++++++ .../HotSpotResolvedObjectTypeImpl.java | 23 ++- .../hotspot/HotSpotResolvedPrimitiveType.java | 11 ++ .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 30 +-- .../classes/jdk/vm/ci/meta/JavaKind.java | 2 - .../jdk/vm/ci/meta/MetaAccessProvider.java | 19 ++ .../jdk/vm/ci/meta/ResolvedJavaField.java | 3 +- .../jdk/vm/ci/meta/ResolvedJavaMethod.java | 1 + .../ci/meta/ResolvedJavaRecordComponent.java | 76 ++++++++ .../jdk/vm/ci/meta/ResolvedJavaType.java | 13 ++ .../jdk/vm/ci/runtime/test/FieldUniverse.java | 11 +- .../vm/ci/runtime/test/MethodUniverse.java | 2 +- .../test/TestResolvedJavaRecordComponent.java | 171 ++++++++++++++++++ .../ci/runtime/test/TestResolvedJavaType.java | 44 ++++- .../jdk/vm/ci/runtime/test/TypeUniverse.java | 20 ++ .../AnnotationTestInput.java | 4 +- 27 files changed, 642 insertions(+), 73 deletions(-) create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaRecordComponent.java create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaRecordComponent.java create mode 100644 test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index ee4c0eeae629e..563aee040423a 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -50,6 +50,7 @@ #include "oops/instanceMirrorKlass.hpp" #include "oops/method.inline.hpp" #include "oops/objArrayKlass.inline.hpp" +#include "oops/recordComponent.hpp" #include "oops/trainingData.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" @@ -401,7 +402,7 @@ C2V_VMENTRY_NULL(jobject, asResolvedJavaMethod, (JNIEnv* env, jobject, jobject e methodHandle method (THREAD, InstanceKlass::cast(holder)->method_with_idnum(slot)); JVMCIObject result = JVMCIENV->get_jvmci_method(method, JVMCI_CHECK_NULL); return JVMCIENV->get_jobject(result); -} +C2V_END C2V_VMENTRY_PREFIX(jboolean, updateCompilerThreadCanCallJava, (JNIEnv* env, jobject, jboolean newState)) return CompilerThreadCanCallJava::update(thread, newState) != nullptr; @@ -2246,6 +2247,28 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, ARGUME return JVMCIENV->get_jobjectArray(methods); C2V_END +C2V_VMENTRY_NULL(jobjectArray, getRecordComponents, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) + Klass* klass = UNPACK_PAIR(Klass, klass); + if (klass == nullptr) { + JVMCI_THROW_NULL(NullPointerException); + } + if (!klass->is_instance_klass()) { + return nullptr; + } + + InstanceKlass* iklass = InstanceKlass::cast(klass); + Array* components = iklass->record_components(); + if (components == nullptr) { + return nullptr; + } + JVMCIObjectArray res = JVMCIENV->new_ResolvedJavaRecordComponent_array(components->length(), JVMCI_CHECK_NULL); + for (int i = 0; i < components->length(); i++) { + JVMCIObject component = JVMCIENV->new_HotSpotResolvedJavaRecordComponent(JVMCIENV->wrap(klass_obj), i, components->at(i), JVMCI_CHECK_NULL); + JVMCIENV->put_object_at(res, i, component); + } + return JVMCIENV->get_jobjectArray(res); +C2V_END + C2V_VMENTRY_NULL(jobjectArray, getAllMethods, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { @@ -3107,18 +3130,35 @@ C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationValues, (JNIEnv* env, return get_encoded_annotation_values(method->method_holder(), raw_annotations, category, memberType, THREAD, JVMCIENV); C2V_END -C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, jint category)) +C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationValues, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, jboolean is_field, jint category)) CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support InstanceKlass* holder = check_field(InstanceKlass::cast(UNPACK_PAIR(Klass, klass)), index, JVMCI_CHECK_NULL); - fieldDescriptor fd(holder, index); - AnnotationArray* raw_annotations; - if (category == CompilerToVM::DECLARED_ANNOTATIONS) { - raw_annotations = fd.annotations(); - } else if (category == CompilerToVM::TYPE_ANNOTATIONS) { - raw_annotations = fd.type_annotations(); + AnnotationArray* raw_annotations = nullptr; + if (is_field) { + fieldDescriptor fd(holder, index); + if (category == CompilerToVM::DECLARED_ANNOTATIONS) { + raw_annotations = fd.annotations(); + } else if (category == CompilerToVM::TYPE_ANNOTATIONS) { + raw_annotations = fd.type_annotations(); + } else { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%d", category)); + } } else { - THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("%d", category)); + Array* components = holder->record_components(); + if (components == nullptr) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%s has no record components", holder->name()->as_C_string())); + } + RecordComponent* rc = components->at(index); + if (category == CompilerToVM::DECLARED_ANNOTATIONS) { + raw_annotations = rc->annotations(); + } else if (category == CompilerToVM::TYPE_ANNOTATIONS) { + raw_annotations = rc->type_annotations(); + } else { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%d", category)); + } } return get_encoded_annotation_values(holder, raw_annotations, category, nullptr, THREAD, JVMCIENV); C2V_END @@ -3324,13 +3364,13 @@ C2V_END #define OBJECT "Ljava/lang/Object;" #define CLASS "Ljava/lang/Class;" #define OBJECTCONSTANT "Ljdk/vm/ci/hotspot/HotSpotObjectConstantImpl;" -#define EXECUTABLE "Ljava/lang/reflect/Executable;" #define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;" #define INSTALLED_CODE "Ljdk/vm/ci/code/InstalledCode;" #define BYTECODE_FRAME "Ljdk/vm/ci/code/BytecodeFrame;" #define JAVACONSTANT "Ljdk/vm/ci/meta/JavaConstant;" #define INSPECTED_FRAME_VISITOR "Ljdk/vm/ci/code/stack/InspectedFrameVisitor;" #define RESOLVED_METHOD "Ljdk/vm/ci/meta/ResolvedJavaMethod;" +#define RESOLVED_RECORD_COMPONENT "Ljdk/vm/ci/meta/ResolvedJavaRecordComponent;" #define FIELDINFO "Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl$FieldInfo;" #define HS_RESOLVED_TYPE "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaType;" #define HS_INSTALLED_CODE "Ljdk/vm/ci/hotspot/HotSpotInstalledCode;" @@ -3339,8 +3379,8 @@ C2V_END #define HS_CONFIG "Ljdk/vm/ci/hotspot/HotSpotVMConfig;" #define HS_STACK_FRAME_REF "Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;" #define HS_SPECULATION_LOG "Ljdk/vm/ci/hotspot/HotSpotSpeculationLog;" -#define REFLECTION_EXECUTABLE "Ljava/lang/reflect/Executable;" -#define REFLECTION_FIELD "Ljava/lang/reflect/Field;" +#define EXECUTABLE "Ljava/lang/reflect/Executable;" +#define FIELD "Ljava/lang/reflect/Field;" // Types wrapping VM pointers. The ...2 macro is for a pair: (wrapper, pointer) #define HS_METHOD "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;" @@ -3436,6 +3476,7 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)}, {CC "getDeclaredConstructors", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)}, {CC "getDeclaredMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)}, + {CC "getRecordComponents", CC "(" HS_KLASS2 ")[" RESOLVED_RECORD_COMPONENT, FN_PTR(getRecordComponents)}, {CC "getAllMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getAllMethods)}, {CC "getDeclaredFieldsInfo", CC "(" HS_KLASS2 ")[" FIELDINFO, FN_PTR(getDeclaredFieldsInfo)}, {CC "readStaticFieldValue", CC "(" HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readStaticFieldValue)}, @@ -3462,11 +3503,11 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "unhand", CC "(J)" OBJECT, FN_PTR(unhand)}, {CC "updateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(updateHotSpotNmethod)}, {CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)}, - {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" REFLECTION_EXECUTABLE, FN_PTR(asReflectionExecutable)}, - {CC "asReflectionField", CC "(" HS_KLASS2 "I)" REFLECTION_FIELD, FN_PTR(asReflectionField)}, + {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" EXECUTABLE, FN_PTR(asReflectionExecutable)}, + {CC "asReflectionField", CC "(" HS_KLASS2 "I)" FIELD, FN_PTR(asReflectionField)}, {CC "getEncodedClassAnnotationValues", CC "(" HS_KLASS2 "I)[B", FN_PTR(getEncodedClassAnnotationValues)}, {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 HS_KLASS2 "I)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, - {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "II)[B", FN_PTR(getEncodedFieldAnnotationValues)}, + {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "IZI)[B", FN_PTR(getEncodedFieldAnnotationValues)}, {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, {CC "getFailedSpeculationsAddress", CC "(" HS_METHOD2 ")J", FN_PTR(getFailedSpeculationsAddress)}, {CC "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)}, diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 23473940178c6..b66940fe035d1 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -38,6 +38,7 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/objArrayKlass.hpp" +#include "oops/recordComponent.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" @@ -1608,6 +1609,30 @@ JVMCIObject JVMCIEnv::new_FieldInfo(FieldInfo* fieldinfo, JVMCI_TRAPS) { } } +JVMCIObject JVMCIEnv::new_HotSpotResolvedJavaRecordComponent(JVMCIObject declaringRecord, int index, RecordComponent* rc, JVMCI_TRAPS) { + JavaThread* THREAD = JavaThread::current(); + if (is_hotspot()) { + JavaCallArguments args; + args.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(declaringRecord))); + args.push_int(index); + args.push_int(rc->name_index()); + args.push_int(rc->descriptor_index()); + Handle obj_h = JavaCalls::construct_new_instance(HotSpotJVMCI::HotSpotResolvedJavaRecordComponent::klass(), + vmSymbols::HotSpotResolvedJavaRecordComponent_constructor_signature(), + &args, + THREAD); + return wrap(obj_h()); + } else { + JNIAccessMark jni(this, THREAD); + jobject result = jni()->NewObject(JNIJVMCI::HotSpotResolvedJavaRecordComponent::clazz(), + JNIJVMCI::HotSpotResolvedJavaRecordComponent::constructor(), + (jint)rc->name_index(), + (jint)rc->descriptor_index()); + + return wrap(result); + } +} + JVMCIObject JVMCIEnv::get_object_constant(oop objOop, bool compressed, bool dont_register) { JavaThread* THREAD = JavaThread::current(); // For exception macros. Handle obj = Handle(THREAD, objOop); diff --git a/src/hotspot/share/jvmci/jvmciEnv.hpp b/src/hotspot/share/jvmci/jvmciEnv.hpp index fbe5be88c3fc7..559a7187ab493 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.hpp +++ b/src/hotspot/share/jvmci/jvmciEnv.hpp @@ -433,6 +433,7 @@ class JVMCIEnv : public ResourceObj { JVMCIObject new_HotSpotStackFrameReference(JVMCI_TRAPS); JVMCIObject new_JVMCIError(JVMCI_TRAPS); JVMCIObject new_FieldInfo(FieldInfo* fieldinfo, JVMCI_TRAPS); + JVMCIObject new_HotSpotResolvedJavaRecordComponent(JVMCIObject declaringRecord, int index, RecordComponent* rc, JVMCI_TRAPS); // Makes a handle to a HotSpot heap object. These handles are // individually reclaimed by JVMCIRuntime::destroy_oop_handle and diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp index 9abf3b4241a08..358a4717a9e69 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp @@ -84,6 +84,9 @@ start_class(HotSpotResolvedJavaMethodImpl, jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl) \ long_field(HotSpotResolvedJavaMethodImpl, methodHandle) \ end_class \ + start_class(HotSpotResolvedJavaRecordComponent, jdk_vm_ci_hotspot_HotSpotResolvedJavaRecordComponent) \ + jvmci_constructor(HotSpotResolvedJavaRecordComponent, "(Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;III)V") \ + end_class \ start_class(HotSpotMethodData, jdk_vm_ci_hotspot_HotSpotMethodData) \ long_field(HotSpotMethodData, methodDataPointer) \ end_class \ @@ -166,6 +169,8 @@ end_class \ start_class(ResolvedJavaMethod, jdk_vm_ci_meta_ResolvedJavaMethod) \ end_class \ + start_class(ResolvedJavaRecordComponent, jdk_vm_ci_meta_ResolvedJavaRecordComponent) \ + end_class \ start_class(PrimitiveConstant, jdk_vm_ci_meta_PrimitiveConstant) \ object_field(PrimitiveConstant, kind, "Ljdk/vm/ci/meta/JavaKind;") \ long_field(PrimitiveConstant, primitive) \ diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index a8b89d149f75f..6a1c09bb89a56 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -1394,6 +1394,13 @@ class JavaVMRefsInitialization: public StackObj { } }; +#ifdef ASSERT +static void assert_equals(const char* desc, int expect, int actual) { + assert(expect == actual, "%s: %d != %d", desc, expect, actual); + +} +#endif + void JVMCIRuntime::initialize(JVMCI_TRAPS) { // Check first without _lock if (_init_state == fully_initialized) { @@ -1464,6 +1471,11 @@ void JVMCIRuntime::initialize(JVMCI_TRAPS) { create_jvmci_primitive_type(T_VOID, JVMCI_CHECK_EXIT_((void)0)); DEBUG_ONLY(CodeInstaller::verify_bci_constants(JVMCIENV);) + + DEBUG_ONLY(assert_equals("DECLARED_ANNOTATIONS", CompilerToVM::DECLARED_ANNOTATIONS, JVMCIENV->get_VMSupport_DECLARED_ANNOTATIONS())); + DEBUG_ONLY(assert_equals("PARAMETER_ANNOTATIONS", CompilerToVM::PARAMETER_ANNOTATIONS, JVMCIENV->get_VMSupport_PARAMETER_ANNOTATIONS())); + DEBUG_ONLY(assert_equals("TYPE_ANNOTATIONS", CompilerToVM::TYPE_ANNOTATIONS, JVMCIENV->get_VMSupport_TYPE_ANNOTATIONS())); + DEBUG_ONLY(assert_equals("ANNOTATION_MEMBER_VALUE", CompilerToVM::ANNOTATION_MEMBER_VALUE, JVMCIENV->get_VMSupport_ANNOTATION_MEMBER_VALUE())); } _init_state = fully_initialized; @@ -1510,23 +1522,11 @@ JVMCIObject JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_TRAPS) { return _HotSpotJVMCIRuntime_instance; } -#ifdef ASSERT -static void assert_equals(const char* desc, int expect, int actual) { - assert(expect == actual, "%s: %d != %d", desc, expect, actual); - -} -#endif - // Implementation of CompilerToVM.registerNatives() // When called from libjvmci, `libjvmciOrHotspotEnv` is a libjvmci env so use JVM_ENTRY_NO_ENV. JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *libjvmciOrHotspotEnv, jclass c2vmClass)) JVMCIENV_FROM_JNI(thread, libjvmciOrHotspotEnv); - DEBUG_ONLY(assert_equals("DECLARED_ANNOTATIONS", CompilerToVM::DECLARED_ANNOTATIONS, JVMCIENV->get_VMSupport_DECLARED_ANNOTATIONS())); - DEBUG_ONLY(assert_equals("PARAMETER_ANNOTATIONS", CompilerToVM::PARAMETER_ANNOTATIONS, JVMCIENV->get_VMSupport_PARAMETER_ANNOTATIONS())); - DEBUG_ONLY(assert_equals("TYPE_ANNOTATIONS", CompilerToVM::TYPE_ANNOTATIONS, JVMCIENV->get_VMSupport_TYPE_ANNOTATIONS())); - DEBUG_ONLY(assert_equals("ANNOTATION_MEMBER_VALUE", CompilerToVM::ANNOTATION_MEMBER_VALUE, JVMCIENV->get_VMSupport_ANNOTATION_MEMBER_VALUE())); - if (!EnableJVMCI) { JVMCI_THROW_MSG(InternalError, JVMCI_NOT_ENABLED_ERROR_MESSAGE); } diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 78c8f00cc2076..1b12f49567a65 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -223,6 +223,7 @@ volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \ nonstatic_field(InstanceKlass, _misc_flags._flags, u2) \ nonstatic_field(InstanceKlass, _annotations, Annotations*) \ + nonstatic_field(InstanceKlass, _record_components, Array*) \ \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_sp, intptr_t*) \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_pc, address) \ diff --git a/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp b/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp index de965da0f8093..3c2c22f40b071 100644 --- a/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp +++ b/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp @@ -37,6 +37,7 @@ template(jdk_vm_ci_hotspot_HotSpotInstalledCode, "jdk/vm/ci/hotspot/HotSpotInstalledCode") \ template(jdk_vm_ci_hotspot_HotSpotNmethod, "jdk/vm/ci/hotspot/HotSpotNmethod") \ template(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl, "jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl") \ + template(jdk_vm_ci_hotspot_HotSpotResolvedJavaRecordComponent, "jdk/vm/ci/hotspot/HotSpotResolvedJavaRecordComponent") \ template(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl, "jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl") \ template(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl_FieldInfo, "jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl$FieldInfo") \ template(jdk_vm_ci_hotspot_HotSpotResolvedPrimitiveType, "jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType") \ @@ -55,6 +56,7 @@ template(jdk_vm_ci_hotspot_VMFlag, "jdk/vm/ci/hotspot/VMFlag") \ template(jdk_vm_ci_hotspot_VMIntrinsicMethod, "jdk/vm/ci/hotspot/VMIntrinsicMethod") \ template(jdk_vm_ci_meta_ResolvedJavaMethod, "jdk/vm/ci/meta/ResolvedJavaMethod") \ + template(jdk_vm_ci_meta_ResolvedJavaRecordComponent, "jdk/vm/ci/meta/ResolvedJavaRecordComponent") \ template(jdk_vm_ci_meta_JavaConstant, "jdk/vm/ci/meta/JavaConstant") \ template(jdk_vm_ci_meta_PrimitiveConstant, "jdk/vm/ci/meta/PrimitiveConstant") \ template(jdk_vm_ci_meta_RawConstant, "jdk/vm/ci/meta/RawConstant") \ @@ -97,6 +99,7 @@ template(getCompiler_signature, "()Ljdk/vm/ci/runtime/JVMCICompiler;") \ template(exceptionToString_name, "exceptionToString") \ template(exceptionToString_signature, "(Ljava/lang/Throwable;ZZ)[Ljava/lang/String;") \ + template(HotSpotResolvedJavaRecordComponent_constructor_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;III)V") \ template(postTranslation_name, "postTranslation") \ template(getName_name, "getName") \ template(bootstrapFinished_name, "bootstrapFinished") \ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index c47461de4ac2f..2396dd525889e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -32,11 +32,13 @@ import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantPool.BootstrapMethodInvocation; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import jdk.vm.ci.meta.ResolvedJavaType; import java.lang.reflect.Executable; @@ -1170,6 +1172,15 @@ ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl klass) { native ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl klass, long klassPointer); + /** + * Gets the {@link ResolvedJavaRecordComponent}s for {@code klass}. + */ + ResolvedJavaRecordComponent[] getRecordComponents(HotSpotResolvedObjectTypeImpl klass) { + return getRecordComponents(klass, klass.getKlassPointer()); + } + + native ResolvedJavaRecordComponent[] getRecordComponents(HotSpotResolvedObjectTypeImpl klass, long klassPointer); + /** * Gets the {@link ResolvedJavaMethod}s for all methods of {@code klass}. */ @@ -1468,14 +1479,15 @@ native byte[] getEncodedExecutableAnnotationValues(HotSpotResolvedJavaMethodImpl HotSpotResolvedObjectTypeImpl memberType, long klassPointer, int category); /** - * Gets the serialized annotation info for the field denoted by {@code holder} and - * {@code fieldIndex} by calling {@code VMSupport.encodeAnnotations} in the HotSpot heap. + * Gets the serialized annotation info for the field ({@code isField == true}) or + * record component ({@code isField == false}) denoted by {@code holder} and + * {@code index} by calling {@code VMSupport.encodeAnnotations} in the HotSpot heap. */ - byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, int fieldIndex, int category) { - return getEncodedFieldAnnotationValues(holder, holder.getKlassPointer(), fieldIndex, category); + byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, int index, boolean isField, int category) { + return getEncodedFieldAnnotationValues(holder, holder.getKlassPointer(), index, isField, category); } - native byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, long klassPointer, int fieldIndex, int category); + native byte[] getEncodedFieldAnnotationValues(HotSpotResolvedObjectTypeImpl holder, long klassPointer, int index, boolean isField, int category); /** * @see HotSpotResolvedJavaMethod#getOopMapAt diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index c35f216e624a1..a4d1190d1617a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -95,6 +95,7 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime { private HotSpotResolvedObjectTypeImpl serializableType; private HotSpotResolvedObjectTypeImpl cloneableType; private HotSpotResolvedObjectTypeImpl enumType; + private HotSpotResolvedObjectTypeImpl recordType; HotSpotResolvedObjectTypeImpl getJavaLangObject() { if (javaLangObject == null) { @@ -103,6 +104,13 @@ HotSpotResolvedObjectTypeImpl getJavaLangObject() { return javaLangObject; } + HotSpotResolvedObjectTypeImpl getJavaLangRecord() { + if (recordType == null) { + recordType = (HotSpotResolvedObjectTypeImpl) fromClass(Record.class); + } + return recordType; + } + HotSpotResolvedObjectTypeImpl getJavaLangString() { if (javaLangString == null) { javaLangString = (HotSpotResolvedObjectTypeImpl) fromClass(String.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java index 0bc6fce0ce203..ed178f4c636ed 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java @@ -42,8 +42,6 @@ import jdk.vm.ci.meta.SpeculationLog.NoSpeculationReason; import jdk.vm.ci.meta.SpeculationLog.Speculation; -// JaCoCo Exclude - /** * HotSpot implementation of {@link MetaAccessProvider}. */ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index fc589ad236592..3ced5f8901ce2 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -38,7 +38,6 @@ import static jdk.internal.misc.Unsafe.ADDRESS_SIZE; import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkIsAnnotation; import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; @@ -85,8 +84,7 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (obj instanceof HotSpotResolvedJavaFieldImpl) { - HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; + if (obj instanceof HotSpotResolvedJavaFieldImpl that) { if (that.offset != this.offset || that.isStatic() != this.isStatic()) { return false; } else if (this.holder.equals(that.holder)) { @@ -141,9 +139,8 @@ public JavaType getType() { // Pull field into local variable to prevent a race causing // a ClassCastException below JavaType currentType = type; - if (currentType instanceof UnresolvedJavaType) { + if (currentType instanceof UnresolvedJavaType unresolvedType) { // Don't allow unresolved types to hang around forever - UnresolvedJavaType unresolvedType = (UnresolvedJavaType) currentType; JavaType resolved = HotSpotJVMCIRuntime.runtime().lookupType(unresolvedType.getName(), holder, false); if (resolved instanceof ResolvedJavaType) { type = resolved; @@ -239,13 +236,13 @@ public Map getDeclaredAnnotationValues() { if (!hasAnnotations()) { return Map.of(); } - byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, VMSupport.DECLARED_ANNOTATIONS); + byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, true, VMSupport.DECLARED_ANNOTATIONS); return new AnnotationValueDecoder(getDeclaringClass()).decode(encoded); } @Override public List getTypeAnnotationValues() { - byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, VMSupport.TYPE_ANNOTATIONS); + byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(holder, index, true, VMSupport.TYPE_ANNOTATIONS); return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringClass())); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaRecordComponent.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaRecordComponent.java new file mode 100644 index 0000000000000..a790eec33e4ec --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaRecordComponent.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025, 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 jdk.vm.ci.hotspot; + +import jdk.internal.vm.VMSupport; +import jdk.vm.ci.meta.JavaType; +import java.lang.reflect.RecordComponent; + +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.AnnotationValueDecoder; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; + +import java.util.List; +import java.util.Map; + +import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; + +/** + * Represents a {@linkplain RecordComponent component} in a HotSpot record. + */ +final class HotSpotResolvedJavaRecordComponent implements ResolvedJavaRecordComponent { + + private final HotSpotResolvedObjectTypeImpl declaringRecord; + private final String name; + private final JavaType type; + + /** + * Index in {@code InstanceKlass::_record_components}. + */ + private final int index; + + /** + * Called from the VM. + */ + @VMEntryPoint + private HotSpotResolvedJavaRecordComponent(HotSpotResolvedObjectTypeImpl declaringRecord, int index, int nameIndex, int typeIndex) { + this.declaringRecord = declaringRecord; + this.index = index; + HotSpotConstantPool cp = declaringRecord.getConstantPool(); + this.name = cp.lookupUtf8(nameIndex); + this.type = runtime().lookupType(cp.lookupUtf8(typeIndex), declaringRecord, false); + } + + @Override + public ResolvedJavaType getDeclaringRecord() { + return declaringRecord; + } + + @Override + public String getName() { + return name; + } + + @Override + public String toString() { + return getAccessor().format("HotSpotResolvedJavaRecordComponent<%H.%n %r>"); + } + + @Override + public JavaType getType() { + return type; + } + @Override + public boolean equals(Object obj) { + if (obj instanceof HotSpotResolvedJavaRecordComponent that) { + return that.index == this.index && that.declaringRecord.equals(this.declaringRecord); + } + return false; + } + + @Override + public int hashCode() { + return declaringRecord.hashCode() ^ index; + } + + @Override + public Map getDeclaredAnnotationValues() { + byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(declaringRecord, index, false, VMSupport.DECLARED_ANNOTATIONS); + return new AnnotationValueDecoder(getDeclaringRecord()).decode(encoded); + } + + @Override + public List getTypeAnnotationValues() { + byte[] encoded = compilerToVM().getEncodedFieldAnnotationValues(declaringRecord, index, false, VMSupport.TYPE_ANNOTATIONS); + return VMSupport.decodeTypeAnnotations(encoded, new AnnotationValueDecoder(getDeclaringRecord())); + } +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 79af586b8e994..539023690f46e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -35,6 +35,7 @@ import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.UnresolvedJavaField; import jdk.vm.ci.meta.UnresolvedJavaType; @@ -73,6 +74,7 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem */ private final long klassPointer; + private ResolvedJavaRecordComponent[] recordComponents; private HotSpotResolvedJavaMethodImpl[] methodCacheArray; private HashMap methodCacheHashMap; private volatile HotSpotResolvedJavaField[] instanceFields; @@ -827,6 +829,26 @@ public ResolvedJavaField[] getStaticFields() { } } + @Override + public boolean isRecord() { + HotSpotResolvedObjectTypeImpl superclass = getSuperclass(); + if (!isLeaf() || superclass == null || !superclass.equals(runtime().getJavaLangRecord())) { + return false; + } + return UNSAFE.getAddress(getKlassPointer() + config().instanceKlassRecordComponentsOffset) != 0; + } + + @Override + public ResolvedJavaRecordComponent[] getRecordComponents() { + if (!isRecord()) { + return null; + } + if (recordComponents == null) { + recordComponents = compilerToVM().getRecordComponents(this); + } + return recordComponents; + } + /** * Gets the instance or static fields of this class. * @@ -834,7 +856,6 @@ public ResolvedJavaField[] getStaticFields() { * @param prepend an array to be prepended to the returned result */ private HotSpotResolvedJavaField[] getFields(boolean retrieveStaticFields, HotSpotResolvedJavaField[] prepend) { - HotSpotVMConfig config = config(); int resultCount = 0; int index = 0; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index ef994f2a610e8..5295206054537 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -29,6 +29,7 @@ import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.annotation.AnnotationValue; import jdk.vm.ci.meta.annotation.TypeAnnotationValue; @@ -229,6 +230,16 @@ public ResolvedJavaField[] getStaticFields() { return new ResolvedJavaField[0]; } + @Override + public boolean isRecord() { + return false; + } + + @Override + public ResolvedJavaRecordComponent[] getRecordComponents() { + return null; + } + @Override public Annotation[] getAnnotations() { return new Annotation[0]; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 85b1a44565524..98530d9b18020 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -26,13 +26,14 @@ import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.services.Services; import jdk.internal.misc.Unsafe; import jdk.internal.util.Architecture; +import java.util.Objects; + /** * Used to access native configuration details. - * + *

* All non-static, public fields in this class are so that they can be compiled as constants. */ class HotSpotVMConfig extends HotSpotVMConfigAccess { @@ -57,14 +58,12 @@ static HotSpotVMConfig config() { */ static String getHostArchitectureName() { Architecture arch = Architecture.current(); - switch (arch) { - case X64: return "amd64"; - default: return arch.name().toLowerCase(); + if (Objects.requireNonNull(arch) == Architecture.X64) { + return "amd64"; } + return arch.name().toLowerCase(); } - final boolean useDeferredInitBarriers = getFlag("ReduceInitialCardMarks", Boolean.class); - final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); final boolean useClassMetaspaceForAllClasses = getFlag("UseClassMetaspaceForAllClasses", Boolean.class); @@ -97,8 +96,8 @@ static String getHostArchitectureName() { final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "InstanceKlass::ClassState"); final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*"); - final int instanceKlassFieldInfoStreamOffset = getFieldOffset("InstanceKlass::_fieldinfo_stream", Integer.class, "Array*"); final int instanceKlassAnnotationsOffset = getFieldOffset("InstanceKlass::_annotations", Integer.class, "Annotations*"); + final int instanceKlassRecordComponentsOffset = getFieldOffset("InstanceKlass::_record_components", Integer.class, "Array*"); final int instanceKlassMiscFlagsOffset = getFieldOffset("InstanceKlass::_misc_flags._flags", Integer.class, "u2"); final int klassMiscFlagsOffset = getFieldOffset("Klass::_misc_flags._flags", Integer.class, "u1"); final int klassVtableStartOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_start_offset", Integer.class, "int"); @@ -112,9 +111,7 @@ static String getHostArchitectureName() { final int annotationsClassAnnotationsOffset = getFieldOffset("Annotations::_class_annotations", Integer.class, "AnnotationArray*"); final int fieldsAnnotationsBaseOffset = getFieldValue("CompilerToVM::Data::_fields_annotations_base_offset", Integer.class, "int"); - final int arrayU1LengthOffset = getFieldOffset("Array::_length", Integer.class, "int"); final int arrayU1DataOffset = getFieldOffset("Array::_data", Integer.class); - final int arrayU2DataOffset = getFieldOffset("Array::_data", Integer.class); final int jvmAccHasFinalizer = getConstant("KlassFlags::_misc_has_finalizer", Integer.class); final int jvmFieldFlagInternalShift = getConstant("FieldInfo::FieldFlags::_ff_injected", Integer.class); @@ -155,7 +152,6 @@ long prototypeMarkWord() { final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, "nmethod*"); final int methodFlagsForceInline = getConstant("MethodFlags::_misc_force_inline", Integer.class); - final int methodFlagsDontInline = getConstant("MethodFlags::_misc_dont_inline", Integer.class); final int nonvirtualVtableIndex = getConstant("Method::nonvirtual_vtable_index", Integer.class); final int invalidVtableIndex = getConstant("Method::invalid_vtable_index", Integer.class); @@ -171,16 +167,6 @@ long prototypeMarkWord() { final int nmethodCompLevelOffset = getFieldOffset("nmethod::_comp_level", Integer.class, "CompLevel"); - final int compilationLevelNone = getConstant("CompLevel_none", Integer.class); - final int compilationLevelSimple = getConstant("CompLevel_simple", Integer.class); - final int compilationLevelLimitedProfile = getConstant("CompLevel_limited_profile", Integer.class); - final int compilationLevelFullProfile = getConstant("CompLevel_full_profile", Integer.class); - final int compilationLevelFullOptimization = getConstant("CompLevel_full_optimization", Integer.class); - - final int compLevelAdjustmentNone = getConstant("JVMCIRuntime::none", Integer.class); - final int compLevelAdjustmentByHolder = getConstant("JVMCIRuntime::by_holder", Integer.class); - final int compLevelAdjustmentByFullSignature = getConstant("JVMCIRuntime::by_full_signature", Integer.class); - final int invocationEntryBci = getConstant("InvocationEntryBci", Integer.class); final int extraStackEntries = getFieldValue("CompilerToVM::Data::Method_extra_stack_entries", Integer.class, "int"); @@ -282,8 +268,6 @@ final int baseVtableLength() { return universeBaseVtableSize / (vtableEntrySize / heapWordSize); } - final int klassOffset = getFieldValue("java_lang_Class::_klass_offset", Integer.class, "int"); - /** * The DataLayout header size is the same as the cell size. */ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java index baa7e295d328c..caafbd1f7daa8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java @@ -24,8 +24,6 @@ import java.lang.reflect.Array; -//JaCoCo Exclude - /** * Denotes the basic kinds of types in CRI, including the all the Java primitive types, for example, * {@link JavaKind#Int} for {@code int} and {@link JavaKind#Object} for all object types. A kind has diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java index 2686ab1737f28..17642b9de99c5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java @@ -26,7 +26,10 @@ import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.RecordComponent; +import java.util.Objects; +import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.SpeculationLog.Speculation; /** @@ -74,6 +77,22 @@ default ResolvedJavaType[] lookupJavaTypes(Class[] classes) { */ ResolvedJavaType lookupJavaType(JavaConstant constant); + /** + * Provides the {@link ResolvedJavaRecordComponent} for {@code recordComponent}. + */ + default ResolvedJavaRecordComponent lookupJavaRecordComponent(RecordComponent recordComponent){ + Class declaringRecord = recordComponent.getDeclaringRecord(); + ResolvedJavaType holder = Objects.requireNonNull(lookupJavaType(declaringRecord)); + ResolvedJavaRecordComponent[] recordComponents = holder.getRecordComponents(); + ResolvedJavaType fieldType = lookupJavaType(recordComponent.getType()); + for (ResolvedJavaRecordComponent rc : recordComponents) { + if (rc.getName().equals(recordComponent.getName()) && rc.getType().equals(fieldType)) { + return rc; + } + } + throw new JVMCIError("unresolved RecordComponent %s", recordComponent); + } + /** * Returns the number of bytes occupied by this constant value or constant object. * diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index 43e02dd98b394..903e789d466af 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -86,7 +86,8 @@ default JavaConstant getConstantValue() { /** * Gets the type annotations for this field that backs the implementation - * of {@link Field#getAnnotatedType()}. + * of {@link Field#getAnnotatedType()}. This method returns an empty + * list if there are no type annotations. * * @throws UnsupportedOperationException if this operation is not supported */ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index 9384e7cab4a3e..579cb680160f0 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -495,6 +495,7 @@ default boolean isScoped() { * Gets the type annotations for this method that back the implementation * of {@link Method#getAnnotatedReturnType()}, {@link Method#getAnnotatedReceiverType()}, * {@link Method#getAnnotatedExceptionTypes()} and {@link Method#getAnnotatedParameterTypes()}. + * This method returns an empty list if there are no type annotations. * * @throws UnsupportedOperationException if this operation is not supported */ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaRecordComponent.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaRecordComponent.java new file mode 100644 index 0000000000000..ce2d1dc5cb210 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaRecordComponent.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025, 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 jdk.vm.ci.meta; + +import jdk.vm.ci.meta.annotation.Annotated; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; + +import java.lang.reflect.RecordComponent; +import java.util.List; + +/** + * A reference to a {@link java.lang.reflect.RecordComponent}. + */ +public interface ResolvedJavaRecordComponent extends Annotated { + + /** + * Gets the {@link ResolvedJavaType} object representing the class which declares this record component. + */ + ResolvedJavaType getDeclaringRecord(); + + /** + * Gets a {@code ResolvedJavaMethod} that represents the accessor for this record + * component. + */ + default ResolvedJavaMethod getAccessor() { + for (ResolvedJavaMethod method : getDeclaringRecord().getDeclaredMethods(false)) { + if (method.getName().equals(getName()) && + method.getSignature().getParameterCount(false) == 0 && + method.getSignature().getReturnType(null).getName().equals(getType().getName())) { + return method; + } + } + return null; + } + + /** + * Returns the name of this record component. + */ + String getName(); + + /** + * Returns a {@link JavaType} object that identifies the declared type for this record component. + */ + JavaType getType(); + + /** + * Gets the type annotations for this record component that backs the implementation + * of {@link RecordComponent#getAnnotatedType()}. This method returns an empty + * list if there are no type annotations. + * + * @throws UnsupportedOperationException if this operation is not supported + */ + default List getTypeAnnotationValues() { + throw new UnsupportedOperationException(getClass().getName()); + } +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index c09517318d1f7..8b6d128c27cd2 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -314,6 +314,18 @@ default ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, Reso */ ResolvedJavaField[] getStaticFields(); + /** + * Returns whether this type is a {@link Record}. + */ + boolean isRecord(); + + /** + * Returns an array of {@code ResolvedJavaRecordComponent} objects representing all the + * record components of this record class, or {@code null} if this class is + * not a record class. + */ + ResolvedJavaRecordComponent[] getRecordComponents(); + /** * Returns the instance field of this class (or one of its super classes) at the given offset, * or {@code null} if there is no such field. @@ -431,6 +443,7 @@ default boolean isConcrete() { /** * Gets the type annotations for this type that back the implementation * of {@link Class#getAnnotatedSuperclass()} and {@link Class#getAnnotatedInterfaces()}. + * This method returns an empty list if there are no type annotations. * * @throws UnsupportedOperationException if this operation is not supported */ diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java index dcc380d158f98..8e927eaf6d88d 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java @@ -23,10 +23,13 @@ package jdk.vm.ci.runtime.test; import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import java.lang.reflect.Field; +import java.lang.reflect.RecordComponent; import java.util.HashMap; import java.util.Map; +import java.util.Objects; /** * Context for field related tests. @@ -34,13 +37,19 @@ public class FieldUniverse extends TypeUniverse { public static final Map fields = new HashMap<>(); + public static final Map recordComponents = new HashMap<>(); - { + static { for (Class c : classes) { for (Field f : c.getDeclaredFields()) { ResolvedJavaField field = metaAccess.lookupJavaField(f); fields.put(f, field); } + if (c.isRecord()) { + for (RecordComponent rc : Objects.requireNonNull(c.getRecordComponents())) { + recordComponents.put(rc, metaAccess.lookupJavaRecordComponent(rc)); + } + } } } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java index 92366580a91ef..03371c48d7602 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java @@ -37,7 +37,7 @@ public class MethodUniverse extends TypeUniverse { public static final Map methods = new HashMap<>(); public static final Map, ResolvedJavaMethod> constructors = new HashMap<>(); - { + static { for (Class c : classes) { for (Method m : c.getDeclaredMethods()) { ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java new file mode 100644 index 0000000000000..832f04bdc8f83 --- /dev/null +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2025, 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. + */ + +/** + * @test + * @requires vm.jvmci + * @library ../../../../../ + * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java + * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java + * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberAdded.java + * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java + * TestResolvedJavaType.java + * @clean jdk.internal.vm.test.AnnotationTestInput$Missing + * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java + * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java + * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java + * @modules jdk.internal.vm.ci/jdk.vm.ci.meta + * java.base/java.lang:open + * java.base/java.lang.reflect:open + * jdk.internal.vm.ci/jdk.vm.ci.meta.annotation + * jdk.internal.vm.ci/jdk.vm.ci.hotspot + * jdk.internal.vm.ci/jdk.vm.ci.runtime + * jdk.internal.vm.ci/jdk.vm.ci.common + * java.base/jdk.internal.reflect + * java.base/jdk.internal.misc + * java.base/jdk.internal.vm + * java.base/sun.reflect.annotation + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaRecordComponent + */ + +package jdk.vm.ci.runtime.test; + +import jdk.internal.vm.test.AnnotationTestInput; +import jdk.internal.vm.test.AnnotationTestInput.AnnotatedRecord; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.TypeAnnotationValue; +import org.junit.Test; +import sun.reflect.annotation.TypeAnnotation; +import sun.reflect.annotation.TypeAnnotationParser; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.RecordComponent; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * Tests for {@link ResolvedJavaRecordComponent}. + */ +public class TestResolvedJavaRecordComponent extends FieldUniverse { + + @Test + public void equalsTest() { + for (ResolvedJavaRecordComponent f : recordComponents.values()) { + for (ResolvedJavaRecordComponent that : recordComponents.values()) { + boolean expect = f == that; + boolean actual = f.equals(that); + assertEquals(expect, actual); + } + } + } + + @Test + public void getDeclaringRecordTest() { + for (Map.Entry e : recordComponents.entrySet()) { + ResolvedJavaRecordComponent rc = e.getValue(); + ResolvedJavaType actual = rc.getDeclaringRecord(); + ResolvedJavaType expect = metaAccess.lookupJavaType(e.getKey().getDeclaringRecord()); + assertEquals(rc.toString(), expect, actual); + } + } + + @Test + public void getNameTest() { + for (Map.Entry e : recordComponents.entrySet()) { + ResolvedJavaRecordComponent rc = e.getValue(); + String actual = rc.getName(); + String expect = e.getKey().getName(); + assertEquals(rc.toString(), expect, actual); + } + } + + @Test + public void getAccessorTest() { + for (Map.Entry e : recordComponents.entrySet()) { + ResolvedJavaRecordComponent rc = e.getValue(); + Method expect = e.getKey().getAccessor(); + ResolvedJavaMethod actual = rc.getAccessor(); + assertEquals(rc.toString(), expect.getName(), actual.getName()); + } + } + + @Test + public void getTypeTest() { + for (Map.Entry e : recordComponents.entrySet()) { + ResolvedJavaRecordComponent rc = e.getValue(); + JavaType actual = rc.getType(); + JavaType expect = metaAccess.lookupJavaType(e.getKey().getType()).resolve(rc.getDeclaringRecord()); + assertEquals(expect, actual); + } + } + + @Test + public void getAnnotationValuesTest() { + for (RecordComponent rc : AnnotatedRecord.class.getRecordComponents()) { + TestResolvedJavaType.getAnnotationValuesTest(rc); + } + for (RecordComponent rc : recordComponents.keySet()) { + TestResolvedJavaType.getAnnotationValuesTest(rc); + } + } + + /** + * Tests that {@link TypeAnnotation}s obtained from {@code rc} + * match {@link TypeAnnotationValue}s for the corresponding {@link ResolvedJavaRecordComponent}. + */ + private static void getTypeAnnotationValuesTest(RecordComponent rc) { + ResolvedJavaRecordComponent resolvedRc = metaAccess.lookupJavaRecordComponent(rc); + TypeAnnotation[] typeAnnotations = getTypeAnnotations(rc); + List typeAnnotationValues = resolvedRc.getTypeAnnotationValues(); + TestResolvedJavaType.assertTypeAnnotationsEquals(typeAnnotations, typeAnnotationValues); + if (!typeAnnotationValues.isEmpty()) { + IO.println(resolvedRc + " -> " + typeAnnotationValues); + } + } + + private static final Field recordComponentTypeAnnotations = lookupField(RecordComponent.class, "typeAnnotations"); + private static final Method classGetConstantPool = lookupMethod(Class.class, "getConstantPool"); + + private static TypeAnnotation[] getTypeAnnotations(RecordComponent rc) { + byte[] rawAnnotations = getFieldValue(recordComponentTypeAnnotations, rc); + Class container = rc.getDeclaringRecord(); + jdk.internal.reflect.ConstantPool cp = invokeMethod(classGetConstantPool, container); + return TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, container); + } + + @Test + public void getTypeAnnotationValuesTest() throws Exception { + for (RecordComponent rc : AnnotatedRecord.class.getRecordComponents()) { + getTypeAnnotationValuesTest(rc); + } + for (RecordComponent rc : recordComponents.keySet()) { + getTypeAnnotationValuesTest(rc); + } + } +} diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index ea7012ab36bfc..c889ffbf819a7 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -59,6 +59,7 @@ import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.annotation.Annotated; import jdk.vm.ci.meta.annotation.AnnotationValue; @@ -88,6 +89,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.RecordComponent; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -97,7 +99,6 @@ import java.util.Map; import java.util.Set; import java.util.function.Supplier; -import java.util.stream.Collectors; import java.util.stream.Stream; import static java.lang.reflect.Modifier.isAbstract; @@ -213,6 +214,16 @@ public void isInstanceClassTest() { } } + @Test + public void isRecordTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + boolean expected = c.isRecord(); + boolean actual = type.isRecord(); + assertEquals(expected, actual); + } + } + @Test public void isArrayTest() { for (Class c : classes) { @@ -1024,6 +1035,27 @@ public void getDeclaredMethodsTest() { } } + @Test + public void getRecordComponentsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + RecordComponent[] raw = c.getRecordComponents(); + if (raw == null) { + assertFalse(type.isRecord()); + continue; + } + assertTrue(type.isRecord()); + Set expected = new HashSet<>(); + for (RecordComponent rc : raw) { + ResolvedJavaRecordComponent resolvedRecordComponent = metaAccess.lookupJavaRecordComponent(rc); + assertNotNull(resolvedRecordComponent); + expected.add(resolvedRecordComponent); + } + Set actual = new HashSet<>(Arrays.asList(type.getRecordComponents())); + assertEquals(expected, actual); + } + } + @Test public void getDeclaredConstructorsTest() { for (Class c : classes) { @@ -1362,6 +1394,14 @@ public static void assertTypeAnnotationsEquals( } private static List testGetAnnotationValues(Annotated annotated, List annotations) throws AssertionError { + try { + return testGetAnnotationValues0(annotated, annotations); + } catch (AssertionError e) { + throw new AssertionError("Annotated: " + annotated, e); + } + } + + private static List testGetAnnotationValues0(Annotated annotated, List annotations) throws AssertionError { List res = new ArrayList<>(annotations.size()); Map allAnnotationValues = annotated.getDeclaredAnnotationValues(); @@ -1389,6 +1429,8 @@ private static Annotated toAnnotated(AnnotatedElement element) { return metaAccess.lookupJavaType(t); } else if (element instanceof Method m) { return metaAccess.lookupJavaMethod(m); + } else if (element instanceof RecordComponent rc) { + return metaAccess.lookupJavaRecordComponent(rc); } else { Field f = (Field) element; return metaAccess.lookupJavaField(f); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java index 2e969b24a44d4..41a954d80cd33 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java @@ -306,6 +306,16 @@ public static Method lookupMethod(Class declaringClass, String methodName, Cl } } + public static Field lookupField(Class declaringClass, String fieldName) { + try { + Field result = declaringClass.getDeclaredField(fieldName); + result.setAccessible(true); + return result; + } catch (ReflectiveOperationException | LinkageError cause) { + throw new AssertionError(cause); + } + } + @SuppressWarnings("unchecked") public static RuntimeException rethrow(Throwable ex) throws E { throw (E) ex; @@ -326,4 +336,14 @@ public static T invokeMethod(Method method, Object receiver, Object... argum throw new AssertionError(ex); } } + + @SuppressWarnings("unchecked") + public static T getFieldValue(Field field, Object receiver) { + field.setAccessible(true); + try { + return (T) field.get(receiver); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } } diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java index 8bedb677c905f..56d7eb9adf042 100644 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java @@ -177,6 +177,8 @@ public static class InheritedName3 extends Super3 {} @SuppressWarnings({"rawtypes", "all"}) public static class AnnotatedClass extends @TypeQualifier Thread implements @TypeQualifier Serializable {} + public static record AnnotatedRecord(@TypeQualifier @Named("obj1Component Name") String obj1Component, @Missing @NestedAnno("int1 value") int int1Component, @Missing float componentWithMissingAnno) {} + @Single(string = "a", stringArray = {"a", "b"}, classValue = String.class, @@ -242,7 +244,7 @@ public static class AnnotatedClass extends @TypeQualifier Thread implements @Typ // Define a type-use annotation @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) - @interface TypeQualifier{ + @interface TypeQualifier { String comment() default ""; } From 90c5da75b5cb6b835b5af42398836d321d718edb Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 28 Aug 2025 12:17:58 +0200 Subject: [PATCH 17/20] sorted initializer for CompilerToVM::methods --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 231 +++++++++--------- 1 file changed, 116 insertions(+), 115 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 563aee040423a..179f275362820 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -3390,141 +3390,142 @@ C2V_END #define HS_CONSTANT_POOL "Ljdk/vm/ci/hotspot/HotSpotConstantPool;" #define HS_CONSTANT_POOL2 "Ljdk/vm/ci/hotspot/HotSpotConstantPool;J" +// Keep this table sorted JNINativeMethod CompilerToVM::methods[] = { + {CC "addFailedSpeculation", CC "(J[B)Z", FN_PTR(addFailedSpeculation)}, + {CC "allocateCompileId", CC "(" HS_METHOD2 "I)I", FN_PTR(allocateCompileId)}, + {CC "arrayBaseOffset", CC "(C)I", FN_PTR(arrayBaseOffset)}, + {CC "arrayIndexScale", CC "(C)I", FN_PTR(arrayIndexScale)}, + {CC "asJavaType", CC "(" OBJECTCONSTANT ")" HS_RESOLVED_TYPE, FN_PTR(asJavaType)}, + {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" EXECUTABLE, FN_PTR(asReflectionExecutable)}, + {CC "asReflectionField", CC "(" HS_KLASS2 "I)" FIELD, FN_PTR(asReflectionField)}, + {CC "asResolvedJavaMethod", CC "(" EXECUTABLE ")" HS_METHOD, FN_PTR(asResolvedJavaMethod)}, + {CC "asString", CC "(" OBJECTCONSTANT ")" STRING, FN_PTR(asString)}, + {CC "attachCurrentThread", CC "([BZ[J)Z", FN_PTR(attachCurrentThread)}, + {CC "bootstrapArgumentIndexAt", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(bootstrapArgumentIndexAt)}, + {CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)}, + {CC "callSystemExit", CC "(I)V", FN_PTR(callSystemExit)}, + {CC "clearOopHandle", CC "(J)V", FN_PTR(clearOopHandle)}, + {CC "collectCounters", CC "()[J", FN_PTR(collectCounters)}, + {CC "compileToBytecode", CC "(" OBJECTCONSTANT ")V", FN_PTR(compileToBytecode)}, + {CC "decodeFieldIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(decodeFieldIndexToCPIndex)}, + {CC "decodeIndyIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "IZ)I", FN_PTR(decodeIndyIndexToCPIndex)}, + {CC "decodeMethodIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(decodeMethodIndexToCPIndex)}, + {CC "detachCurrentThread", CC "(Z)Z", FN_PTR(detachCurrentThread)}, + {CC "disassembleCodeBlob", CC "(" INSTALLED_CODE ")" STRING, FN_PTR(disassembleCodeBlob)}, + {CC "ensureInitialized", CC "(" HS_KLASS2 ")V", FN_PTR(ensureInitialized)}, + {CC "ensureLinked", CC "(" HS_KLASS2 ")V", FN_PTR(ensureLinked)}, + {CC "equals", CC "(" OBJECTCONSTANT "J" OBJECTCONSTANT "J)Z", FN_PTR(equals)}, + {CC "executeHotSpotNmethod", CC "([" OBJECT HS_NMETHOD ")" OBJECT, FN_PTR(executeHotSpotNmethod)}, + {CC "findUniqueConcreteMethod", CC "(" HS_KLASS2 HS_METHOD2 ")" HS_METHOD, FN_PTR(findUniqueConcreteMethod)}, + {CC "flushDebugOutput", CC "()V", FN_PTR(flushDebugOutput)}, + {CC "getAllMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getAllMethods)}, + {CC "getArrayLength", CC "(" OBJECTCONSTANT ")I", FN_PTR(getArrayLength)}, + {CC "getArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getArrayType)}, {CC "getBytecode", CC "(" HS_METHOD2 ")[B", FN_PTR(getBytecode)}, - {CC "getExceptionTableStart", CC "(" HS_METHOD2 ")J", FN_PTR(getExceptionTableStart)}, + {CC "getClassInitializer", CC "(" HS_KLASS2 ")" HS_METHOD, FN_PTR(getClassInitializer)}, + {CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)}, + {CC "getCompilationActivityMode", CC "()I", FN_PTR(getCompilationActivityMode)}, + {CC "getComponentType", CC "(" HS_KLASS2 ")" HS_RESOLVED_TYPE, FN_PTR(getComponentType)}, + {CC "getConstantPool", CC "(" OBJECT "JZ)" HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, + {CC "getCountersSize", CC "()I", FN_PTR(getCountersSize)}, + {CC "getCurrentJavaThread", CC "()J", FN_PTR(getCurrentJavaThread)}, + {CC "getDeclaredConstructors", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)}, + {CC "getDeclaredFieldsInfo", CC "(" HS_KLASS2 ")[" FIELDINFO, FN_PTR(getDeclaredFieldsInfo)}, + {CC "getDeclaredMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)}, + {CC "getEncodedClassAnnotationValues", CC "(" HS_KLASS2 "I)[B", FN_PTR(getEncodedClassAnnotationValues)}, + {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 HS_KLASS2 "I)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, + {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "IZI)[B", FN_PTR(getEncodedFieldAnnotationValues)}, {CC "getExceptionTableLength", CC "(" HS_METHOD2 ")I", FN_PTR(getExceptionTableLength)}, - {CC "findUniqueConcreteMethod", CC "(" HS_KLASS2 HS_METHOD2 ")" HS_METHOD, FN_PTR(findUniqueConcreteMethod)}, + {CC "getExceptionTableStart", CC "(" HS_METHOD2 ")J", FN_PTR(getExceptionTableStart)}, + {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, + {CC "getFailedSpeculationsAddress", CC "(" HS_METHOD2 ")J", FN_PTR(getFailedSpeculationsAddress)}, + {CC "getFlagValue", CC "(" STRING ")" OBJECT, FN_PTR(getFlagValue)}, + {CC "getIdentityHashCode", CC "(" OBJECTCONSTANT ")I", FN_PTR(getIdentityHashCode)}, {CC "getImplementor", CC "(" HS_KLASS2 ")" HS_KLASS, FN_PTR(getImplementor)}, - {CC "getStackTraceElement", CC "(" HS_METHOD2 "I)" STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, - {CC "methodIsIgnoredBySecurityStackWalk", CC "(" HS_METHOD2 ")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, - {CC "setNotInlinableOrCompilable", CC "(" HS_METHOD2 ")V", FN_PTR(setNotInlinableOrCompilable)}, - {CC "isCompilable", CC "(" HS_METHOD2 ")Z", FN_PTR(isCompilable)}, - {CC "hasNeverInlineDirective", CC "(" HS_METHOD2 ")Z", FN_PTR(hasNeverInlineDirective)}, - {CC "shouldInlineMethod", CC "(" HS_METHOD2 ")Z", FN_PTR(shouldInlineMethod)}, - {CC "lookupType", CC "(" STRING HS_KLASS2 "IZ)" HS_RESOLVED_TYPE, FN_PTR(lookupType)}, - {CC "lookupJClass", CC "(J)" HS_RESOLVED_TYPE, FN_PTR(lookupJClass)}, + {CC "getInstallCodeFlags", CC "()I", FN_PTR(getInstallCodeFlags)}, + {CC "getInterfaces", CC "(" HS_KLASS2 ")[" HS_KLASS, FN_PTR(getInterfaces)}, + {CC "getInvalidationReasonDescription", CC "(I)" STRING, FN_PTR(getInvalidationReasonDescription)}, + {CC "getJavaMirror", CC "(" HS_KLASS2 ")" OBJECTCONSTANT, FN_PTR(getJavaMirror)}, {CC "getJObjectValue", CC "(" OBJECTCONSTANT ")J", FN_PTR(getJObjectValue)}, - {CC "getArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getArrayType)}, - {CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)}, - {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupNameInPool)}, - {CC "lookupNameAndTypeRefIndexInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, - {CC "lookupSignatureInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupSignatureInPool)}, - {CC "lookupKlassRefIndexInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(lookupKlassRefIndexInPool)}, - {CC "lookupKlassInPool", CC "(" HS_CONSTANT_POOL2 "I)Ljava/lang/Object;", FN_PTR(lookupKlassInPool)}, - {CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL2 "II)" OBJECTCONSTANT, FN_PTR(lookupAppendixInPool)}, - {CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL2 "IB" HS_METHOD2 ")" HS_METHOD, FN_PTR(lookupMethodInPool)}, - {CC "lookupConstantInPool", CC "(" HS_CONSTANT_POOL2 "IZ)" JAVACONSTANT, FN_PTR(lookupConstantInPool)}, + {CC "getLineNumberTable", CC "(" HS_METHOD2 ")[J", FN_PTR(getLineNumberTable)}, + {CC "getLocalVariableTableLength", CC "(" HS_METHOD2 ")I", FN_PTR(getLocalVariableTableLength)}, + {CC "getLocalVariableTableStart", CC "(" HS_METHOD2 ")J", FN_PTR(getLocalVariableTableStart)}, + {CC "getMaxCallTargetOffset", CC "(J)J", FN_PTR(getMaxCallTargetOffset)}, {CC "getNumIndyEntries", CC "(" HS_CONSTANT_POOL2 ")I", FN_PTR(getNumIndyEntries)}, - {CC "resolveBootstrapMethod", CC "(" HS_CONSTANT_POOL2 "I)[" OBJECT, FN_PTR(resolveBootstrapMethod)}, - {CC "bootstrapArgumentIndexAt", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(bootstrapArgumentIndexAt)}, - {CC "getUncachedStringInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(getUncachedStringInPool)}, - {CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL2 "I)" HS_KLASS, FN_PTR(resolveTypeInPool)}, - {CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL2 "I" HS_METHOD2 "B[I)" HS_KLASS, FN_PTR(resolveFieldInPool)}, - {CC "decodeFieldIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(decodeFieldIndexToCPIndex)}, - {CC "decodeMethodIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(decodeMethodIndexToCPIndex)}, - {CC "decodeIndyIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "IZ)I", FN_PTR(decodeIndyIndexToCPIndex)}, - {CC "resolveInvokeHandleInPool", CC "(" HS_CONSTANT_POOL2 "I)V", FN_PTR(resolveInvokeHandleInPool)}, - {CC "isResolvedInvokeHandleInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(isResolvedInvokeHandleInPool)}, - {CC "resolveMethod", CC "(" HS_KLASS2 HS_METHOD2 HS_KLASS2 ")" HS_METHOD, FN_PTR(resolveMethod)}, + {CC "getOopMapAt", CC "(" HS_METHOD2 "I[J)V", FN_PTR(getOopMapAt)}, + {CC "getRecordComponents", CC "(" HS_KLASS2 ")[" RESOLVED_RECORD_COMPONENT, FN_PTR(getRecordComponents)}, + {CC "getResolvedJavaMethod", CC "(" OBJECTCONSTANT "J)" HS_METHOD, FN_PTR(getResolvedJavaMethod)}, + {CC "getResolvedJavaType0", CC "(Ljava/lang/Object;JZ)" HS_KLASS, FN_PTR(getResolvedJavaType0)}, + {CC "getSignatureName", CC "(J)" STRING, FN_PTR(getSignatureName)}, {CC "getSignaturePolymorphicHolders", CC "()[" STRING, FN_PTR(getSignaturePolymorphicHolders)}, + {CC "getStackTraceElement", CC "(" HS_METHOD2 "I)" STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, + {CC "getSymbol", CC "(J)" STRING, FN_PTR(getSymbol)}, + {CC "getThreadLocalLong", CC "(I)J", FN_PTR(getThreadLocalLong)}, + {CC "getThreadLocalObject", CC "(I)" OBJECT, FN_PTR(getThreadLocalObject)}, + {CC "getUncachedStringInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(getUncachedStringInPool)}, {CC "getVtableIndexForInterfaceMethod", CC "(" HS_KLASS2 HS_METHOD2 ")I", FN_PTR(getVtableIndexForInterfaceMethod)}, - {CC "getClassInitializer", CC "(" HS_KLASS2 ")" HS_METHOD, FN_PTR(getClassInitializer)}, + {CC "hasCompiledCodeForOSR", CC "(" HS_METHOD2 "II)Z", FN_PTR(hasCompiledCodeForOSR)}, {CC "hasFinalizableSubclass", CC "(" HS_KLASS2 ")Z", FN_PTR(hasFinalizableSubclass)}, - {CC "getMaxCallTargetOffset", CC "(J)J", FN_PTR(getMaxCallTargetOffset)}, - {CC "asResolvedJavaMethod", CC "(" EXECUTABLE ")" HS_METHOD, FN_PTR(asResolvedJavaMethod)}, - {CC "getResolvedJavaMethod", CC "(" OBJECTCONSTANT "J)" HS_METHOD, FN_PTR(getResolvedJavaMethod)}, - {CC "getConstantPool", CC "(" OBJECT "JZ)" HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, - {CC "getResolvedJavaType0", CC "(Ljava/lang/Object;JZ)" HS_KLASS, FN_PTR(getResolvedJavaType0)}, - {CC "readConfiguration", CC "()[" OBJECT, FN_PTR(readConfiguration)}, + {CC "hasNeverInlineDirective", CC "(" HS_METHOD2 ")Z", FN_PTR(hasNeverInlineDirective)}, {CC "installCode0", CC "(JJZ" HS_COMPILED_CODE "[" OBJECT INSTALLED_CODE "J[B)I", FN_PTR(installCode0)}, - {CC "getInvalidationReasonDescription", CC "(I)" STRING, FN_PTR(getInvalidationReasonDescription)}, - {CC "getInstallCodeFlags", CC "()I", FN_PTR(getInstallCodeFlags)}, - {CC "resetCompilationStatistics", CC "()V", FN_PTR(resetCompilationStatistics)}, - {CC "disassembleCodeBlob", CC "(" INSTALLED_CODE ")" STRING, FN_PTR(disassembleCodeBlob)}, - {CC "executeHotSpotNmethod", CC "([" OBJECT HS_NMETHOD ")" OBJECT, FN_PTR(executeHotSpotNmethod)}, - {CC "getLineNumberTable", CC "(" HS_METHOD2 ")[J", FN_PTR(getLineNumberTable)}, - {CC "getLocalVariableTableStart", CC "(" HS_METHOD2 ")J", FN_PTR(getLocalVariableTableStart)}, - {CC "getLocalVariableTableLength", CC "(" HS_METHOD2 ")I", FN_PTR(getLocalVariableTableLength)}, - {CC "reprofile", CC "(" HS_METHOD2 ")V", FN_PTR(reprofile)}, + {CC "interpreterFrameSize", CC "(" BYTECODE_FRAME ")I", FN_PTR(interpreterFrameSize)}, {CC "invalidateHotSpotNmethod", CC "(" HS_NMETHOD "ZI)V", FN_PTR(invalidateHotSpotNmethod)}, - {CC "collectCounters", CC "()[J", FN_PTR(collectCounters)}, - {CC "getCountersSize", CC "()I", FN_PTR(getCountersSize)}, - {CC "setCountersSize", CC "(I)Z", FN_PTR(setCountersSize)}, - {CC "allocateCompileId", CC "(" HS_METHOD2 "I)I", FN_PTR(allocateCompileId)}, + {CC "isAssignableFrom", CC "(" HS_KLASS2 HS_KLASS2 ")Z", FN_PTR(isAssignableFrom)}, + {CC "isCompilable", CC "(" HS_METHOD2 ")Z", FN_PTR(isCompilable)}, + {CC "isCompilerThread", CC "()Z", FN_PTR(isCompilerThread)}, + {CC "isCurrentThreadAttached", CC "()Z", FN_PTR(isCurrentThreadAttached)}, + {CC "isInstance", CC "(" HS_KLASS2 OBJECTCONSTANT ")Z", FN_PTR(isInstance)}, + {CC "isInternedString", CC "(" OBJECTCONSTANT ")Z", FN_PTR(isInternedString)}, {CC "isMature", CC "(J)Z", FN_PTR(isMature)}, - {CC "hasCompiledCodeForOSR", CC "(" HS_METHOD2 "II)Z", FN_PTR(hasCompiledCodeForOSR)}, - {CC "getSymbol", CC "(J)" STRING, FN_PTR(getSymbol)}, - {CC "getSignatureName", CC "(J)" STRING, FN_PTR(getSignatureName)}, + {CC "isResolvedInvokeHandleInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(isResolvedInvokeHandleInPool)}, + {CC "isTrustedForIntrinsics", CC "(" HS_KLASS2 ")Z", FN_PTR(isTrustedForIntrinsics)}, {CC "iterateFrames", CC "([" RESOLVED_METHOD "[" RESOLVED_METHOD "I" INSPECTED_FRAME_VISITOR ")" OBJECT, FN_PTR(iterateFrames)}, + {CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL2 "II)" OBJECTCONSTANT, FN_PTR(lookupAppendixInPool)}, + {CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)}, + {CC "lookupConstantInPool", CC "(" HS_CONSTANT_POOL2 "IZ)" JAVACONSTANT, FN_PTR(lookupConstantInPool)}, + {CC "lookupJClass", CC "(J)" HS_RESOLVED_TYPE, FN_PTR(lookupJClass)}, + {CC "lookupKlassInPool", CC "(" HS_CONSTANT_POOL2 "I)Ljava/lang/Object;", FN_PTR(lookupKlassInPool)}, + {CC "lookupKlassRefIndexInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(lookupKlassRefIndexInPool)}, + {CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL2 "IB" HS_METHOD2 ")" HS_METHOD, FN_PTR(lookupMethodInPool)}, + {CC "lookupNameAndTypeRefIndexInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, + {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupNameInPool)}, + {CC "lookupSignatureInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupSignatureInPool)}, + {CC "lookupType", CC "(" STRING HS_KLASS2 "IZ)" HS_RESOLVED_TYPE, FN_PTR(lookupType)}, {CC "materializeVirtualObjects", CC "(" HS_STACK_FRAME_REF "Z)V", FN_PTR(materializeVirtualObjects)}, - {CC "shouldDebugNonSafepoints", CC "()Z", FN_PTR(shouldDebugNonSafepoints)}, - {CC "writeDebugOutput", CC "(JIZ)V", FN_PTR(writeDebugOutput)}, - {CC "flushDebugOutput", CC "()V", FN_PTR(flushDebugOutput)}, - {CC "methodDataProfileDataSize", CC "(JI)I", FN_PTR(methodDataProfileDataSize)}, {CC "methodDataExceptionSeen", CC "(JI)I", FN_PTR(methodDataExceptionSeen)}, - {CC "interpreterFrameSize", CC "(" BYTECODE_FRAME ")I", FN_PTR(interpreterFrameSize)}, - {CC "compileToBytecode", CC "(" OBJECTCONSTANT ")V", FN_PTR(compileToBytecode)}, - {CC "getFlagValue", CC "(" STRING ")" OBJECT, FN_PTR(getFlagValue)}, - {CC "getInterfaces", CC "(" HS_KLASS2 ")[" HS_KLASS, FN_PTR(getInterfaces)}, - {CC "getComponentType", CC "(" HS_KLASS2 ")" HS_RESOLVED_TYPE, FN_PTR(getComponentType)}, - {CC "ensureInitialized", CC "(" HS_KLASS2 ")V", FN_PTR(ensureInitialized)}, - {CC "ensureLinked", CC "(" HS_KLASS2 ")V", FN_PTR(ensureLinked)}, - {CC "getIdentityHashCode", CC "(" OBJECTCONSTANT ")I", FN_PTR(getIdentityHashCode)}, - {CC "isInternedString", CC "(" OBJECTCONSTANT ")Z", FN_PTR(isInternedString)}, - {CC "unboxPrimitive", CC "(" OBJECTCONSTANT ")" OBJECT, FN_PTR(unboxPrimitive)}, - {CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)}, - {CC "getDeclaredConstructors", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)}, - {CC "getDeclaredMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)}, - {CC "getRecordComponents", CC "(" HS_KLASS2 ")[" RESOLVED_RECORD_COMPONENT, FN_PTR(getRecordComponents)}, - {CC "getAllMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getAllMethods)}, - {CC "getDeclaredFieldsInfo", CC "(" HS_KLASS2 ")[" FIELDINFO, FN_PTR(getDeclaredFieldsInfo)}, - {CC "readStaticFieldValue", CC "(" HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readStaticFieldValue)}, - {CC "readFieldValue", CC "(" OBJECTCONSTANT HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readFieldValue)}, - {CC "isInstance", CC "(" HS_KLASS2 OBJECTCONSTANT ")Z", FN_PTR(isInstance)}, - {CC "isAssignableFrom", CC "(" HS_KLASS2 HS_KLASS2 ")Z", FN_PTR(isAssignableFrom)}, - {CC "isTrustedForIntrinsics", CC "(" HS_KLASS2 ")Z", FN_PTR(isTrustedForIntrinsics)}, - {CC "asJavaType", CC "(" OBJECTCONSTANT ")" HS_RESOLVED_TYPE, FN_PTR(asJavaType)}, - {CC "asString", CC "(" OBJECTCONSTANT ")" STRING, FN_PTR(asString)}, - {CC "equals", CC "(" OBJECTCONSTANT "J" OBJECTCONSTANT "J)Z", FN_PTR(equals)}, - {CC "getJavaMirror", CC "(" HS_KLASS2 ")" OBJECTCONSTANT, FN_PTR(getJavaMirror)}, - {CC "getArrayLength", CC "(" OBJECTCONSTANT ")I", FN_PTR(getArrayLength)}, + {CC "methodDataProfileDataSize", CC "(JI)I", FN_PTR(methodDataProfileDataSize)}, + {CC "methodIsIgnoredBySecurityStackWalk", CC "(" HS_METHOD2 ")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, + {CC "notifyCompilerInliningEvent", CC "(I" HS_METHOD2 HS_METHOD2 "ZLjava/lang/String;I)V", FN_PTR(notifyCompilerInliningEvent)}, + {CC "notifyCompilerPhaseEvent", CC "(JIII)V", FN_PTR(notifyCompilerPhaseEvent)}, {CC "readArrayElement", CC "(" OBJECTCONSTANT "I)Ljava/lang/Object;", FN_PTR(readArrayElement)}, - {CC "arrayBaseOffset", CC "(C)I", FN_PTR(arrayBaseOffset)}, - {CC "arrayIndexScale", CC "(C)I", FN_PTR(arrayIndexScale)}, - {CC "clearOopHandle", CC "(J)V", FN_PTR(clearOopHandle)}, - {CC "releaseClearedOopHandles", CC "()V", FN_PTR(releaseClearedOopHandles)}, + {CC "readConfiguration", CC "()[" OBJECT, FN_PTR(readConfiguration)}, + {CC "readFieldValue", CC "(" OBJECTCONSTANT HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readFieldValue)}, + {CC "readStaticFieldValue", CC "(" HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readStaticFieldValue)}, + {CC "registerCompilerPhase", CC "(" STRING ")I", FN_PTR(registerCompilerPhase)}, {CC "registerNativeMethods", CC "(" CLASS ")[J", FN_PTR(registerNativeMethods)}, - {CC "isCurrentThreadAttached", CC "()Z", FN_PTR(isCurrentThreadAttached)}, - {CC "getCurrentJavaThread", CC "()J", FN_PTR(getCurrentJavaThread)}, - {CC "attachCurrentThread", CC "([BZ[J)Z", FN_PTR(attachCurrentThread)}, - {CC "detachCurrentThread", CC "(Z)Z", FN_PTR(detachCurrentThread)}, - {CC "translate", CC "(" OBJECT "Z)J", FN_PTR(translate)}, - {CC "unhand", CC "(J)" OBJECT, FN_PTR(unhand)}, - {CC "updateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(updateHotSpotNmethod)}, - {CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)}, - {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" EXECUTABLE, FN_PTR(asReflectionExecutable)}, - {CC "asReflectionField", CC "(" HS_KLASS2 "I)" FIELD, FN_PTR(asReflectionField)}, - {CC "getEncodedClassAnnotationValues", CC "(" HS_KLASS2 "I)[B", FN_PTR(getEncodedClassAnnotationValues)}, - {CC "getEncodedExecutableAnnotationValues", CC "(" HS_METHOD2 HS_KLASS2 "I)[B", FN_PTR(getEncodedExecutableAnnotationValues)}, - {CC "getEncodedFieldAnnotationValues", CC "(" HS_KLASS2 "IZI)[B", FN_PTR(getEncodedFieldAnnotationValues)}, - {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, - {CC "getFailedSpeculationsAddress", CC "(" HS_METHOD2 ")J", FN_PTR(getFailedSpeculationsAddress)}, + {CC "releaseClearedOopHandles", CC "()V", FN_PTR(releaseClearedOopHandles)}, {CC "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)}, - {CC "addFailedSpeculation", CC "(J[B)Z", FN_PTR(addFailedSpeculation)}, - {CC "callSystemExit", CC "(I)V", FN_PTR(callSystemExit)}, - {CC "ticksNow", CC "()J", FN_PTR(ticksNow)}, - {CC "getThreadLocalObject", CC "(I)" OBJECT, FN_PTR(getThreadLocalObject)}, - {CC "setThreadLocalObject", CC "(I" OBJECT ")V", FN_PTR(setThreadLocalObject)}, - {CC "getThreadLocalLong", CC "(I)J", FN_PTR(getThreadLocalLong)}, + {CC "reprofile", CC "(" HS_METHOD2 ")V", FN_PTR(reprofile)}, + {CC "resetCompilationStatistics", CC "()V", FN_PTR(resetCompilationStatistics)}, + {CC "resolveBootstrapMethod", CC "(" HS_CONSTANT_POOL2 "I)[" OBJECT, FN_PTR(resolveBootstrapMethod)}, + {CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL2 "I" HS_METHOD2 "B[I)" HS_KLASS, FN_PTR(resolveFieldInPool)}, + {CC "resolveInvokeHandleInPool", CC "(" HS_CONSTANT_POOL2 "I)V", FN_PTR(resolveInvokeHandleInPool)}, + {CC "resolveMethod", CC "(" HS_KLASS2 HS_METHOD2 HS_KLASS2 ")" HS_METHOD, FN_PTR(resolveMethod)}, + {CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL2 "I)" HS_KLASS, FN_PTR(resolveTypeInPool)}, + {CC "setCountersSize", CC "(I)Z", FN_PTR(setCountersSize)}, + {CC "setNotInlinableOrCompilable", CC "(" HS_METHOD2 ")V", FN_PTR(setNotInlinableOrCompilable)}, {CC "setThreadLocalLong", CC "(IJ)V", FN_PTR(setThreadLocalLong)}, - {CC "registerCompilerPhase", CC "(" STRING ")I", FN_PTR(registerCompilerPhase)}, - {CC "notifyCompilerPhaseEvent", CC "(JIII)V", FN_PTR(notifyCompilerPhaseEvent)}, - {CC "notifyCompilerInliningEvent", CC "(I" HS_METHOD2 HS_METHOD2 "ZLjava/lang/String;I)V", FN_PTR(notifyCompilerInliningEvent)}, - {CC "getOopMapAt", CC "(" HS_METHOD2 "I[J)V", FN_PTR(getOopMapAt)}, + {CC "setThreadLocalObject", CC "(I" OBJECT ")V", FN_PTR(setThreadLocalObject)}, + {CC "shouldDebugNonSafepoints", CC "()Z", FN_PTR(shouldDebugNonSafepoints)}, + {CC "shouldInlineMethod", CC "(" HS_METHOD2 ")Z", FN_PTR(shouldInlineMethod)}, + {CC "ticksNow", CC "()J", FN_PTR(ticksNow)}, + {CC "translate", CC "(" OBJECT "Z)J", FN_PTR(translate)}, + {CC "unboxPrimitive", CC "(" OBJECTCONSTANT ")" OBJECT, FN_PTR(unboxPrimitive)}, + {CC "unhand", CC "(J)" OBJECT, FN_PTR(unhand)}, {CC "updateCompilerThreadCanCallJava", CC "(Z)Z", FN_PTR(updateCompilerThreadCanCallJava)}, - {CC "getCompilationActivityMode", CC "()I", FN_PTR(getCompilationActivityMode)}, - {CC "isCompilerThread", CC "()Z", FN_PTR(isCompilerThread)}, + {CC "updateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(updateHotSpotNmethod)}, + {CC "writeDebugOutput", CC "(JIZ)V", FN_PTR(writeDebugOutput)}, }; int CompilerToVM::methods_count() { From 5240275cd76d4fd68ea708bde1be1f85fc3cf9aa Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 29 Aug 2025 06:38:26 +0200 Subject: [PATCH 18/20] filter out TypeAnnotations that have a null annotation --- .../classes/jdk/internal/vm/VMSupport.java | 14 +++++++++-- .../runtime/test/TestResolvedJavaField.java | 10 ++++---- .../runtime/test/TestResolvedJavaMethod.java | 10 ++++---- .../test/TestResolvedJavaRecordComponent.java | 13 ++++------- .../ci/runtime/test/TestResolvedJavaType.java | 23 +++++++++++++------ .../AnnotationTestInput.java | 11 ++++++++- .../TestAnnotationEncodingDecoding.java | 1 + 7 files changed, 52 insertions(+), 30 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index 4fc290a7a7c2c..41cbbbb3cb053 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -468,9 +468,19 @@ private static void encodeMemberValue(DataOutputStream dos, Object value) throws * @param dos stream for assembling the byte array */ public static void encodeTypeAnnotations(DataOutputStream dos, TypeAnnotation[] typeAnnotations) throws IOException { - writeLength(dos, typeAnnotations.length); + int wellFormed = 0; for (TypeAnnotation ta : typeAnnotations) { - encodeTypeAnnotation(dos, ta); + // Ignore not well-formed type annotations like + // TypeAnnotationParser.mapTypeAnnotations does + if (ta.getAnnotation() != null) { + wellFormed++; + } + } + writeLength(dos, wellFormed); + for (TypeAnnotation ta : typeAnnotations) { + if (ta.getAnnotation() != null) { + encodeTypeAnnotation(dos, ta); + } } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java index 87cee916f5ec1..7820a5b67c664 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java @@ -31,6 +31,7 @@ * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java * TestResolvedJavaType.java * @clean jdk.internal.vm.test.AnnotationTestInput$Missing + * jdk.internal.vm.test.AnnotationTestInput$MissingTypeQualifier * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java @@ -62,7 +63,6 @@ import org.junit.Assert; import org.junit.Test; import sun.reflect.annotation.TypeAnnotation; -import sun.reflect.annotation.TypeAnnotationParser; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -207,19 +207,17 @@ private Method findTestMethod(Method apiMethod) { */ private static void getTypeAnnotationValuesTest(Field field) { ResolvedJavaField javaField = metaAccess.lookupJavaField(field); - TypeAnnotation[] typeAnnotations = getTypeAnnotations(field); + List typeAnnotations = getTypeAnnotations(field); List typeAnnotationValues = javaField.getTypeAnnotationValues(); TestResolvedJavaType.assertTypeAnnotationsEquals(typeAnnotations, typeAnnotationValues); } private static final Method fieldGetTypeAnnotationBytes = lookupMethod(Field.class, "getTypeAnnotationBytes0"); - private static final Method classGetConstantPool = lookupMethod(Class.class, "getConstantPool"); - private static TypeAnnotation[] getTypeAnnotations(Field f) { + private static List getTypeAnnotations(Field f) { byte[] rawAnnotations = invokeMethod(fieldGetTypeAnnotationBytes, f); Class container = f.getDeclaringClass(); - jdk.internal.reflect.ConstantPool cp = invokeMethod(classGetConstantPool, container); - return TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, container); + return TestResolvedJavaType.getTypeAnnotations(rawAnnotations, container); } @Test diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index ea85f8f48f2d6..47f970de4bd72 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -31,6 +31,7 @@ * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java * TestResolvedJavaType.java * @clean jdk.internal.vm.test.AnnotationTestInput$Missing + * jdk.internal.vm.test.AnnotationTestInput$MissingTypeQualifier * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java @@ -69,7 +70,6 @@ import org.junit.Test; import sun.reflect.annotation.TypeAnnotation; -import sun.reflect.annotation.TypeAnnotationParser; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; @@ -603,7 +603,7 @@ static void methodWithThreeAnnotations() { */ private static void getTypeAnnotationValuesTest(Executable executable) { ResolvedJavaMethod method = metaAccess.lookupJavaMethod(executable); - TypeAnnotation[] typeAnnotations = getTypeAnnotations(executable); + List typeAnnotations = getTypeAnnotations(executable); List typeAnnotationValues = method.getTypeAnnotationValues(); TestResolvedJavaType.assertTypeAnnotationsEquals(typeAnnotations, typeAnnotationValues); } @@ -669,13 +669,11 @@ public static void assertParameterAnnotationsEquals( } private static final Method executableGetTypeAnnotationBytes = lookupMethod(Executable.class, "getTypeAnnotationBytes"); - private static final Method classGetConstantPool = lookupMethod(Class.class, "getConstantPool"); - private static TypeAnnotation[] getTypeAnnotations(Executable e) { + private static List getTypeAnnotations(Executable e) { byte[] rawAnnotations = invokeMethod(executableGetTypeAnnotationBytes, e); Class container = e.getDeclaringClass(); - jdk.internal.reflect.ConstantPool cp = invokeMethod(classGetConstantPool, container); - return TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, container); + return TestResolvedJavaType.getTypeAnnotations(rawAnnotations, container); } @Test diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java index 832f04bdc8f83..e0299c85769db 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java @@ -31,6 +31,7 @@ * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java * TestResolvedJavaType.java * @clean jdk.internal.vm.test.AnnotationTestInput$Missing + * jdk.internal.vm.test.AnnotationTestInput$MissingTypeQualifier * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java @@ -50,7 +51,6 @@ package jdk.vm.ci.runtime.test; -import jdk.internal.vm.test.AnnotationTestInput; import jdk.internal.vm.test.AnnotationTestInput.AnnotatedRecord; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -59,7 +59,6 @@ import jdk.vm.ci.meta.annotation.TypeAnnotationValue; import org.junit.Test; import sun.reflect.annotation.TypeAnnotation; -import sun.reflect.annotation.TypeAnnotationParser; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -141,7 +140,7 @@ public void getAnnotationValuesTest() { */ private static void getTypeAnnotationValuesTest(RecordComponent rc) { ResolvedJavaRecordComponent resolvedRc = metaAccess.lookupJavaRecordComponent(rc); - TypeAnnotation[] typeAnnotations = getTypeAnnotations(rc); + List typeAnnotations = getTypeAnnotations(rc); List typeAnnotationValues = resolvedRc.getTypeAnnotationValues(); TestResolvedJavaType.assertTypeAnnotationsEquals(typeAnnotations, typeAnnotationValues); if (!typeAnnotationValues.isEmpty()) { @@ -150,13 +149,11 @@ private static void getTypeAnnotationValuesTest(RecordComponent rc) { } private static final Field recordComponentTypeAnnotations = lookupField(RecordComponent.class, "typeAnnotations"); - private static final Method classGetConstantPool = lookupMethod(Class.class, "getConstantPool"); - private static TypeAnnotation[] getTypeAnnotations(RecordComponent rc) { - byte[] rawAnnotations = getFieldValue(recordComponentTypeAnnotations, rc); + private static List getTypeAnnotations(RecordComponent rc) { Class container = rc.getDeclaringRecord(); - jdk.internal.reflect.ConstantPool cp = invokeMethod(classGetConstantPool, container); - return TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, container); + byte[] rawAnnotations = getFieldValue(recordComponentTypeAnnotations, rc); + return TestResolvedJavaType.getTypeAnnotations(rawAnnotations, container); } @Test diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index c889ffbf819a7..7d8be53ccfdf4 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -31,6 +31,7 @@ * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java * @clean jdk.internal.vm.test.AnnotationTestInput$Missing + * jdk.internal.vm.test.AnnotationTestInput$MissingTypeQualifier * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberAdded.java * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java @@ -1249,6 +1250,7 @@ private Method findTestMethod(Method apiMethod) { @Test public void getTypeAnnotationValuesTest() { getTypeAnnotationValuesTest(AnnotationTestInput.AnnotatedClass.class); + getTypeAnnotationValuesTest(AnnotationTestInput.AnnotatedClass2.class); getTypeAnnotationValuesTest(int.class); getTypeAnnotationValuesTest(void.class); for (Class c : classes) { @@ -1268,15 +1270,22 @@ private static void getTypeAnnotationValuesTest(Class cls) { private static final Method classGetRawTypeAnnotations = lookupMethod(Class.class, "getRawTypeAnnotations"); private static final Method classGetConstantPool = lookupMethod(Class.class, "getConstantPool"); - private static TypeAnnotation[] getTypeAnnotations(Class c) { + private static List getTypeAnnotations(Class c) { byte[] rawAnnotations = invokeMethod(classGetRawTypeAnnotations, c); - ConstantPool cp = invokeMethod(classGetConstantPool, c); - return TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, c); + return getTypeAnnotations(rawAnnotations, c); + } + + public static List getTypeAnnotations(byte[] rawAnnotations, Class container) { + ConstantPool cp = invokeMethod(classGetConstantPool, container); + return Stream.of(TypeAnnotationParser.parseTypeAnnotations(rawAnnotations, cp, null, false, container)) + .filter(ta -> ta.getAnnotation() != null) + .toList(); } @Test public void getAnnotationValuesTest() { getAnnotationValuesTest(AnnotationTestInput.AnnotatedClass.class); + getAnnotationValuesTest(AnnotationTestInput.AnnotatedClass2.class); getAnnotationValuesTest(int.class); getAnnotationValuesTest(void.class); for (Class c : classes) { @@ -1383,11 +1392,11 @@ public static List getAnnotationValuesTest(AnnotatedElement ann } public static void assertTypeAnnotationsEquals( - TypeAnnotation[] typeAnnotations, + List typeAnnotations, List typeAnnotationValues) throws AssertionError { - assertEquals(typeAnnotations.length, typeAnnotationValues.size()); - for (int i = 0; i < typeAnnotations.length; i++) { - TypeAnnotation typeAnnotation = typeAnnotations[i]; + assertEquals(typeAnnotations.size(), typeAnnotationValues.size()); + for (int i = 0; i < typeAnnotations.size(); i++) { + TypeAnnotation typeAnnotation = typeAnnotations.get(i); TypeAnnotationValue typeAnnotationValue = typeAnnotationValues.get(i); assertTypeAnnotationEquals(typeAnnotation, typeAnnotationValue); } diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java index 56d7eb9adf042..c3ca96387ec85 100644 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java @@ -30,6 +30,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; +import java.util.function.Predicate; public class AnnotationTestInput { @@ -177,7 +178,9 @@ public static class InheritedName3 extends Super3 {} @SuppressWarnings({"rawtypes", "all"}) public static class AnnotatedClass extends @TypeQualifier Thread implements @TypeQualifier Serializable {} - public static record AnnotatedRecord(@TypeQualifier @Named("obj1Component Name") String obj1Component, @Missing @NestedAnno("int1 value") int int1Component, @Missing float componentWithMissingAnno) {} + public record AnnotatedRecord(@TypeQualifier @Named("obj1Component Name") String obj1Component, @Missing @NestedAnno("int1 value") int int1Component, @Missing float componentWithMissingAnno) {} + + public static abstract class AnnotatedClass2 implements Predicate<@MissingTypeQualifier T> {} @Single(string = "a", stringArray = {"a", "b"}, @@ -248,6 +251,12 @@ public static record AnnotatedRecord(@TypeQualifier @Named("obj1Component Name") String comment() default ""; } + // Define a type-use annotation that is missing at runtime + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + @interface MissingTypeQualifier { + } + @Retention(RetentionPolicy.RUNTIME) public @interface NestedAnno { String value(); diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java index d9a5069789a81..833e0b825df82 100644 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java +++ b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java @@ -27,6 +27,7 @@ * @modules java.base/jdk.internal.vm * java.base/sun.reflect.annotation * @clean jdk.internal.vm.test.AnnotationTestInput$Missing + * jdk.internal.vm.test.AnnotationTestInput$MissingTypeQualifier * @compile alt/MemberDeleted.java alt/MemberTypeChanged.java * @run testng/othervm * jdk.internal.vm.test.TestAnnotationEncodingDecoding From e476f3d6552b9170b1a67ef51d651fa23453fe2c Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 2 Sep 2025 16:45:00 +0200 Subject: [PATCH 19/20] show cause of JVMCI API version error --- .../share/classes/jdk/vm/ci/runtime/JVMCI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCI.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCI.java index d07df2ba75d26..dff90a35e5624 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCI.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCI.java @@ -69,7 +69,7 @@ public static JVMCIRuntime getRuntime() { errorMessage.format("The VM does not support the JVMCI API.%n"); errorMessage.format("Currently used Java home directory is %s.%n", javaHome); errorMessage.format("Currently used VM configuration is: %s", vmName); - throw new UnsupportedOperationException(errorMessage.toString()); + throw new UnsupportedOperationException(errorMessage.toString(), e); } finally { initializing = false; } From a17db67ee4b582871f2e7999cad9b641bff740b0 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 4 Sep 2025 09:28:06 +0200 Subject: [PATCH 20/20] preserve class file order of annotations --- .../meta/annotation/AnnotationValueDecoder.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValueDecoder.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValueDecoder.java index df316e0395009..b0f694a5712be 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValueDecoder.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationValueDecoder.java @@ -30,10 +30,10 @@ import jdk.vm.ci.meta.UnresolvedJavaType; import sun.reflect.annotation.TypeAnnotation; +import java.lang.reflect.AnnotatedElement; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; /** * Implementation of {@link AnnotationDecoder} that resolves type names to {@link JavaType} values @@ -44,9 +44,18 @@ public final class AnnotationValueDecoder implements AnnotationDecoder decode(byte[] encoded) { List annotationValues = VMSupport.decodeAnnotations(encoded, this); - return annotationValues.stream().collect(Collectors.toMap(AnnotationValue::getAnnotationType, Function.identity())); + Map result = new LinkedHashMap<>(annotationValues.size()); + for (AnnotationValue av : annotationValues) { + result.put(av.getAnnotationType(), av); + } + return result; } public AnnotationValueDecoder(ResolvedJavaType accessingClass) {