Skip to content

Commit

Permalink
Do not skip InjectedInvoker class in getCallerClass and getStackClass
Browse files Browse the repository at this point in the history
This patch fixes both #14553 and
#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: #14553 #18245
Signed-off-by: Nathan Henderson <nathan.henderson@ibm.com>
  • Loading branch information
ThanHenderson committed Oct 19, 2023
1 parent 6df98f6 commit e32653e
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 24 deletions.
11 changes: 3 additions & 8 deletions runtime/bcutil/ClassFileWriter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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: <HOST_NAME>/InjectedInvoker/<ROM_ADDRESS_LENGTH>.
* 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);
Expand Down
36 changes: 33 additions & 3 deletions runtime/bcutil/ROMClassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1180,7 +1180,7 @@ ROMClassBuilder::finishPrepareAndLaydown(
* + AccRecord
* + AccClassAnonClass
*
* + UNUSED
* + J9AccClassIsInjectedInvoker
* + AccClassUseBisectionSearch
* + AccClassInnerClass
* + J9AccClassHidden
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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) */
3 changes: 3 additions & 0 deletions runtime/bcutil/ROMClassBuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */
1 change: 1 addition & 0 deletions runtime/oti/j9javaaccessflags.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 14 additions & 7 deletions runtime/sunvmi/sunvmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
Expand All @@ -254,7 +262,6 @@ getCallerClassJEP176Iterator(J9VMThread * currentThread, J9StackWalkState * walk
return J9_STACKWALK_KEEP_ITERATING;
}


/**
* JVM_GetCallerClass
*/
Expand Down
20 changes: 14 additions & 6 deletions runtime/vm/NativeHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down

0 comments on commit e32653e

Please sign in to comment.