Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.43.0: Append cp to method and field annotation data to fix redefinition inconsistencies #18491

Merged
merged 1 commit into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
/**
Expand All @@ -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;
}
}
34 changes: 34 additions & 0 deletions jcl/src/java.base/share/classes/com/ibm/oti/vm/VM.java
Original file line number Diff line number Diff line change
Expand Up @@ -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]*/

/**
Expand Down Expand Up @@ -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);
}
}
13 changes: 2 additions & 11 deletions jcl/src/java.base/share/classes/java/lang/Class.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Class<? extends Annotation>, Annotation> directAnnotationsMap = new LinkedHashMap<>(directAnnotations.length * 4 / 3);
Expand Down
92 changes: 43 additions & 49 deletions runtime/jcl/common/reflecthelp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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;
Expand All @@ -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;
}

Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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);
}
}
Expand All @@ -173,32 +167,32 @@ 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;
}

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;
}

/**
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down