Skip to content

Commit 48fd4f2

Browse files
author
Doug Simon
committedApr 19, 2023
8303431: [JVMCI] libgraal annotation API
Reviewed-by: kvn, never, darcy
1 parent c57af31 commit 48fd4f2

34 files changed

+2298
-51
lines changed
 

‎src/hotspot/share/classfile/vmSymbols.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,8 @@
756756
template(encodeThrowable_name, "encodeThrowable") \
757757
template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \
758758
template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \
759+
template(encodeAnnotations_name, "encodeAnnotations") \
760+
template(encodeAnnotations_signature, "([BLjava/lang/Class;Ljdk/internal/reflect/ConstantPool;Z[Ljava/lang/Class;)[B")\
759761
template(decodeAndThrowThrowable_signature, "(JZ)V") \
760762
template(classRedefinedCount_name, "classRedefinedCount") \
761763
template(classLoader_name, "classLoader") \

‎src/hotspot/share/jvmci/jvmciCompilerToVM.cpp

+93-3
Original file line numberDiff line numberDiff line change
@@ -2672,9 +2672,7 @@ C2V_VMENTRY_NULL(jobject, asReflectionExecutable, (JNIEnv* env, jobject, ARGUMEN
26722672
return JNIHandles::make_local(THREAD, executable);
26732673
}
26742674

2675-
C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index))
2676-
requireInHotSpot("asReflectionField", JVMCI_CHECK_NULL);
2677-
Klass* klass = UNPACK_PAIR(Klass, klass);
2675+
static InstanceKlass* check_field(Klass* klass, jint index, JVMCI_TRAPS) {
26782676
if (!klass->is_instance_klass()) {
26792677
JVMCI_THROW_MSG_NULL(IllegalArgumentException,
26802678
err_msg("Expected non-primitive type, got %s", klass->external_name()));
@@ -2684,11 +2682,100 @@ C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAI
26842682
JVMCI_THROW_MSG_NULL(IllegalArgumentException,
26852683
err_msg("Field index %d out of bounds for %s", index, klass->external_name()));
26862684
}
2685+
return iklass;
2686+
}
2687+
2688+
C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index))
2689+
requireInHotSpot("asReflectionField", JVMCI_CHECK_NULL);
2690+
Klass* klass = UNPACK_PAIR(Klass, klass);
2691+
InstanceKlass* iklass = check_field(klass, index, JVMCIENV);
26872692
fieldDescriptor fd(iklass, index);
26882693
oop reflected = Reflection::new_field(&fd, CHECK_NULL);
26892694
return JNIHandles::make_local(THREAD, reflected);
26902695
}
26912696

2697+
static jbyteArray get_encoded_annotation_data(InstanceKlass* holder, AnnotationArray* annotations_array, bool for_class,
2698+
jint filter_length, jlong filter_klass_pointers,
2699+
JavaThread* THREAD, JVMCIEnv* JVMCIENV) {
2700+
// Get a ConstantPool object for annotation parsing
2701+
Handle jcp = reflect_ConstantPool::create(CHECK_NULL);
2702+
reflect_ConstantPool::set_cp(jcp(), holder->constants());
2703+
2704+
// load VMSupport
2705+
Symbol* klass = vmSymbols::jdk_internal_vm_VMSupport();
2706+
Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK_NULL);
2707+
2708+
InstanceKlass* vm_support = InstanceKlass::cast(k);
2709+
if (vm_support->should_be_initialized()) {
2710+
vm_support->initialize(CHECK_NULL);
2711+
}
2712+
2713+
typeArrayOop annotations_oop = Annotations::make_java_array(annotations_array, CHECK_NULL);
2714+
typeArrayHandle annotations = typeArrayHandle(THREAD, annotations_oop);
2715+
2716+
InstanceKlass** filter = filter_length == 1 ?
2717+
(InstanceKlass**) &filter_klass_pointers:
2718+
(InstanceKlass**) filter_klass_pointers;
2719+
objArrayOop filter_oop = oopFactory::new_objectArray(filter_length, CHECK_NULL);
2720+
objArrayHandle filter_classes(THREAD, filter_oop);
2721+
for (int i = 0; i < filter_length; i++) {
2722+
filter_classes->obj_at_put(i, filter[i]->java_mirror());
2723+
}
2724+
2725+
// invoke VMSupport.encodeAnnotations
2726+
JavaValue result(T_OBJECT);
2727+
JavaCallArguments args;
2728+
args.push_oop(annotations);
2729+
args.push_oop(Handle(THREAD, holder->java_mirror()));
2730+
args.push_oop(jcp);
2731+
args.push_int(for_class);
2732+
args.push_oop(filter_classes);
2733+
Symbol* signature = vmSymbols::encodeAnnotations_signature();
2734+
JavaCalls::call_static(&result,
2735+
vm_support,
2736+
vmSymbols::encodeAnnotations_name(),
2737+
signature,
2738+
&args,
2739+
CHECK_NULL);
2740+
2741+
oop res = result.get_oop();
2742+
if (JVMCIENV->is_hotspot()) {
2743+
return (jbyteArray) JNIHandles::make_local(THREAD, res);
2744+
}
2745+
2746+
typeArrayOop ba = typeArrayOop(res);
2747+
int ba_len = ba->length();
2748+
jbyte* ba_buf = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, jbyte, ba_len);
2749+
if (ba_buf == nullptr) {
2750+
JVMCI_THROW_MSG_NULL(InternalError,
2751+
err_msg("could not allocate %d bytes", ba_len));
2752+
2753+
}
2754+
memcpy(ba_buf, ba->byte_at_addr(0), ba_len);
2755+
JVMCIPrimitiveArray ba_dest = JVMCIENV->new_byteArray(ba_len, JVMCI_CHECK_NULL);
2756+
JVMCIENV->copy_bytes_from(ba_buf, ba_dest, 0, ba_len);
2757+
return JVMCIENV->get_jbyteArray(ba_dest);
2758+
}
2759+
2760+
C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass),
2761+
jobject filter, jint filter_length, jlong filter_klass_pointers))
2762+
InstanceKlass* holder = InstanceKlass::cast(UNPACK_PAIR(Klass, klass));
2763+
return get_encoded_annotation_data(holder, holder->class_annotations(), true, filter_length, filter_klass_pointers, THREAD, JVMCIENV);
2764+
C2V_END
2765+
2766+
C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(method),
2767+
jobject filter, jint filter_length, jlong filter_klass_pointers))
2768+
methodHandle method(THREAD, UNPACK_PAIR(Method, method));
2769+
return get_encoded_annotation_data(method->method_holder(), method->annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV);
2770+
C2V_END
2771+
2772+
C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index,
2773+
jobject filter, jint filter_length, jlong filter_klass_pointers))
2774+
InstanceKlass* holder = check_field(InstanceKlass::cast(UNPACK_PAIR(Klass, klass)), index, JVMCIENV);
2775+
fieldDescriptor fd(holder, index);
2776+
return get_encoded_annotation_data(holder, fd.annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV);
2777+
C2V_END
2778+
26922779
C2V_VMENTRY_NULL(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current))
26932780
FailedSpeculation* head = *((FailedSpeculation**)(address) failed_speculations_address);
26942781
int result_length = 0;
@@ -2969,6 +3056,9 @@ JNINativeMethod CompilerToVM::methods[] = {
29693056
{CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)},
29703057
{CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" REFLECTION_EXECUTABLE, FN_PTR(asReflectionExecutable)},
29713058
{CC "asReflectionField", CC "(" HS_KLASS2 "I)" REFLECTION_FIELD, FN_PTR(asReflectionField)},
3059+
{CC "getEncodedClassAnnotationData", CC "(" HS_KLASS2 OBJECT "IJ)[B", FN_PTR(getEncodedClassAnnotationData)},
3060+
{CC "getEncodedExecutableAnnotationData", CC "(" HS_METHOD2 OBJECT "IJ)[B", FN_PTR(getEncodedExecutableAnnotationData)},
3061+
{CC "getEncodedFieldAnnotationData", CC "(" HS_KLASS2 "I" OBJECT "IJ)[B", FN_PTR(getEncodedFieldAnnotationData)},
29723062
{CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)},
29733063
{CC "getFailedSpeculationsAddress", CC "(" HS_METHOD2 ")J", FN_PTR(getFailedSpeculationsAddress)},
29743064
{CC "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)},

‎src/hotspot/share/jvmci/vmStructs_jvmci.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
\
105105
static_field(Abstract_VM_Version, _features, uint64_t) \
106106
\
107+
nonstatic_field(Annotations, _class_annotations, AnnotationArray*) \
107108
nonstatic_field(Annotations, _fields_annotations, Array<AnnotationArray*>*) \
108109
\
109110
nonstatic_field(Array<int>, _length, int) \

‎src/java.base/share/classes/jdk/internal/vm/VMSupport.java

+418-6
Large diffs are not rendered by default.

‎src/java.base/share/classes/module-info.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@
259259
jdk.incubator.concurrent,
260260
jdk.internal.jvmstat,
261261
jdk.management,
262-
jdk.management.agent;
262+
jdk.management.agent,
263+
jdk.internal.vm.ci;
263264
exports jdk.internal.vm.annotation to
264265
java.instrument,
265266
jdk.internal.vm.ci,

‎src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java

+7
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,13 @@ private void readObject(java.io.ObjectInputStream s)
677677
UnsafeAccessor.setMemberValues(this, mv);
678678
}
679679

