Path: blob/master/runtime/compiler/control/JITServerHelpers.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2019, 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 "control/JITServerHelpers.hpp"2324#include "control/CompilationRuntime.hpp"25#include "control/JITServerCompilationThread.hpp"26#include "control/MethodToBeCompiled.hpp"27#include "env/StackMemoryRegion.hpp"28#include "infra/CriticalSection.hpp"29#include "infra/Statistics.hpp"30#include "net/CommunicationStream.hpp"31#include "OMR/Bytes.hpp"// for OMR::alignNoCheck()32#include "runtime/JITServerAOTDeserializer.hpp"33#include "runtime/JITServerSharedROMClassCache.hpp"34#include "romclasswalk.h"35#include "util_api.h"// for allSlotsInROMClassDo()363738uint32_t JITServerHelpers::serverMsgTypeCount[] = {};39uint64_t JITServerHelpers::_waitTimeMs = 0;40bool JITServerHelpers::_serverAvailable = true;41uint64_t JITServerHelpers::_nextConnectionRetryTime = 0;42TR::Monitor *JITServerHelpers::_clientStreamMonitor = NULL;434445// To ensure that the length fields in UTF8 strings appended at the end of the46// packed ROMClass are properly aligned, we must pad the strings accordingly.47// This function returns the total size of a UTF8 string with the padding.48static size_t49getUTF8Size(const J9UTF8 *str)50{51return OMR::alignNoCheck(J9UTF8_TOTAL_SIZE(str), sizeof(*str));52}5354// Copies a UTF8 string and returns its total size including the padding.55// src doesn't have to be padded, dst is padded.56static size_t57copyUTF8(J9UTF8 *dst, const J9UTF8 *src)58{59size_t size = J9UTF8_TOTAL_SIZE(src);60memcpy(dst, src, size);61static_assert(sizeof(*src) == 2, "UTF8 header is not 2 bytes large");62// If the length is not aligned, pad the destination string with a zero63if (!OMR::alignedNoCheck(size, sizeof(*src)))64dst->data[src->length] = '\0';65return getUTF8Size(src);66}6768// State maintained while iterating over UTF8 strings in a ROMClass69struct ROMClassPackContext70{71ROMClassPackContext(TR_Memory *trMemory, size_t origSize) :72_origSize(origSize), _callback(NULL), _stringsSize(0),73_utf8SectionStart((const uint8_t *)-1), _utf8SectionEnd(NULL), _utf8SectionSize(0),74_strToOffsetMap(decltype(_strToOffsetMap)::allocator_type(trMemory->currentStackRegion())),75_packedRomClass(NULL), _cursor(NULL) {}7677bool isInline(const void *address, const J9ROMClass *romClass)78{79return (address >= romClass) && (address < (uint8_t *)romClass + _origSize);80}8182typedef void (*Callback)(const J9ROMClass *, const J9SRP *, const char *, ROMClassPackContext &);8384const size_t _origSize;85Callback _callback;86size_t _stringsSize;87const uint8_t *_utf8SectionStart;88const uint8_t *_utf8SectionEnd;// only needed for assertions89size_t _utf8SectionSize;// only needed for assertions90// Maps original strings to their offsets from UTF8 section start in the packed ROMClass91// Offset value -1 signifies that the string is skipped92UnorderedMap<const J9UTF8 *, size_t> _strToOffsetMap;93J9ROMClass *_packedRomClass;94uint8_t *_cursor;95};9697static bool98shouldSkipSlot(const char *slotName)99{100// Skip variable names and signatures in method debug info; only their slot names have prefix "variable"101static const char prefix[] = "variable";102return strncmp(slotName, prefix, sizeof(prefix) - 1) == 0;103}104105// Updates size info and maps original string to its future location in the packed ROMClass106static void107sizeInfoCallback(const J9ROMClass *romClass, const J9SRP *origSrp, const char *slotName, ROMClassPackContext &ctx)108{109// Skip SRPs stored outside of the ROMClass bounds such as the ones in out-of-line110// method debug info, and the ones that point to strings not used by the JIT.111bool skip = !ctx.isInline(origSrp, romClass) || shouldSkipSlot(slotName);112auto str = NNSRP_PTR_GET(origSrp, const J9UTF8 *);113auto result = ctx._strToOffsetMap.insert({ str, skip ? (size_t)-1 : ctx._stringsSize });114if (!result.second)// duplicate - already visited115{116auto &it = result.first;117if (!skip && (it->second == (size_t)-1))118{119// Previously visited SRPs to this string were skipped, but this one isn't120it->second = ctx._stringsSize;121ctx._stringsSize += getUTF8Size(str);122}123return;124}125126size_t size = getUTF8Size(str);127ctx._stringsSize += skip ? 0 : size;128129if (ctx.isInline(str, romClass))130{131ctx._utf8SectionStart = std::min(ctx._utf8SectionStart, (const uint8_t *)str);132ctx._utf8SectionEnd = std::max(ctx._utf8SectionEnd, (const uint8_t *)str + size);133ctx._utf8SectionSize += size;134}135}136137// Copies original string into its location in the packed ROMClass and updates the SRP to it138static void139packCallback(const J9ROMClass *romClass, const J9SRP *origSrp, const char *slotName, ROMClassPackContext &ctx)140{141// Skip SRPs stored outside of the ROMClass bounds such as the ones in out-of-line method debug info142if (!ctx.isInline(origSrp, romClass))143return;144145auto str = NNSRP_PTR_GET(origSrp, const J9UTF8 *);146auto srp = (J9SRP *)((uint8_t *)ctx._packedRomClass + ((uint8_t *)origSrp - (uint8_t *)romClass));147148// Zero out skipped string SRPs149if (shouldSkipSlot(slotName))150{151TR_ASSERT(ctx._strToOffsetMap.find(str) != ctx._strToOffsetMap.end(),152"UTF8 slot %s not visited in 1st pass", slotName);153*srp = 0;154return;155}156157auto it = ctx._strToOffsetMap.find(str);158TR_ASSERT(it != ctx._strToOffsetMap.end(), "UTF8 slot %s not visited in 1st pass", slotName);159auto dst = (uint8_t *)ctx._packedRomClass + (ctx._utf8SectionStart - (uint8_t *)romClass) + it->second;160161NNSRP_PTR_SET(srp, dst);162if (dst == ctx._cursor)163ctx._cursor += copyUTF8((J9UTF8 *)dst, str);164else165TR_ASSERT((dst < ctx._cursor) && (memcmp(dst, str, J9UTF8_TOTAL_SIZE(str)) == 0), "Must be already copied");166}167168static void169utf8SlotCallback(const J9ROMClass *romClass, const J9SRP *srp, const char *slotName, void *userData)170{171auto &ctx = *(ROMClassPackContext *)userData;172if (*srp)173ctx._callback(romClass, srp, slotName, ctx);174}175176// Invoked for each slot in a ROMClass. Calls ctx._callback for all non-null SRPs to UTF8 strings.177static void178slotCallback(J9ROMClass *romClass, uint32_t slotType, void *slotPtr, const char *slotName, void *userData)179{180switch (slotType)181{182case J9ROM_UTF8:183utf8SlotCallback(romClass, (const J9SRP *)slotPtr, slotName, userData);184break;185186case J9ROM_NAS:187if (auto nas = SRP_PTR_GET(slotPtr, const J9ROMNameAndSignature *))188{189utf8SlotCallback(romClass, &nas->name, slotName, userData);190utf8SlotCallback(romClass, &nas->signature, slotName, userData);191}192break;193}194}195196static bool197isArrayROMClass(const J9ROMClass *romClass)198{199if (!J9ROMCLASS_IS_ARRAY(romClass))200return false;201202auto name = J9ROMCLASS_CLASSNAME(romClass);203TR_ASSERT((name->length == 2) && (name->data[0] == '['),204"Unexpected array ROMClass name: %.*s", name->length, name->data);205return true;206}207208// Array ROMClasses have a different layout (see runtime/vm/romclasses.c):209// they all share the same SRP array of interfaces, which breaks the generic210// packing implementation. Instead, we manually pack all the data stored211// outside of the ROMClass header: class name, superclass name, interfaces.212// This function returns the total size of the packed array ROMClass.213static size_t214getArrayROMClassPackedSize(const J9ROMClass *romClass)215{216size_t totalSize = sizeof(*romClass);217totalSize += getUTF8Size(J9ROMCLASS_CLASSNAME(romClass));218totalSize += getUTF8Size(J9ROMCLASS_SUPERCLASSNAME(romClass));219220totalSize += romClass->interfaceCount * sizeof(J9SRP);221for (size_t i = 0; i < romClass->interfaceCount; ++i)222{223auto name = NNSRP_GET(J9ROMCLASS_INTERFACES(romClass)[i], const J9UTF8 *);224totalSize += getUTF8Size(name);225}226227return OMR::alignNoCheck(totalSize, sizeof(uint64_t));228}229230static void231packUTF8(const J9UTF8 *str, J9SRP &srp, ROMClassPackContext &ctx)232{233NNSRP_SET(srp, ctx._cursor);234ctx._cursor += copyUTF8((J9UTF8 *)ctx._cursor, str);235}236237// Packs the data stored outside of the array ROMClass header238static void239packArrayROMClassData(const J9ROMClass *romClass, ROMClassPackContext &ctx)240{241NNSRP_SET(ctx._packedRomClass->interfaces, ctx._cursor);242ctx._cursor += ctx._packedRomClass->interfaceCount * sizeof(J9SRP);243244packUTF8(J9ROMCLASS_CLASSNAME(romClass), ctx._packedRomClass->className, ctx);245packUTF8(J9ROMCLASS_SUPERCLASSNAME(romClass), ctx._packedRomClass->superclassName, ctx);246247for (size_t i = 0; i < romClass->interfaceCount; ++i)248{249auto name = NNSRP_GET(J9ROMCLASS_INTERFACES(romClass)[i], const J9UTF8 *);250packUTF8(name, J9ROMCLASS_INTERFACES(ctx._packedRomClass)[i], ctx);251}252}253254// Packs a ROMClass to be transferred to the server.255//256// The result is allocated from the stack region of trMemory (as well as temporary data257// structures used for packing). This function should be used with TR::StackMemoryRegion.258// If passed non-zero expectedSize, and it doesn't match the resulting packedSize259// (which is returned to the caller by reference), this function returns NULL.260//261// UTF8 strings that a ROMClass refers to can be interned and stored outside of262// the ROMClass body. This function puts all the strings (including interned ones)263// at the end of the cloned ROMClass in deterministic order and updates the SRPs264// to them. It also removes some of the data that is not used by the JIT compiler.265//266// Note that the strings that were stored inside of the original ROMClass body267// do not keep their offsets in the serialized ROMClass (in the general case).268// The order in which the strings are serialized is determined by the ROMClass269// walk, not by their original locations.270//271// Packing involves 2 passes over all the strings that a ROMClass refers to:272// 1. Compute total size and map original strings to their locations in the packed ROMClass.273// 2. Copy each original string to its location in the packed ROMClass.274//275// This implementation makes (and checks at runtime) the following assumptions:276// - Intermediate class data is either stored at the end of the ROMClass, or points277// to the ROMClass itself, or is interned (i.e. points outside of the ROMClass).278// - All non-interned strings are stored in a single contiguous range (the UTF8 section)279// located at the end of the ROMClass (can only be followed by intermediate class data).280// - ROMClass walk visits all the strings that the ROMClass references.281//282J9ROMClass *283JITServerHelpers::packROMClass(J9ROMClass *romClass, TR_Memory *trMemory, size_t &packedSize, size_t expectedSize)284{285auto name = J9ROMCLASS_CLASSNAME(romClass);286// Primitive ROMClasses have different layout (see runtime/vm/romclasses.c): the last287// ROMClass includes all the others' UTF8 name strings in its romSize, which breaks the288// generic packing implementation. Pretend that its romSize only includes the header.289size_t origRomSize = J9ROMCLASS_IS_PRIMITIVE_TYPE(romClass) ? sizeof(*romClass) : romClass->romSize;290packedSize = origRomSize;291292// Remove intermediate class data (not used by JIT)293uint8_t *icData = J9ROMCLASS_INTERMEDIATECLASSDATA(romClass);294if (JITServerHelpers::isAddressInROMClass(icData, romClass) && (icData != (uint8_t *)romClass))295{296TR_ASSERT_FATAL(icData + romClass->intermediateClassDataLength == (uint8_t *)romClass + romClass->romSize,297"Intermediate class data not stored at the end of ROMClass %.*s", name->length, name->data);298packedSize -= romClass->intermediateClassDataLength;299}300301ROMClassPackContext ctx(trMemory, origRomSize);302303size_t copySize = 0;304if (isArrayROMClass(romClass))305{306copySize = sizeof(*romClass);307packedSize = getArrayROMClassPackedSize(romClass);308}309else310{311// 1st pass: iterate all strings in the ROMClass to compute its total size (including312// interned strings) and map the strings to their locations in the packed ROMClass313ctx._callback = sizeInfoCallback;314allSlotsInROMClassDo(romClass, slotCallback, NULL, NULL, &ctx);315// Handle the case when all strings are interned316auto classEnd = (const uint8_t *)romClass + packedSize;317ctx._utf8SectionStart = std::min(ctx._utf8SectionStart, classEnd);318319auto end = ctx._utf8SectionEnd ? ctx._utf8SectionEnd : classEnd;320TR_ASSERT_FATAL(ctx._utf8SectionSize == end - ctx._utf8SectionStart,321"Missed strings in ROMClass %.*s UTF8 section: %zu != %zu",322name->length, name->data, ctx._utf8SectionSize, end - ctx._utf8SectionStart);323end = (const uint8_t *)OMR::alignNoCheck((uintptr_t)end, sizeof(uint64_t));324TR_ASSERT_FATAL(end == classEnd, "UTF8 section not stored at the end of ROMClass %.*s: %p != %p",325name->length, name->data, end, classEnd);326327copySize = ctx._utf8SectionStart - (const uint8_t *)romClass;328packedSize = OMR::alignNoCheck(copySize + ctx._stringsSize, sizeof(uint64_t));329}330331// Check if expected size matches, otherwise fail early. Size mismatch can occur when JIT client332// packs a ROMClass before computing its hash when deserializing a JITServer-cached AOT method that333// was compiled for a different version of the class. In such cases, we can skip the rest of the334// packing procedure and hash computation since we already know that the ROMClass doesn't match.335if (expectedSize && (expectedSize != packedSize))336return NULL;337338ctx._packedRomClass = (J9ROMClass *)trMemory->allocateStackMemory(packedSize);339if (!ctx._packedRomClass)340throw std::bad_alloc();341memcpy(ctx._packedRomClass, romClass, copySize);342ctx._packedRomClass->romSize = packedSize;343ctx._cursor = (uint8_t *)ctx._packedRomClass + copySize;344345// Zero out SRP to intermediate class data346ctx._packedRomClass->intermediateClassData = 0;347ctx._packedRomClass->intermediateClassDataLength = 0;348349// Zero out SRPs to out-of-line method debug info350J9ROMMethod *romMethod = J9ROMCLASS_ROMMETHODS(ctx._packedRomClass);351for (size_t i = 0; i < ctx._packedRomClass->romMethodCount; ++i)352{353if (J9ROMMETHOD_HAS_DEBUG_INFO(romMethod))354{355auto debugInfo = methodDebugInfoFromROMMethod(romMethod);356if (!(debugInfo->srpToVarInfo & 1))357debugInfo->srpToVarInfo = 0;358}359romMethod = nextROMMethod(romMethod);360}361362if (isArrayROMClass(romClass))363{364packArrayROMClassData(romClass, ctx);365}366else367{368// 2nd pass: copy all strings to their locations in the packed ROMClass369ctx._callback = packCallback;370allSlotsInROMClassDo(romClass, slotCallback, NULL, NULL, &ctx);371}372373// Pad to required alignment374auto end = (uint8_t *)OMR::alignNoCheck((uintptr_t)ctx._cursor, sizeof(uint64_t));375TR_ASSERT_FATAL(end == (uint8_t *)ctx._packedRomClass + packedSize, "Invalid final cursor position: %p != %p",376end, (uint8_t *)ctx._packedRomClass + packedSize);377memset(ctx._cursor, 0, end - ctx._cursor);378379return ctx._packedRomClass;380}381382// insertIntoOOSequenceEntryList needs to be executed with sequencingMonitor in hand.383// This method belongs to ClientSessionData, but is temporarily moved here to be able384// to push the ClientSessionData related code as a standalone piece.385void386JITServerHelpers::insertIntoOOSequenceEntryList(ClientSessionData *clientData, TR_MethodToBeCompiled *entry)387{388uint32_t seqNo = ((TR::CompilationInfoPerThreadRemote*)(entry->_compInfoPT))->getSeqNo();389TR_MethodToBeCompiled *crtEntry = clientData->getOOSequenceEntryList();390TR_MethodToBeCompiled *prevEntry = NULL;391while (crtEntry && (seqNo > ((TR::CompilationInfoPerThreadRemote*)(crtEntry->_compInfoPT))->getSeqNo()))392{393prevEntry = crtEntry;394crtEntry = crtEntry->_next;395}396entry->_next = crtEntry;397if (prevEntry)398prevEntry->_next = entry;399else400clientData->setOOSequenceEntryList(entry);401}402403void404JITServerHelpers::printJITServerMsgStats(J9JITConfig *jitConfig, TR::CompilationInfo *compInfo)405{406uint32_t totalMsgCount = 0;407#ifdef MESSAGE_SIZE_STATS408uint64_t totalMsgSize = 0;409#endif // defined(MESSAGE_SIZE_STATS)410PORT_ACCESS_FROM_JITCONFIG(jitConfig);411412j9tty_printf(PORTLIB, "JITServer Message Type Statistics:\n");413j9tty_printf(PORTLIB, "Type# #called");414#ifdef MESSAGE_SIZE_STATS415j9tty_printf(PORTLIB, "\t\tMax\t\tMin\t\tMean\t\tStdDev\t\tSum");416#endif // defined(MESSAGE_SIZE_STATS)417j9tty_printf(PORTLIB, "\t\tTypeName\n");418419if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::CLIENT)420{421for (int i = 0; i < JITServer::MessageType_MAXTYPE; ++i)422{423if (serverMsgTypeCount[i])424{425j9tty_printf(PORTLIB, "#%04d %7u", i, serverMsgTypeCount[i]);426#ifdef MESSAGE_SIZE_STATS427auto &stat = JITServer::CommunicationStream::msgSizeStats[i];428j9tty_printf(PORTLIB, "\t%f\t%f\t%f\t%f\t%f",429stat.maxVal(), stat.minVal(), stat.mean(), stat.stddev(), stat.sum());430totalMsgSize += stat.sum();431#endif // defined(MESSAGE_SIZE_STATS)432j9tty_printf(PORTLIB, "\t\t%s\n", JITServer::messageNames[i]);433totalMsgCount += serverMsgTypeCount[i];434}435}436j9tty_printf(PORTLIB, "Total number of messages: %u\n", totalMsgCount);437#ifdef MESSAGE_SIZE_STATS438j9tty_printf(PORTLIB, "Total amount of data received: %llu bytes\n", (unsigned long long)totalMsgSize);439#endif // defined(MESSAGE_SIZE_STATS)440441uint32_t numCompilations = serverMsgTypeCount[JITServer::MessageType::compilationCode];442if (numCompilations)443j9tty_printf(PORTLIB, "Average number of messages per compilation: %f\n",444totalMsgCount / float(numCompilations));445446if (auto deserializer = compInfo->getJITServerAOTDeserializer())447{448uint32_t numDeserializedMethods = deserializer->getNumDeserializedMethods();449if (numDeserializedMethods)450j9tty_printf(PORTLIB, "Average number of messages per compilation request (including AOT cache hits): %f\n",451totalMsgCount / float(numCompilations + numDeserializedMethods));452}453}454else if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER)455{456// to print in server, run ./jitserver -Xdump:jit:events=user457// then kill -3 <pidof jitserver>458#ifdef MESSAGE_SIZE_STATS459for (int i = 0; i < JITServer::MessageType_MAXTYPE; ++i)460{461auto &stat = JITServer::CommunicationStream::msgSizeStats[i];462if (stat.samples())463{464j9tty_printf(PORTLIB, "#%04d %7u", i, stat.samples());465j9tty_printf(PORTLIB, "\t%f\t%f\t%f\t%f\t%f",466stat.maxVal(), stat.minVal(), stat.mean(), stat.stddev(), stat.sum());467j9tty_printf(PORTLIB, "\t\t%s\n", JITServer::messageNames[i]);468totalMsgCount += stat.samples();469totalMsgSize += stat.sum();470}471}472j9tty_printf(PORTLIB, "Total number of messages: %u\n", totalMsgCount);473j9tty_printf(PORTLIB, "Total amount of data received: %llu bytes\n", (unsigned long long)totalMsgSize);474475uint32_t numCompilations = JITServer::CommunicationStream::msgSizeStats[JITServer::MessageType::compilationCode].samples();476if (numCompilations)477j9tty_printf(PORTLIB, "Average number of messages per compilation: %f\n",478totalMsgCount, totalMsgCount / float(numCompilations));479480if (auto aotCacheMap = compInfo->getJITServerAOTCacheMap())481{482uint32_t numDeserializedMethods = aotCacheMap->getNumDeserializedMethods();483if (numDeserializedMethods)484j9tty_printf(PORTLIB, "Average number of messages per compilation request (including AOT cache hits): %f\n",485totalMsgCount / float(numCompilations + numDeserializedMethods));486}487#endif // defined(MESSAGE_SIZE_STATS)488}489}490491void492JITServerHelpers::printJITServerCHTableStats(J9JITConfig *jitConfig, TR::CompilationInfo *compInfo)493{494#ifdef COLLECT_CHTABLE_STATS495PORT_ACCESS_FROM_JITCONFIG(jitConfig);496j9tty_printf(PORTLIB, "JITServer CHTable Statistics:\n");497if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::CLIENT)498{499JITClientPersistentCHTable *table = (JITClientPersistentCHTable*)compInfo->getPersistentInfo()->getPersistentCHTable();500j9tty_printf(PORTLIB, "Num updates sent: %d (1 per compilation)\n", table->_numUpdates);501if (table->_numUpdates)502{503j9tty_printf(PORTLIB, "Num commit failures: %d. Average per compilation: %f\n", table->_numCommitFailures, table->_numCommitFailures / float(table->_numUpdates));504j9tty_printf(PORTLIB, "Num classes updated: %d. Average per compilation: %f\n", table->_numClassesUpdated, table->_numClassesUpdated / float(table->_numUpdates));505j9tty_printf(PORTLIB, "Num classes removed: %d. Average per compilation: %f\n", table->_numClassesRemoved, table->_numClassesRemoved / float(table->_numUpdates));506j9tty_printf(PORTLIB, "Total update bytes: %d. Compilation max: %d. Average per compilation: %f\n", table->_updateBytes, table->_maxUpdateBytes, table->_updateBytes / float(table->_numUpdates));507}508}509else if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER)510{511JITServerPersistentCHTable *table = (JITServerPersistentCHTable*)compInfo->getPersistentInfo()->getPersistentCHTable();512j9tty_printf(PORTLIB, "Num updates received: %d (1 per compilation)\n", table->_numUpdates);513if (table->_numUpdates)514{515j9tty_printf(PORTLIB, "Num classes updated: %d. Average per compilation: %f\n", table->_numClassesUpdated, table->_numClassesUpdated / float(table->_numUpdates));516j9tty_printf(PORTLIB, "Num classes removed: %d. Average per compilation: %f\n", table->_numClassesRemoved, table->_numClassesRemoved / float(table->_numUpdates));517j9tty_printf(PORTLIB, "Num class info queries: %d. Average per compilation: %f\n", table->_numQueries, table->_numQueries / float(table->_numUpdates));518j9tty_printf(PORTLIB, "Total update bytes: %d. Compilation max: %d. Average per compilation: %f\n", table->_updateBytes, table->_maxUpdateBytes, table->_updateBytes / float(table->_numUpdates));519}520}521#endif522}523524void525JITServerHelpers::printJITServerCacheStats(J9JITConfig *jitConfig, TR::CompilationInfo *compInfo)526{527PORT_ACCESS_FROM_JITCONFIG(jitConfig);528if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER)529{530auto clientSessionHT = compInfo->getClientSessionHT();531clientSessionHT->printStats();532}533}534535/*536* Free the persistent memory allocated for the given `romClass`.537* If the server uses a global cache of ROMClasses shared among the different JVM clients,538* this routine decrements the reference count for the `romClass` given as parameter,539* and only if the ref count reaches 0, the persistent memory is freed.540*/541void542JITServerHelpers::freeRemoteROMClass(J9ROMClass *romClass, TR_PersistentMemory *persistentMemory)543{544if (auto cache = TR::CompilationInfo::get()->getJITServerSharedROMClassCache())545cache->release(romClass);546else547persistentMemory->freePersistentMemory(romClass);548}549550/*551* `cacheRemoteROMClassOrFreeIt` takes a romClass data structure allocated with552* persistent memory and attempts to cache it in the per-client data session.553* If caching suceeds, the method returns a pointer to the romClass received as parameter.554* If the caching fails, the memory for romClass received as parameter is freed555* and the method returns a pointer to the romClass from the cache556*/557J9ROMClass *558JITServerHelpers::cacheRemoteROMClassOrFreeIt(ClientSessionData *clientSessionData, J9Class *clazz,559J9ROMClass *romClass, const ClassInfoTuple &classInfoTuple)560{561OMR::CriticalSection cacheRemoteROMClass(clientSessionData->getROMMapMonitor());562auto it = clientSessionData->getROMClassMap().find(clazz);563if (it == clientSessionData->getROMClassMap().end())564{565JITServerHelpers::cacheRemoteROMClass(clientSessionData, clazz, romClass, classInfoTuple);566return romClass;567}568// romClass is already present in the cache; must free the duplicate569JITServerHelpers::freeRemoteROMClass(romClass, clientSessionData->persistentMemory());570// Return the cached romClass571return it->second._romClass;572}573574ClientSessionData::ClassInfo &575JITServerHelpers::cacheRemoteROMClass(ClientSessionData *clientSessionData, J9Class *clazz,576J9ROMClass *romClass, const ClassInfoTuple &classInfoTuple)577{578ClientSessionData::ClassInfo classInfoStruct(clientSessionData->persistentMemory());579580classInfoStruct._romClass = romClass;581J9Method *methods = std::get<1>(classInfoTuple);582classInfoStruct._methodsOfClass = methods;583classInfoStruct._baseComponentClass = std::get<2>(classInfoTuple);584classInfoStruct._numDimensions = std::get<3>(classInfoTuple);585classInfoStruct._parentClass = std::get<4>(classInfoTuple);586auto &tmpInterfaces = std::get<5>(classInfoTuple);587auto &persistentAllocator = clientSessionData->persistentMemory()->_persistentAllocator.get();588classInfoStruct._interfaces = new (persistentAllocator) PersistentVector<TR_OpaqueClassBlock *>(589tmpInterfaces.begin(), tmpInterfaces.end(),590PersistentVector<TR_OpaqueClassBlock *>::allocator_type(persistentAllocator)591);592auto &methodTracingInfo = std::get<6>(classInfoTuple);593classInfoStruct._classHasFinalFields = std::get<7>(classInfoTuple);594classInfoStruct._classDepthAndFlags = std::get<8>(classInfoTuple);595classInfoStruct._classInitialized = std::get<9>(classInfoTuple);596classInfoStruct._byteOffsetToLockword = std::get<10>(classInfoTuple);597classInfoStruct._leafComponentClass = std::get<11>(classInfoTuple);598classInfoStruct._classLoader = std::get<12>(classInfoTuple);599classInfoStruct._hostClass = std::get<13>(classInfoTuple);600classInfoStruct._componentClass = std::get<14>(classInfoTuple);601classInfoStruct._arrayClass = std::get<15>(classInfoTuple);602classInfoStruct._totalInstanceSize = std::get<16>(classInfoTuple);603classInfoStruct._remoteRomClass = std::get<17>(classInfoTuple);604classInfoStruct._constantPool = (J9ConstantPool *)std::get<18>(classInfoTuple);605classInfoStruct._classFlags = std::get<19>(classInfoTuple);606classInfoStruct._classChainOffsetIdentifyingLoader = std::get<20>(classInfoTuple);607auto &origROMMethods = std::get<21>(classInfoTuple);608classInfoStruct._classNameIdentifyingLoader = std::get<22>(classInfoTuple);609classInfoStruct._arrayElementSize = std::get<23>(classInfoTuple);610611auto result = clientSessionData->getROMClassMap().insert({ clazz, classInfoStruct });612613auto &methodMap = clientSessionData->getJ9MethodMap();614uint32_t numMethods = romClass->romMethodCount;615J9ROMMethod *romMethod = J9ROMCLASS_ROMMETHODS(romClass);616for (uint32_t i = 0; i < numMethods; i++)617{618ClientSessionData::J9MethodInfo m(romMethod, origROMMethods[i], (TR_OpaqueClassBlock *)clazz,619i, static_cast<bool>(methodTracingInfo[i]));620methodMap.insert({ &methods[i], m });621romMethod = nextROMMethod(romMethod);622}623624// Return a reference to the ClassInfo structure stored in the map in the client session625return result.first->second;626}627628J9ROMClass *629JITServerHelpers::getRemoteROMClassIfCached(ClientSessionData *clientSessionData, J9Class *clazz)630{631OMR::CriticalSection getRemoteROMClassIfCached(clientSessionData->getROMMapMonitor());632auto it = clientSessionData->getROMClassMap().find(clazz);633return (it == clientSessionData->getROMClassMap().end()) ? NULL : it->second._romClass;634}635636JITServerHelpers::ClassInfoTuple637JITServerHelpers::packRemoteROMClassInfo(J9Class *clazz, J9VMThread *vmThread, TR_Memory *trMemory, bool serializeClass)638{639// Always use the base VM here.640// If this method is called inside AOT compilation, TR_J9SharedCacheVM will641// attempt validation and return NULL for many methods invoked here.642// We do not want that, because these values will be cached and later used in non-AOT643// compilations, where we always need a non-NULL result.644TR_J9VM *fe = (TR_J9VM *)TR_J9VMBase::get(vmThread->javaVM->jitConfig, vmThread);645J9Method *methodsOfClass = (J9Method *)fe->getMethods((TR_OpaqueClassBlock *)clazz);646int32_t numDims = 0;647TR_OpaqueClassBlock *baseClass = fe->getBaseComponentClass((TR_OpaqueClassBlock *)clazz, numDims);648TR_OpaqueClassBlock *parentClass = fe->getSuperClass((TR_OpaqueClassBlock *)clazz);649650uint32_t numMethods = clazz->romClass->romMethodCount;651std::vector<uint8_t> methodTracingInfo;652methodTracingInfo.reserve(numMethods);653654std::vector<J9ROMMethod *> origROMMethods;655origROMMethods.reserve(numMethods);656for (uint32_t i = 0; i < numMethods; ++i)657{658methodTracingInfo.push_back(static_cast<uint8_t>(fe->isMethodTracingEnabled((TR_OpaqueMethodBlock *)&methodsOfClass[i])));659// record client-side pointers to ROM methods660origROMMethods.push_back(fe->getROMMethodFromRAMMethod(&methodsOfClass[i]));661}662663bool classHasFinalFields = fe->hasFinalFieldsInClass((TR_OpaqueClassBlock *)clazz);664uintptr_t classDepthAndFlags = fe->getClassDepthAndFlagsValue((TR_OpaqueClassBlock *)clazz);665bool classInitialized = fe->isClassInitialized((TR_OpaqueClassBlock *)clazz);666uint32_t byteOffsetToLockword = fe->getByteOffsetToLockword((TR_OpaqueClassBlock *)clazz);667TR_OpaqueClassBlock *leafComponentClass = fe->getLeafComponentClassFromArrayClass((TR_OpaqueClassBlock *)clazz);668void *classLoader = fe->getClassLoader((TR_OpaqueClassBlock *)clazz);669TR_OpaqueClassBlock *hostClass = fe->convertClassPtrToClassOffset(clazz->hostClass);670TR_OpaqueClassBlock *componentClass = fe->getComponentClassFromArrayClass((TR_OpaqueClassBlock *)clazz);671TR_OpaqueClassBlock *arrayClass = fe->getArrayClassFromComponentClass((TR_OpaqueClassBlock *)clazz);672uintptr_t totalInstanceSize = clazz->totalInstanceSize;673uintptr_t cp = fe->getConstantPoolFromClass((TR_OpaqueClassBlock *)clazz);674uintptr_t classFlags = fe->getClassFlagsValue((TR_OpaqueClassBlock *)clazz);675auto sharedCache = fe->sharedCache();676uintptr_t *classChainIdentifyingLoader = NULL;677uintptr_t classChainOffsetIdentifyingLoader = sharedCache ?678sharedCache->getClassChainOffsetIdentifyingLoaderNoFail((TR_OpaqueClassBlock *)clazz, &classChainIdentifyingLoader) : 0;679680std::string classNameIdentifyingLoader;681if (fe->getPersistentInfo()->getJITServerUseAOTCache() && classChainIdentifyingLoader)682{683const J9UTF8 *name = J9ROMCLASS_CLASSNAME(sharedCache->startingROMClassOfClassChain(classChainIdentifyingLoader));684classNameIdentifyingLoader = std::string((const char *)J9UTF8_DATA(name), J9UTF8_LENGTH(name));685}686687std::string packedROMClassStr;688if (serializeClass)689{690TR::StackMemoryRegion stackMemoryRegion(*trMemory);691size_t packedSize;692J9ROMClass *packedROMClass = packROMClass(clazz->romClass, trMemory, packedSize);693packedROMClassStr = std::string((const char *)packedROMClass, packedSize);694}695696int32_t arrayElementSize = vmThread->javaVM->internalVMFunctions->arrayElementSize((J9ArrayClass*)clazz);697698return std::make_tuple(699packedROMClassStr, methodsOfClass, baseClass, numDims, parentClass,700TR::Compiler->cls.getITable((TR_OpaqueClassBlock *)clazz), methodTracingInfo,701classHasFinalFields, classDepthAndFlags, classInitialized, byteOffsetToLockword, leafComponentClass,702classLoader, hostClass, componentClass, arrayClass, totalInstanceSize, clazz->romClass,703cp, classFlags, classChainOffsetIdentifyingLoader, origROMMethods, classNameIdentifyingLoader, arrayElementSize704);705}706707J9ROMClass *708JITServerHelpers::romClassFromString(const std::string &romClassStr, TR_PersistentMemory *persistentMemory)709{710if (auto cache = TR::CompilationInfo::get()->getJITServerSharedROMClassCache())711return cache->getOrCreate((const J9ROMClass *)romClassStr.data());712713auto romClass = (J9ROMClass *)persistentMemory->allocatePersistentMemory(romClassStr.size(), TR_Memory::ROMClass);714if (!romClass)715throw std::bad_alloc();716memcpy(romClass, romClassStr.data(), romClassStr.size());717return romClass;718}719720J9ROMClass *721JITServerHelpers::getRemoteROMClass(J9Class *clazz, JITServer::ServerStream *stream,722TR_PersistentMemory *persistentMemory, ClassInfoTuple &classInfoTuple)723{724stream->write(JITServer::MessageType::ResolvedMethod_getRemoteROMClassAndMethods, clazz);725auto recv = stream->read<ClassInfoTuple>();726classInfoTuple = std::get<0>(recv);727return romClassFromString(std::get<0>(classInfoTuple), persistentMemory);728}729730// Return true if able to get data from cache, return false otherwise.731bool732JITServerHelpers::getAndCacheRAMClassInfo(J9Class *clazz, ClientSessionData *clientSessionData,733JITServer::ServerStream *stream, ClassInfoDataType dataType, void *data)734{735if (!clazz)736return false;737738{739OMR::CriticalSection getRemoteROMClass(clientSessionData->getROMMapMonitor());740auto it = clientSessionData->getROMClassMap().find(clazz);741if (it != clientSessionData->getROMClassMap().end())742{743JITServerHelpers::getROMClassData(it->second, dataType, data);744return true;745}746}747748stream->write(JITServer::MessageType::ResolvedMethod_getRemoteROMClassAndMethods, clazz);749auto recv = stream->read<ClassInfoTuple>();750auto &classInfoTuple = std::get<0>(recv);751752OMR::CriticalSection cacheRemoteROMClass(clientSessionData->getROMMapMonitor());753auto it = clientSessionData->getROMClassMap().find(clazz);754if (it == clientSessionData->getROMClassMap().end())755{756auto romClass = romClassFromString(std::get<0>(classInfoTuple), clientSessionData->persistentMemory());757auto &classInfoStruct = JITServerHelpers::cacheRemoteROMClass(clientSessionData, clazz, romClass, classInfoTuple);758JITServerHelpers::getROMClassData(classInfoStruct, dataType, data);759}760else761{762JITServerHelpers::getROMClassData(it->second, dataType, data);763}764return false;765}766767// Return true if able to get data from cache, return false otherwise.768bool769JITServerHelpers::getAndCacheRAMClassInfo(J9Class *clazz, ClientSessionData *clientSessionData,770JITServer::ServerStream *stream, ClassInfoDataType dataType1, void *data1,771ClassInfoDataType dataType2, void *data2)772{773if (!clazz)774return false;775776{777OMR::CriticalSection getRemoteROMClass(clientSessionData->getROMMapMonitor());778auto it = clientSessionData->getROMClassMap().find(clazz);779if (it != clientSessionData->getROMClassMap().end())780{781JITServerHelpers::getROMClassData(it->second, dataType1, data1);782JITServerHelpers::getROMClassData(it->second, dataType2, data2);783return true;784}785}786787stream->write(JITServer::MessageType::ResolvedMethod_getRemoteROMClassAndMethods, clazz);788auto recv = stream->read<ClassInfoTuple>();789auto &classInfoTuple = std::get<0>(recv);790791OMR::CriticalSection cacheRemoteROMClass(clientSessionData->getROMMapMonitor());792auto it = clientSessionData->getROMClassMap().find(clazz);793if (it == clientSessionData->getROMClassMap().end())794{795auto romClass = romClassFromString(std::get<0>(classInfoTuple), clientSessionData->persistentMemory());796auto &classInfoStruct = JITServerHelpers::cacheRemoteROMClass(clientSessionData, clazz, romClass, classInfoTuple);797JITServerHelpers::getROMClassData(classInfoStruct, dataType1, data1);798JITServerHelpers::getROMClassData(classInfoStruct, dataType2, data2);799}800else801{802JITServerHelpers::getROMClassData(it->second, dataType1, data1);803JITServerHelpers::getROMClassData(it->second, dataType2, data2);804}805return false;806}807808void809JITServerHelpers::getROMClassData(const ClientSessionData::ClassInfo &classInfo, ClassInfoDataType dataType, void *data)810{811switch (dataType)812{813case CLASSINFO_ROMCLASS_MODIFIERS :814*(uint32_t *)data = classInfo._romClass->modifiers;815break;816case CLASSINFO_ROMCLASS_EXTRAMODIFIERS :817*(uint32_t *)data = classInfo._romClass->extraModifiers;818break;819case CLASSINFO_BASE_COMPONENT_CLASS :820*(TR_OpaqueClassBlock **)data = classInfo._baseComponentClass;821break;822case CLASSINFO_NUMBER_DIMENSIONS :823*(int32_t *)data = classInfo._numDimensions;824break;825case CLASSINFO_PARENT_CLASS :826*(TR_OpaqueClassBlock **)data = classInfo._parentClass;827break;828case CLASSINFO_CLASS_HAS_FINAL_FIELDS :829*(bool *)data = classInfo._classHasFinalFields;830break;831case CLASSINFO_CLASS_DEPTH_AND_FLAGS :832*(uintptr_t *)data = classInfo._classDepthAndFlags;833break;834case CLASSINFO_CLASS_INITIALIZED :835*(bool *)data = classInfo._classInitialized;836break;837case CLASSINFO_BYTE_OFFSET_TO_LOCKWORD :838*(uint32_t *)data = classInfo._byteOffsetToLockword;839break;840case CLASSINFO_LEAF_COMPONENT_CLASS :841*(TR_OpaqueClassBlock **)data = classInfo._leafComponentClass;842break;843case CLASSINFO_CLASS_LOADER :844*(void **)data = classInfo._classLoader;845break;846case CLASSINFO_HOST_CLASS :847*(TR_OpaqueClassBlock **)data = classInfo._hostClass;848break;849case CLASSINFO_COMPONENT_CLASS :850*(TR_OpaqueClassBlock **)data = classInfo._componentClass;851break;852case CLASSINFO_ARRAY_CLASS :853*(TR_OpaqueClassBlock **)data = classInfo._arrayClass;854break;855case CLASSINFO_TOTAL_INSTANCE_SIZE :856*(uintptr_t *)data = classInfo._totalInstanceSize;857break;858case CLASSINFO_REMOTE_ROM_CLASS :859*(J9ROMClass **)data = classInfo._remoteRomClass;860break;861case CLASSINFO_CLASS_FLAGS :862*(uintptr_t *)data = classInfo._classFlags;863break;864case CLASSINFO_METHODS_OF_CLASS :865*(J9Method **)data = classInfo._methodsOfClass;866break;867case CLASSINFO_CONSTANT_POOL :868*(J9ConstantPool **)data = classInfo._constantPool;869break;870case CLASSINFO_CLASS_CHAIN_OFFSET_IDENTIFYING_LOADER:871*(uintptr_t *)data = classInfo._classChainOffsetIdentifyingLoader;872break;873case CLASSINFO_ARRAY_ELEMENT_SIZE:874*(int32_t *)data = classInfo._arrayElementSize;875break;876default:877TR_ASSERT(false, "Class Info not supported %u\n", dataType);878break;879}880}881882J9ROMMethod *883JITServerHelpers::romMethodOfRamMethod(J9Method* method)884{885// JITServer886auto clientData = TR::compInfoPT->getClientData();887J9ROMMethod *romMethod = NULL;888889// Check if the method is already cached.890{891OMR::CriticalSection romCache(clientData->getROMMapMonitor());892auto &map = clientData->getJ9MethodMap();893auto it = map.find((J9Method*) method);894if (it != map.end())895romMethod = it->second._romMethod;896}897898// If not, cache the associated ROM class and get the ROM method from it.899if (!romMethod)900{901auto stream = TR::CompilationInfo::getStream();902stream->write(JITServer::MessageType::VM_getClassOfMethod, (TR_OpaqueMethodBlock*) method);903J9Class *clazz = (J9Class*) std::get<0>(stream->read<TR_OpaqueClassBlock *>());904TR::compInfoPT->getAndCacheRemoteROMClass(clazz);905{906OMR::CriticalSection romCache(clientData->getROMMapMonitor());907auto &map = clientData->getJ9MethodMap();908auto it = map.find((J9Method *) method);909if (it != map.end())910romMethod = it->second._romMethod;911}912}913TR_ASSERT(romMethod, "Should have acquired romMethod");914return romMethod;915}916917void918JITServerHelpers::postStreamFailure(OMRPortLibrary *portLibrary, TR::CompilationInfo *compInfo)919{920OMR::CriticalSection postStreamFailure(getClientStreamMonitor());921922OMRPORT_ACCESS_FROM_OMRPORT(portLibrary);923uint64_t current_time = omrtime_current_time_millis();924if (!_waitTimeMs)925_waitTimeMs = TR::Options::_reconnectWaitTimeMs;926if (current_time >= _nextConnectionRetryTime)927_waitTimeMs *= 2; // Exponential backoff928_nextConnectionRetryTime = current_time + _waitTimeMs;929930if (_serverAvailable && TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerboseJITServerConns))931{932TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,933"t=%6u Lost connection to the server (serverUID=%llu)",934(uint32_t)compInfo->getPersistentInfo()->getElapsedTime(),935(unsigned long long)compInfo->getPersistentInfo()->getServerUID());936compInfo->getPersistentInfo()->setServerUID(0);937}938939_serverAvailable = false;940941// Reset the activation policy flag in case we never reconnect to the server942// and client compiles locally or connects to a new server943compInfo->setCompThreadActivationPolicy(JITServer::CompThreadActivationPolicy::AGGRESSIVE);944if (TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerboseCompilationThreads) ||945TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerboseJITServer))946{947TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,948"t=%6u client has lost connection, resetting activation policy to AGGRESSIVE",949(uint32_t)compInfo->getPersistentInfo()->getElapsedTime());950}951}952953void954JITServerHelpers::postStreamConnectionSuccess()955{956_serverAvailable = true;957_waitTimeMs = TR::Options::_reconnectWaitTimeMs;958}959960bool961JITServerHelpers::shouldRetryConnection(OMRPortLibrary *portLibrary)962{963OMRPORT_ACCESS_FROM_OMRPORT(portLibrary);964return omrtime_current_time_millis() > _nextConnectionRetryTime;965}966967bool968JITServerHelpers::isAddressInROMClass(const void *address, const J9ROMClass *romClass)969{970return ((address >= romClass) && (address < (((uint8_t*) romClass) + romClass->romSize)));971}972973974uintptr_t975JITServerHelpers::walkReferenceChainWithOffsets(TR_J9VM *fe, const std::vector<uintptr_t> &listOfOffsets, uintptr_t receiver)976{977uintptr_t result = receiver;978for (size_t i = 0; i < listOfOffsets.size(); i++)979{980result = fe->getReferenceFieldAt(result, listOfOffsets[i]);981}982return result;983}984985uintptr_t986JITServerHelpers::getRemoteClassDepthAndFlagsWhenROMClassNotCached(J9Class *clazz, ClientSessionData *clientSessionData,987JITServer::ServerStream *stream)988{989stream->write(JITServer::MessageType::ResolvedMethod_getRemoteROMClassAndMethods, clazz);990auto recv = stream->read<JITServerHelpers::ClassInfoTuple>();991auto &classInfoTuple = std::get<0>(recv);992993OMR::CriticalSection cacheRemoteROMClass(clientSessionData->getROMMapMonitor());994auto it = clientSessionData->getROMClassMap().find(clazz);995if (it == clientSessionData->getROMClassMap().end())996{997auto romClass = JITServerHelpers::romClassFromString(std::get<0>(classInfoTuple), clientSessionData->persistentMemory());998auto &classInfoStruct = JITServerHelpers::cacheRemoteROMClass(clientSessionData, clazz, romClass, classInfoTuple);999return classInfoStruct._classDepthAndFlags;1000}1001else1002{1003return it->second._classDepthAndFlags;1004}1005}10061007static void1008addRAMClassToChain(std::vector<J9Class *> &chain, J9Class *clazz, std::vector<J9Class *> &uncached,1009PersistentUnorderedSet<J9Class *> &cached)1010{1011chain.push_back(clazz);1012if (cached.insert(clazz).second)1013uncached.push_back(clazz);1014}10151016std::vector<J9Class *>1017JITServerHelpers::getRAMClassChain(J9Class *clazz, size_t numClasses, J9VMThread *vmThread, TR_Memory *trMemory,1018TR::CompilationInfo *compInfo, std::vector<J9Class *> &uncachedRAMClasses,1019std::vector<ClassInfoTuple> &uncachedClassInfos)1020{1021TR_ASSERT(uncachedRAMClasses.empty(), "Must pass empty vector");1022TR_ASSERT(uncachedClassInfos.empty(), "Must pass empty vector");1023TR_ASSERT(numClasses <= TR_J9SharedCache::maxClassChainLength, "Class chain is too long");10241025std::vector<J9Class *> chain;1026chain.reserve(numClasses);1027uncachedRAMClasses.reserve(numClasses);1028auto &cached = compInfo->getclassesCachedAtServer();10291030{1031OMR::CriticalSection cs(compInfo->getclassesCachedAtServerMonitor());10321033addRAMClassToChain(chain, clazz, uncachedRAMClasses, cached);1034for (size_t i = 0; i < J9CLASS_DEPTH(clazz); ++i)1035addRAMClassToChain(chain, clazz->superclasses[i], uncachedRAMClasses, cached);1036for (auto it = (J9ITable *)clazz->iTable; it; it = it->next)1037addRAMClassToChain(chain, it->interfaceClass, uncachedRAMClasses, cached);1038TR_ASSERT(chain.size() == numClasses, "Invalid RAM class chain length: %zu != %zu", chain.size(), numClasses);1039}10401041uncachedClassInfos.reserve(uncachedRAMClasses.size());1042for (J9Class *c : uncachedRAMClasses)1043uncachedClassInfos.push_back(packRemoteROMClassInfo(c, vmThread, trMemory, true));10441045return chain;1046}10471048void1049JITServerHelpers::cacheRemoteROMClassBatch(ClientSessionData *clientData, const std::vector<J9Class *> &ramClasses,1050const std::vector<ClassInfoTuple> &classInfoTuples)1051{1052TR_ASSERT_FATAL(ramClasses.size() == classInfoTuples.size(), "Must have equal length");10531054for (size_t i = 0; i < ramClasses.size(); ++i)1055{1056auto romClass = romClassFromString(std::get<0>(classInfoTuples[i]), clientData->persistentMemory());1057cacheRemoteROMClassOrFreeIt(clientData, ramClasses[i], romClass, classInfoTuples[i]);1058}1059}106010611062