Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/control/JITServerCompilationThread.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2018, 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/JITServerCompilationThread.hpp"
24
25
#include "codegen/CodeGenerator.hpp"
26
#include "control/CompilationRuntime.hpp"
27
#include "control/MethodToBeCompiled.hpp"
28
#include "control/JITServerHelpers.hpp"
29
#include "env/ClassTableCriticalSection.hpp"
30
#include "env/VMAccessCriticalSection.hpp"
31
#include "env/JITServerAllocationRegion.hpp"
32
#include "env/JITServerPersistentCHTable.hpp"
33
#include "env/SystemSegmentProvider.hpp"
34
#include "env/VerboseLog.hpp"
35
#include "env/ut_j9jit.h"
36
#include "runtime/CodeCache.hpp"
37
#include "runtime/CodeCacheExceptions.hpp"
38
#include "runtime/J9VMAccess.hpp"
39
#include "runtime/RelocationTarget.hpp"
40
#include "net/ClientStream.hpp"
41
#include "net/ServerStream.hpp"
42
#include "jitprotos.h"
43
#include "vmaccess.h"
44
45
/**
46
* @brief Helper method executed at the end of a compilation
47
* to determine whether the server is running out of memory.
48
*/
49
JITServer::ServerMemoryState
50
computeServerMemoryState(TR::CompilationInfo *compInfo)
51
{
52
// Compute LOW memory threshold relative to the number of clients but cap it at 16
53
// to avoid wasting memory in cases when clients disconnect without notifying the server
54
size_t numClients = compInfo->getClientSessionHT()->size();
55
numClients = numClients > 16 ? 16 : numClients;
56
uint64_t lowMemoryThreshold = TR::Options::getSafeReservePhysicalMemoryValue() + (numClients + 4) * TR::Options::getScratchSpaceLowerBound();
57
uint64_t veryLowMemoryThreshold = TR::Options::getSafeReservePhysicalMemoryValue() + 4 * TR::Options::getScratchSpaceLowerBound();
58
59
uint64_t freePhysicalMemorySizeB = compInfo->getCachedFreePhysicalMemoryB();
60
61
// If the last measurement was LOW or VERY_LOW, sample memory at a higher rate to
62
// get more up-to-date information
63
JITServer::ServerMemoryState memoryState = JITServer::ServerMemoryState::NORMAL;
64
int64_t updatePeriodMs = -1;
65
if (freePhysicalMemorySizeB != OMRPORT_MEMINFO_NOT_AVAILABLE)
66
{
67
if (freePhysicalMemorySizeB <= veryLowMemoryThreshold)
68
updatePeriodMs = 50;
69
else if (freePhysicalMemorySizeB <= lowMemoryThreshold)
70
updatePeriodMs = 250;
71
}
72
bool incompleteInfo;
73
freePhysicalMemorySizeB = compInfo->computeAndCacheFreePhysicalMemory(incompleteInfo, updatePeriodMs);
74
75
if (freePhysicalMemorySizeB != OMRPORT_MEMINFO_NOT_AVAILABLE)
76
{
77
memoryState = freePhysicalMemorySizeB <= veryLowMemoryThreshold ?
78
JITServer::ServerMemoryState::VERY_LOW :
79
(freePhysicalMemorySizeB <= lowMemoryThreshold ?
80
JITServer::ServerMemoryState::LOW :
81
JITServer::ServerMemoryState::NORMAL);
82
return memoryState;
83
}
84
// memory info not available, return the default state
85
return JITServer::ServerMemoryState::NORMAL;
86
}
87
88
/**
89
* @brief Helper method executed at the end of a compilation
90
* to determine whether the server is approaching the maximum number of active threads.
91
*/
92
JITServer::ServerActiveThreadsState
93
computeServerActiveThreadsState(TR::CompilationInfo *compInfo)
94
{
95
int32_t highActiveThreadThreshold = TR::Options::getHighActiveThreadThreshold();
96
int32_t veryHighActiveThreadThreshold = TR::Options::getVeryHighActiveThreadThreshold();
97
98
// Typically getNumCompThreadsActive() needs to be protected by the compilationQueueMonitor,
99
// except here we allow some small imprecision because we implement a heuristic.
100
int32_t numOfActiveThreads = compInfo->getNumCompThreadsActive();
101
102
JITServer::ServerActiveThreadsState activeThreadState = numOfActiveThreads > veryHighActiveThreadThreshold ?
103
JITServer::ServerActiveThreadsState::VERY_HIGH_THREAD :
104
(numOfActiveThreads > highActiveThreadThreshold ?
105
JITServer::ServerActiveThreadsState::HIGH_THREAD :
106
JITServer::ServerActiveThreadsState::NORMAL_THREAD);
107
return activeThreadState;
108
}
109
110
/**
111
* @brief Method executed by JITServer to process the end of a compilation.
112
*/
113
void
114
outOfProcessCompilationEnd(TR_MethodToBeCompiled *entry, TR::Compilation *comp)
115
{
116
entry->_tryCompilingAgain = false; // TODO: Need to handle recompilations gracefully when relocation fails
117
auto compInfoPT = (TR::CompilationInfoPerThreadRemote *)entry->_compInfoPT;
118
119
TR::CodeCache *codeCache = comp->cg()->getCodeCache();
120
121
TR_ASSERT(comp->getAotMethodDataStart(), "The header must have been set");
122
TR_AOTMethodHeader *aotMethodHeaderEntry = comp->getAotMethodHeaderEntry();
123
124
uint8_t *codeStart = (uint8_t *)aotMethodHeaderEntry->compileMethodCodeStartPC;
125
OMR::CodeCacheMethodHeader *codeCacheHeader = (OMR::CodeCacheMethodHeader *)codeStart;
126
127
TR_DataCache *dataCache = (TR_DataCache *)comp->getReservedDataCache();
128
TR_ASSERT(dataCache, "A dataCache must be reserved for JITServer compilations");
129
J9JITDataCacheHeader *dataCacheHeader = (J9JITDataCacheHeader *)comp->getAotMethodDataStart();
130
131
size_t codeSize = codeCache->getWarmCodeAlloc() - (uint8_t *)codeCacheHeader;
132
size_t dataSize = dataCache->getSegment()->heapAlloc - (uint8_t *)dataCacheHeader;
133
134
std::string codeCacheStr((const char *)codeCacheHeader, codeSize);
135
std::string dataCacheStr((const char *)dataCacheHeader, dataSize);
136
137
CHTableCommitData chTableData;
138
if (!comp->getOption(TR_DisableCHOpts) && !entry->_useAotCompilation)
139
{
140
TR_CHTable *chTable = comp->getCHTable();
141
chTableData = chTable->computeDataForCHTableCommit(comp);
142
}
143
144
auto classesThatShouldNotBeNewlyExtended = compInfoPT->getClassesThatShouldNotBeNewlyExtended();
145
146
// Pack log file to send to client
147
std::string logFileStr = TR::Options::packLogFile(comp->getOutFile());
148
149
std::string svmValueToSymbolStr;
150
if (comp->getOption(TR_UseSymbolValidationManager))
151
{
152
svmValueToSymbolStr = comp->getSymbolValidationManager()->serializeValueToSymbolMap();
153
}
154
155
// Send runtime assumptions created during compilation to the client
156
std::vector<SerializedRuntimeAssumption> serializedRuntimeAssumptions;
157
if (comp->getSerializedRuntimeAssumptions().size() > 0)
158
{
159
serializedRuntimeAssumptions.reserve(comp->getSerializedRuntimeAssumptions().size());
160
for (auto it : comp->getSerializedRuntimeAssumptions())
161
{
162
serializedRuntimeAssumptions.push_back(*it);
163
}
164
}
165
166
auto resolvedMirrorMethodsPersistIPInfo = compInfoPT->getCachedResolvedMirrorMethodsPersistIPInfo();
167
168
JITServer::ServerMemoryState memoryState = computeServerMemoryState(compInfoPT->getCompilationInfo());
169
JITServer::ServerActiveThreadsState activeThreadState = computeServerActiveThreadsState(compInfoPT->getCompilationInfo());
170
171
// Send methods requring resolved trampolines in this compilation to the client
172
std::vector<TR_OpaqueMethodBlock *> methodsRequiringTrampolines;
173
if (comp->getMethodsRequiringTrampolines().size() > 0)
174
{
175
methodsRequiringTrampolines.reserve(comp->getMethodsRequiringTrampolines().size());
176
for (auto it : comp->getMethodsRequiringTrampolines())
177
{
178
methodsRequiringTrampolines.push_back(it);
179
}
180
}
181
182
entry->_stream->finishCompilation(
183
codeCacheStr, dataCacheStr, chTableData,
184
std::vector<TR_OpaqueClassBlock*>(classesThatShouldNotBeNewlyExtended->begin(), classesThatShouldNotBeNewlyExtended->end()),
185
logFileStr, svmValueToSymbolStr,
186
resolvedMirrorMethodsPersistIPInfo
187
? std::vector<TR_ResolvedJ9Method*>(resolvedMirrorMethodsPersistIPInfo->begin(), resolvedMirrorMethodsPersistIPInfo->end())
188
: std::vector<TR_ResolvedJ9Method*>(),
189
*entry->_optimizationPlan, serializedRuntimeAssumptions, memoryState, activeThreadState, methodsRequiringTrampolines
190
);
191
compInfoPT->clearPerCompilationCaches();
192
193
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
194
{
195
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d has successfully compiled %s memoryState=%d",
196
compInfoPT->getCompThreadId(), compInfoPT->getCompilation()->signature(), memoryState);
197
}
198
199
Trc_JITServerCompileEnd(compInfoPT->getCompilationThread(), compInfoPT->getCompThreadId(),
200
compInfoPT->getCompilation()->signature(), compInfoPT->getCompilation()->getHotnessName());
201
202
if (compInfoPT->isAOTCacheStore())
203
{
204
if (comp->isAOTCacheStore())
205
{
206
auto clientData = comp->getClientData();
207
auto cache = clientData->getAOTCache();
208
cache->storeMethod(compInfoPT->getDefiningClassChainRecord(), compInfoPT->getMethodIndex(),
209
entry->_optimizationPlan->getOptLevel(), clientData->getAOTHeaderRecord(),
210
comp->getSerializationRecords(), codeCacheHeader, codeSize,
211
dataCacheHeader, dataSize, comp->signature(), clientData->getClientUID());
212
}
213
else if (TR::Options::getVerboseOption(TR_VerboseJITServer))
214
{
215
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "Failed to serialize AOT method %s", comp->signature());
216
}
217
}
218
}
219
220
TR::CompilationInfoPerThreadRemote::CompilationInfoPerThreadRemote(TR::CompilationInfo &compInfo, J9JITConfig *jitConfig, int32_t id, bool isDiagnosticThread)
221
: CompilationInfoPerThread(compInfo, jitConfig, id, isDiagnosticThread),
222
_recompilationMethodInfo(NULL),
223
_seqNo(0),
224
_waitToBeNotified(false),
225
_clientOptions(NULL),
226
_clientOptionsSize(0),
227
_methodIPDataPerComp(NULL),
228
_resolvedMethodInfoMap(NULL),
229
_resolvedMirrorMethodsPersistIPInfo(NULL),
230
_classOfStaticMap(NULL),
231
_fieldAttributesCache(NULL),
232
_staticAttributesCache(NULL),
233
_isUnresolvedStrCache(NULL),
234
_classUnloadReadMutexDepth(0),
235
_aotCacheStore(false),
236
_methodIndex((uint32_t)-1),
237
_definingClassChainRecord(NULL)
238
{}
239
240
/**
241
* @brief Method executed by JITServer to dequeue and notify all waiting threads
242
* that the condition they were waiting for has been fulfilled.
243
* Needs to be executed with clientSession->getSequencingMonitor() in hand.
244
*/
245
void
246
TR::CompilationInfoPerThreadRemote::notifyAndDetachWaitingRequests(ClientSessionData *clientSession)
247
{
248
TR_MethodToBeCompiled *nextEntry = clientSession->getOOSequenceEntryList();
249
// I need to keep notifying until the first request that is blocked
250
// because the request it depends on hasn't been processed yet.
251
while (nextEntry)
252
{
253
uint32_t nextWaitingSeqNo = ((CompilationInfoPerThreadRemote*)(nextEntry->_compInfoPT))->getSeqNo();
254
uint32_t expectedSeqNo = ((CompilationInfoPerThreadRemote*)(nextEntry->_compInfoPT))->getExpectedSeqNo();
255
if (expectedSeqNo <= clientSession->getLastProcessedCriticalSeqNo())
256
{
257
clientSession->notifyAndDetachFirstWaitingThread();
258
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
259
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d notifying out-of-sequence thread %d for clientUID=%llu seqNo=%u (entry=%p)",
260
getCompThreadId(), nextEntry->_compInfoPT->getCompThreadId(), (unsigned long long)clientSession->getClientUID(), nextWaitingSeqNo, nextEntry);
261
nextEntry = clientSession->getOOSequenceEntryList();
262
}
263
else // The request I depend on hasn't been processed yet, so stop here
264
{
265
break;
266
}
267
}
268
}
269
270
int32_t TR::CompilationInfoPerThreadRemote::_numClearedCaches = 0;
271
272
/**
273
* @brief Method executed by a compilation thread at JITServer to wait for all
274
* previous compilation requests it depends on to be processed.
275
* Needs to be executed with sequencingMonitor in hand.
276
*/
277
void
278
TR::CompilationInfoPerThreadRemote::waitForMyTurn(ClientSessionData *clientSession, TR_MethodToBeCompiled &entry)
279
{
280
TR_ASSERT(getMethodBeingCompiled() == &entry, "Must have stored the entry to be compiled into compInfoPT");
281
TR_ASSERT(entry._compInfoPT == this, "Must have stored compInfoPT into the entry to be compiled");
282
uint32_t seqNo = getSeqNo();
283
uint32_t criticalSeqNo = getExpectedSeqNo(); // This is the seqNo that I must wait for
284
285
// Insert this thread into the list of out of sequence entries
286
JITServerHelpers::insertIntoOOSequenceEntryList(clientSession, &entry);
287
288
do // Do a timed wait until the missing seqNo arrives
289
{
290
// Always reset _waitToBeNotified before waiting on the monitor
291
// If a notification does not arrive, this request will timeout and possibly clear the caches
292
setWaitToBeNotified(false);
293
294
entry.getMonitor()->enter();
295
clientSession->getSequencingMonitor()->exit(); // release monitor before waiting
296
const int64_t waitTimeMillis = 1000; // TODO: create an option for this
297
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
298
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d (entry=%p) doing a timed wait for %d ms (waiting for seqNo=%u)",
299
getCompThreadId(), &entry, (int32_t)waitTimeMillis, criticalSeqNo);
300
301
Trc_JITServerTimedWait(getCompilationThread(), getCompThreadId(), clientSession,
302
(unsigned long long)clientSession->getClientUID(), &entry,
303
seqNo, criticalSeqNo, clientSession->getNumActiveThreads(), (int32_t)waitTimeMillis);
304
305
intptr_t monitorStatus = entry.getMonitor()->wait_timed(waitTimeMillis, 0); // 0 or J9THREAD_TIMED_OUT
306
if (monitorStatus == 0) // Thread was notified
307
{
308
entry.getMonitor()->exit();
309
clientSession->getSequencingMonitor()->enter();
310
311
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
312
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d (entry=%p) is parked. seqNo=%u was notified",
313
getCompThreadId(), &entry, seqNo);
314
// Will verify condition again to see if expectedSeqNo has advanced enough
315
316
Trc_JITServerParkThread(getCompilationThread(), getCompThreadId(), clientSession,
317
(unsigned long long)clientSession->getClientUID(), &entry,
318
seqNo, criticalSeqNo, clientSession->getNumActiveThreads(), seqNo);
319
}
320
else // Timeout
321
{
322
entry.getMonitor()->exit();
323
TR_ASSERT(monitorStatus == J9THREAD_TIMED_OUT, "Unexpected monitor state");
324
if (TR::Options::isAnyVerboseOptionSet(TR_VerboseCompFailure, TR_VerboseJITServer, TR_VerbosePerformance))
325
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d (entry=%p) timed-out while waiting for seqNo=%u ",
326
getCompThreadId(), &entry, criticalSeqNo);
327
328
Trc_JITServerTimedOut(getCompilationThread(), getCompThreadId(), clientSession,
329
(unsigned long long)clientSession->getClientUID(), &entry,
330
seqNo, criticalSeqNo, clientSession->getNumActiveThreads(), criticalSeqNo);
331
332
// The simplest thing is to delete the cached data for the session and start fresh
333
// However, we must wait for any active threads to drain out
334
clientSession->getSequencingMonitor()->enter();
335
336
// This thread could have been waiting, then timed-out and then waited
337
// to acquire the sequencing monitor. Check whether it can proceed.
338
if (criticalSeqNo <= clientSession->getLastProcessedCriticalSeqNo())
339
{
340
// The entry cannot be in the list
341
TR_MethodToBeCompiled *headEntry = clientSession->getOOSequenceEntryList();
342
if (headEntry)
343
{
344
uint32_t headSeqNo = ((TR::CompilationInfoPerThreadRemote*)(headEntry->_compInfoPT))->getSeqNo();
345
TR_ASSERT_FATAL(seqNo < headSeqNo, "Next in line method cannot be in the waiting list: seqNo=%u >= headSeqNo=%u entry=%p headEntry=%p",
346
seqNo, headSeqNo, &entry, headEntry);
347
}
348
break; // It's my turn, so proceed
349
}
350
351
if (clientSession->getNumActiveThreads() <= 0 && // Wait for active threads to quiesce
352
&entry == clientSession->getOOSequenceEntryList() && // Allow only the smallest seqNo which is the head
353
!getWaitToBeNotified()) // Avoid a cohort of threads clearing the caches
354
{
355
clientSession->clearCaches();
356
incNumClearedCaches();
357
358
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
359
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,
360
"compThreadID=%d has cleared the session caches for clientUID=%llu criticalSeqNo=%u seqNo=%u firstEntry=%p",
361
getCompThreadId(), clientSession->getClientUID(), criticalSeqNo, seqNo, &entry);
362
363
Trc_JITServerClearedSessionCaches(getCompilationThread(), getCompThreadId(), clientSession,
364
(unsigned long long)clientSession->getClientUID(),
365
seqNo, criticalSeqNo, clientSession->getNumActiveThreads(), &entry,
366
clientSession->getLastProcessedCriticalSeqNo(), seqNo);
367
368
clientSession->setLastProcessedCriticalSeqNo(criticalSeqNo);// Allow myself to go through
369
notifyAndDetachWaitingRequests(clientSession);
370
// Mark the next request that it should not try to clear the caches,
371
// but rather to sleep again waiting for my notification.
372
// We only need to do this for the head entry in the waiting list
373
// due to the check `&entry == clientSession->getOOSequenceEntryList()` above
374
TR_MethodToBeCompiled *nextWaitingEntry = clientSession->getOOSequenceEntryList();
375
if (nextWaitingEntry)
376
{
377
((TR::CompilationInfoPerThreadRemote*)(nextWaitingEntry->_compInfoPT))->setWaitToBeNotified(true);
378
}
379
}
380
else
381
{
382
// Wait until all active threads have been drained
383
// and the head of the list has cleared the caches
384
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
385
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,
386
"compThreadID=%d which previously timed-out will go to sleep again. Possible reasons numActiveThreads=%d waitToBeNotified=%d",
387
getCompThreadId(), clientSession->getNumActiveThreads(), getWaitToBeNotified());
388
389
Trc_JITServerThreadGoSleep(getCompilationThread(), getCompThreadId(), clientSession,
390
(unsigned long long)clientSession->getClientUID(),
391
seqNo, criticalSeqNo, clientSession->getNumActiveThreads(), getWaitToBeNotified());
392
}
393
}
394
} while (criticalSeqNo > clientSession->getLastProcessedCriticalSeqNo());
395
}
396
397
bool
398
TR::CompilationInfoPerThreadRemote::serveCachedAOTMethod(TR_MethodToBeCompiled &entry, J9Method *method, J9Class *definingClass,
399
TR_OptimizationPlan *optPlan, ClientSessionData *clientData,
400
J9::J9SegmentProvider &scratchSegmentProvider)
401
{
402
auto aotCache = clientData->getAOTCache();
403
auto serializedMethod = aotCache->findMethod(_definingClassChainRecord, _methodIndex,
404
optPlan->getOptLevel(), clientData->getAOTHeaderRecord());
405
if (!serializedMethod)
406
return false;
407
408
size_t segmentSize = scratchSegmentProvider.getPreferredSegmentSize();
409
if (!segmentSize)
410
segmentSize = 1 << 24/*16 MB*/;
411
TR::RawAllocator rawAllocator(getCompilationThread()->javaVM);
412
J9::SystemSegmentProvider segmentProvider(1 << 16/*64 KB*/, segmentSize, TR::Options::getScratchSpaceLimit(),
413
scratchSegmentProvider, rawAllocator);
414
TR::Region region(segmentProvider, rawAllocator);
415
TR_Memory trMemory(*clientData->persistentMemory(), region);
416
417
VectorAllocator<const AOTSerializationRecord *> recordsAllocator(trMemory.heapMemoryRegion());
418
Vector<const AOTSerializationRecord *> records(recordsAllocator);
419
{
420
OMR::CriticalSection cs(clientData->getAOTCacheKnownIdsMonitor());
421
records = aotCache->getSerializationRecords(serializedMethod, clientData->getAOTCacheKnownIds(), trMemory);
422
}
423
424
std::vector<std::string> serializedRecords;
425
serializedRecords.reserve(records.size());
426
for (auto r : records)
427
serializedRecords.push_back(std::string((const char *)r, r->size()));
428
429
//NOTE: Leaving optimization plan unchanged. This can be changed in the future.
430
entry._stream->write(JITServer::MessageType::AOTCache_serializedAOTMethod,
431
std::string((const char *)&serializedMethod->data(), serializedMethod->data().size()),
432
serializedRecords, *optPlan, computeServerMemoryState(getCompilationInfo()),
433
computeServerActiveThreadsState(getCompilationInfo()));
434
435
return true;
436
}
437
438
/**
439
* @brief Method executed by JITServer to process the compilation request.
440
*/
441
void
442
TR::CompilationInfoPerThreadRemote::processEntry(TR_MethodToBeCompiled &entry, J9::J9SegmentProvider &scratchSegmentProvider)
443
{
444
static bool enableJITServerPerCompConn = feGetEnv("TR_EnableJITServerPerCompConn") ? true : false;
445
446
bool abortCompilation = false;
447
bool deleteStream = false;
448
uint64_t clientId = 0;
449
TR::CompilationInfo *compInfo = getCompilationInfo();
450
J9VMThread *compThread = getCompilationThread();
451
JITServer::ServerStream *stream = entry._stream;
452
setMethodBeingCompiled(&entry); // Must have compilation monitor
453
entry._compInfoPT = this; // Create the reverse link
454
// Update the last time the compilation thread had to do something.
455
compInfo->setLastReqStartTime(compInfo->getPersistentInfo()->getElapsedTime());
456
clearPerCompilationCaches();
457
458
_recompilationMethodInfo = NULL;
459
// Release compMonitor before doing the blocking read
460
compInfo->releaseCompMonitor(compThread);
461
462
char *clientOptions = NULL;
463
TR_OptimizationPlan *optPlan = NULL;
464
_vm = NULL;
465
bool useAotCompilation = false;
466
uint32_t seqNo = 0;
467
ClientSessionData *clientSession = NULL;
468
bool isCriticalRequest = false;
469
// numActiveThreads is incremented after it waits for its turn to execute
470
// and before the thread processes unloaded classes and CHTable init and update.
471
// A stream exception could be thrown at any time such as reading the compilation
472
// request (numActiveThreads hasn't been incremented), or an exeption could be
473
// thrown when a message such as MessageType::getUnloadedClassRangesAndCHTable
474
// is sent to the client (numActiveThreads has been incremented).
475
// hasIncNumActiveThreads is used to determine if decNumActiveThreads() should be
476
// called when an exception is thrown.
477
bool hasIncNumActiveThreads = false;
478
// Keep track of whether the lastProcessedCriticalSeqNo in the client session was updated
479
bool hasUpdatedSeqNo = false;
480
bool aotCacheHit = false;
481
482
_aotCacheStore = false;
483
_methodIndex = (uint32_t)-1;
484
_definingClassChainRecord = NULL;
485
486
try
487
{
488
auto req = stream->readCompileRequest<
489
uint64_t, uint32_t, uint32_t, J9Method *, J9Class *, TR_OptimizationPlan, std::string,
490
J9::IlGeneratorMethodDetailsType, std::vector<TR_OpaqueClassBlock *>, std::vector<TR_OpaqueClassBlock *>,
491
JITServerHelpers::ClassInfoTuple, std::string, std::string, std::string, std::string,
492
bool, bool, bool, uint32_t, uintptr_t *, std::vector<J9Class *>, std::vector<J9Class *>,
493
std::vector<JITServerHelpers::ClassInfoTuple>, std::vector<uintptr_t>
494
>();
495
496
clientId = std::get<0>(req);
497
seqNo = std::get<1>(req); // Sequence number at the client
498
uint32_t criticalSeqNo = std::get<2>(req); // Sequence number of the request this request depends upon
499
J9Method *ramMethod = std::get<3>(req);
500
J9Class *clazz = std::get<4>(req);
501
auto &clientOptPlan = std::get<5>(req);
502
auto &detailsStr = std::get<6>(req);
503
auto detailsType = std::get<7>(req);
504
auto &unloadedClasses = std::get<8>(req);
505
auto &illegalModificationList = std::get<9>(req);
506
auto &classInfoTuple = std::get<10>(req);
507
auto &clientOptStr = std::get<11>(req);
508
auto &recompInfoStr = std::get<12>(req);
509
auto &chtableUnloads = std::get<13>(req);
510
auto &chtableMods = std::get<14>(req);
511
useAotCompilation = std::get<15>(req);
512
bool isInStartupPhase = std::get<16>(req);
513
bool aotCacheLoad = std::get<17>(req);
514
_methodIndex = std::get<18>(req);
515
uintptr_t *classChain = std::get<19>(req);
516
auto &ramClassChain = std::get<20>(req);
517
auto &uncachedRAMClasses = std::get<21>(req);
518
auto &uncachedClassInfos = std::get<22>(req);
519
auto &newKnownIds = std::get<23>(req);
520
521
TR_ASSERT_FATAL(TR::Compiler->persistentMemory() == compInfo->persistentMemory(),
522
"per-client persistent memory must not be set at this point");
523
524
TR::IlGeneratorMethodDetails *clientDetails = (TR::IlGeneratorMethodDetails *)detailsStr.data();
525
*(uintptr_t *)clientDetails = 0; // smash remote vtable pointer to catch bugs early
526
TR::IlGeneratorMethodDetails serverDetailsStorage;
527
TR::IlGeneratorMethodDetails *serverDetails = TR::IlGeneratorMethodDetails::clone(serverDetailsStorage, *clientDetails, detailsType);
528
529
isCriticalRequest =
530
(!chtableMods.empty()
531
|| !chtableUnloads.empty()
532
|| !illegalModificationList.empty()
533
|| !unloadedClasses.empty())
534
&& !serverDetails->isJitDumpMethod(); // if this is a JitDump recompilation, ignore any critical updates
535
536
if (useAotCompilation)
537
{
538
_vm = TR_J9VMBase::get(_jitConfig, compThread, TR_J9VMBase::J9_SHARED_CACHE_SERVER_VM);
539
}
540
else
541
{
542
_vm = TR_J9VMBase::get(_jitConfig, compThread, TR_J9VMBase::J9_SERVER_VM);
543
}
544
545
if (_vm->sharedCache())
546
// Set/update stream pointer in shared cache.
547
// Note that if remote-AOT is enabled, even regular J9_SERVER_VM will have a shared cache
548
// This behaviour is consistent with non-JITServer
549
((TR_J9JITServerSharedCache *) _vm->sharedCache())->setStream(stream);
550
551
//if (seqNo == 501)
552
// throw JITServer::StreamFailure(); // stress testing
553
554
stream->setClientId(clientId);
555
setSeqNo(seqNo); // Memorize the sequence number of this request
556
setExpectedSeqNo(criticalSeqNo); // Memorize the message I have to wait for
557
558
bool sessionDataWasEmpty = false;
559
{
560
// Get a pointer to this client's session data
561
// Obtain monitor RAII style because creating a new hastable entry may throw bad_alloc
562
OMR::CriticalSection compilationMonitorLock(compInfo->getCompilationMonitor());
563
compInfo->getClientSessionHT()->purgeOldDataIfNeeded(); // Try to purge old data
564
if (!(clientSession = compInfo->getClientSessionHT()->findOrCreateClientSession(clientId, criticalSeqNo, &sessionDataWasEmpty, _jitConfig)))
565
throw std::bad_alloc();
566
567
setClientData(clientSession); // Cache the session data into CompilationInfoPerThreadRemote object
568
569
// After this line, all persistent allocations are made per-client,
570
// until exitPerClientAllocationRegion is called
571
enterPerClientAllocationRegion();
572
TR_ASSERT(!clientSession->usesPerClientMemory() || (TR::Compiler->persistentMemory() != compInfo->persistentMemory()),
573
"per-client persistent memory must be set at this point");
574
575
clientSession->setIsInStartupPhase(isInStartupPhase);
576
} // End critical section
577
578
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
579
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,
580
"compThreadID=%d %s clientSessionData=%p for clientUID=%llu seqNo=%u (isCritical=%d) (criticalSeqNo=%u lastProcessedCriticalReq=%u)",
581
getCompThreadId(), sessionDataWasEmpty ? "created" : "found", clientSession, (unsigned long long)clientId, seqNo,
582
isCriticalRequest, criticalSeqNo, clientSession->getLastProcessedCriticalSeqNo());
583
584
Trc_JITServerClientSessionData1(compThread, getCompThreadId(), sessionDataWasEmpty ? "created" : "found",
585
clientSession, (unsigned long long)clientId, seqNo, isCriticalRequest, criticalSeqNo, clientSession->getLastProcessedCriticalSeqNo());
586
587
if (!newKnownIds.empty())
588
{
589
OMR::CriticalSection cs(clientSession->getAOTCacheKnownIdsMonitor());
590
clientSession->getAOTCacheKnownIds().insert(newKnownIds.begin(), newKnownIds.end());
591
}
592
593
// We must process unloaded classes lists in the same order they were generated at the client
594
// Use a sequencing scheme to re-order compilation requests
595
//
596
clientSession->getSequencingMonitor()->enter();
597
clientSession->updateMaxReceivedSeqNo(seqNo); // TODO: why do I need this?
598
599
// This request can go through as long as criticalSeqNo has been processed
600
if (criticalSeqNo > clientSession->getLastProcessedCriticalSeqNo())
601
{
602
// Park this request until `criticalSeqNo` arrives and is processed
603
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
604
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d out-of-sequence msg=%u detected for clientUID=%llu criticalSeqNo=%u > lastCriticalSeqNo=%u. Parking this thread (entry=%p)",
605
getCompThreadId(), seqNo, (unsigned long long)clientId, criticalSeqNo, clientSession->getLastProcessedCriticalSeqNo(), &entry);
606
607
Trc_JITServerOutOfSequenceMsg1(compThread, getCompThreadId(), clientSession, (unsigned long long)clientId, &entry, seqNo,
608
clientSession->getLastProcessedCriticalSeqNo(), clientSession->getNumActiveThreads(), clientSession->getLastProcessedCriticalSeqNo());
609
610
waitForMyTurn(clientSession, entry);
611
}
612
613
TR_ASSERT_FATAL(criticalSeqNo <= clientSession->getLastProcessedCriticalSeqNo(),
614
"Critical requests must be processed in order: compThreadID=%d seqNo=%u criticalSeqNo=%u > lastProcessedCriticalSeqNo=%u clientUID=%llu",
615
getCompThreadId(), seqNo, criticalSeqNo, clientSession->getLastProcessedCriticalSeqNo(), (unsigned long long)clientId);
616
617
if (criticalSeqNo < clientSession->getLastProcessedCriticalSeqNo())
618
{
619
// It's possible that a critical request is delayed so much that we clear the caches, start over,
620
// and then the missing request arrives. At this point we should ignore it, so we throw StreamOOO.
621
// Another possibility is when request 1 arrives before request 0 and creates the session, setting
622
// lastProcessedCriticalSeqNo to 1. As request 0 is "critical" by definition, we throw StreamOOO.
623
// Request 0 will be aborted (retried at te client) while request 1 will ask about entire CHTable
624
// because CHTable is empty at the server
625
if (isCriticalRequest)
626
{
627
if (TR::Options::isAnyVerboseOptionSet(TR_VerboseCompFailure, TR_VerboseJITServer, TR_VerbosePerformance))
628
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,
629
"compThreadID=%d discarding older msg for clientUID=%llu seqNo=%u criticalSeqNo=%u < lastProcessedCriticalSeqNo=%u",
630
getCompThreadId(), (unsigned long long)clientId, seqNo, criticalSeqNo, clientSession->getLastProcessedCriticalSeqNo());
631
632
Trc_JITServerDiscardMessage(compThread, getCompThreadId(), clientSession,
633
(unsigned long long)clientId, seqNo, criticalSeqNo, clientSession->getNumActiveThreads());
634
635
clientSession->getSequencingMonitor()->exit();
636
throw JITServer::StreamOOO();
637
}
638
}
639
640
// Increment the number of active threads before issuing the read for ramClass
641
clientSession->incNumActiveThreads();
642
hasIncNumActiveThreads = true;
643
644
// If class redefinition using HCR extensions occurred, must clear all the caches
645
bool mustClearCaches = std::find(unloadedClasses.begin(), unloadedClasses.end(), ClientSessionData::mustClearCachesFlag) != unloadedClasses.end();
646
if (mustClearCaches)
647
{
648
if (TR::Options::isAnyVerboseOptionSet(TR_VerboseCompFailure, TR_VerboseJITServer, TR_VerbosePerformance))
649
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,
650
"compThreadID=%d clearing all caches for clientUID=%llu due to class redefinition using HCR extensions",
651
getCompThreadId(), (unsigned long long) clientId);
652
Trc_JITServerClearCaches(compThread, getCompThreadId(), clientSession, (unsigned long long) clientId);
653
654
clientSession->clearCachesLocked(_vm);
655
}
656
657
// We can release the sequencing monitor now because no critical request with a
658
// larger sequence number can pass until I increment lastProcessedCriticalSeqNo
659
clientSession->getSequencingMonitor()->exit();
660
661
// At this point I know that all preceeding requests have been processed
662
// and only one thread with critical information can ever be present in this section
663
if (!clientSession->cachesAreCleared())
664
{
665
// Free data for all classes that were unloaded for this sequence number
666
// Redefined classes are marked as unloaded, since they need to be cleared
667
// from the ROM class cache.
668
if (!unloadedClasses.empty())
669
{
670
clientSession->processUnloadedClasses(unloadedClasses, true); // this locks getROMMapMonitor()
671
}
672
673
if (!illegalModificationList.empty())
674
{
675
clientSession->processIllegalFinalFieldModificationList(illegalModificationList); // this locks getROMMapMonitor()
676
}
677
678
// Process the CHTable updates in order
679
// Note that applying the updates will acquire the CHTable monitor and VMAccess
680
if ((!chtableUnloads.empty() || !chtableMods.empty())
681
&& !serverDetails->isJitDumpMethod())
682
{
683
auto chTable = (JITServerPersistentCHTable*)clientSession->getCHTable(); // Will create CHTable if it doesn't exist
684
TR_ASSERT_FATAL(chTable->isInitialized(), "CHTable must have been initialized for clientUID=%llu", (unsigned long long)clientId);
685
chTable->doUpdate(_vm, chtableUnloads, chtableMods);
686
}
687
}
688
else // Internal caches are empty
689
{
690
OMR::CriticalSection cs(clientSession->getCacheInitMonitor());
691
if (clientSession->cachesAreCleared())
692
{
693
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
694
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d will ask for address ranges of unloaded classes and CHTable for clientUID %llu",
695
getCompThreadId(), (unsigned long long)clientId);
696
697
stream->write(JITServer::MessageType::getUnloadedClassRangesAndCHTable, compInfo->getPersistentInfo()->getServerUID());
698
auto response = stream->read<std::vector<TR_AddressRange>, int32_t, std::string>();
699
// TODO: we could send JVM info that is global and does not change together with CHTable
700
auto &unloadedClassRanges = std::get<0>(response);
701
auto maxRanges = std::get<1>(response);
702
std::string &serializedCHTable = std::get<2>(response);
703
704
clientSession->initializeUnloadedClassAddrRanges(unloadedClassRanges, maxRanges);
705
if (!unloadedClasses.empty())
706
{
707
// This function updates multiple caches based on the newly unloaded classes list.
708
// Pass `false` here to indicate that we want the unloaded class ranges table cache excluded,
709
// since we just retrieved the entire table and it should therefore already be up to date.
710
clientSession->processUnloadedClasses(unloadedClasses, false);
711
}
712
auto chTable = static_cast<JITServerPersistentCHTable *>(clientSession->getCHTable());
713
// Need CHTable mutex
714
TR_ASSERT_FATAL(!chTable->isInitialized(), "CHTable must be empty for clientUID=%llu", (unsigned long long)clientId);
715
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
716
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d will initialize CHTable for clientUID %llu size=%zu",
717
getCompThreadId(), (unsigned long long)clientId, serializedCHTable.size());
718
chTable->initializeCHTable(_vm, serializedCHTable);
719
clientSession->setCachesAreCleared(false);
720
}
721
}
722
723
// Critical requests must update lastProcessedCriticalSeqNo and notify any waiting threads.
724
// Dependent threads will pass through once we've released the sequencing monitor.
725
if (isCriticalRequest)
726
{
727
clientSession->getSequencingMonitor()->enter();
728
TR_ASSERT_FATAL(criticalSeqNo <= clientSession->getLastProcessedCriticalSeqNo(),
729
"compThreadID=%d clientSessionData=%p clientUID=%llu seqNo=%u, criticalSeqNo=%u != lastProcessedCriticalSeqNo=%u, numActiveThreads=%d",
730
getCompThreadId(), clientSession, (unsigned long long)clientId, seqNo, criticalSeqNo,
731
clientSession->getLastProcessedCriticalSeqNo(), clientSession->getNumActiveThreads());
732
733
clientSession->setLastProcessedCriticalSeqNo(seqNo);
734
hasUpdatedSeqNo = true;
735
Trc_JITServerUpdateSeqNo(getCompilationThread(), getCompThreadId(), clientSession,
736
(unsigned long long)clientSession->getClientUID(),
737
getSeqNo(), criticalSeqNo, clientSession->getNumActiveThreads(),
738
clientSession->getLastProcessedCriticalSeqNo(), seqNo);
739
740
// Notify waiting threads. I need to keep notifying until the first request that
741
// is blocked because the request it depends on hasn't been processed yet.
742
notifyAndDetachWaitingRequests(clientSession);
743
744
// Finally, release the sequencing monitor so that other threads
745
// can process their lists of unloaded classes
746
clientSession->getSequencingMonitor()->exit();
747
}
748
749
// Copy the option string
750
copyClientOptions(clientOptStr, clientSession->persistentMemory());
751
752
// _recompilationMethodInfo will be passed to J9::Recompilation::_methodInfo,
753
// which will get freed in populateBodyInfo() when creating the
754
// method meta data during the compilation. Since _recompilationMethodInfo is already
755
// freed in populateBodyInfo(), no need to free it at the end of the compilation in this method.
756
if (recompInfoStr.size() > 0)
757
{
758
_recompilationMethodInfo = new (clientSession->persistentMemory()) TR_PersistentMethodInfo();
759
memcpy(_recompilationMethodInfo, recompInfoStr.data(), sizeof(TR_PersistentMethodInfo));
760
J9::Recompilation::resetPersistentProfileInfo(_recompilationMethodInfo);
761
}
762
// Get the ROMClass for the method to be compiled if it is already cached
763
// Or read it from the compilation request and cache it otherwise
764
J9ROMClass *romClass = NULL;
765
if (!(romClass = JITServerHelpers::getRemoteROMClassIfCached(clientSession, clazz)))
766
{
767
// Class for current request is not yet cached.
768
// If the client sent us the desired information in the compilation request, use that.
769
if(!(std::get<0>(classInfoTuple).empty()))
770
{
771
romClass = JITServerHelpers::romClassFromString(std::get<0>(classInfoTuple), clientSession->persistentMemory());
772
}
773
else
774
{
775
// The client did not embed info about desired class in the compilation request.
776
// This could happen if the client determined that it sent required information in
777
// a previous request, info which the server is expected to cache. However, this
778
// could be a new JITServer instance.
779
// Send a message to the client to retrieve desired info.
780
romClass = JITServerHelpers::getRemoteROMClass(clazz, stream, clientSession->persistentMemory(), classInfoTuple);
781
}
782
romClass = JITServerHelpers::cacheRemoteROMClassOrFreeIt(clientSession, clazz, romClass, classInfoTuple);
783
TR_ASSERT_FATAL(romClass, "ROM class of J9Class=%p must be cached at this point", clazz);
784
}
785
786
// Optimization plan needs to use the global allocator,
787
// because there is a global pool of plans
788
{
789
JITServer::GlobalAllocationRegion globalRegion(this);
790
// Build my entry
791
if (!(optPlan = TR_OptimizationPlan::alloc(clientOptPlan.getOptLevel())))
792
throw std::bad_alloc();
793
optPlan->clone(&clientOptPlan);
794
if (optPlan->isLogCompilation())
795
optPlan->setLogCompilation(clientOptPlan.getLogCompilation());
796
}
797
798
// All entries have the same priority for now. In the future we may want to give higher priority to sync requests
799
// Also, oldStartPC is always NULL for JITServer
800
entry._freeTag = ENTRY_IN_POOL_FREE; // Pretend we just got it from the pool because we need to initialize it again
801
entry.initialize(*serverDetails, NULL, CP_SYNC_NORMAL, optPlan);
802
entry._jitStateWhenQueued = compInfo->getPersistentInfo()->getJitState();
803
entry._stream = stream; // Add the stream to the entry
804
entry._entryTime = compInfo->getPersistentInfo()->getElapsedTime(); // Cheaper version
805
entry._methodIsInSharedCache = false; // No SCC for now in JITServer
806
entry._compInfoPT = this; // Need to know which comp thread is handling this request
807
entry._async = true; // All of requests at the server are async
808
// Weight is irrelevant for JITServer.
809
// If we want something then we need to increaseQueueWeightBy(weight) while holding compilation monitor
810
entry._weight = 0;
811
entry._useAotCompilation = useAotCompilation;
812
813
auto aotCache = clientSession->getOrCreateAOTCache(stream);
814
_aotCacheStore = classChain && aotCache;
815
aotCacheLoad = aotCacheLoad && classChain && aotCache;
816
if (aotCache && !aotCacheLoad)
817
aotCache->incNumCacheBypasses();
818
819
if (_aotCacheStore || aotCacheLoad)
820
{
821
// Get defining class chain record to use as a part of the key to lookup or store the method in AOT cache
822
JITServerHelpers::cacheRemoteROMClassBatch(clientSession, uncachedRAMClasses, uncachedClassInfos);
823
_definingClassChainRecord = clientSession->getClassChainRecord(clazz, classChain, ramClassChain, stream);
824
if (!_definingClassChainRecord)
825
{
826
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
827
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,
828
"clientUID %llu failed to get defining class chain record for %p; "
829
"method %p won't be loaded from or stored in AOT cache",
830
(unsigned long long)clientId, clazz, ramMethod
831
);
832
if (aotCacheLoad)
833
aotCache->incNumCacheMisses();
834
_aotCacheStore = false;
835
aotCacheLoad = false;
836
}
837
}
838
839
if (aotCacheLoad)
840
aotCacheHit = serveCachedAOTMethod(entry, ramMethod, clazz, &clientOptPlan, clientSession, scratchSegmentProvider);
841
}
842
catch (const JITServer::StreamFailure &e)
843
{
844
// This could happen because the client disconnected on purpose, in which case there is no harm done,
845
// or if there was a network problem. In the latter case, if the request was critical, the server
846
// will observe a missing seqNo and after a timeout, it will clear the caches and start over
847
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
848
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d stream failed while reading the compilation request: %s",
849
getCompThreadId(), e.what());
850
851
Trc_JITServerStreamFailure(compThread, getCompThreadId(), __FUNCTION__, "", "", e.what());
852
853
abortCompilation = true;
854
deleteStream = true;
855
}
856
catch (const JITServer::StreamVersionIncompatible &e)
857
{
858
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
859
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d stream version incompatible: %s", getCompThreadId(), e.what());
860
861
Trc_JITServerStreamVersionIncompatible(compThread, getCompThreadId(), __FUNCTION__, "", "", e.what());
862
863
stream->writeError(compilationStreamVersionIncompatible);
864
abortCompilation = true;
865
deleteStream = true;
866
}
867
catch (const JITServer::StreamMessageTypeMismatch &e)
868
{
869
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
870
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d stream message type mismatch: %s", getCompThreadId(), e.what());
871
872
Trc_JITServerStreamMessageTypeMismatch(compThread, getCompThreadId(), __FUNCTION__, "", "", e.what());
873
874
stream->writeError(compilationStreamMessageTypeMismatch);
875
abortCompilation = true;
876
deleteStream = true;
877
}
878
catch (const JITServer::StreamConnectionTerminate &e)
879
{
880
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
881
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d stream connection terminated by JITClient on stream %p while reading the compilation request: %s",
882
getCompThreadId(), stream, e.what());
883
884
Trc_JITServerStreamConnectionTerminate(compThread, getCompThreadId(), __FUNCTION__, stream, e.what());
885
886
abortCompilation = true;
887
deleteStream = true;
888
}
889
catch (const JITServer::StreamClientSessionTerminate &e)
890
{
891
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
892
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d stream client session terminated by JITClient: %s", getCompThreadId(), e.what());
893
894
Trc_JITServerStreamClientSessionTerminate(compThread, getCompThreadId(), __FUNCTION__, e.what());
895
896
abortCompilation = true;
897
deleteStream = true;
898
899
deleteClientSessionData(e.getClientId(), compInfo, compThread);
900
}
901
catch (const JITServer::StreamInterrupted &e)
902
{
903
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
904
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d stream interrupted by JITClient while reading the compilation request: %s",
905
getCompThreadId(), e.what());
906
907
Trc_JITServerStreamInterrupted(compThread, getCompThreadId(), __FUNCTION__, "", "", e.what());
908
909
abortCompilation = true;
910
// If the client aborted this compilation, it could have happened while asking for entire
911
// CHTable and unloaded class address ranges and at that point the seqNo was not updated.
912
// In such case, we must update seqNo now to allow for blocking threads to pass through.
913
// Since the caches are already cleared there is no harm in discarding this message.
914
if (isCriticalRequest && !hasUpdatedSeqNo)
915
{
916
clientSession->getSequencingMonitor()->enter();
917
if (seqNo > clientSession->getLastProcessedCriticalSeqNo())
918
{
919
Trc_JITServerUpdateSeqNo(getCompilationThread(), getCompThreadId(), clientSession,
920
(unsigned long long)clientSession->getClientUID(),
921
seqNo, getExpectedSeqNo(), clientSession->getNumActiveThreads(),
922
clientSession->getLastProcessedCriticalSeqNo(), seqNo);
923
924
clientSession->setLastProcessedCriticalSeqNo(seqNo);
925
notifyAndDetachWaitingRequests(clientSession);
926
}
927
clientSession->getSequencingMonitor()->exit();
928
}
929
}
930
catch (const JITServer::StreamOOO &e)
931
{
932
// Error message was printed when the exception was thrown
933
stream->writeError(compilationStreamLostMessage); // the client should recognize this code and retry
934
abortCompilation = true;
935
}
936
catch (const std::bad_alloc &e)
937
{
938
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
939
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "Server out of memory in processEntry: %s", e.what());
940
stream->writeError(compilationLowPhysicalMemory, (uint64_t) computeServerMemoryState(getCompilationInfo()));
941
abortCompilation = true;
942
}
943
944
// Acquire VM access
945
//
946
acquireVMAccessNoSuspend(compThread);
947
948
if (abortCompilation)
949
{
950
if (clientOptions)
951
{
952
deleteClientOptions(getClientData()->persistentMemory());
953
}
954
955
if (_recompilationMethodInfo)
956
{
957
getClientData()->persistentMemory()->freePersistentMemory(_recompilationMethodInfo);
958
_recompilationMethodInfo = NULL;
959
}
960
961
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
962
{
963
if (getClientData())
964
{
965
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d did an early abort for clientUID=%llu seqNo=%u",
966
getCompThreadId(), getClientData()->getClientUID(), getSeqNo());
967
Trc_JITServerEarlyAbortClientData(compThread, getCompThreadId(), (unsigned long long)getClientData()->getClientUID(), getSeqNo());
968
}
969
else
970
{
971
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "compThreadID=%d did an early abort",
972
getCompThreadId());
973
Trc_JITServerEarlyAbort(compThread, getCompThreadId());
974
}
975
}
976
977
compInfo->acquireCompMonitor(compThread);
978
releaseVMAccess(compThread);
979
compInfo->decreaseQueueWeightBy(entry._weight);
980
981
// Put the request back into the pool
982
setMethodBeingCompiled(NULL); // Must have the compQmonitor
983
984
exitPerClientAllocationRegion();
985
986
if (optPlan)
987
{
988
TR_OptimizationPlan::freeOptimizationPlan(optPlan);
989
}
990
991
if (!compInfo->getPersistentInfo()->getDisableFurtherCompilation()
992
&& !deleteStream
993
&& !enableJITServerPerCompConn)
994
{
995
compInfo->requeueOutOfProcessEntry(&entry);
996
}
997
else
998
{
999
// Delete server stream if per compilation connections are enabled
1000
// or if the server disabled compilations due to a crash
1001
stream->~ServerStream();
1002
TR::Compiler->persistentGlobalAllocator().deallocate(stream);
1003
entry._stream = NULL;
1004
}
1005
1006
// Reset the pointer to the cached client session data
1007
if (getClientData())
1008
{
1009
if (hasIncNumActiveThreads)
1010
{
1011
getClientData()->getSequencingMonitor()->enter();
1012
getClientData()->decNumActiveThreads();
1013
getClientData()->getSequencingMonitor()->exit();
1014
}
1015
1016
getClientData()->decInUse(); // We have the compilation monitor so it's safe to access the inUse counter
1017
if (getClientData()->getInUse() == 0)
1018
{
1019
bool result = compInfo->getClientSessionHT()->deleteClientSession(clientId, false);
1020
if (result)
1021
{
1022
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
1023
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,"client (%llu) deleted", (unsigned long long)clientId);
1024
}
1025
}
1026
setClientData(NULL);
1027
}
1028
return;
1029
}
1030
1031
// Do the hack for newInstance thunks
1032
// Also make the method appear as interpreted, otherwise we might want to access recompilation info
1033
// JITServer TODO: is this ever executed for JITServer?
1034
//if (entry.getMethodDetails().isNewInstanceThunk())
1035
// {
1036
// J9::NewInstanceThunkDetails &newInstanceDetails = static_cast<J9::NewInstanceThunkDetails &>(entry.getMethodDetails());
1037
// J9Class *classForNewInstance = newInstanceDetails.classNeedingThunk();
1038
// TR::CompilationInfo::setJ9MethodExtra(ramMethod, (uintptr_t)classForNewInstance | J9_STARTPC_NOT_TRANSLATED);
1039
// }
1040
1041
#ifdef STATS
1042
statQueueSize.update(compInfo->getMethodQueueSize());
1043
#endif
1044
void *startPC = NULL;
1045
// The following block of code will return with compilation monitor in hand
1046
if (aotCacheHit)
1047
{
1048
compInfo->acquireCompMonitor(compThread);
1049
stream->setClientData(NULL);
1050
}
1051
else
1052
{
1053
stream->setClientData(clientSession);
1054
getClientData()->readAcquireClassUnloadRWMutex(this);
1055
1056
startPC = compile(compThread, &entry, scratchSegmentProvider);
1057
1058
getClientData()->readReleaseClassUnloadRWMutex(this);
1059
stream->setClientData(NULL);
1060
}
1061
1062
deleteClientOptions(getClientData()->persistentMemory());
1063
1064
// Notify any threads waiting on this entry's monitor
1065
// The only thread that should be holding a monitor should be the JitDump thread
1066
entry.getMonitor()->notifyAll();
1067
// Release the queue slot monitor because we don't need it anymore
1068
// This will allow us to acquire the sequencing monitor later
1069
entry.releaseSlotMonitor(compThread);
1070
1071
entry._newStartPC = startPC;
1072
// Update statistics regarding the compilation status (including compilationOK)
1073
compInfo->updateCompilationErrorStats((TR_CompilationErrorCode)entry._compErrCode);
1074
1075
// Save the pointer to the plan before recycling the entry
1076
// Decrease the queue weight
1077
compInfo->decreaseQueueWeightBy(entry._weight);
1078
1079
exitPerClientAllocationRegion();
1080
1081
TR_OptimizationPlan::freeOptimizationPlan(optPlan); // we no longer need the optimization plan
1082
1083
// Put the request back into the pool
1084
setMethodBeingCompiled(NULL);
1085
1086
if (!compInfo->getPersistentInfo()->getDisableFurtherCompilation()
1087
&& !enableJITServerPerCompConn
1088
&& entry._compErrCode != compilationStreamFailure)
1089
{
1090
compInfo->requeueOutOfProcessEntry(&entry);
1091
}
1092
else
1093
{
1094
TR_ASSERT(entry._stream, "stream should still exist after compilation even if it encounters a streamFailure.");
1095
// Delete server stream if per compilation connections are enabled,
1096
// if the server disabled compilations due to a crash,
1097
// or if the stream failed
1098
stream->~ServerStream();
1099
TR::Compiler->persistentGlobalAllocator().deallocate(stream);
1100
entry._stream = NULL;
1101
}
1102
1103
compInfo->printQueue();
1104
1105
// Decrement number of active threads before _inUse, but we
1106
// need to acquire the sequencing monitor when accessing numActiveThreads
1107
getClientData()->getSequencingMonitor()->enter();
1108
getClientData()->decNumActiveThreads();
1109
getClientData()->getSequencingMonitor()->exit();
1110
getClientData()->decInUse(); // We have the compMonitor so it's safe to access the inUse counter
1111
if (getClientData()->getInUse() == 0)
1112
{
1113
bool deleted = compInfo->getClientSessionHT()->deleteClientSession(clientId, false);
1114
if (deleted && TR::Options::getVerboseOption(TR_VerboseJITServer))
1115
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,"client (%llu) deleted", (unsigned long long)clientId);
1116
}
1117
1118
setClientData(NULL); // Reset the pointer to the cached client session data
1119
1120
// At this point we should always have VMAccess
1121
// We should always have the compilation monitor
1122
// we should never have classUnloadMonitor
1123
1124
// Release VM access
1125
//
1126
compInfo->debugPrint(compThread, "\tcompilation thread releasing VM access\n");
1127
releaseVMAccess(compThread);
1128
compInfo->debugPrint(compThread, "-VMacc\n");
1129
1130
// We can suspend this thread if too many are active
1131
if (
1132
!isDiagnosticThread() // Must not be reserved for log
1133
&& compInfo->getNumCompThreadsActive() > 1 // we should have at least one active besides this one
1134
&& compilationThreadIsActive() // We haven't already been signaled to suspend or terminate
1135
&& (compInfo->getRampDownMCT() || compInfo->getSuspendThreadDueToLowPhysicalMemory())
1136
)
1137
{
1138
// Suspend this thread
1139
setCompilationThreadState(COMPTHREAD_SIGNAL_SUSPEND);
1140
compInfo->decNumCompThreadsActive();
1141
if (TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerboseCompilationThreads))
1142
{
1143
TR_VerboseLog::writeLineLocked(TR_Vlog_INFO, "t=%6u Suspend compThread %d Qweight=%d active=%d %s %s",
1144
(uint32_t)compInfo->getPersistentInfo()->getElapsedTime(),
1145
getCompThreadId(),
1146
compInfo->getQueueWeight(),
1147
compInfo->getNumCompThreadsActive(),
1148
compInfo->getRampDownMCT() ? "RampDownMCT" : "",
1149
compInfo->getSuspendThreadDueToLowPhysicalMemory() ? "LowPhysicalMem" : "");
1150
}
1151
// If the other remaining active thread(s) are sleeping (maybe because
1152
// we wanted to avoid two concurrent hot requests) we need to wake them
1153
// now as a preventive measure. Worst case scenario they will go back to sleep
1154
if (compInfo->getNumCompThreadsJobless() > 0)
1155
{
1156
compInfo->getCompilationMonitor()->notifyAll();
1157
if (TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerboseCompilationThreads))
1158
{
1159
TR_VerboseLog::writeLineLocked(TR_Vlog_INFO, "t=%6u compThread %d notifying other sleeping comp threads. Jobless=%d",
1160
(uint32_t)compInfo->getPersistentInfo()->getElapsedTime(),
1161
getCompThreadId(),
1162
compInfo->getNumCompThreadsJobless());
1163
}
1164
}
1165
}
1166
else // We will not suspend this thread
1167
{
1168
// If the low memory flag was set but there was no additional comp thread
1169
// to suspend, we must clear the flag now
1170
if (compInfo->getSuspendThreadDueToLowPhysicalMemory() &&
1171
compInfo->getNumCompThreadsActive() < 2)
1172
compInfo->setSuspendThreadDueToLowPhysicalMemory(false);
1173
}
1174
}
1175
1176
/**
1177
* @brief Method executed by JITServer to store bytecode iprofiler info to heap memory (instead of to persistent memory)
1178
*
1179
* @param method J9Method in question
1180
* @param byteCodeIndex bytecode in question
1181
* @param entry iprofile data to be stored
1182
* @return always return true at the moment
1183
*/
1184
bool
1185
TR::CompilationInfoPerThreadRemote::cacheIProfilerInfo(TR_OpaqueMethodBlock *method, uint32_t byteCodeIndex, TR_IPBytecodeHashTableEntry *entry)
1186
{
1187
IPTableHeapEntry *entryMap = NULL;
1188
if(!getCachedValueFromPerCompilationMap(_methodIPDataPerComp, (J9Method *) method, entryMap))
1189
{
1190
// Either first time cacheIProfilerInfo called during current compilation,
1191
// so _methodIPDataPerComp is NULL, or caching a new method, entryMap not found
1192
if (entry)
1193
{
1194
cacheToPerCompilationMap(entryMap, byteCodeIndex, entry);
1195
}
1196
else
1197
{
1198
// If entry is NULL, create entryMap, but do not cache anything
1199
initializePerCompilationCache(entryMap);
1200
}
1201
cacheToPerCompilationMap(_methodIPDataPerComp, (J9Method *) method, entryMap);
1202
}
1203
else if (entry)
1204
{
1205
// Adding an entry for already seen method (i.e. entryMap exists)
1206
cacheToPerCompilationMap(entryMap, byteCodeIndex, entry);
1207
}
1208
return true;
1209
}
1210
1211
/**
1212
* @brief Method executed by JITServer to retrieve bytecode iprofiler info from the heap memory
1213
*
1214
* @param method J9Method in question
1215
* @param byteCodeIndex bytecode in question
1216
* @param methodInfoPresent indicates to the caller whether the data is present
1217
* @return IPTableHeapEntry bytecode iprofile data
1218
*/
1219
TR_IPBytecodeHashTableEntry*
1220
TR::CompilationInfoPerThreadRemote::getCachedIProfilerInfo(TR_OpaqueMethodBlock *method, uint32_t byteCodeIndex, bool *methodInfoPresent)
1221
{
1222
*methodInfoPresent = false;
1223
1224
IPTableHeapEntry *entryMap = NULL;
1225
TR_IPBytecodeHashTableEntry *ipEntry = NULL;
1226
1227
getCachedValueFromPerCompilationMap(_methodIPDataPerComp, (J9Method *) method, entryMap);
1228
// methodInfoPresent=true means that we cached info for this method (i.e. entryMap is not NULL),
1229
// but entry for this bytecode might not exist, which means it's NULL
1230
if (entryMap)
1231
{
1232
*methodInfoPresent = true;
1233
getCachedValueFromPerCompilationMap(entryMap, byteCodeIndex, ipEntry);
1234
}
1235
return ipEntry;
1236
}
1237
1238
/**
1239
* @brief Method executed by JITServer to cache a resolved method to the resolved method cache
1240
*
1241
* @param key Identifier used to identify a resolved method in resolved methods cache
1242
* @param method The resolved method of interest
1243
* @param vTableSlot The vTableSlot for the resolved method of interest
1244
* @param methodInfo Additional method info about the resolved method of interest
1245
* @return returns void
1246
*/
1247
void
1248
TR::CompilationInfoPerThreadRemote::cacheResolvedMethod(TR_ResolvedMethodKey key, TR_OpaqueMethodBlock *method,
1249
uint32_t vTableSlot, const TR_ResolvedJ9JITServerMethodInfo &methodInfo, int32_t ttlForUnresolved)
1250
{
1251
static bool useCaching = !feGetEnv("TR_DisableResolvedMethodsCaching");
1252
if (!useCaching)
1253
return;
1254
// Create a new TR_ResolvedJ9JITServerMethodInfo using scratch memory
1255
1256
TR_ASSERT_FATAL(getCompilation(), "Must be in compilation when calling cacheResolvedMethod\n");
1257
TR_Memory *trMemory = getCompilation()->trMemory();
1258
1259
TR_PersistentJittedBodyInfo *bodyInfo = NULL;
1260
if (!std::get<1>(methodInfo).empty())
1261
{
1262
bodyInfo = (TR_PersistentJittedBodyInfo*) trMemory->allocateHeapMemory(sizeof(TR_PersistentJittedBodyInfo), TR_MemoryBase::Recompilation);
1263
memcpy(bodyInfo, std::get<1>(methodInfo).data(), sizeof(TR_PersistentJittedBodyInfo));
1264
}
1265
TR_PersistentMethodInfo *pMethodInfo = NULL;
1266
if (!std::get<2>(methodInfo).empty())
1267
{
1268
pMethodInfo = (TR_PersistentMethodInfo*) trMemory->allocateHeapMemory(sizeof(TR_PersistentMethodInfo), TR_MemoryBase::Recompilation);
1269
memcpy(pMethodInfo, std::get<2>(methodInfo).data(), sizeof(TR_PersistentMethodInfo));
1270
}
1271
TR_ContiguousIPMethodHashTableEntry *entry = NULL;
1272
if (!std::get<3>(methodInfo).empty())
1273
{
1274
entry = (TR_ContiguousIPMethodHashTableEntry*) trMemory->allocateHeapMemory(sizeof(TR_ContiguousIPMethodHashTableEntry), TR_MemoryBase::Recompilation);
1275
memcpy(entry, std::get<3>(methodInfo).data(), sizeof(TR_ContiguousIPMethodHashTableEntry));
1276
}
1277
1278
TR_ResolvedMethodCacheEntry cacheEntry;
1279
cacheEntry.method = method;
1280
cacheEntry.vTableSlot = vTableSlot;
1281
cacheEntry.methodInfoStruct = std::get<0>(methodInfo);
1282
cacheEntry.persistentBodyInfo = bodyInfo;
1283
cacheEntry.persistentMethodInfo = pMethodInfo;
1284
cacheEntry.IPMethodInfo = entry;
1285
1286
// time-to-live for cached unresolved methods.
1287
// Irrelevant for resolved methods.
1288
cacheEntry.ttlForUnresolved = ttlForUnresolved;
1289
1290
cacheToPerCompilationMap(_resolvedMethodInfoMap, key, cacheEntry);
1291
}
1292
1293
/**
1294
* @brief Method executed by JITServer to retrieve a resolved method from the resolved method cache
1295
*
1296
* @param key Identifier used to identify a resolved method in resolved methods cache
1297
* @param owningMethod Owning method of the resolved method of interest
1298
* @param resolvedMethod The resolved method of interest, set by this API
1299
* @param unresolvedInCP The unresolvedInCP boolean value of interest, set by this API
1300
* @return returns true if method is cached, sets resolvedMethod and unresolvedInCP to cached values, false otherwise.
1301
*/
1302
bool
1303
TR::CompilationInfoPerThreadRemote::getCachedResolvedMethod(TR_ResolvedMethodKey key, TR_ResolvedJ9JITServerMethod *owningMethod,
1304
TR_ResolvedMethod **resolvedMethod, bool *unresolvedInCP)
1305
{
1306
TR_ResolvedMethodCacheEntry methodCacheEntry = {0};
1307
1308
*resolvedMethod = NULL;
1309
1310
if (unresolvedInCP)
1311
*unresolvedInCP = true;
1312
1313
if (getCachedValueFromPerCompilationMap(_resolvedMethodInfoMap, key, methodCacheEntry))
1314
{
1315
auto comp = getCompilation();
1316
TR_OpaqueMethodBlock *method = methodCacheEntry.method;
1317
1318
// if remoteMirror == NULL means we have cached an unresolved method;
1319
// purge the cached entry if time-to-live has expired.
1320
if (!methodCacheEntry.methodInfoStruct.remoteMirror)
1321
{
1322
// decrement time-to-live of this unresolved entry
1323
methodCacheEntry.ttlForUnresolved--;
1324
1325
if (methodCacheEntry.ttlForUnresolved <= 0)
1326
_resolvedMethodInfoMap->erase(key);
1327
return true;
1328
}
1329
1330
uint32_t vTableSlot = methodCacheEntry.vTableSlot;
1331
auto methodInfoStruct = methodCacheEntry.methodInfoStruct;
1332
TR_ResolvedJ9JITServerMethodInfo methodInfo = make_tuple(methodInfoStruct,
1333
methodCacheEntry.persistentBodyInfo ? std::string((const char*)methodCacheEntry.persistentBodyInfo, sizeof(TR_PersistentJittedBodyInfo)) : std::string(),
1334
methodCacheEntry.persistentMethodInfo ? std::string((const char*)methodCacheEntry.persistentMethodInfo, sizeof(TR_PersistentMethodInfo)) : std::string(),
1335
methodCacheEntry.IPMethodInfo ? std::string((const char*)methodCacheEntry.IPMethodInfo, sizeof(TR_ContiguousIPMethodHashTableEntry)) : std::string());
1336
// Re-add validation record
1337
if (comp->compileRelocatableCode() && comp->getOption(TR_UseSymbolValidationManager) && !comp->getSymbolValidationManager()->inHeuristicRegion())
1338
{
1339
if(!owningMethod->addValidationRecordForCachedResolvedMethod(key, method))
1340
return true; // Could not add a validation record
1341
}
1342
1343
// Create resolved method from cached method info
1344
if (key.type != TR_ResolvedMethodType::VirtualFromOffset)
1345
{
1346
*resolvedMethod = owningMethod->createResolvedMethodFromJ9Method(
1347
comp,
1348
key.cpIndex,
1349
vTableSlot,
1350
(J9Method *) method,
1351
unresolvedInCP,
1352
NULL,
1353
methodInfo);
1354
}
1355
else
1356
{
1357
if (_vm->isAOT_DEPRECATED_DO_NOT_USE())
1358
*resolvedMethod = method ? new (comp->trHeapMemory()) TR_ResolvedRelocatableJ9JITServerMethod(method, _vm, comp->trMemory(), methodInfo, owningMethod) : 0;
1359
else
1360
*resolvedMethod = method ? new (comp->trHeapMemory()) TR_ResolvedJ9JITServerMethod(method, _vm, comp->trMemory(), methodInfo, owningMethod) : 0;
1361
}
1362
1363
if (*resolvedMethod)
1364
{
1365
if (unresolvedInCP)
1366
*unresolvedInCP = false;
1367
return true;
1368
}
1369
else
1370
{
1371
TR_ASSERT(false, "Should not have cached unresolved method globally");
1372
}
1373
}
1374
return false;
1375
}
1376
1377
/**
1378
* @brief Method executed by JITServer to compose a TR_ResolvedMethodKey used for the resolved method cache
1379
*
1380
* @param type Resolved method type: VirtualFromCP, VirtualFromOffset, Interface, Static, Special, ImproperInterface, NoType
1381
* @param ramClass ramClass of resolved method of interest
1382
* @param cpIndex constant pool index
1383
* @param classObject default to NULL, only set for resolved interface method
1384
* @return key used to identify a resolved method in the resolved method cache
1385
*/
1386
TR_ResolvedMethodKey
1387
TR::CompilationInfoPerThreadRemote::getResolvedMethodKey(TR_ResolvedMethodType type, TR_OpaqueClassBlock *ramClass, int32_t cpIndex, TR_OpaqueClassBlock *classObject)
1388
{
1389
TR_ResolvedMethodKey key = {type, ramClass, cpIndex, classObject};
1390
return key;
1391
}
1392
1393
/**
1394
* @brief Method executed by JITServer to save the mirrors of resolved method of interest to a list
1395
*
1396
* @param resolvedMethod The mirror of the resolved method of interest (existing at JITClient)
1397
* @return void
1398
*/
1399
void
1400
TR::CompilationInfoPerThreadRemote::cacheResolvedMirrorMethodsPersistIPInfo(TR_ResolvedJ9Method *resolvedMethod)
1401
{
1402
if (!_resolvedMirrorMethodsPersistIPInfo)
1403
{
1404
initializePerCompilationCache(_resolvedMirrorMethodsPersistIPInfo);
1405
if (!_resolvedMirrorMethodsPersistIPInfo)
1406
return;
1407
}
1408
1409
_resolvedMirrorMethodsPersistIPInfo->push_back(resolvedMethod);
1410
}
1411
1412
/**
1413
* @brief Method executed by JITServer to remember NULL answers for classOfStatic() queries
1414
*
1415
* @param ramClass The static class of interest as part of the key
1416
* @param cpIndex The constant pool index of interest as part of the key
1417
* @return void
1418
*/
1419
void
1420
TR::CompilationInfoPerThreadRemote::cacheNullClassOfStatic(TR_OpaqueClassBlock *ramClass, int32_t cpIndex)
1421
{
1422
TR_OpaqueClassBlock *nullClazz = NULL;
1423
cacheToPerCompilationMap(_classOfStaticMap, std::make_pair(ramClass, cpIndex), nullClazz);
1424
}
1425
1426
/**
1427
* @brief Method executed by JITServer to determine if a previous classOfStatic() query returned NULL
1428
*
1429
* @param ramClass The static class of interest
1430
* @param cpIndex The constant pool index of interest
1431
* @return returns true if the previous classOfStatic() query returned NULL and false otherwise
1432
*/
1433
bool
1434
TR::CompilationInfoPerThreadRemote::getCachedNullClassOfStatic(TR_OpaqueClassBlock *ramClass, int32_t cpIndex)
1435
{
1436
TR_OpaqueClassBlock *nullClazz;
1437
return getCachedValueFromPerCompilationMap(_classOfStaticMap, std::make_pair(ramClass, cpIndex), nullClazz);
1438
}
1439
1440
/**
1441
* @brief Method executed by JITServer to cache field or static attributes
1442
*
1443
* @param ramClass The ramClass of interest as part of the key
1444
* @param cpIndex The cpIndex of interest as part of the key
1445
* @param attrs The value we are going to cache
1446
* @param isStatic Whether the field is static
1447
* @return void
1448
*/
1449
void
1450
TR::CompilationInfoPerThreadRemote::cacheFieldOrStaticAttributes(TR_OpaqueClassBlock *ramClass, int32_t cpIndex, const TR_J9MethodFieldAttributes &attrs, bool isStatic)
1451
{
1452
if (isStatic)
1453
cacheToPerCompilationMap(_staticAttributesCache, std::make_pair(ramClass, cpIndex), attrs);
1454
else
1455
cacheToPerCompilationMap(_fieldAttributesCache, std::make_pair(ramClass, cpIndex), attrs);
1456
}
1457
1458
/**
1459
* @brief Method executed by JITServer to retrieve field or static attributes from the cache
1460
*
1461
* @param ramClass The ramClass of interest as part of the key
1462
* @param cpIndex The cpIndex of interest as part of the value
1463
* @param attrs The value to be set by the API
1464
* @param isStatic Whether the field is static
1465
* @return returns true if found in cache else false
1466
*/
1467
bool
1468
TR::CompilationInfoPerThreadRemote::getCachedFieldOrStaticAttributes(TR_OpaqueClassBlock *ramClass, int32_t cpIndex, TR_J9MethodFieldAttributes &attrs, bool isStatic)
1469
{
1470
if (isStatic)
1471
return getCachedValueFromPerCompilationMap(_staticAttributesCache, std::make_pair(ramClass, cpIndex), attrs);
1472
else
1473
return getCachedValueFromPerCompilationMap(_fieldAttributesCache, std::make_pair(ramClass, cpIndex), attrs);
1474
}
1475
1476
/**
1477
* @brief Method executed by JITServer to cache unresolved string
1478
*
1479
* @param ramClass The ramClass of interest as part of the key
1480
* @param cpIndex The cpIndex of interest as part of the key
1481
* @param stringAttrs The value we are going to cache
1482
* @return void
1483
*/
1484
void
1485
TR::CompilationInfoPerThreadRemote::cacheIsUnresolvedStr(TR_OpaqueClassBlock *ramClass, int32_t cpIndex, const TR_IsUnresolvedString &stringAttrs)
1486
{
1487
cacheToPerCompilationMap(_isUnresolvedStrCache, std::make_pair(ramClass, cpIndex), stringAttrs);
1488
}
1489
1490
/**
1491
* @brief Method executed by JITServer to retrieve unresolved string
1492
*
1493
* @param ramClass The ramClass of interest as part of the key
1494
* @param cpIndex The cpIndex of interest as part of the key
1495
* @param attrs The value to be set by the API
1496
* @return returns true if found in cache else false
1497
*/
1498
bool
1499
TR::CompilationInfoPerThreadRemote::getCachedIsUnresolvedStr(TR_OpaqueClassBlock *ramClass, int32_t cpIndex, TR_IsUnresolvedString &stringAttrs)
1500
{
1501
return getCachedValueFromPerCompilationMap(_isUnresolvedStrCache, std::make_pair(ramClass, cpIndex), stringAttrs);
1502
}
1503
1504
/**
1505
* @brief Method executed by JITServer to clear cache for per compilation
1506
*/
1507
void
1508
TR::CompilationInfoPerThreadRemote::clearPerCompilationCaches()
1509
{
1510
clearPerCompilationCache(_methodIPDataPerComp);
1511
clearPerCompilationCache(_resolvedMethodInfoMap);
1512
clearPerCompilationCache(_resolvedMirrorMethodsPersistIPInfo);
1513
clearPerCompilationCache(_classOfStaticMap);
1514
clearPerCompilationCache(_fieldAttributesCache);
1515
clearPerCompilationCache(_staticAttributesCache);
1516
clearPerCompilationCache(_isUnresolvedStrCache);
1517
}
1518
1519
/**
1520
* @brief Method executed by JITServer to delete client session data when client stream is terminated
1521
*/
1522
void
1523
TR::CompilationInfoPerThreadRemote::deleteClientSessionData(uint64_t clientId, TR::CompilationInfo* compInfo, J9VMThread* compThread)
1524
{
1525
// Need to acquire compilation monitor for both deleting the client data and the setting the thread state to COMPTHREAD_SIGNAL_SUSPEND.
1526
compInfo->acquireCompMonitor(compThread);
1527
bool result = compInfo->getClientSessionHT()->deleteClientSession(clientId, true);
1528
if (TR::Options::getVerboseOption(TR_VerboseJITServer) ||
1529
TR::Options::getVerboseOption(TR_VerboseJITServerConns))
1530
{
1531
uint32_t timestamp = (uint32_t) compInfo->getPersistentInfo()->getElapsedTime();
1532
if (!result)
1533
{
1534
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,"t=%6u Client (clientUID=%llu) disconnected. Client session not deleted", timestamp, (unsigned long long)clientId);
1535
}
1536
else
1537
{
1538
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer,"t=%6u Client (clientUID=%llu) disconnected. Client session deleted", timestamp, (unsigned long long)clientId);
1539
}
1540
}
1541
1542
compInfo->releaseCompMonitor(compThread);
1543
}
1544
1545
void
1546
TR::CompilationInfoPerThreadRemote::freeAllResources()
1547
{
1548
if (_recompilationMethodInfo)
1549
{
1550
TR_Memory::jitPersistentFree(_recompilationMethodInfo);
1551
_recompilationMethodInfo = NULL;
1552
}
1553
1554
TR::CompilationInfoPerThread::freeAllResources();
1555
}
1556
1557