From e32653e8a50658d3e481c05d174477dbfaefce6a Mon Sep 17 00:00:00 2001 From: Nathan Henderson Date: Sun, 15 Oct 2023 07:14:41 -0700 Subject: [PATCH] Do not skip InjectedInvoker class in getCallerClass and getStackClass This patch fixes both eclipse-openj9/openj9#14553 and eclipse-openj9/openj9#18245. When OJDK MHs are enabled for JDK11, the Hidden attribute for InjectedInvoker classes caused getStackClass and getCallerClass to return the incorrect class. The solution is to not iterate over InjectedInvoker classes despite them having the J9AccMethodFrameIteratorSkip modifier set due to the Hidden attribute. Closes: eclipse-openj9/openj9#14553 eclipse-openj9/openj9#18245 Signed-off-by: Nathan Henderson --- runtime/bcutil/ClassFileWriter.hpp | 11 +++------ runtime/bcutil/ROMClassBuilder.cpp | 36 +++++++++++++++++++++++++++--- runtime/bcutil/ROMClassBuilder.hpp | 3 +++ runtime/oti/j9javaaccessflags.h | 1 + runtime/sunvmi/sunvmi.c | 21 +++++++++++------ runtime/vm/NativeHelpers.cpp | 20 ++++++++++++----- 6 files changed, 68 insertions(+), 24 deletions(-) diff --git a/runtime/bcutil/ClassFileWriter.hpp b/runtime/bcutil/ClassFileWriter.hpp index de1a734343a..7f82f7ef62d 100644 --- a/runtime/bcutil/ClassFileWriter.hpp +++ b/runtime/bcutil/ClassFileWriter.hpp @@ -358,15 +358,10 @@ class ClassFileWriter { U_16 originalNameLength = anonNameLength - ROM_ADDRESS_LENGTH - 1; U_8 *anonClassNameData = J9UTF8_DATA(_anonClassName); #if defined(J9VM_OPT_OPENJDK_METHODHANDLE) - /* ROM class format: /InjectedInvoker/. - * Search for InjectedInvoker in _anonClassName using the above format. - * If found, reset the class name to "InjectedInvoker" in the class file. + /* If the class is an InjectedInvoker, reset the class name to + * "InjectedInvoker" in the class file. */ - IDATA startIndex = anonNameLength - J9UTF8_LENGTH(&injectedInvokerClassname) - ROM_ADDRESS_LENGTH - 1; - U_8 *start = anonClassNameData + startIndex; - if ((startIndex >= 0) - && (0 == memcmp(start, J9UTF8_DATA(&injectedInvokerClassname), J9UTF8_LENGTH(&injectedInvokerClassname))) - ) { + if (J9_ARE_ALL_BITS_SET(_romClass->extraModifiers, J9AccClassIsInjectedInvoker)) { _isInjectedInvoker = TRUE; originalNameLength = J9UTF8_LENGTH(&injectedInvokerClassname); anonClassNameData = J9UTF8_DATA(&injectedInvokerClassname); diff --git a/runtime/bcutil/ROMClassBuilder.cpp b/runtime/bcutil/ROMClassBuilder.cpp index 0190718ac6f..1e628a95ad9 100644 --- a/runtime/bcutil/ROMClassBuilder.cpp +++ b/runtime/bcutil/ROMClassBuilder.cpp @@ -276,7 +276,7 @@ ROMClassBuilder::handleAnonClassName(J9CfrClassFile *classfile, bool *isLambda, UDATA hostPackageLength = context->hostPackageLength(); PORT_ACCESS_FROM_PORT(_portLibrary); -#if defined(J9VM_OPT_OPENJDK_METHODHANDLE) +#if defined(J9VM_OPT_OPENJDK_METHODHANDLE) && (JAVA_SPEC_VERSION >= 15) /* InjectedInvoker is a hidden class without the strong attribute set. It * is created by MethodHandleImpl.makeInjectedInvoker on the OpenJDK side. * So, OpenJ9 does not have control over the implementation of InjectedInvoker. @@ -321,7 +321,7 @@ ROMClassBuilder::handleAnonClassName(J9CfrClassFile *classfile, bool *isLambda, } #undef J9_INJECTED_INVOKER_CLASSNAME } -#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */ +#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) && (JAVA_SPEC_VERSION >= 15) */ /* check if adding host package name to anonymous class is needed */ UDATA newHostPackageLength = 0; @@ -1180,7 +1180,7 @@ ROMClassBuilder::finishPrepareAndLaydown( * + AccRecord * + AccClassAnonClass * - * + UNUSED + * + J9AccClassIsInjectedInvoker * + AccClassUseBisectionSearch * + AccClassInnerClass * + J9AccClassHidden @@ -1259,6 +1259,12 @@ ROMClassBuilder::computeExtraModifiers(ClassFileOracle *classFileOracle, ROMClas modifiers |= J9AccClassIsValueBased; } +#if defined(J9VM_OPT_OPENJDK_METHODHANDLE) + if (isInjectedInvoker()) { + modifiers |= J9AccClassIsInjectedInvoker; + } +#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */ + U_32 classNameindex = classFileOracle->getClassNameIndex(); #define WEAK_NAME "java/lang/ref/WeakReference" @@ -1558,3 +1564,27 @@ ROMClassBuilder::getSharedCacheSRPRangeInfo(void *address) } #endif #endif + +#if defined(J9VM_OPT_OPENJDK_METHODHANDLE) +bool +ROMClassBuilder::isInjectedInvoker(void) const +{ +#define J9_INJECTED_INVOKER_CLASSNAME "InjectedInvoker" + /* InjectedInvoker classes are anon or hidden */ + bool result = false; + if (NULL != _anonClassNameBuffer) { + IDATA injectedInvokerLength = LITERAL_STRLEN(J9_INJECTED_INVOKER_CLASSNAME); + /* computeExtraModifiers is called after appending 0's to hidden and anoymous classes. */ + IDATA startIndex = strlen((const char *)_anonClassNameBuffer) - injectedInvokerLength - ROM_ADDRESS_LENGTH - 1; + if (startIndex >= 0) { + /* start is the potential beginning of "InjectedInvoker", after the potential package name. */ + U_8 *start = _anonClassNameBuffer + startIndex; + if (0 == memcmp(start, J9_INJECTED_INVOKER_CLASSNAME, injectedInvokerLength)) { + result = true; + } + } + } + return result; +#undef J9_INJECTED_INVOKER_CLASSNAME +} +#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */ diff --git a/runtime/bcutil/ROMClassBuilder.hpp b/runtime/bcutil/ROMClassBuilder.hpp index de0b4d7ff53..451f6055883 100644 --- a/runtime/bcutil/ROMClassBuilder.hpp +++ b/runtime/bcutil/ROMClassBuilder.hpp @@ -164,6 +164,9 @@ class ROMClassBuilder U_32 modifiers, U_32 extraModifiers, U_32 optionalFlags, ROMClassCreationContext * context, U_32 sizeToCompareForLambda, bool isLambda); SharedCacheRangeInfo getSharedCacheSRPRangeInfo(void *address); void getSizeInfo(ROMClassCreationContext *context, ROMClassWriter *romClassWriter, SRPOffsetTable *srpOffsetTable, bool *countDebugDataOutOfLine, SizeInformation *sizeInformation); +#if defined(J9VM_OPT_OPENJDK_METHODHANDLE) + bool isInjectedInvoker(void) const; +#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */ }; #endif /* ROMCLASSBUILDER_HPP_ */ diff --git a/runtime/oti/j9javaaccessflags.h b/runtime/oti/j9javaaccessflags.h index 89407e01aac..a0f11408bcb 100644 --- a/runtime/oti/j9javaaccessflags.h +++ b/runtime/oti/j9javaaccessflags.h @@ -107,6 +107,7 @@ #define J9AccSealed 0x200 #define J9AccRecord 0x400 #define J9AccClassAnonClass 0x800 +#define J9AccClassIsInjectedInvoker 0x1000 #define J9AccClassUseBisectionSearch 0x2000 #define J9AccClassInnerClass 0x4000 #define J9AccClassHidden 0x8000 diff --git a/runtime/sunvmi/sunvmi.c b/runtime/sunvmi/sunvmi.c index ed3ff94bf23..38f5efb3725 100644 --- a/runtime/sunvmi/sunvmi.c +++ b/runtime/sunvmi/sunvmi.c @@ -209,15 +209,23 @@ getCallerClassIterator(J9VMThread * currentThread, J9StackWalkState * walkState) static UDATA -getCallerClassJEP176Iterator(J9VMThread * currentThread, J9StackWalkState * walkState) +getCallerClassJEP176Iterator(J9VMThread *currentThread, J9StackWalkState *walkState) { - J9JavaVM * vm = currentThread->javaVM; + J9JavaVM *vm = currentThread->javaVM; J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; - J9Class * currentClass = J9_CLASS_FROM_CP(walkState->constantPool); + J9Class *currentClass = J9_CLASS_FROM_CP(walkState->constantPool); Assert_SunVMI_mustHaveVMAccess(currentThread); - if (J9_ARE_ALL_BITS_SET(J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)->modifiers, J9AccMethodFrameIteratorSkip)) { + if (J9_ARE_ALL_BITS_SET(J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)->modifiers, J9AccMethodFrameIteratorSkip) +#if defined(J9VM_OPT_OPENJDK_METHODHANDLE) && (JAVA_SPEC_VERSION <= 11) + /* Do not skip InjectedInvoker classes despite them having the J9AccMethodFrameIteratorSkip + * modifier set via the @Hidden attribute. Skipping them causes incorrect, unexpected + * behaviour when using OpenJDK method handles pre-hidden-class support. + */ + && J9_ARE_NO_BITS_SET(currentClass->romClass->extraModifiers, J9AccClassIsInjectedInvoker) +#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) && (JAVA_SPEC_VERSION <= 11) */ + ) { /* Skip methods with java.lang.invoke.FrameIteratorSkip / jdk.internal.vm.annotation.Hidden / java.lang.invoke.LambdaForm$Hidden annotation */ return J9_STACKWALK_KEEP_ITERATING; } @@ -239,8 +247,8 @@ getCallerClassJEP176Iterator(J9VMThread * currentThread, J9StackWalkState * walk #if JAVA_SPEC_VERSION >= 18 || (walkState->method == vm->jlrMethodInvokeMH) #endif /* JAVA_SPEC_VERSION >= 18 */ - || (vm->srMethodAccessor && vmFuncs->instanceOfOrCheckCast(currentClass, J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, *((j9object_t*) vm->srMethodAccessor)))) - || (vm->srConstructorAccessor && vmFuncs->instanceOfOrCheckCast(currentClass, J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, *((j9object_t*) vm->srConstructorAccessor)))) + || (vm->srMethodAccessor && vmFuncs->instanceOfOrCheckCast(currentClass, J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, *((j9object_t *)vm->srMethodAccessor)))) + || (vm->srConstructorAccessor && vmFuncs->instanceOfOrCheckCast(currentClass, J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, *((j9object_t *)vm->srConstructorAccessor)))) ) { /* skip reflection classes and MethodHandle.invokeWithArguments() when reaching depth 0 */ return J9_STACKWALK_KEEP_ITERATING; @@ -254,7 +262,6 @@ getCallerClassJEP176Iterator(J9VMThread * currentThread, J9StackWalkState * walk return J9_STACKWALK_KEEP_ITERATING; } - /** * JVM_GetCallerClass */ diff --git a/runtime/vm/NativeHelpers.cpp b/runtime/vm/NativeHelpers.cpp index 47b0c529f8d..22782289d3e 100644 --- a/runtime/vm/NativeHelpers.cpp +++ b/runtime/vm/NativeHelpers.cpp @@ -82,15 +82,23 @@ getInterfacesHelper(J9VMThread *currentThread, j9object_t clazz) } UDATA -cInterpGetStackClassJEP176Iterator(J9VMThread * currentThread, J9StackWalkState * walkState) +cInterpGetStackClassJEP176Iterator(J9VMThread *currentThread, J9StackWalkState *walkState) { - J9JavaVM * vm = currentThread->javaVM; - J9Class * currentClass = J9_CLASS_FROM_CP(walkState->constantPool); + J9JavaVM *vm = currentThread->javaVM; + J9Class *currentClass = J9_CLASS_FROM_CP(walkState->constantPool); J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions; Assert_VM_mustHaveVMAccess(currentThread); - if (J9_ARE_ALL_BITS_SET(J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)->modifiers, J9AccMethodFrameIteratorSkip)) { + if (J9_ARE_ALL_BITS_SET(J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)->modifiers, J9AccMethodFrameIteratorSkip) +#if defined(J9VM_OPT_OPENJDK_METHODHANDLE) && (JAVA_SPEC_VERSION <= 11) + /* Do not skip InjectedInvoker classes despite them having the J9AccMethodFrameIteratorSkip + * modifier set via the @Hidden attribute. Skipping them causes incorrect, unexpected + * behaviour when using OpenJDK method handles pre-hidden-class support. + */ + && J9_ARE_NO_BITS_SET(currentClass->romClass->extraModifiers, J9AccClassIsInjectedInvoker) +#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) && (JAVA_SPEC_VERSION <= 11) */ + ) { /* Skip methods with java.lang.invoke.FrameIteratorSkip / jdk.internal.vm.annotation.Hidden / java.lang.invoke.LambdaForm$Hidden annotation */ return J9_STACKWALK_KEEP_ITERATING; } @@ -112,8 +120,8 @@ cInterpGetStackClassJEP176Iterator(J9VMThread * currentThread, J9StackWalkState #if JAVA_SPEC_VERSION >= 18 || (walkState->method == vm->jlrMethodInvokeMH) #endif /* JAVA_SPEC_VERSION >= 18 */ - || (vm->srMethodAccessor && vmFuncs->instanceOfOrCheckCast(currentClass, J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, *((j9object_t*) vm->srMethodAccessor)))) - || (vm->srConstructorAccessor && vmFuncs->instanceOfOrCheckCast(currentClass, J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, *((j9object_t*) vm->srConstructorAccessor)))) + || (vm->srMethodAccessor && vmFuncs->instanceOfOrCheckCast(currentClass, J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, *((j9object_t *)vm->srMethodAccessor)))) + || (vm->srConstructorAccessor && vmFuncs->instanceOfOrCheckCast(currentClass, J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, *((j9object_t *)vm->srConstructorAccessor)))) ) { /* skip reflection classes and MethodHandle.invokeWithArguments() when reaching depth 0 */ return J9_STACKWALK_KEEP_ITERATING;