From 90d0a1c9c822b042a51ba0699462fecc2b155327 Mon Sep 17 00:00:00 2001 From: Theresa Mammarella Date: Fri, 10 Nov 2023 10:17:18 -0500 Subject: [PATCH] Append cp to method and field annotation data to fix redefinition inconsistencies Signed-off-by: Theresa Mammarella --- .../ibm/oti/reflect/TypeAnnotationParser.java | 30 ++---- .../share/classes/com/ibm/oti/vm/VM.java | 34 +++++++ .../share/classes/java/lang/Class.java | 13 +-- runtime/jcl/common/reflecthelp.c | 92 +++++++++---------- 4 files changed, 87 insertions(+), 82 deletions(-) diff --git a/jcl/src/java.base/share/classes/com/ibm/oti/reflect/TypeAnnotationParser.java b/jcl/src/java.base/share/classes/com/ibm/oti/reflect/TypeAnnotationParser.java index bec1a743138..82b1d43916e 100644 --- a/jcl/src/java.base/share/classes/com/ibm/oti/reflect/TypeAnnotationParser.java +++ b/jcl/src/java.base/share/classes/com/ibm/oti/reflect/TypeAnnotationParser.java @@ -105,17 +105,10 @@ private static byte[] getAttributeData(Class clazz) { */ public static AnnotatedType[] buildAnnotatedInterfaces(Class clazz) { byte[] attr = getAttributeData(clazz); - long offset = Unsafe.ARRAY_BYTE_BASE_OFFSET + ((attr.length * Unsafe.ARRAY_BYTE_INDEX_SCALE) - VM.FJ9OBJECT_SIZE); - long ramCPAddr = 0; - if (VM.FJ9OBJECT_SIZE == 4) { - /* Compressed object refs */ - ramCPAddr = Integer.toUnsignedLong(Unsafe.getUnsafe().getInt(attr, offset)); - } else { - ramCPAddr = Unsafe.getUnsafe().getLong(attr, offset); - } - Object internalConstantPool = VM.getVMLangAccess().createInternalConstantPool(ramCPAddr); - - AnnotatedType[] annotatedInterfaces = sun.reflect.annotation.TypeAnnotationParser.buildAnnotatedInterfaces(attr, AnnotationParser.getConstantPool(internalConstantPool), clazz); + AnnotatedType[] annotatedInterfaces = sun.reflect.annotation.TypeAnnotationParser.buildAnnotatedInterfaces( + attr, + VM.getConstantPoolFromAnnotationBytes(clazz, attr), + clazz); return annotatedInterfaces; } /** @@ -125,17 +118,10 @@ public static AnnotatedType[] buildAnnotatedInterfaces(Class clazz) { */ public static AnnotatedType buildAnnotatedSupertype(Class clazz) { byte[] attr = getAttributeData(clazz); - long offset = Unsafe.ARRAY_BYTE_BASE_OFFSET + ((attr.length * Unsafe.ARRAY_BYTE_INDEX_SCALE) - VM.FJ9OBJECT_SIZE); - long ramCPAddr = 0; - if (VM.FJ9OBJECT_SIZE == 4) { - /* Compressed object refs */ - ramCPAddr = Integer.toUnsignedLong(Unsafe.getUnsafe().getInt(attr, offset)); - } else { - ramCPAddr = Unsafe.getUnsafe().getLong(attr, offset); - } - Object internalConstantPool = VM.getVMLangAccess().createInternalConstantPool(ramCPAddr); - - AnnotatedType annotatedSuperclass = sun.reflect.annotation.TypeAnnotationParser.buildAnnotatedSuperclass(attr, AnnotationParser.getConstantPool(internalConstantPool), clazz); + AnnotatedType annotatedSuperclass = sun.reflect.annotation.TypeAnnotationParser.buildAnnotatedSuperclass( + attr, + VM.getConstantPoolFromAnnotationBytes(clazz, attr), + clazz); return annotatedSuperclass; } } diff --git a/jcl/src/java.base/share/classes/com/ibm/oti/vm/VM.java b/jcl/src/java.base/share/classes/com/ibm/oti/vm/VM.java index bc0e1f82a37..7768821540c 100644 --- a/jcl/src/java.base/share/classes/com/ibm/oti/vm/VM.java +++ b/jcl/src/java.base/share/classes/com/ibm/oti/vm/VM.java @@ -27,9 +27,13 @@ import com.ibm.oti.util.Util; /*[IF Sidecar19-SE] +import jdk.internal.misc.Unsafe; import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.ConstantPool; /*[ELSE]*/ +import sun.misc.Unsafe; import sun.reflect.CallerSensitive; +import sun.reflect.ConstantPool; /*[ENDIF]*/ /** @@ -583,4 +587,34 @@ public static int markCurrentThreadAsSystem() * @return true if JVM is in single threaded mode, false otherwise */ public static native boolean isJVMInSingleThreadedMode(); + +/** + * A J9ConstantPool* is appended to anntation parameter byte arrays + * so it will be consistent with annotation data if the class is redefined. + * Only use this method with: + * - java.lang.Class.getAnnotationCache() + * - java.lang.reflect.Executable.annotations + * - java.lang.reflect.Method.parameterAnnotations + * - java.lang.reflect.Method.annotationDefault + * - java.lang.reflect.Field.annotations + * @param clazz + * @param array + * @return ConstantPool associated with byte array, if array is null return + * constantpool associated with clazz + */ +public static ConstantPool getConstantPoolFromAnnotationBytes(Class clazz, byte[] array) { + if (null == array) { + return getVMLangAccess().getConstantPool(clazz); + } + long offset = Unsafe.ARRAY_BYTE_BASE_OFFSET + ((array.length * Unsafe.ARRAY_BYTE_INDEX_SCALE) - FJ9OBJECT_SIZE); + long ramCPAddr = 0; + if (FJ9OBJECT_SIZE == 4) { + /* Compressed object refs */ + ramCPAddr = Integer.toUnsignedLong(Unsafe.getUnsafe().getInt(array, offset)); + } else { + ramCPAddr = Unsafe.getUnsafe().getLong(array, offset); + } + Object internalCP = getVMLangAccess().createInternalConstantPool(ramCPAddr); + return getVMLangAccess().getConstantPool(internalCP); +} } diff --git a/jcl/src/java.base/share/classes/java/lang/Class.java b/jcl/src/java.base/share/classes/java/lang/Class.java index c9670cdf801..534725ec7ca 100644 --- a/jcl/src/java.base/share/classes/java/lang/Class.java +++ b/jcl/src/java.base/share/classes/java/lang/Class.java @@ -3591,20 +3591,11 @@ private AnnotationCache getAnnotationCache() { if (annotationsData == null) { annotationCacheResult = new AnnotationCache(null, buildAnnotations(null)); } else { - long offset = Unsafe.ARRAY_BYTE_BASE_OFFSET + ((annotationsData.length * Unsafe.ARRAY_BYTE_INDEX_SCALE) - VM.FJ9OBJECT_SIZE); - long ramCPAddr = 0; - if (VM.FJ9OBJECT_SIZE == 4) { - /* Compressed object refs */ - ramCPAddr = Integer.toUnsignedLong(unsafe.getInt(annotationsData, offset)); - } else { - ramCPAddr = unsafe.getLong(annotationsData, offset); - } - Object internalCP = VM.getVMLangAccess().createInternalConstantPool(ramCPAddr); - + ConstantPool cp = VM.getConstantPoolFromAnnotationBytes(this, annotationsData); Annotation[] directAnnotations = sun.reflect.annotation.AnnotationParser.toArray( sun.reflect.annotation.AnnotationParser.parseAnnotations( annotationsData, - getConstantPool(internalCP), + cp, this)); LinkedHashMap, Annotation> directAnnotationsMap = new LinkedHashMap<>(directAnnotations.length * 4 / 3); diff --git a/runtime/jcl/common/reflecthelp.c b/runtime/jcl/common/reflecthelp.c index 776978b5c50..686808219bf 100644 --- a/runtime/jcl/common/reflecthelp.c +++ b/runtime/jcl/common/reflecthelp.c @@ -59,6 +59,20 @@ static J9WalkFieldAction countFieldIterator(J9ROMFieldShape *romField, J9Class * static J9WalkFieldAction allFieldIterator(J9ROMFieldShape *romField, J9Class *declaringClass, void *userData); static jmethodID reflectMethodToID(J9VMThread *vmThread, jobject reflectMethod); +/* Append J9ConstantPool* at end of array so Class.getAnnotationCache, java.lang.reflect.Method and + * java.lang.reflect.Field can use it to get a ConstantPool consistent with the annotation data in case of redefine + */ +static void +appendConstantPoolToByteArray(struct J9VMThread *vmThread, j9object_t byteArray, U_32 byteCount, J9ConstantPool *ramCP) +{ + J9ConstantPool *ramCPPtr = (J9ConstantPool *)(I_8 *)J9JAVAARRAY_EA(vmThread, byteArray, byteCount, I_8); + if (J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(vmThread)) { + *(U_32 *)ramCPPtr = (U_32)(UDATA)ramCP; + } else { + *(UDATA *)ramCPPtr = (UDATA)ramCP; + } +} + static UDATA isConstructor(J9Method *ramMethod) { @@ -77,7 +91,7 @@ isConstructor(J9Method *ramMethod) * If/when the annotation data is moved, these functions must be updated. */ static j9object_t -getAnnotationDataAsByteArray(struct J9VMThread *vmThread, U_32 *annotationData) +getAnnotationDataAsByteArray(struct J9VMThread *vmThread, U_32 *annotationData, struct J9ConstantPool *constantPool) { U_32 i = 0; U_32 byteCount = *annotationData; @@ -94,6 +108,10 @@ getAnnotationDataAsByteArray(struct J9VMThread *vmThread, U_32 *annotationData) J9JAVAARRAYOFBYTE_STORE(vmThread, byteArray, i, byteData[i]); } + if (NULL != constantPool) { + appendConstantPoolToByteArray(vmThread, byteArray, *annotationData, constantPool); + } + return byteArray; } @@ -104,7 +122,7 @@ getAnnotationDataFromROMMethodHelper(struct J9VMThread *vmThread, J9Method *ramM J9ROMMethod *romMethod = (J9ROMMethod *) (ramMethod->bytecodes - sizeof(J9ROMMethod)); U_32 *annotationData = getAnnotationDataFromROMMethod(romMethod); if (NULL != annotationData) { - result = getAnnotationDataAsByteArray(vmThread, annotationData); + result = getAnnotationDataAsByteArray(vmThread, annotationData, J9_CP_FROM_METHOD(ramMethod)); } return result; } @@ -115,20 +133,7 @@ getClassAnnotationData(struct J9VMThread *vmThread, struct J9Class *declaringCla j9object_t result = NULL; U_32 *annotationData = getClassAnnotationsDataForROMClass(declaringClass->romClass); if (NULL != annotationData) { - J9ConstantPool *ramCP = J9_CP_FROM_CLASS(declaringClass); - result = getAnnotationDataAsByteArray(vmThread, annotationData); - if (NULL != result) { - U_32 byteCount = *annotationData; - /* Append J9ConstantPool* at end of array so Class.getAnnotationCache can use it to - * get a ConstantPool consistent with the annotation data in case of redefine - */ - J9ConstantPool *ramCPPtr = (J9ConstantPool *)(I_8 *)J9JAVAARRAY_EA(vmThread, result, byteCount, I_8); - if (J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(vmThread)) { - *(U_32 *)ramCPPtr = (U_32)(UDATA)ramCP; - } else { - *(UDATA *)ramCPPtr = (UDATA)ramCP; - } - } + result = getAnnotationDataAsByteArray(vmThread, annotationData, J9_CP_FROM_CLASS(declaringClass)); } return result; } @@ -146,19 +151,8 @@ getClassTypeAnnotationsAsByteArray(JNIEnv *env, jclass jlClass) struct J9Class *declaringClass = J9VM_J9CLASS_FROM_HEAPCLASS(vmThread, clazz); U_32 *annotationData = getClassTypeAnnotationsDataForROMClass(declaringClass->romClass); if (NULL != annotationData) { - J9ConstantPool *ramCP = J9_CP_FROM_CLASS(declaringClass); - j9object_t annotationsByteArray = getAnnotationDataAsByteArray(vmThread, annotationData); + j9object_t annotationsByteArray = getAnnotationDataAsByteArray(vmThread, annotationData, J9_CP_FROM_CLASS(declaringClass)); if (NULL != annotationsByteArray) { - U_32 byteCount = *annotationData; - /* Append J9ConstantPool* at end of array so Class.getAnnotationCache can use it to - * get a ConstantPool consistent with the annotation data in case of redefine - */ - J9ConstantPool *ramCPPtr = (J9ConstantPool *)(I_8 *)J9JAVAARRAY_EA(vmThread, annotationsByteArray, byteCount, I_8); - if (J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(vmThread)) { - *(U_32 *)ramCPPtr = (U_32)(UDATA)ramCP; - } else { - *(UDATA *)ramCPPtr = (UDATA)ramCP; - } result = vmThread->javaVM->internalVMFunctions->j9jni_createLocalRef(env, annotationsByteArray); } } @@ -173,7 +167,7 @@ getFieldAnnotationData(struct J9VMThread *vmThread, struct J9Class *declaringCla j9object_t result = NULL; U_32 *annotationData = getFieldAnnotationsDataFromROMField(j9FieldID->field); if ( NULL != annotationData ) { - result = getAnnotationDataAsByteArray(vmThread, annotationData); + result = getAnnotationDataAsByteArray(vmThread, annotationData, J9_CP_FROM_CLASS(declaringClass)); } return result; } @@ -181,24 +175,24 @@ getFieldAnnotationData(struct J9VMThread *vmThread, struct J9Class *declaringCla jbyteArray getFieldTypeAnnotationsAsByteArray(JNIEnv *env, jobject jlrField) { - jobject result = NULL; - j9object_t fieldObject = NULL; - J9VMThread *vmThread = (J9VMThread *) env; - - enterVMFromJNI(vmThread); - fieldObject = J9_JNI_UNWRAP_REFERENCE(jlrField); - if (NULL != fieldObject) { - J9JNIFieldID *fieldID = vmThread->javaVM->reflectFunctions.idFromFieldObject(vmThread, NULL, fieldObject); - U_32 *annotationData = getFieldTypeAnnotationsDataFromROMField(fieldID->field); - if ( NULL != annotationData ) { - j9object_t annotationsByteArray = getAnnotationDataAsByteArray(vmThread, annotationData); - if (NULL != annotationsByteArray) { - result = vmThread->javaVM->internalVMFunctions->j9jni_createLocalRef(env, annotationsByteArray); - } - } - } - exitVMToJNI(vmThread); - return result; + jobject result = NULL; + j9object_t fieldObject = NULL; + J9VMThread *vmThread = (J9VMThread *) env; + + enterVMFromJNI(vmThread); + fieldObject = J9_JNI_UNWRAP_REFERENCE(jlrField); + if (NULL != fieldObject) { + J9JNIFieldID *fieldID = vmThread->javaVM->reflectFunctions.idFromFieldObject(vmThread, NULL, fieldObject); + U_32 *annotationData = getFieldTypeAnnotationsDataFromROMField(fieldID->field); + if ( NULL != annotationData ) { + j9object_t annotationsByteArray = getAnnotationDataAsByteArray(vmThread, annotationData, NULL); + if (NULL != annotationsByteArray) { + result = vmThread->javaVM->internalVMFunctions->j9jni_createLocalRef(env, annotationsByteArray); + } + } + } + exitVMToJNI(vmThread); + return result; } /** @@ -1936,7 +1930,7 @@ getRecordComponentsHelper(JNIEnv *env, jobject cls) /* byte[] annotations */ if (recordComponentHasAnnotations(recordComponent)) { U_32* annotationData = getRecordComponentAnnotationData(recordComponent); - j9object_t byteArray = getAnnotationDataAsByteArray(vmThread, annotationData); + j9object_t byteArray = getAnnotationDataAsByteArray(vmThread, annotationData, NULL); if (NULL != vmThread->currentException) { DROP_OBJECT_IN_SPECIAL_FRAME(vmThread); /* recordComponentObject */ goto done; @@ -1948,7 +1942,7 @@ getRecordComponentsHelper(JNIEnv *env, jobject cls) /* byte[] typeAnnotations */ if (recordComponentHasTypeAnnotations(recordComponent)) { U_32* typeAnnotationData = getRecordComponentTypeAnnotationData(recordComponent); - j9object_t byteArray = getAnnotationDataAsByteArray(vmThread, typeAnnotationData); + j9object_t byteArray = getAnnotationDataAsByteArray(vmThread, typeAnnotationData, NULL); if (NULL != vmThread->currentException) { DROP_OBJECT_IN_SPECIAL_FRAME(vmThread); /* recordComponentObject */ goto done;