From 2315e740650c8ec0a5bf90d0672a1c684dee306d Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Mon, 21 Jul 2025 15:42:37 +0200 Subject: [PATCH 1/7] 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 | 99 ++++++++++++---- .../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(+), 197 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..f69ab7de56c6d 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; @@ -267,6 +294,10 @@ private static Annotation parseAnnotation2(ByteBuffer buf, Map> memberTypes = type.memberTypes(); Map memberValues = new LinkedHashMap(type.memberDefaults()); + 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 +309,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 +357,29 @@ 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; + Object value = parseEnumValue(enumType, buf, constPool, container, eagerResolution); + return eagerResolution ? value : new EnumValue(enumType, (String) value); 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 +489,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 +506,11 @@ private static Object parseEnumValue(Class enumType, ByteBuffer return new AnnotationTypeMismatchExceptionProxy( typeName.substring(1, typeName.length() - 1).replace('/', '.') + "." + constName); } - + if (!resolve) { + return constName; + } try { - return Enum.valueOf(enumType, constName); + return Enum.valueOf(enumType, constName); } catch(IllegalArgumentException e) { return new EnumConstantNotPresentExceptionProxy( (Class>)enumType, constName); @@ -495,7 +535,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 +565,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 +756,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', () -> parseEnumValue(enumType, buf, constPool, container, false)); + 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..283c8edd77b74 --- /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") + 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 6bc974f890f30cc2afb95ff4874b4489e52affc2 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 11:29:13 +0200 Subject: [PATCH 2/7] 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 f69ab7de56c6d..5a476559ee4ce 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 1d7d8aa42184b0245d97f5c7a2ffa1e596125e11 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 11:59:44 +0200 Subject: [PATCH 3/7] 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 827f9735e5e03aceba303e197846cbddb6a133cb Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 15:54:01 +0200 Subject: [PATCH 4/7] 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 391838dae3cfeee6ccfdfffa6d8b55db05a84012 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 16:08:08 +0200 Subject: [PATCH 5/7] model precise annotation parsing error types --- .../classes/jdk/internal/vm/VMSupport.java | 66 ++++++++++-------- .../reflect/annotation/AnnotationParser.java | 3 +- .../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 +++++++++++++--- 10 files changed, 205 insertions(+), 75 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/AnnotationParser.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java index 5a476559ee4ce..ff34ba4dc01f8 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java @@ -291,8 +291,7 @@ private static Annotation parseAnnotation2(ByteBuffer buf, } Map> memberTypes = type.memberTypes(); - Map memberValues = - new LinkedHashMap(type.memberDefaults()); + Map memberValues = new LinkedHashMap<>(type.memberDefaults()); for (var e : type.memberDefaults().entrySet()) { Object value = e.getValue(); memberValues.put(e.getKey(), eagerResolution ? ResolvableValue.resolved(value) : value); 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 0f12d97fe49841a4c9cb5c4a25c89cbee86e698d Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 19:49:58 +0200 Subject: [PATCH 6/7] 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 de8c8c2a8f711bbfb1dabc95afb2babaddaae7f2 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Aug 2025 20:36:02 +0200 Subject: [PATCH 7/7] 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 +++--- 9 files changed, 87 insertions(+), 43 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);