680+
/**
681+
* Gets an unmodifiable view on the member values.
682+
*/
683+
Map<String, Object> memberValues() {
684+
return Collections.unmodifiableMap(memberValues);
685+
}
686+
680687
private static class UnsafeAccessor {
681688
private static final jdk.internal.misc.Unsafe unsafe
682689
= jdk.internal.misc.Unsafe.getUnsafe();

‎src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,14 @@ public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
8383
* Like {@link #parseAnnotations(byte[], sun.reflect.ConstantPool, Class)}
8484
* with an additional parameter {@code selectAnnotationClasses} which selects the
8585
* annotation types to parse (other than selected are quickly skipped).<p>
86-
* This method is only used to parse select meta annotations in the construction
86+
* This method is used to parse select meta annotations in the construction
8787
* phase of {@link AnnotationType} instances to prevent infinite recursion.
8888
*
8989
* @param selectAnnotationClasses an array of annotation types to select when parsing
9090
*/
9191
@SafeVarargs
9292
@SuppressWarnings("varargs") // selectAnnotationClasses is used safely
93-
static Map<Class<? extends Annotation>, Annotation> parseSelectAnnotations(
93+
public static Map<Class<? extends Annotation>, Annotation> parseSelectAnnotations(
9494
byte[] rawAnnotations,
9595
ConstantPool constPool,
9696
Class<?> container,
@@ -336,6 +336,8 @@ public static Object parseMemberValue(Class<?> memberType,
336336
ByteBuffer buf,
337337
ConstantPool constPool,
338338
Class<?> container) {
339+
// Note that VMSupport.encodeAnnotation (used by JVMCI) may need to
340+
// be updated if new annotation member types are added.
339341
Object result = null;
340342
int tag = buf.get();
341343
switch(tag) {

‎src/java.base/share/classes/sun/reflect/annotation/AnnotationSupport.java

+9
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,13 @@ private static <A extends Annotation> void checkTypes(A[] annotations,
281281
}
282282
}
283283
}
284+
285+
/**
286+
* Gets an unmodifiable view of {@code a}'s elements.
287+
*
288+
* @return a map from element names to element values
289+
*/
290+
public static Map<String, Object> memberValues(Annotation a) {
291+
return ((AnnotationInvocationHandler) Proxy.getInvocationHandler(a)).memberValues();
292+
}
284293
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.vm.ci.hotspot;
24+
25+
import java.util.Map;
26+
27+
import jdk.internal.vm.VMSupport.AnnotationDecoder;
28+
import jdk.vm.ci.meta.AnnotationData;
29+
import jdk.vm.ci.meta.EnumData;
30+
import jdk.vm.ci.meta.ErrorData;
31+
import jdk.vm.ci.meta.JavaType;
32+
import jdk.vm.ci.meta.MetaUtil;
33+
import jdk.vm.ci.meta.ResolvedJavaType;
34+
import jdk.vm.ci.meta.UnresolvedJavaType;
35+
36+
/**
37+
* Implementation of {@link AnnotationDecoder} that resolves type names to {@link JavaType} values
38+
* and employs {@link AnnotationData} and {@link EnumData} to represent decoded annotations and enum
39+
* constants respectively.
40+
*/
41+
final class AnnotationDataDecoder implements AnnotationDecoder<JavaType, AnnotationData, EnumData, ErrorData> {
42+
43+
static final AnnotationDataDecoder INSTANCE = new AnnotationDataDecoder();
44+
45+
@Override
46+
public JavaType resolveType(String name) {
47+
String internalName = MetaUtil.toInternalName(name);
48+
return UnresolvedJavaType.create(internalName);
49+
}
50+
51+
@Override
52+
public AnnotationData newAnnotation(JavaType type, Map.Entry<String, Object>[] elements) {
53+
return new AnnotationData(type, elements);
54+
}
55+
56+
@Override
57+
public EnumData newEnumValue(JavaType enumType, String name) {
58+
return new EnumData(enumType, name);
59+
}
60+
61+
@Override
62+
public ErrorData newErrorValue(String description) {
63+
return new ErrorData(description);
64+
}
65+
66+
static ResolvedJavaType[] asArray(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) {
67+
ResolvedJavaType[] filter = new ResolvedJavaType[2 + types.length];
68+
filter[0] = type1;
69+
filter[1] = type2;
70+
System.arraycopy(types, 0, filter, 2, types.length);
71+
return filter;
72+
}
73+
}

‎src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java

+92
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.lang.reflect.Executable;
3030
import java.lang.reflect.Field;
3131

32+
import jdk.internal.misc.Unsafe;
3233
import jdk.vm.ci.code.BytecodeFrame;
3334
import jdk.vm.ci.code.InstalledCode;
3435
import jdk.vm.ci.code.InvalidInstalledCodeException;
@@ -48,6 +49,12 @@
4849
* Calls from Java into HotSpot. The behavior of all the methods in this class that take a native
4950
* pointer as an argument (e.g., {@link #getSymbol(long)}) is undefined if the argument does not
5051
* denote a valid native object.
52+
*
53+
* Note also that some calls pass a raw VM value to avoid a JNI upcall. For example,
54+
* {@link #getBytecode(HotSpotResolvedJavaMethodImpl, long)} needs the raw {@code Method*} value
55+
* (stored in {@link HotSpotResolvedJavaMethodImpl#methodHandle}) in the C++ implementation. The
56+
* {@link HotSpotResolvedJavaMethodImpl} wrapper is still passed as well as it may be the last
57+
* reference keeping the raw value alive.
5158
*/
5259
final class CompilerToVM {
5360
/**
@@ -1303,4 +1310,89 @@ void notifyCompilerInliningEvent(int compileId, HotSpotResolvedJavaMethodImpl ca
13031310

13041311
native void notifyCompilerInliningEvent(int compileId, HotSpotResolvedJavaMethodImpl caller, long callerPointer,
13051312
HotSpotResolvedJavaMethodImpl callee, long calleePointer, boolean succeeded, String message, int bci);
1313+
1314+
/**
1315+
* Gets the serialized annotation info for {@code type} by calling
1316+
* {@code VMSupport.encodeAnnotations} in the HotSpot heap.
1317+
*/
1318+
byte[] getEncodedClassAnnotationData(HotSpotResolvedObjectTypeImpl type, ResolvedJavaType[] filter) {
1319+
try (KlassPointers a = new KlassPointers(filter)) {
1320+
return getEncodedClassAnnotationData(type, type.getKlassPointer(),
1321+
a.types, a.types.length, a.buffer());
1322+
}
1323+
}
1324+
1325+
native byte[] getEncodedClassAnnotationData(HotSpotResolvedObjectTypeImpl type, long klassPointer,
1326+
Object filter, int filterLength, long filterKlassPointers);
1327+
1328+
/**
1329+
* Gets the serialized annotation info for {@code method} by calling
1330+
* {@code VMSupport.encodeAnnotations} in the HotSpot heap.
1331+
*/
1332+
byte[] getEncodedExecutableAnnotationData(HotSpotResolvedJavaMethodImpl method, ResolvedJavaType[] filter) {
1333+
try (KlassPointers a = new KlassPointers(filter)) {
1334+
return getEncodedExecutableAnnotationData(method, method.getMethodPointer(),
1335+
a.types, a.types.length, a.buffer());
1336+
}
1337+
}
1338+
1339+
native byte[] getEncodedExecutableAnnotationData(HotSpotResolvedJavaMethodImpl method, long methodPointer,
1340+
Object filter, int filterLength, long filterKlassPointers);
1341+
1342+
/**
1343+
* Gets the serialized annotation info for the field denoted by {@code holder} and
1344+
* {@code fieldIndex} by calling {@code VMSupport.encodeAnnotations} in the HotSpot heap.
1345+
*/
1346+
byte[] getEncodedFieldAnnotationData(HotSpotResolvedObjectTypeImpl holder, int fieldIndex, ResolvedJavaType[] filter) {
1347+
try (KlassPointers a = new KlassPointers(filter)) {
1348+
return getEncodedFieldAnnotationData(holder, holder.getKlassPointer(), fieldIndex,
1349+
a.types, a.types.length, a.buffer());
1350+
}
1351+
}
1352+
1353+
native byte[] getEncodedFieldAnnotationData(HotSpotResolvedObjectTypeImpl holder, long klassPointer, int fieldIndex,
1354+
Object filterTypes, int filterLength, long filterKlassPointers);
1355+
1356+
/**
1357+
* Helper for passing {@Klass*} values to native code.
1358+
*/
1359+
static final class KlassPointers implements AutoCloseable {
1360+
final ResolvedJavaType[] types;
1361+
long pointersArray;
1362+
final Unsafe unsafe = UnsafeAccess.UNSAFE;
1363+
1364+
KlassPointers(ResolvedJavaType[] types) {
1365+
this.types = types;
1366+
}
1367+
1368+
/**
1369+
* Gets the buffer in which to pass the {@Klass*} values to JNI.
1370+
*
1371+
* @return a {@Klass*} value if {@code types.length == 1} otherwise the address of a native
1372+
* buffer holding an array of {@Klass*} values
1373+
*/
1374+
long buffer() {
1375+
int length = types.length;
1376+
if (length == 1) {
1377+
return ((HotSpotResolvedObjectTypeImpl) types[0]).getKlassPointer();
1378+
} else {
1379+
pointersArray = unsafe.allocateMemory(length * Long.BYTES);
1380+
long pos = pointersArray;
1381+
for (int i = 0; i < types.length; i++) {
1382+
HotSpotResolvedObjectTypeImpl hsType = (HotSpotResolvedObjectTypeImpl) types[i];
1383+
unsafe.putLong(pos, hsType.getKlassPointer());
1384+
pos += Long.BYTES;
1385+
}
1386+
}
1387+
return pointersArray;
1388+
}
1389+
1390+
@Override
1391+
public void close() {
1392+
if (types.length != 1 && pointersArray != 0) {
1393+
unsafe.freeMemory(pointersArray);
1394+
pointersArray = 0;
1395+
}
1396+
}
1397+
}
13061398
}

‎src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java

+26-2
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,17 @@
2323
package jdk.vm.ci.hotspot;
2424

2525
import static jdk.internal.misc.Unsafe.ADDRESS_SIZE;
26+
import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
2627
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
2728
import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
2829
import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
2930

3031
import java.lang.annotation.Annotation;
32+
import java.util.Collections;
33+
import java.util.List;
3134

32-
import jdk.internal.vm.annotation.Stable;
33-
35+
import jdk.internal.vm.VMSupport;
36+
import jdk.vm.ci.meta.AnnotationData;
3437
import jdk.vm.ci.meta.JavaConstant;
3538
import jdk.vm.ci.meta.JavaType;
3639
import jdk.vm.ci.meta.ResolvedJavaType;
@@ -227,4 +230,25 @@ public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
227230
public JavaConstant getConstantValue() {
228231
return holder.getFieldInfo(index).getConstantValue(holder);
229232
}
233+
234+
@Override
235+
public AnnotationData getAnnotationData(ResolvedJavaType annotationType) {
236+
if (!hasAnnotations()) {
237+
return null;
238+
}
239+
return getAnnotationData0(annotationType).get(0);
240+
}
241+
242+
@Override
243+
public List<AnnotationData> getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) {
244+
if (!hasAnnotations()) {
245+
return Collections.emptyList();
246+
}
247+
return getAnnotationData0(AnnotationDataDecoder.asArray(type1, type2, types));
248+
}
249+
250+
private List<AnnotationData> getAnnotationData0(ResolvedJavaType... filter) {
251+
byte[] encoded = compilerToVM().getEncodedFieldAnnotationData(holder, index, filter);
252+
return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE);
253+
}
230254
}

‎src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java

+35-3
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,14 @@
3535
import java.lang.reflect.Executable;
3636
import java.lang.reflect.Modifier;
3737
import java.lang.reflect.Type;
38+
import java.util.Collections;
39+
import java.util.List;
3840
import java.util.Objects;
3941

42+
import jdk.internal.vm.VMSupport;
4043
import jdk.vm.ci.common.JVMCIError;
4144
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option;
45+
import jdk.vm.ci.meta.AnnotationData;
4246
import jdk.vm.ci.meta.Constant;
4347
import jdk.vm.ci.meta.ConstantPool;
4448
import jdk.vm.ci.meta.DefaultProfilingInfo;
@@ -523,28 +527,35 @@ public Annotation[][] getParameterAnnotations() {
523527

524528
@Override
525529
public Annotation[] getAnnotations() {
526-
if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0 || isClassInitializer()) {
530+
if (!hasAnnotations()) {
527531
return new Annotation[0];
528532
}
529533
return runtime().reflection.getMethodAnnotations(this);
530534
}
531535

532536
@Override
533537
public Annotation[] getDeclaredAnnotations() {
534-
if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0 || isClassInitializer()) {
538+
if (!hasAnnotations()) {
535539
return new Annotation[0];
536540
}
537541
return runtime().reflection.getMethodDeclaredAnnotations(this);
538542
}
539543

540544
@Override
541545
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
542-
if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0 || isClassInitializer()) {
546+
if (!hasAnnotations()) {
543547
return null;
544548
}
545549
return runtime().reflection.getMethodAnnotation(this, annotationClass);
546550
}
547551

552+
/**
553+
* Returns whether this method has annotations.
554+
*/
555+
private boolean hasAnnotations() {
556+
return (getConstMethodFlags() & config().constMethodHasMethodAnnotations) != 0 && !isClassInitializer();
557+
}
558+
548559
@Override
549560
public boolean isBridge() {
550561
return (BRIDGE & getModifiers()) != 0;
@@ -752,4 +763,25 @@ public boolean hasCodeAtLevel(int entryBCI, int level) {
752763
public int methodIdnum() {
753764
return UNSAFE.getChar(getConstMethod() + config().constMethodMethodIdnumOffset);
754765
}
766+
767+
@Override
768+
public AnnotationData getAnnotationData(ResolvedJavaType type) {
769+
if (!hasAnnotations()) {
770+
return null;
771+
}
772+
return getAnnotationData0(type).get(0);
773+
}
774+
775+
@Override
776+
public List<AnnotationData> getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) {
777+
if (!hasAnnotations()) {
778+
return Collections.emptyList();
779+
}
780+
return getAnnotationData0(AnnotationDataDecoder.asArray(type1, type2, types));
781+
}
782+
783+
private List<AnnotationData> getAnnotationData0(ResolvedJavaType... filter) {
784+
byte[] encoded = compilerToVM().getEncodedExecutableAnnotationData(this, filter);
785+
return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE);
786+
}
755787
}

‎src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java

+63
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,14 @@
3535
import java.lang.reflect.Modifier;
3636
import java.nio.ByteOrder;
3737
import java.util.Arrays;
38+
import java.util.Collections;
3839
import java.util.Comparator;
3940
import java.util.HashMap;
41+
import java.util.List;
4042

43+
import jdk.internal.vm.VMSupport;
4144
import jdk.vm.ci.common.JVMCIError;
45+
import jdk.vm.ci.meta.AnnotationData;
4246
import jdk.vm.ci.meta.Assumptions.AssumptionResult;
4347
import jdk.vm.ci.meta.Assumptions.ConcreteMethod;
4448
import jdk.vm.ci.meta.Assumptions.ConcreteSubtype;
@@ -871,18 +875,56 @@ public String getSourceFileName() {
871875
return getConstantPool().getSourceFileName();
872876
}
873877

878+
/**
879+
* Determines if this type may have annotations. A positive result does not mean this type has
880+
* annotations but a negative result guarantees this type has no annotations.
881+
*
882+
* @param includingInherited if true, expand this query to include superclasses of this type
883+
*/
884+
private boolean mayHaveAnnotations(boolean includingInherited) {
885+
if (isArray()) {
886+
return false;
887+
}
888+
HotSpotVMConfig config = config();
889+
final long metaspaceAnnotations = UNSAFE.getAddress(getKlassPointer() + config.instanceKlassAnnotationsOffset);
890+
if (metaspaceAnnotations != 0) {
891+
long classAnnotations = UNSAFE.getAddress(metaspaceAnnotations + config.annotationsClassAnnotationsOffset);
892+
if (classAnnotations != 0) {
893+
return true;
894+
}
895+
}
896+
if (includingInherited) {
897+
HotSpotResolvedObjectTypeImpl superClass = getSuperclass();
898+
if (superClass != null) {
899+
return superClass.mayHaveAnnotations(true);
900+
}
901+
}
902+
return false;
903+
}
904+
905+
private static final Annotation[] NO_ANNOTATIONS = {};
906+
874907
@Override
875908
public Annotation[] getAnnotations() {
909+
if (!mayHaveAnnotations(true)) {
910+
return NO_ANNOTATIONS;
911+
}
876912
return runtime().reflection.getAnnotations(this);
877913
}
878914

879915
@Override
880916
public Annotation[] getDeclaredAnnotations() {
917+
if (!mayHaveAnnotations(false)) {
918+
return NO_ANNOTATIONS;
919+
}
881920
return runtime().reflection.getDeclaredAnnotations(this);
882921
}
883922

884923
@Override
885924
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
925+
if (!mayHaveAnnotations(true)) {
926+
return null;
927+
}
886928
return runtime().reflection.getAnnotation(this, annotationClass);
887929
}
888930

@@ -1062,4 +1104,25 @@ public ResolvedJavaField resolveField(UnresolvedJavaField unresolvedJavaField, R
10621104
public boolean isCloneableWithAllocation() {
10631105
return (getAccessFlags() & config().jvmAccIsCloneableFast) != 0;
10641106
}
1107+
1108+
@Override
1109+
public AnnotationData getAnnotationData(ResolvedJavaType annotationType) {
1110+
if (!mayHaveAnnotations(true)) {
1111+
return null;
1112+
}
1113+
return getAnnotationData0(annotationType).get(0);
1114+
}
1115+
1116+
@Override
1117+
public List<AnnotationData> getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) {
1118+
if (!mayHaveAnnotations(true)) {
1119+
return Collections.emptyList();
1120+
}
1121+
return getAnnotationData0(AnnotationDataDecoder.asArray(type1, type2, types));
1122+
}
1123+
1124+
private List<AnnotationData> getAnnotationData0(ResolvedJavaType... filter) {
1125+
byte[] encoded = compilerToVM().getEncodedClassAnnotationData(this, filter);
1126+
return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE);
1127+
}
10651128
}

‎src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java

+14
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@
2727

2828
import java.lang.annotation.Annotation;
2929
import java.lang.reflect.Modifier;
30+
import java.util.Collections;
31+
import java.util.List;
3032

3133
import jdk.vm.ci.common.JVMCIError;
3234
import jdk.vm.ci.common.NativeImageReinitialize;
35+
import jdk.vm.ci.meta.AnnotationData;
3336
import jdk.vm.ci.meta.Assumptions.AssumptionResult;
3437
import jdk.vm.ci.meta.JavaConstant;
3538
import jdk.vm.ci.meta.JavaKind;
@@ -317,4 +320,15 @@ public boolean equals(Object obj) {
317320
JavaConstant getJavaMirror() {
318321
return mirror;
319322
}
323+
324+
@Override
325+
public AnnotationData getAnnotationData(ResolvedJavaType type) {
326+
return null;
327+
}
328+
329+
@Override
330+
public List<AnnotationData> getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) {
331+
return Collections.emptyList();
332+
}
333+
320334
}

‎src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ String getHostArchitectureName() {
110110
final int instanceKlassStateBeingInitialized = getConstant("InstanceKlass::being_initialized", Integer.class);
111111

112112
final int annotationsFieldAnnotationsOffset = getFieldOffset("Annotations::_fields_annotations", Integer.class, "Array<AnnotationArray*>*");
113+
final int annotationsClassAnnotationsOffset = getFieldOffset("Annotations::_class_annotations", Integer.class, "AnnotationArray*");
113114
final int fieldsAnnotationsBaseOffset = getFieldValue("CompilerToVM::Data::_fields_annotations_base_offset", Integer.class, "int");
114115

115116
final int arrayU1LengthOffset = getFieldOffset("Array<int>::_length", Integer.class, "int");

‎src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
*/
4141
final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl {
4242
/**
43-
* An object handle in {@code JVMCI::_object_handles}.
43+
* An object handle in {@code JVMCIRuntime::_oop_handles}.
4444
*/
4545
private long objectHandle;
4646

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.vm.ci.meta;
24+
25+
import java.lang.annotation.Inherited;
26+
import java.util.List;
27+
28+
/**
29+
* Represents a program element such as a method, constructor, field or class for which annotations
30+
* may be present.
31+
*/
32+
public interface Annotated {
33+
34+
/**
35+
* Constructs the annotations present on this element whose types are in the set composed of {@code type1},
36+
* {@code type2} and {@code types}. All enum types referenced by the returned annotation are
37+
* initialized. Class initialization is not triggered for enum types referenced by other
38+
* annotations of this element.
39+
*
40+
* If this element is a class, then {@link Inherited} annotations are included in the set of
41+
* annotations considered.
42+
*
43+
* See {@link java.lang.reflect.AnnotatedElement} for the definition of <em>present</em>.
44+
*
45+
* @param type1 an annotation type
46+
* @param type2 an annotation type
47+
* @param types more annotation types
48+
* @return an immutable list of the annotations present on this element that match one of the
49+
* given types
50+
* @throws IllegalArgumentException if any type in the set composed of {@code type1},
51+
* {@code type2} and {@code types} is not an annotation interface type
52+
* @throws UnsupportedOperationException if this operation is not supported
53+
*/
54+
default List<AnnotationData> getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) {
55+
throw new UnsupportedOperationException();
56+
}
57+
58+
/**
59+
* Constructs the annotation present on this element of type {@code type}.
60+
*
61+
* See {@link java.lang.reflect.AnnotatedElement} for the definition of <em>present</em>.
62+
*
63+
* @param type the type object corresponding to the annotation interface type
64+
* @return this element's annotation for the specified annotation type if present on this
65+
* element, else null
66+
* @throws IllegalArgumentException if {@code type} is not an annotation interface type
67+
* @throws UnsupportedOperationException if this operation is not supported
68+
*/
69+
default AnnotationData getAnnotationData(ResolvedJavaType type) {
70+
throw new UnsupportedOperationException();
71+
}
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.vm.ci.meta;
24+
25+
import java.lang.annotation.Annotation;
26+
import java.util.List;
27+
import java.util.Map;
28+
import java.util.Objects;
29+
import java.util.Set;
30+
31+
/**
32+
* Represents an annotation where element values are represented with the types described
33+
* {@linkplain #get here}.
34+
*
35+
* In contrast to the standard annotation API based on {@link Annotation}, use of
36+
* {@link AnnotationData} allows annotations to be queried without the JVMCI runtime having to
37+
* support dynamic loading of arbitrary {@link Annotation} classes. Such support is impossible in a
38+
* closed world, ahead-of-time compiled environment such as libgraal.
39+
*/
40+
public final class AnnotationData {
41+
42+
private final JavaType type;
43+
private final Map<String, Object> elements;
44+
45+
private static final Set<Class<?>> ELEMENT_TYPES = Set.of(
46+
Boolean.class,
47+
Byte.class,
48+
Character.class,
49+
Short.class,
50+
Integer.class,
51+
Float.class,
52+
Long.class,
53+
Double.class,
54+
String.class,
55+
EnumData.class,
56+
AnnotationData.class);
57+
58+
/**
59+
* Creates an annotation.
60+
*
61+
* @param type the annotation interface of this annotation, represented as a {@link JavaType}
62+
* @param elements the names and values of this annotation's element values. Each value's type
63+
* must be one of the {@code AnnotationData} types described {@linkplain #get here}
64+
* or it must be a {@link ErrorData} object whose {@code toString()} value describes
65+
* the error raised while parsing the element. There is no distinction between a
66+
* value explicitly present in the annotation and an element's default value.
67+
* @throws IllegalArgumentException if the value of an entry in {@code elements} is not of an
68+
* accepted type
69+
* @throws NullPointerException if any of the above parameters is null or any entry in
70+
* {@code elements} is null
71+
*/
72+
@SuppressWarnings({"rawtypes", "unchecked"})
73+
public AnnotationData(JavaType type, Map.Entry<String, Object>[] elements) {
74+
this.type = Objects.requireNonNull(type);
75+
for (Map.Entry<String, Object> e : elements) {
76+
Object value = e.getValue();
77+
if (!(value instanceof ErrorData) &&
78+
!(value instanceof JavaType) &&
79+
!(value instanceof List) &&
80+
!ELEMENT_TYPES.contains(value.getClass())) {
81+
throw new IllegalArgumentException("illegal type for element " + e.getKey() + ": " + value.getClass().getName());
82+
}
83+
}
84+
this.elements = Map.ofEntries(elements);
85+
}
86+
87+
/**
88+
* @return the annotation interface of this annotation, represented as a {@link JavaType}
89+
*/
90+
public JavaType getAnnotationType() {
91+
return type;
92+
}
93+
94+
// @formatter:off
95+
/**
96+
* Gets the annotation element denoted by {@code name}. The following table shows the
97+
* correspondence between the type of an element as declared by a method in the annotation
98+
* interface and the type of value returned by this method:
99+
* <table>
100+
* <thead>
101+
* <tr><th>Annotation</th> <th>AnnotationData</th></tr>
102+
* </thead><tbody>
103+
* <tr><td>boolean</td> <td>Boolean</td></tr>
104+
* <tr><td>byte</td> <td>Byte</td></tr>
105+
* <tr><td>char</td> <td>Character</td></tr>
106+
* <tr><td>short</td> <td>Short</td></tr>
107+
* <tr><td>int</td> <td>Integer</td></tr>
108+
* <tr><td>float</td> <td>Float</td></tr>
109+
* <tr><td>long</td> <td>Long</td></tr>
110+
* <tr><td>double</td> <td>Double</td></tr>
111+
* <tr><td>String</td> <td>String</td></tr>
112+
* <tr><td>Class</td> <td>JavaType</td></tr>
113+
* <tr><td>Enum</td> <td>EnumData</td></tr>
114+
* <tr><td>Annotation</td> <td>AnnotationData</td></tr>
115+
* <tr><td>[]</td><td>immutable List&lt;T&gt; where T is one of the above types</td></tr>
116+
* </tbody>
117+
* </table>
118+
*
119+
* @param <V> the type of the element as per the {@code AnnotationData} column in the above
120+
* table or {@link Object}
121+
* @param elementType the class for the type of the element
122+
* @return the annotation element denoted by {@code name}
123+
* @throws ClassCastException if the element is not of type {@code V}
124+
* @throws IllegalArgumentException if this annotation has no element named {@code name} or if
125+
* there was an error parsing or creating the element value
126+
*/
127+
// @formatter:on
128+
@SuppressWarnings("unchecked")
129+
public <V> V get(String name, Class<V> elementType) {
130+
Object val = elements.get(name);
131+
if (val == null) {
132+
throw new IllegalArgumentException("no element named " + name);
133+
}
134+
Class<? extends Object> valClass = val.getClass();
135+
if (valClass == ErrorData.class) {
136+
throw new IllegalArgumentException(val.toString());
137+
}
138+
return elementType.cast(val);
139+
}
140+
141+
@Override
142+
public String toString() {
143+
return "@" + type.getName() + "(" + elements + ")";
144+
}
145+
146+
@Override
147+
public boolean equals(Object obj) {
148+
if (this == obj) {
149+
return true;
150+
}
151+
if (obj instanceof AnnotationData) {
152+
AnnotationData that = (AnnotationData) obj;
153+
return this.type.equals(that.type) && this.elements.equals(that.elements);
154+
155+
}
156+
return false;
157+
}
158+
159+
@Override
160+
public int hashCode() {
161+
return type.hashCode() ^ elements.hashCode();
162+
}
163+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.vm.ci.meta;
24+
25+
/**
26+
* Represents an enum constant within {@link AnnotationData}.
27+
*/
28+
public final class EnumData {
29+
private final JavaType type;
30+
private final String name;
31+
32+
/**
33+
* Creates an enum constant.
34+
*
35+
* @param type the {@linkplain Enum enum type}
36+
* @param name the {@linkplain Enum#name() name} of the enum
37+
*/
38+
public EnumData(JavaType type, String name) {
39+
this.type = type;
40+
this.name = name;
41+
}
42+
43+
/**
44+
* Gets the {@linkplain Enum enum type}.
45+
*/
46+
public JavaType getEnumType() {
47+
return type;
48+
}
49+
50+
/**
51+
* Gets the {@linkplain Enum#name() name} of the enum.
52+
*/
53+
public String getName() {
54+
return name;
55+
}
56+
57+
@Override
58+
public String toString() {
59+
return name;
60+
}
61+
62+
@Override
63+
public boolean equals(Object obj) {
64+
if (this == obj) {
65+
return true;
66+
}
67+
if (obj instanceof EnumData) {
68+
EnumData that = (EnumData) obj;
69+
return this.type.equals(that.type) && this.name.equals(that.name);
70+
}
71+
return false;
72+
}
73+
74+
@Override
75+
public int hashCode() {
76+
return this.type.hashCode() ^ this.name.hashCode();
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.vm.ci.meta;
24+
25+
/**
26+
* Represents an error constant within {@link AnnotationData}.
27+
*
28+
* Similar to {@code sun.reflect.annotation.ExceptionProxy}.
29+
*/
30+
public final class ErrorData {
31+
private final String description;
32+
33+
/**
34+
* Creates an error constant.
35+
*
36+
* @param description description of the error
37+
*/
38+
public ErrorData(String description) {
39+
this.description = description;
40+
}
41+
42+
@Override
43+
public String toString() {
44+
return description;
45+
}
46+
47+
@Override
48+
public boolean equals(Object obj) {
49+
if (this == obj) {
50+
return true;
51+
}
52+
if (obj instanceof ErrorData) {
53+
ErrorData that = (ErrorData) obj;
54+
return this.description.equals(that.description);
55+
}
56+
return false;
57+
}
58+
59+
@Override
60+
public int hashCode() {
61+
return description.hashCode();
62+
}
63+
}

‎src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
* Represents a reference to a resolved Java field. Fields, like methods and types, are resolved
3030
* through {@link ConstantPool constant pools}.
3131
*/
32-
public interface ResolvedJavaField extends JavaField, ModifiersProvider, AnnotatedElement {
32+
public interface ResolvedJavaField extends JavaField, ModifiersProvider, AnnotatedElement, Annotated {
3333

3434
/**
3535
* {@inheritDoc}

‎src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
* Represents a resolved Java method. Methods, like fields and types, are resolved through
3434
* {@link ConstantPool constant pools}.
3535
*/
36-
public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersProvider, AnnotatedElement {
36+
public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersProvider, AnnotatedElement, Annotated {
3737

3838
/**
3939
* Returns the method's bytecode. The returned bytecode does not contain breakpoints or non-Java

‎src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
* thereof. Types, like fields and methods, are resolved through {@link ConstantPool constant pools}
3232
* .
3333
*/
34-
public interface ResolvedJavaType extends JavaType, ModifiersProvider, AnnotatedElement {
34+
public interface ResolvedJavaType extends JavaType, ModifiersProvider, AnnotatedElement, Annotated {
3535
/**
3636
* Checks whether this type has a finalizer method.
3737
*
@@ -137,8 +137,8 @@ default boolean declaresDefaultMethods() {
137137
boolean isAssignableFrom(ResolvedJavaType other);
138138

139139
/**
140-
* Returns {@code null} since support for VM anonymous class was removed by JDK-8243287.
141-
* This method is preserved for JVMCI backwards compatibility.
140+
* Returns {@code null} since support for VM anonymous class was removed by JDK-8243287. This
141+
* method is preserved for JVMCI backwards compatibility.
142142
*/
143143
@Deprecated
144144
default ResolvedJavaType getHostClass() {

‎test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java

+19
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,20 @@
2525
* @test
2626
* @requires vm.jvmci
2727
* @library ../../../../../
28+
* @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java
29+
* ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java
30+
* ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java
31+
* TestResolvedJavaType.java
32+
* @clean jdk.internal.vm.test.AnnotationTestInput$Missing
33+
* @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java
34+
* ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java
2835
* @modules jdk.internal.vm.ci/jdk.vm.ci.meta
2936
* jdk.internal.vm.ci/jdk.vm.ci.runtime
3037
* jdk.internal.vm.ci/jdk.vm.ci.common
38+
* java.base/jdk.internal.reflect
3139
* java.base/jdk.internal.misc
40+
* java.base/jdk.internal.vm
41+
* java.base/sun.reflect.annotation
3242
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaField
3343
*/
3444

@@ -57,6 +67,7 @@
5767
import org.junit.Assert;
5868
import org.junit.Test;
5969

70+
import jdk.internal.vm.test.AnnotationTestInput;
6071
import jdk.vm.ci.common.JVMCIError;
6172
import jdk.vm.ci.meta.ConstantReflectionProvider;
6273
import jdk.vm.ci.meta.JavaConstant;
@@ -181,6 +192,14 @@ private Method findTestMethod(Method apiMethod) {
181192
return null;
182193
}
183194

195+
@Test
196+
public void getAnnotationDataTest() throws Exception {
197+
TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredField("annotatedField"));
198+
for (Field f : fields.keySet()) {
199+
TestResolvedJavaType.getAnnotationDataTest(f);
200+
}
201+
}
202+
184203
// @formatter:off
185204
private static final String[] untestedApiMethods = {
186205
};

‎test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java

+94-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,9 +25,20 @@
2525
* @test
2626
* @requires vm.jvmci
2727
* @library ../../../../../
28+
* @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java
29+
* ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java
30+
* ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java
31+
* TestResolvedJavaType.java
32+
* @clean jdk.internal.vm.test.AnnotationTestInput$Missing
33+
* @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java
34+
* ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java
2835
* @modules jdk.internal.vm.ci/jdk.vm.ci.meta
2936
* jdk.internal.vm.ci/jdk.vm.ci.runtime
37+
* jdk.internal.vm.ci/jdk.vm.ci.common
38+
* java.base/jdk.internal.reflect
3039
* java.base/jdk.internal.misc
40+
* java.base/jdk.internal.vm
41+
* java.base/sun.reflect.annotation
3142
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaMethod
3243
*/
3344

@@ -61,11 +72,16 @@
6172
import org.junit.Assert;
6273
import org.junit.Test;
6374

75+
import jdk.internal.vm.test.AnnotationTestInput;
6476
import jdk.vm.ci.meta.ConstantPool;
6577
import jdk.vm.ci.meta.ExceptionHandler;
6678
import jdk.vm.ci.meta.ResolvedJavaMethod;
6779
import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter;
6880
import jdk.vm.ci.meta.ResolvedJavaType;
81+
import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.Annotation1;
82+
import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.Annotation2;
83+
import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.Annotation3;
84+
import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.NumbersDE;
6985

7086
/**
7187
* Tests for {@link ResolvedJavaMethod}.
@@ -474,6 +490,83 @@ public void testVirtualMethodTableAccess() {
474490
}
475491
}
476492

493+
/**
494+
* Encapsulates input for {@link TestResolvedJavaMethod#getAnnotationDataTest}.
495+
*/
496+
static class AnnotationDataTest {
497+
498+
public enum NumbersEN {
499+
One,
500+
Two;
501+
}
502+
503+
public enum NumbersDE {
504+
Eins,
505+
Zwei;
506+
}
507+
508+
public enum NumbersUA {
509+
Odyn,
510+
Dva;
511+
}
512+
513+
@Retention(RetentionPolicy.RUNTIME)
514+
public @interface Annotation1 {
515+
NumbersEN value() default NumbersEN.One;
516+
}
517+
518+
@Retention(RetentionPolicy.RUNTIME)
519+
public @interface Annotation2 {
520+
NumbersDE value() default NumbersDE.Eins;
521+
}
522+
523+
@Retention(RetentionPolicy.RUNTIME)
524+
public @interface Annotation3 {
525+
NumbersUA value() default NumbersUA.Odyn;
526+
}
527+
528+
@Annotation1
529+
@Annotation2
530+
@Annotation3(NumbersUA.Dva)
531+
static void methodWithThreeAnnotations() {
532+
533+
}
534+
}
535+
536+
@Test
537+
public void getAnnotationDataTest() throws Exception {
538+
TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod"));
539+
TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingAnnotation"));
540+
try {
541+
TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingNestedAnnotation"));
542+
throw new AssertionError("expected " + NoClassDefFoundError.class.getName());
543+
} catch (NoClassDefFoundError e) {
544+
Assert.assertEquals("jdk/internal/vm/test/AnnotationTestInput$Missing", e.getMessage());
545+
}
546+
TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingTypeOfClassMember"));
547+
TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingMember"));
548+
TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("changeTypeOfMember"));
549+
550+
for (Method m : methods.keySet()) {
551+
TestResolvedJavaType.getAnnotationDataTest(m);
552+
}
553+
554+
ResolvedJavaMethod m = metaAccess.lookupJavaMethod(AnnotationDataTest.class.getDeclaredMethod("methodWithThreeAnnotations"));
555+
ResolvedJavaType a1 = metaAccess.lookupJavaType(Annotation1.class);
556+
ResolvedJavaType a2 = metaAccess.lookupJavaType(Annotation2.class);
557+
ResolvedJavaType a3 = metaAccess.lookupJavaType(Annotation3.class);
558+
ResolvedJavaType a4 = metaAccess.lookupJavaType(AnnotationDataTest.class);
559+
ResolvedJavaType numbersDEType = metaAccess.lookupJavaType(NumbersDE.class);
560+
561+
// Ensure NumbersDE is not initialized before Annotation2 is requested
562+
Assert.assertFalse(numbersDEType.isInitialized());
563+
Assert.assertEquals(2, m.getAnnotationData(a1, a3).size());
564+
565+
// Ensure NumbersDE is initialized after Annotation2 is requested
566+
Assert.assertNotNull(m.getAnnotationData(a2));
567+
Assert.assertTrue(numbersDEType.isInitialized());
568+
}
569+
477570
private Method findTestMethod(Method apiMethod) {
478571
String testName = apiMethod.getName() + "Test";
479572
for (Method m : getClass().getDeclaredMethods()) {

‎test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java

+189-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,12 +25,20 @@
2525
* @test
2626
* @requires vm.jvmci
2727
* @library ../../../../../
28+
* @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java
29+
* ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java
30+
* ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java
31+
* @clean jdk.internal.vm.test.AnnotationTestInput$Missing
32+
* @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java
33+
* ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java
2834
* @modules java.base/jdk.internal.org.objectweb.asm
2935
* java.base/jdk.internal.reflect
3036
* jdk.internal.vm.ci/jdk.vm.ci.meta
3137
* jdk.internal.vm.ci/jdk.vm.ci.runtime
3238
* jdk.internal.vm.ci/jdk.vm.ci.common
3339
* java.base/jdk.internal.misc
40+
* java.base/jdk.internal.vm
41+
* java.base/sun.reflect.annotation
3442
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaType
3543
*/
3644

@@ -57,30 +65,43 @@
5765
import java.lang.annotation.Annotation;
5866
import java.lang.invoke.MethodHandles.Lookup;
5967
import java.lang.reflect.AccessibleObject;
68+
import java.lang.reflect.AnnotatedElement;
69+
import java.lang.reflect.Array;
6070
import java.lang.reflect.Constructor;
6171
import java.lang.reflect.Field;
6272
import java.lang.reflect.Method;
6373
import java.lang.reflect.Modifier;
6474
import java.util.Arrays;
6575
import java.util.Collections;
76+
import java.util.function.BiConsumer;
6677
import java.util.function.Supplier;
6778
import java.util.HashMap;
6879
import java.util.HashSet;
80+
import java.util.List;
6981
import java.util.Map;
7082
import java.util.Set;
83+
import java.util.stream.Collectors;
84+
import java.util.stream.Stream;
7185

7286
import org.junit.Assert;
7387
import org.junit.Test;
7488

75-
import jdk.internal.org.objectweb.asm.*;
7689
import jdk.internal.reflect.ConstantPool;
90+
import jdk.internal.vm.test.AnnotationTestInput;
7791
import jdk.vm.ci.common.JVMCIError;
92+
import jdk.vm.ci.meta.Annotated;
93+
import jdk.vm.ci.meta.AnnotationData;
94+
import jdk.vm.ci.meta.EnumData;
7895
import jdk.vm.ci.meta.Assumptions.AssumptionResult;
7996
import jdk.vm.ci.meta.JavaConstant;
8097
import jdk.vm.ci.meta.JavaKind;
98+
import jdk.vm.ci.meta.JavaType;
99+
import jdk.vm.ci.meta.MetaUtil;
81100
import jdk.vm.ci.meta.ResolvedJavaField;
82101
import jdk.vm.ci.meta.ResolvedJavaMethod;
83102
import jdk.vm.ci.meta.ResolvedJavaType;
103+
import jdk.vm.ci.meta.UnresolvedJavaType;
104+
import sun.reflect.annotation.AnnotationSupport;
84105

85106
/**
86107
* Tests for {@link ResolvedJavaType}.
@@ -177,7 +198,8 @@ public void isArrayTest() {
177198

178199
@Test
179200
public void lambdaInternalNameTest() {
180-
// Verify that the last dot in lambda types is properly handled when transitioning from internal name to java
201+
// Verify that the last dot in lambda types is properly handled when transitioning from
202+
// internal name to java
181203
// name and vice versa.
182204
Supplier<Runnable> lambda = () -> () -> System.out.println("run");
183205
ResolvedJavaType lambdaType = metaAccess.lookupJavaType(lambda.getClass());
@@ -903,11 +925,11 @@ private static boolean isHiddenFromReflection(ResolvedJavaField f) {
903925
return f.getName().equals("allowedModes") || f.getName().equals("lookupClass");
904926
}
905927
if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(ClassLoader.class)) ||
906-
f.getDeclaringClass().equals(metaAccess.lookupJavaType(AccessibleObject.class)) ||
907-
f.getDeclaringClass().equals(metaAccess.lookupJavaType(Constructor.class)) ||
908-
f.getDeclaringClass().equals(metaAccess.lookupJavaType(Field.class)) ||
909-
f.getDeclaringClass().equals(metaAccess.lookupJavaType(Method.class)) ||
910-
f.getDeclaringClass().equals(metaAccess.lookupJavaType(Module.class))) {
928+
f.getDeclaringClass().equals(metaAccess.lookupJavaType(AccessibleObject.class)) ||
929+
f.getDeclaringClass().equals(metaAccess.lookupJavaType(Constructor.class)) ||
930+
f.getDeclaringClass().equals(metaAccess.lookupJavaType(Field.class)) ||
931+
f.getDeclaringClass().equals(metaAccess.lookupJavaType(Method.class)) ||
932+
f.getDeclaringClass().equals(metaAccess.lookupJavaType(Module.class))) {
911933
return true;
912934
}
913935
return false;
@@ -1131,6 +1153,40 @@ private Method findTestMethod(Method apiMethod) {
11311153
return null;
11321154
}
11331155

1156+
@Test
1157+
public void getAnnotationDataTest() throws Exception {
1158+
getAnnotationDataTest(AnnotationTestInput.AnnotatedClass.class);
1159+
getAnnotationDataTest(int.class);
1160+
getAnnotationDataTest(void.class);
1161+
for (Class<?> c : classes) {
1162+
getAnnotationDataTest(c);
1163+
}
1164+
1165+
// Primitive classes have no annotations but we cannot directly
1166+
// test absence of annotations. Instead, just ensure empty answers
1167+
// are returned when looking up an arbitrary annotation type.
1168+
Class<?>[] prims = {void.class, byte.class, int.class, double.class, float.class, short.class, char.class, long.class};
1169+
ResolvedJavaType overrideType = metaAccess.lookupJavaType(Override.class);
1170+
for (Class<?> c : prims) {
1171+
ResolvedJavaType type = metaAccess.lookupJavaType(c);
1172+
AnnotationData ad = type.getAnnotationData(overrideType);
1173+
Assert.assertNull(String.valueOf(ad), ad);
1174+
List<AnnotationData> adArray = type.getAnnotationData(overrideType, overrideType);
1175+
Assert.assertEquals(0, adArray.size());
1176+
}
1177+
1178+
// Test that inherited annotations are handled properly.
1179+
ResolvedJavaType namedType = metaAccess.lookupJavaType(AnnotationTestInput.Named.class);
1180+
AnnotationData ad = metaAccess.lookupJavaType(AnnotationTestInput.OwnName.class).getAnnotationData(namedType);
1181+
Assert.assertEquals("NonInheritedValue", ad.get("value", String.class));
1182+
ad = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName1.class).getAnnotationData(namedType);
1183+
Assert.assertEquals("Super1", ad.get("value", String.class));
1184+
ad = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName2.class).getAnnotationData(namedType);
1185+
Assert.assertEquals("Super2", ad.get("value", String.class));
1186+
ad = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName3.class).getAnnotationData(namedType);
1187+
Assert.assertEquals("Super1", ad.get("value", String.class));
1188+
}
1189+
11341190
// @formatter:off
11351191
private static final String[] untestedApiMethods = {
11361192
"initialize",
@@ -1174,4 +1230,129 @@ public void testCoverage() {
11741230
private static boolean isSignaturePolymorphic(ResolvedJavaMethod method) {
11751231
return method.getAnnotation(SIGNATURE_POLYMORPHIC_CLASS) != null;
11761232
}
1233+
1234+
/**
1235+
* Tests that {@link AnnotationData} obtained from a {@link Class}, {@link Method} or
1236+
* {@link Field} matches {@link AnnotatedElement#getAnnotations()} for the corresponding JVMCI
1237+
* object.
1238+
*
1239+
* @param annotated a {@link Class}, {@link Method} or {@link Field} object
1240+
*/
1241+
public static void getAnnotationDataTest(AnnotatedElement annotated) throws Exception {
1242+
testGetAnnotationData(annotated, List.of(annotated.getAnnotations()));
1243+
}
1244+
1245+
private static void testGetAnnotationData(AnnotatedElement annotated, List<Annotation> annotations) throws AssertionError {
1246+
for (Annotation a : annotations) {
1247+
AnnotationData ad = toAnnotated(annotated).getAnnotationData(metaAccess.lookupJavaType(a.annotationType()));
1248+
assertAnnotationsEquals(a, ad);
1249+
1250+
// Check that encoding/decoding produces a stable result
1251+
AnnotationData ad2 = toAnnotated(annotated).getAnnotationData(metaAccess.lookupJavaType(a.annotationType()));
1252+
assertEquals(ad, ad2);
1253+
}
1254+
if (annotations.size() < 2) {
1255+
return;
1256+
}
1257+
ResolvedJavaType type1 = metaAccess.lookupJavaType(annotations.get(0).annotationType());
1258+
ResolvedJavaType type2 = metaAccess.lookupJavaType(annotations.get(1).annotationType());
1259+
for (int i = 2; i < annotations.size(); i++) {
1260+
1261+
ResolvedJavaType[] types = annotations.//
1262+
subList(2, i + 1).//
1263+
stream().map(a -> metaAccess.lookupJavaType(a.annotationType())).//
1264+
toArray(ResolvedJavaType[]::new);
1265+
List<AnnotationData> annotationData = toAnnotated(annotated).getAnnotationData(type1, type2, types);
1266+
assertEquals(2 + types.length, annotationData.size());
1267+
1268+
for (int j = 0; j < annotationData.size(); j++) {
1269+
Annotation a = annotations.get(j);
1270+
AnnotationData ad = annotationData.get(j);
1271+
assertAnnotationsEquals(a, ad);
1272+
}
1273+
}
1274+
}
1275+
1276+
private static Annotated toAnnotated(AnnotatedElement element) {
1277+
if (element instanceof Class<?> t) {
1278+
return metaAccess.lookupJavaType(t);
1279+
} else if (element instanceof Method m) {
1280+
return metaAccess.lookupJavaMethod(m);
1281+
} else {
1282+
Field f = (Field) element;
1283+
return metaAccess.lookupJavaField(f);
1284+
}
1285+
}
1286+
1287+
private static UnresolvedJavaType asType(Class<?> valueType) {
1288+
return UnresolvedJavaType.create(MetaUtil.toInternalName(valueType.getName()));
1289+
}
1290+
1291+
private static void assertAnnotationsEquals(Annotation a, AnnotationData ad) {
1292+
Map<String, Object> values = AnnotationSupport.memberValues(a);
1293+
for (Map.Entry<String, Object> e : values.entrySet()) {
1294+
String name = e.getKey();
1295+
Object aValue = e.getValue();
1296+
Object adValue;
1297+
try {
1298+
adValue = ad.get(name, Object.class);
1299+
} catch (IllegalArgumentException ex) {
1300+
assertEquals(aValue.toString(), ex.getMessage());
1301+
continue;
1302+
}
1303+
try {
1304+
assertAnnotationElementsEqual(aValue, adValue);
1305+
} catch (ClassCastException ex) {
1306+
throw new AssertionError(a.getClass().getName() + "." + name + " has wrong type: " + adValue.getClass().getName(), ex);
1307+
}
1308+
}
1309+
}
1310+
1311+
private static void assertAnnotationElementsEqual(Object aValue, Object adValue) {
1312+
Class<?> valueType = aValue.getClass();
1313+
if (valueType.isEnum()) {
1314+
assertEnumObjectsEquals(aValue, adValue);
1315+
} else if (aValue instanceof Class) {
1316+
assertClassObjectsEquals(aValue, adValue);
1317+
} else if (aValue instanceof Annotation) {
1318+
assertAnnotationObjectsEquals(aValue, adValue);
1319+
} else if (valueType.isArray()) {
1320+
List<?> adList = (List<?>) adValue;
1321+
int length = Array.getLength(aValue);
1322+
assertEquals(length, adList.size());
1323+
for (int i = 0; i < length; i++) {
1324+
assertAnnotationElementsEqual(Array.get(aValue, i), adList.get(i));
1325+
}
1326+
} else {
1327+
assertEquals(aValue.getClass(), adValue.getClass());
1328+
assertEquals(aValue, adValue);
1329+
}
1330+
}
1331+
1332+
private static void assertClassObjectsEquals(Object aValue, Object adValue) {
1333+
String aName = ((Class<?>) aValue).getName();
1334+
String adName = ((JavaType) adValue).toClassName();
1335+
assertEquals(aName, adName);
1336+
}
1337+
1338+
private static void assertEnumObjectsEquals(Object aValue, Object adValue) {
1339+
EnumData adEnum = (EnumData) adValue;
1340+
String adEnumName = adEnum.getName();
1341+
String aEnumName = ((Enum<?>) aValue).name();
1342+
assertEquals(adEnumName, aEnumName);
1343+
}
1344+
1345+
private static void assertAnnotationObjectsEquals(Object aValue, Object adValue) {
1346+
Annotation aAnnotation = (Annotation) aValue;
1347+
AnnotationData adAnnotation = (AnnotationData) adValue;
1348+
assertAnnotationsEquals(aAnnotation, adAnnotation);
1349+
}
1350+
1351+
private static void assertArraysEqual(Object aValue, Object adValue, int length, BiConsumer<Object, Object> assertEqualty) {
1352+
Object[] aArray = (Object[]) aValue;
1353+
Object[] adArray = (Object[]) adValue;
1354+
for (int i = 0; i < length; i++) {
1355+
assertEqualty.accept(aArray[i], adArray[i]);
1356+
}
1357+
}
11771358
}

‎test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java

+11-10
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,8 @@
2222
*/
2323
package jdk.vm.ci.runtime.test;
2424

25-
import jdk.internal.misc.Unsafe;
26-
import jdk.vm.ci.meta.ConstantReflectionProvider;
27-
import jdk.vm.ci.meta.JavaConstant;
28-
import jdk.vm.ci.meta.MetaAccessProvider;
29-
import jdk.vm.ci.meta.ResolvedJavaField;
30-
import jdk.vm.ci.meta.ResolvedJavaType;
31-
import jdk.vm.ci.runtime.JVMCI;
32-
import org.junit.Test;
25+
import static java.lang.reflect.Modifier.isFinal;
26+
import static java.lang.reflect.Modifier.isStatic;
3327

3428
import java.io.Serializable;
3529
import java.lang.reflect.Array;
@@ -54,8 +48,15 @@
5448
import java.util.function.Predicate;
5549
import java.util.stream.Collectors;
5650

57-
import static java.lang.reflect.Modifier.isFinal;
58-
import static java.lang.reflect.Modifier.isStatic;
51+
import org.junit.Test;
52+
53+
import jdk.internal.misc.Unsafe;
54+
import jdk.vm.ci.meta.ConstantReflectionProvider;
55+
import jdk.vm.ci.meta.JavaConstant;
56+
import jdk.vm.ci.meta.MetaAccessProvider;
57+
import jdk.vm.ci.meta.ResolvedJavaField;
58+
import jdk.vm.ci.meta.ResolvedJavaType;
59+
import jdk.vm.ci.runtime.JVMCI;
5960

6061
/**
6162
* Context for type related tests.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,375 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.internal.vm.test;
24+
25+
import java.lang.annotation.Annotation;
26+
import java.lang.annotation.Inherited;
27+
import java.lang.annotation.Repeatable;
28+
import java.lang.annotation.Retention;
29+
import java.lang.annotation.RetentionPolicy;
30+
31+
public class AnnotationTestInput {
32+
33+
enum Mood {
34+
HAPPY,
35+
SAD,
36+
CONFUSED;
37+
}
38+
39+
private class PrivateClass {}
40+
41+
@Single(string = "a",
42+
stringArray = {"a", "b"},
43+
classValue = String.class,
44+
classArray = {String.class, Exception.class},
45+
byteValue = 1,
46+
byteArray = {1, 2, Byte.MIN_VALUE, Byte.MAX_VALUE},
47+
charValue = 'a',
48+
charArray = {'a', 'b',
49+
Character.MIN_VALUE, Character.MAX_VALUE,
50+
'\b', '\f', '\n', '\r', '\t', '\\', '\'', '\"', '\u012A'},
51+
doubleValue = 3.3D,
52+
doubleArray = {3.3D, 4.4D,
53+
Double.MIN_VALUE, Double.MAX_VALUE,
54+
Double.NaN,
55+
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY},
56+
floatValue = 4.4F,
57+
floatArray = {4.4F, 5.5F,
58+
Float.MIN_VALUE, Float.MAX_VALUE,
59+
Float.NaN,
60+
Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY},
61+
intValue = 5,
62+
intArray = {5, 6, Integer.MIN_VALUE, Integer.MAX_VALUE},
63+
longValue = 6L,
64+
longArray = {6L, 7L, Long.MIN_VALUE, Long.MAX_VALUE},
65+
shortValue = 7,
66+
shortArray = {7, 8, Short.MIN_VALUE, Short.MAX_VALUE},
67+
booleanValue = true,
68+
booleanArray = {true, false},
69+
mood = Mood.SAD,
70+
moodArray = {Mood.CONFUSED, Mood.HAPPY},
71+
nested = @NestedAnno("nested1"),
72+
nestedArray = {@NestedAnno("nested2"), @NestedAnno("nested3")})
73+
@Single(string = "A",
74+
stringArray = {"A", "B"},
75+
classValue = Thread.class,
76+
classArray = {Thread.class, PrivateClass.class},
77+
byteValue = -1,
78+
byteArray = {-1, -2},
79+
charValue = 'A',
80+
charArray = {'a', 'b'},
81+
doubleValue = -3.3D,
82+
doubleArray = {3.3D, 4.4D},
83+
floatValue = -4.4F,
84+
floatArray = {4.4F, 5.5F},
85+
intValue = -5,
86+
intArray = {5, 6},
87+
longValue = -6L,
88+
longArray = {6L, 7L},
89+
shortValue = -7,
90+
shortArray = {7, 8},
91+
booleanValue = true,
92+
booleanArray = {true, false},
93+
mood = Mood.CONFUSED,
94+
moodArray = {Mood.SAD, Mood.CONFUSED},
95+
nested = @NestedAnno("nested4"),
96+
nestedArray = {@NestedAnno("nested5"), @NestedAnno("nested6")})
97+
@SingleWithDefaults
98+
@Deprecated
99+
@SuppressWarnings("unchecked")
100+
public void annotatedMethod() {
101+
}
102+
103+
@Named("Super1")
104+
public static class Super1 {}
105+
@Named("Super2")
106+
public static class Super2 extends Super1 {}
107+
public static class Super3 extends Super1 {}
108+
109+
@Named("NonInheritedValue")
110+
public static class OwnName extends Super1 {}
111+
112+
public static class InheritedName1 extends Super1 {}
113+
public static class InheritedName2 extends Super2 {}
114+
public static class InheritedName3 extends Super3 {}
115+
116+
@Named("AnnotatedClass")
117+
@Single(string = "a",
118+
stringArray = {"a", "b"},
119+
classValue = String.class,
120+
classArray = {String.class, Exception.class},
121+
byteValue = 1,
122+
byteArray = {1, 2, Byte.MIN_VALUE, Byte.MAX_VALUE},
123+
charValue = 'a',
124+
charArray = {'a', 'b',
125+
Character.MIN_VALUE, Character.MAX_VALUE,
126+
'\b', '\f', '\n', '\r', '\t', '\\', '\'', '\"', '\u012A'},
127+
doubleValue = 3.3D,
128+
doubleArray = {3.3D, 4.4D,
129+
Double.MIN_VALUE, Double.MAX_VALUE,
130+
Double.NaN,
131+
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY},
132+
floatValue = 4.4F,
133+
floatArray = {4.4F, 5.5F,
134+
Float.MIN_VALUE, Float.MAX_VALUE,
135+
Float.NaN,
136+
Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY},
137+
intValue = 5,
138+
intArray = {5, 6, Integer.MIN_VALUE, Integer.MAX_VALUE},
139+
longValue = 6L,
140+
longArray = {6L, 7L, Long.MIN_VALUE, Long.MAX_VALUE},
141+
shortValue = 7,
142+
shortArray = {7, 8, Short.MIN_VALUE, Short.MAX_VALUE},
143+
booleanValue = true,
144+
booleanArray = {true, false},
145+
mood = Mood.SAD,
146+
moodArray = {Mood.CONFUSED, Mood.HAPPY},
147+
nested = @NestedAnno("nested7"),
148+
nestedArray = {@NestedAnno("nested8"), @NestedAnno("nested9")})
149+
@Single(string = "A",
150+
stringArray = {"A", "B"},
151+
classValue = Thread.class,
152+
classArray = {Thread.class, PrivateClass.class},
153+
byteValue = -1,
154+
byteArray = {-1, -2},
155+
charValue = 'A',
156+
charArray = {'a', 'b'},
157+
doubleValue = -3.3D,
158+
doubleArray = {3.3D, 4.4D},
159+
floatValue = -4.4F,
160+
floatArray = {4.4F, 5.5F},
161+
intValue = -5,
162+
intArray = {5, 6},
163+
longValue = -6L,
164+
longArray = {6L, 7L},
165+
shortValue = -7,
166+
shortArray = {7, 8},
167+
booleanValue = true,
168+
booleanArray = {true, false},
169+
mood = Mood.CONFUSED,
170+
moodArray = {Mood.SAD, Mood.CONFUSED},
171+
nested = @NestedAnno("nested10"),
172+
nestedArray = {@NestedAnno("nested11"), @NestedAnno("nested12")})
173+
@Deprecated
174+
@SuppressWarnings({"rawtypes", "all"})
175+
public static class AnnotatedClass {}
176+
177+
@Single(string = "a",
178+
stringArray = {"a", "b"},
179+
classValue = String.class,
180+
classArray = {String.class, Exception.class},
181+
byteValue = 1,
182+
byteArray = {1, 2, Byte.MIN_VALUE, Byte.MAX_VALUE},
183+
charValue = 'a',
184+
charArray = {'a', 'b',
185+
Character.MIN_VALUE, Character.MAX_VALUE,
186+
'\b', '\f', '\n', '\r', '\t', '\\', '\'', '\"', '\u012A'},
187+
doubleValue = 3.3D,
188+
doubleArray = {3.3D, 4.4D,
189+
Double.MIN_VALUE, Double.MAX_VALUE,
190+
Double.NaN,
191+
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY},
192+
floatValue = 4.4F,
193+
floatArray = {4.4F, 5.5F,
194+
Float.MIN_VALUE, Float.MAX_VALUE,
195+
Float.NaN,
196+
Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY},
197+
intValue = 5,
198+
intArray = {5, 6, Integer.MIN_VALUE, Integer.MAX_VALUE},
199+
longValue = 6L,
200+
longArray = {6L, 7L, Long.MIN_VALUE, Long.MAX_VALUE},
201+
shortValue = 7,
202+
shortArray = {7, 8, Short.MIN_VALUE, Short.MAX_VALUE},
203+
booleanValue = true,
204+
booleanArray = {true, false},
205+
mood = Mood.SAD,
206+
moodArray = {Mood.CONFUSED, Mood.HAPPY},
207+
nested = @NestedAnno("nested12"),
208+
nestedArray = {@NestedAnno("nested13"), @NestedAnno("nested14")})
209+
@Single(string = "A",
210+
stringArray = {"A", "B"},
211+
classValue = Thread.class,
212+
classArray = {Thread.class, PrivateClass.class},
213+
byteValue = -1,
214+
byteArray = {-1, -2},
215+
charValue = 'A',
216+
charArray = {'a', 'b'},
217+
doubleValue = -3.3D,
218+
doubleArray = {3.3D, 4.4D},
219+
floatValue = -4.4F,
220+
floatArray = {4.4F, 5.5F},
221+
intValue = -5,
222+
intArray = {5, 6},
223+
longValue = -6L,
224+
longArray = {6L, 7L},
225+
shortValue = -7,
226+
shortArray = {7, 8},
227+
booleanValue = true,
228+
booleanArray = {true, false},
229+
mood = Mood.CONFUSED,
230+
moodArray = {Mood.SAD, Mood.CONFUSED},
231+
nested = @NestedAnno("nested15"),
232+
nestedArray = {@NestedAnno("nested16"), @NestedAnno("nested17")})
233+
private static final int annotatedField = 45;
234+
235+
@Retention(RetentionPolicy.RUNTIME)
236+
public @interface NestedAnno {
237+
String value();
238+
}
239+
240+
@Inherited
241+
@Retention(RetentionPolicy.RUNTIME)
242+
public @interface Named {
243+
String value();
244+
}
245+
246+
@Retention(RetentionPolicy.RUNTIME)
247+
@Repeatable(SingleList.class)
248+
public @interface Single {
249+
Class<?> classValue();
250+
Class<?>[] classArray();
251+
252+
String string();
253+
String[] stringArray();
254+
255+
byte byteValue();
256+
byte[] byteArray();
257+
258+
char charValue();
259+
char[] charArray();
260+
261+
double doubleValue();
262+
double[] doubleArray();
263+
264+
float floatValue();
265+
float[] floatArray();
266+
267+
int intValue();
268+
int[] intArray();
269+
270+
long longValue();
271+
long[] longArray();
272+
273+
short shortValue();
274+
short[] shortArray();
275+
276+
boolean booleanValue();
277+
boolean[] booleanArray();
278+
279+
Mood mood();
280+
Mood[] moodArray();
281+
282+
NestedAnno nested();
283+
NestedAnno[] nestedArray();
284+
}
285+
286+
@Retention(RetentionPolicy.RUNTIME)
287+
@interface SingleWithDefaults {
288+
Class<?> classValue() default SingleWithDefaults.class;
289+
Class<?>[] classArray() default {};
290+
291+
String string() default "anonymous";
292+
String[] stringArray() default {};
293+
294+
byte byteValue() default 101;
295+
byte[] byteArray() default {};
296+
297+
char charValue() default 'Z';
298+
char[] charArray() default {};
299+
300+
double doubleValue() default 102.102D;
301+
double[] doubleArray() default {};
302+
303+
float floatValue() default 103.103F;
304+
float[] floatArray() default {};
305+
306+
int intValue() default 104;
307+
int[] intArray() default {};
308+
309+
long longValue() default 105L;
310+
long[] longArray() default {};
311+
312+
short shortValue() default 105;
313+
short[] shortArray() default {};
314+
315+
boolean booleanValue() default true;
316+
boolean[] booleanArray() default {};
317+
318+
Mood mood() default Mood.HAPPY;
319+
Mood[] moodArray() default {};
320+
}
321+
322+
@Retention(RetentionPolicy.RUNTIME)
323+
public @interface SingleList {
324+
Single[] value();
325+
}
326+
327+
@Retention(RetentionPolicy.RUNTIME)
328+
public @interface Missing {}
329+
330+
@Retention(RetentionPolicy.RUNTIME)
331+
public @interface MissingWrapper {
332+
Missing value();
333+
}
334+
335+
@Retention(RetentionPolicy.RUNTIME)
336+
public @interface MissingContainer {
337+
Class<?> value();
338+
}
339+
340+
/**
341+
* Method with a directly missing annotation.
342+
*/
343+
@Missing
344+
public void missingAnnotation() {}
345+
346+
/**
347+
* Method with an indirectly missing nested annotation.
348+
*/
349+
@MissingWrapper(@Missing)
350+
public void missingNestedAnnotation() {}
351+
352+
/**
353+
* Method with an annotation that has a Class member
354+
* that cannot be resolved.
355+
*/
356+
@MissingContainer(Missing.class)
357+
public void missingTypeOfClassMember() {}
358+
359+
/**
360+
* Method with an annotation that has a member
361+
* that is deleted in a newer version of the annotation.
362+
*/
363+
@MemberDeleted(value = "evolving", retained = -34, deleted = 56)
364+
public void missingMember() {}
365+
366+
/**
367+
* Method with an annotation that has a member named "any"
368+
* whose type is changed from int to String in a newer version
369+
* of the annotation.
370+
*/
371+
@MemberTypeChanged(value = "evolving", retained = -34, any = 56)
372+
public void changeTypeOfMember() {}
373+
374+
}
375+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.internal.vm.test;
24+
25+
import java.lang.annotation.Retention;
26+
import java.lang.annotation.RetentionPolicy;
27+
28+
@Retention(RetentionPolicy.RUNTIME)
29+
public @interface MemberDeleted {
30+
String value();
31+
int retained();
32+
int deleted();
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.internal.vm.test;
24+
25+
import java.lang.annotation.Retention;
26+
import java.lang.annotation.RetentionPolicy;
27+
28+
@Retention(RetentionPolicy.RUNTIME)
29+
public @interface MemberTypeChanged {
30+
String value();
31+
int retained();
32+
int any();
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @compile AnnotationTestInput.java MemberDeleted.java MemberTypeChanged.java
27+
* @modules java.base/jdk.internal.vm
28+
* java.base/sun.reflect.annotation
29+
* @clean jdk.internal.vm.test.AnnotationTestInput$Missing
30+
* @compile alt/MemberDeleted.java alt/MemberTypeChanged.java
31+
* @run testng/othervm
32+
* jdk.internal.vm.test.TestAnnotationEncodingDecoding
33+
*/
34+
package jdk.internal.vm.test;
35+
36+
import java.lang.annotation.Annotation;
37+
import java.lang.reflect.AnnotatedElement;
38+
import java.lang.reflect.Array;
39+
import java.lang.reflect.Method;
40+
import java.util.LinkedHashMap;
41+
import java.util.HashMap;
42+
import java.util.Iterator;
43+
import java.util.List;
44+
import java.util.Map;
45+
import java.util.Objects;
46+
import java.util.TreeMap;
47+
48+
import org.testng.Assert;
49+
import org.testng.annotations.Test;
50+
51+
import sun.reflect.annotation.AnnotationSupport;
52+
import sun.reflect.annotation.AnnotationParser;
53+
import sun.reflect.annotation.ExceptionProxy;
54+
55+
import jdk.internal.vm.VMSupport;
56+
import jdk.internal.vm.VMSupport.AnnotationDecoder;
57+
58+
public class TestAnnotationEncodingDecoding {
59+
60+
@Test
61+
public void encodeDecodeTest() throws Exception {
62+
checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredField("annotatedField"));
63+
checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod"));
64+
checkDecodedEqualsEncoded(AnnotationTestInput.AnnotatedClass.class);
65+
66+
checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingAnnotation"));
67+
checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingNestedAnnotation"), true);
68+
checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingTypeOfClassMember"), false);
69+
checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingMember"));
70+
checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("changeTypeOfMember"), false);
71+
}
72+
73+
private void checkDecodedEqualsEncoded(AnnotatedElement annotated) {
74+
checkDecodedEqualsEncoded(annotated, false);
75+
}
76+
77+
private void checkDecodedEqualsEncoded(AnnotatedElement annotated, boolean expectNCDFE) {
78+
Annotation[] annotations = getAnnotations(annotated, expectNCDFE);
79+
if (annotations == null) {
80+
return;
81+
}
82+
83+
byte[] encoded = VMSupport.encodeAnnotations(List.of(annotations));
84+
MyDecoder decoder = new MyDecoder();
85+
List<AnnotationConst> decoded = VMSupport.decodeAnnotations(encoded, decoder);
86+
int i = 0;
87+
for (AnnotationConst actual : decoded) {
88+
AnnotationConst expect = new AnnotationConst(annotations[i]);
89+
checkEquals(actual, expect);
90+
checkEquals(actual.toString(), expect.toString());
91+
i++;
92+
}
93+
}
94+
95+
private static Annotation[] getAnnotations(AnnotatedElement annotated, boolean expectNCDFE) throws AssertionError {
96+
try {
97+
Annotation[] annotations = annotated.getAnnotations();
98+
Assert.assertFalse(expectNCDFE, annotated.toString());
99+
return annotations;
100+
} catch (NoClassDefFoundError e) {
101+
if (!expectNCDFE) {
102+
throw new AssertionError(annotated.toString(), e);
103+
}
104+
return null;
105+
}
106+
}
107+
108+
private static void checkEquals(Object actual, Object expect) {
109+
if (!actual.equals(expect)) {
110+
throw new AssertionError(String.format("actual != expect%nactual: %s%n%nexpect: %s", actual, expect));
111+
}
112+
}
113+
114+
public static final class AnnotationConst {
115+
final Class<?> type;
116+
final Map<String, Object> elements;
117+
118+
AnnotationConst(Class<?> type, Map.Entry<String, Object>[] elements) {
119+
this.type = type;
120+
this.elements = Map.ofEntries(elements);
121+
}
122+
123+
AnnotationConst(Annotation a) {
124+
Map<String, Object> values = AnnotationSupport.memberValues(a);
125+
this.type = a.annotationType();
126+
Map.Entry[] elements = new Map.Entry[values.size()];
127+
int i = 0;
128+
for (Map.Entry<String, Object> e : values.entrySet()) {
129+
elements[i++] = Map.entry(e.getKey(), decodeValue(e.getValue()));
130+
}
131+
this.elements = Map.ofEntries(elements);
132+
}
133+
134+
@Override
135+
public boolean equals(Object obj) {
136+
if (obj instanceof AnnotationConst) {
137+
AnnotationConst that = (AnnotationConst) obj;
138+
return this.type.equals(that.type) &&
139+
this.elements.equals(that.elements);
140+
}
141+
return false;
142+
}
143+
144+
@Override
145+
public String toString() {
146+
return "@" + type.getName() + "(" + elements + ")";
147+
}
148+
149+
private Object decodeValue(Object value) {
150+
Class<?> valueType = value.getClass();
151+
if (value instanceof Enum) {
152+
return new EnumConst(valueType, ((Enum<?>) value).name());
153+
} else if (value instanceof Annotation) {
154+
return new AnnotationConst((Annotation) value);
155+
} else if (valueType.isArray()) {
156+
int len = Array.getLength(value);
157+
Object[] arr = new Object[len];
158+
for (int i = 0; i < len; i++) {
159+
arr[i] = decodeValue(Array.get(value, i));
160+
}
161+
return List.of(arr);
162+
} else if (value instanceof ExceptionProxy) {
163+
return new ErrorConst(value.toString());
164+
} else {
165+
return value;
166+
}
167+
}
168+
169+
public Class<?> getType() {
170+
return type;
171+
}
172+
}
173+
174+
public static final class ErrorConst {
175+
final String desc;
176+
public ErrorConst(String desc) {
177+
this.desc = Objects.requireNonNull(desc);
178+
}
179+
180+
@Override
181+
public String toString() {
182+
return desc;
183+
}
184+
185+
@Override
186+
public int hashCode() {
187+
return desc.hashCode();
188+
}
189+
190+
@Override
191+
public boolean equals(Object obj) {
192+
if (obj instanceof ErrorConst) {
193+
return ((ErrorConst) obj).desc.equals(desc);
194+
}
195+
return false;
196+
}
197+
}
198+
199+
public static final class EnumConst {
200+
final Class<?> type;
201+
final String name;
202+
203+
public EnumConst(Class<?> type, String name) {
204+
this.type = type;
205+
this.name = name;
206+
}
207+
208+
@Override
209+
public boolean equals(Object obj) {
210+
if (obj instanceof EnumConst) {
211+
EnumConst that = (EnumConst) obj;
212+
return this.type.equals(that.type) &&
213+
this.name.equals(that.name);
214+
}
215+
return false;
216+
}
217+
218+
@Override
219+
public String toString() {
220+
return type.getName() + "." + name;
221+
}
222+
223+
public Class<?> getEnumType() {
224+
return type;
225+
}
226+
227+
public String getName() {
228+
return name;
229+
}
230+
}
231+
232+
static class MyDecoder implements AnnotationDecoder<Class<?>, AnnotationConst, EnumConst, ErrorConst> {
233+
@Override
234+
public Class<?> resolveType(String name) {
235+
try {
236+
return Class.forName(name);
237+
} catch (ClassNotFoundException e) {
238+
throw new RuntimeException(e);
239+
}
240+
}
241+
242+
@Override
243+
public AnnotationConst newAnnotation(Class<?> type, Map.Entry<String, Object>[] elements) {
244+
return new AnnotationConst(type, elements);
245+
}
246+
247+
@Override
248+
public EnumConst newEnumValue(Class<?> enumType, String name) {
249+
return new EnumConst(enumType, name);
250+
}
251+
252+
@Override
253+
public ErrorConst newErrorValue(String description) {
254+
return new ErrorConst(description);
255+
}
256+
}
257+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.internal.vm.test;
24+
25+
import java.lang.annotation.Retention;
26+
import java.lang.annotation.RetentionPolicy;
27+
28+
@Retention(RetentionPolicy.RUNTIME)
29+
public @interface MemberDeleted {
30+
String value();
31+
int retained();
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.internal.vm.test;
24+
25+
import java.lang.annotation.Retention;
26+
import java.lang.annotation.RetentionPolicy;
27+
28+
@Retention(RetentionPolicy.RUNTIME)
29+
public @interface MemberTypeChanged {
30+
String value();
31+
int retained();
32+
String any();
33+
}

‎test/jdk/jdk/internal/vm/TestTranslatedException.java

-9
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,6 @@ public void encodeDecodeTest() throws Exception {
5858
}
5959
encodeDecode(throwable);
6060
}
61-
@SuppressWarnings("unchecked")
62-
@Test
63-
public void encodeDecodeTest2() throws Exception {
64-
Throwable throwable = new ExceptionInInitializerError(new InvocationTargetException(new Untranslatable("test exception", new NullPointerException()), "invoke"));
65-
for (int i = 0; i < 10; i++) {
66-
throwable = new ExceptionInInitializerError(new InvocationTargetException(new RuntimeException(String.valueOf(i), throwable), "invoke"));
67-
}
68-
encodeDecode(throwable);
69-
}
7061

7162
private void encodeDecode(Throwable throwable) throws Exception {
7263
Unsafe unsafe = Unsafe.getUnsafe();

0 commit comments

Comments
 (0)
Please sign in to comment.