diff --git a/doc/features/SharedClassesCache.md b/doc/features/SharedClassesCache.md new file mode 100644 index 00000000000..383cd7a64c7 --- /dev/null +++ b/doc/features/SharedClassesCache.md @@ -0,0 +1,57 @@ + + +The Shared Classes Cache (SCC) is a feature of OpenJ9 that enables sharing +data between JVMs. For more information see [1]. + +## JIT + +The JIT Compiler uses the SCC to store both AOT code as well as data either +necessary for AOT +(e.g. [Class Chains](https://github.com/eclipse/openj9/blob/master/doc/compiler/aot/ClassChains.md)), +or for performace (e.g. IProfiler data). The JIT interfaces with the SCC via +the `TR_J9SharedCache` class. + +### Offsets + +When data that is stored into the SCC needs to refer to other data, it is +referred to by using offsets. Traditionally, the offset would always be +relative to the start of the SCC. However, if the SCC is resized, only +offsets of data in the ROM Class section of the SCC will be invariant. +Therefore, offsets of all data, which must be in the metadata section, +are calculated relative to the start of the metadata section. Another +point of clarification is that offsets of data within the ROMClass section +is calculated using the start of the ROMClass section as no ROM Structure +pointer should point before the start of the section. The offsets that +are generated and stored as part of relocation information are first +left shifted 1 bit; the low bit is used to determine whether the offset +is relative to the start of the ROM Class section or the start of the +metadata section. + +The APIs in in `TR_J9SharedCache` provide an abstraction layer so that +other parts of the compiler do not need to worry about the details. +However, it is important that one does not use the offsets directly, but +only via the `TR_J9SharedCache` class. + +
+ +[1] https://www.eclipse.org/openj9/docs/shrc/ diff --git a/runtime/compiler/aarch64/codegen/J9AheadOfTimeCompile.cpp b/runtime/compiler/aarch64/codegen/J9AheadOfTimeCompile.cpp index 2baf4413784..c4265efeac1 100644 --- a/runtime/compiler/aarch64/codegen/J9AheadOfTimeCompile.cpp +++ b/runtime/compiler/aarch64/codegen/J9AheadOfTimeCompile.cpp @@ -75,8 +75,8 @@ void J9::ARM64::AheadOfTimeCompile::processRelocations() TR::SymbolValidationManager *svm = self()->comp()->getSymbolValidationManager(); void *offsets = const_cast(svm->wellKnownClassChainOffsets()); - *(uintptr_t *)relocationDataCursor = reinterpret_cast( - fej9->sharedCache()->offsetInSharedCacheFromPointer(offsets)); + *(uintptr_t *)relocationDataCursor = + self()->offsetInSharedCacheFromPointer(fej9->sharedCache(), offsets); relocationDataCursor += SIZEPOINTER; } @@ -681,7 +681,7 @@ uint8_t *J9::ARM64::AheadOfTimeCompile::initializeAOTRelocationHeader(TR::Iterat // Store rom method to get name of method J9Method *methodToValidate = reinterpret_cast(record->_method); J9ROMMethod *romMethod = static_cast(fej9)->getROMMethodFromRAMMethod(methodToValidate); - uintptr_t romMethodOffsetInSharedCache = self()->offsetInSharedCacheFromPointer(sharedCache, romMethod); + uintptr_t romMethodOffsetInSharedCache = self()->offsetInSharedCacheFromROMMethod(sharedCache, romMethod); binaryTemplate->_methodID = symValManager->getIDFromSymbol(static_cast(record->_method)); binaryTemplate->_definingClassID = symValManager->getIDFromSymbol(static_cast(record->definingClass())); diff --git a/runtime/compiler/codegen/J9AheadOfTimeCompile.cpp b/runtime/compiler/codegen/J9AheadOfTimeCompile.cpp index 4711e2b6e2a..ab0f0f98cf7 100644 --- a/runtime/compiler/codegen/J9AheadOfTimeCompile.cpp +++ b/runtime/compiler/codegen/J9AheadOfTimeCompile.cpp @@ -64,7 +64,31 @@ J9::AheadOfTimeCompile::offsetInSharedCacheFromPointer(TR_SharedCache *sharedCac if (sharedCache->isPointerInSharedCache(ptr, &offset)) return offset; else - self()->comp()->failCompilation("Failed to find pointer in SCC"); + self()->comp()->failCompilation("Failed to find pointer %p in SCC", ptr); + + return offset; + } + +uintptr_t +J9::AheadOfTimeCompile::offsetInSharedCacheFromROMClass(TR_SharedCache *sharedCache, J9ROMClass *romClass) + { + uintptr_t offset = 0; + if (sharedCache->isROMClassInSharedCache(romClass, &offset)) + return offset; + else + self()->comp()->failCompilation("Failed to find romClass %p in SCC", romClass); + + return offset; + } + +uintptr_t +J9::AheadOfTimeCompile::offsetInSharedCacheFromROMMethod(TR_SharedCache *sharedCache, J9ROMMethod *romMethod) + { + uintptr_t offset = 0; + if (sharedCache->isROMMethodInSharedCache(romMethod, &offset)) + return offset; + else + self()->comp()->failCompilation("Failed to find romMethod %p in SCC", romMethod); return offset; } @@ -382,8 +406,8 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal } TR_OpaqueClassBlock *inlinedMethodClass = resolvedMethod->containingClass(); - void *romClass = reinterpret_cast(fej9->getPersistentClassPointerFromClassPointer(inlinedMethodClass)); - uintptr_t romClassOffsetInSharedCache = self()->offsetInSharedCacheFromPointer(sharedCache, romClass); + J9ROMClass *romClass = reinterpret_cast(fej9->getPersistentClassPointerFromClassPointer(inlinedMethodClass)); + uintptr_t romClassOffsetInSharedCache = self()->offsetInSharedCacheFromROMClass(sharedCache, romClass); imRecord->setReloFlags(reloTarget, flags); imRecord->setInlinedSiteIndex(reloTarget, inlinedSiteIndex); @@ -405,8 +429,8 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal uintptr_t inlinedSiteIndex = reinterpret_cast(relocation->getTargetAddress()); TR::AOTClassInfo *aotCI = reinterpret_cast(relocation->getTargetAddress2()); - void *romClass = reinterpret_cast(fej9->getPersistentClassPointerFromClassPointer(aotCI->_clazz)); - uintptr_t romClassOffsetInSharedCache = self()->offsetInSharedCacheFromPointer(sharedCache, romClass); + J9ROMClass *romClass = reinterpret_cast(fej9->getPersistentClassPointerFromClassPointer(aotCI->_clazz)); + uintptr_t romClassOffsetInSharedCache = self()->offsetInSharedCacheFromROMClass(sharedCache, romClass); vsfRecord->setInlinedSiteIndex(reloTarget, inlinedSiteIndex); vsfRecord->setConstantPool(reloTarget, reinterpret_cast(aotCI->_constantPool)); @@ -448,8 +472,8 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal TR_ResolvedMethod *inlinedMethod = ((TR_AOTMethodInfo *)ics._methodInfo)->resolvedMethod; TR_OpaqueClassBlock *inlinedCodeClass = reinterpret_cast(inlinedMethod->classOfMethod()); - void *romClass = reinterpret_cast(fej9->getPersistentClassPointerFromClassPointer(inlinedCodeClass)); - uintptr_t romClassOffsetInSharedCache = self()->offsetInSharedCacheFromPointer(sharedCache, romClass); + J9ROMClass *romClass = reinterpret_cast(fej9->getPersistentClassPointerFromClassPointer(inlinedCodeClass)); + uintptr_t romClassOffsetInSharedCache = self()->offsetInSharedCacheFromROMClass(sharedCache, romClass); traceMsg(comp, "class is %p, romclass is %p, offset is %llu\n", inlinedCodeClass, romClass, romClassOffsetInSharedCache); uintptr_t classChainIdentifyingLoaderOffsetInSharedCache = sharedCache->getClassChainOffsetOfIdentifyingLoaderForClazzInSharedCache(inlinedCodeClass); diff --git a/runtime/compiler/codegen/J9AheadOfTimeCompile.hpp b/runtime/compiler/codegen/J9AheadOfTimeCompile.hpp index 9ab3c9ab223..12bef75c923 100644 --- a/runtime/compiler/codegen/J9AheadOfTimeCompile.hpp +++ b/runtime/compiler/codegen/J9AheadOfTimeCompile.hpp @@ -68,10 +68,9 @@ class OMR_EXTENSIBLE AheadOfTimeCompile : public OMR::AheadOfTimeCompileConnecto static bool classAddressUsesReloRecordInfo() { return false; } protected: + /** - * @brief Wrapper around TR_J9SharedCache::isPointerInSharedCache - * - * TR_J9SharedCache::offsetInSharedCacheFromPointer asserts if the pointer + * @brief TR_J9SharedCache::offsetInSharedCacheFrom* asserts if the pointer * passed in does not exist in the SCC. Under HCR, when an agent redefines * a class, it causes the J9Class pointer to stay the same, but the * J9ROMClass pointer changes. This means that if the compiler has a @@ -85,7 +84,7 @@ class OMR_EXTENSIBLE AheadOfTimeCompile : public OMR::AheadOfTimeCompileConnecto * * Calling TR_J9SharedCache::offsetInSharedCacheFromPointer after such a * redefinition could result in an assert. Therefore, this method exists as - * a wrapper around TR_J9SharedCache::isPointerInSharedCache which doesn't + * a wrapper around TR_J9SharedCache::isROMClassInSharedCache which doesn't * assert and conveniently, updates the location referred to by the cacheOffset * pointer passed in as a parameter. * @@ -93,6 +92,25 @@ class OMR_EXTENSIBLE AheadOfTimeCompile : public OMR::AheadOfTimeCompileConnecto * compilation. If the ptr is in the SCC, then the cacheOffset will be updated. * * @param sharedCache pointer to the TR_SharedCache object + * @param romClass J9ROMClass * whose offset in the SCC is required + * @return The offset into the SCC of romClass + */ + uintptr_t offsetInSharedCacheFromROMClass(TR_SharedCache *sharedCache, J9ROMClass *romClass); + + /** + * @brief Same circumstance as offsetInSharedCacheFromROMClass above + * + * @param sharedCache pointer to the TR_SharedCache object + * @param romMethod J9ROMMethod * whose offset in the SCC is required + * @return The offset into the SCC of romMethod + */ + uintptr_t offsetInSharedCacheFromROMMethod(TR_SharedCache *sharedCache, J9ROMMethod *romMethod); + + /** + * @brief Wrapper around TR_J9SharedCache::offsetInSharedCacheFromPointer for + * consistency with the above APIs + * + * @param sharedCache pointer to the TR_SharedCache object * @param ptr pointer whose offset in the SCC is required * @return The offset into the SCC of ptr */ diff --git a/runtime/compiler/control/CompilationThread.cpp b/runtime/compiler/control/CompilationThread.cpp index 28cb59316cf..7a46f8fc7e2 100644 --- a/runtime/compiler/control/CompilationThread.cpp +++ b/runtime/compiler/control/CompilationThread.cpp @@ -7242,7 +7242,7 @@ TR::CompilationInfoPerThreadBase::preCompilationTasks(J9VMThread * vmThread, !TR::CompilationInfo::isCompiled(method) && !entry->isDLTCompile() && !entry->_doNotUseAotCodeFromSharedCache && - fe->sharedCache()->isPointerInSharedCache(J9_CLASS_FROM_METHOD(method)->romClass) && + fe->sharedCache()->isROMClassInSharedCache(J9_CLASS_FROM_METHOD(method)->romClass) && !isMethodIneligibleForAot(method) && (!TR::Options::getAOTCmdLineOptions()->getOption(TR_AOTCompileOnlyFromBootstrap) || fe->isClassLibraryMethod((TR_OpaqueMethodBlock *)method), true) && diff --git a/runtime/compiler/control/HookedByTheJit.cpp b/runtime/compiler/control/HookedByTheJit.cpp index 4c5cf873665..e3a4cbf2b43 100644 --- a/runtime/compiler/control/HookedByTheJit.cpp +++ b/runtime/compiler/control/HookedByTheJit.cpp @@ -460,7 +460,7 @@ static void jitHookInitializeSendTarget(J9HookInterface * * hook, UDATA eventNum // been created before options were processed. TR_J9SharedCache *sc = TR_J9VMBase::get(jitConfig, vmThread, TR_J9VMBase::AOT_VM)->sharedCache(); #if defined(J9VM_INTERP_AOT_COMPILE_SUPPORT) && defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64)) - if (TR_J9VMBase::get(jitConfig, vmThread, TR_J9VMBase::AOT_VM)->sharedCache()->isPointerInSharedCache(J9_CLASS_FROM_METHOD(method)->romClass)) + if (TR_J9VMBase::get(jitConfig, vmThread, TR_J9VMBase::AOT_VM)->sharedCache()->isROMClassInSharedCache(J9_CLASS_FROM_METHOD(method)->romClass)) { PORT_ACCESS_FROM_JAVAVM(jitConfig->javaVM); I_64 sharedQueryTime = 0; @@ -623,7 +623,7 @@ static void jitHookInitializeSendTarget(J9HookInterface * * hook, UDATA eventNum int32_t sigLen = sprintf(buf, "%.*s.%.*s%.*s", className->length, utf8Data(className), name->length, utf8Data(name), signature->length, utf8Data(signature)); printf("Initial: Signature %s Count %d isLoopy %d isAOT %lu is in SCC %d SCCContainsProfilingInfo %d \n",buf,TR::CompilationInfo::getInvocationCount(method),J9ROMMETHOD_HAS_BACKWARDS_BRANCHES(romMethod), TR::Options::sharedClassCache() ? jitConfig->javaVM->sharedClassConfig->existsCachedCodeForROMMethod(vmThread, romMethod) : 0, - TR::Options::sharedClassCache() ? TR_J9VMBase::get(jitConfig, vmThread, TR_J9VMBase::AOT_VM)->sharedCache()->isPointerInSharedCache(J9_CLASS_FROM_METHOD(method)->romClass) : 0,containsInfo) ; fflush(stdout); + TR::Options::sharedClassCache() ? TR_J9VMBase::get(jitConfig, vmThread, TR_J9VMBase::AOT_VM)->sharedCache()->isROMClassInSharedCache(J9_CLASS_FROM_METHOD(method)->romClass) : 0,containsInfo) ; fflush(stdout); } } diff --git a/runtime/compiler/control/JITClientCompilationThread.cpp b/runtime/compiler/control/JITClientCompilationThread.cpp index 4d0277ad7b4..8233e110ff1 100644 --- a/runtime/compiler/control/JITClientCompilationThread.cpp +++ b/runtime/compiler/control/JITClientCompilationThread.cpp @@ -478,8 +478,7 @@ handleServerMessage(JITServer::ClientStream *client, TR_J9VM *fe, JITServer::Mes } // For multi-layered SCC support - std::vector listOfCacheStartAddress; - std::vector listOfCacheSizeBytes; + std::vector listOfCacheDescriptors; if (fe->sharedCache() && fe->sharedCache()->getCacheDescriptorList()) { // The cache descriptor list is linked last to first and is circular, so last->previous == first. @@ -487,14 +486,20 @@ handleServerMessage(JITServer::ClientStream *client, TR_J9VM *fe, JITServer::Mes J9SharedClassCacheDescriptor *curCache = head; do { - listOfCacheStartAddress.push_back((uintptr_t)curCache->cacheStartAddress); - listOfCacheSizeBytes.push_back(curCache->cacheSizeBytes); + ClientSessionData::CacheDescriptor cacheDesc = + { + (uintptr_t)curCache->cacheStartAddress, + curCache->cacheSizeBytes, + (uintptr_t)curCache->romclassStartAddress, + (uintptr_t)curCache->metadataStartAddress + }; + listOfCacheDescriptors.push_back(cacheDesc); curCache = curCache->next; } while (curCache != head); } - client->write(response, vmInfo, listOfCacheStartAddress, listOfCacheSizeBytes); + client->write(response, vmInfo, listOfCacheDescriptors); } break; case MessageType::VM_isPrimitiveArray: @@ -1903,7 +1908,7 @@ handleServerMessage(JITServer::ClientStream *client, TR_J9VM *fe, JITServer::Mes // Collect AOT stats TR_ResolvedJ9Method *resolvedMethod = std::get<0>(methodInfo).remoteMirror; - isRomClassForMethodInSC = fe->sharedCache()->isPointerInSharedCache(J9_CLASS_FROM_METHOD(j9method)->romClass); + isRomClassForMethodInSC = fe->sharedCache()->isROMClassInSharedCache(J9_CLASS_FROM_METHOD(j9method)->romClass); J9Class *j9clazz = (J9Class *) J9_CLASS_FROM_CP(((J9RAMConstantPoolItem *) J9_CP_FROM_METHOD(((J9Method *)j9method)))); TR_OpaqueClassBlock *clazzOfInlinedMethod = fe->convertClassPtrToClassOffset(j9clazz); diff --git a/runtime/compiler/env/J9SharedCache.cpp b/runtime/compiler/env/J9SharedCache.cpp index c5ae670bbaf..9488e4117cb 100644 --- a/runtime/compiler/env/J9SharedCache.cpp +++ b/runtime/compiler/env/J9SharedCache.cpp @@ -52,6 +52,10 @@ log("" format "", ##__VA_ARGS__); \ } +// From CompositeCache.cpp +#define UPDATEPTR(ca) (((uint8_t *)(ca)) + (ca)->updateSRP) +#define SEGUPDATEPTR(ca) (((uint8_t *)(ca)) + (ca)->segmentSRP) + TR_J9SharedCache::TR_J9SharedCacheDisabledReason TR_J9SharedCache::_sharedCacheState = TR_J9SharedCache::UNINITIALIZED; TR_YesNoMaybe TR_J9SharedCache::_sharedCacheDisabledBecauseFull = TR_maybe; UDATA TR_J9SharedCache::_storeSharedDataFailedLength = 0; @@ -319,7 +323,7 @@ TR_J9SharedCache::addHint(J9Method * method, TR_SharedCacheHint theHint) if (scHints.flags == 0) // If no prior hints exist, we can perform a "storeAttachedData" operation { uint32_t bytesToPersist = 0; - + if (!SCfull) { scHints.flags |= newHint; @@ -374,7 +378,7 @@ TR_J9SharedCache::addHint(J9Method * method, TR_SharedCacheHint theHint) if (isFailedValidationHint) scHints.data = 10 * _initialHintSCount; } - else + else { // hint already exists, but maybe we need to update the count if (isFailedValidationHint) @@ -455,14 +459,96 @@ TR_J9SharedCache::isPointerInCache(const J9SharedClassCacheDescriptor *cacheDesc { bool isPointerInCache = false; #if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64)) - uintptr_t ptrValue = (uintptr_t)ptr; - uintptr_t cacheStart = (uintptr_t)cacheDesc->cacheStartAddress; // Inclusive - uintptr_t cacheEnd = cacheStart + cacheDesc->cacheSizeBytes; // Exclusive + uintptr_t ptrValue = reinterpret_cast(ptr); + uintptr_t cacheStart = reinterpret_cast(cacheDesc->cacheStartAddress); // Inclusive + uintptr_t cacheEnd = cacheStart + cacheDesc->cacheSizeBytes; // Exclusive + isPointerInCache = (ptrValue >= cacheStart) && (ptrValue < cacheEnd); #endif return isPointerInCache; } +bool +TR_J9SharedCache::isOffsetInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset) + { + bool isOffsetInCache = false; +#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64)) + uintptr_t decodedOffset = isOffsetFromStart(offset) ? decodeOffsetFromStart(offset) : decodeOffsetFromEnd(offset); + isOffsetInCache = (decodedOffset < cacheDesc->cacheSizeBytes); +#endif + return isOffsetInCache; + } + +bool +TR_J9SharedCache::isPointerInMetadataSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr) + { + bool isPointerInMetadataSection = false; +#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64)) + if (isPointerInCache(cacheDesc, ptr)) + { + uintptr_t ptrValue = reinterpret_cast(ptr); + uintptr_t metadataEndAddress = reinterpret_cast(UPDATEPTR(cacheDesc->cacheStartAddress)); // Inclusive + uintptr_t metadataStartAddress = reinterpret_cast(cacheDesc->metadataStartAddress); // Exclusive + + isPointerInMetadataSection = (ptrValue >= metadataEndAddress) && (ptrValue < metadataStartAddress); + } +#endif + return isPointerInMetadataSection; + } + +bool +TR_J9SharedCache::isOffsetInMetadataSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset) + { + bool isOffsetInMetadataSection = false; +#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64)) + if (isOffsetFromEnd(offset) && isOffsetInCache(cacheDesc, offset)) + { + uintptr_t metadataEndAddress = reinterpret_cast(UPDATEPTR(cacheDesc->cacheStartAddress)); + uintptr_t metadataStartAddress = reinterpret_cast(cacheDesc->metadataStartAddress); + + uintptr_t metadataEndOffset = metadataStartAddress - metadataEndAddress; // Inclusive + + isOffsetInMetadataSection = ((decodeOffsetFromEnd(offset) > 0 ) && (decodeOffsetFromEnd(offset) <= metadataEndOffset)); + } +#endif + return isOffsetInMetadataSection; + } + +bool +TR_J9SharedCache::isPointerInROMClassesSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr) + { + bool isPointerInRomClassesSection = false; +#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64)) + if (isPointerInCache(cacheDesc, ptr)) + { + uintptr_t ptrValue = reinterpret_cast(ptr); + uintptr_t romclassStartAddress = reinterpret_cast(cacheDesc->romclassStartAddress); // Inclusive + uintptr_t romclassEndAddress = reinterpret_cast(SEGUPDATEPTR(cacheDesc->cacheStartAddress)); // Exclusive + + isPointerInRomClassesSection = (ptrValue >= romclassStartAddress) && (ptrValue < romclassEndAddress); + } +#endif + return isPointerInRomClassesSection; + } + +bool +TR_J9SharedCache::isOffsetinROMClassesSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset) + { + bool isOffsetInRomClassesSection = false; +#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64)) + if (isOffsetFromStart(offset) && isOffsetInCache(cacheDesc, offset)) + { + uintptr_t romclassStartAddress = reinterpret_cast(cacheDesc->romclassStartAddress); + uintptr_t romclassEndAddress = reinterpret_cast(SEGUPDATEPTR(cacheDesc->cacheStartAddress)); + + uintptr_t romclassEndOffset = romclassEndAddress - romclassStartAddress; // Exclusive + + isOffsetInRomClassesSection = (decodeOffsetFromStart(offset) < romclassEndOffset); + } +#endif + return isOffsetInRomClassesSection; + } + void * TR_J9SharedCache::pointerFromOffsetInSharedCache(uintptr_t offset) { @@ -471,12 +557,42 @@ TR_J9SharedCache::pointerFromOffsetInSharedCache(uintptr_t offset) { return (void *)ptr; } - TR_ASSERT_FATAL(false, "Shared cache offset out of bounds"); + TR_ASSERT_FATAL(false, "Shared cache offset %d out of bounds", offset); return (void *)ptr; } +void * +TR_J9SharedCache::romStructureFromOffsetInSharedCache(uintptr_t offset) + { + void *romStructure = NULL; + if (isROMStructureOffsetInSharedCache(offset, &romStructure)) + { + return romStructure; + } + TR_ASSERT_FATAL(false, "Shared cache ROM Structure offset %d out of bounds", offset); + return romStructure; + } + +J9ROMClass * +TR_J9SharedCache::romClassFromOffsetInSharedCache(uintptr_t offset) + { + return reinterpret_cast(romStructureFromOffsetInSharedCache(offset)); + } + +J9ROMMethod * +TR_J9SharedCache::romMethodFromOffsetInSharedCache(uintptr_t offset) + { + return reinterpret_cast(romStructureFromOffsetInSharedCache(offset)); + } + +void * +TR_J9SharedCache::ptrToROMClassesSectionFromOffsetInSharedCache(uintptr_t offset) + { + return romStructureFromOffsetInSharedCache(offset); + } + bool -TR_J9SharedCache::isOffsetInSharedCache(uintptr_t offset, void *ptr) +TR_J9SharedCache::isOffsetInSharedCache(uintptr_t encoded_offset, void *ptr) { #if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64)) #if defined(J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE) @@ -485,27 +601,29 @@ TR_J9SharedCache::isOffsetInSharedCache(uintptr_t offset, void *ptr) J9SharedClassCacheDescriptor *curCache = firstCache; do { - if (offset < curCache->cacheSizeBytes) + TR_ASSERT_FATAL(isOffsetFromEnd(encoded_offset), "Shared cache (encoded) offset %lld not from end\n", encoded_offset); + if (isOffsetInMetadataSectionInCache(curCache, encoded_offset)) { if (ptr) { - uintptr_t cacheStart = (uintptr_t)curCache->cacheStartAddress; - *(uintptr_t *)ptr = offset + cacheStart; + uintptr_t metadataStartAddress = reinterpret_cast(curCache->metadataStartAddress); + *reinterpret_cast(ptr) = metadataStartAddress - decodeOffsetFromEnd(encoded_offset); } return true; } - offset -= curCache->cacheSizeBytes; + encoded_offset = encodeOffsetFromEnd(decodeOffsetFromEnd(encoded_offset) - curCache->cacheSizeBytes); curCache = curCache->previous; } while (curCache != firstCache); #else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE + TR_ASSERT_FATAL(isOffsetFromEnd(encoded_offset), "Shared cache (encoded) offset %lld not from end\n", encoded_offset); J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList(); - if (offset < curCache->cacheSizeBytes) + if (isOffsetInMetadataSectionInCache(curCache, encoded_offset)) { if (ptr) { - uintptr_t cacheStart = (uintptr_t)curCache->cacheStartAddress; - *(uintptr_t *)ptr = offset + cacheStart; + uintptr_t metadataStartAddress = reinterpret_cast(curCache->metadataStartAddress); + *reinterpret_cast(ptr) = metadataStartAddress - decodeOffsetFromEnd(encoded_offset); } return true; } @@ -514,6 +632,65 @@ TR_J9SharedCache::isOffsetInSharedCache(uintptr_t offset, void *ptr) return false; } +bool +TR_J9SharedCache::isROMStructureOffsetInSharedCache(uintptr_t encoded_offset, void **romStructurePtr) + { +#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64)) +#if defined(J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE) + // The cache descriptor list is linked last to first and is circular, so last->previous == first. + J9SharedClassCacheDescriptor *firstCache = getCacheDescriptorList()->previous; + J9SharedClassCacheDescriptor *curCache = firstCache; + do + { + TR_ASSERT_FATAL(isOffsetFromStart(encoded_offset), "Shared cache (encoded) offset %lld not from start\n", encoded_offset); + if (isOffsetinROMClassesSectionInCache(curCache, encoded_offset)) + { + if (romStructurePtr) + { + uintptr_t romclassStartAddress = reinterpret_cast(curCache->romclassStartAddress); + *romStructurePtr = reinterpret_cast(romclassStartAddress + decodeOffsetFromStart(encoded_offset)); + } + return true; + } + encoded_offset = encodeOffsetFromStart(decodeOffsetFromStart(encoded_offset) - curCache->cacheSizeBytes); + curCache = curCache->previous; + } + while (curCache != firstCache); +#else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE + TR_ASSERT_FATAL(isOffsetFromStart(encoded_offset), "Shared cache (encoded) offset %lld not from start\n", encoded_offset); + J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList(); + if (isOffsetinROMClassesSectionInCache(curCache, encoded_offset)) + { + if (romStructurePtr) + { + uintptr_t romclassStartAddress = reinterpret_cast(curCache->romclassStartAddress); + *romStructurePtr = reinterpret_cast(romclassStartAddress + decodeOffsetFromStart(encoded_offset)); + } + return true; + } +#endif // J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE +#endif + return false; + } + +bool +TR_J9SharedCache::isROMClassOffsetInSharedCache(uintptr_t offset, J9ROMClass **romClassPtr) + { + return isROMStructureOffsetInSharedCache(offset, reinterpret_cast(romClassPtr)); + } + +bool +TR_J9SharedCache::isROMMethodOffsetInSharedCache(uintptr_t offset, J9ROMMethod **romMethodPtr) + { + return isROMStructureOffsetInSharedCache(offset, reinterpret_cast(romMethodPtr)); + } + +bool +TR_J9SharedCache::isOffsetOfPtrToROMClassesSectionInSharedCache(uintptr_t offset, void **ptr) + { + return isROMStructureOffsetInSharedCache(offset, ptr); + } + uintptr_t TR_J9SharedCache::offsetInSharedCacheFromPointer(void *ptr) { @@ -522,10 +699,40 @@ TR_J9SharedCache::offsetInSharedCacheFromPointer(void *ptr) { return offset; } - TR_ASSERT_FATAL(false, "Shared cache pointer out of bounds"); + TR_ASSERT_FATAL(false, "Shared cache pointer %p out of bounds", ptr); return offset; } +uintptr_t +TR_J9SharedCache::offsetInSharedcacheFromROMStructure(void *romStructure) + { + uintptr_t offset = 0; + if (isROMStructureInSharedCache(romStructure, &offset)) + { + return offset; + } + TR_ASSERT_FATAL(false, "Shared cache ROM Structure pointer %p out of bounds", romStructure); + return offset; + } + +uintptr_t +TR_J9SharedCache::offsetInSharedCacheFromROMClass(J9ROMClass *romClass) + { + return offsetInSharedcacheFromROMStructure(romClass); + } + +uintptr_t +TR_J9SharedCache::offsetInSharedCacheFromROMMethod(J9ROMMethod *romMethod) + { + return offsetInSharedcacheFromROMStructure(romMethod); + } + +uintptr_t +TR_J9SharedCache::offsetInSharedCacheFromPtrToROMClassesSection(void *ptr) + { + return offsetInSharedcacheFromROMStructure(ptr); + } + bool TR_J9SharedCache::isPointerInSharedCache(void *ptr, uintptr_t *cacheOffset) { @@ -537,12 +744,52 @@ TR_J9SharedCache::isPointerInSharedCache(void *ptr, uintptr_t *cacheOffset) J9SharedClassCacheDescriptor *curCache = firstCache; do { - if (isPointerInCache(curCache, ptr)) + if (isPointerInMetadataSectionInCache(curCache, ptr)) + { + if (cacheOffset) + { + uintptr_t metadataStartAddress = reinterpret_cast(curCache->metadataStartAddress); + *cacheOffset = encodeOffsetFromEnd(metadataStartAddress - reinterpret_cast(ptr) + offset); + } + return true; + } + offset += curCache->cacheSizeBytes; + curCache = curCache->previous; + } + while (curCache != firstCache); +#else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE + J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList(); + if (isPointerInMetadataSectionInCache(curCache, ptr)) + { + if (cacheOffset) + { + uintptr_t metadataStartAddress = reinterpret_cast(curCache->metadataStartAddress); + *cacheOffset = encodeOffsetFromEnd(metadataStartAddress - reinterpret_cast(ptr)); + } + return true; + } +#endif // J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE +#endif + return false; + } + +bool +TR_J9SharedCache::isROMStructureInSharedCache(void *romStructure, uintptr_t *cacheOffset) + { +#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64)) +#if defined(J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE) + uintptr_t offset = 0; + // The cache descriptor list is linked last to first and is circular, so last->previous == first. + J9SharedClassCacheDescriptor *firstCache = getCacheDescriptorList()->previous; + J9SharedClassCacheDescriptor *curCache = firstCache; + do + { + if (isPointerInROMClassesSectionInCache(curCache, romStructure)) { if (cacheOffset) { - uintptr_t cacheStart = (uintptr_t)curCache->cacheStartAddress; - *cacheOffset = (uintptr_t)ptr - cacheStart + offset; + uintptr_t romclassStartAddress = reinterpret_cast(curCache->romclassStartAddress); + *cacheOffset = encodeOffsetFromStart(reinterpret_cast(romStructure) - romclassStartAddress + offset); } return true; } @@ -552,12 +799,12 @@ TR_J9SharedCache::isPointerInSharedCache(void *ptr, uintptr_t *cacheOffset) while (curCache != firstCache); #else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList(); - if (isPointerInCache(curCache, ptr)) + if (isPointerInROMClassesSectionInCache(curCache, romStructure)) { if (cacheOffset) { - uintptr_t cacheStart = (uintptr_t)curCache->cacheStartAddress; - *cacheOffset = (uintptr_t)ptr - cacheStart; + uintptr_t romclassStartAddress = reinterpret_cast(curCache->romclassStartAddress); + *cacheOffset = encodeOffsetFromStart(reinterpret_cast(romStructure) - romclassStartAddress); } return true; } @@ -566,6 +813,24 @@ TR_J9SharedCache::isPointerInSharedCache(void *ptr, uintptr_t *cacheOffset) return false; } +bool +TR_J9SharedCache::isROMClassInSharedCache(J9ROMClass *romClass, uintptr_t *cacheOffset) + { + return isROMStructureInSharedCache(romClass, cacheOffset); + } + +bool +TR_J9SharedCache::isROMMethodInSharedCache(J9ROMMethod *romMethod, uintptr_t *cacheOffset) + { + return isROMStructureInSharedCache(romMethod, cacheOffset); + } + +bool +TR_J9SharedCache::isPtrToROMClassesSectionInSharedCache(void *ptr, uintptr_t *cacheOffset) + { + return isROMStructureInSharedCache(ptr, cacheOffset); + } + J9ROMClass * TR_J9SharedCache::startingROMClassOfClassChain(UDATA *classChain) { @@ -573,8 +838,7 @@ TR_J9SharedCache::startingROMClassOfClassChain(UDATA *classChain) TR_ASSERT_FATAL(lengthInBytes >= 2 * sizeof (UDATA), "class chain is too short!"); UDATA romClassOffset = classChain[1]; - void *romClass = pointerFromOffsetInSharedCache(romClassOffset); - return static_cast(romClass); + return romClassFromOffsetInSharedCache(romClassOffset); } // convert an offset into a string of 8 characters @@ -609,7 +873,7 @@ TR_J9SharedCache::rememberClass(J9Class *clazz, bool create) LOG(1, "rememberClass class %p romClass %p %.*s\n", clazz, romClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className)); uintptr_t classOffsetInCache; - if (!isPointerInSharedCache(romClass, &classOffsetInCache)) + if (!isROMClassInSharedCache(romClass, &classOffsetInCache)) { LOG(1,"\trom class not in shared cache, returning\n"); return NULL; @@ -739,7 +1003,7 @@ bool TR_J9SharedCache::writeClassToChain(J9ROMClass *romClass, UDATA * & chainPtr) { uintptr_t classOffsetInCache; - if (!isPointerInSharedCache(romClass, &classOffsetInCache)) + if (!isROMClassInSharedCache(romClass, &classOffsetInCache)) { LOG(3, "\t\tromclass %p not in shared cache, writeClassToChain returning false\n", romClass); return false; @@ -813,7 +1077,7 @@ TR_J9SharedCache::romclassMatchesCachedVersion(J9ROMClass *romClass, UDATA * & c { J9UTF8 * className = J9ROMCLASS_CLASSNAME(romClass); UDATA romClassOffset; - if (!isPointerInSharedCache(romClass, &romClassOffset)) + if (!isROMClassInSharedCache(romClass, &romClassOffset)) return false; LOG(3, "\t\tExamining romclass %p (%.*s) offset %d, comparing to %d\n", romClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className), romClassOffset, *chainPtr); if ((chainPtr > chainEnd) || (romClassOffset != *chainPtr++)) @@ -919,7 +1183,7 @@ TR_J9SharedCache::classMatchesCachedVersion(J9Class *clazz, UDATA *chainData) /* If the pointer isn't the SCC, then return false immmediately * as the map holds offsets into the SCC of romclasses */ - if (!isPointerInSharedCache(romClass, &classOffsetInCache)) + if (!isROMClassInSharedCache(romClass, &classOffsetInCache)) { LOG(1, "\tclass not in shared cache, returning false\n"); return false; @@ -996,7 +1260,7 @@ TR_OpaqueClassBlock * TR_J9SharedCache::lookupClassFromChainAndLoader(uintptr_t *chainData, void *classLoader) { UDATA *ptrToRomClassOffset = chainData+1; - J9ROMClass *romClass = (J9ROMClass *)pointerFromOffsetInSharedCache(*ptrToRomClassOffset); + J9ROMClass *romClass = romClassFromOffsetInSharedCache(*ptrToRomClassOffset); J9UTF8 *className = J9ROMCLASS_CLASSNAME(romClass); TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe()); J9VMThread *vmThread = fej9->getCurrentVMThread(); @@ -1021,7 +1285,7 @@ TR_J9SharedCache::getClassChainOffsetOfIdentifyingLoaderForClazzInSharedCache(TR if (comp) { /* - * TR_J9SharedCache::offsetInSharedCacheFromPointer asserts if the pointer + * TR_J9SharedCache::offsetInSharedCacheFrom* asserts if the pointer * passed in does not exist in the SCC. Under HCR, when an agent redefines * a class, it causes the J9Class pointer to stay the same, but the * J9ROMClass pointer changes. This means that if the compiler has a @@ -1043,7 +1307,7 @@ TR_J9SharedCache::getClassChainOffsetOfIdentifyingLoaderForClazzInSharedCache(TR * compilation. If the ptr is in the SCC, then the cacheOffset will be updated. */ if (!isPointerInSharedCache(classChainIdentifyingLoaderForClazz, &classChainOffsetInSharedCache)) - comp->failCompilation("Failed to find pointer in SCC"); + comp->failCompilation("Failed to find pointer %p in SCC", classChainIdentifyingLoaderForClazz); } else { @@ -1140,7 +1404,7 @@ TR_J9JITServerSharedCache::getClassChainOffsetOfIdentifyingLoaderForClazzInShare uintptr_t classChainOffset = 0; TR_ASSERT(_stream, "stream must be initialized by now"); ClientSessionData *clientData = TR::compInfoPT->getClientData(); - JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazz, clientData, _stream, + JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazz, clientData, _stream, JITServerHelpers::CLASSINFO_CLASS_CHAIN_OFFSET, (void *)&classChainOffset); // Test if cached value of `classChainOffset` is initialized. Ask the client if it's not. // This situation is possible if we cache ClassInfo during a non-AOT compilation. @@ -1148,7 +1412,7 @@ TR_J9JITServerSharedCache::getClassChainOffsetOfIdentifyingLoaderForClazzInShare { _stream->write(JITServer::MessageType::SharedCache_getClassChainOffsetInSharedCache, clazz); classChainOffset = std::get<0>(_stream->read()); - + // If we got a valid value back, cache that if (classChainOffset) { diff --git a/runtime/compiler/env/J9SharedCache.hpp b/runtime/compiler/env/J9SharedCache.hpp index 94f41c1e930..afa693ae9ff 100644 --- a/runtime/compiler/env/J9SharedCache.hpp +++ b/runtime/compiler/env/J9SharedCache.hpp @@ -47,18 +47,45 @@ struct J9SharedDataDescriptor; /** * \brief An interface to the VM's shared class cache. * - * This class provides an interface to the VM's shared class cache as represented by the the descriptors in J9SharedClassConfig::cacheDescriptorList. - * The cache descriptor list is a circular linked list. It is doubly linked when J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE is defined - * or singly linked otherwise. + * This class provides an interface to the VM's shared class cache as represented + * by the the descriptors in J9SharedClassConfig::cacheDescriptorList.The cache + * descriptor list is a circular linked list. It is doubly linked when + * J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE is defined or singly linked otherwise. * - * If J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE is not defined, the list consists of a single element who's next pointer refers back to itself. - * Offsets into the shared cache represent the distance from the start of the cache. Converting between pointers and offsets can be done with - * simple pointer arithmetic. + * If J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE is not defined, the list consists of + * a single element who's next pointer refers back to itself. Offsets into the + * shared cache represent the distance from the start of the rom classes section or + * or start of the metadata section; the offset is then left shifted 1 bit in order + * to use the low bit to determine whether the offset is relative to the start of + * the rom classes section or the start of the metadata section. Converting between + * pointers and offsets can be done with simple pointer arithmetic. * - * If J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE is defined, the head of the list represents the top-most (and therefore writable) - * layer of the shared class cache, the next element represents the (N-1)th layer, and so on. The element previous to the head represents the base layer. - * The list of cache layers can be thought of as a single logical cache starting at layer 0 and ending at layer N. Offsets into the shared cache - * represent the distance from the start of the cache. Converting between pointers and offsets requires traversing the list starting at the base layer. + * If J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE is defined, the head of the list + * represents the top-most (and therefore writable) layer of the shared class cache, + * the next element represents the (N-1)th layer, and so on. The element previous to + * the head represents the base layer. The list of cache layers can be thought of as + * a single logical cache starting at layer 0 and ending at layer N. Offsets into the + * shared cache represent the distance from the start of the cache. Converting + * between pointers and offsets requires traversing the list starting at the base + * layer. + * + * The layout of section of the SCC relevant for this class is: + * + * Increasing Address -----> + * *-------------*------------------*----------* + * | ROM CLASSES |---> FREE <---| METADATA | + * *-------------*------------------*----------* + * ^ ^ ^ ^ + * | | | | + * | | | cacheDesc->metadataStartAddress + * | | | + * | | UPDATEPTR(cacheDesc->cacheStartAddress) + * | | + * | SEGUPDATEPTR(cacheDesc->cacheStartAddress) + * | + * cacheDesc->romclassStartAddress + * + * See CompositeCache.cpp for more details. */ class TR_J9SharedCache : public TR_SharedCache { @@ -75,7 +102,8 @@ class TR_J9SharedCache : public TR_SharedCache virtual bool isMostlyFull(); /** - * \brief Converts a shared cache offset into a pointer. + * \brief Converts a shared cache offset, calculated from the end of the SCC, into the + * metadata section of the SCC into a pointer. * * \param[in] offset The offset to convert. * \return A pointer. Raises a fatal assertion before returning NULL if the offset is invalid. @@ -83,13 +111,63 @@ class TR_J9SharedCache : public TR_SharedCache virtual void *pointerFromOffsetInSharedCache(uintptr_t offset); /** - * \brief Converts a pointer into the shared cache into an offset. + * \brief Converts a pointer into the metadata section of the SCC into an offset, calculated + * from the end of the SCC. * * \param[in] ptr The pointer to convert. * \return An offset. Raises a fatal assertion before returning 0 if the pointer is invalid. */ virtual uintptr_t offsetInSharedCacheFromPointer(void *ptr); + /** + * \brief Converts an offset into the ROMClass section into a J9ROMClass *. + * + * \param[in] offset The offset to convert. + * \return A J9ROMClass *. Raises a fatal assertion before returning NULL if the offset is invalid. + */ + virtual J9ROMClass *romClassFromOffsetInSharedCache(uintptr_t offset); + + /** + * \brief Converts a J9ROMClass * pointer into the SCC into an offset. + * + * \param[in] romClass The J9ROMClass * to convert + * \return An offset. Raises a fatal assertion before returning 0 if the pointer is invalid. + */ + virtual uintptr_t offsetInSharedCacheFromROMClass(J9ROMClass *romClass); + + /** + * \brief Converts an offset into the ROMClass section into a J9ROMMethod *. + * + * \param[in] offset The offset to convert + * \return A J9ROMMethod *. Raises a fatal assertion before returning NULL if the offset is invalid. + */ + virtual J9ROMMethod *romMethodFromOffsetInSharedCache(uintptr_t offset); + + /** + * \brief Converts a J9ROMMethod * pointer into the SCC into an offset. + * + * \param[in] romMethod The J9ROMMethod * to convert + * \return An offset. Raises a fatal assertion before returning 0 if the pointer is invalid. + */ + virtual uintptr_t offsetInSharedCacheFromROMMethod(J9ROMMethod *romMethod); + + /** + * \brief Converts an offset into the ROMClass section into a pointer. + * + * \param[in] offset The offset to convert + * \return A pointer. Raises a fatal assertion before returning NULL if the offset is invalid. + */ + virtual void *ptrToROMClassesSectionFromOffsetInSharedCache(uintptr_t offset); + + /** + * \brief Converts a pointer into the ROM Classes section of the SCC into an offset. + * + * \param[in] ptr The pointer to convert + * \return An offset. Raises a fatal assertion before returning 0 if the pointer is invalid. + */ + virtual uintptr_t offsetInSharedCacheFromPtrToROMClassesSection(void *ptr); + + virtual void persistIprofileInfo(TR::ResolvedMethodSymbol *, TR::Compilation *comp); virtual void persistIprofileInfo(TR::ResolvedMethodSymbol *, TR_ResolvedMethod*, TR::Compilation *comp); @@ -117,22 +195,102 @@ class TR_J9SharedCache : public TR_SharedCache virtual TR_OpaqueClassBlock *lookupClassFromChainAndLoader(uintptr_t *chainData, void *classLoader); /** - * \brief Checks whether the specified pointer points into the shared cache. + * \brief Checks whether the specified pointer points into the metadata section + * of the shared cache. * * \param[in] ptr The pointer to check. - * \param[out] cacheOffset If ptr points into the shared cache and this parameter is not NULL the result of converting ptr into an offset will be returned here. If ptr does not point into the shared cache this parameter is ignored. + * \param[out] cacheOffset If ptr points into the shared cache and this parameter + * is not NULL the result of converting ptr into an offset will be + * returned here. If ptr does not point into the shared cache this + * parameter is ignored. The offset is calculated from the end of + * the SCC. * \return True if the pointer points into the shared cache, false otherwise. */ virtual bool isPointerInSharedCache(void *ptr, uintptr_t *cacheOffset = NULL); /** - * \brief Checks whether the specified offset is within the shared cache. + * \brief Checks whether the specified offset, calculated from the end of the SCC, + * is within the metadata section of the shared cache. + * + * \param[in] offset The offset to check. + * \param[out] ptr If offset is within the shared cache and this parameter is not + * NULL the result of converting offset into a pointer will be returned + * here. If offset is not within the shared cache this parameter is ignored. + * \return True if the offset is within the shared cache, false otherwise. + */ + virtual bool isOffsetInSharedCache(uintptr_t encoded_offset, void *ptr = NULL); + + /** + * \brief Checks whether the specified J9ROMClass exists in the SCC + * + * \param[in] romClass The J9ROMClass * to check + * \param[out] cacheOffset If the J9ROMClass is in the SCC and this parameter + * is not NULL the result of converting romClass into an offset will + * be returned here. If romClass does not point into the SCC, this + * parameter is ignored. + * \return True if romClass points into the SCC, false otherwise. + */ + virtual bool isROMClassInSharedCache(J9ROMClass *romClass, uintptr_t *cacheOffset = NULL); + + /** + * \brief Checks whether the specified offset is within the ROMClass section + * of the shared cache. + * + * \param[in] offset The offset to check + * \param[out] romClass If offset is within the shared cache and this parameter is not + * NULL the result of converting offset into a J9ROMClass * will be returned + * here. If offset is not within the shared cache this parameter is ignored. + * \return True if the offset is within the shared cache, false otherwise. + */ + virtual bool isROMClassOffsetInSharedCache(uintptr_t offset, J9ROMClass **romClassPtr = NULL); + + /** + * \brief Checks whether the specified J9ROMMethod exists in the SCC + * + * \param[in] romMethod The J9ROMMethod * to check + * \param[out] cacheOffset If the J9ROMMethod is in the SCC and this parameter + * is not NULL the result of converting romMethod into an offset will + * be returned here. If romMethod does not point into the SCC, this + * parameter is ignored. + * \return True if romMethod points into the SCC, false otherwise. + */ + virtual bool isROMMethodInSharedCache(J9ROMMethod *romMethod, uintptr_t *cacheOffset = NULL); + + /** + * \brief Checks whether the specified offset is within the ROMClass section + * of the shared cache. + * \param[in] offset The offset to check + * \param[out] romMethodPtr If offset is within the shared cache and this parameter is not + * NULL the result of converting offset into a J9ROMMethod * will be returned + * here. If offset is not within the shared cache this parameter is ignored. + * \return True if the offset is within the shared cache, false otherwise. + */ + virtual bool isROMMethodOffsetInSharedCache(uintptr_t offset, J9ROMMethod **romMethodPtr = NULL); + + /** + * \brief Checks whether the specified pointer points into the ROMClass section + * of the shared cache. + * + * \param[in] ptr The pointer to check + * \param[out] cacheOffset If ptr points into the shared cache and this parameter + * is not NULL the result of converting ptr into an offset will be + * returned here. If ptr does not point into the shared cache this + * parameter is ignored. + * \return True if the pointer points into the shared cache, false otherwise. + */ + virtual bool isPtrToROMClassesSectionInSharedCache(void *ptr, uintptr_t *cacheOffset = NULL); + + /** + * \brief Checks whether the specified offset is within the ROMClass section + * of the shared cache. * * \param[in] offset The offset to check. - * \param[out] ptr If offset is within the shared cache and this parameter is not NULL the result of converting offset into a pointer will be returned here. If offset is not within the shared cache this parameter is ignored. + * \param[out] ptr If offset is within the shared cache and this parameter is not + * NULL the result of converting offset into a pointer will be returned + * here. If offset is not within the shared cache this parameter is ignored. * \return True if the offset is within the shared cache, false otherwise. */ - virtual bool isOffsetInSharedCache(uintptr_t offset, void *ptr = NULL); + virtual bool isOffsetOfPtrToROMClassesSectionInSharedCache(uintptr_t offset, void **ptr = NULL); J9ROMClass *startingROMClassOfClassChain(UDATA *classChain); @@ -173,6 +331,32 @@ class TR_J9SharedCache : public TR_SharedCache virtual J9SharedClassCacheDescriptor *getCacheDescriptorList(); +protected: + /** + * \brief Helper method; used to check if a pointer is within the SCC + * + * \param[in] cacheDesc the J9SharedClassCacheDescriptor for the cache + * \param[in] ptr The pointer to check + * \return True if ptr is within the SCC, false otherwise + */ + static bool isPointerInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr); + + /** + * \brief Helper method; used to check if an offset is within the SCC + * + * \param[in] cacheDesc the J9SharedClassCacheDescriptor for the cache + * \param[in] offset the offset to check + * \return True if offset is within the SCC, false otherwise + */ + static bool isOffsetInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset); + + static inline bool isOffsetFromStart(uintptr_t offset) { return ((offset & OFFSET_FROM_END) != OFFSET_FROM_END); } + static inline bool isOffsetFromEnd(uintptr_t offset) { return ((offset & OFFSET_FROM_END) == OFFSET_FROM_END); } + static inline uintptr_t encodeOffsetFromStart(uintptr_t offset) { return (offset << 1); } + static inline uintptr_t decodeOffsetFromStart(uintptr_t offset) { return (offset >> 1); } + static inline uintptr_t encodeOffsetFromEnd(uintptr_t offset) { return ((offset << 1) | OFFSET_FROM_END); } + static inline uintptr_t decodeOffsetFromEnd(uintptr_t offset) { return (offset >> 1); } + private: // This class is intended to be a POD; keep it simple. struct SCCHint @@ -183,6 +367,8 @@ class TR_J9SharedCache : public TR_SharedCache uint16_t data; }; + static const uintptr_t OFFSET_FROM_END = 0x1; + J9JITConfig *jitConfig() { return _jitConfig; } J9JavaVM *javaVM() { return _javaVM; } TR_J9VMBase *fe() { return _fe; } @@ -209,54 +395,127 @@ class TR_J9SharedCache : public TR_SharedCache UDATA *findChainForClass(J9Class *clazz, const char *key, uint32_t keyLength); /** - * @brief Validates the provided class chain. This method modifies the chainPtr arg. + * \brief Helper Method; Converts an offset into the ROMClass section into a pointer. + * + * \param offset The offset to convert + * \return A pointer. Raises a fatal assertion before returning NULL if the offset is invalid. + */ + void *romStructureFromOffsetInSharedCache(uintptr_t offset); + + /** + * \brief Converts a pointer into the ROMClass section of the SCC into an offset. + * + * \param[in] romStructure The pointer to convert. + * \return An offset. Raises a fatal assertion before returning 0 if the pointer is invalid. + */ + uintptr_t offsetInSharedcacheFromROMStructure(void *romStructure); + + /** + * \brief Checks whether the specified pointer points into the ROMClass section + * of the shared cache. + * + * \param[in] romStructure The pointer to check + * \param[out] cacheOffset If romStructure points into the shared cache and this parameter + * is not NULL the result of converting romStructure into an offset will be + * returned here. If romStructure does not point into the shared cache this + * parameter is ignored. + * \return True if the pointer points into the shared cache, false otherwise. + */ + bool isROMStructureInSharedCache(void *romStructure, uintptr_t *cacheOffset = NULL); + + /** + * \brief Checks whether the specified offset is within the ROMClass section + * of the shared cache. + * + * \param[in] offset The offset to check. + * \param[out] romStructurePtr If offset is within the shared cache and this parameter is not + * NULL the result of converting offset into a pointer will be returned + * here. If offset is not within the shared cache this parameter is ignored. + * \return True if the offset is within the shared cache, false otherwise. + */ + bool isROMStructureOffsetInSharedCache(uintptr_t encoded_offset, void **romStructurePtr = NULL); + + /** + * \brief Validates the provided class chain. This method modifies the chainPtr arg. * - * @param romClass The J9ROMClass of the class whose chain is to be validated - * @param clazz The TR_OpaqueClassBlock of the class whose chain is to be validated - * @param chainPtr Pointer to the start of the class chain passed by reference - * @param chainEnd Pointer to the end of the class chain - * @return true if validation succeeded, false otherwise. + * \param[in] romClass The J9ROMClass of the class whose chain is to be validated + * \param[in] clazz The TR_OpaqueClassBlock of the class whose chain is to be validated + * \param[in,out] chainPtr Pointer to the start of the class chain passed by reference + * \param[in] chainEnd Pointer to the end of the class chain + * \return true if validation succeeded, false otherwise. */ bool validateClassChain(J9ROMClass *romClass, TR_OpaqueClassBlock *clazz, UDATA * & chainPtr, UDATA *chainEnd); /** - * @brief Validates the super classes portion of the class chain. This method modifies the chainPtr arg. + * \brief Validates the super classes portion of the class chain. This method modifies the chainPtr arg. * - * @param clazz The TR_OpaqueClassBlock of the class whose chain is to be validated - * @param chainPtr Pointer to the start of super classes portion of the class chain passed by reference - * @param chainEnd Pointer to the end of the class chain - * @return true if validation succeeded, false otherwise. + * \param[in] clazz The TR_OpaqueClassBlock of the class whose chain is to be validated + * \param[in,out] chainPtr Pointer to the start of super classes portion of the class chain passed by reference + * \param[in] chainEnd Pointer to the end of the class chain + * \return true if validation succeeded, false otherwise. */ bool validateSuperClassesInClassChain(TR_OpaqueClassBlock *clazz, UDATA * & chainPtr, UDATA *chainEnd); /** - * @brief Validates the interfaces portion of the class chain. This method modifies the chainPtr arg. + * \brief Validates the interfaces portion of the class chain. This method modifies the chainPtr arg. * - * @param clazz The TR_OpaqueClassBlock of the class whose chain is to be validated - * @param chainPtr Pointer to the start of interfaces portion of the class chain passed by reference - * @param chainEnd Pointer to the end of the class chain - * @return true if validation succeeded, false otherwise. + * \param[in] clazz The TR_OpaqueClassBlock of the class whose chain is to be validated + * \param[in,out] chainPtr Pointer to the start of interfaces portion of the class chain passed by reference + * \param[in] chainEnd Pointer to the end of the class chain + * \return true if validation succeeded, false otherwise. */ bool validateInterfacesInClassChain(TR_OpaqueClassBlock *clazz, UDATA * & chainPtr, UDATA *chainEnd); - static bool isPointerInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr); + /** + * \brief Helper method; used to check if a pointer is within the metadata section of the SCC + * \param[in] cacheDesc the J9SharedClassCacheDescriptor for the cache + * \param[in] ptr The pointer to check + * \return True if ptr is within the metadata section of the SCC, false otherwise + */ + virtual bool isPointerInMetadataSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr); /** - * @brief Gets the cached result of a prior class chain validation + * \brief Helper method; used to check if an offset is within the metadata section of the SCC * - * @param clazz The class to be validated + * \param[in] cacheDesc the J9SharedClassCacheDescriptor for the cache + * \param[in] offset the offset to check + * \return True if offset is within the metadata section of the SCC, false otherwise + */ + virtual bool isOffsetInMetadataSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset); + + /** + * \brief Helper method; used to check if a pointer is within the ROMClass section of the SCC + * \param[in] cacheDesc the J9SharedClassCacheDescriptor for the cache + * \param[in] ptr The pointer to check + * \return True if ptr is within the ROMClass section of the SCC, false otherwise + */ + virtual bool isPointerInROMClassesSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr); + + /** + * \brief Helper method; used to check if an offset is within the ROMClass section of the SCC * - * @return The cached CCVResult; CCVResult::notYetValidated if result does not exist. + * \param[in] cacheDesc the J9SharedClassCacheDescriptor for the cache + * \param[in] offset the offset to check + * \return True if offset is within the ROMClass section of the SCC, false otherwise + */ + virtual bool isOffsetinROMClassesSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset); + + /** + * \brief Gets the cached result of a prior class chain validation + * + * \param[in] clazz The class to be validated + * + * \return The cached CCVResult; CCVResult::notYetValidated if result does not exist. */ const CCVResult getCachedCCVResult(TR_OpaqueClassBlock *clazz); /** - * @brief Caches the result of a class chain validation + * \brief Caches the result of a class chain validation * - * @param clazz The class to be validated - * @param result The result represented as a CCVResult + * \param[in] clazz The class to be validated + * \param[in] result The result represented as a CCVResult * - * @return The result of the insertion + * \return The result of the insertion */ bool cacheCCVResult(TR_OpaqueClassBlock *clazz, CCVResult result); @@ -283,8 +542,8 @@ class TR_J9SharedCache : public TR_SharedCache #if defined(J9VM_OPT_JITSERVER) /** -* @class TR_J9JITServerSharedCache -* @brief Class used by JITServer for querying client-side SharedCache information +* \class TR_J9JITServerSharedCache +* \brief Class used by JITServer for querying client-side SharedCache information * * This class is an extension of the TR_J9SharedCache class which overrides a number * of TR_J9SharedCache's APIs. TR_J9JITServerSharedCache is used by JITServer and @@ -330,6 +589,24 @@ class TR_J9JITServerSharedCache : public TR_J9SharedCache virtual const void *storeSharedData(J9VMThread *vmThread, char *key, J9SharedDataDescriptor *descriptor); private: + + virtual bool isPointerInMetadataSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr) + { + return isPointerInCache(cacheDesc, ptr); + } + virtual bool isOffsetInMetadataSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset) + { + return (isOffsetFromEnd(offset) && isOffsetInCache(cacheDesc, offset)); + } + virtual bool isPointerInROMClassesSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr) + { + return isPointerInCache(cacheDesc, ptr); + } + virtual bool isOffsetinROMClassesSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset) + { + return (isOffsetFromStart(offset) && isOffsetInCache(cacheDesc, offset)); + } + JITServer::ServerStream *_stream; }; #endif /* defined(J9VM_OPT_JITSERVER) */ diff --git a/runtime/compiler/env/SharedCache.hpp b/runtime/compiler/env/SharedCache.hpp index d2f8eb8b4fa..7c026cc3c3c 100644 --- a/runtime/compiler/env/SharedCache.hpp +++ b/runtime/compiler/env/SharedCache.hpp @@ -23,6 +23,7 @@ #ifndef SHARED_CACHE_HPP #define SHARED_CACHE_HPP +#include "j9.h" #include "env/jittypes.h" class TR_PersistentClassLoaderTable; @@ -43,8 +44,23 @@ class TR_SharedCache virtual void *pointerFromOffsetInSharedCache(uintptr_t offset) { return NULL; } virtual uintptr_t offsetInSharedCacheFromPointer(void *ptr) { return 0; } - virtual bool isPointerInSharedCache(void *ptr, uintptr_t *cacheOffset = NULL) { return false; } + virtual bool isOffsetInSharedCache(uintptr_t offset, void *ptr = NULL) { return false; } + + virtual J9ROMClass *romClassFromOffsetInSharedCache(uintptr_t offset) { return NULL; } + virtual uintptr_t offsetInSharedCacheFromROMClass(J9ROMClass *romClass) { return 0; } + virtual bool isROMClassInSharedCache(J9ROMClass *romClass, uintptr_t *cacheOffset = NULL) { return false; } + virtual bool isROMClassOffsetInSharedCache(uintptr_t offset, J9ROMClass **romClassPtr = NULL) { return false; } + + virtual J9ROMMethod *romMethodFromOffsetInSharedCache(uintptr_t offset) { return NULL; } + virtual uintptr_t offsetInSharedCacheFromROMMethod(J9ROMMethod *romMethod) { return 0; } + virtual bool isROMMethodInSharedCache(J9ROMMethod *romMethod, uintptr_t *cacheOffset = NULL) { return false; } + virtual bool isROMMethodOffsetInSharedCache(uintptr_t offset, J9ROMMethod **romMethodPtr = NULL) { return false; } + + virtual void *ptrToROMClassesSectionFromOffsetInSharedCache(uintptr_t offset) { return NULL; } + virtual uintptr_t offsetInSharedCacheFromPtrToROMClassesSection(void *ptr) { return 0; } + virtual bool isPtrToROMClassesSectionInSharedCache(void *ptr, uintptr_t *cacheOffset = NULL) { return false; } + virtual bool isOffsetOfPtrToROMClassesSectionInSharedCache(uintptr_t offset, void **ptr = NULL) { return false; } virtual TR_OpaqueClassBlock *lookupClassFromChainAndLoader(uintptr_t *cinaData, void *loader) { return NULL; } diff --git a/runtime/compiler/env/j9method.cpp b/runtime/compiler/env/j9method.cpp index 45accc4e774..2dc496337c8 100644 --- a/runtime/compiler/env/j9method.cpp +++ b/runtime/compiler/env/j9method.cpp @@ -1130,7 +1130,7 @@ static intptr_t getInitialCountForMethod(TR_ResolvedMethod *rm, TR::Compilation J9ROMClass *romClass = m->romClassPtr(); J9ROMMethod *romMethod = m->romMethod(); - if (!comp->fej9()->sharedCache()->isPointerInSharedCache(romClass)) + if (!comp->fej9()->sharedCache()->isROMClassInSharedCache(romClass)) { #if defined(J9ZOS390) // Do not change the counts on zos at the moment since the shared cache capacity is higher on this platform @@ -2215,7 +2215,7 @@ TR_ResolvedRelocatableJ9Method::createResolvedMethodFromJ9Method(TR::Compilation isSystemClassLoader = ((void*)_fe->vmThread()->javaVM->systemClassLoader->classLoaderObject == (void*)_fe->getClassLoader(clazzOfInlinedMethod)); } - bool methodInSCC = _fe->sharedCache()->isPointerInSharedCache(J9_CLASS_FROM_METHOD(j9method)->romClass); + bool methodInSCC = _fe->sharedCache()->isROMClassInSharedCache(J9_CLASS_FROM_METHOD(j9method)->romClass); if (methodInSCC) { bool sameLoaders = false; diff --git a/runtime/compiler/env/j9methodServer.cpp b/runtime/compiler/env/j9methodServer.cpp index 8ac2199c7b6..55379c15ace 100644 --- a/runtime/compiler/env/j9methodServer.cpp +++ b/runtime/compiler/env/j9methodServer.cpp @@ -1612,7 +1612,7 @@ TR_ResolvedJ9JITServerMethod::createResolvedMethodFromJ9MethodMirror(TR_Resolved isSystemClassLoader = ((void*)fej9->vmThread()->javaVM->systemClassLoader->classLoaderObject == (void*)fej9->getClassLoader(clazzOfInlinedMethod)); } - if (fej9->sharedCache()->isPointerInSharedCache(J9_CLASS_FROM_METHOD(j9method)->romClass)) + if (fej9->sharedCache()->isROMClassInSharedCache(J9_CLASS_FROM_METHOD(j9method)->romClass)) { bool sameLoaders = false; TR_J9VMBase *fej9 = (TR_J9VMBase *)fe; diff --git a/runtime/compiler/net/CommunicationStream.hpp b/runtime/compiler/net/CommunicationStream.hpp index 536c0f7fa67..c7bf7846865 100644 --- a/runtime/compiler/net/CommunicationStream.hpp +++ b/runtime/compiler/net/CommunicationStream.hpp @@ -102,7 +102,7 @@ class CommunicationStream ClientMessage _cMsg; static const uint8_t MAJOR_NUMBER = 1; - static const uint16_t MINOR_NUMBER = 9; + static const uint16_t MINOR_NUMBER = 10; static const uint8_t PATCH_NUMBER = 0; static uint32_t CONFIGURATION_FLAGS; diff --git a/runtime/compiler/p/codegen/J9AheadOfTimeCompile.cpp b/runtime/compiler/p/codegen/J9AheadOfTimeCompile.cpp index 051a143f0e6..497bcc257f6 100644 --- a/runtime/compiler/p/codegen/J9AheadOfTimeCompile.cpp +++ b/runtime/compiler/p/codegen/J9AheadOfTimeCompile.cpp @@ -852,7 +852,7 @@ uint8_t *J9::Power::AheadOfTimeCompile::initializeAOTRelocationHeader(TR::Iterat // Store rom method to get name of method J9Method *methodToValidate = reinterpret_cast(record->_method); J9ROMMethod *romMethod = static_cast(fej9)->getROMMethodFromRAMMethod(methodToValidate); - uintptr_t romMethodOffsetInSharedCache = self()->offsetInSharedCacheFromPointer(sharedCache, romMethod); + uintptr_t romMethodOffsetInSharedCache = self()->offsetInSharedCacheFromROMMethod(sharedCache, romMethod); binaryTemplate->_methodID = symValManager->getIDFromSymbol(static_cast(record->_method)); binaryTemplate->_definingClassID = symValManager->getIDFromSymbol(static_cast(record->definingClass())); diff --git a/runtime/compiler/runtime/IProfiler.cpp b/runtime/compiler/runtime/IProfiler.cpp index bffc7c225d0..a1cac364d54 100644 --- a/runtime/compiler/runtime/IProfiler.cpp +++ b/runtime/compiler/runtime/IProfiler.cpp @@ -398,9 +398,9 @@ TR_IProfiler::persistIprofileInfo(TR::ResolvedMethodSymbol *resolvedMethodSymbol int32_t currentCount = resolvedMethod->getInvocationCount(); // can only persist profile info if the method is in the shared cache - if (comp->fej9()->sharedCache()->isPointerInSharedCache(romMethod)) + if (comp->fej9()->sharedCache()->isROMMethodInSharedCache(romMethod)) { - TR_ASSERT(comp->fej9()->sharedCache()->isPointerInSharedCache((void *)methodStart), "bytecodes not in shared cache"); + TR_ASSERT(comp->fej9()->sharedCache()->isPtrToROMClassesSectionInSharedCache((void *)methodStart), "bytecodes not in shared cache"); // check if there is already an entry unsigned char storeBuffer[1000]; uint32_t bufferLength = 1000; @@ -1259,7 +1259,7 @@ TR_IProfiler::persistentProfilingSample(TR_OpaqueMethodBlock *method, uint32_t b void *methodStart = (void *)TR::Compiler->mtd.bytecodeStart(method); // can only persist profile info if the method is in the shared cache - if (!comp->fej9()->sharedCache()->isPointerInSharedCache(methodStart)) + if (!comp->fej9()->sharedCache()->isPtrToROMClassesSectionInSharedCache(methodStart)) return NULL; // check the shared cache @@ -1281,7 +1281,7 @@ TR_IProfiler::persistentProfilingSample(TR_OpaqueMethodBlock *method, uint32_t b *methodProfileExistsInSCC = true; // Compute the pc we are interested in uintptr_t pc = getSearchPC(method, byteCodeIndex, comp); - store = searchForPersistentSample(store, (uintptr_t)comp->fej9()->sharedCache()->offsetInSharedCacheFromPointer((void *)pc)); + store = searchForPersistentSample(store, (uintptr_t)comp->fej9()->sharedCache()->offsetInSharedCacheFromPtrToROMClassesSection((void *)pc)); if (TR::Options::getAOTCmdLineOptions()->getOption(TR_EnableIprofilerChanges) || TR::Options::getJITCmdLineOptions()->getOption(TR_EnableIprofilerChanges)) { @@ -1332,12 +1332,12 @@ TR_IProfiler::persistentProfilingSample(TR_OpaqueMethodBlock *method, uint32_t b void *methodStart = (void *) TR::Compiler->mtd.bytecodeStart(method); // can only persist profile info if the method is in the shared cache - if (!comp->fej9()->sharedCache()->isPointerInSharedCache(methodStart)) + if (!comp->fej9()->sharedCache()->isPtrToROMClassesSectionInSharedCache(methodStart)) return NULL; *methodProfileExistsInSCC = true; void *pc = (void *)getSearchPC(method, byteCodeIndex, comp); - store = searchForPersistentSample(store, (uintptr_t)comp->fej9()->sharedCache()->offsetInSharedCacheFromPointer(pc)); + store = searchForPersistentSample(store, (uintptr_t)comp->fej9()->sharedCache()->offsetInSharedCacheFromPtrToROMClassesSection(pc)); return store; } return NULL; @@ -2627,7 +2627,7 @@ void TR_IPBCDataFourBytes::createPersistentCopy(TR_J9SharedCache *sharedCache, TR_IPBCDataStorageHeader *storage, TR::PersistentInfo *info) { TR_IPBCDataFourBytesStorage * store = (TR_IPBCDataFourBytesStorage *) storage; - uintptr_t offset = (uintptr_t)sharedCache->offsetInSharedCacheFromPointer((void *)_pc); + uintptr_t offset = (uintptr_t)sharedCache->offsetInSharedCacheFromPtrToROMClassesSection((void *)_pc); TR_ASSERT_FATAL(offset <= UINT_MAX, "Offset too large for TR_IPBCDataFourBytes"); storage->pc = (uint32_t)offset; storage->left = 0; @@ -2676,7 +2676,7 @@ void TR_IPBCDataEightWords::createPersistentCopy(TR_J9SharedCache *sharedCache, TR_IPBCDataStorageHeader *storage, TR::PersistentInfo *info) { TR_IPBCDataEightWordsStorage * store = (TR_IPBCDataEightWordsStorage *) storage; - uintptr_t offset = (uintptr_t)sharedCache->offsetInSharedCacheFromPointer((void *)_pc); + uintptr_t offset = (uintptr_t)sharedCache->offsetInSharedCacheFromPtrToROMClassesSection((void *)_pc); TR_ASSERT_FATAL(offset <= UINT_MAX, "Offset too large for TR_IPBCDataEightWords"); storage->pc = (uint32_t)offset; storage->ID = TR_IPBCD_EIGHT_WORDS; @@ -3062,7 +3062,7 @@ TR_IPBCDataCallGraph::canBePersisted(TR_J9SharedCache *sharedCache, TR::Persiste return IPBC_ENTRY_PERSIST_UNLOADED; } - if (!sharedCache->isPointerInSharedCache(clazz->romClass)) + if (!sharedCache->isROMClassInSharedCache(clazz->romClass)) { releaseEntry(); // release the lock on the entry return IPBC_ENTRY_PERSIST_NOTINSCC; @@ -3077,7 +3077,7 @@ void TR_IPBCDataCallGraph::createPersistentCopy(TR_J9SharedCache *sharedCache, TR_IPBCDataStorageHeader *storage, TR::PersistentInfo *info) { TR_IPBCDataCallGraphStorage * store = (TR_IPBCDataCallGraphStorage *) storage; - uintptr_t offset = (uintptr_t)sharedCache->offsetInSharedCacheFromPointer((void *)_pc); + uintptr_t offset = (uintptr_t)sharedCache->offsetInSharedCacheFromPtrToROMClassesSection((void *)_pc); TR_ASSERT_FATAL(offset <= UINT_MAX, "Offset too large for TR_IPBCDataCallGraph"); storage->pc = (uint32_t)offset; storage->ID = TR_IPBCD_CALL_GRAPH; @@ -3111,9 +3111,9 @@ TR_IPBCDataCallGraph::createPersistentCopy(TR_J9SharedCache *sharedCache, TR_IPB * performance, in order to prevent an issue in loadFromPersistentCopy, check again whether * the romClass is within the SCC. */ - if (sharedCache->isPointerInSharedCache(clazz->romClass)) + if (sharedCache->isROMClassInSharedCache(clazz->romClass)) { - store->_csInfo.setClazz(i, (uintptr_t)sharedCache->offsetInSharedCacheFromPointer(clazz->romClass)); + store->_csInfo.setClazz(i, (uintptr_t)sharedCache->offsetInSharedCacheFromROMClass(clazz->romClass)); TR_ASSERT(_csInfo.getClazz(i), "Race condition detected: cached value=%p, pc=%p", clazz, _pc); } else @@ -3146,10 +3146,10 @@ TR_IPBCDataCallGraph::loadFromPersistentCopy(TR_IPBCDataStorageHeader * storage, if (store->_csInfo.getClazz(i)) { J9Class *ramClass = NULL; - uintptr_t romClass = 0; + J9ROMClass *romClass = 0; uintptr_t csInfoClazzOffset = store->_csInfo.getClazz(i); - if (comp->fej9()->sharedCache()->isOffsetInSharedCache(csInfoClazzOffset, &romClass)) + if (comp->fej9()->sharedCache()->isROMClassOffsetInSharedCache(csInfoClazzOffset, &romClass)) ramClass = ((TR_J9VM *)comp->fej9())->matchRAMclassFromROMclass((J9ROMClass *)romClass, comp); if (ramClass) diff --git a/runtime/compiler/runtime/JITClientSession.cpp b/runtime/compiler/runtime/JITClientSession.cpp index 1fa33942cbd..199003b9614 100644 --- a/runtime/compiler/runtime/JITClientSession.cpp +++ b/runtime/compiler/runtime/JITClientSession.cpp @@ -370,24 +370,27 @@ ClientSessionData::getOrCacheVMInfo(JITServer::ServerStream *stream) if (!_vmInfo) { stream->write(JITServer::MessageType::VM_getVMInfo, JITServer::Void()); - auto recv = stream->read, std::vector >(); + auto recv = stream->read >(); _vmInfo = new (PERSISTENT_NEW) VMInfo(std::get<0>(recv)); - _vmInfo->_j9SharedClassCacheDescriptorList = reconstructJ9SharedClassCacheDescriptorList(std::get<1>(recv), std::get<2>(recv)); + _vmInfo->_j9SharedClassCacheDescriptorList = reconstructJ9SharedClassCacheDescriptorList(std::get<1>(recv)); } return _vmInfo; } J9SharedClassCacheDescriptor * -ClientSessionData::reconstructJ9SharedClassCacheDescriptorList(const std::vector &listOfCacheStartAddress, const std::vector &listOfCacheSizeBytes) +ClientSessionData::reconstructJ9SharedClassCacheDescriptorList(const std::vector &listOfCacheDescriptors) { J9SharedClassCacheDescriptor * cur = NULL; J9SharedClassCacheDescriptor * prev = NULL; J9SharedClassCacheDescriptor * head = NULL; - for (size_t i = 0; i < listOfCacheStartAddress.size(); i++) + for (size_t i = 0; i < listOfCacheDescriptors.size(); i++) { + auto cacheDesc = listOfCacheDescriptors[i]; cur = new (PERSISTENT_NEW) J9SharedClassCacheDescriptor(); - cur->cacheStartAddress = (J9SharedCacheHeader*)(listOfCacheStartAddress[i]); - cur->cacheSizeBytes = listOfCacheSizeBytes[i]; + cur->cacheStartAddress = (J9SharedCacheHeader *)cacheDesc.cacheStartAddress; + cur->cacheSizeBytes = cacheDesc.cacheSizeBytes; + cur->romclassStartAddress = (void *)cacheDesc.romClassStartAddress; + cur->metadataStartAddress = (void *)cacheDesc.metadataStartAddress; if (prev) { prev->next = cur; diff --git a/runtime/compiler/runtime/JITClientSession.hpp b/runtime/compiler/runtime/JITClientSession.hpp index 628cc8422ba..903f17a877c 100644 --- a/runtime/compiler/runtime/JITClientSession.hpp +++ b/runtime/compiler/runtime/JITClientSession.hpp @@ -334,6 +334,18 @@ class ClientSessionData U_32 _extendedRuntimeFlags2; }; // struct VMInfo + /** + * @class CacheDescriptor + * @brief Struct which contains data found in a cache descriptor + */ + struct CacheDescriptor + { + uintptr_t cacheStartAddress; + uintptr_t cacheSizeBytes; + uintptr_t romClassStartAddress; + uintptr_t metadataStartAddress; + }; + TR_PERSISTENT_ALLOC(TR_Memory::ClientSessionData) ClientSessionData(uint64_t clientUID, uint32_t seqNo); ~ClientSessionData(); @@ -408,7 +420,7 @@ class ClientSessionData template void purgeCache(std::vector *unloadedClasses, map& m, key ClassUnloadedData::*k); - J9SharedClassCacheDescriptor * reconstructJ9SharedClassCacheDescriptorList(const std::vector &listOfCacheStartAddress, const std::vector &listOfCacheSizeBytes); + J9SharedClassCacheDescriptor * reconstructJ9SharedClassCacheDescriptorList(const std::vector &listOfCacheDescriptors); void destroyJ9SharedClassCacheDescriptorList(); volatile bool isClassUnloadingAttempted() const { return _bClassUnloadingAttempt; } diff --git a/runtime/compiler/runtime/RelocationRecord.cpp b/runtime/compiler/runtime/RelocationRecord.cpp index 373fc32731f..86ab8301349 100644 --- a/runtime/compiler/runtime/RelocationRecord.cpp +++ b/runtime/compiler/runtime/RelocationRecord.cpp @@ -2183,7 +2183,7 @@ TR_RelocationRecordInlinedMethod::print(TR_RelocationRuntime *reloRuntime) TR_RelocationTarget *reloTarget = reloRuntime->reloTarget(); TR_RelocationRuntimeLogger *reloLogger = reloRuntime->reloLogger(); TR_RelocationRecordConstantPoolWithIndex::print(reloRuntime); - J9ROMClass *inlinedCodeRomClass = (J9ROMClass *)reloRuntime->fej9()->sharedCache()->pointerFromOffsetInSharedCache(romClassOffsetInSharedCache(reloTarget)); + J9ROMClass *inlinedCodeRomClass = reloRuntime->fej9()->sharedCache()->romClassFromOffsetInSharedCache(romClassOffsetInSharedCache(reloTarget)); J9UTF8 *inlinedCodeClassName = J9ROMCLASS_CLASSNAME(inlinedCodeRomClass); reloLogger->printf("\tromClassOffsetInSharedCache %x %.*s\n", romClassOffsetInSharedCache(reloTarget), inlinedCodeClassName->length, inlinedCodeClassName->data ); //reloLogger->printf("\tromClassOffsetInSharedCache %x %.*s\n", romClassOffsetInSharedCache(reloTarget), J9UTF8_LENGTH(inlinedCodeClassname), J9UTF8_DATA(inlinedCodeClassName)); @@ -2345,8 +2345,8 @@ TR_RelocationRecordInlinedMethod::inlinedSiteValid(TR_RelocationRuntime *reloRun if (inlinedSiteIsValid) { /* Calculate the runtime rom class value from the code cache */ - void *compileRomClass = reloRuntime->fej9()->sharedCache()->pointerFromOffsetInSharedCache(romClassOffsetInSharedCache(reloTarget)); - void *currentRomClass = (void *)J9_CLASS_FROM_METHOD(currentMethod)->romClass; + J9ROMClass *compileRomClass = reloRuntime->fej9()->sharedCache()->romClassFromOffsetInSharedCache(romClassOffsetInSharedCache(reloTarget)); + J9ROMClass *currentRomClass = J9_CLASS_FROM_METHOD(currentMethod)->romClass; RELO_LOG(reloRuntime->reloLogger(), 6, "\tinlinedSiteValid: compileRomClass %p currentRomClass %p\n", compileRomClass, currentRomClass); if (compileRomClass == currentRomClass) @@ -2804,7 +2804,7 @@ TR_RelocationRecordProfiledInlinedMethod::preparePrivateData(TR_RelocationRuntim } else { - J9ROMClass *inlinedCodeRomClass = (J9ROMClass *) reloRuntime->fej9()->sharedCache()->pointerFromOffsetInSharedCache(romClassOffsetInSharedCache(reloTarget)); + J9ROMClass *inlinedCodeRomClass = reloRuntime->fej9()->sharedCache()->romClassFromOffsetInSharedCache(romClassOffsetInSharedCache(reloTarget)); J9UTF8 *inlinedCodeClassName = J9ROMCLASS_CLASSNAME(inlinedCodeRomClass); RELO_LOG(reloRuntime->reloLogger(), 6,"\tpreparePrivateData: inlinedCodeRomClass %p %.*s\n", inlinedCodeRomClass, inlinedCodeClassName->length, inlinedCodeClassName->data); @@ -3130,8 +3130,13 @@ TR_RelocationRecordValidateClass::applyRelocation(TR_RelocationRuntime *reloRunt bool verified = false; if (definingClass) { - void *classChain = reloRuntime->fej9()->sharedCache()->pointerFromOffsetInSharedCache(classChainOffsetInSharedCache(reloTarget)); - verified = validateClass(reloRuntime, definingClass, classChain); + void *classChainOrROMClass; + if (isStaticFieldValidation()) + classChainOrROMClass = reloRuntime->fej9()->sharedCache()->romClassFromOffsetInSharedCache(classChainOffsetInSharedCache(reloTarget)); + else + classChainOrROMClass = reloRuntime->fej9()->sharedCache()->pointerFromOffsetInSharedCache(classChainOffsetInSharedCache(reloTarget)); + + verified = validateClass(reloRuntime, definingClass, classChainOrROMClass); } if (!verified) @@ -3787,7 +3792,7 @@ TR_RelocationRecordValidateMethodFromClassAndSig::applyRelocation(TR_RelocationR uint16_t beholderID = reloTarget->loadUnsigned16b((uint8_t *) &((TR_RelocationRecordValidateMethodFromClassAndSigBinaryTemplate *)_record)->_beholderID); uintptr_t romMethodOffset = reloTarget->loadRelocationRecordValue((uintptr_t *) &((TR_RelocationRecordValidateMethodFromClassAndSigBinaryTemplate *)_record)->_romMethodOffsetInSCC); - void *romMethod = reloRuntime->fej9()->sharedCache()->pointerFromOffsetInSharedCache(romMethodOffset); + J9ROMMethod *romMethod = reloRuntime->fej9()->sharedCache()->romMethodFromOffsetInSharedCache(romMethodOffset); if (reloRuntime->reloLogger()->logEnabled()) { @@ -3799,7 +3804,7 @@ TR_RelocationRecordValidateMethodFromClassAndSig::applyRelocation(TR_RelocationR reloRuntime->reloLogger()->printf("\tapplyRelocation: romMethod %p\n", romMethod); } - if (reloRuntime->comp()->getSymbolValidationManager()->validateMethodFromClassAndSignatureRecord(methodID, definingClassID, lookupClassID, beholderID, static_cast(romMethod))) + if (reloRuntime->comp()->getSymbolValidationManager()->validateMethodFromClassAndSignatureRecord(methodID, definingClassID, lookupClassID, beholderID, romMethod)) return 0; else return compilationAotClassReloFailure; diff --git a/runtime/compiler/runtime/RelocationRecord.hpp b/runtime/compiler/runtime/RelocationRecord.hpp index 9bc895ad578..e909378c821 100644 --- a/runtime/compiler/runtime/RelocationRecord.hpp +++ b/runtime/compiler/runtime/RelocationRecord.hpp @@ -1348,6 +1348,8 @@ class TR_RelocationRecordValidateClass : public TR_RelocationRecordConstantPoolW virtual int32_t bytesInHeaderAndPayload(); + virtual bool isStaticFieldValidation() { return false ; } + void setClassChainOffsetInSharedCache(TR_RelocationTarget *reloTarget, uintptr_t classChainOffsetInSharedCache); uintptr_t classChainOffsetInSharedCache(TR_RelocationTarget *reloTarget); @@ -1365,7 +1367,7 @@ class TR_RelocationRecordValidateInstanceField : public TR_RelocationRecordValid public: TR_RelocationRecordValidateInstanceField() {} TR_RelocationRecordValidateInstanceField(TR_RelocationRuntime *reloRuntime, TR_RelocationRecordBinaryTemplate *record) : TR_RelocationRecordValidateClass(reloRuntime, record) {} - virtual char *name(); + virtual char *name(); protected: virtual TR_OpaqueClassBlock *getClassFromCP(TR_RelocationRuntime *reloRuntime, TR_RelocationTarget *reloTarget, void *void_cp); @@ -1382,6 +1384,8 @@ class TR_RelocationRecordValidateStaticField : public TR_RelocationRecordValidat virtual int32_t bytesInHeaderAndPayload(); + virtual bool isStaticFieldValidation() { return true; } + void setRomClassOffsetInSharedCache(TR_RelocationTarget *reloTarget, uintptr_t romClassOffsetInSharedCache); uintptr_t romClassOffsetInSharedCache(TR_RelocationTarget *reloTarget); diff --git a/runtime/compiler/runtime/RelocationRuntime.cpp b/runtime/compiler/runtime/RelocationRuntime.cpp index 1d0fa7973a5..3b35deac2aa 100644 --- a/runtime/compiler/runtime/RelocationRuntime.cpp +++ b/runtime/compiler/runtime/RelocationRuntime.cpp @@ -1021,12 +1021,45 @@ TR_SharedCacheRelocationRuntime::getProcessorDescriptionFromSCC(TR_FrontEnd *fe, return hdrInCache->processorDescription; } +static void setAOTHeaderInvalid(TR_JitPrivateConfig *privateConfig) + { + TR::Options::getAOTCmdLineOptions()->setOption(TR_NoStoreAOT); + TR::Options::getAOTCmdLineOptions()->setOption(TR_NoLoadAOT); + privateConfig->aotValidHeader = TR_no; + TR_J9SharedCache::setSharedCacheDisabledReason(TR_J9SharedCache::AOT_HEADER_INVALID); + } + // This function currently does not rely on the object beyond the v-table override (compiled as static without any problems). // If this changes, we will need to look further into whether its users risk concurrent access. bool TR_SharedCacheRelocationRuntime::validateAOTHeader(TR_FrontEnd *fe, J9VMThread *curThread) { - TR_J9VMBase *fej9 = (TR_J9VMBase *)fe; + bool cacheTooBig; + J9SharedClassCacheDescriptor *curCache = javaVM()->sharedClassConfig->cacheDescriptorList; +#if defined(TR_TARGET_64BIT) + cacheTooBig = (curCache->cacheSizeBytes > 0x7FFFFFFFFFFFFFFF); +#else + cacheTooBig = (curCache->cacheSizeBytes > 0x7FFFFFFF); +#endif + + /* We don't have to check all caches (in the multi-SCC case) + * as this check would have had to pass for all layers. + * + * That said, it is technically possible for there to be + * multiple layers such that it won't be possible for the JIT + * to encode the offsets, for example two layers if at least one + * of them was of size 0x7FFFFFFFFFFFFFFF. However, given that + * currently the max size of a SCC is 0x7FFFFFF8, it would + * require over 0x100000000 layers, which can safely be assumed + * to never be occur. + */ + if (cacheTooBig) + { + incompatibleCache(J9NLS_RELOCATABLE_CODE_CACHE_TOO_BIG, + "SCC is too big for the JIT to correctly encode offsets into it"); + setAOTHeaderInvalid(static_cast(jitConfig()->privateConfig)); + return false; + } /* Look for an AOT header in the cache and see if this JVM is compatible */ @@ -1097,10 +1130,7 @@ TR_SharedCacheRelocationRuntime::validateAOTHeader(TR_FrontEnd *fe, J9VMThread * } // not compatible, so stop looking and don't compile anything for cache - TR::Options::getAOTCmdLineOptions()->setOption(TR_NoStoreAOT); - TR::Options::getAOTCmdLineOptions()->setOption(TR_NoLoadAOT); - static_cast(jitConfig()->privateConfig)->aotValidHeader = TR_no; - TR_J9SharedCache::setSharedCacheDisabledReason(TR_J9SharedCache::AOT_HEADER_INVALID); + setAOTHeaderInvalid(static_cast(jitConfig()->privateConfig)); // Generate a trace point Trc_JIT_IncompatibleAOTHeader(curThread); diff --git a/runtime/compiler/x/codegen/J9AheadOfTimeCompile.cpp b/runtime/compiler/x/codegen/J9AheadOfTimeCompile.cpp index b5b1db54f71..b9beeb98f8c 100644 --- a/runtime/compiler/x/codegen/J9AheadOfTimeCompile.cpp +++ b/runtime/compiler/x/codegen/J9AheadOfTimeCompile.cpp @@ -679,7 +679,7 @@ uint8_t *J9::X86::AheadOfTimeCompile::initializeAOTRelocationHeader(TR::Iterated // Store rom method to get name of method J9Method *methodToValidate = reinterpret_cast(record->_method); J9ROMMethod *romMethod = static_cast(fej9)->getROMMethodFromRAMMethod(methodToValidate); - uintptr_t romMethodOffsetInSharedCache = self()->offsetInSharedCacheFromPointer(sharedCache, romMethod); + uintptr_t romMethodOffsetInSharedCache = self()->offsetInSharedCacheFromROMMethod(sharedCache, romMethod); binaryTemplate->_methodID = symValManager->getIDFromSymbol(static_cast(record->_method)); binaryTemplate->_definingClassID = symValManager->getIDFromSymbol(static_cast(record->definingClass())); diff --git a/runtime/compiler/z/codegen/J9AheadOfTimeCompile.cpp b/runtime/compiler/z/codegen/J9AheadOfTimeCompile.cpp index 77363941fe5..c4c335c9f62 100644 --- a/runtime/compiler/z/codegen/J9AheadOfTimeCompile.cpp +++ b/runtime/compiler/z/codegen/J9AheadOfTimeCompile.cpp @@ -555,7 +555,7 @@ uint8_t *J9::Z::AheadOfTimeCompile::initializeAOTRelocationHeader(TR::IteratedEx // Store rom method to get name of method J9Method *methodToValidate = reinterpret_cast(record->_method); J9ROMMethod *romMethod = static_cast(fej9)->getROMMethodFromRAMMethod(methodToValidate); - uintptr_t romMethodOffsetInSharedCache = self()->offsetInSharedCacheFromPointer(sharedCache, romMethod); + uintptr_t romMethodOffsetInSharedCache = self()->offsetInSharedCacheFromROMMethod(sharedCache, romMethod); binaryTemplate->_methodID = symValManager->getIDFromSymbol(static_cast(record->_method)); binaryTemplate->_definingClassID = symValManager->getIDFromSymbol(static_cast(record->definingClass())); binaryTemplate->_lookupClassID = symValManager->getIDFromSymbol(static_cast(record->_lookupClass)); diff --git a/runtime/nls/jitm/j9jit.nls b/runtime/nls/jitm/j9jit.nls index 7f850236f6a..ad2fb3d1296 100644 --- a/runtime/nls/jitm/j9jit.nls +++ b/runtime/nls/jitm/j9jit.nls @@ -232,6 +232,14 @@ J9NLS_RELOCATABLE_CODE_CMPRS_REF_SHIFT_MISMATCH.user_response=Destroy and recrea J9NLS_RELOCATABLE_CODE_CMPRS_REF_SHIFT_MISMATCH.link=dita:///diag/appendixes/cmdline/cmdline_x.dita#cmdline_x/xshareclasses-reset # END NON-TRANSLATABLE +J9NLS_RELOCATABLE_CODE_CACHE_TOO_BIG=The SCC is too big for the JIT to correctly encode offsets. Ignoring AOT code in shared class cache. +# START NON-TRANSLATABLE +J9NLS_RELOCATABLE_CODE_CACHE_TOO_BIG.explanation=The SCC is too big for the JIT to correctly encode offsets. +J9NLS_RELOCATABLE_CODE_CACHE_TOO_BIG.system_action=The compiler will not generate AOT code. AOT code from the shared class cache will not be used. +J9NLS_RELOCATABLE_CODE_CACHE_TOO_BIG.user_response=Destroy and recreate the AOT code in the shared class cache for the current platform using the -Xshareclasses:reset option. +J9NLS_RELOCATABLE_CODE_CACHE_TOO_BIG.link=dita:///diag/appendixes/cmdline/cmdline_x.dita#cmdline_x/xshareclasses-reset +# END NON-TRANSLATABLE + J9NLS_RELOCATABLE_CODE_UNKNOWN_PROBLEM=Unknown Problem. Ignoring AOT code in shared class cache. # START NON-TRANSLATABLE