Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

wip Stable and unique Lambda and LambdaForm class names #19763

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 1 addition & 20 deletions runtime/bcutil/ComparingCursor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,29 +428,10 @@ ComparingCursor::shouldCheckForEquality(DataType dataType, U_32 u32Value)
}

switch (dataType) {
case SRP_TO_UTF8_CLASS_NAME:
#if JAVA_SPEC_VERSION < 21
if (_context->isLambdaClass() && _romClassIsShared) {
/*
* If the class is a lambda class, don't compare the class names because lambda
* classes might have different index numbers from run to run.
*/
return false;
}
#endif /* JAVA_SPEC_VERSION < 21 */
break;
case SRP_TO_UTF8_CLASS_NAME: /* fall through */
case BYTECODE: /* fall through */
case GENERIC: /* fall through */
case CLASS_FILE_SIZE: /* fall through */
#if JAVA_SPEC_VERSION < 21
if ((CLASS_FILE_SIZE == dataType)
&& _context->isLambdaClass()
&& _romClassIsShared
) {
/* If comparing a lambda class from the shared cache, class file size comparison is already done in ROMClassBuilder::compareROMClassForEquality(). */
return false;
}
#endif /* JAVA_SPEC_VERSION < 21 */
case SRP_TO_DEBUG_DATA: /* fall through */
case SRP_TO_GENERIC: /* fall through */
case SRP_TO_UTF8: /* fall through */
Expand Down
98 changes: 9 additions & 89 deletions runtime/bcutil/ROMClassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,16 +277,6 @@ ROMClassBuilder::handleAnonClassName(J9CfrClassFile *classfile, ROMClassCreation
PORT_ACCESS_FROM_PORT(_portLibrary);

#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
/*
* Prevent generated LambdaForm classes from MethodHandles to be stored to the shared cache.
* When there are a large number of such classes in the shared cache, they trigger a lot of class comparisons.
* Performance can be much worse (compared to shared cache turned off).
*/
if (isLambdaFormClassName(originalStringBytes, originalStringLength, NULL/*deterministicPrefixLength*/)) {
context->addFindClassFlags(J9_FINDCLASS_FLAG_DO_NOT_SHARE);
context->addFindClassFlags(J9_FINDCLASS_FLAG_LAMBDAFORM);
}

#if JAVA_SPEC_VERSION >= 15
/* InjectedInvoker is a hidden class without the strong attribute set. It
* is created by MethodHandleImpl.makeInjectedInvoker on the OpenJDK side.
Expand Down Expand Up @@ -417,22 +407,6 @@ ROMClassBuilder::handleAnonClassName(J9CfrClassFile *classfile, ROMClassCreation
j9str_printf(PORTLIB, buf, ROM_ADDRESS_LENGTH + 1, ROM_ADDRESS_FORMAT, 0);
memcpy(constantPool[newUtfCPEntry].bytes + newHostPackageLength + originalStringLength + 1, buf, ROM_ADDRESS_LENGTH + 1);

/* Mark if the class is a Lambda class. */
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
if (!context->isLambdaFormClass()
&& isLambdaClassName(reinterpret_cast<const char *>(_anonClassNameBuffer),
newAnonClassNameLength - 1, NULL/*deterministicPrefixLength*/)
) {
context->addFindClassFlags(J9_FINDCLASS_FLAG_LAMBDA);
}
#else /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
if (isLambdaClassName(reinterpret_cast<const char *>(_anonClassNameBuffer),
newAnonClassNameLength - 1, NULL/*deterministicPrefixLength*/)
) {
context->addFindClassFlags(J9_FINDCLASS_FLAG_LAMBDA);
}
#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */

/* search constantpool for all other identical classRefs. We have not actually
* tested this scenario as javac will not output more than one classRef or utfRef of the
* same kind.
Expand Down Expand Up @@ -590,18 +564,6 @@ ROMClassBuilder::prepareAndLaydown( BufferManager *bufferManager, ClassFileParse
getSizeInfo(context, &romClassWriter, &srpOffsetTable, &countDebugDataOutOfLine, &sizeInformation);

U_32 romSize = 0;
#if JAVA_SPEC_VERSION < 21
U_32 sizeToCompareForLambda = 0;
if (context->isLambdaClass()) {
/*
* romSize calculated from getSizeInfo() does not involve StringInternManager. It is only accurate for string intern disabled classes.
* Lambda classes in java 15 and up are strong hidden classes (defined with Option.STONG), which has the same lifecycle as its
* defining class loader. It is string intern enabled. So pass classFileSize instead of romSize to sizeToCompareForLambda.
*/
sizeToCompareForLambda = classFileOracle.getClassFileSize();
}
#endif /* JAVA_SPEC_VERSION < 21 */

if (context->shouldCompareROMClassForEquality()) {
ROMClassVerbosePhase v(context, CompareHashtableROMClass);

Expand All @@ -624,9 +586,6 @@ ROMClassBuilder::prepareAndLaydown( BufferManager *bufferManager, ClassFileParse
modifiers,
extraModifiers,
optionalFlags,
#if JAVA_SPEC_VERSION < 21
sizeToCompareForLambda,
#endif /* JAVA_SPEC_VERSION < 21 */
context)
) {
return OK;
Expand Down Expand Up @@ -720,9 +679,6 @@ ROMClassBuilder::prepareAndLaydown( BufferManager *bufferManager, ClassFileParse
modifiers,
extraModifiers,
optionalFlags,
#if JAVA_SPEC_VERSION < 21
sizeToCompareForLambda,
#endif /* JAVA_SPEC_VERSION < 21 */
context)

) {
Expand Down Expand Up @@ -1479,55 +1435,19 @@ ROMClassBuilder::compareROMClassForEquality(
U_32 modifiers,
U_32 extraModifiers,
U_32 optionalFlags,
#if JAVA_SPEC_VERSION < 21
U_32 sizeToCompareForLambda,
#endif /* JAVA_SPEC_VERSION < 21 */
ROMClassCreationContext *context)
{
bool ret = false;
ComparingCursor compareCursor(_javaVM, srpOffsetTable, srpKeyProducer, classFileOracle, romClass, romClassIsShared, context);
romClassWriter->writeROMClass(&compareCursor,
&compareCursor,
&compareCursor,
NULL,
NULL,
0, modifiers, extraModifiers, optionalFlags,
ROMClassWriter::WRITE);

#if JAVA_SPEC_VERSION < 21
if (context->isLambdaClass()) {
/*
* Lambda class names are in the format of HostClassName$$Lambda$<IndexNumber>/<zeroed out ROM_ADDRESS>.
* When we reach this check, the host class names will be the same for both the classes because
* of the earlier hash-key check. So, the only difference in the size will be the difference
* between the number of digits of the index number. The same lambda class might have a
* different index number from run to run and when the number of digits of the index number
* increases by 1, classFileSize also increases by 1. The indexNumber is the counter for the number of
* lambda classes defined so far. It is an int in the JCL side. So the it cannot vary more than max
* integer vs 0, which is maxVariance (9 bytes). This check is different than the romSize check because
* when the number of digits of the index number increases by 1, classFileSize also increases by 1 but
* romSize increases by 2.
*/
int maxVariance = 9;
int variance = abs(static_cast<int>((sizeToCompareForLambda - reinterpret_cast<J9ROMClass *>(romClass)->classFileSize)));
if (variance <= maxVariance) {
ComparingCursor compareCursor(_javaVM, srpOffsetTable, srpKeyProducer, classFileOracle, romClass, romClassIsShared, context);
romClassWriter->writeROMClass(&compareCursor,
&compareCursor,
&compareCursor,
NULL,
NULL,
0, modifiers, extraModifiers, optionalFlags,
ROMClassWriter::WRITE);

ret = compareCursor.isEqual();
}
} else
#endif /* JAVA_SPEC_VERSION < 21 */
{
ComparingCursor compareCursor(_javaVM, srpOffsetTable, srpKeyProducer, classFileOracle, romClass, romClassIsShared, context);
romClassWriter->writeROMClass(&compareCursor,
&compareCursor,
&compareCursor,
NULL,
NULL,
0, modifiers, extraModifiers, optionalFlags,
ROMClassWriter::WRITE);

ret = compareCursor.isEqual();
}
ret = compareCursor.isEqual();
J9UTF8* name = J9ROMCLASS_CLASSNAME((J9ROMClass *)romClass);
Trc_BCU_compareROMClassForEquality_event(ret, J9UTF8_LENGTH(name), J9UTF8_DATA(name));
return ret;
Expand Down
3 changes: 0 additions & 3 deletions runtime/bcutil/ROMClassBuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,6 @@ class ROMClassBuilder
U_32 modifiers,
U_32 extraModifiers,
U_32 optionalFlags,
#if JAVA_SPEC_VERSION < 21
U_32 sizeToCompareForLambda,
#endif /* JAVA_SPEC_VERSION < 21 */
ROMClassCreationContext *context);

SharedCacheRangeInfo getSharedCacheSRPRangeInfo(void *address);
Expand Down
28 changes: 1 addition & 27 deletions runtime/bcutil/ROMClassCreationContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,6 @@ class ROMClassCreationContext
bool isHiddenClassOptNestmateSet() const { return J9_ARE_ALL_BITS_SET(_findClassFlags, J9_FINDCLASS_FLAG_CLASS_OPTION_NESTMATE); }
bool isHiddenClassOptStrongSet() const { return J9_ARE_ALL_BITS_SET(_findClassFlags, J9_FINDCLASS_FLAG_CLASS_OPTION_STRONG); }
bool isDoNotShareClassFlagSet() const {return J9_ARE_ALL_BITS_SET(_findClassFlags, J9_FINDCLASS_FLAG_DO_NOT_SHARE);}
bool isLambdaClass() const { return J9_ARE_ALL_BITS_SET(_findClassFlags, J9_FINDCLASS_FLAG_LAMBDA); }
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
bool isLambdaFormClass() const { return J9_ARE_ALL_BITS_SET(_findClassFlags, J9_FINDCLASS_FLAG_LAMBDAFORM); }
#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */

bool isClassUnmodifiable() const {
bool unmodifiable = false;
Expand Down Expand Up @@ -406,33 +402,11 @@ class ROMClassCreationContext
if (NULL != _className) {
U_16 classNameLenToCompare0 = static_cast<U_16>(_classNameLength);
U_16 classNameLenToCompare1 = classNameLength;
BOOLEAN misMatch = FALSE;
if (isClassHidden()) {
/* For hidden classes, className has the ROM address appended, _className does not. */
classNameLenToCompare1 = static_cast<U_16>(_classNameLength);
#if JAVA_SPEC_VERSION < 21
if (isROMClassShareable()) {
/*
* Before JDK21, Lambda class names are in the format:
* HostClassName$$Lambda$<IndexNumber>/<zeroed out ROM_ADDRESS>
* Do not compare the IndexNumber as it can be different from run to run.
*/
U_8 *lambdaClass0 = reinterpret_cast<U_8 *>(getLastDollarSignOfLambdaClassName(
reinterpret_cast<const char *>(_className), _classNameLength));
U_8 *lambdaClass1 = reinterpret_cast<U_8 *>(getLastDollarSignOfLambdaClassName(
reinterpret_cast<const char *>(className), classNameLength));
if ((NULL != lambdaClass0) && (NULL != lambdaClass1)) {
classNameLenToCompare0 = static_cast<U_16>(lambdaClass0 - _className + 1);
classNameLenToCompare1 = static_cast<U_16>(lambdaClass1 - className + 1);
} else if ((NULL == lambdaClass0) != (NULL == lambdaClass1)) {
misMatch = TRUE;
}
}
#endif /* JAVA_SPEC_VERSION < 21 */
}
if (misMatch
|| !J9UTF8_DATA_EQUALS(_className, classNameLenToCompare0, className, classNameLenToCompare1)
) {
if (!J9UTF8_DATA_EQUALS(_className, classNameLenToCompare0, className, classNameLenToCompare1)) {
#define J9WRONGNAME " (wrong name: "
PORT_ACCESS_FROM_PORT(_portLibrary);
UDATA errorStringSize = _classNameLength + sizeof(J9WRONGNAME) + 1 + classNameLength;
Expand Down
3 changes: 3 additions & 0 deletions runtime/jcl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ target_link_libraries(jclse
j9vm_interface
j9vm_gc_includes

j9shrcommon
j9shrutil
j9zip
omrsig
j9hookable
j9zlib
Expand Down
123 changes: 121 additions & 2 deletions runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,14 @@
#include "j9vmconstantpool.h"
#include "ObjectAccessBarrierAPI.hpp"
#include "objhelp.h"
#include "SCAbstractAPI.h"

#include <string.h>
#include <assert.h>

#undef UT_MODULE_LOADED
#undef UT_MODULE_UNLOADED
#include "CacheMap.hpp"
#include "VMHelpers.hpp"

extern "C" {
Expand Down Expand Up @@ -945,6 +949,121 @@ Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobj
vmFuncs->internalExitVMToJNI(currentThread);
}

/**
* Find a Lambda or customized LambdaForm class in the SCC.
* Requires non-null input arguments.
* If found, returns a pointer to a RAMClass of the SCC-cached class, otherwise nullptr.
*
* Throws OutOfMemoryError if lookup key memory allocation fails.
*/
jobject
findLambdaOrLambdaFormInSCC(JNIEnv *env, jclass clazz, jstring classnameObject, jclass lookupClass, UDATA options)
{
jobject result = nullptr;

#if defined(J9VM_OPT_SHARED_CLASSES)
J9VMThread *currentThread = reinterpret_cast<J9VMThread*>(env);
J9JavaVM *vm = currentThread->javaVM;
const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
PORT_ACCESS_FROM_JAVAVM(vm);
vmFuncs->internalEnterVMFromJNI(currentThread);
Trc_JCL_java_lang_invoke_MethodHandleNatives_findLambdaOrLambdaFormInSCC_Entry(env, classnameObject, lookupClass, options);

#if defined(J9VM_ENV_DATA64)
#define J9_ROM_ADDRESS_SUFFIX "/0x0000000000000000"
#else /* defined(J9VM_ENV_DATA64) */
#define J9_ROM_ADDRESS_SUFFIX "/0x00000000"
#endif /* defined(J9VM_ENV_DATA64) */
j9object_t classname = J9_JNI_UNWRAP_REFERENCE(classnameObject);
IDATA classnameLength = vmFuncs->getStringUTF8Length(currentThread, classname);
UDATA romAddressSuffixLength = LITERAL_STRLEN(J9_ROM_ADDRESS_SUFFIX);
UDATA lookupKeyLength = classnameLength + romAddressSuffixLength + 1; /* +1 for null terminator. */
char *lookupKey = static_cast<char *>(j9mem_allocate_memory(lookupKeyLength, OMRMEM_CATEGORY_VM));

if (nullptr == lookupKey) {
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
} else {
vmFuncs->copyStringToUTF8Helper(currentThread, classname, J9_STR_NONE, 0, classnameLength, reinterpret_cast<U_8 *>(lookupKey), classnameLength);
memcpy(lookupKey + classnameLength, J9_ROM_ADDRESS_SUFFIX, romAddressSuffixLength);
lookupKey[lookupKeyLength - 1] = '\0';

if (nullptr != vm->sharedClassConfig && nullptr != vm->sharedClassConfig->sharedAPIObject) {
SCAbstractAPI *sharedapi = static_cast<SCAbstractAPI *>(vm->sharedClassConfig->sharedAPIObject);
J9ROMClass *romClass = sharedapi->jclFindOrphanROMClassByUniqueID(currentThread, lookupKey, lookupKeyLength - 1);
if (nullptr != romClass) {
J9Class *hostClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(lookupClass));
J9ClassLoader *classloader = hostClass->classLoader;
if (nullptr != hostClass) {
omrthread_monitor_enter(vm->classTableMutex);
/* internalCreateRAMClassFromROMClass will release the classTableMutex. */
J9Class *ramClass = vmFuncs->internalCreateRAMClassFromROMClass(
currentThread,
classloader,
romClass,
options,
nullptr /* elementClass */,
nullptr /* protectionDomain */,
nullptr /* methodRemapArray */,
J9_CP_INDEX_NONE,
LOAD_LOCATION_UNKNOWN,
nullptr /* classBeingRedefined */,
hostClass);
if (nullptr != ramClass && nullptr == currentThread->currentException) {
Trc_JCL_java_lang_invoke_MethodHandleNatives_findLambdaOrLambdaFormInSCC_Found(env, lookupKeyLength - 1, lookupKey, lookupClass, options);
result = vmFuncs->j9jni_createLocalRef(env, J9VM_J9CLASS_TO_HEAPCLASS(ramClass));
}
}
}
}
}

if (nullptr != lookupKey) {
j9mem_free_memory(lookupKey);
}
Trc_JCL_java_lang_invoke_MethodHandleNatives_findLambdaOrLambdaFormInSCC_Exit(env);
vmFuncs->internalExitVMToJNI(currentThread);
#undef J9_ROM_ADDRESS_SUFFIX
#endif /* J9VM_OPT_SHARED_CLASSES */
return result;
}

/**
* static native Class<?> findLambdaInSCC(String classname, Class<?> hostClass);
*
* Find a Lambda class in the SCC.
* Requires non-null input arguments.
* If found, returns a pointer to a RAMClass of the SCC-cached, otherwise nullptr.
*/
jobject JNICALL
Java_java_lang_invoke_MethodHandleNatives_findLambdaInSCC(JNIEnv *env, jclass clazz, jstring classnameObject, jclass lookupClass)
{
UDATA options = J9_FINDCLASS_FLAG_NO_CHECK_FOR_EXISTING_CLASS
| J9_FINDCLASS_FLAG_THROW_ON_FAIL
| J9_FINDCLASS_FLAG_UNSAFE
| J9_FINDCLASS_FLAG_HIDDEN
| J9_FINDCLASS_FLAG_CLASS_OPTION_NESTMATE
| J9_FINDCLASS_FLAG_CLASS_OPTION_STRONG;
return findLambdaOrLambdaFormInSCC(env, clazz, classnameObject, lookupClass, options);
}

/**
* static native Class<?> findLambdaFormInSCC(String classname, Class<?> hostClass);
*
* Find a customized LambdaForm class in the SCC.
* Requires non-null input arguments.
* If found, returns a pointer to a RAMClass of the SCC-cached class, otherwise nullptr.
*/
jobject JNICALL
Java_java_lang_invoke_MethodHandleNatives_findLambdaFormInSCC(JNIEnv *env, jclass clazz, jstring classnameObject, jclass lookupClass)
{
UDATA options = J9_FINDCLASS_FLAG_NO_CHECK_FOR_EXISTING_CLASS
| J9_FINDCLASS_FLAG_THROW_ON_FAIL
| J9_FINDCLASS_FLAG_UNSAFE
| J9_FINDCLASS_FLAG_HIDDEN
| J9_FINDCLASS_FLAG_ANON;
return findLambdaOrLambdaFormInSCC(env, clazz, classnameObject, lookupClass, options);
}

/**
* [JDK8] static native MemberName resolve(MemberName self, Class<?> caller)
* throws LinkageError, ClassNotFoundException;
Expand Down Expand Up @@ -987,7 +1106,7 @@ Java_java_lang_invoke_MethodHandleNatives_resolve(
char nameBuffer[256];
nameBuffer[0] = 0;
J9UTF8 *signature = NULL;
char signatureBuffer[256];
char signatureBuffer[512];
signatureBuffer[0] = 0;
PORT_ACCESS_FROM_JAVAVM(vm);
vmFuncs->internalEnterVMFromJNI(currentThread);
Expand Down Expand Up @@ -1419,7 +1538,7 @@ Java_java_lang_invoke_MethodHandleNatives_getMembers(
char nameBuffer[256];
nameBuffer[0] = 0;
J9UTF8 *signature = NULL;
char signatureBuffer[256];
char signatureBuffer[512];
signatureBuffer[0] = 0;
j9object_t callerObject = ((NULL == caller) ? NULL : J9_JNI_UNWRAP_REFERENCE(caller));

Expand Down
Loading