Skip to content

Commit

Permalink
wip Stable and unique Lambda and LambdaForm class names
Browse files Browse the repository at this point in the history
  • Loading branch information
ThanHenderson committed Jun 26, 2024
1 parent 2f3ea37 commit 8d34c85
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 155 deletions.
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
112 changes: 112 additions & 0 deletions runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
#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 @@ -772,6 +775,115 @@ 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.
* Returns a pointer to a SCC-cached ROMClass if found, otherwise nullptr.
*
* Throws OutOfMemoryError upon failure to allocate memory.
*/
jobject JNICALL
Java_java_lang_invoke_MethodHandleNatives_findInSCC(JNIEnv *env, jclass clazz, jstring classnameObject, jclass lookupClass)
{
#if defined(J9VM_OPT_SHARED_CLASSES)
#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) */

J9VMThread *currentThread = reinterpret_cast<J9VMThread*>(env);
J9JavaVM *vm = currentThread->javaVM;
const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
PORT_ACCESS_FROM_JAVAVM(vm);

vmFuncs->internalEnterVMFromJNI(currentThread);

J9Class *hostClass = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(lookupClass));
J9ClassLoader *classloader = hostClass->classLoader;
if (nullptr == classloader) {
vmFuncs->internalEnterVMFromJNI(currentThread);
return nullptr;
}

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 + /* null terminator */ 1;
char *lookupKey = static_cast<char *>(j9mem_allocate_memory(lookupKeyLength, OMRMEM_CATEGORY_VM));

/* Memory cleanup and exit routine. */
auto cleanup = [=]() {
if (nullptr != lookupKey) {
j9mem_free_memory(lookupKey);
}
vmFuncs->internalExitVMToJNI(currentThread);
};

if (nullptr == lookupKey) {
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
cleanup();
return nullptr;
}

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

J9SharedClassConfig *sconfig = currentThread->javaVM->sharedClassConfig;
if (nullptr == sconfig) {
cleanup();
return nullptr;
}

SH_CacheMap* cachemap = reinterpret_cast<SH_CacheMap*>(sconfig->sharedClassCache);
/* TODO Look to see if we should use a different API here. */
void *iterator = nullptr;
void *firstFound = nullptr;
omrthread_monitor_enter(vm->classMemorySegments->segmentMutex);
J9ROMClass *romClass = const_cast<J9ROMClass *>(cachemap->findNextROMClass(currentThread, iterator, firstFound, lookupKeyLength - 1, lookupKey));
omrthread_monitor_exit(vm->classMemorySegments->segmentMutex);

if (nullptr == romClass) {
cleanup();
return nullptr;
}

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
| J9_FINDCLASS_FLAG_CLASS_OPTION_NESTMATE
| J9_FINDCLASS_FLAG_CLASS_OPTION_STRONG;

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) {
cleanup();
return nullptr;
}

jobject result = vmFuncs->j9jni_createLocalRef(env, J9VM_J9CLASS_TO_HEAPCLASS(ramClass));
cleanup();
return result;
#undef J9_ROM_ADDRESS_SUFFIX
#else /* J9VM_OPT_SHARED_CLASSES */
return nullptr;
#endif /* J9VM_OPT_SHARED_CLASSES */
}

/**
* [JDK8] static native MemberName resolve(MemberName self, Class<?> caller)
* throws LinkageError, ClassNotFoundException;
Expand Down
1 change: 1 addition & 0 deletions runtime/jcl/exports.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ if(J9VM_OPT_OPENJDK_METHODHANDLE)
omr_add_exports(jclse
Java_java_lang_invoke_MethodHandleNatives_init
Java_java_lang_invoke_MethodHandleNatives_expand
Java_java_lang_invoke_MethodHandleNatives_findInSCC
Java_java_lang_invoke_MethodHandleNatives_resolve
Java_java_lang_invoke_MethodHandleNatives_getMembers
Java_java_lang_invoke_MethodHandleNatives_objectFieldOffset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-ex
<exports group="java_lang_invoke_MethodHandleNatives">
<export name="Java_java_lang_invoke_MethodHandleNatives_init" />
<export name="Java_java_lang_invoke_MethodHandleNatives_expand" />
<export name="Java_java_lang_invoke_MethodHandleNatives_findInSCC" />
<export name="Java_java_lang_invoke_MethodHandleNatives_resolve" />
<export name="Java_java_lang_invoke_MethodHandleNatives_getMembers" />
<export name="Java_java_lang_invoke_MethodHandleNatives_objectFieldOffset" />
Expand Down
2 changes: 0 additions & 2 deletions runtime/oti/j9consts.h
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,6 @@ extern "C" {
#define J9_FINDCLASS_FLAG_CLASS_OPTION_NESTMATE 0x40000
#define J9_FINDCLASS_FLAG_CLASS_OPTION_STRONG 0x80000
#define J9_FINDCLASS_FLAG_DO_NOT_SHARE 0x100000
#define J9_FINDCLASS_FLAG_LAMBDA 0x200000
#define J9_FINDCLASS_FLAG_LAMBDAFORM 0x400000

#define J9_FINDKNOWNCLASS_FLAG_INITIALIZE 0x1
#define J9_FINDKNOWNCLASS_FLAG_EXISTING_ONLY 0x2
Expand Down
1 change: 1 addition & 0 deletions runtime/oti/jclprots.h
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,7 @@ jobject JNICALL Java_java_lang_invoke_MethodType_makeTenured(JNIEnv *env, jclass
#if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
void JNICALL Java_java_lang_invoke_MethodHandleNatives_init(JNIEnv *env, jclass clazz, jobject self, jobject ref);
void JNICALL Java_java_lang_invoke_MethodHandleNatives_expand(JNIEnv *env, jclass clazz, jobject self);
jobject JNICALL Java_java_lang_invoke_MethodHandleNatives_findInSCC(JNIEnv *env, jclass clazz, jstring classname, jclass lookupClass);
jobject JNICALL Java_java_lang_invoke_MethodHandleNatives_resolve(
#if JAVA_SPEC_VERSION == 8
JNIEnv *env, jclass clazz, jobject self, jclass caller);
Expand Down
Loading

0 comments on commit 8d34c85

Please sign in to comment.