From cb5693f0c2968937ae5d40493390ac3d71cd9657 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 16 Sep 2025 16:58:53 +0200 Subject: [PATCH 1/5] keep CompilerToVM::methods initializer sorted --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 229 +++++++++--------- .../CheckCompilerToVMMethodTableIsSorted.java | 120 +++++++++ 2 files changed, 235 insertions(+), 114 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/jvmci/compilerToVM/CheckCompilerToVMMethodTableIsSorted.java diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index e2da3e61a6e..d3017b47ab3 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -3363,140 +3363,141 @@ C2V_END #define HS_CONSTANT_POOL "Ljdk/vm/ci/hotspot/HotSpotConstantPool;" #define HS_CONSTANT_POOL2 "Ljdk/vm/ci/hotspot/HotSpotConstantPool;J" +// Keep this table case-insensitive sorted JNINativeMethod CompilerToVM::methods[] = { + {CC "addFailedSpeculation", CC "(J[B)Z", FN_PTR(addFailedSpeculation)}, + {CC "allocateCompileId", CC "(" HS_METHOD2 "I)I", FN_PTR(allocateCompileId)}, + {CC "arrayBaseOffset", CC "(C)I", FN_PTR(arrayBaseOffset)}, + {CC "arrayIndexScale", CC "(C)I", FN_PTR(arrayIndexScale)}, + {CC "asJavaType", CC "(" OBJECTCONSTANT ")" HS_RESOLVED_TYPE, FN_PTR(asJavaType)}, + {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" REFLECTION_EXECUTABLE, FN_PTR(asReflectionExecutable)}, + {CC "asReflectionField", CC "(" HS_KLASS2 "I)" REFLECTION_FIELD, FN_PTR(asReflectionField)}, + {CC "asResolvedJavaMethod", CC "(" EXECUTABLE ")" HS_METHOD, FN_PTR(asResolvedJavaMethod)}, + {CC "asString", CC "(" OBJECTCONSTANT ")" STRING, FN_PTR(asString)}, + {CC "attachCurrentThread", CC "([BZ[J)Z", FN_PTR(attachCurrentThread)}, + {CC "bootstrapArgumentIndexAt", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(bootstrapArgumentIndexAt)}, + {CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)}, + {CC "callSystemExit", CC "(I)V", FN_PTR(callSystemExit)}, + {CC "clearOopHandle", CC "(J)V", FN_PTR(clearOopHandle)}, + {CC "collectCounters", CC "()[J", FN_PTR(collectCounters)}, + {CC "compileToBytecode", CC "(" OBJECTCONSTANT ")V", FN_PTR(compileToBytecode)}, + {CC "decodeFieldIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(decodeFieldIndexToCPIndex)}, + {CC "decodeIndyIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "IZ)I", FN_PTR(decodeIndyIndexToCPIndex)}, + {CC "decodeMethodIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(decodeMethodIndexToCPIndex)}, + {CC "detachCurrentThread", CC "(Z)Z", FN_PTR(detachCurrentThread)}, + {CC "disassembleCodeBlob", CC "(" INSTALLED_CODE ")" STRING, FN_PTR(disassembleCodeBlob)}, + {CC "ensureInitialized", CC "(" HS_KLASS2 ")V", FN_PTR(ensureInitialized)}, + {CC "ensureLinked", CC "(" HS_KLASS2 ")V", FN_PTR(ensureLinked)}, + {CC "equals", CC "(" OBJECTCONSTANT "J" OBJECTCONSTANT "J)Z", FN_PTR(equals)}, + {CC "executeHotSpotNmethod", CC "([" OBJECT HS_NMETHOD ")" OBJECT, FN_PTR(executeHotSpotNmethod)}, + {CC "findUniqueConcreteMethod", CC "(" HS_KLASS2 HS_METHOD2 ")" HS_METHOD, FN_PTR(findUniqueConcreteMethod)}, + {CC "flushDebugOutput", CC "()V", FN_PTR(flushDebugOutput)}, + {CC "getAllMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getAllMethods)}, + {CC "getArrayLength", CC "(" OBJECTCONSTANT ")I", FN_PTR(getArrayLength)}, + {CC "getArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getArrayType)}, {CC "getBytecode", CC "(" HS_METHOD2 ")[B", FN_PTR(getBytecode)}, - {CC "getExceptionTableStart", CC "(" HS_METHOD2 ")J", FN_PTR(getExceptionTableStart)}, + {CC "getClassInitializer", CC "(" HS_KLASS2 ")" HS_METHOD, FN_PTR(getClassInitializer)}, + {CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)}, + {CC "getCompilationActivityMode", CC "()I", FN_PTR(getCompilationActivityMode)}, + {CC "getComponentType", CC "(" HS_KLASS2 ")" HS_RESOLVED_TYPE, FN_PTR(getComponentType)}, + {CC "getConstantPool", CC "(" OBJECT "JZ)" HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, + {CC "getCountersSize", CC "()I", FN_PTR(getCountersSize)}, + {CC "getCurrentJavaThread", CC "()J", FN_PTR(getCurrentJavaThread)}, + {CC "getDeclaredConstructors", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)}, + {CC "getDeclaredFieldsInfo", CC "(" HS_KLASS2 ")[" FIELDINFO, FN_PTR(getDeclaredFieldsInfo)}, + {CC "getDeclaredMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)}, + {CC "getDeclaredTypes", CC "(" HS_KLASS2 ")[" HS_KLASS, FN_PTR(getDeclaredTypes)}, + {CC "getEncodedClassAnnotationData", CC "(" HS_KLASS2 OBJECT "IJ)[B", FN_PTR(getEncodedClassAnnotationData)}, + {CC "getEncodedExecutableAnnotationData", CC "(" HS_METHOD2 OBJECT "IJ)[B", FN_PTR(getEncodedExecutableAnnotationData)}, + {CC "getEncodedFieldAnnotationData", CC "(" HS_KLASS2 "I" OBJECT "IJ)[B", FN_PTR(getEncodedFieldAnnotationData)}, {CC "getExceptionTableLength", CC "(" HS_METHOD2 ")I", FN_PTR(getExceptionTableLength)}, - {CC "findUniqueConcreteMethod", CC "(" HS_KLASS2 HS_METHOD2 ")" HS_METHOD, FN_PTR(findUniqueConcreteMethod)}, + {CC "getExceptionTableStart", CC "(" HS_METHOD2 ")J", FN_PTR(getExceptionTableStart)}, + {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, + {CC "getFailedSpeculationsAddress", CC "(" HS_METHOD2 ")J", FN_PTR(getFailedSpeculationsAddress)}, + {CC "getFlagValue", CC "(" STRING ")" OBJECT, FN_PTR(getFlagValue)}, + {CC "getIdentityHashCode", CC "(" OBJECTCONSTANT ")I", FN_PTR(getIdentityHashCode)}, {CC "getImplementor", CC "(" HS_KLASS2 ")" HS_KLASS, FN_PTR(getImplementor)}, - {CC "getStackTraceElement", CC "(" HS_METHOD2 "I)" STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, - {CC "methodIsIgnoredBySecurityStackWalk", CC "(" HS_METHOD2 ")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, - {CC "setNotInlinableOrCompilable", CC "(" HS_METHOD2 ")V", FN_PTR(setNotInlinableOrCompilable)}, - {CC "isCompilable", CC "(" HS_METHOD2 ")Z", FN_PTR(isCompilable)}, - {CC "hasNeverInlineDirective", CC "(" HS_METHOD2 ")Z", FN_PTR(hasNeverInlineDirective)}, - {CC "shouldInlineMethod", CC "(" HS_METHOD2 ")Z", FN_PTR(shouldInlineMethod)}, - {CC "lookupType", CC "(" STRING HS_KLASS2 "IZ)" HS_RESOLVED_TYPE, FN_PTR(lookupType)}, - {CC "lookupJClass", CC "(J)" HS_RESOLVED_TYPE, FN_PTR(lookupJClass)}, + {CC "getInstallCodeFlags", CC "()I", FN_PTR(getInstallCodeFlags)}, + {CC "getInterfaces", CC "(" HS_KLASS2 ")[" HS_KLASS, FN_PTR(getInterfaces)}, + {CC "getJavaMirror", CC "(" HS_KLASS2 ")" OBJECTCONSTANT, FN_PTR(getJavaMirror)}, {CC "getJObjectValue", CC "(" OBJECTCONSTANT ")J", FN_PTR(getJObjectValue)}, - {CC "getArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getArrayType)}, - {CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)}, - {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupNameInPool)}, - {CC "lookupNameAndTypeRefIndexInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, - {CC "lookupSignatureInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupSignatureInPool)}, - {CC "lookupKlassRefIndexInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(lookupKlassRefIndexInPool)}, - {CC "lookupKlassInPool", CC "(" HS_CONSTANT_POOL2 "I)Ljava/lang/Object;", FN_PTR(lookupKlassInPool)}, - {CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL2 "II)" OBJECTCONSTANT, FN_PTR(lookupAppendixInPool)}, - {CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL2 "IB" HS_METHOD2 ")" HS_METHOD, FN_PTR(lookupMethodInPool)}, - {CC "lookupConstantInPool", CC "(" HS_CONSTANT_POOL2 "IZ)" JAVACONSTANT, FN_PTR(lookupConstantInPool)}, + {CC "getLineNumberTable", CC "(" HS_METHOD2 ")[J", FN_PTR(getLineNumberTable)}, + {CC "getLocalVariableTableLength", CC "(" HS_METHOD2 ")I", FN_PTR(getLocalVariableTableLength)}, + {CC "getLocalVariableTableStart", CC "(" HS_METHOD2 ")J", FN_PTR(getLocalVariableTableStart)}, + {CC "getMaxCallTargetOffset", CC "(J)J", FN_PTR(getMaxCallTargetOffset)}, {CC "getNumIndyEntries", CC "(" HS_CONSTANT_POOL2 ")I", FN_PTR(getNumIndyEntries)}, - {CC "resolveBootstrapMethod", CC "(" HS_CONSTANT_POOL2 "I)[" OBJECT, FN_PTR(resolveBootstrapMethod)}, - {CC "bootstrapArgumentIndexAt", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(bootstrapArgumentIndexAt)}, - {CC "getUncachedStringInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(getUncachedStringInPool)}, - {CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL2 "I)" HS_KLASS, FN_PTR(resolveTypeInPool)}, - {CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL2 "I" HS_METHOD2 "B[I)" HS_KLASS, FN_PTR(resolveFieldInPool)}, - {CC "decodeFieldIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(decodeFieldIndexToCPIndex)}, - {CC "decodeMethodIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(decodeMethodIndexToCPIndex)}, - {CC "decodeIndyIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "IZ)I", FN_PTR(decodeIndyIndexToCPIndex)}, - {CC "resolveInvokeHandleInPool", CC "(" HS_CONSTANT_POOL2 "I)V", FN_PTR(resolveInvokeHandleInPool)}, - {CC "isResolvedInvokeHandleInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(isResolvedInvokeHandleInPool)}, - {CC "resolveMethod", CC "(" HS_KLASS2 HS_METHOD2 HS_KLASS2 ")" HS_METHOD, FN_PTR(resolveMethod)}, + {CC "getOopMapAt", CC "(" HS_METHOD2 "I[J)V", FN_PTR(getOopMapAt)}, + {CC "getResolvedJavaMethod", CC "(" OBJECTCONSTANT "J)" HS_METHOD, FN_PTR(getResolvedJavaMethod)}, + {CC "getResolvedJavaType0", CC "(Ljava/lang/Object;JZ)" HS_KLASS, FN_PTR(getResolvedJavaType0)}, + {CC "getSignatureName", CC "(J)" STRING, FN_PTR(getSignatureName)}, {CC "getSignaturePolymorphicHolders", CC "()[" STRING, FN_PTR(getSignaturePolymorphicHolders)}, + {CC "getStackTraceElement", CC "(" HS_METHOD2 "I)" STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, + {CC "getSymbol", CC "(J)" STRING, FN_PTR(getSymbol)}, + {CC "getThreadLocalLong", CC "(I)J", FN_PTR(getThreadLocalLong)}, + {CC "getThreadLocalObject", CC "(I)" OBJECT, FN_PTR(getThreadLocalObject)}, + {CC "getUncachedStringInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(getUncachedStringInPool)}, {CC "getVtableIndexForInterfaceMethod", CC "(" HS_KLASS2 HS_METHOD2 ")I", FN_PTR(getVtableIndexForInterfaceMethod)}, - {CC "getClassInitializer", CC "(" HS_KLASS2 ")" HS_METHOD, FN_PTR(getClassInitializer)}, + {CC "hasCompiledCodeForOSR", CC "(" HS_METHOD2 "II)Z", FN_PTR(hasCompiledCodeForOSR)}, {CC "hasFinalizableSubclass", CC "(" HS_KLASS2 ")Z", FN_PTR(hasFinalizableSubclass)}, - {CC "getMaxCallTargetOffset", CC "(J)J", FN_PTR(getMaxCallTargetOffset)}, - {CC "asResolvedJavaMethod", CC "(" EXECUTABLE ")" HS_METHOD, FN_PTR(asResolvedJavaMethod)}, - {CC "getResolvedJavaMethod", CC "(" OBJECTCONSTANT "J)" HS_METHOD, FN_PTR(getResolvedJavaMethod)}, - {CC "getConstantPool", CC "(" OBJECT "JZ)" HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, - {CC "getResolvedJavaType0", CC "(Ljava/lang/Object;JZ)" HS_KLASS, FN_PTR(getResolvedJavaType0)}, - {CC "readConfiguration", CC "()[" OBJECT, FN_PTR(readConfiguration)}, + {CC "hasNeverInlineDirective", CC "(" HS_METHOD2 ")Z", FN_PTR(hasNeverInlineDirective)}, {CC "installCode0", CC "(JJZ" HS_COMPILED_CODE "[" OBJECT INSTALLED_CODE "J[B)I", FN_PTR(installCode0)}, - {CC "getInstallCodeFlags", CC "()I", FN_PTR(getInstallCodeFlags)}, - {CC "resetCompilationStatistics", CC "()V", FN_PTR(resetCompilationStatistics)}, - {CC "disassembleCodeBlob", CC "(" INSTALLED_CODE ")" STRING, FN_PTR(disassembleCodeBlob)}, - {CC "executeHotSpotNmethod", CC "([" OBJECT HS_NMETHOD ")" OBJECT, FN_PTR(executeHotSpotNmethod)}, - {CC "getLineNumberTable", CC "(" HS_METHOD2 ")[J", FN_PTR(getLineNumberTable)}, - {CC "getLocalVariableTableStart", CC "(" HS_METHOD2 ")J", FN_PTR(getLocalVariableTableStart)}, - {CC "getLocalVariableTableLength", CC "(" HS_METHOD2 ")I", FN_PTR(getLocalVariableTableLength)}, - {CC "reprofile", CC "(" HS_METHOD2 ")V", FN_PTR(reprofile)}, + {CC "interpreterFrameSize", CC "(" BYTECODE_FRAME ")I", FN_PTR(interpreterFrameSize)}, {CC "invalidateHotSpotNmethod", CC "(" HS_NMETHOD "Z)V", FN_PTR(invalidateHotSpotNmethod)}, - {CC "collectCounters", CC "()[J", FN_PTR(collectCounters)}, - {CC "getCountersSize", CC "()I", FN_PTR(getCountersSize)}, - {CC "setCountersSize", CC "(I)Z", FN_PTR(setCountersSize)}, - {CC "allocateCompileId", CC "(" HS_METHOD2 "I)I", FN_PTR(allocateCompileId)}, + {CC "isAssignableFrom", CC "(" HS_KLASS2 HS_KLASS2 ")Z", FN_PTR(isAssignableFrom)}, + {CC "isCompilable", CC "(" HS_METHOD2 ")Z", FN_PTR(isCompilable)}, + {CC "isCompilerThread", CC "()Z", FN_PTR(isCompilerThread)}, + {CC "isCurrentThreadAttached", CC "()Z", FN_PTR(isCurrentThreadAttached)}, + {CC "isInstance", CC "(" HS_KLASS2 OBJECTCONSTANT ")Z", FN_PTR(isInstance)}, + {CC "isInternedString", CC "(" OBJECTCONSTANT ")Z", FN_PTR(isInternedString)}, {CC "isMature", CC "(J)Z", FN_PTR(isMature)}, - {CC "hasCompiledCodeForOSR", CC "(" HS_METHOD2 "II)Z", FN_PTR(hasCompiledCodeForOSR)}, - {CC "getSymbol", CC "(J)" STRING, FN_PTR(getSymbol)}, - {CC "getSignatureName", CC "(J)" STRING, FN_PTR(getSignatureName)}, + {CC "isResolvedInvokeHandleInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(isResolvedInvokeHandleInPool)}, + {CC "isTrustedForIntrinsics", CC "(" HS_KLASS2 ")Z", FN_PTR(isTrustedForIntrinsics)}, {CC "iterateFrames", CC "([" RESOLVED_METHOD "[" RESOLVED_METHOD "I" INSPECTED_FRAME_VISITOR ")" OBJECT, FN_PTR(iterateFrames)}, + {CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL2 "II)" OBJECTCONSTANT, FN_PTR(lookupAppendixInPool)}, + {CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)}, + {CC "lookupConstantInPool", CC "(" HS_CONSTANT_POOL2 "IZ)" JAVACONSTANT, FN_PTR(lookupConstantInPool)}, + {CC "lookupJClass", CC "(J)" HS_RESOLVED_TYPE, FN_PTR(lookupJClass)}, + {CC "lookupKlassInPool", CC "(" HS_CONSTANT_POOL2 "I)Ljava/lang/Object;", FN_PTR(lookupKlassInPool)}, + {CC "lookupKlassRefIndexInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(lookupKlassRefIndexInPool)}, + {CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL2 "IB" HS_METHOD2 ")" HS_METHOD, FN_PTR(lookupMethodInPool)}, + {CC "lookupNameAndTypeRefIndexInPool", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, + {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupNameInPool)}, + {CC "lookupSignatureInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupSignatureInPool)}, + {CC "lookupType", CC "(" STRING HS_KLASS2 "IZ)" HS_RESOLVED_TYPE, FN_PTR(lookupType)}, {CC "materializeVirtualObjects", CC "(" HS_STACK_FRAME_REF "Z)V", FN_PTR(materializeVirtualObjects)}, - {CC "shouldDebugNonSafepoints", CC "()Z", FN_PTR(shouldDebugNonSafepoints)}, - {CC "writeDebugOutput", CC "(JIZ)V", FN_PTR(writeDebugOutput)}, - {CC "flushDebugOutput", CC "()V", FN_PTR(flushDebugOutput)}, - {CC "methodDataProfileDataSize", CC "(JI)I", FN_PTR(methodDataProfileDataSize)}, {CC "methodDataExceptionSeen", CC "(JI)I", FN_PTR(methodDataExceptionSeen)}, - {CC "interpreterFrameSize", CC "(" BYTECODE_FRAME ")I", FN_PTR(interpreterFrameSize)}, - {CC "compileToBytecode", CC "(" OBJECTCONSTANT ")V", FN_PTR(compileToBytecode)}, - {CC "getFlagValue", CC "(" STRING ")" OBJECT, FN_PTR(getFlagValue)}, - {CC "getInterfaces", CC "(" HS_KLASS2 ")[" HS_KLASS, FN_PTR(getInterfaces)}, - {CC "getComponentType", CC "(" HS_KLASS2 ")" HS_RESOLVED_TYPE, FN_PTR(getComponentType)}, - {CC "ensureInitialized", CC "(" HS_KLASS2 ")V", FN_PTR(ensureInitialized)}, - {CC "ensureLinked", CC "(" HS_KLASS2 ")V", FN_PTR(ensureLinked)}, - {CC "getIdentityHashCode", CC "(" OBJECTCONSTANT ")I", FN_PTR(getIdentityHashCode)}, - {CC "isInternedString", CC "(" OBJECTCONSTANT ")Z", FN_PTR(isInternedString)}, - {CC "unboxPrimitive", CC "(" OBJECTCONSTANT ")" OBJECT, FN_PTR(unboxPrimitive)}, - {CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)}, - {CC "getDeclaredConstructors", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)}, - {CC "getDeclaredMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)}, - {CC "getAllMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getAllMethods)}, - {CC "getDeclaredFieldsInfo", CC "(" HS_KLASS2 ")[" FIELDINFO, FN_PTR(getDeclaredFieldsInfo)}, - {CC "readStaticFieldValue", CC "(" HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readStaticFieldValue)}, - {CC "readFieldValue", CC "(" OBJECTCONSTANT HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readFieldValue)}, - {CC "isInstance", CC "(" HS_KLASS2 OBJECTCONSTANT ")Z", FN_PTR(isInstance)}, - {CC "isAssignableFrom", CC "(" HS_KLASS2 HS_KLASS2 ")Z", FN_PTR(isAssignableFrom)}, - {CC "isTrustedForIntrinsics", CC "(" HS_KLASS2 ")Z", FN_PTR(isTrustedForIntrinsics)}, - {CC "asJavaType", CC "(" OBJECTCONSTANT ")" HS_RESOLVED_TYPE, FN_PTR(asJavaType)}, - {CC "asString", CC "(" OBJECTCONSTANT ")" STRING, FN_PTR(asString)}, - {CC "equals", CC "(" OBJECTCONSTANT "J" OBJECTCONSTANT "J)Z", FN_PTR(equals)}, - {CC "getJavaMirror", CC "(" HS_KLASS2 ")" OBJECTCONSTANT, FN_PTR(getJavaMirror)}, - {CC "getArrayLength", CC "(" OBJECTCONSTANT ")I", FN_PTR(getArrayLength)}, + {CC "methodDataProfileDataSize", CC "(JI)I", FN_PTR(methodDataProfileDataSize)}, + {CC "methodIsIgnoredBySecurityStackWalk", CC "(" HS_METHOD2 ")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, + {CC "notifyCompilerInliningEvent", CC "(I" HS_METHOD2 HS_METHOD2 "ZLjava/lang/String;I)V", FN_PTR(notifyCompilerInliningEvent)}, + {CC "notifyCompilerPhaseEvent", CC "(JIII)V", FN_PTR(notifyCompilerPhaseEvent)}, {CC "readArrayElement", CC "(" OBJECTCONSTANT "I)Ljava/lang/Object;", FN_PTR(readArrayElement)}, - {CC "arrayBaseOffset", CC "(C)I", FN_PTR(arrayBaseOffset)}, - {CC "arrayIndexScale", CC "(C)I", FN_PTR(arrayIndexScale)}, - {CC "clearOopHandle", CC "(J)V", FN_PTR(clearOopHandle)}, - {CC "releaseClearedOopHandles", CC "()V", FN_PTR(releaseClearedOopHandles)}, + {CC "readConfiguration", CC "()[" OBJECT, FN_PTR(readConfiguration)}, + {CC "readFieldValue", CC "(" OBJECTCONSTANT HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readFieldValue)}, + {CC "readStaticFieldValue", CC "(" HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readStaticFieldValue)}, + {CC "registerCompilerPhase", CC "(" STRING ")I", FN_PTR(registerCompilerPhase)}, {CC "registerNativeMethods", CC "(" CLASS ")[J", FN_PTR(registerNativeMethods)}, - {CC "isCurrentThreadAttached", CC "()Z", FN_PTR(isCurrentThreadAttached)}, - {CC "getCurrentJavaThread", CC "()J", FN_PTR(getCurrentJavaThread)}, - {CC "attachCurrentThread", CC "([BZ[J)Z", FN_PTR(attachCurrentThread)}, - {CC "detachCurrentThread", CC "(Z)Z", FN_PTR(detachCurrentThread)}, - {CC "translate", CC "(" OBJECT "Z)J", FN_PTR(translate)}, - {CC "unhand", CC "(J)" OBJECT, FN_PTR(unhand)}, - {CC "updateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(updateHotSpotNmethod)}, - {CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)}, - {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" REFLECTION_EXECUTABLE, FN_PTR(asReflectionExecutable)}, - {CC "asReflectionField", CC "(" HS_KLASS2 "I)" REFLECTION_FIELD, FN_PTR(asReflectionField)}, - {CC "getEncodedClassAnnotationData", CC "(" HS_KLASS2 OBJECT "IJ)[B", FN_PTR(getEncodedClassAnnotationData)}, - {CC "getEncodedExecutableAnnotationData", CC "(" HS_METHOD2 OBJECT "IJ)[B", FN_PTR(getEncodedExecutableAnnotationData)}, - {CC "getEncodedFieldAnnotationData", CC "(" HS_KLASS2 "I" OBJECT "IJ)[B", FN_PTR(getEncodedFieldAnnotationData)}, - {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, - {CC "getFailedSpeculationsAddress", CC "(" HS_METHOD2 ")J", FN_PTR(getFailedSpeculationsAddress)}, + {CC "releaseClearedOopHandles", CC "()V", FN_PTR(releaseClearedOopHandles)}, {CC "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)}, - {CC "addFailedSpeculation", CC "(J[B)Z", FN_PTR(addFailedSpeculation)}, - {CC "callSystemExit", CC "(I)V", FN_PTR(callSystemExit)}, - {CC "ticksNow", CC "()J", FN_PTR(ticksNow)}, - {CC "getThreadLocalObject", CC "(I)" OBJECT, FN_PTR(getThreadLocalObject)}, - {CC "setThreadLocalObject", CC "(I" OBJECT ")V", FN_PTR(setThreadLocalObject)}, - {CC "getThreadLocalLong", CC "(I)J", FN_PTR(getThreadLocalLong)}, + {CC "reprofile", CC "(" HS_METHOD2 ")V", FN_PTR(reprofile)}, + {CC "resetCompilationStatistics", CC "()V", FN_PTR(resetCompilationStatistics)}, + {CC "resolveBootstrapMethod", CC "(" HS_CONSTANT_POOL2 "I)[" OBJECT, FN_PTR(resolveBootstrapMethod)}, + {CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL2 "I" HS_METHOD2 "B[I)" HS_KLASS, FN_PTR(resolveFieldInPool)}, + {CC "resolveInvokeHandleInPool", CC "(" HS_CONSTANT_POOL2 "I)V", FN_PTR(resolveInvokeHandleInPool)}, + {CC "resolveMethod", CC "(" HS_KLASS2 HS_METHOD2 HS_KLASS2 ")" HS_METHOD, FN_PTR(resolveMethod)}, + {CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL2 "I)" HS_KLASS, FN_PTR(resolveTypeInPool)}, + {CC "setCountersSize", CC "(I)Z", FN_PTR(setCountersSize)}, + {CC "setNotInlinableOrCompilable", CC "(" HS_METHOD2 ")V", FN_PTR(setNotInlinableOrCompilable)}, {CC "setThreadLocalLong", CC "(IJ)V", FN_PTR(setThreadLocalLong)}, - {CC "registerCompilerPhase", CC "(" STRING ")I", FN_PTR(registerCompilerPhase)}, - {CC "notifyCompilerPhaseEvent", CC "(JIII)V", FN_PTR(notifyCompilerPhaseEvent)}, - {CC "notifyCompilerInliningEvent", CC "(I" HS_METHOD2 HS_METHOD2 "ZLjava/lang/String;I)V", FN_PTR(notifyCompilerInliningEvent)}, - {CC "getOopMapAt", CC "(" HS_METHOD2 "I[J)V", FN_PTR(getOopMapAt)}, + {CC "setThreadLocalObject", CC "(I" OBJECT ")V", FN_PTR(setThreadLocalObject)}, + {CC "shouldDebugNonSafepoints", CC "()Z", FN_PTR(shouldDebugNonSafepoints)}, + {CC "shouldInlineMethod", CC "(" HS_METHOD2 ")Z", FN_PTR(shouldInlineMethod)}, + {CC "ticksNow", CC "()J", FN_PTR(ticksNow)}, + {CC "translate", CC "(" OBJECT "Z)J", FN_PTR(translate)}, + {CC "unboxPrimitive", CC "(" OBJECTCONSTANT ")" OBJECT, FN_PTR(unboxPrimitive)}, + {CC "unhand", CC "(J)" OBJECT, FN_PTR(unhand)}, {CC "updateCompilerThreadCanCallJava", CC "(Z)Z", FN_PTR(updateCompilerThreadCanCallJava)}, - {CC "getCompilationActivityMode", CC "()I", FN_PTR(getCompilationActivityMode)}, - {CC "isCompilerThread", CC "()Z", FN_PTR(isCompilerThread)}, - {CC "getDeclaredTypes", CC "(" HS_KLASS2 ")[" HS_KLASS, FN_PTR(getDeclaredTypes)}, + {CC "updateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(updateHotSpotNmethod)}, + {CC "writeDebugOutput", CC "(JIZ)V", FN_PTR(writeDebugOutput)}, }; int CompilerToVM::methods_count() { diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/CheckCompilerToVMMethodTableIsSorted.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/CheckCompilerToVMMethodTableIsSorted.java new file mode 100644 index 00000000000..412bbe3c524 --- /dev/null +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/CheckCompilerToVMMethodTableIsSorted.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Tests that the initializer for CompilerToVM::methods is sorted (case-insensitive). + * @run main compiler.jvmci.compilerToVM.CheckCompilerToVMMethodTableIsSorted + */ + +package compiler.jvmci.compilerToVM; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public class CheckCompilerToVMMethodTableIsSorted { + + public static final String METHOD_TABLE_DECL_OPEN = "JNINativeMethod CompilerToVM::methods[] = {"; + public static final String METHOD_TABLE_DECL_CLOSE = "};"; + + /** + * Gets the absolute path to {@code /src/hotspot} by searching up the file system starting + * at {@code dir}. + */ + private static Path getHotSpotSrcDir(Path dir) { + while (dir != null) { + Path path = dir.resolve("src").resolve("hotspot"); + if (Files.exists(path)) { + return path; + } + dir = dir.getParent(); + } + throw new RuntimeException("Could not locate the src/hotspot directory by searching up from " + dir); + } + + public static void main(String[] args) throws IOException { + Path testSrcDir = null; + Path jvmciCompilerToVM; + boolean check; + if (args.length == 0) { + check = true; + testSrcDir = Paths.get(System.getProperty("test.src")); + Path root = getHotSpotSrcDir(testSrcDir); + jvmciCompilerToVM = root.resolve("share/jvmci/jvmciCompilerToVM.cpp"); + } else { + check = false; + jvmciCompilerToVM = Path.of(args[0]); + } + List lines = Files.readAllLines(jvmciCompilerToVM); + int open = lines.indexOf(METHOD_TABLE_DECL_OPEN); + if (open == -1) { + throw new RuntimeException("Could not find \"" + METHOD_TABLE_DECL_OPEN + "\" in " + jvmciCompilerToVM); + } + int close = lines.subList(open, lines.size()).indexOf(METHOD_TABLE_DECL_CLOSE); + if (close == -1) { + throw new RuntimeException("Could not find \"" + METHOD_TABLE_DECL_CLOSE + "\" in " + jvmciCompilerToVM + " after line " + open); + } + close = open + close; + List table = lines.subList(open + 1, close); + List sortedTable = table.stream().sorted(Comparator.comparing(String::toLowerCase)).toList(); + String unsortedMsg = null; + for (int i = 0; i != table.size(); i++) { + String expect = sortedTable.get(i); + String actual = table.get(i); + if (!expect.equals(actual)) { + unsortedMsg = String.format("CompilerToVM::methods table is out of (case-insensitive) order%n%s:%d:%n expect: %s%n actual: %s", + jvmciCompilerToVM, i + open + 2, expect, actual); + if (check) { + String errorMsg = String.format(""" + %s + + This should be fixable by running: + + java %s.java %s + """, + unsortedMsg, + testSrcDir.resolve(CheckCompilerToVMMethodTableIsSorted.class.getSimpleName()), + jvmciCompilerToVM); + throw new RuntimeException(errorMsg); + } + break; + } + } + if (unsortedMsg != null) { + // Update file + System.out.println(unsortedMsg); + List newLines = new ArrayList<>(lines.subList(0, open + 1)); + newLines.addAll(sortedTable); + newLines.addAll(lines.subList(close, lines.size())); + Files.writeString(jvmciCompilerToVM, String.join("\n", newLines) + "\n"); + System.out.printf("CompilerToVM::methods table in %s is now sorted%n", jvmciCompilerToVM); + } else { + System.out.printf("CompilerToVM::methods table in %s is already sorted%n", jvmciCompilerToVM); + } + } +} From 4a356befb37cedb0a28ec77574172ce15b64b2c9 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Wed, 24 Sep 2025 10:48:30 +0200 Subject: [PATCH 2/5] removed default implementation of ResolvedJavaType.lookupType --- .../classes/jdk/vm/ci/meta/ResolvedJavaType.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index c951d43b3de..56b5966b530 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -459,12 +459,15 @@ default ResolvedJavaMethod findMethod(String name, Signature signature) { boolean isCloneableWithAllocation(); /** - * Lookup an unresolved type relative to an existing resolved type. + * Looks up {@code unresolvedJavaType} using the class loader of this resolved type. + * + * @param resolve specifies whether to attempt resolution if there is no currently resolved + * type corresponding to {@code unresolvedJavaType} + * @return a resolved type for {@code unresolvedJavaType} or null + * @throws LinkageError if {@code resolve == true} and resolution failed */ @SuppressWarnings("unused") - default ResolvedJavaType lookupType(UnresolvedJavaType unresolvedJavaType, boolean resolve) { - return null; - } + ResolvedJavaType lookupType(UnresolvedJavaType unresolvedJavaType, boolean resolve); @SuppressWarnings("unused") default ResolvedJavaField resolveField(UnresolvedJavaField unresolvedJavaField, ResolvedJavaType accessingClass) { From 63403659f8795e4f1c310031ff6cf1574152ca99 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 16 Sep 2025 15:11:23 +0200 Subject: [PATCH 3/5] reduced JVMCI annotation API to accessing raw class file bytes and added ResolvedJavaRecordComponent --- src/hotspot/share/classfile/vmSymbols.hpp | 2 - src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 202 +++++---- src/hotspot/share/jvmci/jvmciCompilerToVM.hpp | 8 +- .../share/jvmci/jvmciCompilerToVMInit.cpp | 4 +- src/hotspot/share/jvmci/jvmciEnv.cpp | 25 ++ src/hotspot/share/jvmci/jvmciEnv.hpp | 1 + src/hotspot/share/jvmci/jvmciJavaClasses.hpp | 13 +- src/hotspot/share/jvmci/jvmciRuntime.cpp | 11 + src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 7 +- src/hotspot/share/jvmci/vmSymbols_jvmci.hpp | 3 + .../classes/jdk/internal/vm/VMSupport.java | 416 ------------------ .../vm/ci/hotspot/AnnotationDataDecoder.java | 73 --- .../jdk/vm/ci/hotspot/CompilerToVM.java | 131 ++---- .../vm/ci/hotspot/HotSpotConstantPool.java | 3 +- .../vm/ci/hotspot/HotSpotJVMCIRuntime.java | 8 + .../ci/hotspot/HotSpotMetaAccessProvider.java | 3 - .../hotspot/HotSpotResolvedJavaFieldImpl.java | 73 ++- .../HotSpotResolvedJavaMethodImpl.java | 108 ++--- .../HotSpotResolvedJavaRecordComponent.java | 103 +++++ .../ci/hotspot/HotSpotResolvedJavaType.java | 16 +- .../HotSpotResolvedObjectTypeImpl.java | 111 ++--- .../hotspot/HotSpotResolvedPrimitiveType.java | 43 +- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 25 +- .../classes/jdk/vm/ci/meta/Annotated.java | 72 --- .../jdk/vm/ci/meta/AnnotationData.java | 161 ------- .../classes/jdk/vm/ci/meta/EnumData.java | 78 ---- .../classes/jdk/vm/ci/meta/JavaKind.java | 147 +++---- .../jdk/vm/ci/meta/MetaAccessProvider.java | 20 + .../jdk/vm/ci/meta/ResolvedJavaField.java | 2 + .../jdk/vm/ci/meta/ResolvedJavaMethod.java | 20 +- .../ci/meta/ResolvedJavaRecordComponent.java | 61 +++ .../jdk/vm/ci/meta/ResolvedJavaType.java | 17 +- .../jdk/vm/ci/meta/UnresolvedJavaType.java | 6 +- .../Annotated.java} | 48 +- .../ci/meta/annotation/AnnotationsInfo.java | 48 ++ .../classes/jdk/vm/ci/runtime/JVMCI.java | 2 +- .../jdk/vm/ci/runtime/test/FieldUniverse.java | 11 +- .../vm/ci/runtime/test/MethodUniverse.java | 2 +- .../runtime/test/TestResolvedJavaField.java | 63 +-- .../runtime/test/TestResolvedJavaMethod.java | 164 +++---- .../test/TestResolvedJavaRecordComponent.java | 134 ++++++ .../ci/runtime/test/TestResolvedJavaType.java | 371 +++++----------- .../jdk/vm/ci/runtime/test/TypeUniverse.java | 136 +++++- .../AnnotationTestInput.java | 375 ---------------- .../MemberDeleted.java | 33 -- .../MemberTypeChanged.java | 33 -- .../TestAnnotationEncodingDecoding.java | 257 ----------- .../alt/MemberDeleted.java | 32 -- .../alt/MemberTypeChanged.java | 33 -- 49 files changed, 1239 insertions(+), 2476 deletions(-) delete mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationDataDecoder.java create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaRecordComponent.java delete mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java delete mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationData.java delete mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaRecordComponent.java rename src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/{ErrorData.java => annotation/Annotated.java} (56%) create mode 100644 src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationsInfo.java create mode 100644 test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java delete mode 100644 test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java delete mode 100644 test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java delete mode 100644 test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java delete mode 100644 test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java delete mode 100644 test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java delete mode 100644 test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index dc9ce61627b..19f1b48d6b8 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -705,8 +705,6 @@ class SerializeClosure; template(encodeThrowable_name, "encodeThrowable") \ template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \ template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \ - template(encodeAnnotations_name, "encodeAnnotations") \ - template(encodeAnnotations_signature, "([BLjava/lang/Class;Ljdk/internal/reflect/ConstantPool;Z[Ljava/lang/Class;)[B")\ template(decodeAndThrowThrowable_signature, "(IJZZ)V") \ template(classRedefinedCount_name, "classRedefinedCount") \ template(classLoader_name, "classLoader") \ diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index d3017b47ab3..f993b3bed1e 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -49,6 +49,7 @@ #include "oops/instanceMirrorKlass.hpp" #include "oops/method.inline.hpp" #include "oops/objArrayKlass.inline.hpp" +#include "oops/recordComponent.hpp" #include "oops/trainingData.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" @@ -400,7 +401,7 @@ C2V_VMENTRY_NULL(jobject, asResolvedJavaMethod, (JNIEnv* env, jobject, jobject e methodHandle method (THREAD, InstanceKlass::cast(holder)->method_with_idnum(slot)); JVMCIObject result = JVMCIENV->get_jvmci_method(method, JVMCI_CHECK_NULL); return JVMCIENV->get_jobject(result); -} +C2V_END C2V_VMENTRY_PREFIX(jboolean, updateCompilerThreadCanCallJava, (JNIEnv* env, jobject, jboolean newState)) return CompilerThreadCanCallJava::update(thread, newState) != nullptr; @@ -2283,6 +2284,28 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, ARGUME return JVMCIENV->get_jobjectArray(methods); C2V_END +C2V_VMENTRY_NULL(jobjectArray, getRecordComponents, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) + Klass* klass = UNPACK_PAIR(Klass, klass); + if (klass == nullptr) { + JVMCI_THROW_NULL(NullPointerException); + } + if (!klass->is_instance_klass()) { + return nullptr; + } + + InstanceKlass* iklass = InstanceKlass::cast(klass); + Array* components = iklass->record_components(); + if (components == nullptr) { + return nullptr; + } + JVMCIObjectArray res = JVMCIENV->new_ResolvedJavaRecordComponent_array(components->length(), JVMCI_CHECK_NULL); + for (int i = 0; i < components->length(); i++) { + JVMCIObject component = JVMCIENV->new_HotSpotResolvedJavaRecordComponent(JVMCIENV->wrap(klass_obj), i, components->at(i), JVMCI_CHECK_NULL); + JVMCIENV->put_object_at(res, i, component); + } + return JVMCIENV->get_jobjectArray(res); +C2V_END + C2V_VMENTRY_NULL(jobjectArray, getAllMethods, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { @@ -3051,89 +3074,93 @@ C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAI return JNIHandles::make_local(THREAD, reflected); C2V_END -static jbyteArray get_encoded_annotation_data(InstanceKlass* holder, AnnotationArray* annotations_array, bool for_class, - jint filter_length, jlong filter_klass_pointers, - JavaThread* THREAD, JVMCI_TRAPS) { - // Get a ConstantPool object for annotation parsing - Handle jcp = reflect_ConstantPool::create(CHECK_NULL); - reflect_ConstantPool::set_cp(jcp(), holder->constants()); - - // load VMSupport - Symbol* klass = vmSymbols::jdk_internal_vm_VMSupport(); - Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK_NULL); - - InstanceKlass* vm_support = InstanceKlass::cast(k); - if (vm_support->should_be_initialized()) { - vm_support->initialize(CHECK_NULL); - } - - typeArrayOop annotations_oop = Annotations::make_java_array(annotations_array, CHECK_NULL); - typeArrayHandle annotations = typeArrayHandle(THREAD, annotations_oop); +C2V_VMENTRY_NULL(jbyteArray, getRawAnnotationBytes, (JNIEnv* env, jobject, jchar containerTag, ARGUMENT_PAIR(container), jint fieldOrRecordComponentIndex, jint category)) + AnnotationArray* raw_annotations = nullptr; + bool illegal_category = false; + const char* illegal_category_container_title = nullptr; + switch (containerTag) { + case 't': { + InstanceKlass* holder = InstanceKlass::cast(UNPACK_PAIR(Klass, container)); + if (category == CompilerToVM::DECLARED_ANNOTATIONS) { + raw_annotations = holder->class_annotations(); + } else if (category == CompilerToVM::TYPE_ANNOTATIONS) { + raw_annotations = holder->class_type_annotations(); + } else { + illegal_category = true; + } + break; + } + case 'm': { + methodHandle method(THREAD, UNPACK_PAIR(Method, container)); + if (category == CompilerToVM::DECLARED_ANNOTATIONS) { + raw_annotations = method->annotations(); + } else if (category == CompilerToVM::PARAMETER_ANNOTATIONS) { + raw_annotations = method->parameter_annotations(); + } else if (category == CompilerToVM::TYPE_ANNOTATIONS) { + raw_annotations = method->type_annotations(); + } else if (category == CompilerToVM::ANNOTATION_MEMBER_VALUE) { + raw_annotations = method->annotation_default(); + } else { + illegal_category = true; + } + break; + } + case 'f': { + InstanceKlass* holder = check_field(InstanceKlass::cast(UNPACK_PAIR(Klass, container)), fieldOrRecordComponentIndex, JVMCI_CHECK_NULL); + fieldDescriptor fd(holder, fieldOrRecordComponentIndex); + if (category == CompilerToVM::DECLARED_ANNOTATIONS) { + raw_annotations = fd.annotations(); + } else if (category == CompilerToVM::TYPE_ANNOTATIONS) { + raw_annotations = fd.type_annotations(); + } else { + illegal_category = true; + } + break; + } + case 'r': { + InstanceKlass* holder = InstanceKlass::cast(UNPACK_PAIR(Klass, container)); + Array* components = holder->record_components(); + if (components == nullptr) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%s has no record components", holder->name()->as_C_string())); + } + if (fieldOrRecordComponentIndex < 0 || fieldOrRecordComponentIndex >= components->length()) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%d is out of bounds for record components of %s", + fieldOrRecordComponentIndex, + holder->name()->as_C_string())); + } + RecordComponent* rc = components->at(fieldOrRecordComponentIndex); + if (category == CompilerToVM::DECLARED_ANNOTATIONS) { + raw_annotations = rc->annotations(); + } else if (category == CompilerToVM::TYPE_ANNOTATIONS) { + raw_annotations = rc->type_annotations(); + } else { + illegal_category = true; + } + break; + } + default: { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("illegal tag %c", containerTag)); - InstanceKlass** filter = filter_length == 1 ? - (InstanceKlass**) &filter_klass_pointers: - (InstanceKlass**) filter_klass_pointers; - objArrayOop filter_oop = oopFactory::new_objArray(vmClasses::Class_klass(), filter_length, CHECK_NULL); - objArrayHandle filter_classes(THREAD, filter_oop); - for (int i = 0; i < filter_length; i++) { - filter_classes->obj_at_put(i, filter[i]->java_mirror()); + } } - - // invoke VMSupport.encodeAnnotations - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(annotations); - args.push_oop(Handle(THREAD, holder->java_mirror())); - args.push_oop(jcp); - args.push_int(for_class); - args.push_oop(filter_classes); - Symbol* signature = vmSymbols::encodeAnnotations_signature(); - JavaCalls::call_static(&result, - vm_support, - vmSymbols::encodeAnnotations_name(), - signature, - &args, - CHECK_NULL); - - oop res = result.get_oop(); - if (JVMCIENV->is_hotspot()) { - return (jbyteArray) JNIHandles::make_local(THREAD, res); + if (illegal_category) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Illegal category for a %s: %d", + containerTag == 't' ? "type" : + containerTag == 'm' ? "method" : + containerTag == 'f' ? "field" : "record component", + category)); } - - typeArrayOop ba = typeArrayOop(res); - int ba_len = ba->length(); - jbyte* ba_buf = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, jbyte, ba_len); - if (ba_buf == nullptr) { - JVMCI_THROW_MSG_NULL(InternalError, - err_msg("could not allocate %d bytes", ba_len)); - + if (raw_annotations == nullptr) { + return nullptr; } - memcpy(ba_buf, ba->byte_at_addr(0), ba_len); - JVMCIPrimitiveArray ba_dest = JVMCIENV->new_byteArray(ba_len, JVMCI_CHECK_NULL); - JVMCIENV->copy_bytes_from(ba_buf, ba_dest, 0, ba_len); - return JVMCIENV->get_jbyteArray(ba_dest); -} - -C2V_VMENTRY_NULL(jbyteArray, getEncodedClassAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), - jobject filter, jint filter_length, jlong filter_klass_pointers)) - CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support - InstanceKlass* holder = InstanceKlass::cast(UNPACK_PAIR(Klass, klass)); - return get_encoded_annotation_data(holder, holder->class_annotations(), true, filter_length, filter_klass_pointers, THREAD, JVMCIENV); -C2V_END - -C2V_VMENTRY_NULL(jbyteArray, getEncodedExecutableAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), - jobject filter, jint filter_length, jlong filter_klass_pointers)) - CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support - methodHandle method(THREAD, UNPACK_PAIR(Method, method)); - return get_encoded_annotation_data(method->method_holder(), method->annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV); -C2V_END - -C2V_VMENTRY_NULL(jbyteArray, getEncodedFieldAnnotationData, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass), jint index, - jobject filter, jint filter_length, jlong filter_klass_pointers)) - CompilerThreadCanCallJava canCallJava(thread, true); // Requires Java support - InstanceKlass* holder = check_field(InstanceKlass::cast(UNPACK_PAIR(Klass, klass)), index, JVMCI_CHECK_NULL); - fieldDescriptor fd(holder, index); - return get_encoded_annotation_data(holder, fd.annotations(), false, filter_length, filter_klass_pointers, THREAD, JVMCIENV); + int length = raw_annotations->length(); + JVMCIPrimitiveArray result = JVMCIENV->new_byteArray(length, JVMCI_CHECK_NULL); + JVMCIENV->copy_bytes_from((jbyte*) raw_annotations->data(), result, 0, length); + return JVMCIENV->get_jbyteArray(result); C2V_END C2V_VMENTRY_NULL(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current)) @@ -3337,13 +3364,13 @@ C2V_END #define OBJECT "Ljava/lang/Object;" #define CLASS "Ljava/lang/Class;" #define OBJECTCONSTANT "Ljdk/vm/ci/hotspot/HotSpotObjectConstantImpl;" -#define EXECUTABLE "Ljava/lang/reflect/Executable;" #define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;" #define INSTALLED_CODE "Ljdk/vm/ci/code/InstalledCode;" #define BYTECODE_FRAME "Ljdk/vm/ci/code/BytecodeFrame;" #define JAVACONSTANT "Ljdk/vm/ci/meta/JavaConstant;" #define INSPECTED_FRAME_VISITOR "Ljdk/vm/ci/code/stack/InspectedFrameVisitor;" #define RESOLVED_METHOD "Ljdk/vm/ci/meta/ResolvedJavaMethod;" +#define RESOLVED_RECORD_COMPONENT "Ljdk/vm/ci/meta/ResolvedJavaRecordComponent;" #define FIELDINFO "Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl$FieldInfo;" #define HS_RESOLVED_TYPE "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaType;" #define HS_INSTALLED_CODE "Ljdk/vm/ci/hotspot/HotSpotInstalledCode;" @@ -3352,8 +3379,8 @@ C2V_END #define HS_CONFIG "Ljdk/vm/ci/hotspot/HotSpotVMConfig;" #define HS_STACK_FRAME_REF "Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;" #define HS_SPECULATION_LOG "Ljdk/vm/ci/hotspot/HotSpotSpeculationLog;" -#define REFLECTION_EXECUTABLE "Ljava/lang/reflect/Executable;" -#define REFLECTION_FIELD "Ljava/lang/reflect/Field;" +#define EXECUTABLE "Ljava/lang/reflect/Executable;" +#define FIELD "Ljava/lang/reflect/Field;" // Types wrapping VM pointers. The ...2 macro is for a pair: (wrapper, pointer) #define HS_METHOD "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;" @@ -3370,8 +3397,8 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "arrayBaseOffset", CC "(C)I", FN_PTR(arrayBaseOffset)}, {CC "arrayIndexScale", CC "(C)I", FN_PTR(arrayIndexScale)}, {CC "asJavaType", CC "(" OBJECTCONSTANT ")" HS_RESOLVED_TYPE, FN_PTR(asJavaType)}, - {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" REFLECTION_EXECUTABLE, FN_PTR(asReflectionExecutable)}, - {CC "asReflectionField", CC "(" HS_KLASS2 "I)" REFLECTION_FIELD, FN_PTR(asReflectionField)}, + {CC "asReflectionExecutable", CC "(" HS_METHOD2 ")" EXECUTABLE, FN_PTR(asReflectionExecutable)}, + {CC "asReflectionField", CC "(" HS_KLASS2 "I)" FIELD, FN_PTR(asReflectionField)}, {CC "asResolvedJavaMethod", CC "(" EXECUTABLE ")" HS_METHOD, FN_PTR(asResolvedJavaMethod)}, {CC "asString", CC "(" OBJECTCONSTANT ")" STRING, FN_PTR(asString)}, {CC "attachCurrentThread", CC "([BZ[J)Z", FN_PTR(attachCurrentThread)}, @@ -3407,9 +3434,6 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "getDeclaredFieldsInfo", CC "(" HS_KLASS2 ")[" FIELDINFO, FN_PTR(getDeclaredFieldsInfo)}, {CC "getDeclaredMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)}, {CC "getDeclaredTypes", CC "(" HS_KLASS2 ")[" HS_KLASS, FN_PTR(getDeclaredTypes)}, - {CC "getEncodedClassAnnotationData", CC "(" HS_KLASS2 OBJECT "IJ)[B", FN_PTR(getEncodedClassAnnotationData)}, - {CC "getEncodedExecutableAnnotationData", CC "(" HS_METHOD2 OBJECT "IJ)[B", FN_PTR(getEncodedExecutableAnnotationData)}, - {CC "getEncodedFieldAnnotationData", CC "(" HS_KLASS2 "I" OBJECT "IJ)[B", FN_PTR(getEncodedFieldAnnotationData)}, {CC "getExceptionTableLength", CC "(" HS_METHOD2 ")I", FN_PTR(getExceptionTableLength)}, {CC "getExceptionTableStart", CC "(" HS_METHOD2 ")J", FN_PTR(getExceptionTableStart)}, {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, @@ -3427,6 +3451,8 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "getMaxCallTargetOffset", CC "(J)J", FN_PTR(getMaxCallTargetOffset)}, {CC "getNumIndyEntries", CC "(" HS_CONSTANT_POOL2 ")I", FN_PTR(getNumIndyEntries)}, {CC "getOopMapAt", CC "(" HS_METHOD2 "I[J)V", FN_PTR(getOopMapAt)}, + {CC "getRawAnnotationBytes", CC "(C" OBJECT "JII)[B", FN_PTR(getRawAnnotationBytes)}, + {CC "getRecordComponents", CC "(" HS_KLASS2 ")[" RESOLVED_RECORD_COMPONENT, FN_PTR(getRecordComponents)}, {CC "getResolvedJavaMethod", CC "(" OBJECTCONSTANT "J)" HS_METHOD, FN_PTR(getResolvedJavaMethod)}, {CC "getResolvedJavaType0", CC "(Ljava/lang/Object;JZ)" HS_KLASS, FN_PTR(getResolvedJavaType0)}, {CC "getSignatureName", CC "(J)" STRING, FN_PTR(getSignatureName)}, diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index 41531b083fc..1fd1f221d83 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -35,6 +35,12 @@ class JVMCIObjectArray; class CompilerToVM { public: + // Keep in sync with constants in CompilerToVM.java + static const int DECLARED_ANNOTATIONS = 0; + static const int PARAMETER_ANNOTATIONS = 1; + static const int TYPE_ANNOTATIONS = 2; + static const int ANNOTATION_MEMBER_VALUE = 3; + class Data { friend class JVMCIVMStructs; @@ -94,7 +100,7 @@ class CompilerToVM { static HeapWord** _heap_end_addr; static HeapWord* volatile* _heap_top_addr; static int _max_oop_map_stack_offset; - static int _fields_annotations_base_offset; + static int _annotation_array_array_base_offset; static CardTable::CardValue* cardtable_start_address; static int cardtable_shift; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 1beb1917b9a..43b37c1fc57 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -118,7 +118,7 @@ bool CompilerToVM::Data::_supports_inline_contig_alloc; HeapWord** CompilerToVM::Data::_heap_end_addr; HeapWord* volatile* CompilerToVM::Data::_heap_top_addr; int CompilerToVM::Data::_max_oop_map_stack_offset; -int CompilerToVM::Data::_fields_annotations_base_offset; +int CompilerToVM::Data::_annotation_array_array_base_offset; CardTable::CardValue* CompilerToVM::Data::cardtable_start_address; int CompilerToVM::Data::cardtable_shift; @@ -226,7 +226,7 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) { symbol_init = (address) vmSymbols::object_initializer_name(); symbol_clinit = (address) vmSymbols::class_initializer_name(); - _fields_annotations_base_offset = Array::base_offset_in_bytes(); + _annotation_array_array_base_offset = Array::base_offset_in_bytes(); data_section_item_alignment = relocInfo::addr_unit(); diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 6c8695686ee..d9e1ce3d731 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -38,6 +38,7 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/objArrayKlass.hpp" +#include "oops/recordComponent.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" @@ -1609,6 +1610,30 @@ JVMCIObject JVMCIEnv::new_FieldInfo(FieldInfo* fieldinfo, JVMCI_TRAPS) { } } +JVMCIObject JVMCIEnv::new_HotSpotResolvedJavaRecordComponent(JVMCIObject declaringRecord, int index, RecordComponent* rc, JVMCI_TRAPS) { + JavaThread* THREAD = JavaThread::current(); + if (is_hotspot()) { + JavaCallArguments args; + args.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(declaringRecord))); + args.push_int(index); + args.push_int(rc->name_index()); + args.push_int(rc->descriptor_index()); + Handle obj_h = JavaCalls::construct_new_instance(HotSpotJVMCI::HotSpotResolvedJavaRecordComponent::klass(), + vmSymbols::HotSpotResolvedJavaRecordComponent_constructor_signature(), + &args, + THREAD); + return wrap(obj_h()); + } else { + JNIAccessMark jni(this, THREAD); + jobject result = jni()->NewObject(JNIJVMCI::HotSpotResolvedJavaRecordComponent::clazz(), + JNIJVMCI::HotSpotResolvedJavaRecordComponent::constructor(), + (jint)rc->name_index(), + (jint)rc->descriptor_index()); + + return wrap(result); + } +} + JVMCIObject JVMCIEnv::get_object_constant(oop objOop, bool compressed, bool dont_register) { JavaThread* THREAD = JavaThread::current(); // For exception macros. Handle obj = Handle(THREAD, objOop); diff --git a/src/hotspot/share/jvmci/jvmciEnv.hpp b/src/hotspot/share/jvmci/jvmciEnv.hpp index 7947a59824d..61eb989c492 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.hpp +++ b/src/hotspot/share/jvmci/jvmciEnv.hpp @@ -433,6 +433,7 @@ class JVMCIEnv : public ResourceObj { JVMCIObject new_HotSpotStackFrameReference(JVMCI_TRAPS); JVMCIObject new_JVMCIError(JVMCI_TRAPS); JVMCIObject new_FieldInfo(FieldInfo* fieldinfo, JVMCI_TRAPS); + JVMCIObject new_HotSpotResolvedJavaRecordComponent(JVMCIObject declaringRecord, int index, RecordComponent* rc, JVMCI_TRAPS); // Makes a handle to a HotSpot heap object. These handles are // individually reclaimed by JVMCIRuntime::destroy_oop_handle and diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp index 24069330bf9..90624e61e63 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp @@ -84,6 +84,9 @@ start_class(HotSpotResolvedJavaMethodImpl, jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl) \ long_field(HotSpotResolvedJavaMethodImpl, methodHandle) \ end_class \ + start_class(HotSpotResolvedJavaRecordComponent, jdk_vm_ci_hotspot_HotSpotResolvedJavaRecordComponent) \ + jvmci_constructor(HotSpotResolvedJavaRecordComponent, "(Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;III)V") \ + end_class \ start_class(HotSpotMethodData, jdk_vm_ci_hotspot_HotSpotMethodData) \ long_field(HotSpotMethodData, methodDataPointer) \ end_class \ @@ -165,6 +168,8 @@ end_class \ start_class(ResolvedJavaMethod, jdk_vm_ci_meta_ResolvedJavaMethod) \ end_class \ + start_class(ResolvedJavaRecordComponent, jdk_vm_ci_meta_ResolvedJavaRecordComponent) \ + end_class \ start_class(PrimitiveConstant, jdk_vm_ci_meta_PrimitiveConstant) \ object_field(PrimitiveConstant, kind, "Ljdk/vm/ci/meta/JavaKind;") \ long_field(PrimitiveConstant, primitive) \ @@ -211,12 +216,18 @@ jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, exceptionToString, exceptionToString_signature) \ jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, postTranslation, object_void_signature) \ end_class \ + start_class(CompilerToVM, jdk_vm_ci_hotspot_CompilerToVM) \ + static_int_field(CompilerToVM, DECLARED_ANNOTATIONS) \ + static_int_field(CompilerToVM, PARAMETER_ANNOTATIONS) \ + static_int_field(CompilerToVM, TYPE_ANNOTATIONS) \ + static_int_field(CompilerToVM, ANNOTATION_MEMBER_VALUE) \ + end_class \ start_class(JVMCIError, jdk_vm_ci_common_JVMCIError) \ jvmci_constructor(JVMCIError, "(Ljava/lang/String;)V") \ end_class \ start_class(InspectedFrameVisitor, jdk_vm_ci_code_stack_InspectedFrameVisitor) \ end_class \ - start_class(Services, jdk_vm_ci_services_Services) \ + start_class(Services, jdk_vm_ci_services_Services) \ end_class \ start_class(JVMCI, jdk_vm_ci_runtime_JVMCI) \ jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JVMCI, getRuntime, getRuntime_signature) \ diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 749ddaaf492..b381b5bff25 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -1419,6 +1419,12 @@ class JavaVMRefsInitialization: public StackObj { } }; +#ifdef ASSERT +static void assert_equals(const char* desc, int expect, int actual) { + assert(expect == actual, "%s: %d != %d", desc, expect, actual); +} +#endif + void JVMCIRuntime::initialize(JVMCI_TRAPS) { // Check first without _lock if (_init_state == fully_initialized) { @@ -1489,6 +1495,11 @@ void JVMCIRuntime::initialize(JVMCI_TRAPS) { create_jvmci_primitive_type(T_VOID, JVMCI_CHECK_EXIT_((void)0)); DEBUG_ONLY(CodeInstaller::verify_bci_constants(JVMCIENV);) + + DEBUG_ONLY(assert_equals("DECLARED_ANNOTATIONS", CompilerToVM::DECLARED_ANNOTATIONS, JVMCIENV->get_CompilerToVM_DECLARED_ANNOTATIONS())); + DEBUG_ONLY(assert_equals("PARAMETER_ANNOTATIONS", CompilerToVM::PARAMETER_ANNOTATIONS, JVMCIENV->get_CompilerToVM_PARAMETER_ANNOTATIONS())); + DEBUG_ONLY(assert_equals("TYPE_ANNOTATIONS", CompilerToVM::TYPE_ANNOTATIONS, JVMCIENV->get_CompilerToVM_TYPE_ANNOTATIONS())); + DEBUG_ONLY(assert_equals("ANNOTATION_MEMBER_VALUE", CompilerToVM::ANNOTATION_MEMBER_VALUE, JVMCIENV->get_CompilerToVM_ANNOTATION_MEMBER_VALUE())); } _init_state = fully_initialized; diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 59c5da9d81c..0a66c08c347 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -117,7 +117,7 @@ static_field(CompilerToVM::Data, _heap_top_addr, HeapWord* volatile*) \ \ static_field(CompilerToVM::Data, _max_oop_map_stack_offset, int) \ - static_field(CompilerToVM::Data, _fields_annotations_base_offset, int) \ + static_field(CompilerToVM::Data, _annotation_array_array_base_offset, int) \ \ static_field(CompilerToVM::Data, cardtable_start_address, CardTable::CardValue*) \ static_field(CompilerToVM::Data, cardtable_shift, int) \ @@ -158,7 +158,9 @@ static_field(Abstract_VM_Version, _features, uint64_t) \ \ nonstatic_field(Annotations, _class_annotations, AnnotationArray*) \ + nonstatic_field(Annotations, _class_type_annotations, AnnotationArray*) \ nonstatic_field(Annotations, _fields_annotations, Array*) \ + nonstatic_field(Annotations, _fields_type_annotations, Array*) \ \ nonstatic_field(Array, _length, int) \ unchecked_nonstatic_field(Array, _data, sizeof(u1)) \ @@ -224,6 +226,7 @@ nonstatic_field(InstanceKlass, _misc_flags._flags, u2) \ nonstatic_field(InstanceKlass, _annotations, Annotations*) \ nonstatic_field(InstanceKlass, _permitted_subclasses, Array*) \ + nonstatic_field(InstanceKlass, _record_components, Array*) \ \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_sp, intptr_t*) \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_pc, address) \ @@ -689,7 +692,9 @@ declare_constant(ConstMethodFlags::_misc_has_localvariable_table) \ declare_constant(ConstMethodFlags::_misc_has_exception_table) \ declare_constant(ConstMethodFlags::_misc_has_method_annotations) \ + declare_constant(ConstMethodFlags::_misc_has_type_annotations) \ declare_constant(ConstMethodFlags::_misc_has_parameter_annotations) \ + declare_constant(ConstMethodFlags::_misc_has_default_annotations) \ declare_constant(ConstMethodFlags::_misc_caller_sensitive) \ declare_constant(ConstMethodFlags::_misc_is_hidden) \ declare_constant(ConstMethodFlags::_misc_intrinsic_candidate) \ diff --git a/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp b/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp index de965da0f80..3c2c22f40b0 100644 --- a/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp +++ b/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp @@ -37,6 +37,7 @@ template(jdk_vm_ci_hotspot_HotSpotInstalledCode, "jdk/vm/ci/hotspot/HotSpotInstalledCode") \ template(jdk_vm_ci_hotspot_HotSpotNmethod, "jdk/vm/ci/hotspot/HotSpotNmethod") \ template(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl, "jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl") \ + template(jdk_vm_ci_hotspot_HotSpotResolvedJavaRecordComponent, "jdk/vm/ci/hotspot/HotSpotResolvedJavaRecordComponent") \ template(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl, "jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl") \ template(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl_FieldInfo, "jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl$FieldInfo") \ template(jdk_vm_ci_hotspot_HotSpotResolvedPrimitiveType, "jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType") \ @@ -55,6 +56,7 @@ template(jdk_vm_ci_hotspot_VMFlag, "jdk/vm/ci/hotspot/VMFlag") \ template(jdk_vm_ci_hotspot_VMIntrinsicMethod, "jdk/vm/ci/hotspot/VMIntrinsicMethod") \ template(jdk_vm_ci_meta_ResolvedJavaMethod, "jdk/vm/ci/meta/ResolvedJavaMethod") \ + template(jdk_vm_ci_meta_ResolvedJavaRecordComponent, "jdk/vm/ci/meta/ResolvedJavaRecordComponent") \ template(jdk_vm_ci_meta_JavaConstant, "jdk/vm/ci/meta/JavaConstant") \ template(jdk_vm_ci_meta_PrimitiveConstant, "jdk/vm/ci/meta/PrimitiveConstant") \ template(jdk_vm_ci_meta_RawConstant, "jdk/vm/ci/meta/RawConstant") \ @@ -97,6 +99,7 @@ template(getCompiler_signature, "()Ljdk/vm/ci/runtime/JVMCICompiler;") \ template(exceptionToString_name, "exceptionToString") \ template(exceptionToString_signature, "(Ljava/lang/Throwable;ZZ)[Ljava/lang/String;") \ + template(HotSpotResolvedJavaRecordComponent_constructor_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;III)V") \ template(postTranslation_name, "postTranslation") \ template(getName_name, "getName") \ template(bootstrapFinished_name, "bootstrapFinished") \ diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index 197da0d456c..afb34d9ade8 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -25,28 +25,12 @@ package jdk.internal.vm; import jdk.internal.misc.Unsafe; -import jdk.internal.misc.VM; -import jdk.internal.access.SharedSecrets; -import jdk.internal.access.JavaLangAccess; -import jdk.internal.reflect.ConstantPool; -import sun.reflect.annotation.AnnotationParser; -import sun.reflect.annotation.AnnotationSupport; -import sun.reflect.annotation.AnnotationType; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.IOException; -import java.lang.annotation.Annotation; -import java.lang.annotation.IncompleteAnnotationException; import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.Map; import java.util.Properties; import java.util.Set; -import java.util.List; /* * Support class used by JVMCI, JVMTI and VM attach mechanism. @@ -183,404 +167,4 @@ public static int encodeThrowable(Throwable throwable, long buffer, int bufferSi U.copyMemory(encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, buffer + 4, encoding.length); return requiredSize; } - - /** - * Parses {@code rawAnnotations} into a list of {@link Annotation}s and then - * serializes them to a byte array with {@link #encodeAnnotations(Collection)}. - */ - public static byte[] encodeAnnotations(byte[] rawAnnotations, - Class declaringClass, - ConstantPool cp, - boolean forClass, - Class[] selectAnnotationClasses) - { - for (Class c : selectAnnotationClasses) { - if (!c.isAnnotation()) { - throw new IllegalArgumentException(c + " is not an annotation interface"); - } - } - Map, Annotation> annotations = - AnnotationParser.parseSelectAnnotations(rawAnnotations, cp, declaringClass, selectAnnotationClasses); - if (forClass && annotations.size() != selectAnnotationClasses.length) { - Class superClass = declaringClass.getSuperclass(); - nextSuperClass: - while (superClass != null) { - JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); - Map, Annotation> superAnnotations = - AnnotationParser.parseSelectAnnotations( - jla.getRawClassAnnotations(superClass), - jla.getConstantPool(superClass), - superClass, - selectAnnotationClasses); - - for (Map.Entry, Annotation> e : superAnnotations.entrySet()) { - Class annotationClass = e.getKey(); - if (!annotations.containsKey(annotationClass) && AnnotationType.getInstance(annotationClass).isInherited()) { - if (annotations.isEmpty()) { - // An empty map might be unmodifiable (e.g. Collections.emptyMap()). - annotations = new LinkedHashMap, Annotation>(); - } - annotations.put(annotationClass, e.getValue()); - if (annotations.size() == selectAnnotationClasses.length) { - break nextSuperClass; - } - } - } - superClass = superClass.getSuperclass(); - } - } - return encodeAnnotations(annotations.values()); - } - - /** - * Encodes annotations to a byte array. The byte array can be decoded with {@link #decodeAnnotations(byte[], AnnotationDecoder)}. - */ - public static byte[] encodeAnnotations(Collection annotations) { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(128); - try (DataOutputStream dos = new DataOutputStream(baos)) { - writeLength(dos, annotations.size()); - for (Annotation a : annotations) { - encodeAnnotation(dos, a); - } - } - return baos.toByteArray(); - } catch (Exception e) { - throw new InternalError(e); - } - } - - private static void encodeAnnotation(DataOutputStream dos, Annotation a) throws Exception { - Class type = a.annotationType(); - Map values = AnnotationSupport.memberValues(a); - dos.writeUTF(type.getName()); - writeLength(dos, values.size()); - for (Map.Entry e : values.entrySet()) { - Object value = e.getValue(); - if (value == null) { - // IncompleteAnnotationException - dos.writeByte('x'); - dos.writeUTF(new IncompleteAnnotationException(type, e.getKey()).toString()); - continue; - } - Class valueType = value.getClass(); - dos.writeUTF(e.getKey()); - if (valueType == Byte.class) { - dos.writeByte('B'); - dos.writeByte((byte) value); - } else if (valueType == Character.class) { - dos.writeByte('C'); - dos.writeChar((char) value); - } else if (valueType == Double.class) { - dos.writeByte('D'); - dos.writeDouble((double) value); - } else if (valueType == Float.class) { - dos.writeByte('F'); - dos.writeFloat((float) value); - } else if (valueType == Integer.class) { - dos.writeByte('I'); - dos.writeInt((int) value); - } else if (valueType == Long.class) { - dos.writeByte('J'); - dos.writeLong((long) value); - } else if (valueType == Short.class) { - dos.writeByte('S'); - dos.writeShort((short) value); - } else if (valueType == Boolean.class) { - dos.writeByte('Z'); - dos.writeBoolean((boolean) value); - } else if (valueType == String.class) { - dos.writeByte('s'); - dos.writeUTF((String) value); - } else if (valueType == Class.class) { - dos.writeByte('c'); - dos.writeUTF(((Class) value).getName()); - } else if (valueType.isEnum()) { - dos.writeByte('e'); - dos.writeUTF(valueType.getName()); - dos.writeUTF(((Enum) value).name()); - } else if (value instanceof Annotation) { - dos.writeByte('@'); - encodeAnnotation(dos, (Annotation) value); - } else if (valueType.isArray()) { - Class componentType = valueType.getComponentType(); - if (componentType == byte.class) { - byte[] array = (byte[]) value; - dos.writeByte('['); - dos.writeByte('B'); - writeLength(dos, array.length); - dos.write(array); - } else if (componentType == char.class) { - char[] array = (char[]) value; - dos.writeByte('['); - dos.writeByte('C'); - writeLength(dos, array.length); - for (char c : array) { - dos.writeChar(c); - } - } else if (componentType == double.class) { - double[] array = (double[]) value; - dos.writeByte('['); - dos.writeByte('D'); - writeLength(dos, array.length); - for (double v : array) { - dos.writeDouble(v); - } - } else if (componentType == float.class) { - float[] array = (float[]) value; - dos.writeByte('['); - dos.writeByte('F'); - writeLength(dos, array.length); - for (float v : array) { - dos.writeFloat(v); - } - } else if (componentType == int.class) { - int[] array = (int[]) value; - dos.writeByte('['); - dos.writeByte('I'); - writeLength(dos, array.length); - for (int j : array) { - dos.writeInt(j); - } - } else if (componentType == long.class) { - long[] array = (long[]) value; - dos.writeByte('['); - dos.writeByte('J'); - writeLength(dos, array.length); - for (long l : array) { - dos.writeLong(l); - } - } else if (componentType == short.class) { - short[] array = (short[]) value; - dos.writeByte('['); - dos.writeByte('S'); - writeLength(dos, array.length); - for (short item : array) { - dos.writeShort(item); - } - } else if (componentType == boolean.class) { - boolean[] array = (boolean[]) value; - dos.writeByte('['); - dos.writeByte('Z'); - writeLength(dos, array.length); - for (boolean b : array) { - dos.writeBoolean(b); - } - } else if (componentType == String.class) { - String[] array = (String[]) value; - dos.writeByte('['); - dos.writeByte('s'); - writeLength(dos, array.length); - for (String s : array) { - dos.writeUTF(s); - } - } else if (componentType == Class.class) { - Class[] array = (Class[]) value; - dos.writeByte('['); - dos.writeByte('c'); - writeLength(dos, array.length); - for (Class aClass : array) { - dos.writeUTF(aClass.getName()); - } - } else if (componentType.isEnum()) { - Enum[] array = (Enum[]) value; - dos.writeByte('['); - dos.writeByte('e'); - dos.writeUTF(componentType.getName()); - writeLength(dos, array.length); - for (Enum anEnum : array) { - dos.writeUTF(anEnum.name()); - } - } else if (componentType.isAnnotation()) { - Annotation[] array = (Annotation[]) value; - dos.writeByte('['); - dos.writeByte('@'); - writeLength(dos, array.length); - for (Annotation annotation : array) { - encodeAnnotation(dos, annotation); - } - } else { - dos.writeByte('x'); - dos.writeUTF(value.toString()); - } - - } else { - dos.writeByte('x'); - dos.writeUTF(value.toString()); - } - } - } - - /** - * Helper for {@link #decodeAnnotations(byte[], AnnotationDecoder)} to convert a byte - * array (ostensibly produced by {@link VMSupport#encodeAnnotations}) into objects. - * - * @param type to which a type name is {@linkplain #resolveType(String) resolved} - * @param type of the object representing a decoded annotation - * @param type of the object representing a decoded enum constant - * @param type of the object representing a decoded error - */ - public interface AnnotationDecoder { - /** - * Resolves a name in {@link Class#getName()} format to an object of type {@code T}. - */ - T resolveType(String name); - - /** - * Creates an object representing a decoded annotation. - * - * @param type the annotation interface of the annotation - * @param elements elements of the annotation - */ - A newAnnotation(T type, Map.Entry[] elements); - - /** - * Creates an object representing a decoded enum constant. - * - * @param enumType the enum type - * @param name the name of the enum constant - */ - E newEnumValue(T enumType, String name); - - /** - * Creates an object representing a decoded error value. - * - * @param description of the error - */ - X newErrorValue(String description); - } - - /** - * Decodes annotations serialized in {@code encoded} to objects. - * - * @param type to which a type name is resolved - * @param type of the object representing a decoded annotation - * @param type of the object representing a decoded enum constant - * @param type of the object representing a decoded error - * @return an immutable list of {@code A} objects - */ - @SuppressWarnings("unchecked") - public static List decodeAnnotations(byte[] encoded, AnnotationDecoder decoder) { - try { - ByteArrayInputStream bais = new ByteArrayInputStream(encoded); - DataInputStream dis = new DataInputStream(bais); - return (List) readArray(dis, () -> decodeAnnotation(dis, decoder)); - } catch (Exception e) { - throw new InternalError(e); - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private static A decodeAnnotation(DataInputStream dis, AnnotationDecoder decoder) throws IOException { - String typeName = dis.readUTF(); - T type = decoder.resolveType(typeName); - int n = readLength(dis); - Map.Entry[] elements = new Map.Entry[n]; - for (int i = 0; i < n; i++) { - String name = dis.readUTF(); - byte tag = dis.readByte(); - elements[i] = Map.entry(name, switch (tag) { - case 'B' -> dis.readByte(); - case 'C' -> dis.readChar(); - case 'D' -> dis.readDouble(); - case 'F' -> dis.readFloat(); - case 'I' -> dis.readInt(); - case 'J' -> dis.readLong(); - case 'S' -> dis.readShort(); - case 'Z' -> dis.readBoolean(); - case 's' -> dis.readUTF(); - case 'c' -> decoder.resolveType(dis.readUTF()); - case 'e' -> decoder.newEnumValue(decoder.resolveType(dis.readUTF()), dis.readUTF()); - case '@' -> decodeAnnotation(dis, decoder); - case '[' -> decodeArray(dis, decoder); - case 'x' -> decoder.newErrorValue(dis.readUTF()); - default -> throw new InternalError("Unsupported tag: " + tag); - }); - } - return decoder.newAnnotation(type, (Map.Entry[]) elements); - } - @FunctionalInterface - interface IOReader { - Object read() throws IOException; - } - - private static Object decodeArray(DataInputStream dis, AnnotationDecoder decoder) throws IOException { - byte componentTag = dis.readByte(); - return switch (componentTag) { - case 'B' -> readArray(dis, dis::readByte); - case 'C' -> readArray(dis, dis::readChar); - case 'D' -> readArray(dis, dis::readDouble); - case 'F' -> readArray(dis, dis::readFloat); - case 'I' -> readArray(dis, dis::readInt); - case 'J' -> readArray(dis, dis::readLong); - case 'S' -> readArray(dis, dis::readShort); - case 'Z' -> readArray(dis, dis::readBoolean); - case 's' -> readArray(dis, dis::readUTF); - case 'c' -> readArray(dis, () -> readClass(dis, decoder)); - case 'e' -> { - T enumType = decoder.resolveType(dis.readUTF()); - yield readArray(dis, () -> readEnum(dis, decoder, enumType)); - } - case '@' -> readArray(dis, () -> decodeAnnotation(dis, decoder)); - default -> throw new InternalError("Unsupported component tag: " + componentTag); - }; - } - - /** - * Reads an enum encoded at the current read position of {@code dis} and - * returns it as an object of type {@code E}. - */ - private static E readEnum(DataInputStream dis, AnnotationDecoder decoder, T enumType) throws IOException { - return decoder.newEnumValue(enumType, dis.readUTF()); - } - - /** - * Reads a class encoded at the current read position of {@code dis} and - * returns it as an object of type {@code T}. - */ - private static T readClass(DataInputStream dis, AnnotationDecoder decoder) throws IOException { - return decoder.resolveType(dis.readUTF()); - } - - /** - * Reads an array encoded at the current read position of {@code dis} and - * returns it in an immutable list. - * - * @param reader reads array elements from {@code dis} - * @return an immutable list of {@code A} objects - */ - private static List readArray(DataInputStream dis, IOReader reader) throws IOException { - Object[] array = new Object[readLength(dis)]; - for (int i = 0; i < array.length; i++) { - array[i] = reader.read(); - } - return List.of(array); - } - - /** - * Encodes {@code length} in 1 byte if it is less than 128. - */ - private static void writeLength(DataOutputStream dos, int length) throws IOException { - if (length < 0) { - throw new NegativeArraySizeException(); - } else if (length <= 127) { - dos.writeByte((byte) (0x80 | length)); - } else { - dos.writeInt(length); - } - } - - private static int readLength(DataInputStream dis) throws IOException { - int ch1 = dis.readByte(); - int length; - if (ch1 < 0) { - length = ch1 & 0x7F; - } else { - int ch2 = dis.read(); - int ch3 = dis.read(); - int ch4 = dis.read(); - length = (ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0); - } - return length; - } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationDataDecoder.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationDataDecoder.java deleted file mode 100644 index 9cc33a395fc..00000000000 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/AnnotationDataDecoder.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.hotspot; - -import java.util.Map; - -import jdk.internal.vm.VMSupport.AnnotationDecoder; -import jdk.vm.ci.meta.AnnotationData; -import jdk.vm.ci.meta.EnumData; -import jdk.vm.ci.meta.ErrorData; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.MetaUtil; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.UnresolvedJavaType; - -/** - * Implementation of {@link AnnotationDecoder} that resolves type names to {@link JavaType} values - * and employs {@link AnnotationData} and {@link EnumData} to represent decoded annotations and enum - * constants respectively. - */ -final class AnnotationDataDecoder implements AnnotationDecoder { - - static final AnnotationDataDecoder INSTANCE = new AnnotationDataDecoder(); - - @Override - public JavaType resolveType(String name) { - String internalName = MetaUtil.toInternalName(name); - return UnresolvedJavaType.create(internalName); - } - - @Override - public AnnotationData newAnnotation(JavaType type, Map.Entry[] elements) { - return new AnnotationData(type, elements); - } - - @Override - public EnumData newEnumValue(JavaType enumType, String name) { - return new EnumData(enumType, name); - } - - @Override - public ErrorData newErrorValue(String description) { - return new ErrorData(description); - } - - static ResolvedJavaType[] asArray(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { - ResolvedJavaType[] filter = new ResolvedJavaType[2 + types.length]; - filter[0] = type1; - filter[1] = type2; - System.arraycopy(types, 0, filter, 2, types.length); - return filter; - } -} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index e78f39e0be8..27feed67617 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -23,27 +23,29 @@ package jdk.vm.ci.hotspot; -import java.lang.reflect.Executable; -import java.lang.reflect.Field; - -import jdk.internal.misc.Unsafe; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.code.InvalidInstalledCodeException; import jdk.vm.ci.code.stack.InspectedFrameVisitor; import jdk.vm.ci.common.InitTimer; -import static jdk.vm.ci.common.InitTimer.timer; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; -import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantPool.BootstrapMethodInvocation; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import jdk.vm.ci.meta.ResolvedJavaType; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; + +import static jdk.vm.ci.common.InitTimer.timer; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; + /** * Calls from Java into HotSpot. The behavior of all the methods in this class that take a native * pointer as an argument (e.g., {@link #getSymbol(long)}) is undefined if the argument does not @@ -86,7 +88,7 @@ final class CompilerToVM { @SuppressWarnings("try") CompilerToVM() { - try (InitTimer t = timer("CompilerToVM.registerNatives")) { + try (InitTimer _ = timer("CompilerToVM.registerNatives")) { registerNatives(); ARRAY_BOOLEAN_BASE_OFFSET = arrayBaseOffset(JavaKind.Boolean.getTypeChar()); ARRAY_BYTE_BASE_OFFSET = arrayBaseOffset(JavaKind.Byte.getTypeChar()); @@ -1167,6 +1169,15 @@ ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl klass) { native ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl klass, long klassPointer); + /** + * Gets the {@link ResolvedJavaRecordComponent}s for {@code klass}. + */ + ResolvedJavaRecordComponent[] getRecordComponents(HotSpotResolvedObjectTypeImpl klass) { + return getRecordComponents(klass, klass.getKlassPointer()); + } + + native ResolvedJavaRecordComponent[] getRecordComponents(HotSpotResolvedObjectTypeImpl klass, long klassPointer); + /** * Gets the {@link ResolvedJavaMethod}s for all methods of {@code klass}. */ @@ -1450,90 +1461,34 @@ void notifyCompilerInliningEvent(int compileId, HotSpotResolvedJavaMethodImpl ca native void notifyCompilerInliningEvent(int compileId, HotSpotResolvedJavaMethodImpl caller, long callerPointer, HotSpotResolvedJavaMethodImpl callee, long calleePointer, boolean succeeded, String message, int bci); - /** - * Gets the serialized annotation info for {@code type} by calling - * {@code VMSupport.encodeAnnotations} in the HotSpot heap. - */ - byte[] getEncodedClassAnnotationData(HotSpotResolvedObjectTypeImpl type, ResolvedJavaType[] filter) { - try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedClassAnnotationData(type, type.getKlassPointer(), - a.types, a.types.length, a.buffer()); - } - } + /// Denotes class file bytes of a `RuntimeVisibleAnnotations` attribute after + /// the `u2 attribute_name_index; u4 attribute_length` prefix. + static final int DECLARED_ANNOTATIONS = 0; - native byte[] getEncodedClassAnnotationData(HotSpotResolvedObjectTypeImpl type, long klassPointer, - Object filter, int filterLength, long filterKlassPointers); + /// Denotes class file bytes of a `RuntimeVisibleParameterAnnotations` attribute after + /// the `u2 attribute_name_index; u4 attribute_length` prefix. + static final int PARAMETER_ANNOTATIONS = 1; - /** - * Gets the serialized annotation info for {@code method} by calling - * {@code VMSupport.encodeAnnotations} in the HotSpot heap. - */ - byte[] getEncodedExecutableAnnotationData(HotSpotResolvedJavaMethodImpl method, ResolvedJavaType[] filter) { - try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedExecutableAnnotationData(method, method.getMethodPointer(), - a.types, a.types.length, a.buffer()); - } - } - - native byte[] getEncodedExecutableAnnotationData(HotSpotResolvedJavaMethodImpl method, long methodPointer, - Object filter, int filterLength, long filterKlassPointers); - - /** - * Gets the serialized annotation info for the field denoted by {@code holder} and - * {@code fieldIndex} by calling {@code VMSupport.encodeAnnotations} in the HotSpot heap. - */ - byte[] getEncodedFieldAnnotationData(HotSpotResolvedObjectTypeImpl holder, int fieldIndex, ResolvedJavaType[] filter) { - try (KlassPointers a = new KlassPointers(filter)) { - return getEncodedFieldAnnotationData(holder, holder.getKlassPointer(), fieldIndex, - a.types, a.types.length, a.buffer()); - } - } + /// Denotes class file bytes of a `RuntimeVisibleTypeAnnotations` attribute after + /// the `u2 attribute_name_index; u4 attribute_length` prefix. + static final int TYPE_ANNOTATIONS = 2; - native byte[] getEncodedFieldAnnotationData(HotSpotResolvedObjectTypeImpl holder, long klassPointer, int fieldIndex, - Object filterTypes, int filterLength, long filterKlassPointers); + /// Denotes class file bytes of a `AnnotationDefault` attribute after + /// the `u2 attribute_name_index; u4 attribute_length` prefix. + static final int ANNOTATION_MEMBER_VALUE = 3; - /** - * Helper for passing {@Klass*} values to native code. - */ - static final class KlassPointers implements AutoCloseable { - final ResolvedJavaType[] types; - long pointersArray; - final Unsafe unsafe = UnsafeAccess.UNSAFE; - - KlassPointers(ResolvedJavaType[] types) { - this.types = types; - } - - /** - * Gets the buffer in which to pass the {@Klass*} values to JNI. - * - * @return a {@Klass*} value if {@code types.length == 1} otherwise the address of a native - * buffer holding an array of {@Klass*} values - */ - long buffer() { - int length = types.length; - if (length == 1) { - return ((HotSpotResolvedObjectTypeImpl) types[0]).getKlassPointer(); - } else { - pointersArray = unsafe.allocateMemory(length * Long.BYTES); - long pos = pointersArray; - for (int i = 0; i < types.length; i++) { - HotSpotResolvedObjectTypeImpl hsType = (HotSpotResolvedObjectTypeImpl) types[i]; - unsafe.putLong(pos, hsType.getKlassPointer()); - pos += Long.BYTES; - } - } - return pointersArray; - } - - @Override - public void close() { - if (types.length != 1 && pointersArray != 0) { - unsafe.freeMemory(pointersArray); - pointersArray = 0; - } - } - } + /// Gets the raw bytes of a class file annotations attribute (e.g. `RuntimeVisibleAnnotations`). + /// The relationship the arguments is shown below: + /// + /// | containerTag | container class | containerPointer C++ type | fieldOrRecordComponentIndex | + /// |--------------|------------------------------------|---------------------------|----------------------------------------| + /// | 't' | HotSpotResolvedObjectTypeImpl | Klass* | - | + /// | 'm' | HotSpotResolvedJavaMethodImpl | Method* | - | + /// | 'f' | HotSpotResolvedObjectTypeImpl | Klass* | index of field in container | + /// | 'r' | HotSpotResolvedObjectTypeImpl | Klass* | index of record component in container | + /// + /// @param category [#DECLARED_ANNOTATIONS], [#PARAMETER_ANNOTATIONS], [#TYPE_ANNOTATIONS] or [#ANNOTATION_MEMBER_VALUE] + native byte[] getRawAnnotationBytes(char containerTag, Object container, long containerPointer, int fieldOrRecordComponentIndex, int category); /** * @see HotSpotResolvedJavaMethod#getOopMapAt @@ -1548,7 +1503,7 @@ void getOopMapAt(HotSpotResolvedJavaMethodImpl method, int bci, long[] oopMap) { * If the current thread is a CompilerThread associated with a JVMCI compiler where * newState != CompilerThread::_can_call_java, then _can_call_java is set to newState. * - * @returns false if no change was made, otherwise true + * @return false if no change was made, otherwise true */ native boolean updateCompilerThreadCanCallJava(boolean newState); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java index 20e3915527d..c1b0c37d928 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java @@ -852,8 +852,7 @@ public JavaField lookupField(int rawIndex, ResolvedJavaMethod method, int opcode final int offset = info[1]; final int fieldIndex = info[2]; final int fieldFlags = info[3]; - HotSpotResolvedJavaField result = resolvedHolder.createField(type, offset, flags, fieldFlags, fieldIndex); - return result; + return resolvedHolder.createField(type, offset, flags, fieldFlags, fieldIndex); } else { return new UnresolvedJavaField(fieldHolder, lookupUtf8(getNameRefIndexAt(nameAndTypeIndex)), type); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index c35f216e624..a4d1190d161 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -95,6 +95,7 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime { private HotSpotResolvedObjectTypeImpl serializableType; private HotSpotResolvedObjectTypeImpl cloneableType; private HotSpotResolvedObjectTypeImpl enumType; + private HotSpotResolvedObjectTypeImpl recordType; HotSpotResolvedObjectTypeImpl getJavaLangObject() { if (javaLangObject == null) { @@ -103,6 +104,13 @@ HotSpotResolvedObjectTypeImpl getJavaLangObject() { return javaLangObject; } + HotSpotResolvedObjectTypeImpl getJavaLangRecord() { + if (recordType == null) { + recordType = (HotSpotResolvedObjectTypeImpl) fromClass(Record.class); + } + return recordType; + } + HotSpotResolvedObjectTypeImpl getJavaLangString() { if (javaLangString == null) { javaLangString = (HotSpotResolvedObjectTypeImpl) fromClass(String.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java index 0bc6fce0ce2..649f3fde260 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java @@ -42,8 +42,6 @@ import jdk.vm.ci.meta.SpeculationLog.NoSpeculationReason; import jdk.vm.ci.meta.SpeculationLog.Speculation; -// JaCoCo Exclude - /** * HotSpot implementation of {@link MetaAccessProvider}. */ @@ -84,7 +82,6 @@ public ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod) { @Override public ResolvedJavaField lookupJavaField(Field reflectionField) { Class fieldHolder = reflectionField.getDeclaringClass(); - HotSpotResolvedJavaType holder = runtime.fromClass(fieldHolder); assert holder != null : fieldHolder; ResolvedJavaField[] fields; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index b75edb9df08..2bc6af55024 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -22,26 +22,20 @@ */ package jdk.vm.ci.hotspot; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.UnresolvedJavaType; +import jdk.vm.ci.meta.annotation.AnnotationsInfo; + +import java.lang.annotation.Annotation; + import static jdk.internal.misc.Unsafe.ADDRESS_SIZE; import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkAreAnnotations; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkIsAnnotation; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.getFirstAnnotationOrNull; import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; -import java.lang.annotation.Annotation; -import java.util.Collections; -import java.util.List; - -import jdk.internal.vm.VMSupport; -import jdk.vm.ci.meta.AnnotationData; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.UnresolvedJavaType; - /** * Represents a field in a HotSpot type. */ @@ -85,8 +79,7 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (obj instanceof HotSpotResolvedJavaFieldImpl) { - HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; + if (obj instanceof HotSpotResolvedJavaFieldImpl that) { if (that.offset != this.offset || that.isStatic() != this.isStatic()) { return false; } else if (this.holder.equals(that.holder)) { @@ -141,9 +134,8 @@ public JavaType getType() { // Pull field into local variable to prevent a race causing // a ClassCastException below JavaType currentType = type; - if (currentType instanceof UnresolvedJavaType) { + if (currentType instanceof UnresolvedJavaType unresolvedType) { // Don't allow unresolved types to hang around forever - UnresolvedJavaType unresolvedType = (UnresolvedJavaType) currentType; JavaType resolved = HotSpotJVMCIRuntime.runtime().lookupType(unresolvedType.getName(), holder, false); if (resolved instanceof ResolvedJavaType) { type = resolved; @@ -187,17 +179,23 @@ public boolean isSynthetic() { */ @Override public boolean isStable() { - return (1 << (config().jvmFieldFlagStableShift ) & internalFlags) != 0; + return (1 << (config().jvmFieldFlagStableShift) & internalFlags) != 0; } - private boolean hasAnnotations() { + /** + * Returns whether this field has type annotations ({@code typeAnnotations == true}) or + * declared annotations ({@code typeAnnotations == false}). + */ + private boolean hasAnnotations(boolean typeAnnotations) { if (!isInternal()) { HotSpotVMConfig config = config(); final long metaspaceAnnotations = UNSAFE.getAddress(holder.getKlassPointer() + config.instanceKlassAnnotationsOffset); if (metaspaceAnnotations != 0) { - long fieldsAnnotations = UNSAFE.getAddress(metaspaceAnnotations + config.annotationsFieldAnnotationsOffset); + int annotationsOffset = typeAnnotations? config.annotationsFieldTypeAnnotationsOffset: config.annotationsFieldAnnotationsOffset; + long fieldsAnnotations = UNSAFE.getAddress(metaspaceAnnotations + annotationsOffset); if (fieldsAnnotations != 0) { - long fieldAnnotations = UNSAFE.getAddress(fieldsAnnotations + config.fieldsAnnotationsBaseOffset + (ADDRESS_SIZE * index)); + int indexOffset = ADDRESS_SIZE * index; + long fieldAnnotations = UNSAFE.getAddress(fieldsAnnotations + config.annotationArrayArrayBaseOffset + indexOffset); return fieldAnnotations != 0; } } @@ -207,7 +205,7 @@ private boolean hasAnnotations() { @Override public Annotation[] getAnnotations() { - if (!hasAnnotations()) { + if (!hasAnnotations(false)) { return new Annotation[0]; } return runtime().reflection.getFieldAnnotations(this); @@ -215,7 +213,7 @@ public Annotation[] getAnnotations() { @Override public Annotation[] getDeclaredAnnotations() { - if (!hasAnnotations()) { + if (!hasAnnotations(false)) { return new Annotation[0]; } return runtime().reflection.getFieldDeclaredAnnotations(this); @@ -223,7 +221,7 @@ public Annotation[] getDeclaredAnnotations() { @Override public T getAnnotation(Class annotationClass) { - if (!hasAnnotations()) { + if (!hasAnnotations(false)) { return null; } return runtime().reflection.getFieldAnnotation(this, annotationClass); @@ -235,27 +233,20 @@ public JavaConstant getConstantValue() { } @Override - public AnnotationData getAnnotationData(ResolvedJavaType annotationType) { - if (!hasAnnotations()) { - checkIsAnnotation(annotationType); + public AnnotationsInfo getDeclaredAnnotationInfo() { + if (!hasAnnotations(false)) { return null; } - return getFirstAnnotationOrNull(getAnnotationData0(annotationType)); + byte[] bytes = compilerToVM().getRawAnnotationBytes('f', holder, holder.getKlassPointer(), index, CompilerToVM.DECLARED_ANNOTATIONS); + return AnnotationsInfo.make(bytes, getDeclaringClass().getConstantPool(), getDeclaringClass()); } @Override - public List getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { - checkIsAnnotation(type1); - checkIsAnnotation(type2); - checkAreAnnotations(types); - if (!hasAnnotations()) { - return List.of(); + public AnnotationsInfo getTypeAnnotationInfo() { + if (!hasAnnotations(true)) { + return null; } - return getAnnotationData0(AnnotationDataDecoder.asArray(type1, type2, types)); - } - - private List getAnnotationData0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedFieldAnnotationData(holder, index, filter); - return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE); + byte[] bytes = compilerToVM().getRawAnnotationBytes('f', holder, holder.getKlassPointer(), index, CompilerToVM.TYPE_ANNOTATIONS); + return AnnotationsInfo.make(bytes, getDeclaringClass().getConstantPool(), getDeclaringClass()); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 224e8b1a070..466db3dcdf8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -22,31 +22,8 @@ */ package jdk.vm.ci.hotspot; -import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; -import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; -import static jdk.vm.ci.hotspot.HotSpotModifiers.BRIDGE; -import static jdk.vm.ci.hotspot.HotSpotModifiers.SYNTHETIC; -import static jdk.vm.ci.hotspot.HotSpotModifiers.VARARGS; -import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmMethodModifiers; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkAreAnnotations; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.checkIsAnnotation; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaType.getFirstAnnotationOrNull; -import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; -import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Executable; -import java.lang.reflect.Modifier; -import java.lang.reflect.Type; -import java.util.BitSet; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -import jdk.internal.vm.VMSupport; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; -import jdk.vm.ci.meta.AnnotationData; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.DefaultProfilingInfo; @@ -61,6 +38,22 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.SpeculationLog; import jdk.vm.ci.meta.TriState; +import jdk.vm.ci.meta.annotation.AnnotationsInfo; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Executable; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.BitSet; + +import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; +import static jdk.vm.ci.hotspot.HotSpotModifiers.BRIDGE; +import static jdk.vm.ci.hotspot.HotSpotModifiers.SYNTHETIC; +import static jdk.vm.ci.hotspot.HotSpotModifiers.VARARGS; +import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmMethodModifiers; +import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; /** * Implementation of {@link JavaMethod} for resolved HotSpot methods. @@ -517,7 +510,7 @@ public Parameter[] getParameters() { @Override public Annotation[][] getParameterAnnotations() { - if ((getConstMethodFlags() & config().constMethodHasParameterAnnotations) == 0 || isClassInitializer()) { + if (!hasAnnotations(HotSpotVMConfig.config().constMethodHasParameterAnnotations)) { return new Annotation[signature.getParameterCount(false)][0]; } return runtime().reflection.getParameterAnnotations(this); @@ -525,7 +518,7 @@ public Annotation[][] getParameterAnnotations() { @Override public Annotation[] getAnnotations() { - if (!hasAnnotations()) { + if (!hasAnnotations(config().constMethodHasMethodAnnotations)) { return new Annotation[0]; } return runtime().reflection.getMethodAnnotations(this); @@ -533,7 +526,7 @@ public Annotation[] getAnnotations() { @Override public Annotation[] getDeclaredAnnotations() { - if (!hasAnnotations()) { + if (!hasAnnotations(config().constMethodHasMethodAnnotations)) { return new Annotation[0]; } return runtime().reflection.getMethodDeclaredAnnotations(this); @@ -541,17 +534,19 @@ public Annotation[] getDeclaredAnnotations() { @Override public T getAnnotation(Class annotationClass) { - if (!hasAnnotations()) { + if (!hasAnnotations(config().constMethodHasMethodAnnotations)) { return null; } return runtime().reflection.getMethodAnnotation(this, annotationClass); } /** - * Returns whether this method has annotations. + * Returns whether this method has annotations in the category specified by {@code category}. + * + * @param category a {@code ConstMethodFlags::_misc_has_*_annotations} value */ - private boolean hasAnnotations() { - return (getConstMethodFlags() & config().constMethodHasMethodAnnotations) != 0 && !isClassInitializer(); + private boolean hasAnnotations(int category) { + return (getConstMethodFlags() & category) != 0 && !isClassInitializer(); } @Override @@ -776,38 +771,49 @@ public int methodIdnum() { } @Override - public AnnotationData getAnnotationData(ResolvedJavaType type) { - if (!hasAnnotations()) { - checkIsAnnotation(type); + public BitSet getOopMapAt(int bci) { + if (getCodeSize() == 0) { + throw new IllegalArgumentException("has no bytecode"); + } + int nwords = ((getMaxLocals() + getMaxStackSize() - 1) / 64) + 1; + long[] oopMap = new long[nwords]; + compilerToVM().getOopMapAt(this, bci, oopMap); + return BitSet.valueOf(oopMap); + } + + @Override + public AnnotationsInfo getDeclaredAnnotationInfo() { + if (!hasAnnotations(config().constMethodHasMethodAnnotations)) { return null; } - return getFirstAnnotationOrNull(getAnnotationData0(type)); + byte[] bytes = compilerToVM().getRawAnnotationBytes('m', this, this.getMethodPointer(), 0, CompilerToVM.DECLARED_ANNOTATIONS); + return AnnotationsInfo.make(bytes, constantPool, getDeclaringClass()); } @Override - public List getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { - checkIsAnnotation(type1); - checkIsAnnotation(type2); - checkAreAnnotations(types); - if (!hasAnnotations()) { - return List.of(); + public AnnotationsInfo getTypeAnnotationInfo() { + if (!hasAnnotations(config().constMethodHasTypeAnnotations)) { + return null; } - return getAnnotationData0(AnnotationDataDecoder.asArray(type1, type2, types)); + byte[] bytes = compilerToVM().getRawAnnotationBytes('m', this, this.getMethodPointer(), 0, CompilerToVM.TYPE_ANNOTATIONS); + return AnnotationsInfo.make(bytes, constantPool, getDeclaringClass()); } - private List getAnnotationData0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedExecutableAnnotationData(this, filter); - return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE); + @Override + public AnnotationsInfo getAnnotationDefaultInfo() { + if (!hasAnnotations(config().constMethodHasDefaultAnnotations)) { + return null; + } + byte[] bytes = compilerToVM().getRawAnnotationBytes('m', this, this.getMethodPointer(), 0, CompilerToVM.ANNOTATION_MEMBER_VALUE); + return AnnotationsInfo.make(bytes, constantPool, getDeclaringClass()); } @Override - public BitSet getOopMapAt(int bci) { - if (getCodeSize() == 0) { - throw new IllegalArgumentException("has no bytecode"); + public AnnotationsInfo getParameterAnnotationInfo() { + if (!hasAnnotations(config().constMethodHasParameterAnnotations)) { + return null; } - int nwords = ((getMaxLocals() + getMaxStackSize() - 1) / 64) + 1; - long[] oopMap = new long[nwords]; - compilerToVM().getOopMapAt(this, bci, oopMap); - return BitSet.valueOf(oopMap); + byte[] bytes = compilerToVM().getRawAnnotationBytes('m', this, this.getMethodPointer(), 0, CompilerToVM.PARAMETER_ANNOTATIONS); + return AnnotationsInfo.make(bytes, constantPool, getDeclaringClass()); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaRecordComponent.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaRecordComponent.java new file mode 100644 index 00000000000..5c6f7f3fc90 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaRecordComponent.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.JavaType; +import java.lang.reflect.RecordComponent; + +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; +import jdk.vm.ci.meta.annotation.AnnotationsInfo; + +import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; + +/** + * Represents a {@linkplain RecordComponent component} in a HotSpot record. + */ +final class HotSpotResolvedJavaRecordComponent implements ResolvedJavaRecordComponent { + + private final HotSpotResolvedObjectTypeImpl declaringRecord; + private final String name; + private final JavaType type; + + /** + * Index in {@code InstanceKlass::_record_components}. + */ + private final int index; + + /** + * Called from the VM. + */ + @VMEntryPoint + private HotSpotResolvedJavaRecordComponent(HotSpotResolvedObjectTypeImpl declaringRecord, int index, int nameIndex, int typeIndex) { + this.declaringRecord = declaringRecord; + this.index = index; + HotSpotConstantPool cp = declaringRecord.getConstantPool(); + this.name = cp.lookupUtf8(nameIndex); + this.type = runtime().lookupType(cp.lookupUtf8(typeIndex), declaringRecord, false); + } + + @Override + public HotSpotResolvedObjectTypeImpl getDeclaringRecord() { + return declaringRecord; + } + + @Override + public String getName() { + return name; + } + + @Override + public String toString() { + return getAccessor().format("HotSpotResolvedJavaRecordComponent<%H.%n %r>"); + } + + @Override + public JavaType getType() { + return type; + } + @Override + public boolean equals(Object obj) { + if (obj instanceof HotSpotResolvedJavaRecordComponent that) { + return that.index == this.index && that.declaringRecord.equals(this.declaringRecord); + } + return false; + } + + @Override + public int hashCode() { + return declaringRecord.hashCode() ^ index; + } + + @Override + public AnnotationsInfo getDeclaredAnnotationInfo() { + byte[] bytes = compilerToVM().getRawAnnotationBytes('r', declaringRecord, declaringRecord.getKlassPointer(), index, CompilerToVM.DECLARED_ANNOTATIONS); + return AnnotationsInfo.make(bytes, getDeclaringRecord().getConstantPool(), getDeclaringRecord()); + } + + @Override + public AnnotationsInfo getTypeAnnotationInfo() { + byte[] bytes = compilerToVM().getRawAnnotationBytes('r', declaringRecord, declaringRecord.getKlassPointer(), index, CompilerToVM.TYPE_ANNOTATIONS); + return AnnotationsInfo.make(bytes, getDeclaringRecord().getConstantPool(), getDeclaringRecord()); + } +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java index ab634568a84..d1e95bb6b4d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java @@ -22,11 +22,10 @@ */ package jdk.vm.ci.hotspot; -import java.util.List; - -import jdk.vm.ci.meta.AnnotationData; import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.UnresolvedJavaType; public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType { @@ -77,13 +76,12 @@ static void checkIsAnnotation(ResolvedJavaType type) { } } - static void checkAreAnnotations(ResolvedJavaType... types) { - for (ResolvedJavaType type : types) { - checkIsAnnotation(type); + static ResolvedJavaType lookupType(UnresolvedJavaType unresolvedJavaType, HotSpotResolvedObjectType accessingType, boolean resolve) { + JavaType javaType = HotSpotJVMCIRuntime.runtime().lookupType(unresolvedJavaType.getName(), accessingType, resolve); + if (javaType instanceof ResolvedJavaType resolved) { + return resolved; } + return null; } - static AnnotationData getFirstAnnotationOrNull(List list) { - return list.isEmpty() ? null : list.get(0); - } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 67fcf1e027f..57275fecd0d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -34,14 +34,13 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.nio.ByteOrder; +import java.util.Arrays; import java.util.Collections; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import jdk.internal.vm.VMSupport; import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.AnnotationData; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.Assumptions.ConcreteMethod; import jdk.vm.ci.meta.Assumptions.ConcreteSubtype; @@ -53,9 +52,11 @@ import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.UnresolvedJavaField; import jdk.vm.ci.meta.UnresolvedJavaType; +import jdk.vm.ci.meta.annotation.AnnotationsInfo; /** * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. This class is not @@ -72,6 +73,7 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem */ private final long klassPointer; + private List recordComponents; private HotSpotResolvedJavaMethodImpl[] methodCacheArray; private HashMap methodCacheHashMap; private volatile HotSpotResolvedJavaField[] instanceFields; @@ -569,7 +571,10 @@ public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaT @Override public HotSpotConstantPool getConstantPool() { - if (constantPool == null || !isArray() && UNSAFE.getAddress(getKlassPointer() + config().instanceKlassConstantsOffset) != constantPool.getConstantPoolPointer()) { + if (isArray()) { + return null; + } + if (constantPool == null || UNSAFE.getAddress(getKlassPointer() + config().instanceKlassConstantsOffset) != constantPool.getConstantPoolPointer()) { /* * If the pointer to the ConstantPool has changed since this was last read refresh the * HotSpotConstantPool wrapper object. This ensures that uses of the constant pool are @@ -704,7 +709,7 @@ public AssumptionResult findUniqueConcreteMethod(ResolvedJav return null; } - private FieldInfo[] getFieldInfo() { + FieldInfo[] getFieldInfo() { if (fieldInfo == null) { fieldInfo = runtime().compilerToVm.getDeclaredFieldsInfo(this); } @@ -773,26 +778,14 @@ static class FieldInfo { this.initializerIndex = initializerIndex; } - private int getClassfileFlags() { + int getClassfileFlags() { return classfileFlags; } - private int getInternalFlags() { + int getInternalFlags() { return internalFlags; } - private int getNameIndex() { - return nameIndex; - } - - private int getSignatureIndex() { - return signatureIndex; - } - - private int getConstantValueIndex() { - return initializerIndex; - } - public int getOffset() { return offset; } @@ -889,6 +882,26 @@ public ResolvedJavaField[] getStaticFields() { } } + @Override + public boolean isRecord() { + HotSpotResolvedObjectTypeImpl superclass = getSuperclass(); + if (!isLeaf() || superclass == null || !superclass.equals(runtime().getJavaLangRecord())) { + return false; + } + return UNSAFE.getAddress(getKlassPointer() + config().instanceKlassRecordComponentsOffset) != 0; + } + + @Override + public List getRecordComponents() { + if (!isRecord()) { + return null; + } + if (recordComponents == null) { + recordComponents = Collections.unmodifiableList(Arrays.asList(compilerToVM().getRecordComponents(this))); + } + return recordComponents; + } + /** * Gets the instance or static fields of this class. * @@ -896,7 +909,6 @@ public ResolvedJavaField[] getStaticFields() { * @param prepend an array to be prepended to the returned result */ private HotSpotResolvedJavaField[] getFields(boolean retrieveStaticFields, HotSpotResolvedJavaField[] prepend) { - HotSpotVMConfig config = config(); int resultCount = 0; int index = 0; @@ -948,16 +960,8 @@ public String getSourceFileName() { * @param includingInherited if true, expand this query to include superclasses of this type */ private boolean mayHaveAnnotations(boolean includingInherited) { - if (isArray()) { - return false; - } - HotSpotVMConfig config = config(); - final long metaspaceAnnotations = UNSAFE.getAddress(getKlassPointer() + config.instanceKlassAnnotationsOffset); - if (metaspaceAnnotations != 0) { - long classAnnotations = UNSAFE.getAddress(metaspaceAnnotations + config.annotationsClassAnnotationsOffset); - if (classAnnotations != 0) { - return true; - } + if (hasDirectAnnotations(false)) { + return true; } if (includingInherited) { HotSpotResolvedObjectTypeImpl superClass = getSuperclass(); @@ -968,6 +972,24 @@ private boolean mayHaveAnnotations(boolean includingInherited) { return false; } + /** + * Returns whether this type has type annotations ({@code typeAnnotations == true}) or + * non-inherited declared annotations ({@code typeAnnotations == false}). + */ + private boolean hasDirectAnnotations(boolean typeAnnotations) { + if (isArray()) { + return false; + } + HotSpotVMConfig config = config(); + final long metaspaceAnnotations = UNSAFE.getAddress(getKlassPointer() + config.instanceKlassAnnotationsOffset); + if (metaspaceAnnotations != 0) { + int annotationsOffset = typeAnnotations?config.annotationsClassTypeAnnotationsOffset: config.annotationsClassAnnotationsOffset; + long classAnnotations = UNSAFE.getAddress(metaspaceAnnotations + annotationsOffset); + return classAnnotations != 0; + } + return false; + } + private static final Annotation[] NO_ANNOTATIONS = {}; @Override @@ -1160,11 +1182,7 @@ public String toString() { @Override public ResolvedJavaType lookupType(UnresolvedJavaType unresolvedJavaType, boolean resolve) { - JavaType javaType = HotSpotJVMCIRuntime.runtime().lookupType(unresolvedJavaType.getName(), this, resolve); - if (javaType instanceof ResolvedJavaType) { - return (ResolvedJavaType) javaType; - } - return null; + return lookupType(unresolvedJavaType, this, resolve); } @Override @@ -1188,27 +1206,20 @@ public boolean isCloneableWithAllocation() { } @Override - public AnnotationData getAnnotationData(ResolvedJavaType annotationType) { - if (!mayHaveAnnotations(true)) { - checkIsAnnotation(annotationType); + public AnnotationsInfo getDeclaredAnnotationInfo() { + if (!hasDirectAnnotations(false)) { return null; } - return getFirstAnnotationOrNull(getAnnotationData0(annotationType)); + byte[] bytes = compilerToVM().getRawAnnotationBytes('t', this, this.getKlassPointer(), 0, CompilerToVM.DECLARED_ANNOTATIONS); + return AnnotationsInfo.make(bytes, getConstantPool(), this); } @Override - public List getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { - if (!mayHaveAnnotations(true)) { - checkIsAnnotation(type1); - checkIsAnnotation(type2); - checkAreAnnotations(types); - return List.of(); + public AnnotationsInfo getTypeAnnotationInfo() { + if (!hasDirectAnnotations(true)) { + return null; } - return getAnnotationData0(AnnotationDataDecoder.asArray(type1, type2, types)); - } - - private List getAnnotationData0(ResolvedJavaType... filter) { - byte[] encoded = compilerToVM().getEncodedClassAnnotationData(this, filter); - return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE); + byte[] bytes = compilerToVM().getRawAnnotationBytes('t', this, this.getKlassPointer(), 0, CompilerToVM.TYPE_ANNOTATIONS); + return AnnotationsInfo.make(bytes, getConstantPool(), this); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index fac3caf8160..43ed6980477 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -22,23 +22,23 @@ */ package jdk.vm.ci.hotspot; -import static java.util.Objects.requireNonNull; -import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Modifier; -import java.util.Collections; -import java.util.List; - import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.AnnotationData; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.UnresolvedJavaType; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Modifier; +import java.util.List; + +import static java.util.Objects.requireNonNull; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; /** * Implementation of {@link JavaType} for primitive HotSpot types. @@ -47,7 +47,7 @@ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType static HotSpotResolvedPrimitiveType[] primitives; - private JavaKind kind; + private final JavaKind kind; HotSpotObjectConstantImpl mirror; /** @@ -238,6 +238,16 @@ public ResolvedJavaField[] getStaticFields() { return new ResolvedJavaField[0]; } + @Override + public boolean isRecord() { + return false; + } + + @Override + public List getRecordComponents() { + return null; + } + @Override public Annotation[] getAnnotations() { return new Annotation[0]; @@ -357,16 +367,7 @@ public JavaConstant getJavaMirror() { } @Override - public AnnotationData getAnnotationData(ResolvedJavaType type) { - checkIsAnnotation(type); - return null; - } - - @Override - public List getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { - checkIsAnnotation(type1); - checkIsAnnotation(type2); - checkAreAnnotations(types); - return List.of(); + public ResolvedJavaType lookupType(UnresolvedJavaType unresolvedJavaType, boolean resolve) { + return lookupType(unresolvedJavaType, runtime().getJavaLangObject(), resolve); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index b83981a6a74..df2c5651bb6 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -31,7 +31,7 @@ /** * Used to access native configuration details. - * + *

