Path: blob/master/runtime/compiler/env/J9SharedCache.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2022 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "env/J9SharedCache.hpp"2324#include <algorithm>25#include "j9cfg.h"26#include "control/CompilationRuntime.hpp"27#include "control/Options.hpp"28#include "control/Options_inlines.hpp"29#include "compile/ResolvedMethod.hpp"30#include "env/ClassLoaderTable.hpp"31#include "env/ClassTableCriticalSection.hpp"32#include "env/jittypes.h"33#include "env/j9method.h"34#include "env/PersistentCHTable.hpp"35#include "env/VMAccessCriticalSection.hpp"36#include "env/VMJ9.h"37#include "env/VerboseLog.hpp"38#include "exceptions/PersistenceFailure.hpp"39#include "infra/CriticalSection.hpp"40#include "runtime/CodeRuntime.hpp"41#include "runtime/IProfiler.hpp"42#include "runtime/RuntimeAssumptions.hpp"43#if defined(J9VM_OPT_JITSERVER)44#include "control/CompilationThread.hpp" // for TR::compInfoPT45#include "control/JITServerHelpers.hpp"46#include "runtime/JITClientSession.hpp"47#endif4849#define LOG(logLevel, format, ...) \50if (_logLevel >= logLevel) \51{ \52log("" format "", ##__VA_ARGS__); \53}5455// From CompositeCache.cpp56#define UPDATEPTR(ca) (((uint8_t *)(ca)) + (ca)->updateSRP)57#define SEGUPDATEPTR(ca) (((uint8_t *)(ca)) + (ca)->segmentSRP)5859TR_J9SharedCache::TR_J9SharedCacheDisabledReason TR_J9SharedCache::_sharedCacheState = TR_J9SharedCache::UNINITIALIZED;60TR_YesNoMaybe TR_J9SharedCache::_sharedCacheDisabledBecauseFull = TR_maybe;61UDATA TR_J9SharedCache::_storeSharedDataFailedLength = 0;6263TR_YesNoMaybe TR_J9SharedCache::isSharedCacheDisabledBecauseFull(TR::CompilationInfo *compInfo)64{65if (_sharedCacheDisabledBecauseFull == TR_maybe)66{67if (_sharedCacheState == SHARED_CACHE_FULL)68{69_sharedCacheDisabledBecauseFull = TR_yes;70}71#if defined(J9VM_OPT_SHARED_CLASSES) && defined(J9VM_INTERP_AOT_RUNTIME_SUPPORT)72// Need to check if the AOT Header / Class Chain Data failed to store because73// the SCC is full or for some other reason.74else if (_sharedCacheState == AOT_HEADER_STORE_FAILED ||75_sharedCacheState == SHARED_CACHE_CLASS_CHAIN_STORE_FAILED)76{77J9JavaVM * javaVM = compInfo->getJITConfig()->javaVM;78if (javaVM->sharedClassConfig && javaVM->sharedClassConfig->getJavacoreData)79{80J9SharedClassJavacoreDataDescriptor javacoreData;81memset(&javacoreData, 0, sizeof(J9SharedClassJavacoreDataDescriptor));82javaVM->sharedClassConfig->getJavacoreData(javaVM, &javacoreData);8384if (javacoreData.freeBytes <= _storeSharedDataFailedLength)85_sharedCacheDisabledBecauseFull = TR_yes;86else87_sharedCacheDisabledBecauseFull = TR_no;8889if (TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerbosePerformance))90TR_VerboseLog::writeLineLocked(TR_Vlog_PERF, "Free Bytes in SCC = %u B", javacoreData.freeBytes);91}92else93{94_sharedCacheDisabledBecauseFull = TR_no;95}96}97#endif98else99{100_sharedCacheDisabledBecauseFull = TR_no;101}102}103104return _sharedCacheDisabledBecauseFull;105}106107const CCVResult108TR_J9SharedCache::getCachedCCVResult(TR_OpaqueClassBlock *clazz)109{110if (!TR::Options::getCmdLineOptions()->getOption(TR_DisableCHOpts))111{112TR::ClassTableCriticalSection cacheResult(_fe);113TR_PersistentCHTable *table = _compInfo->getPersistentInfo()->getPersistentCHTable();114TR_PersistentClassInfo *classInfo = table->findClassInfo(clazz);115return classInfo->getCCVResult();116}117return CCVResult::notYetValidated;118}119120bool121TR_J9SharedCache::cacheCCVResult(TR_OpaqueClassBlock *clazz, CCVResult result)122{123if (!TR::Options::getCmdLineOptions()->getOption(TR_DisableCHOpts))124{125TR::ClassTableCriticalSection cacheResult(_fe);126TR_PersistentCHTable *table = _compInfo->getPersistentInfo()->getPersistentCHTable();127TR_PersistentClassInfo *classInfo = table->findClassInfo(clazz);128classInfo->setCCVResult(result);129return true;130}131return false;132}133134TR_J9SharedCache::TR_J9SharedCache(TR_J9VMBase *fe)135{136#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))137_fe = fe;138_jitConfig = fe->getJ9JITConfig();139_javaVM = _jitConfig->javaVM;140_compInfo = TR::CompilationInfo::get(_jitConfig);141_aotStats = fe->getPrivateConfig()->aotStats;142_sharedCacheConfig = _javaVM->sharedClassConfig;143_numDigitsForCacheOffsets = 8;144145#if defined(J9VM_OPT_JITSERVER)146TR_ASSERT_FATAL(_sharedCacheConfig || _compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER, "Must have _sharedCacheConfig");147#else148TR_ASSERT_FATAL(_sharedCacheConfig, "Must have _sharedCacheConfig");149#endif150151#if defined(J9VM_OPT_JITSERVER)152if (_sharedCacheConfig)153#endif154{155UDATA totalCacheSize = 0;156J9SharedClassCacheDescriptor *curCache = _sharedCacheConfig->cacheDescriptorList;157do158{159totalCacheSize += curCache->cacheSizeBytes;160curCache = curCache->next;161}162while (curCache != _sharedCacheConfig->cacheDescriptorList);163164if (totalCacheSize > UINT_MAX)165_numDigitsForCacheOffsets = 16;166167_hintsEnabledMask = 0;168if (!TR::Options::getAOTCmdLineOptions()->getOption(TR_DisableSharedCacheHints))169_hintsEnabledMask = TR::Options::getAOTCmdLineOptions()->getEnableSCHintFlags();170171_initialHintSCount = std::min(TR::Options::getCmdLineOptions()->getInitialSCount(), TR::Options::getAOTCmdLineOptions()->getInitialSCount());172if (_initialHintSCount == 0)173_initialHintSCount = 1;174175_logLevel = std::max(TR::Options::getAOTCmdLineOptions()->getAotrtDebugLevel(), TR::Options::getCmdLineOptions()->getAotrtDebugLevel());176177_verboseHints = TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerboseSCHints);178179LOG(1, "\t_sharedCacheConfig %p\n", _sharedCacheConfig);180LOG(1, "\ttotalCacheSize %p\n", totalCacheSize);181}182#endif183}184185J9SharedClassCacheDescriptor *186TR_J9SharedCache::getCacheDescriptorList()187{188#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))189if (_sharedCacheConfig)190return _sharedCacheConfig->cacheDescriptorList;191#endif192return NULL;193}194195void196TR_J9SharedCache::log(char *format, ...)197{198PORT_ACCESS_FROM_PORT(_javaVM->portLibrary);199char outputBuffer[512] = "TR_J9SC:";200const uint32_t startOffset = 8; // strlen("TR_J9SC:")201202va_list args;203va_start(args, format);204j9str_vprintf(outputBuffer+startOffset, 512, format, args);205va_end(args);206207rtlogPrintLocked(jitConfig(), _fe->_compInfoPT, outputBuffer);208}209210TR_J9SharedCache::SCCHint211TR_J9SharedCache::getHint(J9VMThread * vmThread, J9Method *method)212{213SCCHint result;214215#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))216J9ROMMethod * romMethod = fe()->getROMMethodFromRAMMethod(method);217218J9SharedDataDescriptor descriptor;219descriptor.address = (U_8 *)&result;220descriptor.length = sizeof(result);221descriptor.type = J9SHR_ATTACHED_DATA_TYPE_JITHINT;222descriptor.flags = J9SHR_ATTACHED_DATA_NO_FLAGS;223IDATA dataIsCorrupt;224SCCHint *find = (SCCHint *)sharedCacheConfig()->findAttachedData(vmThread, romMethod, &descriptor, &dataIsCorrupt);225226if ((find != (SCCHint *)descriptor.address) || (dataIsCorrupt != -1))227{228result.clear();229}230#endif // 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))231return result;232}233234uint16_t235TR_J9SharedCache::getAllEnabledHints(J9Method *method)236{237uint16_t hintFlags = 0;238#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))239if (_hintsEnabledMask)240{241TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());242J9VMThread * vmThread = fej9->getCurrentVMThread();243SCCHint scHints = getHint(vmThread, method);244hintFlags = scHints.flags & _hintsEnabledMask;245}246#endif // 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))247return hintFlags;248}249250251bool252TR_J9SharedCache::isHint(J9Method *method, TR_SharedCacheHint theHint, uint16_t *dataField)253{254bool isHint = false;255256#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))257uint16_t hint = ((uint16_t)theHint) & _hintsEnabledMask;258if (hint != 0)259{260TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());261J9ROMMethod * romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);262J9VMThread * vmThread = fej9->getCurrentVMThread();263SCCHint scHints = getHint(vmThread, method);264265if (dataField)266*dataField = scHints.data;267268if (_verboseHints)269{270char methodSignature[500];271int32_t maxSignatureLength = 500;272fej9->printTruncatedSignature(methodSignature, maxSignatureLength, (TR_OpaqueMethodBlock *) method);273TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"is hint %x(%x) %s", scHints.flags, hint, methodSignature);274}275isHint = (scHints.flags & hint) != 0;276}277#endif // 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))278return isHint;279}280281bool282TR_J9SharedCache::isHint(TR_ResolvedMethod *method, TR_SharedCacheHint hint, uint16_t *dataField)283{284return isHint(((TR_ResolvedJ9Method *) method)->ramMethod(), hint, dataField);285}286287void288TR_J9SharedCache::addHint(J9Method * method, TR_SharedCacheHint theHint)289{290#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))291static bool SCfull = false;292uint16_t newHint = ((uint16_t)theHint) & _hintsEnabledMask;293if (newHint)294{295TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());296J9ROMMethod * romMethod = fej9->getROMMethodFromRAMMethod(method);297J9VMThread * vmThread = fej9->getCurrentVMThread();298299char methodSignature[500];300uint32_t maxSignatureLength = 500;301302bool isFailedValidationHint = (newHint == TR_HintFailedValidation);303304if (_verboseHints)305{306fej9->printTruncatedSignature(methodSignature, maxSignatureLength, (TR_OpaqueMethodBlock *) method);307TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"adding hint 0x%x %s", newHint, methodSignature);308}309310// There is only one scenario where concurrency *may* matter, so we don't get a lock311// The scenario is where a compilation thread wants to register a hint about the method it's compiling at312// the same time that another thread is inlining it *for the first time*. In that case, one of the hints313// won't be registered. The affect, however is minimal, and likely to correct itself in the current run314// (if the inlining hint is missed) or a subsequent run (if the other hint is missed).315316SCCHint scHints = getHint(vmThread, method);317const uint32_t scHintDataLength = sizeof(scHints);318319if (scHints.flags == 0) // If no prior hints exist, we can perform a "storeAttachedData" operation320{321uint32_t bytesToPersist = 0;322323if (!SCfull)324{325scHints.flags |= newHint;326if (isFailedValidationHint)327scHints.data = 10 * _initialHintSCount;328329J9SharedDataDescriptor descriptor;330descriptor.address = (U_8 *)&scHints;331descriptor.length = scHintDataLength; // Size includes the 2nd data field, currently only used for TR_HintFailedValidation332descriptor.type = J9SHR_ATTACHED_DATA_TYPE_JITHINT;333descriptor.flags = J9SHR_ATTACHED_DATA_NO_FLAGS;334UDATA store = sharedCacheConfig()->storeAttachedData(vmThread, romMethod, &descriptor, 0);335TR::CompilationInfo * compInfo = TR::CompilationInfo::get(jitConfig());336if (store == 0)337{338if (_verboseHints)339TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"hint added 0x%x, key = %s, scount: %d", scHints.flags, methodSignature, scHints.data);340}341else if (store != J9SHR_RESOURCE_STORE_FULL)342{343if (_verboseHints)344TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"hint error: could not be added into SC\n");345}346else347{348SCfull = true;349bytesToPersist = scHintDataLength;350if (_verboseHints)351TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"hint error: SCC full\n");352}353}354else // SCC Full355{356bytesToPersist = scHintDataLength;357}358359if (SCfull &&360bytesToPersist &&361!TR::Options::getCmdLineOptions()->getOption(TR_DisableUpdateJITBytesSize))362{363_compInfo->increaseUnstoredBytes(0, bytesToPersist);364}365}366else // Some hints already exist for this method. We must perform an "updateAttachedData"367{368bool updateHint = false;369bool hintDidNotExist = ((newHint & scHints.flags) == 0);370if (hintDidNotExist)371{372updateHint = true;373scHints.flags |= newHint;374if (isFailedValidationHint)375scHints.data = 10 * _initialHintSCount;376}377else378{379// hint already exists, but maybe we need to update the count380if (isFailedValidationHint)381{382uint16_t oldCount = scHints.data;383uint16_t newCount = std::min(oldCount * 10, TR_DEFAULT_INITIAL_COUNT);384if (newCount != oldCount)385{386updateHint = true;387scHints.data = newCount;388}389else390{391if (_verboseHints)392{393TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS, "hint reached max count of %d", oldCount);394}395}396}397}398if (updateHint)399{400J9SharedDataDescriptor descriptor;401descriptor.address = (U_8 *)&scHints;402descriptor.length = scHintDataLength; // Size includes the 2nd data field, currently only used for TR_HintFailedValidation403descriptor.type = J9SHR_ATTACHED_DATA_TYPE_JITHINT;404descriptor.flags = J9SHR_ATTACHED_DATA_NO_FLAGS;405UDATA update = sharedCacheConfig()->updateAttachedData(vmThread, romMethod, 0, &descriptor);406407if (_verboseHints)408{409if (update == 0)410{411TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"hint updated 0x%x, key = %s, scount: %d", scHints.flags, methodSignature, scHints.data);412}413else414{415TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"hint error: could not be updated into SC\n");416}417}418}419}420}421422#endif // 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))423}424425void426TR_J9SharedCache::addHint(TR_ResolvedMethod * method, TR_SharedCacheHint hint)427{428addHint(((TR_ResolvedJ9Method *) method)->ramMethod(), hint);429}430431432void433TR_J9SharedCache::persistIprofileInfo(TR::ResolvedMethodSymbol *methodSymbol, TR::Compilation *comp)434{435persistIprofileInfo(methodSymbol, methodSymbol->getResolvedMethod(), comp);436}437438void439TR_J9SharedCache::persistIprofileInfo(TR::ResolvedMethodSymbol *methodSymbol, TR_ResolvedMethod *method, TR::Compilation *comp)440{441TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());442TR_IProfiler *profiler = fej9->getIProfiler();443if (profiler)444profiler->persistIprofileInfo(methodSymbol, method, comp);445}446447bool448TR_J9SharedCache::isMostlyFull()449{450return (double) sharedCacheConfig()->getFreeSpaceBytes(_javaVM) / sharedCacheConfig()->getCacheSizeBytes(_javaVM) < 0.8;451}452453bool454TR_J9SharedCache::isPointerInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr)455{456bool isPointerInCache = false;457#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))458uintptr_t ptrValue = reinterpret_cast<uintptr_t>(ptr);459uintptr_t cacheStart = reinterpret_cast<uintptr_t>(cacheDesc->cacheStartAddress); // Inclusive460uintptr_t cacheEnd = cacheStart + cacheDesc->cacheSizeBytes; // Exclusive461462isPointerInCache = (ptrValue >= cacheStart) && (ptrValue < cacheEnd);463#endif464return isPointerInCache;465}466467bool468TR_J9SharedCache::isOffsetInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset)469{470bool isOffsetInCache = false;471#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))472uintptr_t decodedOffset = isOffsetFromStart(offset) ? decodeOffsetFromStart(offset) : decodeOffsetFromEnd(offset);473isOffsetInCache = (decodedOffset < cacheDesc->cacheSizeBytes);474#endif475return isOffsetInCache;476}477478bool479TR_J9SharedCache::isPointerInMetadataSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr)480{481bool isPointerInMetadataSection = false;482#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))483if (isPointerInCache(cacheDesc, ptr))484{485uintptr_t ptrValue = reinterpret_cast<uintptr_t>(ptr);486uintptr_t metadataEndAddress = reinterpret_cast<uintptr_t>(UPDATEPTR(cacheDesc->cacheStartAddress)); // Inclusive487uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(cacheDesc->metadataStartAddress); // Exclusive488489isPointerInMetadataSection = (ptrValue >= metadataEndAddress) && (ptrValue < metadataStartAddress);490}491#endif492return isPointerInMetadataSection;493}494495bool496TR_J9SharedCache::isOffsetInMetadataSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset)497{498bool isOffsetInMetadataSection = false;499#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))500if (isOffsetFromEnd(offset) && isOffsetInCache(cacheDesc, offset))501{502uintptr_t metadataEndAddress = reinterpret_cast<uintptr_t>(UPDATEPTR(cacheDesc->cacheStartAddress));503uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(cacheDesc->metadataStartAddress);504505uintptr_t metadataEndOffset = metadataStartAddress - metadataEndAddress; // Inclusive506507isOffsetInMetadataSection = ((decodeOffsetFromEnd(offset) > 0 ) && (decodeOffsetFromEnd(offset) <= metadataEndOffset));508}509#endif510return isOffsetInMetadataSection;511}512513bool514TR_J9SharedCache::isPointerInROMClassesSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr)515{516bool isPointerInRomClassesSection = false;517#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))518if (isPointerInCache(cacheDesc, ptr))519{520uintptr_t ptrValue = reinterpret_cast<uintptr_t>(ptr);521uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(cacheDesc->romclassStartAddress); // Inclusive522uintptr_t romclassEndAddress = reinterpret_cast<uintptr_t>(SEGUPDATEPTR(cacheDesc->cacheStartAddress)); // Exclusive523524isPointerInRomClassesSection = (ptrValue >= romclassStartAddress) && (ptrValue < romclassEndAddress);525}526#endif527return isPointerInRomClassesSection;528}529530bool531TR_J9SharedCache::isOffsetinROMClassesSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset)532{533bool isOffsetInRomClassesSection = false;534#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))535if (isOffsetFromStart(offset) && isOffsetInCache(cacheDesc, offset))536{537uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(cacheDesc->romclassStartAddress);538uintptr_t romclassEndAddress = reinterpret_cast<uintptr_t>(SEGUPDATEPTR(cacheDesc->cacheStartAddress));539540uintptr_t romclassEndOffset = romclassEndAddress - romclassStartAddress; // Exclusive541542isOffsetInRomClassesSection = (decodeOffsetFromStart(offset) < romclassEndOffset);543}544#endif545return isOffsetInRomClassesSection;546}547548void *549TR_J9SharedCache::pointerFromOffsetInSharedCache(uintptr_t offset)550{551uintptr_t ptr = 0;552if (isOffsetInSharedCache(offset, &ptr))553{554return (void *)ptr;555}556TR_ASSERT_FATAL(false, "Shared cache offset %d out of bounds", offset);557return (void *)ptr;558}559560void *561TR_J9SharedCache::romStructureFromOffsetInSharedCache(uintptr_t offset)562{563void *romStructure = NULL;564if (isROMStructureOffsetInSharedCache(offset, &romStructure))565{566return romStructure;567}568TR_ASSERT_FATAL(false, "Shared cache ROM Structure offset %d out of bounds", offset);569return romStructure;570}571572J9ROMClass *573TR_J9SharedCache::romClassFromOffsetInSharedCache(uintptr_t offset)574{575return reinterpret_cast<J9ROMClass *>(romStructureFromOffsetInSharedCache(offset));576}577578J9ROMMethod *579TR_J9SharedCache::romMethodFromOffsetInSharedCache(uintptr_t offset)580{581return reinterpret_cast<J9ROMMethod *>(romStructureFromOffsetInSharedCache(offset));582}583584void *585TR_J9SharedCache::ptrToROMClassesSectionFromOffsetInSharedCache(uintptr_t offset)586{587return romStructureFromOffsetInSharedCache(offset);588}589590bool591TR_J9SharedCache::isOffsetInSharedCache(uintptr_t encoded_offset, void *ptr)592{593#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))594#if defined(J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE)595// The cache descriptor list is linked last to first and is circular, so last->previous == first.596J9SharedClassCacheDescriptor *firstCache = getCacheDescriptorList()->previous;597J9SharedClassCacheDescriptor *curCache = firstCache;598do599{600TR_ASSERT_FATAL(isOffsetFromEnd(encoded_offset), "Shared cache (encoded) offset %lld not from end\n", encoded_offset);601if (isOffsetInMetadataSectionInCache(curCache, encoded_offset))602{603if (ptr)604{605uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(curCache->metadataStartAddress);606*reinterpret_cast<uintptr_t *>(ptr) = metadataStartAddress - decodeOffsetFromEnd(encoded_offset);607}608return true;609}610encoded_offset = encodeOffsetFromEnd(decodeOffsetFromEnd(encoded_offset) - curCache->cacheSizeBytes);611curCache = curCache->previous;612}613while (curCache != firstCache);614#else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE615TR_ASSERT_FATAL(isOffsetFromEnd(encoded_offset), "Shared cache (encoded) offset %lld not from end\n", encoded_offset);616J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList();617if (isOffsetInMetadataSectionInCache(curCache, encoded_offset))618{619if (ptr)620{621uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(curCache->metadataStartAddress);622*reinterpret_cast<uintptr_t *>(ptr) = metadataStartAddress - decodeOffsetFromEnd(encoded_offset);623}624return true;625}626#endif // J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE627#endif628return false;629}630631bool632TR_J9SharedCache::isROMStructureOffsetInSharedCache(uintptr_t encoded_offset, void **romStructurePtr)633{634#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))635#if defined(J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE)636// The cache descriptor list is linked last to first and is circular, so last->previous == first.637J9SharedClassCacheDescriptor *firstCache = getCacheDescriptorList()->previous;638J9SharedClassCacheDescriptor *curCache = firstCache;639do640{641TR_ASSERT_FATAL(isOffsetFromStart(encoded_offset), "Shared cache (encoded) offset %lld not from start\n", encoded_offset);642if (isOffsetinROMClassesSectionInCache(curCache, encoded_offset))643{644if (romStructurePtr)645{646uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(curCache->romclassStartAddress);647*romStructurePtr = reinterpret_cast<void *>(romclassStartAddress + decodeOffsetFromStart(encoded_offset));648}649return true;650}651encoded_offset = encodeOffsetFromStart(decodeOffsetFromStart(encoded_offset) - curCache->cacheSizeBytes);652curCache = curCache->previous;653}654while (curCache != firstCache);655#else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE656TR_ASSERT_FATAL(isOffsetFromStart(encoded_offset), "Shared cache (encoded) offset %lld not from start\n", encoded_offset);657J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList();658if (isOffsetinROMClassesSectionInCache(curCache, encoded_offset))659{660if (romStructurePtr)661{662uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(curCache->romclassStartAddress);663*romStructurePtr = reinterpret_cast<void *>(romclassStartAddress + decodeOffsetFromStart(encoded_offset));664}665return true;666}667#endif // J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE668#endif669return false;670}671672bool673TR_J9SharedCache::isROMClassOffsetInSharedCache(uintptr_t offset, J9ROMClass **romClassPtr)674{675return isROMStructureOffsetInSharedCache(offset, reinterpret_cast<void **>(romClassPtr));676}677678bool679TR_J9SharedCache::isROMMethodOffsetInSharedCache(uintptr_t offset, J9ROMMethod **romMethodPtr)680{681return isROMStructureOffsetInSharedCache(offset, reinterpret_cast<void **>(romMethodPtr));682}683684bool685TR_J9SharedCache::isOffsetOfPtrToROMClassesSectionInSharedCache(uintptr_t offset, void **ptr)686{687return isROMStructureOffsetInSharedCache(offset, ptr);688}689690uintptr_t691TR_J9SharedCache::offsetInSharedCacheFromPointer(void *ptr)692{693uintptr_t offset = 0;694if (isPointerInSharedCache(ptr, &offset))695{696return offset;697}698TR_ASSERT_FATAL(false, "Shared cache pointer %p out of bounds", ptr);699return offset;700}701702uintptr_t703TR_J9SharedCache::offsetInSharedcacheFromROMStructure(void *romStructure)704{705uintptr_t offset = 0;706if (isROMStructureInSharedCache(romStructure, &offset))707{708return offset;709}710TR_ASSERT_FATAL(false, "Shared cache ROM Structure pointer %p out of bounds", romStructure);711return offset;712}713714uintptr_t715TR_J9SharedCache::offsetInSharedCacheFromROMClass(J9ROMClass *romClass)716{717return offsetInSharedcacheFromROMStructure(romClass);718}719720uintptr_t721TR_J9SharedCache::offsetInSharedCacheFromROMMethod(J9ROMMethod *romMethod)722{723return offsetInSharedcacheFromROMStructure(romMethod);724}725726uintptr_t727TR_J9SharedCache::offsetInSharedCacheFromPtrToROMClassesSection(void *ptr)728{729return offsetInSharedcacheFromROMStructure(ptr);730}731732bool733TR_J9SharedCache::isPointerInSharedCache(void *ptr, uintptr_t *cacheOffset)734{735#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))736#if defined(J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE)737uintptr_t offset = 0;738// The cache descriptor list is linked last to first and is circular, so last->previous == first.739J9SharedClassCacheDescriptor *firstCache = getCacheDescriptorList()->previous;740J9SharedClassCacheDescriptor *curCache = firstCache;741do742{743if (isPointerInMetadataSectionInCache(curCache, ptr))744{745if (cacheOffset)746{747uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(curCache->metadataStartAddress);748*cacheOffset = encodeOffsetFromEnd(metadataStartAddress - reinterpret_cast<uintptr_t>(ptr) + offset);749}750return true;751}752offset += curCache->cacheSizeBytes;753curCache = curCache->previous;754}755while (curCache != firstCache);756#else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE757J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList();758if (isPointerInMetadataSectionInCache(curCache, ptr))759{760if (cacheOffset)761{762uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(curCache->metadataStartAddress);763*cacheOffset = encodeOffsetFromEnd(metadataStartAddress - reinterpret_cast<uintptr_t>(ptr));764}765return true;766}767#endif // J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE768#endif769return false;770}771772bool773TR_J9SharedCache::isROMStructureInSharedCache(void *romStructure, uintptr_t *cacheOffset)774{775#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))776#if defined(J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE)777uintptr_t offset = 0;778// The cache descriptor list is linked last to first and is circular, so last->previous == first.779J9SharedClassCacheDescriptor *firstCache = getCacheDescriptorList()->previous;780J9SharedClassCacheDescriptor *curCache = firstCache;781do782{783if (isPointerInROMClassesSectionInCache(curCache, romStructure))784{785if (cacheOffset)786{787uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(curCache->romclassStartAddress);788*cacheOffset = encodeOffsetFromStart(reinterpret_cast<uintptr_t>(romStructure) - romclassStartAddress + offset);789}790return true;791}792offset += curCache->cacheSizeBytes;793curCache = curCache->previous;794}795while (curCache != firstCache);796#else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE797J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList();798if (isPointerInROMClassesSectionInCache(curCache, romStructure))799{800if (cacheOffset)801{802uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(curCache->romclassStartAddress);803*cacheOffset = encodeOffsetFromStart(reinterpret_cast<uintptr_t>(romStructure) - romclassStartAddress);804}805return true;806}807#endif // J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE808#endif809return false;810}811812bool813TR_J9SharedCache::isROMClassInSharedCache(J9ROMClass *romClass, uintptr_t *cacheOffset)814{815return isROMStructureInSharedCache(romClass, cacheOffset);816}817818bool819TR_J9SharedCache::isROMMethodInSharedCache(J9ROMMethod *romMethod, uintptr_t *cacheOffset)820{821return isROMStructureInSharedCache(romMethod, cacheOffset);822}823824bool825TR_J9SharedCache::isPtrToROMClassesSectionInSharedCache(void *ptr, uintptr_t *cacheOffset)826{827return isROMStructureInSharedCache(ptr, cacheOffset);828}829830J9ROMClass *831TR_J9SharedCache::startingROMClassOfClassChain(UDATA *classChain)832{833UDATA lengthInBytes = classChain[0];834TR_ASSERT_FATAL(lengthInBytes >= 2 * sizeof (UDATA), "class chain is too short!");835836UDATA romClassOffset = classChain[1];837return romClassFromOffsetInSharedCache(romClassOffset);838}839840// convert an offset into a string of 8 characters841void842TR_J9SharedCache::convertUnsignedOffsetToASCII(UDATA offset, char *buffer)843{844for (int i = _numDigitsForCacheOffsets; i >= 0; i--, offset >>= 4)845{846uint8_t lowNibble = offset & 0xf;847buffer[i] = (lowNibble > 9 ? lowNibble - 10 + 'a' : lowNibble + '0');848}849buffer[_numDigitsForCacheOffsets] = 0;850TR_ASSERT(offset == 0, "Unsigned offset unexpectedly not fully converted to ASCII");851}852853void854TR_J9SharedCache::createClassKey(UDATA classOffsetInCache, char *key, uint32_t & keyLength)855{856keyLength = _numDigitsForCacheOffsets;857convertUnsignedOffsetToASCII(classOffsetInCache, key);858}859860uintptr_t *861TR_J9SharedCache::rememberClass(J9Class *clazz, const AOTCacheClassChainRecord **classChainRecord, bool create)862{863uintptr_t *chainData = NULL;864#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))865TR_J9VMBase *fej9 = (TR_J9VMBase *)fe();866J9ROMClass *romClass = TR::Compiler->cls.romClassOf(fej9->convertClassPtrToClassOffset(clazz));867868J9UTF8 *className = J9ROMCLASS_CLASSNAME(romClass);869LOG(1, "rememberClass class %p romClass %p %.*s\n", clazz, romClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className));870871uintptr_t classOffsetInCache;872if (!isROMClassInSharedCache(romClass, &classOffsetInCache))873{874LOG(1,"\trom class not in shared cache, returning\n");875return NULL;876}877878char key[17]; // longest possible key length is way less than 16 digits879uint32_t keyLength;880createClassKey(classOffsetInCache, key, keyLength);881882LOG(3, "\tkey created: %.*s\n", keyLength, key);883884chainData = findChainForClass(clazz, key, keyLength);885if (chainData != NULL)886{887LOG(1, "\tchain exists (%p) so nothing to store\n", chainData);888return chainData;889}890891int32_t numSuperclasses = TR::Compiler->cls.classDepthOf(fe()->convertClassPtrToClassOffset(clazz));892int32_t numInterfaces = numInterfacesImplemented(clazz);893894LOG(3, "\tcreating chain now: 1 + 1 + %d superclasses + %d interfaces\n", numSuperclasses, numInterfaces);895uintptr_t chainLength = (2 + numSuperclasses + numInterfaces) * sizeof(uintptr_t);896uintptr_t chainDataBuffer[maxClassChainLength];897chainData = chainDataBuffer;898if (chainLength > maxClassChainLength * sizeof(uintptr_t))899{900LOG(1, "\t\t > %u so bailing\n", maxClassChainLength);901return NULL;902}903904if (!fillInClassChain(clazz, chainData, chainLength, numSuperclasses, numInterfaces))905{906LOG(1, "\tfillInClassChain failed, bailing\n");907return NULL;908}909910if (!create)911{912LOG(1, "\tnot asked to create but could create, returning non-null\n");913return (uintptr_t *)0x1;914}915916uintptr_t chainDataLength = chainData[0];917918J9SharedDataDescriptor dataDescriptor;919dataDescriptor.address = (uint8_t *)chainData;920dataDescriptor.length = chainDataLength;921dataDescriptor.type = J9SHR_DATA_TYPE_AOTCLASSCHAIN;922dataDescriptor.flags = J9SHRDATA_SINGLE_STORE_FOR_KEY_TYPE;923924if (aotStats())925aotStats()->numNewCHEntriesInSharedClass++;926927J9VMThread *vmThread = fej9->getCurrentVMThread();928chainData = (uintptr_t *)sharedCacheConfig()->storeSharedData(vmThread, key, keyLength, &dataDescriptor);929if (chainData)930{931LOG(1, "\tstored data, chain at %p\n", chainData);932}933else934{935LOG(1, "\tunable to store chain\n");936TR::Options::getAOTCmdLineOptions()->setOption(TR_NoStoreAOT);937938setSharedCacheDisabledReason(SHARED_CACHE_CLASS_CHAIN_STORE_FAILED);939setStoreSharedDataFailedLength(chainDataLength);940}941#endif942return chainData;943}944945UDATA946TR_J9SharedCache::rememberDebugCounterName(const char *name)947{948UDATA offset = 0;949#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))950TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());951J9VMThread *vmThread = fej9->getCurrentVMThread();952953J9SharedDataDescriptor dataDescriptor;954dataDescriptor.address = (U_8*)name;955dataDescriptor.length = (strlen(name) + 1); // +1 for the \0 terminator956dataDescriptor.type = J9SHR_DATA_TYPE_JITHINT;957dataDescriptor.flags = J9SHRDATA_NOT_INDEXED;958959const U_8 *data = sharedCacheConfig()->storeSharedData(vmThread,960(const char*)NULL,9610,962&dataDescriptor);963964offset = data ? offsetInSharedCacheFromPointer((void *)data) : (UDATA)-1;965966//printf("\nrememberDebugCounterName: Tried to store %s (%p), data=%p, offset=%p\n", name, name, data, offset);967#endif968return offset;969}970971const char *972TR_J9SharedCache::getDebugCounterName(UDATA offset)973{974const char *name = (offset != (UDATA)-1) ? (const char *)pointerFromOffsetInSharedCache(offset) : NULL;975976//printf("\ngetDebugCounterName: Tried to find %p, name=%s (%p)\n", offset, (name ? name : ""), name);977978return name;979}980981uint32_t982TR_J9SharedCache::numInterfacesImplemented(J9Class *clazz)983{984uint32_t count=0;985J9ITable *element = TR::Compiler->cls.iTableOf(fe()->convertClassPtrToClassOffset(clazz));986while (element != NULL)987{988count++;989element = TR::Compiler->cls.iTableNext(element);990}991return count;992}993994bool995TR_J9SharedCache::writeClassToChain(J9ROMClass *romClass, UDATA * & chainPtr)996{997uintptr_t classOffsetInCache;998if (!isROMClassInSharedCache(romClass, &classOffsetInCache))999{1000LOG(3, "\t\tromclass %p not in shared cache, writeClassToChain returning false\n", romClass);1001return false;1002}10031004J9UTF8 * className = J9ROMCLASS_CLASSNAME(romClass);1005LOG(3, "\t\tChain %p storing romclass %p (%.*s) offset %d\n", chainPtr, romClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className), classOffsetInCache);1006*chainPtr++ = classOffsetInCache;1007return true;1008}10091010bool1011TR_J9SharedCache::writeClassesToChain(J9Class *clazz, int32_t numSuperclasses, UDATA * & chainPtr)1012{1013LOG(3, "\t\twriteClassesToChain:\n");10141015for (int32_t index=0; index < numSuperclasses;index++)1016{1017J9ROMClass *romClass = TR::Compiler->cls.romClassOfSuperClass(fe()->convertClassPtrToClassOffset(clazz), index);1018if (!writeClassToChain(romClass, chainPtr))1019return false;1020}1021return true;1022}10231024bool1025TR_J9SharedCache::writeInterfacesToChain(J9Class *clazz, UDATA * & chainPtr)1026{1027LOG(3, "\t\twriteInterfacesToChain:\n");10281029J9ITable *element = TR::Compiler->cls.iTableOf(fe()->convertClassPtrToClassOffset(clazz));1030while (element != NULL)1031{1032J9ROMClass *romClass = TR::Compiler->cls.iTableRomClass(element);1033if (!writeClassToChain(romClass, chainPtr))1034return false;10351036element = TR::Compiler->cls.iTableNext(element);1037}10381039return true;1040}10411042bool1043TR_J9SharedCache::fillInClassChain(J9Class *clazz, UDATA *chainData, uint32_t chainLength,1044uint32_t numSuperclasses, uint32_t numInterfaces)1045{1046LOG(3, "\t\tChain %p store chainLength %d\n", chainData, chainLength);10471048UDATA *chainPtr = chainData;1049*chainPtr++ = chainLength;1050J9ROMClass* romClass = TR::Compiler->cls.romClassOf(fe()->convertClassPtrToClassOffset(clazz));1051writeClassToChain(romClass, chainPtr);1052if (!writeClassesToChain(clazz, numSuperclasses, chainPtr))1053{1054return false;1055}10561057if (!writeInterfacesToChain(clazz, chainPtr))1058{1059return false;1060}10611062LOG(3, "\t\tfillInClassChain returning true\n");1063return chainData;1064}106510661067bool1068TR_J9SharedCache::romclassMatchesCachedVersion(J9ROMClass *romClass, UDATA * & chainPtr, UDATA *chainEnd)1069{1070J9UTF8 * className = J9ROMCLASS_CLASSNAME(romClass);1071UDATA romClassOffset;1072if (!isROMClassInSharedCache(romClass, &romClassOffset))1073return false;1074LOG(3, "\t\tExamining romclass %p (%.*s) offset %d, comparing to %d\n", romClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className), romClassOffset, *chainPtr);1075if ((chainPtr > chainEnd) || (romClassOffset != *chainPtr++))1076return false;1077return true;1078}10791080UDATA *1081TR_J9SharedCache::findChainForClass(J9Class *clazz, const char *key, uint32_t keyLength)1082{1083UDATA * chainForClass = NULL;1084#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))1085J9SharedDataDescriptor dataDescriptor;1086dataDescriptor.address = NULL;1087TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());10881089J9VMThread *vmThread = fej9->getCurrentVMThread();1090sharedCacheConfig()->findSharedData(vmThread,1091key,1092keyLength,1093J9SHR_DATA_TYPE_AOTCLASSCHAIN,1094FALSE,1095&dataDescriptor,1096NULL);10971098//fprintf(stderr,"findChainForClass: key %.*s chain %p\n", keyLength, key, dataDescriptor.address);1099chainForClass = (UDATA *) dataDescriptor.address;1100#endif1101return chainForClass;1102}11031104bool1105TR_J9SharedCache::validateSuperClassesInClassChain(TR_OpaqueClassBlock *clazz, UDATA * & chainPtr, UDATA *chainEnd)1106{1107int32_t numSuperclasses = TR::Compiler->cls.classDepthOf(clazz);1108for (int32_t index=0; index < numSuperclasses; index++)1109{1110J9ROMClass *romClass = TR::Compiler->cls.romClassOfSuperClass(clazz, index);1111if (!romclassMatchesCachedVersion(romClass, chainPtr, chainEnd))1112{1113LOG(1, "\tClass in hierarchy did not match, returning false\n");1114return false;1115}1116}1117return true;1118}11191120bool1121TR_J9SharedCache::validateInterfacesInClassChain(TR_OpaqueClassBlock *clazz, UDATA * & chainPtr, UDATA *chainEnd)1122{1123J9ITable *interfaceElement = TR::Compiler->cls.iTableOf(clazz);1124while (interfaceElement)1125{1126J9ROMClass * romClass = TR::Compiler->cls.iTableRomClass(interfaceElement);1127if (!romclassMatchesCachedVersion(romClass, chainPtr, chainEnd))1128{1129LOG(1, "\tInterface class did not match, returning false\n");1130return false;1131}1132interfaceElement = TR::Compiler->cls.iTableNext(interfaceElement);1133}1134return true;1135}11361137bool1138TR_J9SharedCache::validateClassChain(J9ROMClass *romClass, TR_OpaqueClassBlock *clazz, UDATA * & chainPtr, UDATA *chainEnd)1139{1140bool validationSucceeded = false;11411142if (!romclassMatchesCachedVersion(romClass, chainPtr, chainEnd))1143{1144LOG(1, "\tClass did not match, returning false\n");1145}1146else if (!validateSuperClassesInClassChain(clazz, chainPtr, chainEnd))1147{1148LOG(1, "\tClass in hierarchy did not match, returning false\n");1149}1150else if (!validateInterfacesInClassChain(clazz, chainPtr, chainEnd))1151{1152LOG(1, "\tInterface class did not match, returning false\n");1153}1154else if (chainPtr != chainEnd)1155{1156LOG(1, "\tfinished classes and interfaces, but not at chain end, returning false\n");1157}1158else1159{1160validationSucceeded = true;1161}11621163return validationSucceeded;1164}11651166bool1167TR_J9SharedCache::classMatchesCachedVersion(J9Class *clazz, UDATA *chainData)1168{1169J9ROMClass *romClass = TR::Compiler->cls.romClassOf(fe()->convertClassPtrToClassOffset(clazz));1170J9UTF8 * className = J9ROMCLASS_CLASSNAME(romClass);1171LOG(1, "classMatchesCachedVersion class %p %.*s\n", clazz, J9UTF8_LENGTH(className), J9UTF8_DATA(className));11721173uintptr_t classOffsetInCache;11741175/* If the pointer isn't the SCC, then return false immmediately1176* as the map holds offsets into the SCC of romclasses1177*/1178if (!isROMClassInSharedCache(romClass, &classOffsetInCache))1179{1180LOG(1, "\tclass not in shared cache, returning false\n");1181return false;1182}11831184/* Check if the validation of the class chain was previously1185* performed; if so, return the result of that validation1186*/1187if (TR::Options::getAOTCmdLineOptions()->getOption(TR_EnableClassChainValidationCaching))1188{1189auto result = getCachedCCVResult(reinterpret_cast<TR_OpaqueClassBlock *>(clazz));1190if (result == CCVResult::success)1191{1192LOG(1, "\tcached result: validation succeeded\n");1193return true;1194}1195else if (result == CCVResult::failure)1196{1197LOG(1, "\tcached result: validation failed\n");1198return false;1199}1200else1201{1202TR_ASSERT_FATAL(result == CCVResult::notYetValidated, "Unknown result cached %d\n", result);1203}1204}12051206/* If the chainData passed in is NULL, try to find it in the SCC1207* using the romclass1208*/1209if (chainData == NULL)1210{1211char key[17]; // longest possible key length is way less than 16 digits1212uint32_t keyLength;1213createClassKey(classOffsetInCache, key, keyLength);1214LOG(3, "\tno chain specific, so looking up for key %.*s\n", keyLength, key);1215chainData = findChainForClass(clazz, key, keyLength);1216}12171218/* If the chainData is still NULL, cache the result as failure1219* and return false1220*/1221if (chainData == NULL)1222{1223LOG(1, "\tno stored chain, returning false\n");1224if (TR::Options::getAOTCmdLineOptions()->getOption(TR_EnableClassChainValidationCaching))1225cacheCCVResult(reinterpret_cast<TR_OpaqueClassBlock *>(clazz), CCVResult::failure);12261227return false;1228}12291230UDATA *chainPtr = chainData;1231UDATA chainLength = *chainPtr++;1232UDATA *chainEnd = (UDATA *) (((U_8*)chainData) + chainLength);1233LOG(3, "\tfound chain: %p with length %d\n", chainData, chainLength);12341235/* Perform class chain validation */1236bool success = validateClassChain(romClass, fe()->convertClassPtrToClassOffset(clazz), chainPtr, chainEnd);12371238/* Cache the result of the validation */1239if (TR::Options::getAOTCmdLineOptions()->getOption(TR_EnableClassChainValidationCaching))1240{1241auto result = success ? CCVResult::success : CCVResult::failure;1242cacheCCVResult(reinterpret_cast<TR_OpaqueClassBlock *>(clazz), result);1243}12441245if (success)1246LOG(1, "\tMatch! return true\n");12471248return success;1249}12501251TR_OpaqueClassBlock *1252TR_J9SharedCache::lookupClassFromChainAndLoader(uintptr_t *chainData, void *classLoader)1253{1254UDATA *ptrToRomClassOffset = chainData+1;1255J9ROMClass *romClass = romClassFromOffsetInSharedCache(*ptrToRomClassOffset);1256J9UTF8 *className = J9ROMCLASS_CLASSNAME(romClass);1257TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());1258J9VMThread *vmThread = fej9->getCurrentVMThread();1259J9Class *clazz = jitGetClassInClassloaderFromUTF8(vmThread, (J9ClassLoader *) classLoader,1260(char *) J9UTF8_DATA(className),1261J9UTF8_LENGTH(className));12621263if (clazz != NULL && classMatchesCachedVersion(clazz, chainData))1264return (TR_OpaqueClassBlock *) clazz;12651266return NULL;1267}12681269uintptr_t1270TR_J9SharedCache::getClassChainOffsetIdentifyingLoader(TR_OpaqueClassBlock *clazz, uintptr_t **classChain)1271{1272void *loaderForClazz = _fe->getClassLoader(clazz);1273void *classChainIdentifyingLoaderForClazz = persistentClassLoaderTable()->lookupClassChainAssociatedWithClassLoader(loaderForClazz);12741275uintptr_t classChainOffsetInSharedCache;1276TR::Compilation *comp = TR::comp();1277if (comp)1278{1279/*1280* TR_J9SharedCache::offsetInSharedCacheFrom* asserts if the pointer1281* passed in does not exist in the SCC. Under HCR, when an agent redefines1282* a class, it causes the J9Class pointer to stay the same, but the1283* J9ROMClass pointer changes. This means that if the compiler has a1284* reference to a J9Class who J9ROMClass was in the SCC at one point in the1285* compilation, it may no longer be so at another point in the compilation.1286*1287* This means that the compilation is no longer valid and should be aborted.1288* Even if there isn't an abort during the compilation, at the end of the1289* compilation, the compiler will fail the compile if such a redefinition1290* occurred.1291*1292* Calling TR_J9SharedCache::offsetInSharedCacheFromPointer after such a1293* redefinition could result in an assert. Therefore, this method exists as1294* a wrapper around TR_J9SharedCache::isPointerInSharedCache which doesn't1295* assert and conveniently, updates the location referred to by the cacheOffset1296* pointer passed in as a parameter.1297*1298* If the ptr isn't in the SCC, then the current method will abort the1299* compilation. If the ptr is in the SCC, then the cacheOffset will be updated.1300*/1301if (!isPointerInSharedCache(classChainIdentifyingLoaderForClazz, &classChainOffsetInSharedCache))1302comp->failCompilation<J9::ClassChainPersistenceFailure>("Failed to find pointer %p in SCC", classChainIdentifyingLoaderForClazz);1303}1304else1305{1306/*1307* If we're not in a compilation, then perhaps it's better to call this API1308* which will assert if anything's amiss1309*/1310classChainOffsetInSharedCache = offsetInSharedCacheFromPointer(classChainIdentifyingLoaderForClazz);1311}13121313if (classChain)1314*classChain = (uintptr_t *)classChainIdentifyingLoaderForClazz;1315return classChainOffsetInSharedCache;1316}13171318#if defined(J9VM_OPT_JITSERVER)1319uintptr_t1320TR_J9SharedCache::getClassChainOffsetIdentifyingLoaderNoFail(TR_OpaqueClassBlock *clazz, uintptr_t **classChain)1321{1322TR_ASSERT_FATAL(TR::comp() && !TR::comp()->isOutOfProcessCompilation(),1323"getClassChainOffsetIdentifyingLoaderNoFail should be called only the JVM client");1324void *loaderForClazz = _fe->getClassLoader(clazz);1325void *classChainIdentifyingLoaderForClazz = persistentClassLoaderTable()->lookupClassChainAssociatedWithClassLoader(loaderForClazz);1326uintptr_t classChainOffsetInSharedCache;1327if (!isPointerInSharedCache(classChainIdentifyingLoaderForClazz, &classChainOffsetInSharedCache))1328return 0;13291330if (classChain)1331*classChain = (uintptr_t *)classChainIdentifyingLoaderForClazz;1332return classChainOffsetInSharedCache;1333}1334#endif // defined(J9VM_OPT_JITSERVER)13351336const void *1337TR_J9SharedCache::storeSharedData(J9VMThread *vmThread, char *key, J9SharedDataDescriptor *descriptor)1338{1339#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))1340return _sharedCacheConfig->storeSharedData(1341vmThread,1342key,1343strlen(key),1344descriptor);1345#else1346return NULL;1347#endif1348}13491350#if defined(J9VM_OPT_JITSERVER)1351TR_J9JITServerSharedCache::TR_J9JITServerSharedCache(TR_J9VMBase *fe)1352: TR_J9SharedCache(fe)1353{1354_stream = NULL;1355}13561357uintptr_t *1358TR_J9JITServerSharedCache::rememberClass(J9Class *clazz, const AOTCacheClassChainRecord **classChainRecord, bool create)1359{1360TR_ASSERT_FATAL(classChainRecord || !create, "Must pass classChainRecord if creating class chain at JITServer");1361TR_ASSERT(_stream, "stream must be initialized by now");13621363uintptr_t *classChain = NULL;1364TR::Compilation *comp = TR::compInfoPT->getCompilation();1365ClientSessionData *clientData = comp->getClientData();1366bool needClassChainRecord = create && comp->isAOTCacheStore();1367const AOTCacheClassChainRecord *record = NULL;13681369// Check if the class chain is already cached1370auto &cache = clientData->getClassChainDataMap();1371{1372OMR::CriticalSection classChainDataMapMonitor(clientData->getClassChainDataMapMonitor());1373auto it = cache.find(clazz);1374if (it != cache.end())1375{1376classChain = it->second._classChain;1377record = it->second._aotCacheClassChainRecord;1378}1379}13801381// If the class chain is cached and the AOT cache record is either cached or not needed, return the cached values1382if (classChain && (record || !needClassChainRecord))1383{1384if (classChainRecord)1385*classChainRecord = record;1386return classChain;1387}13881389// Request missing class chain information from the client1390_stream->write(JITServer::MessageType::SharedCache_rememberClass, clazz, create, needClassChainRecord);1391auto recv = _stream->read<uintptr_t *, std::vector<J9Class *>, std::vector<J9Class *>,1392std::vector<JITServerHelpers::ClassInfoTuple>>();1393if (classChain)1394TR_ASSERT_FATAL(std::get<0>(recv) == classChain, "Received mismatching class chain: %p != %p",1395std::get<0>(recv), classChain);1396classChain = std::get<0>(recv);1397auto &ramClassChain = std::get<1>(recv);1398auto &uncachedRAMClasses = std::get<2>(recv);1399auto &uncachedClassInfos = std::get<3>(recv);14001401// Cache the result if the class chain was succesfully created at the client1402if (classChain && create)1403{1404if (needClassChainRecord)1405{1406JITServerHelpers::cacheRemoteROMClassBatch(clientData, uncachedRAMClasses, uncachedClassInfos);1407// This call will cache both the class chain and the AOT cache record in the client session1408record = clientData->getClassChainRecord(clazz, classChain, ramClassChain, _stream);1409if (classChainRecord)1410*classChainRecord = record;1411}1412else1413{1414OMR::CriticalSection classChainDataMapMonitor(clientData->getClassChainDataMapMonitor());1415cache.insert({ clazz, { classChain, NULL } });1416}1417}14181419return classChain;1420}14211422J9SharedClassCacheDescriptor *1423TR_J9JITServerSharedCache::getCacheDescriptorList()1424{1425auto *vmInfo = TR::compInfoPT->getClientData()->getOrCacheVMInfo(_stream);1426return vmInfo->_j9SharedClassCacheDescriptorList;1427}14281429uintptr_t1430TR_J9JITServerSharedCache::getClassChainOffsetIdentifyingLoader(TR_OpaqueClassBlock *clazz, uintptr_t **classChain)1431{1432TR_ASSERT(!classChain, "Must always be NULL at JITServer");1433TR_ASSERT(_stream, "stream must be initialized by now");14341435uintptr_t classChainOffset = 0;1436ClientSessionData *clientData = TR::compInfoPT->getClientData();1437JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazz, clientData, _stream,1438JITServerHelpers::CLASSINFO_CLASS_CHAIN_OFFSET_IDENTIFYING_LOADER,1439(void *)&classChainOffset);1440// Test if cached value of `classChainOffset` is initialized. Ask the client if it's not.1441// This situation is possible if we cache ClassInfo during a non-AOT compilation.1442if (classChainOffset == 0)1443{1444// Request the class name identifying loader if this client uses AOT cache1445// (even if the result of this specific compilation won't be stored in AOT cache)1446bool getName = clientData->usesAOTCache();1447_stream->write(JITServer::MessageType::SharedCache_getClassChainOffsetIdentifyingLoader, clazz, getName);1448auto recv = _stream->read<uintptr_t, std::string>();1449classChainOffset = std::get<0>(recv);1450auto &className = std::get<1>(recv);14511452// If we got a valid value back, cache that1453if (classChainOffset)1454{1455OMR::CriticalSection getRemoteROMClass(clientData->getROMMapMonitor());1456auto it = clientData->getROMClassMap().find((J9Class *)clazz);1457if (it != clientData->getROMClassMap().end())1458{1459it->second._classChainOffsetIdentifyingLoader = classChainOffset;1460if (getName)1461it->second._classNameIdentifyingLoader = className;1462}1463}1464}1465return classChainOffset;1466}14671468void1469TR_J9JITServerSharedCache::addHint(J9Method * method, TR_SharedCacheHint theHint)1470{1471TR_ASSERT(_stream, "stream must be initialized by now");1472auto *vmInfo = TR::compInfoPT->getClientData()->getOrCacheVMInfo(_stream);1473if (vmInfo->_hasSharedClassCache)1474{1475_stream->write(JITServer::MessageType::SharedCache_addHint, method, theHint);1476_stream->read<JITServer::Void>();1477}1478}14791480const void *1481TR_J9JITServerSharedCache::storeSharedData(J9VMThread *vmThread, char *key, J9SharedDataDescriptor *descriptor)1482{1483TR_ASSERT(_stream, "stream must be initialized by now");1484std::string dataStr((char *) descriptor->address, descriptor->length);14851486_stream->write(JITServer::MessageType::SharedCache_storeSharedData, std::string(key, strlen(key)), *descriptor, dataStr);1487return std::get<0>(_stream->read<const void *>());1488}14891490#endif149114921493