Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/control/JITServerHelpers.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2019, 2022 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* 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-exception
21
*******************************************************************************/
22
23
#include "control/JITServerHelpers.hpp"
24
25
#include "control/CompilationRuntime.hpp"
26
#include "control/JITServerCompilationThread.hpp"
27
#include "control/MethodToBeCompiled.hpp"
28
#include "env/StackMemoryRegion.hpp"
29
#include "infra/CriticalSection.hpp"
30
#include "infra/Statistics.hpp"
31
#include "net/CommunicationStream.hpp"
32
#include "OMR/Bytes.hpp"// for OMR::alignNoCheck()
33
#include "runtime/JITServerAOTDeserializer.hpp"
34
#include "runtime/JITServerSharedROMClassCache.hpp"
35
#include "romclasswalk.h"
36
#include "util_api.h"// for allSlotsInROMClassDo()
37
38
39
uint32_t JITServerHelpers::serverMsgTypeCount[] = {};
40
uint64_t JITServerHelpers::_waitTimeMs = 0;
41
bool JITServerHelpers::_serverAvailable = true;
42
uint64_t JITServerHelpers::_nextConnectionRetryTime = 0;
43
TR::Monitor *JITServerHelpers::_clientStreamMonitor = NULL;
44
45
46
// To ensure that the length fields in UTF8 strings appended at the end of the
47
// packed ROMClass are properly aligned, we must pad the strings accordingly.
48
// This function returns the total size of a UTF8 string with the padding.
49
static size_t
50
getUTF8Size(const J9UTF8 *str)
51
{
52
return OMR::alignNoCheck(J9UTF8_TOTAL_SIZE(str), sizeof(*str));
53
}
54
55
// Copies a UTF8 string and returns its total size including the padding.
56
// src doesn't have to be padded, dst is padded.
57
static size_t
58
copyUTF8(J9UTF8 *dst, const J9UTF8 *src)
59
{
60
size_t size = J9UTF8_TOTAL_SIZE(src);
61
memcpy(dst, src, size);
62
static_assert(sizeof(*src) == 2, "UTF8 header is not 2 bytes large");
63
// If the length is not aligned, pad the destination string with a zero
64
if (!OMR::alignedNoCheck(size, sizeof(*src)))
65
dst->data[src->length] = '\0';
66
return getUTF8Size(src);
67
}
68
69
// State maintained while iterating over UTF8 strings in a ROMClass
70
struct ROMClassPackContext
71
{
72
ROMClassPackContext(TR_Memory *trMemory, size_t origSize) :
73
_origSize(origSize), _callback(NULL), _stringsSize(0),
74
_utf8SectionStart((const uint8_t *)-1), _utf8SectionEnd(NULL), _utf8SectionSize(0),
75
_strToOffsetMap(decltype(_strToOffsetMap)::allocator_type(trMemory->currentStackRegion())),
76
_packedRomClass(NULL), _cursor(NULL) {}
77
78
bool isInline(const void *address, const J9ROMClass *romClass)
79
{
80
return (address >= romClass) && (address < (uint8_t *)romClass + _origSize);
81
}
82
83
typedef void (*Callback)(const J9ROMClass *, const J9SRP *, const char *, ROMClassPackContext &);
84
85
const size_t _origSize;
86
Callback _callback;
87
size_t _stringsSize;
88
const uint8_t *_utf8SectionStart;
89
const uint8_t *_utf8SectionEnd;// only needed for assertions
90
size_t _utf8SectionSize;// only needed for assertions
91
// Maps original strings to their offsets from UTF8 section start in the packed ROMClass
92
// Offset value -1 signifies that the string is skipped
93
UnorderedMap<const J9UTF8 *, size_t> _strToOffsetMap;
94
J9ROMClass *_packedRomClass;
95
uint8_t *_cursor;
96
};
97
98
static bool
99
shouldSkipSlot(const char *slotName)
100
{
101
// Skip variable names and signatures in method debug info; only their slot names have prefix "variable"
102
static const char prefix[] = "variable";
103
return strncmp(slotName, prefix, sizeof(prefix) - 1) == 0;
104
}
105
106
// Updates size info and maps original string to its future location in the packed ROMClass
107
static void
108
sizeInfoCallback(const J9ROMClass *romClass, const J9SRP *origSrp, const char *slotName, ROMClassPackContext &ctx)
109
{
110
// Skip SRPs stored outside of the ROMClass bounds such as the ones in out-of-line
111
// method debug info, and the ones that point to strings not used by the JIT.
112
bool skip = !ctx.isInline(origSrp, romClass) || shouldSkipSlot(slotName);
113
auto str = NNSRP_PTR_GET(origSrp, const J9UTF8 *);
114
auto result = ctx._strToOffsetMap.insert({ str, skip ? (size_t)-1 : ctx._stringsSize });
115
if (!result.second)// duplicate - already visited
116
{
117
auto &it = result.first;
118
if (!skip && (it->second == (size_t)-1))
119
{
120
// Previously visited SRPs to this string were skipped, but this one isn't
121
it->second = ctx._stringsSize;
122
ctx._stringsSize += getUTF8Size(str);
123
}
124
return;
125
}
126
127
size_t size = getUTF8Size(str);
128
ctx._stringsSize += skip ? 0 : size;
129
130
if (ctx.isInline(str, romClass))
131
{
132
ctx._utf8SectionStart = std::min(ctx._utf8SectionStart, (const uint8_t *)str);
133
ctx._utf8SectionEnd = std::max(ctx._utf8SectionEnd, (const uint8_t *)str + size);
134
ctx._utf8SectionSize += size;
135
}
136
}
137
138
// Copies original string into its location in the packed ROMClass and updates the SRP to it
139
static void
140
packCallback(const J9ROMClass *romClass, const J9SRP *origSrp, const char *slotName, ROMClassPackContext &ctx)
141
{
142
// Skip SRPs stored outside of the ROMClass bounds such as the ones in out-of-line method debug info
143
if (!ctx.isInline(origSrp, romClass))
144
return;
145
146
auto str = NNSRP_PTR_GET(origSrp, const J9UTF8 *);
147
auto srp = (J9SRP *)((uint8_t *)ctx._packedRomClass + ((uint8_t *)origSrp - (uint8_t *)romClass));
148
149
// Zero out skipped string SRPs
150
if (shouldSkipSlot(slotName))
151
{
152
TR_ASSERT(ctx._strToOffsetMap.find(str) != ctx._strToOffsetMap.end(),
153
"UTF8 slot %s not visited in 1st pass", slotName);
154
*srp = 0;
155
return;
156
}
157
158
auto it = ctx._strToOffsetMap.find(str);
159
TR_ASSERT(it != ctx._strToOffsetMap.end(), "UTF8 slot %s not visited in 1st pass", slotName);
160
auto dst = (uint8_t *)ctx._packedRomClass + (ctx._utf8SectionStart - (uint8_t *)romClass) + it->second;
161
162
NNSRP_PTR_SET(srp, dst);
163
if (dst == ctx._cursor)
164
ctx._cursor += copyUTF8((J9UTF8 *)dst, str);
165
else
166
TR_ASSERT((dst < ctx._cursor) && (memcmp(dst, str, J9UTF8_TOTAL_SIZE(str)) == 0), "Must be already copied");
167
}
168
169
static void
170
utf8SlotCallback(const J9ROMClass *romClass, const J9SRP *srp, const char *slotName, void *userData)
171
{
172
auto &ctx = *(ROMClassPackContext *)userData;
173
if (*srp)
174
ctx._callback(romClass, srp, slotName, ctx);
175
}
176
177
// Invoked for each slot in a ROMClass. Calls ctx._callback for all non-null SRPs to UTF8 strings.
178
static void
179
slotCallback(J9ROMClass *romClass, uint32_t slotType, void *slotPtr, const char *slotName, void *userData)
180
{
181
switch (slotType)
182
{
183
case J9ROM_UTF8:
184
utf8SlotCallback(romClass, (const J9SRP *)slotPtr, slotName, userData);
185
break;
186
187
case J9ROM_NAS:
188
if (auto nas = SRP_PTR_GET(slotPtr, const J9ROMNameAndSignature *))
189
{
190
utf8SlotCallback(romClass, &nas->name, slotName, userData);
191
utf8SlotCallback(romClass, &nas->signature, slotName, userData);
192
}
193
break;
194
}
195
}
196
197
static bool
198
isArrayROMClass(const J9ROMClass *romClass)
199
{
200
if (!J9ROMCLASS_IS_ARRAY(romClass))
201
return false;
202
203
auto name = J9ROMCLASS_CLASSNAME(romClass);
204
TR_ASSERT((name->length == 2) && (name->data[0] == '['),
205
"Unexpected array ROMClass name: %.*s", name->length, name->data);
206
return true;
207
}
208
209
// Array ROMClasses have a different layout (see runtime/vm/romclasses.c):
210
// they all share the same SRP array of interfaces, which breaks the generic
211
// packing implementation. Instead, we manually pack all the data stored
212
// outside of the ROMClass header: class name, superclass name, interfaces.
213
// This function returns the total size of the packed array ROMClass.
214
static size_t
215
getArrayROMClassPackedSize(const J9ROMClass *romClass)
216
{
217
size_t totalSize = sizeof(*romClass);
218
totalSize += getUTF8Size(J9ROMCLASS_CLASSNAME(romClass));
219
totalSize += getUTF8Size(J9ROMCLASS_SUPERCLASSNAME(romClass));
220
221
totalSize += romClass->interfaceCount * sizeof(J9SRP);
222
for (size_t i = 0; i < romClass->interfaceCount; ++i)
223
{
224
auto name = NNSRP_GET(J9ROMCLASS_INTERFACES(romClass)[i], const J9UTF8 *);
225
totalSize += getUTF8Size(name);
226
}
227
228
return OMR::alignNoCheck(totalSize, sizeof(uint64_t));
229
}
230
231
static void
232
packUTF8(const J9UTF8 *str, J9SRP &srp, ROMClassPackContext &ctx)
233
{
234
NNSRP_SET(srp, ctx._cursor);
235
ctx._cursor += copyUTF8((J9UTF8 *)ctx._cursor, str);
236
}
237
238
// Packs the data stored outside of the array ROMClass header
239
static void
240
packArrayROMClassData(const J9ROMClass *romClass, ROMClassPackContext &ctx)
241
{
242
NNSRP_SET(ctx._packedRomClass->interfaces, ctx._cursor);
243
ctx._cursor += ctx._packedRomClass->interfaceCount * sizeof(J9SRP);
244
245
packUTF8(J9ROMCLASS_CLASSNAME(romClass), ctx._packedRomClass->className, ctx);
246
packUTF8(J9ROMCLASS_SUPERCLASSNAME(romClass), ctx._packedRomClass->superclassName, ctx);
247
248
for (size_t i = 0; i < romClass->interfaceCount; ++i)
249
{
250
auto name = NNSRP_GET(J9ROMCLASS_INTERFACES(romClass)[i], const J9UTF8 *);
251
packUTF8(name, J9ROMCLASS_INTERFACES(ctx._packedRomClass)[i], ctx);
252
}
253
}
254
255
// Packs a ROMClass to be transferred to the server.
256
//
257
// The result is allocated from the stack region of trMemory (as well as temporary data
258
// structures used for packing). This function should be used with TR::StackMemoryRegion.
259
// If passed non-zero expectedSize, and it doesn't match the resulting packedSize
260
// (which is returned to the caller by reference), this function returns NULL.
261
//
262
// UTF8 strings that a ROMClass refers to can be interned and stored outside of
263
// the ROMClass body. This function puts all the strings (including interned ones)
264
// at the end of the cloned ROMClass in deterministic order and updates the SRPs
265
// to them. It also removes some of the data that is not used by the JIT compiler.
266
//
267
// Note that the strings that were stored inside of the original ROMClass body
268
// do not keep their offsets in the serialized ROMClass (in the general case).
269
// The order in which the strings are serialized is determined by the ROMClass
270
// walk, not by their original locations.
271
//
272
// Packing involves 2 passes over all the strings that a ROMClass refers to:
273
// 1. Compute total size and map original strings to their locations in the packed ROMClass.
274
// 2. Copy each original string to its location in the packed ROMClass.
275
//
276
// This implementation makes (and checks at runtime) the following assumptions:
277
// - Intermediate class data is either stored at the end of the ROMClass, or points
278
// to the ROMClass itself, or is interned (i.e. points outside of the ROMClass).
279
// - All non-interned strings are stored in a single contiguous range (the UTF8 section)
280
// located at the end of the ROMClass (can only be followed by intermediate class data).
281
// - ROMClass walk visits all the strings that the ROMClass references.
282
//
283
J9ROMClass *
284
JITServerHelpers::packROMClass(J9ROMClass *romClass, TR_Memory *trMemory, size_t &packedSize, size_t expectedSize)
285
{
286
auto name = J9ROMCLASS_CLASSNAME(romClass);
287
// Primitive ROMClasses have different layout (see runtime/vm/romclasses.c): the last
288
// ROMClass includes all the others' UTF8 name strings in its romSize, which breaks the
289
// generic packing implementation. Pretend that its romSize only includes the header.
290
size_t origRomSize = J9ROMCLASS_IS_PRIMITIVE_TYPE(romClass) ? sizeof(*romClass) : romClass->romSize;
291
packedSize = origRomSize;
292
293
// Remove intermediate class data (not used by JIT)
294
uint8_t *icData = J9ROMCLASS_INTERMEDIATECLASSDATA(romClass);
295
if (JITServerHelpers::isAddressInROMClass(icData, romClass) && (icData != (uint8_t *)romClass))
296
{
297
TR_ASSERT_FATAL(icData + romClass->intermediateClassDataLength == (uint8_t *)romClass + romClass->romSize,
298
"Intermediate class data not stored at the end of ROMClass %.*s", name->length, name->data);
299
packedSize -= romClass->intermediateClassDataLength;
300
}
301
302
ROMClassPackContext ctx(trMemory, origRomSize);
303
304
size_t copySize = 0;
305
if (isArrayROMClass(romClass))
306
{
307
copySize = sizeof(*romClass);
308
packedSize = getArrayROMClassPackedSize(romClass);
309
}
310
else
311
{
312
// 1st pass: iterate all strings in the ROMClass to compute its total size (including
313
// interned strings) and map the strings to their locations in the packed ROMClass
314
ctx._callback = sizeInfoCallback;
315
allSlotsInROMClassDo(romClass, slotCallback, NULL, NULL, &ctx);
316
// Handle the case when all strings are interned
317
auto classEnd = (const uint8_t *)romClass + packedSize;
318
ctx._utf8SectionStart = std::min(ctx._utf8SectionStart, classEnd);
319
320
auto end = ctx._utf8SectionEnd ? ctx._utf8SectionEnd : classEnd;
321
TR_ASSERT_FATAL(ctx._utf8SectionSize == end - ctx._utf8SectionStart,
322
"Missed strings in ROMClass %.*s UTF8 section: %zu != %zu",
323
name->length, name->data, ctx._utf8SectionSize, end - ctx._utf8SectionStart);
324
end = (const uint8_t *)OMR::alignNoCheck((uintptr_t)end, sizeof(uint64_t));
325
TR_ASSERT_FATAL(end == classEnd, "UTF8 section not stored at the end of ROMClass %.*s: %p != %p",
326
name->length, name->data, end, classEnd);
327
328
copySize = ctx._utf8SectionStart - (const uint8_t *)romClass;
329
packedSize = OMR::alignNoCheck(copySize + ctx._stringsSize, sizeof(uint64_t));
330
}
331
332
// Check if expected size matches, otherwise fail early. Size mismatch can occur when JIT client
333
// packs a ROMClass before computing its hash when deserializing a JITServer-cached AOT method that
334
// was compiled for a different version of the class. In such cases, we can skip the rest of the
335
// packing procedure and hash computation since we already know that the ROMClass doesn't match.
336
if (expectedSize && (expectedSize != packedSize))
337
return NULL;
338
339
ctx._packedRomClass = (J9ROMClass *)trMemory->allocateStackMemory(packedSize);
340
if (!ctx._packedRomClass)
341
throw std::bad_alloc();
342
memcpy(ctx._packedRomClass, romClass, copySize);
343
ctx._packedRomClass->romSize = packedSize;
344
ctx._cursor = (uint8_t *)ctx._packedRomClass + copySize;
345
346
// Zero out SRP to intermediate class data
347
ctx._packedRomClass->intermediateClassData = 0;
348
ctx._packedRomClass->intermediateClassDataLength = 0;
349
350
// Zero out SRPs to out-of-line method debug info
351
J9ROMMethod *romMethod = J9ROMCLASS_ROMMETHODS(ctx._packedRomClass);
352
for (size_t i = 0; i < ctx._packedRomClass->romMethodCount; ++i)
353
{
354
if (J9ROMMETHOD_HAS_DEBUG_INFO(romMethod))
355
{
356
auto debugInfo = methodDebugInfoFromROMMethod(romMethod);
357
if (!(debugInfo->srpToVarInfo & 1))
358
debugInfo->srpToVarInfo = 0;
359
}
360
romMethod = nextROMMethod(romMethod);
361
}
362
363
if (isArrayROMClass(romClass))
364
{
365
packArrayROMClassData(romClass, ctx);
366
}
367
else
368
{
369
// 2nd pass: copy all strings to their locations in the packed ROMClass
370
ctx._callback = packCallback;
371
allSlotsInROMClassDo(romClass, slotCallback, NULL, NULL, &ctx);
372
}
373
374
// Pad to required alignment
375
auto end = (uint8_t *)OMR::alignNoCheck((uintptr_t)ctx._cursor, sizeof(uint64_t));
376
TR_ASSERT_FATAL(end == (uint8_t *)ctx._packedRomClass + packedSize, "Invalid final cursor position: %p != %p",
377
end, (uint8_t *)ctx._packedRomClass + packedSize);
378
memset(ctx._cursor, 0, end - ctx._cursor);
379
380
return ctx._packedRomClass;
381
}
382
383
// insertIntoOOSequenceEntryList needs to be executed with sequencingMonitor in hand.
384
// This method belongs to ClientSessionData, but is temporarily moved here to be able
385
// to push the ClientSessionData related code as a standalone piece.
386
void
387
JITServerHelpers::insertIntoOOSequenceEntryList(ClientSessionData *clientData, TR_MethodToBeCompiled *entry)
388
{
389
uint32_t seqNo = ((TR::CompilationInfoPerThreadRemote*)(entry->_compInfoPT))->getSeqNo();
390
TR_MethodToBeCompiled *crtEntry = clientData->getOOSequenceEntryList();
391
TR_MethodToBeCompiled *prevEntry = NULL;
392
while (crtEntry && (seqNo > ((TR::CompilationInfoPerThreadRemote*)(crtEntry->_compInfoPT))->getSeqNo()))
393
{
394
prevEntry = crtEntry;
395
crtEntry = crtEntry->_next;
396
}
397
entry->_next = crtEntry;
398
if (prevEntry)
399
prevEntry->_next = entry;
400
else
401
clientData->setOOSequenceEntryList(entry);
402
}
403
404
void
405
JITServerHelpers::printJITServerMsgStats(J9JITConfig *jitConfig, TR::CompilationInfo *compInfo)
406
{
407
uint32_t totalMsgCount = 0;
408
#ifdef MESSAGE_SIZE_STATS
409
uint64_t totalMsgSize = 0;
410
#endif // defined(MESSAGE_SIZE_STATS)
411
PORT_ACCESS_FROM_JITCONFIG(jitConfig);
412
413
j9tty_printf(PORTLIB, "JITServer Message Type Statistics:\n");
414
j9tty_printf(PORTLIB, "Type# #called");
415
#ifdef MESSAGE_SIZE_STATS
416
j9tty_printf(PORTLIB, "\t\tMax\t\tMin\t\tMean\t\tStdDev\t\tSum");
417
#endif // defined(MESSAGE_SIZE_STATS)
418
j9tty_printf(PORTLIB, "\t\tTypeName\n");
419
420
if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::CLIENT)
421
{
422
for (int i = 0; i < JITServer::MessageType_MAXTYPE; ++i)
423
{
424
if (serverMsgTypeCount[i])
425
{
426
j9tty_printf(PORTLIB, "#%04d %7u", i, serverMsgTypeCount[i]);
427
#ifdef MESSAGE_SIZE_STATS
428
auto &stat = JITServer::CommunicationStream::msgSizeStats[i];
429
j9tty_printf(PORTLIB, "\t%f\t%f\t%f\t%f\t%f",
430
stat.maxVal(), stat.minVal(), stat.mean(), stat.stddev(), stat.sum());
431
totalMsgSize += stat.sum();
432
#endif // defined(MESSAGE_SIZE_STATS)
433
j9tty_printf(PORTLIB, "\t\t%s\n", JITServer::messageNames[i]);
434
totalMsgCount += serverMsgTypeCount[i];
435
}
436
}
437
j9tty_printf(PORTLIB, "Total number of messages: %u\n", totalMsgCount);
438
#ifdef MESSAGE_SIZE_STATS
439
j9tty_printf(PORTLIB, "Total amount of data received: %llu bytes\n", (unsigned long long)totalMsgSize);
440
#endif // defined(MESSAGE_SIZE_STATS)
441
442
uint32_t numCompilations = serverMsgTypeCount[JITServer::MessageType::compilationCode];
443
if (numCompilations)
444
j9tty_printf(PORTLIB, "Average number of messages per compilation: %f\n",
445
totalMsgCount / float(numCompilations));
446
447
if (auto deserializer = compInfo->getJITServerAOTDeserializer())
448
{
449
uint32_t numDeserializedMethods = deserializer->getNumDeserializedMethods();
450
if (numDeserializedMethods)
451
j9tty_printf(PORTLIB, "Average number of messages per compilation request (including AOT cache hits): %f\n",
452
totalMsgCount / float(numCompilations + numDeserializedMethods));
453
}
454
}
455
else if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER)
456
{
457
// to print in server, run ./jitserver -Xdump:jit:events=user
458
// then kill -3 <pidof jitserver>
459
#ifdef MESSAGE_SIZE_STATS
460
for (int i = 0; i < JITServer::MessageType_MAXTYPE; ++i)
461
{
462
auto &stat = JITServer::CommunicationStream::msgSizeStats[i];
463
if (stat.samples())
464
{
465
j9tty_printf(PORTLIB, "#%04d %7u", i, stat.samples());
466
j9tty_printf(PORTLIB, "\t%f\t%f\t%f\t%f\t%f",
467
stat.maxVal(), stat.minVal(), stat.mean(), stat.stddev(), stat.sum());
468
j9tty_printf(PORTLIB, "\t\t%s\n", JITServer::messageNames[i]);
469
totalMsgCount += stat.samples();
470
totalMsgSize += stat.sum();
471
}
472
}
473
j9tty_printf(PORTLIB, "Total number of messages: %u\n", totalMsgCount);
474
j9tty_printf(PORTLIB, "Total amount of data received: %llu bytes\n", (unsigned long long)totalMsgSize);
475
476
uint32_t numCompilations = JITServer::CommunicationStream::msgSizeStats[JITServer::MessageType::compilationCode].samples();
477
if (numCompilations)
478
j9tty_printf(PORTLIB, "Average number of messages per compilation: %f\n",
479
totalMsgCount, totalMsgCount / float(numCompilations));
480
481
if (auto aotCacheMap = compInfo->getJITServerAOTCacheMap())
482
{
483
uint32_t numDeserializedMethods = aotCacheMap->getNumDeserializedMethods();
484
if (numDeserializedMethods)
485
j9tty_printf(PORTLIB, "Average number of messages per compilation request (including AOT cache hits): %f\n",
486
totalMsgCount / float(numCompilations + numDeserializedMethods));
487
}
488
#endif // defined(MESSAGE_SIZE_STATS)
489
}
490
}
491
492
void
493
JITServerHelpers::printJITServerCHTableStats(J9JITConfig *jitConfig, TR::CompilationInfo *compInfo)
494
{
495
#ifdef COLLECT_CHTABLE_STATS
496
PORT_ACCESS_FROM_JITCONFIG(jitConfig);
497
j9tty_printf(PORTLIB, "JITServer CHTable Statistics:\n");
498
if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::CLIENT)
499
{
500
JITClientPersistentCHTable *table = (JITClientPersistentCHTable*)compInfo->getPersistentInfo()->getPersistentCHTable();
501
j9tty_printf(PORTLIB, "Num updates sent: %d (1 per compilation)\n", table->_numUpdates);
502
if (table->_numUpdates)
503
{
504
j9tty_printf(PORTLIB, "Num commit failures: %d. Average per compilation: %f\n", table->_numCommitFailures, table->_numCommitFailures / float(table->_numUpdates));
505
j9tty_printf(PORTLIB, "Num classes updated: %d. Average per compilation: %f\n", table->_numClassesUpdated, table->_numClassesUpdated / float(table->_numUpdates));
506
j9tty_printf(PORTLIB, "Num classes removed: %d. Average per compilation: %f\n", table->_numClassesRemoved, table->_numClassesRemoved / float(table->_numUpdates));
507
j9tty_printf(PORTLIB, "Total update bytes: %d. Compilation max: %d. Average per compilation: %f\n", table->_updateBytes, table->_maxUpdateBytes, table->_updateBytes / float(table->_numUpdates));
508
}
509
}
510
else if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER)
511
{
512
JITServerPersistentCHTable *table = (JITServerPersistentCHTable*)compInfo->getPersistentInfo()->getPersistentCHTable();
513
j9tty_printf(PORTLIB, "Num updates received: %d (1 per compilation)\n", table->_numUpdates);
514
if (table->_numUpdates)
515
{
516
j9tty_printf(PORTLIB, "Num classes updated: %d. Average per compilation: %f\n", table->_numClassesUpdated, table->_numClassesUpdated / float(table->_numUpdates));
517
j9tty_printf(PORTLIB, "Num classes removed: %d. Average per compilation: %f\n", table->_numClassesRemoved, table->_numClassesRemoved / float(table->_numUpdates));
518
j9tty_printf(PORTLIB, "Num class info queries: %d. Average per compilation: %f\n", table->_numQueries, table->_numQueries / float(table->_numUpdates));
519
j9tty_printf(PORTLIB, "Total update bytes: %d. Compilation max: %d. Average per compilation: %f\n", table->_updateBytes, table->_maxUpdateBytes, table->_updateBytes / float(table->_numUpdates));
520
}
521
}
522
#endif
523
}
524
525
void
526
JITServerHelpers::printJITServerCacheStats(J9JITConfig *jitConfig, TR::CompilationInfo *compInfo)
527
{
528
PORT_ACCESS_FROM_JITCONFIG(jitConfig);
529
if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER)
530
{
531
auto clientSessionHT = compInfo->getClientSessionHT();
532
clientSessionHT->printStats();
533
}
534
}
535
536
/*
537
* Free the persistent memory allocated for the given `romClass`.
538
* If the server uses a global cache of ROMClasses shared among the different JVM clients,
539
* this routine decrements the reference count for the `romClass` given as parameter,
540
* and only if the ref count reaches 0, the persistent memory is freed.
541
*/
542
void
543
JITServerHelpers::freeRemoteROMClass(J9ROMClass *romClass, TR_PersistentMemory *persistentMemory)
544
{
545
if (auto cache = TR::CompilationInfo::get()->getJITServerSharedROMClassCache())
546
cache->release(romClass);
547
else
548
persistentMemory->freePersistentMemory(romClass);
549
}
550
551
/*
552
* `cacheRemoteROMClassOrFreeIt` takes a romClass data structure allocated with
553
* persistent memory and attempts to cache it in the per-client data session.
554
* If caching suceeds, the method returns a pointer to the romClass received as parameter.
555
* If the caching fails, the memory for romClass received as parameter is freed
556
* and the method returns a pointer to the romClass from the cache
557
*/
558
J9ROMClass *
559
JITServerHelpers::cacheRemoteROMClassOrFreeIt(ClientSessionData *clientSessionData, J9Class *clazz,
560
J9ROMClass *romClass, const ClassInfoTuple &classInfoTuple)
561
{
562
OMR::CriticalSection cacheRemoteROMClass(clientSessionData->getROMMapMonitor());
563
auto it = clientSessionData->getROMClassMap().find(clazz);
564
if (it == clientSessionData->getROMClassMap().end())
565
{
566
JITServerHelpers::cacheRemoteROMClass(clientSessionData, clazz, romClass, classInfoTuple);
567
return romClass;
568
}
569
// romClass is already present in the cache; must free the duplicate
570
JITServerHelpers::freeRemoteROMClass(romClass, clientSessionData->persistentMemory());
571
// Return the cached romClass
572
return it->second._romClass;
573
}
574
575
ClientSessionData::ClassInfo &
576
JITServerHelpers::cacheRemoteROMClass(ClientSessionData *clientSessionData, J9Class *clazz,
577
J9ROMClass *romClass, const ClassInfoTuple &classInfoTuple)
578
{
579
ClientSessionData::ClassInfo classInfoStruct(clientSessionData->persistentMemory());
580
581
classInfoStruct._romClass = romClass;
582
J9Method *methods = std::get<1>(classInfoTuple);
583
classInfoStruct._methodsOfClass = methods;
584
classInfoStruct._baseComponentClass = std::get<2>(classInfoTuple);
585
classInfoStruct._numDimensions = std::get<3>(classInfoTuple);
586
classInfoStruct._parentClass = std::get<4>(classInfoTuple);
587
auto &tmpInterfaces = std::get<5>(classInfoTuple);
588
auto &persistentAllocator = clientSessionData->persistentMemory()->_persistentAllocator.get();
589
classInfoStruct._interfaces = new (persistentAllocator) PersistentVector<TR_OpaqueClassBlock *>(
590
tmpInterfaces.begin(), tmpInterfaces.end(),
591
PersistentVector<TR_OpaqueClassBlock *>::allocator_type(persistentAllocator)
592
);
593
auto &methodTracingInfo = std::get<6>(classInfoTuple);
594
classInfoStruct._classHasFinalFields = std::get<7>(classInfoTuple);
595
classInfoStruct._classDepthAndFlags = std::get<8>(classInfoTuple);
596
classInfoStruct._classInitialized = std::get<9>(classInfoTuple);
597
classInfoStruct._byteOffsetToLockword = std::get<10>(classInfoTuple);
598
classInfoStruct._leafComponentClass = std::get<11>(classInfoTuple);
599
classInfoStruct._classLoader = std::get<12>(classInfoTuple);
600
classInfoStruct._hostClass = std::get<13>(classInfoTuple);
601
classInfoStruct._componentClass = std::get<14>(classInfoTuple);
602
classInfoStruct._arrayClass = std::get<15>(classInfoTuple);
603
classInfoStruct._totalInstanceSize = std::get<16>(classInfoTuple);
604
classInfoStruct._remoteRomClass = std::get<17>(classInfoTuple);
605
classInfoStruct._constantPool = (J9ConstantPool *)std::get<18>(classInfoTuple);
606
classInfoStruct._classFlags = std::get<19>(classInfoTuple);
607
classInfoStruct._classChainOffsetIdentifyingLoader = std::get<20>(classInfoTuple);
608
auto &origROMMethods = std::get<21>(classInfoTuple);
609
classInfoStruct._classNameIdentifyingLoader = std::get<22>(classInfoTuple);
610
classInfoStruct._arrayElementSize = std::get<23>(classInfoTuple);
611
612
auto result = clientSessionData->getROMClassMap().insert({ clazz, classInfoStruct });
613
614
auto &methodMap = clientSessionData->getJ9MethodMap();
615
uint32_t numMethods = romClass->romMethodCount;
616
J9ROMMethod *romMethod = J9ROMCLASS_ROMMETHODS(romClass);
617
for (uint32_t i = 0; i < numMethods; i++)
618
{
619
ClientSessionData::J9MethodInfo m(romMethod, origROMMethods[i], (TR_OpaqueClassBlock *)clazz,
620
i, static_cast<bool>(methodTracingInfo[i]));
621
methodMap.insert({ &methods[i], m });
622
romMethod = nextROMMethod(romMethod);
623
}
624
625
// Return a reference to the ClassInfo structure stored in the map in the client session
626
return result.first->second;
627
}
628
629
J9ROMClass *
630
JITServerHelpers::getRemoteROMClassIfCached(ClientSessionData *clientSessionData, J9Class *clazz)
631
{
632
OMR::CriticalSection getRemoteROMClassIfCached(clientSessionData->getROMMapMonitor());
633
auto it = clientSessionData->getROMClassMap().find(clazz);
634
return (it == clientSessionData->getROMClassMap().end()) ? NULL : it->second._romClass;
635
}
636
637
JITServerHelpers::ClassInfoTuple
638
JITServerHelpers::packRemoteROMClassInfo(J9Class *clazz, J9VMThread *vmThread, TR_Memory *trMemory, bool serializeClass)
639
{
640
// Always use the base VM here.
641
// If this method is called inside AOT compilation, TR_J9SharedCacheVM will
642
// attempt validation and return NULL for many methods invoked here.
643
// We do not want that, because these values will be cached and later used in non-AOT
644
// compilations, where we always need a non-NULL result.
645
TR_J9VM *fe = (TR_J9VM *)TR_J9VMBase::get(vmThread->javaVM->jitConfig, vmThread);
646
J9Method *methodsOfClass = (J9Method *)fe->getMethods((TR_OpaqueClassBlock *)clazz);
647
int32_t numDims = 0;
648
TR_OpaqueClassBlock *baseClass = fe->getBaseComponentClass((TR_OpaqueClassBlock *)clazz, numDims);
649
TR_OpaqueClassBlock *parentClass = fe->getSuperClass((TR_OpaqueClassBlock *)clazz);
650
651
uint32_t numMethods = clazz->romClass->romMethodCount;
652
std::vector<uint8_t> methodTracingInfo;
653
methodTracingInfo.reserve(numMethods);
654
655
std::vector<J9ROMMethod *> origROMMethods;
656
origROMMethods.reserve(numMethods);
657
for (uint32_t i = 0; i < numMethods; ++i)
658
{
659
methodTracingInfo.push_back(static_cast<uint8_t>(fe->isMethodTracingEnabled((TR_OpaqueMethodBlock *)&methodsOfClass[i])));
660
// record client-side pointers to ROM methods
661
origROMMethods.push_back(fe->getROMMethodFromRAMMethod(&methodsOfClass[i]));
662
}
663
664
bool classHasFinalFields = fe->hasFinalFieldsInClass((TR_OpaqueClassBlock *)clazz);
665
uintptr_t classDepthAndFlags = fe->getClassDepthAndFlagsValue((TR_OpaqueClassBlock *)clazz);
666
bool classInitialized = fe->isClassInitialized((TR_OpaqueClassBlock *)clazz);
667
uint32_t byteOffsetToLockword = fe->getByteOffsetToLockword((TR_OpaqueClassBlock *)clazz);
668
TR_OpaqueClassBlock *leafComponentClass = fe->getLeafComponentClassFromArrayClass((TR_OpaqueClassBlock *)clazz);
669
void *classLoader = fe->getClassLoader((TR_OpaqueClassBlock *)clazz);
670
TR_OpaqueClassBlock *hostClass = fe->convertClassPtrToClassOffset(clazz->hostClass);
671
TR_OpaqueClassBlock *componentClass = fe->getComponentClassFromArrayClass((TR_OpaqueClassBlock *)clazz);
672
TR_OpaqueClassBlock *arrayClass = fe->getArrayClassFromComponentClass((TR_OpaqueClassBlock *)clazz);
673
uintptr_t totalInstanceSize = clazz->totalInstanceSize;
674
uintptr_t cp = fe->getConstantPoolFromClass((TR_OpaqueClassBlock *)clazz);
675
uintptr_t classFlags = fe->getClassFlagsValue((TR_OpaqueClassBlock *)clazz);
676
auto sharedCache = fe->sharedCache();
677
uintptr_t *classChainIdentifyingLoader = NULL;
678
uintptr_t classChainOffsetIdentifyingLoader = sharedCache ?
679
sharedCache->getClassChainOffsetIdentifyingLoaderNoFail((TR_OpaqueClassBlock *)clazz, &classChainIdentifyingLoader) : 0;
680
681
std::string classNameIdentifyingLoader;
682
if (fe->getPersistentInfo()->getJITServerUseAOTCache() && classChainIdentifyingLoader)
683
{
684
const J9UTF8 *name = J9ROMCLASS_CLASSNAME(sharedCache->startingROMClassOfClassChain(classChainIdentifyingLoader));
685
classNameIdentifyingLoader = std::string((const char *)J9UTF8_DATA(name), J9UTF8_LENGTH(name));
686
}
687
688
std::string packedROMClassStr;
689
if (serializeClass)
690
{
691
TR::StackMemoryRegion stackMemoryRegion(*trMemory);
692
size_t packedSize;
693
J9ROMClass *packedROMClass = packROMClass(clazz->romClass, trMemory, packedSize);
694
packedROMClassStr = std::string((const char *)packedROMClass, packedSize);
695
}
696
697
int32_t arrayElementSize = vmThread->javaVM->internalVMFunctions->arrayElementSize((J9ArrayClass*)clazz);
698
699
return std::make_tuple(
700
packedROMClassStr, methodsOfClass, baseClass, numDims, parentClass,
701
TR::Compiler->cls.getITable((TR_OpaqueClassBlock *)clazz), methodTracingInfo,
702
classHasFinalFields, classDepthAndFlags, classInitialized, byteOffsetToLockword, leafComponentClass,
703
classLoader, hostClass, componentClass, arrayClass, totalInstanceSize, clazz->romClass,
704
cp, classFlags, classChainOffsetIdentifyingLoader, origROMMethods, classNameIdentifyingLoader, arrayElementSize
705
);
706
}
707
708
J9ROMClass *
709
JITServerHelpers::romClassFromString(const std::string &romClassStr, TR_PersistentMemory *persistentMemory)
710
{
711
if (auto cache = TR::CompilationInfo::get()->getJITServerSharedROMClassCache())
712
return cache->getOrCreate((const J9ROMClass *)romClassStr.data());
713
714
auto romClass = (J9ROMClass *)persistentMemory->allocatePersistentMemory(romClassStr.size(), TR_Memory::ROMClass);
715
if (!romClass)
716
throw std::bad_alloc();
717
memcpy(romClass, romClassStr.data(), romClassStr.size());
718
return romClass;
719
}
720
721
J9ROMClass *
722
JITServerHelpers::getRemoteROMClass(J9Class *clazz, JITServer::ServerStream *stream,
723
TR_PersistentMemory *persistentMemory, ClassInfoTuple &classInfoTuple)
724
{
725
stream->write(JITServer::MessageType::ResolvedMethod_getRemoteROMClassAndMethods, clazz);
726
auto recv = stream->read<ClassInfoTuple>();
727
classInfoTuple = std::get<0>(recv);
728
return romClassFromString(std::get<0>(classInfoTuple), persistentMemory);
729
}
730
731
// Return true if able to get data from cache, return false otherwise.
732
bool
733
JITServerHelpers::getAndCacheRAMClassInfo(J9Class *clazz, ClientSessionData *clientSessionData,
734
JITServer::ServerStream *stream, ClassInfoDataType dataType, void *data)
735
{
736
if (!clazz)
737
return false;
738
739
{
740
OMR::CriticalSection getRemoteROMClass(clientSessionData->getROMMapMonitor());
741
auto it = clientSessionData->getROMClassMap().find(clazz);
742
if (it != clientSessionData->getROMClassMap().end())
743
{
744
JITServerHelpers::getROMClassData(it->second, dataType, data);
745
return true;
746
}
747
}
748
749
stream->write(JITServer::MessageType::ResolvedMethod_getRemoteROMClassAndMethods, clazz);
750
auto recv = stream->read<ClassInfoTuple>();
751
auto &classInfoTuple = std::get<0>(recv);
752
753
OMR::CriticalSection cacheRemoteROMClass(clientSessionData->getROMMapMonitor());
754
auto it = clientSessionData->getROMClassMap().find(clazz);
755
if (it == clientSessionData->getROMClassMap().end())
756
{
757
auto romClass = romClassFromString(std::get<0>(classInfoTuple), clientSessionData->persistentMemory());
758
auto &classInfoStruct = JITServerHelpers::cacheRemoteROMClass(clientSessionData, clazz, romClass, classInfoTuple);
759
JITServerHelpers::getROMClassData(classInfoStruct, dataType, data);
760
}
761
else
762
{
763
JITServerHelpers::getROMClassData(it->second, dataType, data);
764
}
765
return false;
766
}
767
768
// Return true if able to get data from cache, return false otherwise.
769
bool
770
JITServerHelpers::getAndCacheRAMClassInfo(J9Class *clazz, ClientSessionData *clientSessionData,
771
JITServer::ServerStream *stream, ClassInfoDataType dataType1, void *data1,
772
ClassInfoDataType dataType2, void *data2)
773
{
774
if (!clazz)
775
return false;
776
777
{
778
OMR::CriticalSection getRemoteROMClass(clientSessionData->getROMMapMonitor());
779
auto it = clientSessionData->getROMClassMap().find(clazz);
780
if (it != clientSessionData->getROMClassMap().end())
781
{
782
JITServerHelpers::getROMClassData(it->second, dataType1, data1);
783
JITServerHelpers::getROMClassData(it->second, dataType2, data2);
784
return true;
785
}
786
}
787
788
stream->write(JITServer::MessageType::ResolvedMethod_getRemoteROMClassAndMethods, clazz);
789
auto recv = stream->read<ClassInfoTuple>();
790
auto &classInfoTuple = std::get<0>(recv);
791
792
OMR::CriticalSection cacheRemoteROMClass(clientSessionData->getROMMapMonitor());
793
auto it = clientSessionData->getROMClassMap().find(clazz);
794
if (it == clientSessionData->getROMClassMap().end())
795
{
796
auto romClass = romClassFromString(std::get<0>(classInfoTuple), clientSessionData->persistentMemory());
797
auto &classInfoStruct = JITServerHelpers::cacheRemoteROMClass(clientSessionData, clazz, romClass, classInfoTuple);
798
JITServerHelpers::getROMClassData(classInfoStruct, dataType1, data1);
799
JITServerHelpers::getROMClassData(classInfoStruct, dataType2, data2);
800
}
801
else
802
{
803
JITServerHelpers::getROMClassData(it->second, dataType1, data1);
804
JITServerHelpers::getROMClassData(it->second, dataType2, data2);
805
}
806
return false;
807
}
808
809
void
810
JITServerHelpers::getROMClassData(const ClientSessionData::ClassInfo &classInfo, ClassInfoDataType dataType, void *data)
811
{
812
switch (dataType)
813
{
814
case CLASSINFO_ROMCLASS_MODIFIERS :
815
*(uint32_t *)data = classInfo._romClass->modifiers;
816
break;
817
case CLASSINFO_ROMCLASS_EXTRAMODIFIERS :
818
*(uint32_t *)data = classInfo._romClass->extraModifiers;
819
break;
820
case CLASSINFO_BASE_COMPONENT_CLASS :
821
*(TR_OpaqueClassBlock **)data = classInfo._baseComponentClass;
822
break;
823
case CLASSINFO_NUMBER_DIMENSIONS :
824
*(int32_t *)data = classInfo._numDimensions;
825
break;
826
case CLASSINFO_PARENT_CLASS :
827
*(TR_OpaqueClassBlock **)data = classInfo._parentClass;
828
break;
829
case CLASSINFO_CLASS_HAS_FINAL_FIELDS :
830
*(bool *)data = classInfo._classHasFinalFields;
831
break;
832
case CLASSINFO_CLASS_DEPTH_AND_FLAGS :
833
*(uintptr_t *)data = classInfo._classDepthAndFlags;
834
break;
835
case CLASSINFO_CLASS_INITIALIZED :
836
*(bool *)data = classInfo._classInitialized;
837
break;
838
case CLASSINFO_BYTE_OFFSET_TO_LOCKWORD :
839
*(uint32_t *)data = classInfo._byteOffsetToLockword;
840
break;
841
case CLASSINFO_LEAF_COMPONENT_CLASS :
842
*(TR_OpaqueClassBlock **)data = classInfo._leafComponentClass;
843
break;
844
case CLASSINFO_CLASS_LOADER :
845
*(void **)data = classInfo._classLoader;
846
break;
847
case CLASSINFO_HOST_CLASS :
848
*(TR_OpaqueClassBlock **)data = classInfo._hostClass;
849
break;
850
case CLASSINFO_COMPONENT_CLASS :
851
*(TR_OpaqueClassBlock **)data = classInfo._componentClass;
852
break;
853
case CLASSINFO_ARRAY_CLASS :
854
*(TR_OpaqueClassBlock **)data = classInfo._arrayClass;
855
break;
856
case CLASSINFO_TOTAL_INSTANCE_SIZE :
857
*(uintptr_t *)data = classInfo._totalInstanceSize;
858
break;
859
case CLASSINFO_REMOTE_ROM_CLASS :
860
*(J9ROMClass **)data = classInfo._remoteRomClass;
861
break;
862
case CLASSINFO_CLASS_FLAGS :
863
*(uintptr_t *)data = classInfo._classFlags;
864
break;
865
case CLASSINFO_METHODS_OF_CLASS :
866
*(J9Method **)data = classInfo._methodsOfClass;
867
break;
868
case CLASSINFO_CONSTANT_POOL :
869
*(J9ConstantPool **)data = classInfo._constantPool;
870
break;
871
case CLASSINFO_CLASS_CHAIN_OFFSET_IDENTIFYING_LOADER:
872
*(uintptr_t *)data = classInfo._classChainOffsetIdentifyingLoader;
873
break;
874
case CLASSINFO_ARRAY_ELEMENT_SIZE:
875
*(int32_t *)data = classInfo._arrayElementSize;
876
break;
877
default:
878
TR_ASSERT(false, "Class Info not supported %u\n", dataType);
879
break;
880
}
881
}
882
883
J9ROMMethod *
884
JITServerHelpers::romMethodOfRamMethod(J9Method* method)
885
{
886
// JITServer
887
auto clientData = TR::compInfoPT->getClientData();
888
J9ROMMethod *romMethod = NULL;
889
890
// Check if the method is already cached.
891
{
892
OMR::CriticalSection romCache(clientData->getROMMapMonitor());
893
auto &map = clientData->getJ9MethodMap();
894
auto it = map.find((J9Method*) method);
895
if (it != map.end())
896
romMethod = it->second._romMethod;
897
}
898
899
// If not, cache the associated ROM class and get the ROM method from it.
900
if (!romMethod)
901
{
902
auto stream = TR::CompilationInfo::getStream();
903
stream->write(JITServer::MessageType::VM_getClassOfMethod, (TR_OpaqueMethodBlock*) method);
904
J9Class *clazz = (J9Class*) std::get<0>(stream->read<TR_OpaqueClassBlock *>());
905
TR::compInfoPT->getAndCacheRemoteROMClass(clazz);
906
{
907
OMR::CriticalSection romCache(clientData->getROMMapMonitor());
908
auto &map = clientData->getJ9MethodMap();
909
auto it = map.find((J9Method *) method);
910
if (it != map.end())
911
romMethod = it->second._romMethod;
912
}
913
}
914
TR_ASSERT(romMethod, "Should have acquired romMethod");
915
return romMethod;
916
}
917
918
void
919
JITServerHelpers::postStreamFailure(OMRPortLibrary *portLibrary, TR::CompilationInfo *compInfo)
920
{
921
OMR::CriticalSection postStreamFailure(getClientStreamMonitor());
922
923
OMRPORT_ACCESS_FROM_OMRPORT(portLibrary);
924
uint64_t current_time = omrtime_current_time_millis();
925
if (!_waitTimeMs)
926
_waitTimeMs = TR::Options::_reconnectWaitTimeMs;
927
if (current_time >= _nextConnectionRetryTime)
928
_waitTimeMs *= 2; // Exponential backoff
929
_nextConnectionRetryTime = current_time + _waitTimeMs;
930
931
if (_serverAvailable && TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerboseJITServerConns))
932
{
933
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,
934
"t=%6u Lost connection to the server (serverUID=%llu)",
935
(uint32_t)compInfo->getPersistentInfo()->getElapsedTime(),
936
(unsigned long long)compInfo->getPersistentInfo()->getServerUID());
937
compInfo->getPersistentInfo()->setServerUID(0);
938
}
939
940
_serverAvailable = false;
941
942
// Reset the activation policy flag in case we never reconnect to the server
943
// and client compiles locally or connects to a new server
944
compInfo->setCompThreadActivationPolicy(JITServer::CompThreadActivationPolicy::AGGRESSIVE);
945
if (TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerboseCompilationThreads) ||
946
TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerboseJITServer))
947
{
948
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,
949
"t=%6u client has lost connection, resetting activation policy to AGGRESSIVE",
950
(uint32_t)compInfo->getPersistentInfo()->getElapsedTime());
951
}
952
}
953
954
void
955
JITServerHelpers::postStreamConnectionSuccess()
956
{
957
_serverAvailable = true;
958
_waitTimeMs = TR::Options::_reconnectWaitTimeMs;
959
}
960
961
bool
962
JITServerHelpers::shouldRetryConnection(OMRPortLibrary *portLibrary)
963
{
964
OMRPORT_ACCESS_FROM_OMRPORT(portLibrary);
965
return omrtime_current_time_millis() > _nextConnectionRetryTime;
966
}
967
968
bool
969
JITServerHelpers::isAddressInROMClass(const void *address, const J9ROMClass *romClass)
970
{
971
return ((address >= romClass) && (address < (((uint8_t*) romClass) + romClass->romSize)));
972
}
973
974
975
uintptr_t
976
JITServerHelpers::walkReferenceChainWithOffsets(TR_J9VM *fe, const std::vector<uintptr_t> &listOfOffsets, uintptr_t receiver)
977
{
978
uintptr_t result = receiver;
979
for (size_t i = 0; i < listOfOffsets.size(); i++)
980
{
981
result = fe->getReferenceFieldAt(result, listOfOffsets[i]);
982
}
983
return result;
984
}
985
986
uintptr_t
987
JITServerHelpers::getRemoteClassDepthAndFlagsWhenROMClassNotCached(J9Class *clazz, ClientSessionData *clientSessionData,
988
JITServer::ServerStream *stream)
989
{
990
stream->write(JITServer::MessageType::ResolvedMethod_getRemoteROMClassAndMethods, clazz);
991
auto recv = stream->read<JITServerHelpers::ClassInfoTuple>();
992
auto &classInfoTuple = std::get<0>(recv);
993
994
OMR::CriticalSection cacheRemoteROMClass(clientSessionData->getROMMapMonitor());
995
auto it = clientSessionData->getROMClassMap().find(clazz);
996
if (it == clientSessionData->getROMClassMap().end())
997
{
998
auto romClass = JITServerHelpers::romClassFromString(std::get<0>(classInfoTuple), clientSessionData->persistentMemory());
999
auto &classInfoStruct = JITServerHelpers::cacheRemoteROMClass(clientSessionData, clazz, romClass, classInfoTuple);
1000
return classInfoStruct._classDepthAndFlags;
1001
}
1002
else
1003
{
1004
return it->second._classDepthAndFlags;
1005
}
1006
}
1007
1008
static void
1009
addRAMClassToChain(std::vector<J9Class *> &chain, J9Class *clazz, std::vector<J9Class *> &uncached,
1010
PersistentUnorderedSet<J9Class *> &cached)
1011
{
1012
chain.push_back(clazz);
1013
if (cached.insert(clazz).second)
1014
uncached.push_back(clazz);
1015
}
1016
1017
std::vector<J9Class *>
1018
JITServerHelpers::getRAMClassChain(J9Class *clazz, size_t numClasses, J9VMThread *vmThread, TR_Memory *trMemory,
1019
TR::CompilationInfo *compInfo, std::vector<J9Class *> &uncachedRAMClasses,
1020
std::vector<ClassInfoTuple> &uncachedClassInfos)
1021
{
1022
TR_ASSERT(uncachedRAMClasses.empty(), "Must pass empty vector");
1023
TR_ASSERT(uncachedClassInfos.empty(), "Must pass empty vector");
1024
TR_ASSERT(numClasses <= TR_J9SharedCache::maxClassChainLength, "Class chain is too long");
1025
1026
std::vector<J9Class *> chain;
1027
chain.reserve(numClasses);
1028
uncachedRAMClasses.reserve(numClasses);
1029
auto &cached = compInfo->getclassesCachedAtServer();
1030
1031
{
1032
OMR::CriticalSection cs(compInfo->getclassesCachedAtServerMonitor());
1033
1034
addRAMClassToChain(chain, clazz, uncachedRAMClasses, cached);
1035
for (size_t i = 0; i < J9CLASS_DEPTH(clazz); ++i)
1036
addRAMClassToChain(chain, clazz->superclasses[i], uncachedRAMClasses, cached);
1037
for (auto it = (J9ITable *)clazz->iTable; it; it = it->next)
1038
addRAMClassToChain(chain, it->interfaceClass, uncachedRAMClasses, cached);
1039
TR_ASSERT(chain.size() == numClasses, "Invalid RAM class chain length: %zu != %zu", chain.size(), numClasses);
1040
}
1041
1042
uncachedClassInfos.reserve(uncachedRAMClasses.size());
1043
for (J9Class *c : uncachedRAMClasses)
1044
uncachedClassInfos.push_back(packRemoteROMClassInfo(c, vmThread, trMemory, true));
1045
1046
return chain;
1047
}
1048
1049
void
1050
JITServerHelpers::cacheRemoteROMClassBatch(ClientSessionData *clientData, const std::vector<J9Class *> &ramClasses,
1051
const std::vector<ClassInfoTuple> &classInfoTuples)
1052
{
1053
TR_ASSERT_FATAL(ramClasses.size() == classInfoTuples.size(), "Must have equal length");
1054
1055
for (size_t i = 0; i < ramClasses.size(); ++i)
1056
{
1057
auto romClass = romClassFromString(std::get<0>(classInfoTuples[i]), clientData->persistentMemory());
1058
cacheRemoteROMClassOrFreeIt(clientData, ramClasses[i], romClass, classInfoTuples[i]);
1059
}
1060
}
1061
1062