* All non-static, public fields in this class are so that they can be compiled as constants. */ class HotSpotVMConfig extends HotSpotVMConfigAccess { @@ -94,9 +94,9 @@ static String getHostArchitectureName() { final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "InstanceKlass::ClassState"); final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*"); - final int instanceKlassFieldInfoStreamOffset = getFieldOffset("InstanceKlass::_fieldinfo_stream", Integer.class, "Array*"); final int instanceKlassAnnotationsOffset = getFieldOffset("InstanceKlass::_annotations", Integer.class, "Annotations*"); final int instanceKlassPermittedSubclassesOffset = getFieldOffset("InstanceKlass::_permitted_subclasses", Integer.class, "Array*"); + final int instanceKlassRecordComponentsOffset = getFieldOffset("InstanceKlass::_record_components", Integer.class, "Array*"); final int instanceKlassMiscFlagsOffset = getFieldOffset("InstanceKlass::_misc_flags._flags", Integer.class, "u2"); final int klassMiscFlagsOffset = getFieldOffset("Klass::_misc_flags._flags", Integer.class, "u1"); final int klassVtableStartOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_start_offset", Integer.class, "int"); @@ -107,12 +107,12 @@ static String getHostArchitectureName() { final int instanceKlassStateBeingInitialized = getConstant("InstanceKlass::being_initialized", Integer.class); final int annotationsFieldAnnotationsOffset = getFieldOffset("Annotations::_fields_annotations", Integer.class, "Array*"); + final int annotationsFieldTypeAnnotationsOffset = getFieldOffset("Annotations::_fields_type_annotations", Integer.class, "Array*"); final int annotationsClassAnnotationsOffset = getFieldOffset("Annotations::_class_annotations", Integer.class, "AnnotationArray*"); - final int fieldsAnnotationsBaseOffset = getFieldValue("CompilerToVM::Data::_fields_annotations_base_offset", Integer.class, "int"); + final int annotationsClassTypeAnnotationsOffset = getFieldOffset("Annotations::_class_type_annotations", Integer.class, "AnnotationArray*"); + final int annotationArrayArrayBaseOffset = getFieldValue("CompilerToVM::Data::_annotation_array_array_base_offset", Integer.class, "int"); - final int arrayU1LengthOffset = getFieldOffset("Array::_length", Integer.class, "int"); final int arrayU1DataOffset = getFieldOffset("Array::_data", Integer.class); - final int arrayU2DataOffset = getFieldOffset("Array::_data", Integer.class); final int arrayJUShortDataOffset = getFieldOffset("Array::_data", Integer.class); final int arrayJUShortLengthOffset = getFieldOffset("Array::_length", Integer.class, "int"); @@ -155,7 +155,6 @@ long prototypeMarkWord() { final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, "nmethod*"); final int methodFlagsForceInline = getConstant("MethodFlags::_misc_force_inline", Integer.class); - final int methodFlagsDontInline = getConstant("MethodFlags::_misc_dont_inline", Integer.class); final int nonvirtualVtableIndex = getConstant("Method::nonvirtual_vtable_index", Integer.class); final int invalidVtableIndex = getConstant("Method::invalid_vtable_index", Integer.class); @@ -171,16 +170,6 @@ long prototypeMarkWord() { final int nmethodCompLevelOffset = getFieldOffset("nmethod::_comp_level", Integer.class, "CompLevel"); - final int compilationLevelNone = getConstant("CompLevel_none", Integer.class); - final int compilationLevelSimple = getConstant("CompLevel_simple", Integer.class); - final int compilationLevelLimitedProfile = getConstant("CompLevel_limited_profile", Integer.class); - final int compilationLevelFullProfile = getConstant("CompLevel_full_profile", Integer.class); - final int compilationLevelFullOptimization = getConstant("CompLevel_full_optimization", Integer.class); - - final int compLevelAdjustmentNone = getConstant("JVMCIRuntime::none", Integer.class); - final int compLevelAdjustmentByHolder = getConstant("JVMCIRuntime::by_holder", Integer.class); - final int compLevelAdjustmentByFullSignature = getConstant("JVMCIRuntime::by_full_signature", Integer.class); - final int invocationEntryBci = getConstant("InvocationEntryBci", Integer.class); final int extraStackEntries = getFieldValue("CompilerToVM::Data::Method_extra_stack_entries", Integer.class, "int"); @@ -202,7 +191,9 @@ long prototypeMarkWord() { final int constMethodHasLineNumberTable = getConstant("ConstMethodFlags::_misc_has_linenumber_table", Integer.class); final int constMethodHasLocalVariableTable = getConstant("ConstMethodFlags::_misc_has_localvariable_table", Integer.class); final int constMethodHasMethodAnnotations = getConstant("ConstMethodFlags::_misc_has_method_annotations", Integer.class); + final int constMethodHasTypeAnnotations = getConstant("ConstMethodFlags::_misc_has_type_annotations", Integer.class); final int constMethodHasParameterAnnotations = getConstant("ConstMethodFlags::_misc_has_parameter_annotations", Integer.class); + final int constMethodHasDefaultAnnotations = getConstant("ConstMethodFlags::_misc_has_default_annotations", Integer.class); final int constMethodHasExceptionTable = getConstant("ConstMethodFlags::_misc_has_exception_table", Integer.class); final int exceptionTableElementSize = getFieldValue("CompilerToVM::Data::sizeof_ExceptionTableElement", Integer.class, "int"); @@ -281,8 +272,6 @@ final int baseVtableLength() { return universeBaseVtableSize / (vtableEntrySize / heapWordSize); } - final int klassOffset = getFieldValue("java_lang_Class::_klass_offset", Integer.class, "int"); - /** * The DataLayout header size is the same as the cell size. */ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java deleted file mode 100644 index 666e1181cb1..00000000000 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Annotated.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.meta; - -import java.lang.annotation.Inherited; -import java.util.List; - -/** - * Represents a program element such as a method, constructor, field or class for which annotations - * may be present. - */ -public interface Annotated { - - /** - * Constructs the annotations present on this element whose types are in the set composed of {@code type1}, - * {@code type2} and {@code types}. All enum types referenced by the returned annotation are - * initialized. Class initialization is not triggered for enum types referenced by other - * annotations of this element. - * - * If this element is a class, then {@link Inherited} annotations are included in the set of - * annotations considered. - * - * See {@link java.lang.reflect.AnnotatedElement} for the definition of present. - * - * @param type1 an annotation type - * @param type2 an annotation type - * @param types more annotation types - * @return an immutable list of the annotations present on this element that match one of the - * given types - * @throws IllegalArgumentException if any type in the set composed of {@code type1}, - * {@code type2} and {@code types} is not an annotation interface type - * @throws UnsupportedOperationException if this operation is not supported - */ - default List getAnnotationData(ResolvedJavaType type1, ResolvedJavaType type2, ResolvedJavaType... types) { - throw new UnsupportedOperationException(); - } - - /** - * Constructs the annotation present on this element of type {@code type}. - * - * See {@link java.lang.reflect.AnnotatedElement} for the definition of present. - * - * @param type the type object corresponding to the annotation interface type - * @return this element's annotation for the specified annotation type if present on this - * element, else null - * @throws IllegalArgumentException if {@code type} is not an annotation interface type - * @throws UnsupportedOperationException if this operation is not supported - */ - default AnnotationData getAnnotationData(ResolvedJavaType type) { - throw new UnsupportedOperationException(); - } -} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationData.java deleted file mode 100644 index 76edb8c83a7..00000000000 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AnnotationData.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.meta; - -import java.lang.annotation.Annotation; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -/** - * Represents an annotation where element values are represented with the types described - * {@linkplain #get here}. - * - * In contrast to the standard annotation API based on {@link Annotation}, use of - * {@link AnnotationData} allows annotations to be queried without the JVMCI runtime having to - * support dynamic loading of arbitrary {@link Annotation} classes. Such support is impossible in a - * closed world, ahead-of-time compiled environment such as libgraal. - */ -public final class AnnotationData { - - private final JavaType type; - private final Map elements; - - private static final Set> ELEMENT_TYPES = Set.of( - Boolean.class, - Byte.class, - Character.class, - Short.class, - Integer.class, - Float.class, - Long.class, - Double.class, - String.class, - EnumData.class, - AnnotationData.class); - - /** - * Creates an annotation. - * - * @param type the annotation interface of this annotation, represented as a {@link JavaType} - * @param elements the names and values of this annotation's element values. Each value's type - * must be one of the {@code AnnotationData} types described {@linkplain #get here} - * or it must be a {@link ErrorData} object whose {@code toString()} value describes - * the error raised while parsing the element. There is no distinction between a - * value explicitly present in the annotation and an element's default value. - * @throws IllegalArgumentException if the value of an entry in {@code elements} is not of an - * accepted type - * @throws NullPointerException if any of the above parameters is null or any entry in - * {@code elements} is null - */ - public AnnotationData(JavaType type, Map.Entry[] elements) { - this.type = Objects.requireNonNull(type); - for (Map.Entry e : elements) { - Object value = e.getValue(); - if (!(value instanceof ErrorData) && - !(value instanceof JavaType) && - !(value instanceof List) && - !ELEMENT_TYPES.contains(value.getClass())) { - throw new IllegalArgumentException("illegal type for element " + e.getKey() + ": " + value.getClass().getName()); - } - } - this.elements = Map.ofEntries(elements); - } - - /** - * @return the annotation interface of this annotation, represented as a {@link JavaType} - */ - public JavaType getAnnotationType() { - return type; - } - - // @formatter:off - /** - * Gets the annotation element denoted by {@code name}. The following table shows the - * correspondence between the type of an element as declared by a method in the annotation - * interface and the type of value returned by this method: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Annotation AnnotationData
boolean Boolean
byte Byte
char Character
short Short
int Integer
float Float
long Long
double Double
String String
Class JavaType
Enum EnumData
Annotation AnnotationData
[]immutable List<T> where T is one of the above types
- * - * @param the type of the element as per the {@code AnnotationData} column in the above - * table or {@link Object} - * @param elementType the class for the type of the element - * @return the annotation element denoted by {@code name} - * @throws ClassCastException if the element is not of type {@code V} - * @throws IllegalArgumentException if this annotation has no element named {@code name} or if - * there was an error parsing or creating the element value - */ - // @formatter:on - public V get(String name, Class elementType) { - Object val = elements.get(name); - if (val == null) { - throw new IllegalArgumentException("no element named " + name); - } - Class valClass = val.getClass(); - if (valClass == ErrorData.class) { - throw new IllegalArgumentException(val.toString()); - } - return elementType.cast(val); - } - - @Override - public String toString() { - return "@" + type.getName() + "(" + elements + ")"; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof AnnotationData) { - AnnotationData that = (AnnotationData) obj; - return this.type.equals(that.type) && this.elements.equals(that.elements); - - } - return false; - } - - @Override - public int hashCode() { - return type.hashCode() ^ elements.hashCode(); - } -} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java deleted file mode 100644 index 4e8fc3a8ab7..00000000000 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EnumData.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.meta; - -/** - * Represents an enum constant within {@link AnnotationData}. - */ -public final class EnumData { - private final JavaType type; - private final String name; - - /** - * Creates an enum constant. - * - * @param type the {@linkplain Enum enum type} - * @param name the {@linkplain Enum#name() name} of the enum - */ - public EnumData(JavaType type, String name) { - this.type = type; - this.name = name; - } - - /** - * Gets the {@linkplain Enum enum type}. - */ - public JavaType getEnumType() { - return type; - } - - /** - * Gets the {@linkplain Enum#name() name} of the enum. - */ - public String getName() { - return name; - } - - @Override - public String toString() { - return name; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof EnumData) { - EnumData that = (EnumData) obj; - return this.type.equals(that.type) && this.name.equals(that.name); - } - return false; - } - - @Override - public int hashCode() { - return this.type.hashCode() ^ this.name.hashCode(); - } -} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java index baa7e295d32..970e95abe08 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java @@ -24,8 +24,6 @@ import java.lang.reflect.Array; -//JaCoCo Exclude - /** * Denotes the basic kinds of types in CRI, including the all the Java primitive types, for example, * {@link JavaKind#Int} for {@code int} and {@link JavaKind#Object} for all object types. A kind has @@ -175,7 +173,7 @@ public boolean isNumericFloat() { } /** - * Checks whether this represent an Object of some sort. + * Checks whether this represents an Object of some sort. * * @return {@code true} if this is {@link #Object}. */ @@ -188,9 +186,12 @@ public boolean isObject() { * * @param typeString the Java type string * @return the kind + * @throws IllegalArgumentException if {@code typeString} is empty */ public static JavaKind fromTypeString(String typeString) { - assert typeString.length() > 0; + if (typeString.isEmpty()) { + throw new IllegalArgumentException("empty typeString"); + } final char first = typeString.charAt(0); if (first == '[' || first == 'L') { return JavaKind.Object; @@ -217,32 +218,36 @@ public static JavaKind fromWordSize(int wordSizeInBytes) { * Returns the kind from the character describing a primitive or void. * * @param ch the character for a void or primitive kind as returned by {@link #getTypeChar()} - * @return the kind + * @return the void or primitive kind for {@code ch} + * @throws IllegalArgumentException if {@code ch} does not represent a void or primitive kind */ public static JavaKind fromPrimitiveOrVoidTypeChar(char ch) { - switch (ch) { - case 'Z': - return Boolean; - case 'C': - return Char; - case 'F': - return Float; - case 'D': - return Double; - case 'B': - return Byte; - case 'S': - return Short; - case 'I': - return Int; - case 'J': - return Long; - case 'V': - return Void; + JavaKind kind = forPrimitiveTypeChar(ch); + if (kind != null) { + return kind; } throw new IllegalArgumentException("unknown primitive or void type character: " + ch); } + /** + * Gets the {@linkplain #isPrimitive() primitive kind} for {@code ch} + * or {@code null} of {@code ch} does not denote the type char of a primitive kind. + */ + public static JavaKind forPrimitiveTypeChar(char ch) { + return switch (ch) { + case 'Z' -> Boolean; + case 'C' -> Char; + case 'F' -> Float; + case 'D' -> Double; + case 'B' -> Byte; + case 'S' -> Short; + case 'I' -> Int; + case 'J' -> Long; + case 'V' -> Void; + default -> null; + }; + } + /** * Returns the Kind representing the given Java class. * @@ -328,8 +333,7 @@ public String format(Object value) { if (value == null) { return "null"; } else { - if (value instanceof String) { - String s = (String) value; + if (value instanceof String s) { if (s.length() > 50) { return "String:\"" + s.substring(0, 30) + "...\""; } else { @@ -340,7 +344,7 @@ public String format(Object value) { } else if (value instanceof Enum) { return MetaUtil.getSimpleName(value.getClass(), true) + ":" + ((Enum) value).name(); } else if (value instanceof FormatWithToString) { - return MetaUtil.getSimpleName(value.getClass(), true) + ":" + String.valueOf(value); + return MetaUtil.getSimpleName(value.getClass(), true) + ":" + value; } else if (value instanceof Class) { return "Class:" + ((Class) value).getName(); } else if (isToStringSafe(value.getClass())) { @@ -386,26 +390,17 @@ private static String formatArray(Object array) { * @return the minimum value represented as a {@code long} */ public long getMinValue() { - switch (this) { - case Boolean: - return 0; - case Byte: - return java.lang.Byte.MIN_VALUE; - case Char: - return java.lang.Character.MIN_VALUE; - case Short: - return java.lang.Short.MIN_VALUE; - case Int: - return java.lang.Integer.MIN_VALUE; - case Long: - return java.lang.Long.MIN_VALUE; - case Float: - return java.lang.Float.floatToRawIntBits(java.lang.Float.MIN_VALUE); - case Double: - return java.lang.Double.doubleToRawLongBits(java.lang.Double.MIN_VALUE); - default: - throw new IllegalArgumentException("illegal call to minValue on " + this); - } + return switch (this) { + case Boolean -> 0; + case Byte -> java.lang.Byte.MIN_VALUE; + case Char -> Character.MIN_VALUE; + case Short -> java.lang.Short.MIN_VALUE; + case Int -> Integer.MIN_VALUE; + case Long -> java.lang.Long.MIN_VALUE; + case Float -> java.lang.Float.floatToRawIntBits(java.lang.Float.MIN_VALUE); + case Double -> java.lang.Double.doubleToRawLongBits(java.lang.Double.MIN_VALUE); + default -> throw new IllegalArgumentException("illegal call to minValue on " + this); + }; } /** @@ -414,26 +409,17 @@ public long getMinValue() { * @return the maximum value represented as a {@code long} */ public long getMaxValue() { - switch (this) { - case Boolean: - return 1; - case Byte: - return java.lang.Byte.MAX_VALUE; - case Char: - return java.lang.Character.MAX_VALUE; - case Short: - return java.lang.Short.MAX_VALUE; - case Int: - return java.lang.Integer.MAX_VALUE; - case Long: - return java.lang.Long.MAX_VALUE; - case Float: - return java.lang.Float.floatToRawIntBits(java.lang.Float.MAX_VALUE); - case Double: - return java.lang.Double.doubleToRawLongBits(java.lang.Double.MAX_VALUE); - default: - throw new IllegalArgumentException("illegal call to maxValue on " + this); - } + return switch (this) { + case Boolean -> 1; + case Byte -> java.lang.Byte.MAX_VALUE; + case Char -> Character.MAX_VALUE; + case Short -> java.lang.Short.MAX_VALUE; + case Int -> Integer.MAX_VALUE; + case Long -> java.lang.Long.MAX_VALUE; + case Float -> java.lang.Float.floatToRawIntBits(java.lang.Float.MAX_VALUE); + case Double -> java.lang.Double.doubleToRawLongBits(java.lang.Double.MAX_VALUE); + default -> throw new IllegalArgumentException("illegal call to maxValue on " + this); + }; } /** @@ -455,24 +441,13 @@ public int getByteCount() { * @return the number of bits */ public int getBitCount() { - switch (this) { - case Boolean: - return 1; - case Byte: - return 8; - case Char: - case Short: - return 16; - case Float: - return 32; - case Int: - return 32; - case Double: - return 64; - case Long: - return 64; - default: - throw new IllegalArgumentException("illegal call to getBitCount() on " + this); - } + return switch (this) { + case Boolean -> 1; + case Byte -> 8; + case Char, Short -> 16; + case Float, Int -> 32; + case Double, Long -> 64; + default -> throw new IllegalArgumentException("illegal call to getBitCount() on " + this); + }; } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java index 2686ab1737f..aa6c9896454 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java @@ -26,7 +26,11 @@ import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.RecordComponent; +import java.util.List; +import java.util.Objects; +import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.SpeculationLog.Speculation; /** @@ -74,6 +78,22 @@ default ResolvedJavaType[] lookupJavaTypes(Class[] classes) { */ ResolvedJavaType lookupJavaType(JavaConstant constant); + /** + * Provides the {@link ResolvedJavaRecordComponent} for {@code recordComponent}. + */ + default ResolvedJavaRecordComponent lookupJavaRecordComponent(RecordComponent recordComponent){ + Class declaringRecord = recordComponent.getDeclaringRecord(); + ResolvedJavaType holder = Objects.requireNonNull(lookupJavaType(declaringRecord)); + List recordComponents = holder.getRecordComponents(); + ResolvedJavaType fieldType = lookupJavaType(recordComponent.getType()); + for (ResolvedJavaRecordComponent rc : recordComponents) { + if (rc.getName().equals(recordComponent.getName()) && rc.getType().equals(fieldType)) { + return rc; + } + } + throw new JVMCIError("unresolved RecordComponent %s", recordComponent); + } + /** * Returns the number of bytes occupied by this constant value or constant object. * diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index cb891ab2e1b..0de311571e3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -22,6 +22,8 @@ */ package jdk.vm.ci.meta; +import jdk.vm.ci.meta.annotation.Annotated; + import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Modifier; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index f401bc30f83..747ee325951 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -22,13 +22,15 @@ */ package jdk.vm.ci.meta; +import jdk.vm.ci.meta.annotation.Annotated; +import jdk.vm.ci.meta.annotation.AnnotationsInfo; + import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; -import java.util.BitSet; /** * Represents a resolved Java method. Methods, like fields and types, are resolved through @@ -486,4 +488,20 @@ default boolean isScoped() { * responsibility to ensure the same speculation log is used throughout a compilation. */ SpeculationLog getSpeculationLog(); + + /** + * Gets the class file info for the parameter annotations on this method + * or {@code null} if no such info exists. + */ + default AnnotationsInfo getParameterAnnotationInfo() { + return null; + } + + /** + * Gets the class file info for the default value of the annotation element represented + * by this method or {@code null} if no such info exists. + */ + default AnnotationsInfo getAnnotationDefaultInfo() { + return null; + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaRecordComponent.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaRecordComponent.java new file mode 100644 index 00000000000..6bfa27b3953 --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaRecordComponent.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import jdk.vm.ci.meta.annotation.Annotated; + +/** + * A reference to a {@link java.lang.reflect.RecordComponent}. + */ +public interface ResolvedJavaRecordComponent extends Annotated { + + /** + * Gets the {@link ResolvedJavaType} object representing the class which declares this record component. + */ + ResolvedJavaType getDeclaringRecord(); + + /** + * Gets a {@code ResolvedJavaMethod} that represents the accessor for this record + * component. + */ + default ResolvedJavaMethod getAccessor() { + for (ResolvedJavaMethod method : getDeclaringRecord().getDeclaredMethods(false)) { + if (method.getName().equals(getName()) && + method.getSignature().getParameterCount(false) == 0 && + method.getSignature().getReturnType(null).getName().equals(getType().getName())) { + return method; + } + } + return null; + } + + /** + * Returns the name of this record component. + */ + String getName(); + + /** + * Returns a {@link JavaType} object that identifies the declared type for this record component. + */ + JavaType getType(); +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index 56b5966b530..c7a73f2fe3d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -22,11 +22,12 @@ */ package jdk.vm.ci.meta; +import jdk.vm.ci.meta.Assumptions.AssumptionResult; +import jdk.vm.ci.meta.annotation.Annotated; + import java.lang.reflect.AnnotatedElement; import java.util.List; -import jdk.vm.ci.meta.Assumptions.AssumptionResult; - /** * Represents a resolved Java type. Types include primitives, objects, {@code void}, and arrays * thereof. Types, like fields and methods, are resolved through {@link ConstantPool constant pools} @@ -348,6 +349,18 @@ default ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, Reso */ ResolvedJavaField[] getStaticFields(); + /** + * Returns whether this type is a {@link Record}. + */ + boolean isRecord(); + + /** + * Returns an unmodifiable list of {@code ResolvedJavaRecordComponent} objects representing all the + * record components of this record class, or {@code null} if this class is + * not a record class. + */ + List getRecordComponents(); + /** * Returns the instance field of this class (or one of its super classes) at the given offset, * or {@code null} if there is no such field. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaType.java index 1740744b4b1..ee7373219e2 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaType.java @@ -107,6 +107,10 @@ public String toString() { @Override public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { - return accessingClass.lookupType(this, true); + ResolvedJavaType type = accessingClass.lookupType(this, true); + if (type == null) { + throw new NoClassDefFoundError(toClassName()); + } + return type; } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ErrorData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java similarity index 56% rename from src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ErrorData.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java index 72177ddcbbc..cdfa356128b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ErrorData.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/Annotated.java @@ -20,44 +20,30 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.vm.ci.meta; +package jdk.vm.ci.meta.annotation; + +import java.lang.reflect.AnnotatedElement; /** - * Represents an error constant within {@link AnnotationData}. - * - * Similar to {@code sun.reflect.annotation.ExceptionProxy}. + * Represents a program element such as a method, constructor, field or class for which annotations + * may be directly present. This API is analogous to {@link java.lang.reflect.AnnotatedElement} + * except that it only supports {@linkplain AnnotatedElement#getDeclaredAnnotations() declared annotations}. */ -public final class ErrorData { - private final String description; +public interface Annotated { /** - * Creates an error constant. - * - * @param description description of the error + * Gets the class file info for the annotations directly present on this element + * or {@code null} if no such info exists. */ - public ErrorData(String description) { - this.description = description; - } - - @Override - public String toString() { - return description; + default AnnotationsInfo getDeclaredAnnotationInfo() { + return null; } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof ErrorData) { - ErrorData that = (ErrorData) obj; - return this.description.equals(that.description); - } - return false; - } - - @Override - public int hashCode() { - return description.hashCode(); + /** + * Gets the class file info for the type annotations associated with this element + * or {@code null} if no such info exists. + */ + default AnnotationsInfo getTypeAnnotationInfo() { + return null; } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationsInfo.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationsInfo.java new file mode 100644 index 00000000000..e60e134d02d --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/annotation/AnnotationsInfo.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta.annotation; + +import jdk.vm.ci.meta.ConstantPool; +import jdk.vm.ci.meta.ResolvedJavaType; + +import java.util.Objects; + +/** + * Encapsulates the raw info of a class file annotations attribute (e.g. {@code RuntimeVisibleAnnotations}). + * + * @param bytes raw bytes of the attribute after the {@code u2 attribute_name_index; u4 attribute_length} prefix + * @param constPool for decoding constant pool indexes in embedded in {@code bytes} + * @param container for resolving type names embedded in {@code bytes} + */ +public record AnnotationsInfo(byte[] bytes, ConstantPool constPool, ResolvedJavaType container) { + /** + * Returns an {@link AnnotationsInfo} instance for the given args if + * {@code bytes != null} else {@code null}. + */ + public static AnnotationsInfo make(byte[] bytes, ConstantPool constPool, ResolvedJavaType container) { + if (bytes == null) { + return null; + } + return new AnnotationsInfo(bytes, Objects.requireNonNull(constPool), Objects.requireNonNull(container)); + } +} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCI.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCI.java index d07df2ba75d..dff90a35e56 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCI.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCI.java @@ -69,7 +69,7 @@ public static JVMCIRuntime getRuntime() { errorMessage.format("The VM does not support the JVMCI API.%n"); errorMessage.format("Currently used Java home directory is %s.%n", javaHome); errorMessage.format("Currently used VM configuration is: %s", vmName); - throw new UnsupportedOperationException(errorMessage.toString()); + throw new UnsupportedOperationException(errorMessage.toString(), e); } finally { initializing = false; } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java index dcc380d158f..8e927eaf6d8 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java @@ -23,10 +23,13 @@ package jdk.vm.ci.runtime.test; import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import java.lang.reflect.Field; +import java.lang.reflect.RecordComponent; import java.util.HashMap; import java.util.Map; +import java.util.Objects; /** * Context for field related tests. @@ -34,13 +37,19 @@ public class FieldUniverse extends TypeUniverse { public static final Map fields = new HashMap<>(); + public static final Map recordComponents = new HashMap<>(); - { + static { for (Class c : classes) { for (Field f : c.getDeclaredFields()) { ResolvedJavaField field = metaAccess.lookupJavaField(f); fields.put(f, field); } + if (c.isRecord()) { + for (RecordComponent rc : Objects.requireNonNull(c.getRecordComponents())) { + recordComponents.put(rc, metaAccess.lookupJavaRecordComponent(rc)); + } + } } } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java index 92366580a91..03371c48d76 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java @@ -37,7 +37,7 @@ public class MethodUniverse extends TypeUniverse { public static final Map methods = new HashMap<>(); public static final Map, ResolvedJavaMethod> constructors = new HashMap<>(); - { + static { for (Class c : classes) { for (Method m : c.getDeclaredMethods()) { ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java index 8e9be9eda37..15ed60515e7 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,10 @@ * @test * @requires vm.jvmci * @library ../../../../../ - * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java - * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java - * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java - * TestResolvedJavaType.java - * @clean jdk.internal.vm.test.AnnotationTestInput$Missing - * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java - * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules jdk.internal.vm.ci/jdk.vm.ci.meta + * java.base/java.lang:open + * java.base/java.lang.reflect:open + * jdk.internal.vm.ci/jdk.vm.ci.meta.annotation * jdk.internal.vm.ci/jdk.vm.ci.hotspot * jdk.internal.vm.ci/jdk.vm.ci.runtime * jdk.internal.vm.ci/jdk.vm.ci.common @@ -45,12 +41,15 @@ package jdk.vm.ci.runtime.test; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.runtime.test.TestResolvedJavaField.TestClassLoader; +import org.junit.Assert; +import org.junit.Test; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -65,17 +64,12 @@ import java.util.Map; import java.util.Set; -import org.junit.Assert; -import org.junit.Test; - -import jdk.internal.vm.test.AnnotationTestInput; -import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.runtime.test.TestResolvedJavaField.TestClassLoader; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; /** * Tests for {@link ResolvedJavaField}. @@ -193,11 +187,24 @@ private Method findTestMethod(Method apiMethod) { return null; } + private static final Field fieldAnnotations = lookupField(Field.class, "annotations"); + private static final Method fieldGetTypeAnnotationBytes = lookupMethod(Field.class, "getTypeAnnotationBytes0"); + + @Test + public void getTypeAnnotationInfoTest() { + for (Field f : fields.keySet()) { + ResolvedJavaField field = metaAccess.lookupJavaField(f); + byte[] rawAnnotations = invokeMethod(fieldGetTypeAnnotationBytes, f); + TestResolvedJavaType.checkRawAnnotations(field, "getTypeAnnotationInfo", rawAnnotations, field.getTypeAnnotationInfo()); + } + } + @Test - public void getAnnotationDataTest() throws Exception { - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredField("annotatedField")); + public void getDeclaredAnnotationInfoTest() { for (Field f : fields.keySet()) { - TestResolvedJavaType.getAnnotationDataTest(f); + ResolvedJavaField field = metaAccess.lookupJavaField(f); + byte[] rawAnnotations = getFieldValue(fieldAnnotations, f); + TestResolvedJavaType.checkRawAnnotations(field, "getDeclaredAnnotationInfo", rawAnnotations, field.getDeclaredAnnotationInfo()); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 6151ae68ce7..1f1af4d0af2 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,10 @@ * @test * @requires vm.jvmci * @library ../../../../../ - * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java - * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java - * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java - * TestResolvedJavaType.java - * @clean jdk.internal.vm.test.AnnotationTestInput$Missing - * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java - * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules jdk.internal.vm.ci/jdk.vm.ci.meta + * java.base/java.lang:open + * java.base/java.lang.reflect:open + * jdk.internal.vm.ci/jdk.vm.ci.meta.annotation * jdk.internal.vm.ci/jdk.vm.ci.runtime * jdk.internal.vm.ci/jdk.vm.ci.common * jdk.internal.vm.ci/jdk.vm.ci.hotspot @@ -45,20 +41,31 @@ package jdk.vm.ci.runtime.test; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ConstantPool; +import jdk.vm.ci.meta.ExceptionHandler; +import jdk.vm.ci.meta.Local; +import jdk.vm.ci.meta.LocalVariableTable; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; +import jdk.vm.ci.meta.ResolvedJavaType; +import org.junit.Assert; +import org.junit.Test; -import java.io.DataInputStream; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.classfile.CodeElement; +import java.lang.classfile.Instruction; +import java.lang.classfile.MethodModel; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; +import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -66,8 +73,6 @@ import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -80,30 +85,11 @@ import java.util.Objects; import java.util.Set; -import org.junit.Assert; -import org.junit.Test; - -import jdk.internal.vm.test.AnnotationTestInput; -import java.lang.classfile.Attributes; -import java.lang.classfile.ClassFile; -import java.lang.classfile.ClassModel; -import java.lang.classfile.CodeElement; -import java.lang.classfile.MethodModel; -import java.lang.classfile.Instruction; -import java.lang.classfile.attribute.CodeAttribute; - -import jdk.vm.ci.meta.ConstantPool; -import jdk.vm.ci.meta.ExceptionHandler; -import jdk.vm.ci.meta.Local; -import jdk.vm.ci.meta.LocalVariableTable; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.Annotation1; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.Annotation2; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.Annotation3; -import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.NumbersDE; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** * Tests for {@link ResolvedJavaMethod}. @@ -368,9 +354,11 @@ public void getAnnotationsTest() throws NoSuchMethodException { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) @interface Special { + String elementWithDefault() default "NO_NAME"; + long elementWithoutDefault(); } - private static native void methodWithAnnotatedParameters(@NonNull HashMap p1, @Special @NonNull Class p2); + private static native void methodWithAnnotatedParameters(@NonNull HashMap p1, @Special(elementWithoutDefault = 42) @NonNull Class p2); @Test public void getParameterAnnotationsTest() throws NoSuchMethodException { @@ -543,81 +531,45 @@ public void testVirtualMethodTableAccess() { } } - /** - * Encapsulates input for {@link TestResolvedJavaMethod#getAnnotationDataTest}. - */ - static class AnnotationDataTest { - - public enum NumbersEN { - One, - Two; - } - - public enum NumbersDE { - Eins, - Zwei; - } - - public enum NumbersUA { - Odyn, - Dva; - } - - @Retention(RetentionPolicy.RUNTIME) - public @interface Annotation1 { - NumbersEN value() default NumbersEN.One; - } + private static final Method executableGetTypeAnnotationBytes = lookupMethod(Executable.class, "getTypeAnnotationBytes"); + private static final Field methodAnnotations = lookupField(Method.class, "annotations"); + private static final Field methodParameterAnnotations = lookupField(Method.class, "parameterAnnotations"); + private static final Field methodAnnotationDefault = lookupField(Method.class, "annotationDefault"); - @Retention(RetentionPolicy.RUNTIME) - public @interface Annotation2 { - NumbersDE value() default NumbersDE.Eins; - } - - @Retention(RetentionPolicy.RUNTIME) - public @interface Annotation3 { - NumbersUA value() default NumbersUA.Odyn; + @Test + public void getTypeAnnotationInfoTest() { + for (Method f : methods.keySet()) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(f); + byte[] rawAnnotations = invokeMethod(executableGetTypeAnnotationBytes, f); + TestResolvedJavaType.checkRawAnnotations(method, "getTypeAnnotationInfo", rawAnnotations, method.getTypeAnnotationInfo()); } + } - @Annotation1 - @Annotation2 - @Annotation3(NumbersUA.Dva) - static void methodWithThreeAnnotations() { - + @Test + public void getDeclaredAnnotationInfoTest() { + for (Method m : methods.keySet()) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + byte[] rawAnnotations = getFieldValue(methodAnnotations, m); + TestResolvedJavaType.checkRawAnnotations(method, "getDeclaredAnnotationInfo", rawAnnotations, method.getDeclaredAnnotationInfo()); } } @Test - public void getAnnotationDataTest() throws Exception { - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingAnnotation")); - try { - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingNestedAnnotation")); - throw new AssertionError("expected " + NoClassDefFoundError.class.getName()); - } catch (NoClassDefFoundError e) { - Assert.assertEquals("jdk/internal/vm/test/AnnotationTestInput$Missing", e.getMessage()); + public void getParameterAnnotationInfoTest() throws Exception { + for (Method m : methods.keySet()) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + byte[] rawAnnotations = getFieldValue(methodParameterAnnotations, m); + TestResolvedJavaType.checkRawAnnotations(method, "getParameterAnnotationInfo", rawAnnotations, method.getParameterAnnotationInfo()); } - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingTypeOfClassMember")); - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("missingMember")); - TestResolvedJavaType.getAnnotationDataTest(AnnotationTestInput.class.getDeclaredMethod("changeTypeOfMember")); + } + @Test + public void getAnnotationDefaultInfoTest() throws Exception { for (Method m : methods.keySet()) { - TestResolvedJavaType.getAnnotationDataTest(m); + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + byte[] rawAnnotations = getFieldValue(methodAnnotationDefault, m); + TestResolvedJavaType.checkRawAnnotations(method, "getAnnotationDefaultInfo", rawAnnotations, method.getAnnotationDefaultInfo()); } - - ResolvedJavaMethod m = metaAccess.lookupJavaMethod(AnnotationDataTest.class.getDeclaredMethod("methodWithThreeAnnotations")); - ResolvedJavaType a1 = metaAccess.lookupJavaType(Annotation1.class); - ResolvedJavaType a2 = metaAccess.lookupJavaType(Annotation2.class); - ResolvedJavaType a3 = metaAccess.lookupJavaType(Annotation3.class); - ResolvedJavaType a4 = metaAccess.lookupJavaType(AnnotationDataTest.class); - ResolvedJavaType numbersDEType = metaAccess.lookupJavaType(NumbersDE.class); - - // Ensure NumbersDE is not initialized before Annotation2 is requested - Assert.assertFalse(numbersDEType.isInitialized()); - Assert.assertEquals(2, m.getAnnotationData(a1, a3).size()); - - // Ensure NumbersDE is initialized after Annotation2 is requested - Assert.assertNotNull(m.getAnnotationData(a2)); - Assert.assertTrue(numbersDEType.isInitialized()); } private static ClassModel readClassfile(Class c) throws Exception { @@ -691,7 +643,7 @@ private static Map buildMethodMap(ResolvedJavaType t return methodMap; } - @Test + //@Test public void getOopMapAtTest() throws Exception { Collection> allClasses = new ArrayList<>(classes); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java new file mode 100644 index 00000000000..474b5412d71 --- /dev/null +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaRecordComponent.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires vm.jvmci + * @library ../../../../../ + * @modules jdk.internal.vm.ci/jdk.vm.ci.meta + * java.base/java.lang:open + * java.base/java.lang.reflect:open + * jdk.internal.vm.ci/jdk.vm.ci.meta.annotation + * jdk.internal.vm.ci/jdk.vm.ci.hotspot + * jdk.internal.vm.ci/jdk.vm.ci.runtime + * jdk.internal.vm.ci/jdk.vm.ci.common + * java.base/jdk.internal.reflect + * java.base/jdk.internal.misc + * java.base/jdk.internal.vm + * java.base/sun.reflect.annotation + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaRecordComponent + */ + +package jdk.vm.ci.runtime.test; + +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; +import jdk.vm.ci.meta.ResolvedJavaType; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.RecordComponent; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * Tests for {@link ResolvedJavaRecordComponent}. + */ +public class TestResolvedJavaRecordComponent extends FieldUniverse { + + @Test + public void equalsTest() { + for (ResolvedJavaRecordComponent f : recordComponents.values()) { + for (ResolvedJavaRecordComponent that : recordComponents.values()) { + boolean expect = f == that; + boolean actual = f.equals(that); + assertEquals(expect, actual); + } + } + } + + @Test + public void getDeclaringRecordTest() { + for (Map.Entry e : recordComponents.entrySet()) { + ResolvedJavaRecordComponent rc = e.getValue(); + ResolvedJavaType actual = rc.getDeclaringRecord(); + ResolvedJavaType expect = metaAccess.lookupJavaType(e.getKey().getDeclaringRecord()); + assertEquals(rc.toString(), expect, actual); + } + } + + @Test + public void getNameTest() { + for (Map.Entry e : recordComponents.entrySet()) { + ResolvedJavaRecordComponent rc = e.getValue(); + String actual = rc.getName(); + String expect = e.getKey().getName(); + assertEquals(rc.toString(), expect, actual); + } + } + + @Test + public void getAccessorTest() { + for (Map.Entry e : recordComponents.entrySet()) { + ResolvedJavaRecordComponent rc = e.getValue(); + Method expect = e.getKey().getAccessor(); + ResolvedJavaMethod actual = rc.getAccessor(); + assertEquals(rc.toString(), expect.getName(), actual.getName()); + } + } + + @Test + public void getTypeTest() { + for (Map.Entry e : recordComponents.entrySet()) { + ResolvedJavaRecordComponent rc = e.getValue(); + JavaType actual = rc.getType(); + JavaType expect = metaAccess.lookupJavaType(e.getKey().getType()).resolve(rc.getDeclaringRecord()); + assertEquals(expect, actual); + } + } + + @Test + public void getTypeAnnotationInfoTest() { + for (RecordComponent rc : recordComponents.keySet()) { + ResolvedJavaRecordComponent jrc = metaAccess.lookupJavaRecordComponent(rc); + byte[] rawAnnotations = getFieldValue(recordComponentTypeAnnotations, rc); + TestResolvedJavaType.checkRawAnnotations(jrc, "getTypeAnnotationInfo", rawAnnotations, jrc.getTypeAnnotationInfo()); + } + } + + @Test + public void getDeclaredAnnotationInfoTest() { + for (RecordComponent rc : recordComponents.keySet()) { + ResolvedJavaRecordComponent jrc = metaAccess.lookupJavaRecordComponent(rc); + byte[] rawAnnotations = getFieldValue(recordComponentAnnotations, rc); + TestResolvedJavaType.checkRawAnnotations(jrc, "getDeclaredAnnotationInfo", rawAnnotations, jrc.getDeclaredAnnotationInfo()); + } + } + + private static final Field recordComponentAnnotations = lookupField(RecordComponent.class, "annotations"); + private static final Field recordComponentTypeAnnotations = lookupField(RecordComponent.class, "typeAnnotations"); + +} diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index f67832407b8..8fb29fbb725 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -26,14 +26,10 @@ * @requires vm.jvmci * @library ../../../../../ * @library /testlibrary/asm - * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java - * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java - * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java - * @clean jdk.internal.vm.test.AnnotationTestInput$Missing - * @compile ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java - * ../../../../../../../../../../../jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java * @modules java.base/jdk.internal.reflect + * java.base/java.lang:open * jdk.internal.vm.ci/jdk.vm.ci.meta + * jdk.internal.vm.ci/jdk.vm.ci.meta.annotation * jdk.internal.vm.ci/jdk.vm.ci.hotspot * jdk.internal.vm.ci/jdk.vm.ci.runtime * jdk.internal.vm.ci/jdk.vm.ci.common @@ -45,21 +41,21 @@ package jdk.vm.ci.runtime.test; -import static java.lang.reflect.Modifier.isAbstract; -import static java.lang.reflect.Modifier.isFinal; -import static java.lang.reflect.Modifier.isPrivate; -import static java.lang.reflect.Modifier.isProtected; -import static java.lang.reflect.Modifier.isPublic; -import static java.lang.reflect.Modifier.isStatic; -import static jdk.vm.ci.meta.MetaUtil.internalNameToJava; -import static jdk.vm.ci.meta.MetaUtil.toInternalName; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import jdk.internal.reflect.ConstantPool; +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.meta.Assumptions.AssumptionResult; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; +import jdk.vm.ci.meta.annotation.AnnotationsInfo; +import org.junit.Assert; +import org.junit.Test; import java.io.DataInputStream; import java.io.IOException; @@ -67,45 +63,35 @@ import java.lang.annotation.Annotation; import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.AccessibleObject; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.RecordComponent; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.function.BiConsumer; -import java.util.function.Supplier; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.junit.Assert; -import org.junit.Test; - -import jdk.internal.reflect.ConstantPool; -import jdk.internal.vm.test.AnnotationTestInput; -import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.Annotated; -import jdk.vm.ci.meta.AnnotationData; -import jdk.vm.ci.meta.EnumData; -import jdk.vm.ci.meta.Assumptions.AssumptionResult; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.MetaUtil; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.UnresolvedJavaType; -import sun.reflect.annotation.AnnotationSupport; -import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import static java.lang.reflect.Modifier.isAbstract; +import static java.lang.reflect.Modifier.isPrivate; +import static java.lang.reflect.Modifier.isStatic; +import static jdk.vm.ci.meta.MetaUtil.internalNameToJava; +import static jdk.vm.ci.meta.MetaUtil.toInternalName; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * Tests for {@link ResolvedJavaType}. @@ -117,6 +103,26 @@ public class TestResolvedJavaType extends TypeUniverse { public TestResolvedJavaType() { } + /** + * Checks that {@code expect} and {@code actual} match in terms of nullness and + * in terms of {@code actual.bytes()}. + * + * @param element the annotated element + * @param operation the JVMCI method that returned {@code actual} + */ + static void checkRawAnnotations(Annotated element, String operation, byte[] expect, AnnotationsInfo actual) { + if (expect == null) { + if (actual != null) { + fail(String.format("%s[%s]: expect null, actual is not null", operation, element)); + } + } else if (actual == null) { + fail(String.format("%s[%s]: expect not null, actual is null", operation, element)); + } else { + byte[] bytes = actual.bytes(); + assertArrayEquals(String.format("%s[%s]", operation, element), expect, bytes); + } + } + @Test public void getMirrorTest() { for (ResolvedJavaType type : javaTypes) { @@ -208,6 +214,16 @@ public void isInstanceClassTest() { } } + @Test + public void isRecordTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + boolean expected = c.isRecord(); + boolean actual = type.isRecord(); + assertEquals(expected, actual); + } + } + @Test public void isArrayTest() { for (Class c : classes) { @@ -751,40 +767,6 @@ private void assertGetPermittedSubclasses(Class clazz) { } } - static class Declarations { - - final Method implementation; - final Set declarations; - - Declarations(Method impl) { - this.implementation = impl; - declarations = new HashSet<>(); - } - } - - /** - * See Method - * overriding. - */ - static boolean isOverriderOf(Method impl, Method m) { - if (!isPrivate(m.getModifiers()) && !isFinal(m.getModifiers())) { - if (m.getName().equals(impl.getName())) { - if (m.getReturnType() == impl.getReturnType()) { - if (Arrays.equals(m.getParameterTypes(), impl.getParameterTypes())) { - if (isPublic(m.getModifiers()) || isProtected(m.getModifiers())) { - // m is public or protected - return isPublic(impl.getModifiers()) || isProtected(impl.getModifiers()); - } else { - // m is package-private - return impl.getDeclaringClass().getPackage() == m.getDeclaringClass().getPackage(); - } - } - } - } - } - return false; - } - static final Map, VTable> vtables = new HashMap<>(); static class VTable { @@ -1095,6 +1077,27 @@ public void getDeclaredMethodsTest() { } } + @Test + public void getRecordComponentsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + RecordComponent[] raw = c.getRecordComponents(); + if (raw == null) { + assertFalse(type.isRecord()); + continue; + } + assertTrue(type.isRecord()); + Set expected = new HashSet<>(); + for (RecordComponent rc : raw) { + ResolvedJavaRecordComponent resolvedRecordComponent = metaAccess.lookupJavaRecordComponent(rc); + assertNotNull(resolvedRecordComponent); + expected.add(resolvedRecordComponent); + } + Set actual = new HashSet<>(type.getRecordComponents()); + assertEquals(expected, actual); + } + } + @Test public void getDeclaredConstructorsTest() { for (Class c : classes) { @@ -1304,38 +1307,37 @@ private Method findTestMethod(Method apiMethod) { return null; } + private static final Method classGetRawAnnotations = lookupMethod(Class.class, "getRawAnnotations"); + private static final Method classGetRawTypeAnnotations = lookupMethod(Class.class, "getRawTypeAnnotations"); + @Test - public void getAnnotationDataTest() throws Exception { - getAnnotationDataTest(AnnotationTestInput.AnnotatedClass.class); - getAnnotationDataTest(int.class); - getAnnotationDataTest(void.class); + public void getTypeAnnotationInfoTest() { + checkTypeAnnotationInfo(int.class); + checkTypeAnnotationInfo(void.class); for (Class c : classes) { - getAnnotationDataTest(c); + checkTypeAnnotationInfo(c); } + } - // Primitive classes have no annotations but we cannot directly - // test absence of annotations. Instead, just ensure empty answers - // are returned when looking up an arbitrary annotation type. - Class[] prims = {void.class, byte.class, int.class, double.class, float.class, short.class, char.class, long.class}; - ResolvedJavaType overrideType = metaAccess.lookupJavaType(Override.class); - for (Class c : prims) { - ResolvedJavaType type = metaAccess.lookupJavaType(c); - AnnotationData ad = type.getAnnotationData(overrideType); - Assert.assertNull(String.valueOf(ad), ad); - List adArray = type.getAnnotationData(overrideType, overrideType); - Assert.assertEquals(0, adArray.size()); + private static void checkTypeAnnotationInfo(Class cls) { + ResolvedJavaType rt = metaAccess.lookupJavaType(cls); + byte[] rawAnnotations = invokeMethod(classGetRawTypeAnnotations, cls); + checkRawAnnotations(rt, "getTypeAnnotationInfo", rawAnnotations, rt.getTypeAnnotationInfo()); + } + + @Test + public void getDeclaredAnnotationInfoTest() { + checkDeclaredAnnotationInfo(int.class); + checkDeclaredAnnotationInfo(void.class); + for (Class c : classes) { + checkDeclaredAnnotationInfo(c); } + } - // Test that inherited annotations are handled properly. - ResolvedJavaType namedType = metaAccess.lookupJavaType(AnnotationTestInput.Named.class); - AnnotationData ad = metaAccess.lookupJavaType(AnnotationTestInput.OwnName.class).getAnnotationData(namedType); - Assert.assertEquals("NonInheritedValue", ad.get("value", String.class)); - ad = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName1.class).getAnnotationData(namedType); - Assert.assertEquals("Super1", ad.get("value", String.class)); - ad = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName2.class).getAnnotationData(namedType); - Assert.assertEquals("Super2", ad.get("value", String.class)); - ad = metaAccess.lookupJavaType(AnnotationTestInput.InheritedName3.class).getAnnotationData(namedType); - Assert.assertEquals("Super1", ad.get("value", String.class)); + public static void checkDeclaredAnnotationInfo(Class clazz) { + Annotated type = metaAccess.lookupJavaType(clazz); + byte[] rawAnnotations = invokeMethod(classGetRawAnnotations, clazz); + checkRawAnnotations(type, "getDeclaredAnnotationInfo", rawAnnotations, type.getDeclaredAnnotationInfo()); } // @formatter:off @@ -1381,163 +1383,4 @@ public void testCoverage() { private static boolean isSignaturePolymorphic(ResolvedJavaMethod method) { return method.getAnnotation(SIGNATURE_POLYMORPHIC_CLASS) != null; } - - private static void getAnnotationDataExpectedToFail(Annotated annotated, ResolvedJavaType... annotationTypes) { - try { - if (annotationTypes.length == 1) { - annotated.getAnnotationData(annotationTypes[0]); - } else { - var tail = Arrays.copyOfRange(annotationTypes, 2, annotationTypes.length); - annotated.getAnnotationData(annotationTypes[0], annotationTypes[1], tail); - } - String s = Stream.of(annotationTypes).map(ResolvedJavaType::toJavaName).collect(Collectors.joining(", ")); - throw new AssertionError("Expected IllegalArgumentException for retrieving (" + s + " from " + annotated); - } catch (IllegalArgumentException iae) { - assertTrue(iae.getMessage(), iae.getMessage().contains("not an annotation interface")); - } - } - - /** - * Tests that {@link AnnotationData} obtained from a {@link Class}, {@link Method} or - * {@link Field} matches {@link AnnotatedElement#getAnnotations()} for the corresponding JVMCI - * object. - * - * @param annotatedElement a {@link Class}, {@link Method} or {@link Field} object - */ - public static void getAnnotationDataTest(AnnotatedElement annotatedElement) throws Exception { - Annotated annotated = toAnnotated(annotatedElement); - ResolvedJavaType objectType = metaAccess.lookupJavaType(Object.class); - ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); - getAnnotationDataExpectedToFail(annotated, objectType); - getAnnotationDataExpectedToFail(annotated, suppressWarningsType, objectType); - getAnnotationDataExpectedToFail(annotated, suppressWarningsType, suppressWarningsType, objectType); - - // Check that querying a missing annotation returns null or an empty list - assertNull(annotated.getAnnotationData(suppressWarningsType)); - List data = annotated.getAnnotationData(suppressWarningsType, suppressWarningsType); - assertTrue(data.toString(), data.isEmpty()); - data = annotated.getAnnotationData(suppressWarningsType, suppressWarningsType, suppressWarningsType, suppressWarningsType); - assertTrue(data.toString(), data.isEmpty()); - - testGetAnnotationData(annotatedElement, annotated, List.of(annotatedElement.getAnnotations())); - } - - private static void testGetAnnotationData(AnnotatedElement annotatedElement, Annotated annotated, List annotations) throws AssertionError { - ResolvedJavaType suppressWarningsType = metaAccess.lookupJavaType(SuppressWarnings.class); - for (Annotation a : annotations) { - var annotationType = metaAccess.lookupJavaType(a.annotationType()); - AnnotationData ad = annotated.getAnnotationData(annotationType); - assertAnnotationsEquals(a, ad); - - // Check that encoding/decoding produces a stable result - AnnotationData ad2 = annotated.getAnnotationData(annotationType); - assertEquals(ad, ad2); - - List annotationData = annotated.getAnnotationData(annotationType, suppressWarningsType, suppressWarningsType); - assertEquals(1, annotationData.size()); - } - if (annotations.size() < 2) { - return; - } - ResolvedJavaType type1 = metaAccess.lookupJavaType(annotations.get(0).annotationType()); - ResolvedJavaType type2 = metaAccess.lookupJavaType(annotations.get(1).annotationType()); - for (int i = 2; i < annotations.size(); i++) { - - ResolvedJavaType[] types = annotations.// - subList(2, i + 1).// - stream().map(a -> metaAccess.lookupJavaType(a.annotationType())).// - toArray(ResolvedJavaType[]::new); - List annotationData = annotated.getAnnotationData(type1, type2, types); - assertEquals(2 + types.length, annotationData.size()); - - for (int j = 0; j < annotationData.size(); j++) { - Annotation a = annotations.get(j); - AnnotationData ad = annotationData.get(j); - assertAnnotationsEquals(a, ad); - } - } - } - - private static Annotated toAnnotated(AnnotatedElement element) { - if (element instanceof Class t) { - return metaAccess.lookupJavaType(t); - } else if (element instanceof Method m) { - return metaAccess.lookupJavaMethod(m); - } else { - Field f = (Field) element; - return metaAccess.lookupJavaField(f); - } - } - - private static UnresolvedJavaType asType(Class valueType) { - return UnresolvedJavaType.create(MetaUtil.toInternalName(valueType.getName())); - } - - private static void assertAnnotationsEquals(Annotation a, AnnotationData ad) { - Map values = AnnotationSupport.memberValues(a); - for (Map.Entry e : values.entrySet()) { - String name = e.getKey(); - Object aValue = e.getValue(); - Object adValue; - try { - adValue = ad.get(name, Object.class); - } catch (IllegalArgumentException ex) { - assertEquals(aValue.toString(), ex.getMessage()); - continue; - } - try { - assertAnnotationElementsEqual(aValue, adValue); - } catch (ClassCastException ex) { - throw new AssertionError(a.getClass().getName() + "." + name + " has wrong type: " + adValue.getClass().getName(), ex); - } - } - } - - private static void assertAnnotationElementsEqual(Object aValue, Object adValue) { - Class valueType = aValue.getClass(); - if (valueType.isEnum()) { - assertEnumObjectsEquals(aValue, adValue); - } else if (aValue instanceof Class) { - assertClassObjectsEquals(aValue, adValue); - } else if (aValue instanceof Annotation) { - assertAnnotationObjectsEquals(aValue, adValue); - } else if (valueType.isArray()) { - List adList = (List) adValue; - int length = Array.getLength(aValue); - assertEquals(length, adList.size()); - for (int i = 0; i < length; i++) { - assertAnnotationElementsEqual(Array.get(aValue, i), adList.get(i)); - } - } else { - assertEquals(aValue.getClass(), adValue.getClass()); - assertEquals(aValue, adValue); - } - } - - private static void assertClassObjectsEquals(Object aValue, Object adValue) { - String aName = ((Class) aValue).getName(); - String adName = ((JavaType) adValue).toClassName(); - assertEquals(aName, adName); - } - - private static void assertEnumObjectsEquals(Object aValue, Object adValue) { - EnumData adEnum = (EnumData) adValue; - String adEnumName = adEnum.getName(); - String aEnumName = ((Enum) aValue).name(); - assertEquals(adEnumName, aEnumName); - } - - private static void assertAnnotationObjectsEquals(Object aValue, Object adValue) { - Annotation aAnnotation = (Annotation) aValue; - AnnotationData adAnnotation = (AnnotationData) adValue; - assertAnnotationsEquals(aAnnotation, adAnnotation); - } - - private static void assertArraysEqual(Object aValue, Object adValue, int length, BiConsumer assertEqualty) { - Object[] aArray = (Object[]) aValue; - Object[] adArray = (Object[]) adValue; - for (int i = 0; i < length; i++) { - assertEqualty.accept(aArray[i], adArray[i]); - } - } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java index 28ba77fa6b0..92ba906555c 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java @@ -22,12 +22,24 @@ */ package jdk.vm.ci.runtime.test; -import static java.lang.reflect.Modifier.isFinal; -import static java.lang.reflect.Modifier.isStatic; +import jdk.internal.misc.ScopedMemoryAccess; +import jdk.internal.misc.Unsafe; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.runtime.JVMCI; +import org.junit.Test; import java.io.Serializable; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.AbstractCollection; import java.util.AbstractList; @@ -48,16 +60,8 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -import org.junit.Test; - -import jdk.internal.misc.Unsafe; -import jdk.internal.misc.ScopedMemoryAccess; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.runtime.JVMCI; +import static java.lang.reflect.Modifier.isFinal; +import static java.lang.reflect.Modifier.isStatic; /** * Context for type related tests. @@ -76,8 +80,25 @@ public class TypeUniverse { private static List constants; - public class InnerClass { + // Define a type-use annotation + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + @interface TypeQualifier { + String comment() default ""; + int id() default -1; + } + // Define a parameter annotation + @Target(ElementType.PARAMETER) + @Retention(RetentionPolicy.RUNTIME) + @interface ParameterQualifier { + String value() default ""; + int tag() default -1; + } + + public class InnerClass { + public class InnerInnerClass { + } } public static class InnerStaticClass { @@ -208,6 +229,28 @@ public static List readConstants(Class fromClass) { } } + // Annotates the class type String + public @TypeQualifier String[][] typeAnnotatedField1; + // Annotates the array type String[][] + public String @TypeQualifier [][] typeAnnotatedField2; + // Annotates the array type String[] + String[] @TypeQualifier [] typeAnnotatedField3; + + public @TypeQualifier(comment = "comment1", id = 42) TypeUniverse.InnerClass.InnerInnerClass typeAnnotatedField4; + public TypeUniverse.@TypeQualifier InnerClass.InnerInnerClass typeAnnotatedField5; + public TypeUniverse.InnerClass.@TypeQualifier(comment = "47", id = -10) InnerInnerClass typeAnnotatedField6; + + public @TypeQualifier(comment = "comment2", id = 52) TypeUniverse.InnerClass.InnerInnerClass typeAnnotatedMethod1() { return null; } + public TypeUniverse.@TypeQualifier InnerClass.InnerInnerClass typeAnnotatedMethod2() { return null; } + public TypeUniverse.InnerClass.@TypeQualifier(comment = "57", id = -20) InnerInnerClass typeAnnotatedMethod3() { return null; } + + public void annotatedParameters1( + @TypeQualifier(comment = "comment3", id = 62) TypeUniverse this, + @TypeQualifier(comment = "comment4", id = 72) @ParameterQualifier String annotatedParam1, + int notAnnotatedParam2, + @ParameterQualifier(value = "foo", tag = 123) Thread annotatedParam3) { + } + public synchronized Class getArrayClass(Class componentType) { Class arrayClass = arrayClasses.get(componentType); if (arrayClass == null) { @@ -232,6 +275,9 @@ private static void addClass(Class c) { for (Class sc : c.getInterfaces()) { addClass(sc); } + for (Class enclosing = c.getEnclosingClass(); enclosing != null; enclosing = enclosing.getEnclosingClass()) { + addClass(enclosing); + } for (Class dc : c.getDeclaredClasses()) { addClass(dc); } @@ -249,4 +295,68 @@ private static void addClass(Class c) { } } } + + public static Method lookupMethod(Class declaringClass, String methodName, Class... parameterTypes) { + try { + Method result = declaringClass.getDeclaredMethod(methodName, parameterTypes); + result.setAccessible(true); + return result; + } catch (ReflectiveOperationException | LinkageError cause) { + throw new AssertionError(cause); + } + } + + public static Field lookupField(Class declaringClass, String fieldName) { + try { + Field result = declaringClass.getDeclaredField(fieldName); + result.setAccessible(true); + return result; + } catch (ReflectiveOperationException | LinkageError cause) { + /* Try to get hidden field */ + try { + Method fieldGetDeclaredFields0 = lookupMethod(Class.class, "getDeclaredFields0", boolean.class); + Field[] allFields = (Field[]) fieldGetDeclaredFields0.invoke(declaringClass, false); + for (Field field : allFields) { + if (field.getName().equals(fieldName)) { + field.setAccessible(true); + return field; + } + } + } catch (ReflectiveOperationException e) { + // ignore + } + throw new AssertionError(cause); + } + } + + @SuppressWarnings("unchecked") + public static RuntimeException rethrow(Throwable ex) throws E { + throw (E) ex; + } + + @SuppressWarnings("unchecked") + public static T invokeMethod(Method method, Object receiver, Object... arguments) { + try { + method.setAccessible(true); + return (T) method.invoke(receiver, arguments); + } catch (InvocationTargetException ex) { + Throwable cause = ex.getCause(); + if (cause != null) { + throw rethrow(cause); + } + throw new AssertionError(ex); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + @SuppressWarnings("unchecked") + public static T getFieldValue(Field field, Object receiver) { + field.setAccessible(true); + try { + return (T) field.get(receiver); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } } diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java deleted file mode 100644 index 446fb891ac4..00000000000 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/AnnotationTestInput.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.vm.test; - -import java.lang.annotation.Annotation; -import java.lang.annotation.Inherited; -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -public class AnnotationTestInput { - - enum Mood { - HAPPY, - SAD, - CONFUSED; - } - - private class PrivateClass {} - - @Single(string = "a", - stringArray = {"a", "b"}, - classValue = String.class, - classArray = {String.class, Exception.class}, - byteValue = 1, - byteArray = {1, 2, Byte.MIN_VALUE, Byte.MAX_VALUE}, - charValue = 'a', - charArray = {'a', 'b', - Character.MIN_VALUE, Character.MAX_VALUE, - '\b', '\f', '\n', '\r', '\t', '\\', '\'', '\"', '\u012A'}, - doubleValue = 3.3D, - doubleArray = {3.3D, 4.4D, - Double.MIN_VALUE, Double.MAX_VALUE, - Double.NaN, - Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}, - floatValue = 4.4F, - floatArray = {4.4F, 5.5F, - Float.MIN_VALUE, Float.MAX_VALUE, - Float.NaN, - Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY}, - intValue = 5, - intArray = {5, 6, Integer.MIN_VALUE, Integer.MAX_VALUE}, - longValue = 6L, - longArray = {6L, 7L, Long.MIN_VALUE, Long.MAX_VALUE}, - shortValue = 7, - shortArray = {7, 8, Short.MIN_VALUE, Short.MAX_VALUE}, - booleanValue = true, - booleanArray = {true, false}, - mood = Mood.SAD, - moodArray = {Mood.CONFUSED, Mood.HAPPY}, - nested = @NestedAnno("nested1"), - nestedArray = {@NestedAnno("nested2"), @NestedAnno("nested3")}) - @Single(string = "A", - stringArray = {"A", "B"}, - classValue = Thread.class, - classArray = {Thread.class, PrivateClass.class}, - byteValue = -1, - byteArray = {-1, -2}, - charValue = 'A', - charArray = {'a', 'b'}, - doubleValue = -3.3D, - doubleArray = {3.3D, 4.4D}, - floatValue = -4.4F, - floatArray = {4.4F, 5.5F}, - intValue = -5, - intArray = {5, 6}, - longValue = -6L, - longArray = {6L, 7L}, - shortValue = -7, - shortArray = {7, 8}, - booleanValue = true, - booleanArray = {true, false}, - mood = Mood.CONFUSED, - moodArray = {Mood.SAD, Mood.CONFUSED}, - nested = @NestedAnno("nested4"), - nestedArray = {@NestedAnno("nested5"), @NestedAnno("nested6")}) - @SingleWithDefaults - @Deprecated - @SuppressWarnings("unchecked") - public void annotatedMethod() { - } - - @Named("Super1") - public static class Super1 {} - @Named("Super2") - public static class Super2 extends Super1 {} - public static class Super3 extends Super1 {} - - @Named("NonInheritedValue") - public static class OwnName extends Super1 {} - - public static class InheritedName1 extends Super1 {} - public static class InheritedName2 extends Super2 {} - public static class InheritedName3 extends Super3 {} - - @Named("AnnotatedClass") - @Single(string = "a", - stringArray = {"a", "b"}, - classValue = String.class, - classArray = {String.class, Exception.class}, - byteValue = 1, - byteArray = {1, 2, Byte.MIN_VALUE, Byte.MAX_VALUE}, - charValue = 'a', - charArray = {'a', 'b', - Character.MIN_VALUE, Character.MAX_VALUE, - '\b', '\f', '\n', '\r', '\t', '\\', '\'', '\"', '\u012A'}, - doubleValue = 3.3D, - doubleArray = {3.3D, 4.4D, - Double.MIN_VALUE, Double.MAX_VALUE, - Double.NaN, - Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}, - floatValue = 4.4F, - floatArray = {4.4F, 5.5F, - Float.MIN_VALUE, Float.MAX_VALUE, - Float.NaN, - Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY}, - intValue = 5, - intArray = {5, 6, Integer.MIN_VALUE, Integer.MAX_VALUE}, - longValue = 6L, - longArray = {6L, 7L, Long.MIN_VALUE, Long.MAX_VALUE}, - shortValue = 7, - shortArray = {7, 8, Short.MIN_VALUE, Short.MAX_VALUE}, - booleanValue = true, - booleanArray = {true, false}, - mood = Mood.SAD, - moodArray = {Mood.CONFUSED, Mood.HAPPY}, - nested = @NestedAnno("nested7"), - nestedArray = {@NestedAnno("nested8"), @NestedAnno("nested9")}) - @Single(string = "A", - stringArray = {"A", "B"}, - classValue = Thread.class, - classArray = {Thread.class, PrivateClass.class}, - byteValue = -1, - byteArray = {-1, -2}, - charValue = 'A', - charArray = {'a', 'b'}, - doubleValue = -3.3D, - doubleArray = {3.3D, 4.4D}, - floatValue = -4.4F, - floatArray = {4.4F, 5.5F}, - intValue = -5, - intArray = {5, 6}, - longValue = -6L, - longArray = {6L, 7L}, - shortValue = -7, - shortArray = {7, 8}, - booleanValue = true, - booleanArray = {true, false}, - mood = Mood.CONFUSED, - moodArray = {Mood.SAD, Mood.CONFUSED}, - nested = @NestedAnno("nested10"), - nestedArray = {@NestedAnno("nested11"), @NestedAnno("nested12")}) - @Deprecated - @SuppressWarnings({"rawtypes", "all"}) - public static class AnnotatedClass {} - - @Single(string = "a", - stringArray = {"a", "b"}, - classValue = String.class, - classArray = {String.class, Exception.class}, - byteValue = 1, - byteArray = {1, 2, Byte.MIN_VALUE, Byte.MAX_VALUE}, - charValue = 'a', - charArray = {'a', 'b', - Character.MIN_VALUE, Character.MAX_VALUE, - '\b', '\f', '\n', '\r', '\t', '\\', '\'', '\"', '\u012A'}, - doubleValue = 3.3D, - doubleArray = {3.3D, 4.4D, - Double.MIN_VALUE, Double.MAX_VALUE, - Double.NaN, - Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}, - floatValue = 4.4F, - floatArray = {4.4F, 5.5F, - Float.MIN_VALUE, Float.MAX_VALUE, - Float.NaN, - Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY}, - intValue = 5, - intArray = {5, 6, Integer.MIN_VALUE, Integer.MAX_VALUE}, - longValue = 6L, - longArray = {6L, 7L, Long.MIN_VALUE, Long.MAX_VALUE}, - shortValue = 7, - shortArray = {7, 8, Short.MIN_VALUE, Short.MAX_VALUE}, - booleanValue = true, - booleanArray = {true, false}, - mood = Mood.SAD, - moodArray = {Mood.CONFUSED, Mood.HAPPY}, - nested = @NestedAnno("nested12"), - nestedArray = {@NestedAnno("nested13"), @NestedAnno("nested14")}) - @Single(string = "A", - stringArray = {"A", "B"}, - classValue = Thread.class, - classArray = {Thread.class, PrivateClass.class}, - byteValue = -1, - byteArray = {-1, -2}, - charValue = 'A', - charArray = {'a', 'b'}, - doubleValue = -3.3D, - doubleArray = {3.3D, 4.4D}, - floatValue = -4.4F, - floatArray = {4.4F, 5.5F}, - intValue = -5, - intArray = {5, 6}, - longValue = -6L, - longArray = {6L, 7L}, - shortValue = -7, - shortArray = {7, 8}, - booleanValue = true, - booleanArray = {true, false}, - mood = Mood.CONFUSED, - moodArray = {Mood.SAD, Mood.CONFUSED}, - nested = @NestedAnno("nested15"), - nestedArray = {@NestedAnno("nested16"), @NestedAnno("nested17")}) - private static final int annotatedField = 45; - - @Retention(RetentionPolicy.RUNTIME) - public @interface NestedAnno { - String value(); - } - - @Inherited - @Retention(RetentionPolicy.RUNTIME) - public @interface Named { - String value(); - } - - @Retention(RetentionPolicy.RUNTIME) - @Repeatable(SingleList.class) - public @interface Single { - Class classValue(); - Class[] classArray(); - - String string(); - String[] stringArray(); - - byte byteValue(); - byte[] byteArray(); - - char charValue(); - char[] charArray(); - - double doubleValue(); - double[] doubleArray(); - - float floatValue(); - float[] floatArray(); - - int intValue(); - int[] intArray(); - - long longValue(); - long[] longArray(); - - short shortValue(); - short[] shortArray(); - - boolean booleanValue(); - boolean[] booleanArray(); - - Mood mood(); - Mood[] moodArray(); - - NestedAnno nested(); - NestedAnno[] nestedArray(); - } - - @Retention(RetentionPolicy.RUNTIME) - @interface SingleWithDefaults { - Class classValue() default SingleWithDefaults.class; - Class[] classArray() default {}; - - String string() default "anonymous"; - String[] stringArray() default {}; - - byte byteValue() default 101; - byte[] byteArray() default {}; - - char charValue() default 'Z'; - char[] charArray() default {}; - - double doubleValue() default 102.102D; - double[] doubleArray() default {}; - - float floatValue() default 103.103F; - float[] floatArray() default {}; - - int intValue() default 104; - int[] intArray() default {}; - - long longValue() default 105L; - long[] longArray() default {}; - - short shortValue() default 105; - short[] shortArray() default {}; - - boolean booleanValue() default true; - boolean[] booleanArray() default {}; - - Mood mood() default Mood.HAPPY; - Mood[] moodArray() default {}; - } - - @Retention(RetentionPolicy.RUNTIME) - public @interface SingleList { - Single[] value(); - } - - @Retention(RetentionPolicy.RUNTIME) - public @interface Missing {} - - @Retention(RetentionPolicy.RUNTIME) - public @interface MissingWrapper { - Missing value(); - } - - @Retention(RetentionPolicy.RUNTIME) - public @interface MissingContainer { - Class value(); - } - - /** - * Method with a directly missing annotation. - */ - @Missing - public void missingAnnotation() {} - - /** - * Method with an indirectly missing nested annotation. - */ - @MissingWrapper(@Missing) - public void missingNestedAnnotation() {} - - /** - * Method with an annotation that has a Class member - * that cannot be resolved. - */ - @MissingContainer(Missing.class) - public void missingTypeOfClassMember() {} - - /** - * Method with an annotation that has a member - * that is deleted in a newer version of the annotation. - */ - @MemberDeleted(value = "evolving", retained = -34, deleted = 56) - public void missingMember() {} - - /** - * Method with an annotation that has a member named "any" - * whose type is changed from int to String in a newer version - * of the annotation. - */ - @MemberTypeChanged(value = "evolving", retained = -34, any = 56) - public void changeTypeOfMember() {} - -} - diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java deleted file mode 100644 index 2707886b4c7..00000000000 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberDeleted.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.vm.test; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.RUNTIME) -public @interface MemberDeleted { - String value(); - int retained(); - int deleted(); -} diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java deleted file mode 100644 index 99670e63b9a..00000000000 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/MemberTypeChanged.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.vm.test; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.RUNTIME) -public @interface MemberTypeChanged { - String value(); - int retained(); - int any(); -} diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java deleted file mode 100644 index 64e559a5713..00000000000 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/TestAnnotationEncodingDecoding.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @compile AnnotationTestInput.java MemberDeleted.java MemberTypeChanged.java - * @modules java.base/jdk.internal.vm - * java.base/sun.reflect.annotation - * @clean jdk.internal.vm.test.AnnotationTestInput$Missing - * @compile alt/MemberDeleted.java alt/MemberTypeChanged.java - * @run testng/othervm - * jdk.internal.vm.test.TestAnnotationEncodingDecoding - */ -package jdk.internal.vm.test; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.util.LinkedHashMap; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.TreeMap; - -import org.testng.Assert; -import org.testng.annotations.Test; - -import sun.reflect.annotation.AnnotationSupport; -import sun.reflect.annotation.AnnotationParser; -import sun.reflect.annotation.ExceptionProxy; - -import jdk.internal.vm.VMSupport; -import jdk.internal.vm.VMSupport.AnnotationDecoder; - -public class TestAnnotationEncodingDecoding { - - @Test - public void encodeDecodeTest() throws Exception { - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredField("annotatedField")); - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("annotatedMethod")); - checkDecodedEqualsEncoded(AnnotationTestInput.AnnotatedClass.class); - - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingAnnotation")); - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingNestedAnnotation"), true); - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingTypeOfClassMember"), false); - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("missingMember")); - checkDecodedEqualsEncoded(AnnotationTestInput.class.getDeclaredMethod("changeTypeOfMember"), false); - } - - private void checkDecodedEqualsEncoded(AnnotatedElement annotated) { - checkDecodedEqualsEncoded(annotated, false); - } - - private void checkDecodedEqualsEncoded(AnnotatedElement annotated, boolean expectNCDFE) { - Annotation[] annotations = getAnnotations(annotated, expectNCDFE); - if (annotations == null) { - return; - } - - byte[] encoded = VMSupport.encodeAnnotations(List.of(annotations)); - MyDecoder decoder = new MyDecoder(); - List decoded = VMSupport.decodeAnnotations(encoded, decoder); - int i = 0; - for (AnnotationConst actual : decoded) { - AnnotationConst expect = new AnnotationConst(annotations[i]); - checkEquals(actual, expect); - checkEquals(actual.toString(), expect.toString()); - i++; - } - } - - private static Annotation[] getAnnotations(AnnotatedElement annotated, boolean expectNCDFE) throws AssertionError { - try { - Annotation[] annotations = annotated.getAnnotations(); - Assert.assertFalse(expectNCDFE, annotated.toString()); - return annotations; - } catch (NoClassDefFoundError e) { - if (!expectNCDFE) { - throw new AssertionError(annotated.toString(), e); - } - return null; - } - } - - private static void checkEquals(Object actual, Object expect) { - if (!actual.equals(expect)) { - throw new AssertionError(String.format("actual != expect%nactual: %s%n%nexpect: %s", actual, expect)); - } - } - - public static final class AnnotationConst { - final Class type; - final Map elements; - - AnnotationConst(Class type, Map.Entry[] elements) { - this.type = type; - this.elements = Map.ofEntries(elements); - } - - AnnotationConst(Annotation a) { - Map values = AnnotationSupport.memberValues(a); - this.type = a.annotationType(); - Map.Entry[] elements = new Map.Entry[values.size()]; - int i = 0; - for (Map.Entry e : values.entrySet()) { - elements[i++] = Map.entry(e.getKey(), decodeValue(e.getValue())); - } - this.elements = Map.ofEntries(elements); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof AnnotationConst) { - AnnotationConst that = (AnnotationConst) obj; - return this.type.equals(that.type) && - this.elements.equals(that.elements); - } - return false; - } - - @Override - public String toString() { - return "@" + type.getName() + "(" + elements + ")"; - } - - private Object decodeValue(Object value) { - Class valueType = value.getClass(); - if (value instanceof Enum) { - return new EnumConst(valueType, ((Enum) value).name()); - } else if (value instanceof Annotation) { - return new AnnotationConst((Annotation) value); - } else if (valueType.isArray()) { - int len = Array.getLength(value); - Object[] arr = new Object[len]; - for (int i = 0; i < len; i++) { - arr[i] = decodeValue(Array.get(value, i)); - } - return List.of(arr); - } else if (value instanceof ExceptionProxy) { - return new ErrorConst(value.toString()); - } else { - return value; - } - } - - public Class getType() { - return type; - } - } - - public static final class ErrorConst { - final String desc; - public ErrorConst(String desc) { - this.desc = Objects.requireNonNull(desc); - } - - @Override - public String toString() { - return desc; - } - - @Override - public int hashCode() { - return desc.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ErrorConst) { - return ((ErrorConst) obj).desc.equals(desc); - } - return false; - } - } - - public static final class EnumConst { - final Class type; - final String name; - - public EnumConst(Class type, String name) { - this.type = type; - this.name = name; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof EnumConst) { - EnumConst that = (EnumConst) obj; - return this.type.equals(that.type) && - this.name.equals(that.name); - } - return false; - } - - @Override - public String toString() { - return type.getName() + "." + name; - } - - public Class getEnumType() { - return type; - } - - public String getName() { - return name; - } - } - - static class MyDecoder implements AnnotationDecoder, AnnotationConst, EnumConst, ErrorConst> { - @Override - public Class resolveType(String name) { - try { - return Class.forName(name); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - - @Override - public AnnotationConst newAnnotation(Class type, Map.Entry[] elements) { - return new AnnotationConst(type, elements); - } - - @Override - public EnumConst newEnumValue(Class enumType, String name) { - return new EnumConst(enumType, name); - } - - @Override - public ErrorConst newErrorValue(String description) { - return new ErrorConst(description); - } - } -} diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java deleted file mode 100644 index c27eca83229..00000000000 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberDeleted.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.vm.test; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.RUNTIME) -public @interface MemberDeleted { - String value(); - int retained(); -} diff --git a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java b/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java deleted file mode 100644 index b0518582166..00000000000 --- a/test/jdk/jdk/internal/vm/AnnotationEncodingDecoding/alt/MemberTypeChanged.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.vm.test; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.RUNTIME) -public @interface MemberTypeChanged { - String value(); - int retained(); - String any(); -} From 0c957526464b354afc5db63fc75e200b835ed8f4 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 23 Sep 2025 22:02:27 +0200 Subject: [PATCH 4/5] applied some IntelliJ suggestions --- .../vm/ci/hotspot/HotSpotJVMCIRuntime.java | 187 +++++++----------- .../ci/hotspot/HotSpotMetaAccessProvider.java | 81 +++----- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 2 +- .../HotSpotResolvedJavaMethodImpl.java | 9 +- .../HotSpotResolvedObjectTypeImpl.java | 85 +++----- .../hotspot/HotSpotResolvedPrimitiveType.java | 3 +- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 10 +- 7 files changed, 133 insertions(+), 244 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index a4d1190d161..30d163e44dc 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -25,7 +25,6 @@ import static jdk.vm.ci.common.InitTimer.timer; import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; -import java.io.IOException; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.io.PrintStream; @@ -90,7 +89,6 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime { private HotSpotResolvedObjectTypeImpl constantCallSiteType; private HotSpotResolvedObjectTypeImpl callSiteType; private HotSpotResolvedObjectTypeImpl javaLangString; - private HotSpotResolvedObjectTypeImpl javaLangClass; private HotSpotResolvedObjectTypeImpl throwableType; private HotSpotResolvedObjectTypeImpl serializableType; private HotSpotResolvedObjectTypeImpl cloneableType; @@ -118,13 +116,6 @@ HotSpotResolvedObjectTypeImpl getJavaLangString() { return javaLangString; } - HotSpotResolvedObjectTypeImpl getJavaLangClass() { - if (javaLangClass == null) { - javaLangClass = (HotSpotResolvedObjectTypeImpl) fromClass(Class.class); - } - return javaLangClass; - } - HotSpotResolvedObjectTypeImpl getJavaLangCloneable() { if (cloneableType == null) { cloneableType = (HotSpotResolvedObjectTypeImpl) fromClass(Cloneable.class); @@ -188,7 +179,7 @@ public static HotSpotJVMCIRuntime runtime() { synchronized (JVMCI.class) { result = instance; if (result == null) { - try (InitTimer t = timer("HotSpotJVMCIRuntime.")) { + try (InitTimer _ = timer("HotSpotJVMCIRuntime.")) { instance = result = new HotSpotJVMCIRuntime(); // Can only do eager initialization of the JVMCI compiler @@ -426,8 +417,6 @@ static float stringSimiliarity(String str1, String str2) { /** * Parses all system properties starting with {@value #JVMCI_OPTION_PROPERTY_PREFIX} and * initializes the options based on their values. - * - * @param runtime */ static void parse(HotSpotJVMCIRuntime runtime) { Map savedProps = jdk.vm.ci.services.Services.getSavedProperties(); @@ -452,9 +441,8 @@ static void parse(HotSpotJVMCIRuntime runtime) { } } msg.format("%nError: A fatal exception has occurred. Program will exit.%n"); - runtime.exitHotSpotWithMessage(1, msg.toString()); - } else if (value instanceof Option) { - Option option = (Option) value; + throw runtime.exitHotSpotWithMessage(1, msg.toString()); + } else if (value instanceof Option option) { option.init(e.getValue()); } } @@ -491,15 +479,15 @@ public static JavaKind getHostWordKind() { return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind; } - protected final CompilerToVM compilerToVm; + final CompilerToVM compilerToVm; - protected final HotSpotVMConfigStore configStore; - protected final HotSpotVMConfig config; + final HotSpotVMConfigStore configStore; + final HotSpotVMConfig config; private final JVMCIBackend hostBackend; private final JVMCICompilerFactory compilerFactory; private volatile JVMCICompiler compiler; - protected final HotSpotJVMCIReflection reflection; + final HotSpotJVMCIReflection reflection; private volatile boolean creatingCompiler; @@ -571,7 +559,7 @@ public KlassWeakReference(Long klassPointer, HotSpotResolvedObjectTypeImpl refer private HotSpotJVMCIRuntime() { compilerToVm = new CompilerToVM(); - try (InitTimer t = timer("HotSpotVMConfig")) { + try (InitTimer _ = timer("HotSpotVMConfig")) { configStore = new HotSpotVMConfigStore(compilerToVm); config = new HotSpotVMConfig(configStore); } @@ -589,7 +577,7 @@ private HotSpotJVMCIRuntime() { // Initialize the Option values. Option.parse(this); - try (InitTimer t = timer("create JVMCI backend:", backendFactory.getArchitecture())) { + try (InitTimer _ = timer("create JVMCI backend:", backendFactory.getArchitecture())) { hostBackend = registerBackend(backendFactory.createJVMCIBackend(this, null)); } @@ -744,11 +732,11 @@ public HotSpotVMConfigStore getConfigStore() { return configStore; } - public HotSpotVMConfig getConfig() { + HotSpotVMConfig getConfig() { return config; } - public CompilerToVM getCompilerToVM() { + CompilerToVM getCompilerToVM() { return compilerToVm; } @@ -764,15 +752,11 @@ HotSpotJVMCIReflection getReflection() { * compiler. */ public Predicate getIntrinsificationTrustPredicate(Class... compilerLeafClasses) { - return new Predicate<>() { - @Override - public boolean test(ResolvedJavaType type) { - if (type instanceof HotSpotResolvedObjectTypeImpl) { - HotSpotResolvedObjectTypeImpl hsType = (HotSpotResolvedObjectTypeImpl) type; - return compilerToVm.isTrustedForIntrinsics(hsType); - } else { - return false; - } + return type -> { + if (type instanceof HotSpotResolvedObjectTypeImpl hsType) { + return compilerToVm.isTrustedForIntrinsics(hsType); + } else { + return false; } }; } @@ -822,23 +806,18 @@ public Field getMirror(ResolvedJavaField field) { return null; } - static class ErrorCreatingCompiler implements JVMCICompiler { - private final RuntimeException t; - - ErrorCreatingCompiler(RuntimeException t) { - this.t = t; - } + record ErrorCreatingCompiler(RuntimeException t) implements JVMCICompiler { @Override public CompilationRequestResult compileMethod(CompilationRequest request) { - throw t; - } + throw t; + } @Override public boolean isGCSupported(int gcIdentifier) { - return false; + return false; + } } - } @Override public JVMCICompiler getCompiler() { @@ -867,7 +846,7 @@ public JVMCICompiler getCompiler() { * Converts a name to a Java type. This method attempts to resolve {@code name} to a * {@link ResolvedJavaType}. * - * @param name a well formed Java type in {@linkplain JavaType#getName() internal} format + * @param name a well-formed Java type in {@linkplain JavaType#getName() internal} format * @param accessingType the context of resolution which must be non-null * @param resolve specifies whether resolution failure results in an unresolved type being * return or a {@link LinkageError} being thrown @@ -913,7 +892,7 @@ JavaType lookupTypeInternal(String name, HotSpotResolvedObjectType accessingType final HotSpotResolvedJavaType klass = compilerToVm.lookupType(name, hsAccessingType, resolve); if (klass == null) { - assert resolve == false : name; + assert !resolve : name; return UnresolvedJavaType.create(name); } return klass; @@ -994,7 +973,7 @@ private boolean isIntrinsicSupported(int intrinsicIdentifier) { * Shuts down the runtime. */ @VMEntryPoint - private void shutdown() throws Exception { + private void shutdown() { if (isShutdown.compareAndSet(false, true)) { // Cleaners are normally only processed when a new Cleaner is // instantiated so process all remaining cleaners now. @@ -1010,18 +989,14 @@ private void shutdown() throws Exception { * Notify on completion of a bootstrap. */ @VMEntryPoint - private void bootstrapFinished() throws Exception { + private void bootstrapFinished() { for (HotSpotVMEventListener vmEventListener : vmEventListeners) { vmEventListener.notifyBootstrapFinished(); } } /** - * Notify on successful install into the CodeCache. - * - * @param hotSpotCodeCacheProvider - * @param installedCode - * @param compiledCode + * Notify on successful installation into the CodeCache. */ void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompiledCode compiledCode) { for (HotSpotVMEventListener vmEventListener : vmEventListeners) { @@ -1092,7 +1067,7 @@ public OutputStream getLogStream() { return new OutputStream() { @Override - public void write(byte[] b, int off, int len) throws IOException { + public void write(byte[] b, int off, int len) { if (b == null) { throw new NullPointerException(); } else if (off < 0 || off > b.length || len < 0 || (off + len) > b.length || (off + len) < 0) { @@ -1104,12 +1079,12 @@ public void write(byte[] b, int off, int len) throws IOException { } @Override - public void write(int b) throws IOException { + public void write(int b) { write(new byte[]{(byte) b}, 0, 1); } @Override - public void flush() throws IOException { + public void flush() { compilerToVm.flushDebugOutput(); } }; @@ -1135,7 +1110,6 @@ public int getCountersSize() { * Attempt to enlarge the number of per thread counters available. Requires a safepoint so * resizing should be rare to avoid performance effects. * - * @param newSize * @return false if the resizing failed */ public boolean setCountersSize(int newSize) { @@ -1148,28 +1122,18 @@ public boolean setCountersSize(int newSize) { * @return the offset in bytes */ public int getArrayBaseOffset(JavaKind kind) { - switch (kind) { - case Boolean: - return compilerToVm.ARRAY_BOOLEAN_BASE_OFFSET; - case Byte: - return compilerToVm.ARRAY_BYTE_BASE_OFFSET; - case Char: - return compilerToVm.ARRAY_CHAR_BASE_OFFSET; - case Short: - return compilerToVm.ARRAY_SHORT_BASE_OFFSET; - case Int: - return compilerToVm.ARRAY_INT_BASE_OFFSET; - case Long: - return compilerToVm.ARRAY_LONG_BASE_OFFSET; - case Float: - return compilerToVm.ARRAY_FLOAT_BASE_OFFSET; - case Double: - return compilerToVm.ARRAY_DOUBLE_BASE_OFFSET; - case Object: - return compilerToVm.ARRAY_OBJECT_BASE_OFFSET; - default: - throw new JVMCIError("%s", kind); - } + return switch (kind) { + case Boolean -> compilerToVm.ARRAY_BOOLEAN_BASE_OFFSET; + case Byte -> compilerToVm.ARRAY_BYTE_BASE_OFFSET; + case Char -> compilerToVm.ARRAY_CHAR_BASE_OFFSET; + case Short -> compilerToVm.ARRAY_SHORT_BASE_OFFSET; + case Int -> compilerToVm.ARRAY_INT_BASE_OFFSET; + case Long -> compilerToVm.ARRAY_LONG_BASE_OFFSET; + case Float -> compilerToVm.ARRAY_FLOAT_BASE_OFFSET; + case Double -> compilerToVm.ARRAY_DOUBLE_BASE_OFFSET; + case Object -> compilerToVm.ARRAY_OBJECT_BASE_OFFSET; + default -> throw new JVMCIError("%s", kind); + }; } @@ -1179,29 +1143,18 @@ public int getArrayBaseOffset(JavaKind kind) { * @return the scale in order to convert the index into a byte offset */ public int getArrayIndexScale(JavaKind kind) { - switch (kind) { - case Boolean: - return compilerToVm.ARRAY_BOOLEAN_INDEX_SCALE; - case Byte: - return compilerToVm.ARRAY_BYTE_INDEX_SCALE; - case Char: - return compilerToVm.ARRAY_CHAR_INDEX_SCALE; - case Short: - return compilerToVm.ARRAY_SHORT_INDEX_SCALE; - case Int: - return compilerToVm.ARRAY_INT_INDEX_SCALE; - case Long: - return compilerToVm.ARRAY_LONG_INDEX_SCALE; - case Float: - return compilerToVm.ARRAY_FLOAT_INDEX_SCALE; - case Double: - return compilerToVm.ARRAY_DOUBLE_INDEX_SCALE; - case Object: - return compilerToVm.ARRAY_OBJECT_INDEX_SCALE; - default: - throw new JVMCIError("%s", kind); - - } + return switch (kind) { + case Boolean -> compilerToVm.ARRAY_BOOLEAN_INDEX_SCALE; + case Byte -> compilerToVm.ARRAY_BYTE_INDEX_SCALE; + case Char -> compilerToVm.ARRAY_CHAR_INDEX_SCALE; + case Short -> compilerToVm.ARRAY_SHORT_INDEX_SCALE; + case Int -> compilerToVm.ARRAY_INT_INDEX_SCALE; + case Long -> compilerToVm.ARRAY_LONG_INDEX_SCALE; + case Float -> compilerToVm.ARRAY_FLOAT_INDEX_SCALE; + case Double -> compilerToVm.ARRAY_DOUBLE_INDEX_SCALE; + case Object -> compilerToVm.ARRAY_OBJECT_INDEX_SCALE; + default -> throw new JVMCIError("%s", kind); + }; } /** @@ -1334,22 +1287,26 @@ static void postTranslation(Object translatedObject) { String value = Option.ForceTranslateFailure.getString(); String toMatch; String type; - if (translatedObject instanceof HotSpotResolvedJavaMethodImpl) { - toMatch = ((HotSpotResolvedJavaMethodImpl) translatedObject).format("%H.%n"); - type = "method"; - } else if (translatedObject instanceof HotSpotResolvedObjectTypeImpl) { - toMatch = ((HotSpotResolvedObjectTypeImpl) translatedObject).toJavaName(); - type = "type"; - } else if (translatedObject instanceof HotSpotNmethod) { - HotSpotNmethod nmethod = (HotSpotNmethod) translatedObject; - if (nmethod.getMethod() != null) { - toMatch = nmethod.getMethod().format("%H.%n"); - } else { - toMatch = String.valueOf(nmethod.getName()); + switch (translatedObject) { + case HotSpotResolvedJavaMethodImpl hotSpotResolvedJavaMethod -> { + toMatch = hotSpotResolvedJavaMethod.format("%H.%n"); + type = "method"; + } + case HotSpotResolvedObjectTypeImpl hotSpotResolvedObjectType -> { + toMatch = hotSpotResolvedObjectType.toJavaName(); + type = "type"; + } + case HotSpotNmethod nmethod -> { + if (nmethod.getMethod() != null) { + toMatch = nmethod.getMethod().format("%H.%n"); + } else { + toMatch = String.valueOf(nmethod.getName()); + } + type = "nmethod"; + } + case null, default -> { + return; } - type = "nmethod"; - } else { - return; } String[] filters = value.split(","); for (String filter : filters) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java index 649f3fde260..41cc31736e3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java @@ -122,16 +122,14 @@ public JavaConstant encodeDeoptActionAndReason(DeoptimizationAction action, Deop public DeoptimizationReason decodeDeoptReason(JavaConstant constant) { HotSpotVMConfig config = runtime.getConfig(); int reasonValue = ((~constant.asInt()) >> config.deoptimizationReasonShift) & intMaskRight(config.deoptimizationReasonBits); - DeoptimizationReason reason = convertDeoptReason(reasonValue); - return reason; + return convertDeoptReason(reasonValue); } @Override public DeoptimizationAction decodeDeoptAction(JavaConstant constant) { HotSpotVMConfig config = runtime.getConfig(); int actionValue = ((~constant.asInt()) >> config.deoptimizationActionShift) & intMaskRight(config.deoptimizationActionBits); - DeoptimizationAction action = convertDeoptAction(actionValue); - return action; + return convertDeoptAction(actionValue); } @Override @@ -161,20 +159,13 @@ public Speculation decodeSpeculation(JavaConstant constant, SpeculationLog specu public int convertDeoptAction(DeoptimizationAction action) { HotSpotVMConfig config = runtime.getConfig(); - switch (action) { - case None: - return config.deoptActionNone; - case RecompileIfTooManyDeopts: - return config.deoptActionMaybeRecompile; - case InvalidateReprofile: - return config.deoptActionReinterpret; - case InvalidateRecompile: - return config.deoptActionMakeNotEntrant; - case InvalidateStopCompiling: - return config.deoptActionMakeNotCompilable; - default: - throw new JVMCIError("%s", action); - } + return switch (action) { + case None -> config.deoptActionNone; + case RecompileIfTooManyDeopts -> config.deoptActionMaybeRecompile; + case InvalidateReprofile -> config.deoptActionReinterpret; + case InvalidateRecompile -> config.deoptActionMakeNotEntrant; + case InvalidateStopCompiling -> config.deoptActionMakeNotCompilable; + }; } public DeoptimizationAction convertDeoptAction(int action) { @@ -199,42 +190,24 @@ public DeoptimizationAction convertDeoptAction(int action) { public int convertDeoptReason(DeoptimizationReason reason) { HotSpotVMConfig config = runtime.getConfig(); - switch (reason) { - case None: - return config.deoptReasonNone; - case NullCheckException: - return config.deoptReasonNullCheck; - case BoundsCheckException: - return config.deoptReasonRangeCheck; - case ClassCastException: - return config.deoptReasonClassCheck; - case ArrayStoreException: - return config.deoptReasonArrayCheck; - case UnreachedCode: - return config.deoptReasonUnreached0; - case TypeCheckedInliningViolated: - return config.deoptReasonTypeCheckInlining; - case OptimizedTypeCheckViolated: - return config.deoptReasonOptimizedTypeCheck; - case NotCompiledExceptionHandler: - return config.deoptReasonNotCompiledExceptionHandler; - case Unresolved: - return config.deoptReasonUnresolved; - case JavaSubroutineMismatch: - return config.deoptReasonJsrMismatch; - case ArithmeticException: - return config.deoptReasonDiv0Check; - case RuntimeConstraint: - return config.deoptReasonConstraint; - case LoopLimitCheck: - return config.deoptReasonLoopLimitCheck; - case Aliasing: - return config.deoptReasonAliasing; - case TransferToInterpreter: - return config.deoptReasonTransferToInterpreter; - default: - throw new JVMCIError("%s", reason); - } + return switch (reason) { + case None -> config.deoptReasonNone; + case NullCheckException -> config.deoptReasonNullCheck; + case BoundsCheckException -> config.deoptReasonRangeCheck; + case ClassCastException -> config.deoptReasonClassCheck; + case ArrayStoreException -> config.deoptReasonArrayCheck; + case UnreachedCode -> config.deoptReasonUnreached0; + case TypeCheckedInliningViolated -> config.deoptReasonTypeCheckInlining; + case OptimizedTypeCheckViolated -> config.deoptReasonOptimizedTypeCheck; + case NotCompiledExceptionHandler -> config.deoptReasonNotCompiledExceptionHandler; + case Unresolved -> config.deoptReasonUnresolved; + case JavaSubroutineMismatch -> config.deoptReasonJsrMismatch; + case ArithmeticException -> config.deoptReasonDiv0Check; + case RuntimeConstraint -> config.deoptReasonConstraint; + case LoopLimitCheck -> config.deoptReasonLoopLimitCheck; + case Aliasing -> config.deoptReasonAliasing; + case TransferToInterpreter -> config.deoptReasonTransferToInterpreter; + }; } public DeoptimizationReason convertDeoptReason(int reason) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 2bc6af55024..49a3773f1d4 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -155,7 +155,7 @@ public int getOffset() { } /** - * Gets the value of this field's index (i.e. {@code fieldDescriptor::index()} in the encoded + * Gets the value of this field's index (i.e. {@code fieldDescriptor::index()}) in the encoded * fields of the declaring class. */ int getIndex() { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 466db3dcdf8..893d25bc5f1 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -148,8 +148,7 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (obj instanceof HotSpotResolvedJavaMethodImpl) { - HotSpotResolvedJavaMethodImpl that = (HotSpotResolvedJavaMethodImpl) obj; + if (obj instanceof HotSpotResolvedJavaMethodImpl that) { return that.getMethodPointer() == getMethodPointer(); } return false; @@ -273,8 +272,7 @@ public ExceptionHandler[] getExceptionHandlers() { catchType = constantPool.lookupType(catchTypeIndex, opcode); // Check for Throwable which catches everything. - if (catchType instanceof HotSpotResolvedObjectTypeImpl) { - HotSpotResolvedObjectTypeImpl resolvedType = (HotSpotResolvedObjectTypeImpl) catchType; + if (catchType instanceof HotSpotResolvedObjectTypeImpl resolvedType) { if (resolvedType.equals(runtime().getJavaLangThrowable())) { catchTypeIndex = 0; catchType = null; @@ -690,8 +688,7 @@ public int vtableEntryOffset(ResolvedJavaType resolved) { @Override public boolean isInVirtualMethodTable(ResolvedJavaType resolved) { - if (resolved instanceof HotSpotResolvedObjectTypeImpl) { - HotSpotResolvedObjectTypeImpl hotspotResolved = (HotSpotResolvedObjectTypeImpl) resolved; + if (resolved instanceof HotSpotResolvedObjectTypeImpl hotspotResolved) { int vtableIndex = getVtableIndex(hotspotResolved); return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength(); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 57275fecd0d..41ec70cae9e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -60,7 +60,7 @@ /** * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. This class is not - * an {@link MetaspaceHandleObject} because it doesn't have to be scanned for GC. It's liveness is + * an {@link MetaspaceHandleObject} because it doesn't have to be scanned for GC. Its liveness is * maintained by a reference to the {@link Class} instance. */ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, MetaspaceObject { @@ -84,7 +84,7 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem /** * Lazily initialized cache for {@link #getComponentType()}. Set to {@code this}, if this has no - * component type (i.e., this is an non-array type). + * component type (i.e., this is a non-array type). */ private HotSpotResolvedJavaType componentType; @@ -134,7 +134,7 @@ private static HotSpotResolvedObjectTypeImpl fromMetaspace(long klassPointer) { // The mirror object must be in the global scope since // this object will be cached in HotSpotJVMCIRuntime.resolvedJavaTypes // and live across more than one compilation. - try (HotSpotObjectConstantScope global = HotSpotObjectConstantScope.enterGlobalScope()) { + try (HotSpotObjectConstantScope _ = HotSpotObjectConstantScope.enterGlobalScope()) { this.mirror = runtime().compilerToVm.getJavaMirror(this); assert getName().charAt(0) != '[' || isArray() : getName(); } @@ -272,8 +272,8 @@ public AssumptionResult findLeafConcreteSubtype() { } else if (isInterface()) { HotSpotResolvedObjectTypeImpl implementor = getSingleImplementor(); /* - * If the implementor field contains itself that indicates that the interface has more - * than one implementors (see: InstanceKlass::add_implementor). + * If the implementor field contains itself, it indicates that the interface has more + * than one implementor (see: InstanceKlass::add_implementor). */ if (implementor == null || implementor.equals(this)) { return null; @@ -455,17 +455,17 @@ public boolean isEnum() { @Override public boolean isInitialized() { - return isArray() ? true : getInitState() == config().instanceKlassStateFullyInitialized; + return isArray() || getInitState() == config().instanceKlassStateFullyInitialized; } @Override public boolean isBeingInitialized() { - return isArray() ? false : getInitState() == config().instanceKlassStateBeingInitialized; + return !isArray() && getInitState() == config().instanceKlassStateBeingInitialized; } @Override public boolean isLinked() { - return isArray() ? true : getInitState() >= config().instanceKlassStateLinked; + return isArray() || getInitState() >= config().instanceKlassStateLinked; } @Override @@ -529,8 +529,7 @@ public boolean isInterface() { @Override public boolean isAssignableFrom(ResolvedJavaType other) { assert other != null; - if (other instanceof HotSpotResolvedObjectTypeImpl) { - HotSpotResolvedObjectTypeImpl otherType = (HotSpotResolvedObjectTypeImpl) other; + if (other instanceof HotSpotResolvedObjectTypeImpl otherType) { return runtime().reflection.isAssignableFrom(this, otherType); } return false; @@ -729,10 +728,9 @@ public boolean equals(Object obj) { if (obj == this) { return true; } - if (!(obj instanceof HotSpotResolvedObjectTypeImpl)) { + if (!(obj instanceof HotSpotResolvedObjectTypeImpl that)) { return false; } - HotSpotResolvedObjectTypeImpl that = (HotSpotResolvedObjectTypeImpl) obj; return getKlassPointer() == that.getKlassPointer(); } @@ -749,46 +747,16 @@ protected HotSpotResolvedObjectTypeImpl getArrayType() { /** * This class represents the field information for one field contained in the fields array of an * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. + * + * @param nameIndex index of field's name in the constant pool + * @param signatureIndex index of field's signature in the constant pool + * @param offset field's offset + * @param classfileFlags field's access flags (from the class file) + * @param internalFlags field's internal flags (from the VM) + * @param initializerIndex field's initial value index in the constant pool */ - static class FieldInfo { - - private final int nameIndex; - private final int signatureIndex; - private final int offset; - private final int classfileFlags; - private final int internalFlags; - private final int initializerIndex; - - /** - * Creates a field info with the provided indices. - * - * @param nameIndex index of field's name in the constant pool - * @param signatureIndex index of field's signature in the constant pool - * @param offset field's offset - * @param classfileFlags field's access flags (from the class file) - * @param internalFlags field's internal flags (from the VM) - * @param initializerIndex field's initial value index in the constant pool - */ - FieldInfo(int nameIndex, int signatureIndex, int offset, int classfileFlags, int internalFlags, int initializerIndex) { - this.nameIndex = nameIndex; - this.signatureIndex = signatureIndex; - this.offset = offset; - this.classfileFlags = classfileFlags; - this.internalFlags = internalFlags; - this.initializerIndex = initializerIndex; - } - - int getClassfileFlags() { - return classfileFlags; - } - - int getInternalFlags() { - return internalFlags; - } - - public int getOffset() { - return offset; - } + record FieldInfo(int nameIndex, int signatureIndex, int offset, int classfileFlags, int internalFlags, + int initializerIndex) { /** * Returns the name of this field as a {@link String}. If the field is an internal field the @@ -828,11 +796,11 @@ public JavaType getType(HotSpotResolvedObjectTypeImpl klass) { } private boolean isInternal() { - return (getInternalFlags() & (1 << config().jvmFieldFlagInternalShift)) != 0; + return (internalFlags() & (1 << config().jvmFieldFlagInternalShift)) != 0; } public boolean isStatic() { - return Modifier.isStatic(getClassfileFlags()); + return Modifier.isStatic(classfileFlags()); } } @@ -910,7 +878,7 @@ public List getRecordComponents() { */ private HotSpotResolvedJavaField[] getFields(boolean retrieveStaticFields, HotSpotResolvedJavaField[] prepend) { int resultCount = 0; - int index = 0; + int index; for (index = 0; index < getFieldInfo().length; index++) { if (getFieldInfo(index).isStatic() == retrieveStaticFields) { @@ -937,8 +905,8 @@ private HotSpotResolvedJavaField[] getFields(boolean retrieveStaticFields, HotSp for (int i = 0; i < getFieldInfo().length; ++i) { FieldInfo field = getFieldInfo(i); if (field.isStatic() == retrieveStaticFields) { - int offset = field.getOffset(); - HotSpotResolvedJavaField resolvedJavaField = createField(field.getType(this), offset, field.getClassfileFlags(), field.getInternalFlags(), i); + int offset = field.offset(); + HotSpotResolvedJavaField resolvedJavaField = createField(field.getType(this), offset, field.classfileFlags(), field.internalFlags(), i); result[resultIndex++] = resolvedJavaField; } } @@ -1084,11 +1052,6 @@ public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expec return findFieldWithOffset(offset, expectedEntryKind, declaredFields); } - public ResolvedJavaField findStaticFieldWithOffset(long offset, JavaKind expectedEntryKind) { - ResolvedJavaField[] declaredFields = getStaticFields(); - return findFieldWithOffset(offset, expectedEntryKind, declaredFields); - } - private static ResolvedJavaField findFieldWithOffset(long offset, JavaKind expectedEntryKind, ResolvedJavaField[] declaredFields) { for (ResolvedJavaField field : declaredFields) { long resolvedFieldOffset = field.getOffset(); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index 43ed6980477..02d91f53a68 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -354,10 +354,9 @@ public boolean isCloneableWithAllocation() { @Override public boolean equals(Object obj) { - if (!(obj instanceof HotSpotResolvedPrimitiveType)) { + if (!(obj instanceof HotSpotResolvedPrimitiveType that)) { return false; } - HotSpotResolvedPrimitiveType that = (HotSpotResolvedPrimitiveType) obj; return that.kind == kind; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index df2c5651bb6..b358e7914d9 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -29,6 +29,8 @@ import jdk.internal.misc.Unsafe; import jdk.internal.util.Architecture; +import java.util.Objects; + /** * Used to access native configuration details. *

@@ -56,14 +58,12 @@ static HotSpotVMConfig config() { */ static String getHostArchitectureName() { Architecture arch = Architecture.current(); - switch (arch) { - case X64: return "amd64"; - default: return arch.name().toLowerCase(); + if (Objects.requireNonNull(arch) == Architecture.X64) { + return "amd64"; } + return arch.name().toLowerCase(); } - final boolean useDeferredInitBarriers = getFlag("ReduceInitialCardMarks", Boolean.class); - final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); final int objectAlignment = getFlag("ObjectAlignmentInBytes", Integer.class); From faecb268a3cee15c0df76894605354726fc6db5c Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 2 Oct 2025 11:53:02 +0200 Subject: [PATCH 5/5] mitigate cost of HotSpotMetaAccessProvider.lookupField for classes with many fields --- .../ci/hotspot/HotSpotMetaAccessProvider.java | 19 +---- .../HotSpotResolvedObjectTypeImpl.java | 72 +++++++++++++++++-- 2 files changed, 67 insertions(+), 24 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java index 41cc31736e3..3947c81bc78 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java @@ -82,23 +82,8 @@ public ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod) { @Override public ResolvedJavaField lookupJavaField(Field reflectionField) { Class fieldHolder = reflectionField.getDeclaringClass(); - HotSpotResolvedJavaType holder = runtime.fromClass(fieldHolder); - assert holder != null : fieldHolder; - ResolvedJavaField[] fields; - if (Modifier.isStatic(reflectionField.getModifiers())) { - fields = holder.getStaticFields(); - } else { - fields = holder.getInstanceFields(false); - } - ResolvedJavaType fieldType = lookupJavaType(reflectionField.getType()); - for (ResolvedJavaField field : fields) { - if (reflectionField.getName().equals(field.getName()) && field.getType().equals(fieldType)) { - assert Modifier.isStatic(reflectionField.getModifiers()) == field.isStatic(); - return field; - } - } - - throw new JVMCIError("unresolved field %s", reflectionField); + HotSpotResolvedObjectTypeImpl holder = (HotSpotResolvedObjectTypeImpl) runtime.fromClass(fieldHolder); + return holder.lookupField(reflectionField); } private static int intMaskRight(int n) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 41ec70cae9e..0d43dea419e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Assumptions.AssumptionResult; @@ -50,6 +51,7 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaRecordComponent; @@ -744,6 +746,51 @@ protected HotSpotResolvedObjectTypeImpl getArrayType() { return runtime().compilerToVm.getArrayType((char) 0, this); } + /** + * Map to mitigate exponential cost of {@link #lookupField} for classes with many fields. + */ + Map fieldInfoMap; + + /** + * Classes with more than this number of fields will use {@link #fieldInfoMap} + * in {@link #lookupField(Field)}. + */ + private static final int FIELD_INFO_MAP_THRESHOLD = 1024; + + /** + * Support for {@link HotSpotMetaAccessProvider#lookupJavaField(Field)}. + */ + HotSpotResolvedJavaField lookupField(Field reflectionField) { + FieldInfo[] fields = getFieldInfo(); + String name = reflectionField.getName(); + String sig = MetaUtil.toInternalName(reflectionField.getType().getName()); + boolean isStatic = Modifier.isStatic(reflectionField.getModifiers()); + FieldInfo.Key key = new FieldInfo.Key(name, sig, isStatic); + if (fields.length > FIELD_INFO_MAP_THRESHOLD) { + if (fieldInfoMap == null) { + Map map = new HashMap<>(fields.length); + for (int index = 0; index < fields.length; index++) { + FieldInfo fi = fields[index]; + map.put(FieldInfo.Key.from(fi, this), index); + } + fieldInfoMap = map; + } + Integer index = fieldInfoMap.get(key); + if (index != null) { + FieldInfo fi = fields[index]; + return createField(fi.getType(this), fi.offset(), fi.classfileFlags(), fi.internalFlags(), index); + } + } else { + for (int index = 0; index < fields.length; index++) { + FieldInfo fi = fields[index]; + if (FieldInfo.Key.from(fi, this).equals(key)) { + return createField(fi.getType(this), fi.offset(), fi.classfileFlags(), fi.internalFlags(), index); + } + } + } + throw new JVMCIError("unresolved field %s", reflectionField); + } + /** * This class represents the field information for one field contained in the fields array of an * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. @@ -755,8 +802,18 @@ protected HotSpotResolvedObjectTypeImpl getArrayType() { * @param internalFlags field's internal flags (from the VM) * @param initializerIndex field's initial value index in the constant pool */ - record FieldInfo(int nameIndex, int signatureIndex, int offset, int classfileFlags, int internalFlags, - int initializerIndex) { + record FieldInfo(int nameIndex, + int signatureIndex, + int offset, + int classfileFlags, + int internalFlags, + int initializerIndex) { + + record Key(String name, String signature, boolean isStatic) { + static Key from(FieldInfo fi, HotSpotResolvedObjectTypeImpl holder) { + return new FieldInfo.Key(fi.getName(holder), fi.getSignature(holder), fi.isStatic()); + } + } /** * Returns the name of this field as a {@link String}. If the field is an internal field the @@ -880,8 +937,9 @@ private HotSpotResolvedJavaField[] getFields(boolean retrieveStaticFields, HotSp int resultCount = 0; int index; - for (index = 0; index < getFieldInfo().length; index++) { - if (getFieldInfo(index).isStatic() == retrieveStaticFields) { + FieldInfo[] fieldInfo = getFieldInfo(); + for (index = 0; index < fieldInfo.length; index++) { + if (fieldInfo[index].isStatic() == retrieveStaticFields) { resultCount++; } } @@ -902,8 +960,8 @@ private HotSpotResolvedJavaField[] getFields(boolean retrieveStaticFields, HotSp // but the array of fields to be returned must be sorted by increasing offset // This code populates the array, then applies the sorting function int resultIndex = prependLength; - for (int i = 0; i < getFieldInfo().length; ++i) { - FieldInfo field = getFieldInfo(i); + for (int i = 0; i < fieldInfo.length; ++i) { + FieldInfo field = fieldInfo[i]; if (field.isStatic() == retrieveStaticFields) { int offset = field.offset(); HotSpotResolvedJavaField resolvedJavaField = createField(field.getType(this), offset, field.classfileFlags(), field.internalFlags(), i); @@ -1058,7 +1116,7 @@ private static ResolvedJavaField findFieldWithOffset(long offset, JavaKind expec // @formatter:off if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && expectedEntryKind.isPrimitive() && - !expectedEntryKind.equals(JavaKind.Void) && + !expectedEntryKind.equals(jdk.vm.ci.meta.JavaKind.Void) && field.getJavaKind().isPrimitive()) { resolvedFieldOffset += field.getJavaKind().getByteCount() -