Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/env/J9SharedCache.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 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 "env/J9SharedCache.hpp"
24
25
#include <algorithm>
26
#include "j9cfg.h"
27
#include "control/CompilationRuntime.hpp"
28
#include "control/Options.hpp"
29
#include "control/Options_inlines.hpp"
30
#include "compile/ResolvedMethod.hpp"
31
#include "env/ClassLoaderTable.hpp"
32
#include "env/ClassTableCriticalSection.hpp"
33
#include "env/jittypes.h"
34
#include "env/j9method.h"
35
#include "env/PersistentCHTable.hpp"
36
#include "env/VMAccessCriticalSection.hpp"
37
#include "env/VMJ9.h"
38
#include "env/VerboseLog.hpp"
39
#include "exceptions/PersistenceFailure.hpp"
40
#include "infra/CriticalSection.hpp"
41
#include "runtime/CodeRuntime.hpp"
42
#include "runtime/IProfiler.hpp"
43
#include "runtime/RuntimeAssumptions.hpp"
44
#if defined(J9VM_OPT_JITSERVER)
45
#include "control/CompilationThread.hpp" // for TR::compInfoPT
46
#include "control/JITServerHelpers.hpp"
47
#include "runtime/JITClientSession.hpp"
48
#endif
49
50
#define LOG(logLevel, format, ...) \
51
if (_logLevel >= logLevel) \
52
{ \
53
log("" format "", ##__VA_ARGS__); \
54
}
55
56
// From CompositeCache.cpp
57
#define UPDATEPTR(ca) (((uint8_t *)(ca)) + (ca)->updateSRP)
58
#define SEGUPDATEPTR(ca) (((uint8_t *)(ca)) + (ca)->segmentSRP)
59
60
TR_J9SharedCache::TR_J9SharedCacheDisabledReason TR_J9SharedCache::_sharedCacheState = TR_J9SharedCache::UNINITIALIZED;
61
TR_YesNoMaybe TR_J9SharedCache::_sharedCacheDisabledBecauseFull = TR_maybe;
62
UDATA TR_J9SharedCache::_storeSharedDataFailedLength = 0;
63
64
TR_YesNoMaybe TR_J9SharedCache::isSharedCacheDisabledBecauseFull(TR::CompilationInfo *compInfo)
65
{
66
if (_sharedCacheDisabledBecauseFull == TR_maybe)
67
{
68
if (_sharedCacheState == SHARED_CACHE_FULL)
69
{
70
_sharedCacheDisabledBecauseFull = TR_yes;
71
}
72
#if defined(J9VM_OPT_SHARED_CLASSES) && defined(J9VM_INTERP_AOT_RUNTIME_SUPPORT)
73
// Need to check if the AOT Header / Class Chain Data failed to store because
74
// the SCC is full or for some other reason.
75
else if (_sharedCacheState == AOT_HEADER_STORE_FAILED ||
76
_sharedCacheState == SHARED_CACHE_CLASS_CHAIN_STORE_FAILED)
77
{
78
J9JavaVM * javaVM = compInfo->getJITConfig()->javaVM;
79
if (javaVM->sharedClassConfig && javaVM->sharedClassConfig->getJavacoreData)
80
{
81
J9SharedClassJavacoreDataDescriptor javacoreData;
82
memset(&javacoreData, 0, sizeof(J9SharedClassJavacoreDataDescriptor));
83
javaVM->sharedClassConfig->getJavacoreData(javaVM, &javacoreData);
84
85
if (javacoreData.freeBytes <= _storeSharedDataFailedLength)
86
_sharedCacheDisabledBecauseFull = TR_yes;
87
else
88
_sharedCacheDisabledBecauseFull = TR_no;
89
90
if (TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerbosePerformance))
91
TR_VerboseLog::writeLineLocked(TR_Vlog_PERF, "Free Bytes in SCC = %u B", javacoreData.freeBytes);
92
}
93
else
94
{
95
_sharedCacheDisabledBecauseFull = TR_no;
96
}
97
}
98
#endif
99
else
100
{
101
_sharedCacheDisabledBecauseFull = TR_no;
102
}
103
}
104
105
return _sharedCacheDisabledBecauseFull;
106
}
107
108
const CCVResult
109
TR_J9SharedCache::getCachedCCVResult(TR_OpaqueClassBlock *clazz)
110
{
111
if (!TR::Options::getCmdLineOptions()->getOption(TR_DisableCHOpts))
112
{
113
TR::ClassTableCriticalSection cacheResult(_fe);
114
TR_PersistentCHTable *table = _compInfo->getPersistentInfo()->getPersistentCHTable();
115
TR_PersistentClassInfo *classInfo = table->findClassInfo(clazz);
116
return classInfo->getCCVResult();
117
}
118
return CCVResult::notYetValidated;
119
}
120
121
bool
122
TR_J9SharedCache::cacheCCVResult(TR_OpaqueClassBlock *clazz, CCVResult result)
123
{
124
if (!TR::Options::getCmdLineOptions()->getOption(TR_DisableCHOpts))
125
{
126
TR::ClassTableCriticalSection cacheResult(_fe);
127
TR_PersistentCHTable *table = _compInfo->getPersistentInfo()->getPersistentCHTable();
128
TR_PersistentClassInfo *classInfo = table->findClassInfo(clazz);
129
classInfo->setCCVResult(result);
130
return true;
131
}
132
return false;
133
}
134
135
TR_J9SharedCache::TR_J9SharedCache(TR_J9VMBase *fe)
136
{
137
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
138
_fe = fe;
139
_jitConfig = fe->getJ9JITConfig();
140
_javaVM = _jitConfig->javaVM;
141
_compInfo = TR::CompilationInfo::get(_jitConfig);
142
_aotStats = fe->getPrivateConfig()->aotStats;
143
_sharedCacheConfig = _javaVM->sharedClassConfig;
144
_numDigitsForCacheOffsets = 8;
145
146
#if defined(J9VM_OPT_JITSERVER)
147
TR_ASSERT_FATAL(_sharedCacheConfig || _compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER, "Must have _sharedCacheConfig");
148
#else
149
TR_ASSERT_FATAL(_sharedCacheConfig, "Must have _sharedCacheConfig");
150
#endif
151
152
#if defined(J9VM_OPT_JITSERVER)
153
if (_sharedCacheConfig)
154
#endif
155
{
156
UDATA totalCacheSize = 0;
157
J9SharedClassCacheDescriptor *curCache = _sharedCacheConfig->cacheDescriptorList;
158
do
159
{
160
totalCacheSize += curCache->cacheSizeBytes;
161
curCache = curCache->next;
162
}
163
while (curCache != _sharedCacheConfig->cacheDescriptorList);
164
165
if (totalCacheSize > UINT_MAX)
166
_numDigitsForCacheOffsets = 16;
167
168
_hintsEnabledMask = 0;
169
if (!TR::Options::getAOTCmdLineOptions()->getOption(TR_DisableSharedCacheHints))
170
_hintsEnabledMask = TR::Options::getAOTCmdLineOptions()->getEnableSCHintFlags();
171
172
_initialHintSCount = std::min(TR::Options::getCmdLineOptions()->getInitialSCount(), TR::Options::getAOTCmdLineOptions()->getInitialSCount());
173
if (_initialHintSCount == 0)
174
_initialHintSCount = 1;
175
176
_logLevel = std::max(TR::Options::getAOTCmdLineOptions()->getAotrtDebugLevel(), TR::Options::getCmdLineOptions()->getAotrtDebugLevel());
177
178
_verboseHints = TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerboseSCHints);
179
180
LOG(1, "\t_sharedCacheConfig %p\n", _sharedCacheConfig);
181
LOG(1, "\ttotalCacheSize %p\n", totalCacheSize);
182
}
183
#endif
184
}
185
186
J9SharedClassCacheDescriptor *
187
TR_J9SharedCache::getCacheDescriptorList()
188
{
189
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
190
if (_sharedCacheConfig)
191
return _sharedCacheConfig->cacheDescriptorList;
192
#endif
193
return NULL;
194
}
195
196
void
197
TR_J9SharedCache::log(char *format, ...)
198
{
199
PORT_ACCESS_FROM_PORT(_javaVM->portLibrary);
200
char outputBuffer[512] = "TR_J9SC:";
201
const uint32_t startOffset = 8; // strlen("TR_J9SC:")
202
203
va_list args;
204
va_start(args, format);
205
j9str_vprintf(outputBuffer+startOffset, 512, format, args);
206
va_end(args);
207
208
rtlogPrintLocked(jitConfig(), _fe->_compInfoPT, outputBuffer);
209
}
210
211
TR_J9SharedCache::SCCHint
212
TR_J9SharedCache::getHint(J9VMThread * vmThread, J9Method *method)
213
{
214
SCCHint result;
215
216
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
217
J9ROMMethod * romMethod = fe()->getROMMethodFromRAMMethod(method);
218
219
J9SharedDataDescriptor descriptor;
220
descriptor.address = (U_8 *)&result;
221
descriptor.length = sizeof(result);
222
descriptor.type = J9SHR_ATTACHED_DATA_TYPE_JITHINT;
223
descriptor.flags = J9SHR_ATTACHED_DATA_NO_FLAGS;
224
IDATA dataIsCorrupt;
225
SCCHint *find = (SCCHint *)sharedCacheConfig()->findAttachedData(vmThread, romMethod, &descriptor, &dataIsCorrupt);
226
227
if ((find != (SCCHint *)descriptor.address) || (dataIsCorrupt != -1))
228
{
229
result.clear();
230
}
231
#endif // defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
232
return result;
233
}
234
235
uint16_t
236
TR_J9SharedCache::getAllEnabledHints(J9Method *method)
237
{
238
uint16_t hintFlags = 0;
239
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
240
if (_hintsEnabledMask)
241
{
242
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
243
J9VMThread * vmThread = fej9->getCurrentVMThread();
244
SCCHint scHints = getHint(vmThread, method);
245
hintFlags = scHints.flags & _hintsEnabledMask;
246
}
247
#endif // defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
248
return hintFlags;
249
}
250
251
252
bool
253
TR_J9SharedCache::isHint(J9Method *method, TR_SharedCacheHint theHint, uint16_t *dataField)
254
{
255
bool isHint = false;
256
257
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
258
uint16_t hint = ((uint16_t)theHint) & _hintsEnabledMask;
259
if (hint != 0)
260
{
261
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
262
J9ROMMethod * romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);
263
J9VMThread * vmThread = fej9->getCurrentVMThread();
264
SCCHint scHints = getHint(vmThread, method);
265
266
if (dataField)
267
*dataField = scHints.data;
268
269
if (_verboseHints)
270
{
271
char methodSignature[500];
272
int32_t maxSignatureLength = 500;
273
fej9->printTruncatedSignature(methodSignature, maxSignatureLength, (TR_OpaqueMethodBlock *) method);
274
TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"is hint %x(%x) %s", scHints.flags, hint, methodSignature);
275
}
276
isHint = (scHints.flags & hint) != 0;
277
}
278
#endif // defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
279
return isHint;
280
}
281
282
bool
283
TR_J9SharedCache::isHint(TR_ResolvedMethod *method, TR_SharedCacheHint hint, uint16_t *dataField)
284
{
285
return isHint(((TR_ResolvedJ9Method *) method)->ramMethod(), hint, dataField);
286
}
287
288
void
289
TR_J9SharedCache::addHint(J9Method * method, TR_SharedCacheHint theHint)
290
{
291
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
292
static bool SCfull = false;
293
uint16_t newHint = ((uint16_t)theHint) & _hintsEnabledMask;
294
if (newHint)
295
{
296
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
297
J9ROMMethod * romMethod = fej9->getROMMethodFromRAMMethod(method);
298
J9VMThread * vmThread = fej9->getCurrentVMThread();
299
300
char methodSignature[500];
301
uint32_t maxSignatureLength = 500;
302
303
bool isFailedValidationHint = (newHint == TR_HintFailedValidation);
304
305
if (_verboseHints)
306
{
307
fej9->printTruncatedSignature(methodSignature, maxSignatureLength, (TR_OpaqueMethodBlock *) method);
308
TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"adding hint 0x%x %s", newHint, methodSignature);
309
}
310
311
// There is only one scenario where concurrency *may* matter, so we don't get a lock
312
// The scenario is where a compilation thread wants to register a hint about the method it's compiling at
313
// the same time that another thread is inlining it *for the first time*. In that case, one of the hints
314
// won't be registered. The affect, however is minimal, and likely to correct itself in the current run
315
// (if the inlining hint is missed) or a subsequent run (if the other hint is missed).
316
317
SCCHint scHints = getHint(vmThread, method);
318
const uint32_t scHintDataLength = sizeof(scHints);
319
320
if (scHints.flags == 0) // If no prior hints exist, we can perform a "storeAttachedData" operation
321
{
322
uint32_t bytesToPersist = 0;
323
324
if (!SCfull)
325
{
326
scHints.flags |= newHint;
327
if (isFailedValidationHint)
328
scHints.data = 10 * _initialHintSCount;
329
330
J9SharedDataDescriptor descriptor;
331
descriptor.address = (U_8 *)&scHints;
332
descriptor.length = scHintDataLength; // Size includes the 2nd data field, currently only used for TR_HintFailedValidation
333
descriptor.type = J9SHR_ATTACHED_DATA_TYPE_JITHINT;
334
descriptor.flags = J9SHR_ATTACHED_DATA_NO_FLAGS;
335
UDATA store = sharedCacheConfig()->storeAttachedData(vmThread, romMethod, &descriptor, 0);
336
TR::CompilationInfo * compInfo = TR::CompilationInfo::get(jitConfig());
337
if (store == 0)
338
{
339
if (_verboseHints)
340
TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"hint added 0x%x, key = %s, scount: %d", scHints.flags, methodSignature, scHints.data);
341
}
342
else if (store != J9SHR_RESOURCE_STORE_FULL)
343
{
344
if (_verboseHints)
345
TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"hint error: could not be added into SC\n");
346
}
347
else
348
{
349
SCfull = true;
350
bytesToPersist = scHintDataLength;
351
if (_verboseHints)
352
TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"hint error: SCC full\n");
353
}
354
}
355
else // SCC Full
356
{
357
bytesToPersist = scHintDataLength;
358
}
359
360
if (SCfull &&
361
bytesToPersist &&
362
!TR::Options::getCmdLineOptions()->getOption(TR_DisableUpdateJITBytesSize))
363
{
364
_compInfo->increaseUnstoredBytes(0, bytesToPersist);
365
}
366
}
367
else // Some hints already exist for this method. We must perform an "updateAttachedData"
368
{
369
bool updateHint = false;
370
bool hintDidNotExist = ((newHint & scHints.flags) == 0);
371
if (hintDidNotExist)
372
{
373
updateHint = true;
374
scHints.flags |= newHint;
375
if (isFailedValidationHint)
376
scHints.data = 10 * _initialHintSCount;
377
}
378
else
379
{
380
// hint already exists, but maybe we need to update the count
381
if (isFailedValidationHint)
382
{
383
uint16_t oldCount = scHints.data;
384
uint16_t newCount = std::min(oldCount * 10, TR_DEFAULT_INITIAL_COUNT);
385
if (newCount != oldCount)
386
{
387
updateHint = true;
388
scHints.data = newCount;
389
}
390
else
391
{
392
if (_verboseHints)
393
{
394
TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS, "hint reached max count of %d", oldCount);
395
}
396
}
397
}
398
}
399
if (updateHint)
400
{
401
J9SharedDataDescriptor descriptor;
402
descriptor.address = (U_8 *)&scHints;
403
descriptor.length = scHintDataLength; // Size includes the 2nd data field, currently only used for TR_HintFailedValidation
404
descriptor.type = J9SHR_ATTACHED_DATA_TYPE_JITHINT;
405
descriptor.flags = J9SHR_ATTACHED_DATA_NO_FLAGS;
406
UDATA update = sharedCacheConfig()->updateAttachedData(vmThread, romMethod, 0, &descriptor);
407
408
if (_verboseHints)
409
{
410
if (update == 0)
411
{
412
TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"hint updated 0x%x, key = %s, scount: %d", scHints.flags, methodSignature, scHints.data);
413
}
414
else
415
{
416
TR_VerboseLog::writeLineLocked(TR_Vlog_SCHINTS,"hint error: could not be updated into SC\n");
417
}
418
}
419
}
420
}
421
}
422
423
#endif // defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
424
}
425
426
void
427
TR_J9SharedCache::addHint(TR_ResolvedMethod * method, TR_SharedCacheHint hint)
428
{
429
addHint(((TR_ResolvedJ9Method *) method)->ramMethod(), hint);
430
}
431
432
433
void
434
TR_J9SharedCache::persistIprofileInfo(TR::ResolvedMethodSymbol *methodSymbol, TR::Compilation *comp)
435
{
436
persistIprofileInfo(methodSymbol, methodSymbol->getResolvedMethod(), comp);
437
}
438
439
void
440
TR_J9SharedCache::persistIprofileInfo(TR::ResolvedMethodSymbol *methodSymbol, TR_ResolvedMethod *method, TR::Compilation *comp)
441
{
442
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
443
TR_IProfiler *profiler = fej9->getIProfiler();
444
if (profiler)
445
profiler->persistIprofileInfo(methodSymbol, method, comp);
446
}
447
448
bool
449
TR_J9SharedCache::isMostlyFull()
450
{
451
return (double) sharedCacheConfig()->getFreeSpaceBytes(_javaVM) / sharedCacheConfig()->getCacheSizeBytes(_javaVM) < 0.8;
452
}
453
454
bool
455
TR_J9SharedCache::isPointerInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr)
456
{
457
bool isPointerInCache = false;
458
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
459
uintptr_t ptrValue = reinterpret_cast<uintptr_t>(ptr);
460
uintptr_t cacheStart = reinterpret_cast<uintptr_t>(cacheDesc->cacheStartAddress); // Inclusive
461
uintptr_t cacheEnd = cacheStart + cacheDesc->cacheSizeBytes; // Exclusive
462
463
isPointerInCache = (ptrValue >= cacheStart) && (ptrValue < cacheEnd);
464
#endif
465
return isPointerInCache;
466
}
467
468
bool
469
TR_J9SharedCache::isOffsetInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset)
470
{
471
bool isOffsetInCache = false;
472
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
473
uintptr_t decodedOffset = isOffsetFromStart(offset) ? decodeOffsetFromStart(offset) : decodeOffsetFromEnd(offset);
474
isOffsetInCache = (decodedOffset < cacheDesc->cacheSizeBytes);
475
#endif
476
return isOffsetInCache;
477
}
478
479
bool
480
TR_J9SharedCache::isPointerInMetadataSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr)
481
{
482
bool isPointerInMetadataSection = false;
483
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
484
if (isPointerInCache(cacheDesc, ptr))
485
{
486
uintptr_t ptrValue = reinterpret_cast<uintptr_t>(ptr);
487
uintptr_t metadataEndAddress = reinterpret_cast<uintptr_t>(UPDATEPTR(cacheDesc->cacheStartAddress)); // Inclusive
488
uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(cacheDesc->metadataStartAddress); // Exclusive
489
490
isPointerInMetadataSection = (ptrValue >= metadataEndAddress) && (ptrValue < metadataStartAddress);
491
}
492
#endif
493
return isPointerInMetadataSection;
494
}
495
496
bool
497
TR_J9SharedCache::isOffsetInMetadataSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset)
498
{
499
bool isOffsetInMetadataSection = false;
500
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
501
if (isOffsetFromEnd(offset) && isOffsetInCache(cacheDesc, offset))
502
{
503
uintptr_t metadataEndAddress = reinterpret_cast<uintptr_t>(UPDATEPTR(cacheDesc->cacheStartAddress));
504
uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(cacheDesc->metadataStartAddress);
505
506
uintptr_t metadataEndOffset = metadataStartAddress - metadataEndAddress; // Inclusive
507
508
isOffsetInMetadataSection = ((decodeOffsetFromEnd(offset) > 0 ) && (decodeOffsetFromEnd(offset) <= metadataEndOffset));
509
}
510
#endif
511
return isOffsetInMetadataSection;
512
}
513
514
bool
515
TR_J9SharedCache::isPointerInROMClassesSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, void *ptr)
516
{
517
bool isPointerInRomClassesSection = false;
518
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
519
if (isPointerInCache(cacheDesc, ptr))
520
{
521
uintptr_t ptrValue = reinterpret_cast<uintptr_t>(ptr);
522
uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(cacheDesc->romclassStartAddress); // Inclusive
523
uintptr_t romclassEndAddress = reinterpret_cast<uintptr_t>(SEGUPDATEPTR(cacheDesc->cacheStartAddress)); // Exclusive
524
525
isPointerInRomClassesSection = (ptrValue >= romclassStartAddress) && (ptrValue < romclassEndAddress);
526
}
527
#endif
528
return isPointerInRomClassesSection;
529
}
530
531
bool
532
TR_J9SharedCache::isOffsetinROMClassesSectionInCache(const J9SharedClassCacheDescriptor *cacheDesc, uintptr_t offset)
533
{
534
bool isOffsetInRomClassesSection = false;
535
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
536
if (isOffsetFromStart(offset) && isOffsetInCache(cacheDesc, offset))
537
{
538
uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(cacheDesc->romclassStartAddress);
539
uintptr_t romclassEndAddress = reinterpret_cast<uintptr_t>(SEGUPDATEPTR(cacheDesc->cacheStartAddress));
540
541
uintptr_t romclassEndOffset = romclassEndAddress - romclassStartAddress; // Exclusive
542
543
isOffsetInRomClassesSection = (decodeOffsetFromStart(offset) < romclassEndOffset);
544
}
545
#endif
546
return isOffsetInRomClassesSection;
547
}
548
549
void *
550
TR_J9SharedCache::pointerFromOffsetInSharedCache(uintptr_t offset)
551
{
552
uintptr_t ptr = 0;
553
if (isOffsetInSharedCache(offset, &ptr))
554
{
555
return (void *)ptr;
556
}
557
TR_ASSERT_FATAL(false, "Shared cache offset %d out of bounds", offset);
558
return (void *)ptr;
559
}
560
561
void *
562
TR_J9SharedCache::romStructureFromOffsetInSharedCache(uintptr_t offset)
563
{
564
void *romStructure = NULL;
565
if (isROMStructureOffsetInSharedCache(offset, &romStructure))
566
{
567
return romStructure;
568
}
569
TR_ASSERT_FATAL(false, "Shared cache ROM Structure offset %d out of bounds", offset);
570
return romStructure;
571
}
572
573
J9ROMClass *
574
TR_J9SharedCache::romClassFromOffsetInSharedCache(uintptr_t offset)
575
{
576
return reinterpret_cast<J9ROMClass *>(romStructureFromOffsetInSharedCache(offset));
577
}
578
579
J9ROMMethod *
580
TR_J9SharedCache::romMethodFromOffsetInSharedCache(uintptr_t offset)
581
{
582
return reinterpret_cast<J9ROMMethod *>(romStructureFromOffsetInSharedCache(offset));
583
}
584
585
void *
586
TR_J9SharedCache::ptrToROMClassesSectionFromOffsetInSharedCache(uintptr_t offset)
587
{
588
return romStructureFromOffsetInSharedCache(offset);
589
}
590
591
bool
592
TR_J9SharedCache::isOffsetInSharedCache(uintptr_t encoded_offset, void *ptr)
593
{
594
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
595
#if defined(J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE)
596
// The cache descriptor list is linked last to first and is circular, so last->previous == first.
597
J9SharedClassCacheDescriptor *firstCache = getCacheDescriptorList()->previous;
598
J9SharedClassCacheDescriptor *curCache = firstCache;
599
do
600
{
601
TR_ASSERT_FATAL(isOffsetFromEnd(encoded_offset), "Shared cache (encoded) offset %lld not from end\n", encoded_offset);
602
if (isOffsetInMetadataSectionInCache(curCache, encoded_offset))
603
{
604
if (ptr)
605
{
606
uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(curCache->metadataStartAddress);
607
*reinterpret_cast<uintptr_t *>(ptr) = metadataStartAddress - decodeOffsetFromEnd(encoded_offset);
608
}
609
return true;
610
}
611
encoded_offset = encodeOffsetFromEnd(decodeOffsetFromEnd(encoded_offset) - curCache->cacheSizeBytes);
612
curCache = curCache->previous;
613
}
614
while (curCache != firstCache);
615
#else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE
616
TR_ASSERT_FATAL(isOffsetFromEnd(encoded_offset), "Shared cache (encoded) offset %lld not from end\n", encoded_offset);
617
J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList();
618
if (isOffsetInMetadataSectionInCache(curCache, encoded_offset))
619
{
620
if (ptr)
621
{
622
uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(curCache->metadataStartAddress);
623
*reinterpret_cast<uintptr_t *>(ptr) = metadataStartAddress - decodeOffsetFromEnd(encoded_offset);
624
}
625
return true;
626
}
627
#endif // J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE
628
#endif
629
return false;
630
}
631
632
bool
633
TR_J9SharedCache::isROMStructureOffsetInSharedCache(uintptr_t encoded_offset, void **romStructurePtr)
634
{
635
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
636
#if defined(J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE)
637
// The cache descriptor list is linked last to first and is circular, so last->previous == first.
638
J9SharedClassCacheDescriptor *firstCache = getCacheDescriptorList()->previous;
639
J9SharedClassCacheDescriptor *curCache = firstCache;
640
do
641
{
642
TR_ASSERT_FATAL(isOffsetFromStart(encoded_offset), "Shared cache (encoded) offset %lld not from start\n", encoded_offset);
643
if (isOffsetinROMClassesSectionInCache(curCache, encoded_offset))
644
{
645
if (romStructurePtr)
646
{
647
uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(curCache->romclassStartAddress);
648
*romStructurePtr = reinterpret_cast<void *>(romclassStartAddress + decodeOffsetFromStart(encoded_offset));
649
}
650
return true;
651
}
652
encoded_offset = encodeOffsetFromStart(decodeOffsetFromStart(encoded_offset) - curCache->cacheSizeBytes);
653
curCache = curCache->previous;
654
}
655
while (curCache != firstCache);
656
#else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE
657
TR_ASSERT_FATAL(isOffsetFromStart(encoded_offset), "Shared cache (encoded) offset %lld not from start\n", encoded_offset);
658
J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList();
659
if (isOffsetinROMClassesSectionInCache(curCache, encoded_offset))
660
{
661
if (romStructurePtr)
662
{
663
uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(curCache->romclassStartAddress);
664
*romStructurePtr = reinterpret_cast<void *>(romclassStartAddress + decodeOffsetFromStart(encoded_offset));
665
}
666
return true;
667
}
668
#endif // J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE
669
#endif
670
return false;
671
}
672
673
bool
674
TR_J9SharedCache::isROMClassOffsetInSharedCache(uintptr_t offset, J9ROMClass **romClassPtr)
675
{
676
return isROMStructureOffsetInSharedCache(offset, reinterpret_cast<void **>(romClassPtr));
677
}
678
679
bool
680
TR_J9SharedCache::isROMMethodOffsetInSharedCache(uintptr_t offset, J9ROMMethod **romMethodPtr)
681
{
682
return isROMStructureOffsetInSharedCache(offset, reinterpret_cast<void **>(romMethodPtr));
683
}
684
685
bool
686
TR_J9SharedCache::isOffsetOfPtrToROMClassesSectionInSharedCache(uintptr_t offset, void **ptr)
687
{
688
return isROMStructureOffsetInSharedCache(offset, ptr);
689
}
690
691
uintptr_t
692
TR_J9SharedCache::offsetInSharedCacheFromPointer(void *ptr)
693
{
694
uintptr_t offset = 0;
695
if (isPointerInSharedCache(ptr, &offset))
696
{
697
return offset;
698
}
699
TR_ASSERT_FATAL(false, "Shared cache pointer %p out of bounds", ptr);
700
return offset;
701
}
702
703
uintptr_t
704
TR_J9SharedCache::offsetInSharedcacheFromROMStructure(void *romStructure)
705
{
706
uintptr_t offset = 0;
707
if (isROMStructureInSharedCache(romStructure, &offset))
708
{
709
return offset;
710
}
711
TR_ASSERT_FATAL(false, "Shared cache ROM Structure pointer %p out of bounds", romStructure);
712
return offset;
713
}
714
715
uintptr_t
716
TR_J9SharedCache::offsetInSharedCacheFromROMClass(J9ROMClass *romClass)
717
{
718
return offsetInSharedcacheFromROMStructure(romClass);
719
}
720
721
uintptr_t
722
TR_J9SharedCache::offsetInSharedCacheFromROMMethod(J9ROMMethod *romMethod)
723
{
724
return offsetInSharedcacheFromROMStructure(romMethod);
725
}
726
727
uintptr_t
728
TR_J9SharedCache::offsetInSharedCacheFromPtrToROMClassesSection(void *ptr)
729
{
730
return offsetInSharedcacheFromROMStructure(ptr);
731
}
732
733
bool
734
TR_J9SharedCache::isPointerInSharedCache(void *ptr, uintptr_t *cacheOffset)
735
{
736
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
737
#if defined(J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE)
738
uintptr_t offset = 0;
739
// The cache descriptor list is linked last to first and is circular, so last->previous == first.
740
J9SharedClassCacheDescriptor *firstCache = getCacheDescriptorList()->previous;
741
J9SharedClassCacheDescriptor *curCache = firstCache;
742
do
743
{
744
if (isPointerInMetadataSectionInCache(curCache, ptr))
745
{
746
if (cacheOffset)
747
{
748
uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(curCache->metadataStartAddress);
749
*cacheOffset = encodeOffsetFromEnd(metadataStartAddress - reinterpret_cast<uintptr_t>(ptr) + offset);
750
}
751
return true;
752
}
753
offset += curCache->cacheSizeBytes;
754
curCache = curCache->previous;
755
}
756
while (curCache != firstCache);
757
#else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE
758
J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList();
759
if (isPointerInMetadataSectionInCache(curCache, ptr))
760
{
761
if (cacheOffset)
762
{
763
uintptr_t metadataStartAddress = reinterpret_cast<uintptr_t>(curCache->metadataStartAddress);
764
*cacheOffset = encodeOffsetFromEnd(metadataStartAddress - reinterpret_cast<uintptr_t>(ptr));
765
}
766
return true;
767
}
768
#endif // J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE
769
#endif
770
return false;
771
}
772
773
bool
774
TR_J9SharedCache::isROMStructureInSharedCache(void *romStructure, uintptr_t *cacheOffset)
775
{
776
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
777
#if defined(J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE)
778
uintptr_t offset = 0;
779
// The cache descriptor list is linked last to first and is circular, so last->previous == first.
780
J9SharedClassCacheDescriptor *firstCache = getCacheDescriptorList()->previous;
781
J9SharedClassCacheDescriptor *curCache = firstCache;
782
do
783
{
784
if (isPointerInROMClassesSectionInCache(curCache, romStructure))
785
{
786
if (cacheOffset)
787
{
788
uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(curCache->romclassStartAddress);
789
*cacheOffset = encodeOffsetFromStart(reinterpret_cast<uintptr_t>(romStructure) - romclassStartAddress + offset);
790
}
791
return true;
792
}
793
offset += curCache->cacheSizeBytes;
794
curCache = curCache->previous;
795
}
796
while (curCache != firstCache);
797
#else // !J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE
798
J9SharedClassCacheDescriptor *curCache = getCacheDescriptorList();
799
if (isPointerInROMClassesSectionInCache(curCache, romStructure))
800
{
801
if (cacheOffset)
802
{
803
uintptr_t romclassStartAddress = reinterpret_cast<uintptr_t>(curCache->romclassStartAddress);
804
*cacheOffset = encodeOffsetFromStart(reinterpret_cast<uintptr_t>(romStructure) - romclassStartAddress);
805
}
806
return true;
807
}
808
#endif // J9VM_OPT_MULTI_LAYER_SHARED_CLASS_CACHE
809
#endif
810
return false;
811
}
812
813
bool
814
TR_J9SharedCache::isROMClassInSharedCache(J9ROMClass *romClass, uintptr_t *cacheOffset)
815
{
816
return isROMStructureInSharedCache(romClass, cacheOffset);
817
}
818
819
bool
820
TR_J9SharedCache::isROMMethodInSharedCache(J9ROMMethod *romMethod, uintptr_t *cacheOffset)
821
{
822
return isROMStructureInSharedCache(romMethod, cacheOffset);
823
}
824
825
bool
826
TR_J9SharedCache::isPtrToROMClassesSectionInSharedCache(void *ptr, uintptr_t *cacheOffset)
827
{
828
return isROMStructureInSharedCache(ptr, cacheOffset);
829
}
830
831
J9ROMClass *
832
TR_J9SharedCache::startingROMClassOfClassChain(UDATA *classChain)
833
{
834
UDATA lengthInBytes = classChain[0];
835
TR_ASSERT_FATAL(lengthInBytes >= 2 * sizeof (UDATA), "class chain is too short!");
836
837
UDATA romClassOffset = classChain[1];
838
return romClassFromOffsetInSharedCache(romClassOffset);
839
}
840
841
// convert an offset into a string of 8 characters
842
void
843
TR_J9SharedCache::convertUnsignedOffsetToASCII(UDATA offset, char *buffer)
844
{
845
for (int i = _numDigitsForCacheOffsets; i >= 0; i--, offset >>= 4)
846
{
847
uint8_t lowNibble = offset & 0xf;
848
buffer[i] = (lowNibble > 9 ? lowNibble - 10 + 'a' : lowNibble + '0');
849
}
850
buffer[_numDigitsForCacheOffsets] = 0;
851
TR_ASSERT(offset == 0, "Unsigned offset unexpectedly not fully converted to ASCII");
852
}
853
854
void
855
TR_J9SharedCache::createClassKey(UDATA classOffsetInCache, char *key, uint32_t & keyLength)
856
{
857
keyLength = _numDigitsForCacheOffsets;
858
convertUnsignedOffsetToASCII(classOffsetInCache, key);
859
}
860
861
uintptr_t *
862
TR_J9SharedCache::rememberClass(J9Class *clazz, const AOTCacheClassChainRecord **classChainRecord, bool create)
863
{
864
uintptr_t *chainData = NULL;
865
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
866
TR_J9VMBase *fej9 = (TR_J9VMBase *)fe();
867
J9ROMClass *romClass = TR::Compiler->cls.romClassOf(fej9->convertClassPtrToClassOffset(clazz));
868
869
J9UTF8 *className = J9ROMCLASS_CLASSNAME(romClass);
870
LOG(1, "rememberClass class %p romClass %p %.*s\n", clazz, romClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className));
871
872
uintptr_t classOffsetInCache;
873
if (!isROMClassInSharedCache(romClass, &classOffsetInCache))
874
{
875
LOG(1,"\trom class not in shared cache, returning\n");
876
return NULL;
877
}
878
879
char key[17]; // longest possible key length is way less than 16 digits
880
uint32_t keyLength;
881
createClassKey(classOffsetInCache, key, keyLength);
882
883
LOG(3, "\tkey created: %.*s\n", keyLength, key);
884
885
chainData = findChainForClass(clazz, key, keyLength);
886
if (chainData != NULL)
887
{
888
LOG(1, "\tchain exists (%p) so nothing to store\n", chainData);
889
return chainData;
890
}
891
892
int32_t numSuperclasses = TR::Compiler->cls.classDepthOf(fe()->convertClassPtrToClassOffset(clazz));
893
int32_t numInterfaces = numInterfacesImplemented(clazz);
894
895
LOG(3, "\tcreating chain now: 1 + 1 + %d superclasses + %d interfaces\n", numSuperclasses, numInterfaces);
896
uintptr_t chainLength = (2 + numSuperclasses + numInterfaces) * sizeof(uintptr_t);
897
uintptr_t chainDataBuffer[maxClassChainLength];
898
chainData = chainDataBuffer;
899
if (chainLength > maxClassChainLength * sizeof(uintptr_t))
900
{
901
LOG(1, "\t\t > %u so bailing\n", maxClassChainLength);
902
return NULL;
903
}
904
905
if (!fillInClassChain(clazz, chainData, chainLength, numSuperclasses, numInterfaces))
906
{
907
LOG(1, "\tfillInClassChain failed, bailing\n");
908
return NULL;
909
}
910
911
if (!create)
912
{
913
LOG(1, "\tnot asked to create but could create, returning non-null\n");
914
return (uintptr_t *)0x1;
915
}
916
917
uintptr_t chainDataLength = chainData[0];
918
919
J9SharedDataDescriptor dataDescriptor;
920
dataDescriptor.address = (uint8_t *)chainData;
921
dataDescriptor.length = chainDataLength;
922
dataDescriptor.type = J9SHR_DATA_TYPE_AOTCLASSCHAIN;
923
dataDescriptor.flags = J9SHRDATA_SINGLE_STORE_FOR_KEY_TYPE;
924
925
if (aotStats())
926
aotStats()->numNewCHEntriesInSharedClass++;
927
928
J9VMThread *vmThread = fej9->getCurrentVMThread();
929
chainData = (uintptr_t *)sharedCacheConfig()->storeSharedData(vmThread, key, keyLength, &dataDescriptor);
930
if (chainData)
931
{
932
LOG(1, "\tstored data, chain at %p\n", chainData);
933
}
934
else
935
{
936
LOG(1, "\tunable to store chain\n");
937
TR::Options::getAOTCmdLineOptions()->setOption(TR_NoStoreAOT);
938
939
setSharedCacheDisabledReason(SHARED_CACHE_CLASS_CHAIN_STORE_FAILED);
940
setStoreSharedDataFailedLength(chainDataLength);
941
}
942
#endif
943
return chainData;
944
}
945
946
UDATA
947
TR_J9SharedCache::rememberDebugCounterName(const char *name)
948
{
949
UDATA offset = 0;
950
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
951
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
952
J9VMThread *vmThread = fej9->getCurrentVMThread();
953
954
J9SharedDataDescriptor dataDescriptor;
955
dataDescriptor.address = (U_8*)name;
956
dataDescriptor.length = (strlen(name) + 1); // +1 for the \0 terminator
957
dataDescriptor.type = J9SHR_DATA_TYPE_JITHINT;
958
dataDescriptor.flags = J9SHRDATA_NOT_INDEXED;
959
960
const U_8 *data = sharedCacheConfig()->storeSharedData(vmThread,
961
(const char*)NULL,
962
0,
963
&dataDescriptor);
964
965
offset = data ? offsetInSharedCacheFromPointer((void *)data) : (UDATA)-1;
966
967
//printf("\nrememberDebugCounterName: Tried to store %s (%p), data=%p, offset=%p\n", name, name, data, offset);
968
#endif
969
return offset;
970
}
971
972
const char *
973
TR_J9SharedCache::getDebugCounterName(UDATA offset)
974
{
975
const char *name = (offset != (UDATA)-1) ? (const char *)pointerFromOffsetInSharedCache(offset) : NULL;
976
977
//printf("\ngetDebugCounterName: Tried to find %p, name=%s (%p)\n", offset, (name ? name : ""), name);
978
979
return name;
980
}
981
982
uint32_t
983
TR_J9SharedCache::numInterfacesImplemented(J9Class *clazz)
984
{
985
uint32_t count=0;
986
J9ITable *element = TR::Compiler->cls.iTableOf(fe()->convertClassPtrToClassOffset(clazz));
987
while (element != NULL)
988
{
989
count++;
990
element = TR::Compiler->cls.iTableNext(element);
991
}
992
return count;
993
}
994
995
bool
996
TR_J9SharedCache::writeClassToChain(J9ROMClass *romClass, UDATA * & chainPtr)
997
{
998
uintptr_t classOffsetInCache;
999
if (!isROMClassInSharedCache(romClass, &classOffsetInCache))
1000
{
1001
LOG(3, "\t\tromclass %p not in shared cache, writeClassToChain returning false\n", romClass);
1002
return false;
1003
}
1004
1005
J9UTF8 * className = J9ROMCLASS_CLASSNAME(romClass);
1006
LOG(3, "\t\tChain %p storing romclass %p (%.*s) offset %d\n", chainPtr, romClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className), classOffsetInCache);
1007
*chainPtr++ = classOffsetInCache;
1008
return true;
1009
}
1010
1011
bool
1012
TR_J9SharedCache::writeClassesToChain(J9Class *clazz, int32_t numSuperclasses, UDATA * & chainPtr)
1013
{
1014
LOG(3, "\t\twriteClassesToChain:\n");
1015
1016
for (int32_t index=0; index < numSuperclasses;index++)
1017
{
1018
J9ROMClass *romClass = TR::Compiler->cls.romClassOfSuperClass(fe()->convertClassPtrToClassOffset(clazz), index);
1019
if (!writeClassToChain(romClass, chainPtr))
1020
return false;
1021
}
1022
return true;
1023
}
1024
1025
bool
1026
TR_J9SharedCache::writeInterfacesToChain(J9Class *clazz, UDATA * & chainPtr)
1027
{
1028
LOG(3, "\t\twriteInterfacesToChain:\n");
1029
1030
J9ITable *element = TR::Compiler->cls.iTableOf(fe()->convertClassPtrToClassOffset(clazz));
1031
while (element != NULL)
1032
{
1033
J9ROMClass *romClass = TR::Compiler->cls.iTableRomClass(element);
1034
if (!writeClassToChain(romClass, chainPtr))
1035
return false;
1036
1037
element = TR::Compiler->cls.iTableNext(element);
1038
}
1039
1040
return true;
1041
}
1042
1043
bool
1044
TR_J9SharedCache::fillInClassChain(J9Class *clazz, UDATA *chainData, uint32_t chainLength,
1045
uint32_t numSuperclasses, uint32_t numInterfaces)
1046
{
1047
LOG(3, "\t\tChain %p store chainLength %d\n", chainData, chainLength);
1048
1049
UDATA *chainPtr = chainData;
1050
*chainPtr++ = chainLength;
1051
J9ROMClass* romClass = TR::Compiler->cls.romClassOf(fe()->convertClassPtrToClassOffset(clazz));
1052
writeClassToChain(romClass, chainPtr);
1053
if (!writeClassesToChain(clazz, numSuperclasses, chainPtr))
1054
{
1055
return false;
1056
}
1057
1058
if (!writeInterfacesToChain(clazz, chainPtr))
1059
{
1060
return false;
1061
}
1062
1063
LOG(3, "\t\tfillInClassChain returning true\n");
1064
return chainData;
1065
}
1066
1067
1068
bool
1069
TR_J9SharedCache::romclassMatchesCachedVersion(J9ROMClass *romClass, UDATA * & chainPtr, UDATA *chainEnd)
1070
{
1071
J9UTF8 * className = J9ROMCLASS_CLASSNAME(romClass);
1072
UDATA romClassOffset;
1073
if (!isROMClassInSharedCache(romClass, &romClassOffset))
1074
return false;
1075
LOG(3, "\t\tExamining romclass %p (%.*s) offset %d, comparing to %d\n", romClass, J9UTF8_LENGTH(className), J9UTF8_DATA(className), romClassOffset, *chainPtr);
1076
if ((chainPtr > chainEnd) || (romClassOffset != *chainPtr++))
1077
return false;
1078
return true;
1079
}
1080
1081
UDATA *
1082
TR_J9SharedCache::findChainForClass(J9Class *clazz, const char *key, uint32_t keyLength)
1083
{
1084
UDATA * chainForClass = NULL;
1085
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
1086
J9SharedDataDescriptor dataDescriptor;
1087
dataDescriptor.address = NULL;
1088
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
1089
1090
J9VMThread *vmThread = fej9->getCurrentVMThread();
1091
sharedCacheConfig()->findSharedData(vmThread,
1092
key,
1093
keyLength,
1094
J9SHR_DATA_TYPE_AOTCLASSCHAIN,
1095
FALSE,
1096
&dataDescriptor,
1097
NULL);
1098
1099
//fprintf(stderr,"findChainForClass: key %.*s chain %p\n", keyLength, key, dataDescriptor.address);
1100
chainForClass = (UDATA *) dataDescriptor.address;
1101
#endif
1102
return chainForClass;
1103
}
1104
1105
bool
1106
TR_J9SharedCache::validateSuperClassesInClassChain(TR_OpaqueClassBlock *clazz, UDATA * & chainPtr, UDATA *chainEnd)
1107
{
1108
int32_t numSuperclasses = TR::Compiler->cls.classDepthOf(clazz);
1109
for (int32_t index=0; index < numSuperclasses; index++)
1110
{
1111
J9ROMClass *romClass = TR::Compiler->cls.romClassOfSuperClass(clazz, index);
1112
if (!romclassMatchesCachedVersion(romClass, chainPtr, chainEnd))
1113
{
1114
LOG(1, "\tClass in hierarchy did not match, returning false\n");
1115
return false;
1116
}
1117
}
1118
return true;
1119
}
1120
1121
bool
1122
TR_J9SharedCache::validateInterfacesInClassChain(TR_OpaqueClassBlock *clazz, UDATA * & chainPtr, UDATA *chainEnd)
1123
{
1124
J9ITable *interfaceElement = TR::Compiler->cls.iTableOf(clazz);
1125
while (interfaceElement)
1126
{
1127
J9ROMClass * romClass = TR::Compiler->cls.iTableRomClass(interfaceElement);
1128
if (!romclassMatchesCachedVersion(romClass, chainPtr, chainEnd))
1129
{
1130
LOG(1, "\tInterface class did not match, returning false\n");
1131
return false;
1132
}
1133
interfaceElement = TR::Compiler->cls.iTableNext(interfaceElement);
1134
}
1135
return true;
1136
}
1137
1138
bool
1139
TR_J9SharedCache::validateClassChain(J9ROMClass *romClass, TR_OpaqueClassBlock *clazz, UDATA * & chainPtr, UDATA *chainEnd)
1140
{
1141
bool validationSucceeded = false;
1142
1143
if (!romclassMatchesCachedVersion(romClass, chainPtr, chainEnd))
1144
{
1145
LOG(1, "\tClass did not match, returning false\n");
1146
}
1147
else if (!validateSuperClassesInClassChain(clazz, chainPtr, chainEnd))
1148
{
1149
LOG(1, "\tClass in hierarchy did not match, returning false\n");
1150
}
1151
else if (!validateInterfacesInClassChain(clazz, chainPtr, chainEnd))
1152
{
1153
LOG(1, "\tInterface class did not match, returning false\n");
1154
}
1155
else if (chainPtr != chainEnd)
1156
{
1157
LOG(1, "\tfinished classes and interfaces, but not at chain end, returning false\n");
1158
}
1159
else
1160
{
1161
validationSucceeded = true;
1162
}
1163
1164
return validationSucceeded;
1165
}
1166
1167
bool
1168
TR_J9SharedCache::classMatchesCachedVersion(J9Class *clazz, UDATA *chainData)
1169
{
1170
J9ROMClass *romClass = TR::Compiler->cls.romClassOf(fe()->convertClassPtrToClassOffset(clazz));
1171
J9UTF8 * className = J9ROMCLASS_CLASSNAME(romClass);
1172
LOG(1, "classMatchesCachedVersion class %p %.*s\n", clazz, J9UTF8_LENGTH(className), J9UTF8_DATA(className));
1173
1174
uintptr_t classOffsetInCache;
1175
1176
/* If the pointer isn't the SCC, then return false immmediately
1177
* as the map holds offsets into the SCC of romclasses
1178
*/
1179
if (!isROMClassInSharedCache(romClass, &classOffsetInCache))
1180
{
1181
LOG(1, "\tclass not in shared cache, returning false\n");
1182
return false;
1183
}
1184
1185
/* Check if the validation of the class chain was previously
1186
* performed; if so, return the result of that validation
1187
*/
1188
if (TR::Options::getAOTCmdLineOptions()->getOption(TR_EnableClassChainValidationCaching))
1189
{
1190
auto result = getCachedCCVResult(reinterpret_cast<TR_OpaqueClassBlock *>(clazz));
1191
if (result == CCVResult::success)
1192
{
1193
LOG(1, "\tcached result: validation succeeded\n");
1194
return true;
1195
}
1196
else if (result == CCVResult::failure)
1197
{
1198
LOG(1, "\tcached result: validation failed\n");
1199
return false;
1200
}
1201
else
1202
{
1203
TR_ASSERT_FATAL(result == CCVResult::notYetValidated, "Unknown result cached %d\n", result);
1204
}
1205
}
1206
1207
/* If the chainData passed in is NULL, try to find it in the SCC
1208
* using the romclass
1209
*/
1210
if (chainData == NULL)
1211
{
1212
char key[17]; // longest possible key length is way less than 16 digits
1213
uint32_t keyLength;
1214
createClassKey(classOffsetInCache, key, keyLength);
1215
LOG(3, "\tno chain specific, so looking up for key %.*s\n", keyLength, key);
1216
chainData = findChainForClass(clazz, key, keyLength);
1217
}
1218
1219
/* If the chainData is still NULL, cache the result as failure
1220
* and return false
1221
*/
1222
if (chainData == NULL)
1223
{
1224
LOG(1, "\tno stored chain, returning false\n");
1225
if (TR::Options::getAOTCmdLineOptions()->getOption(TR_EnableClassChainValidationCaching))
1226
cacheCCVResult(reinterpret_cast<TR_OpaqueClassBlock *>(clazz), CCVResult::failure);
1227
1228
return false;
1229
}
1230
1231
UDATA *chainPtr = chainData;
1232
UDATA chainLength = *chainPtr++;
1233
UDATA *chainEnd = (UDATA *) (((U_8*)chainData) + chainLength);
1234
LOG(3, "\tfound chain: %p with length %d\n", chainData, chainLength);
1235
1236
/* Perform class chain validation */
1237
bool success = validateClassChain(romClass, fe()->convertClassPtrToClassOffset(clazz), chainPtr, chainEnd);
1238
1239
/* Cache the result of the validation */
1240
if (TR::Options::getAOTCmdLineOptions()->getOption(TR_EnableClassChainValidationCaching))
1241
{
1242
auto result = success ? CCVResult::success : CCVResult::failure;
1243
cacheCCVResult(reinterpret_cast<TR_OpaqueClassBlock *>(clazz), result);
1244
}
1245
1246
if (success)
1247
LOG(1, "\tMatch! return true\n");
1248
1249
return success;
1250
}
1251
1252
TR_OpaqueClassBlock *
1253
TR_J9SharedCache::lookupClassFromChainAndLoader(uintptr_t *chainData, void *classLoader)
1254
{
1255
UDATA *ptrToRomClassOffset = chainData+1;
1256
J9ROMClass *romClass = romClassFromOffsetInSharedCache(*ptrToRomClassOffset);
1257
J9UTF8 *className = J9ROMCLASS_CLASSNAME(romClass);
1258
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
1259
J9VMThread *vmThread = fej9->getCurrentVMThread();
1260
J9Class *clazz = jitGetClassInClassloaderFromUTF8(vmThread, (J9ClassLoader *) classLoader,
1261
(char *) J9UTF8_DATA(className),
1262
J9UTF8_LENGTH(className));
1263
1264
if (clazz != NULL && classMatchesCachedVersion(clazz, chainData))
1265
return (TR_OpaqueClassBlock *) clazz;
1266
1267
return NULL;
1268
}
1269
1270
uintptr_t
1271
TR_J9SharedCache::getClassChainOffsetIdentifyingLoader(TR_OpaqueClassBlock *clazz, uintptr_t **classChain)
1272
{
1273
void *loaderForClazz = _fe->getClassLoader(clazz);
1274
void *classChainIdentifyingLoaderForClazz = persistentClassLoaderTable()->lookupClassChainAssociatedWithClassLoader(loaderForClazz);
1275
1276
uintptr_t classChainOffsetInSharedCache;
1277
TR::Compilation *comp = TR::comp();
1278
if (comp)
1279
{
1280
/*
1281
* TR_J9SharedCache::offsetInSharedCacheFrom* asserts if the pointer
1282
* passed in does not exist in the SCC. Under HCR, when an agent redefines
1283
* a class, it causes the J9Class pointer to stay the same, but the
1284
* J9ROMClass pointer changes. This means that if the compiler has a
1285
* reference to a J9Class who J9ROMClass was in the SCC at one point in the
1286
* compilation, it may no longer be so at another point in the compilation.
1287
*
1288
* This means that the compilation is no longer valid and should be aborted.
1289
* Even if there isn't an abort during the compilation, at the end of the
1290
* compilation, the compiler will fail the compile if such a redefinition
1291
* occurred.
1292
*
1293
* Calling TR_J9SharedCache::offsetInSharedCacheFromPointer after such a
1294
* redefinition could result in an assert. Therefore, this method exists as
1295
* a wrapper around TR_J9SharedCache::isPointerInSharedCache which doesn't
1296
* assert and conveniently, updates the location referred to by the cacheOffset
1297
* pointer passed in as a parameter.
1298
*
1299
* If the ptr isn't in the SCC, then the current method will abort the
1300
* compilation. If the ptr is in the SCC, then the cacheOffset will be updated.
1301
*/
1302
if (!isPointerInSharedCache(classChainIdentifyingLoaderForClazz, &classChainOffsetInSharedCache))
1303
comp->failCompilation<J9::ClassChainPersistenceFailure>("Failed to find pointer %p in SCC", classChainIdentifyingLoaderForClazz);
1304
}
1305
else
1306
{
1307
/*
1308
* If we're not in a compilation, then perhaps it's better to call this API
1309
* which will assert if anything's amiss
1310
*/
1311
classChainOffsetInSharedCache = offsetInSharedCacheFromPointer(classChainIdentifyingLoaderForClazz);
1312
}
1313
1314
if (classChain)
1315
*classChain = (uintptr_t *)classChainIdentifyingLoaderForClazz;
1316
return classChainOffsetInSharedCache;
1317
}
1318
1319
#if defined(J9VM_OPT_JITSERVER)
1320
uintptr_t
1321
TR_J9SharedCache::getClassChainOffsetIdentifyingLoaderNoFail(TR_OpaqueClassBlock *clazz, uintptr_t **classChain)
1322
{
1323
TR_ASSERT_FATAL(TR::comp() && !TR::comp()->isOutOfProcessCompilation(),
1324
"getClassChainOffsetIdentifyingLoaderNoFail should be called only the JVM client");
1325
void *loaderForClazz = _fe->getClassLoader(clazz);
1326
void *classChainIdentifyingLoaderForClazz = persistentClassLoaderTable()->lookupClassChainAssociatedWithClassLoader(loaderForClazz);
1327
uintptr_t classChainOffsetInSharedCache;
1328
if (!isPointerInSharedCache(classChainIdentifyingLoaderForClazz, &classChainOffsetInSharedCache))
1329
return 0;
1330
1331
if (classChain)
1332
*classChain = (uintptr_t *)classChainIdentifyingLoaderForClazz;
1333
return classChainOffsetInSharedCache;
1334
}
1335
#endif // defined(J9VM_OPT_JITSERVER)
1336
1337
const void *
1338
TR_J9SharedCache::storeSharedData(J9VMThread *vmThread, char *key, J9SharedDataDescriptor *descriptor)
1339
{
1340
#if defined(J9VM_OPT_SHARED_CLASSES) && (defined(TR_HOST_X86) || defined(TR_HOST_POWER) || defined(TR_HOST_S390) || defined(TR_HOST_ARM) || defined(TR_HOST_ARM64))
1341
return _sharedCacheConfig->storeSharedData(
1342
vmThread,
1343
key,
1344
strlen(key),
1345
descriptor);
1346
#else
1347
return NULL;
1348
#endif
1349
}
1350
1351
#if defined(J9VM_OPT_JITSERVER)
1352
TR_J9JITServerSharedCache::TR_J9JITServerSharedCache(TR_J9VMBase *fe)
1353
: TR_J9SharedCache(fe)
1354
{
1355
_stream = NULL;
1356
}
1357
1358
uintptr_t *
1359
TR_J9JITServerSharedCache::rememberClass(J9Class *clazz, const AOTCacheClassChainRecord **classChainRecord, bool create)
1360
{
1361
TR_ASSERT_FATAL(classChainRecord || !create, "Must pass classChainRecord if creating class chain at JITServer");
1362
TR_ASSERT(_stream, "stream must be initialized by now");
1363
1364
uintptr_t *classChain = NULL;
1365
TR::Compilation *comp = TR::compInfoPT->getCompilation();
1366
ClientSessionData *clientData = comp->getClientData();
1367
bool needClassChainRecord = create && comp->isAOTCacheStore();
1368
const AOTCacheClassChainRecord *record = NULL;
1369
1370
// Check if the class chain is already cached
1371
auto &cache = clientData->getClassChainDataMap();
1372
{
1373
OMR::CriticalSection classChainDataMapMonitor(clientData->getClassChainDataMapMonitor());
1374
auto it = cache.find(clazz);
1375
if (it != cache.end())
1376
{
1377
classChain = it->second._classChain;
1378
record = it->second._aotCacheClassChainRecord;
1379
}
1380
}
1381
1382
// If the class chain is cached and the AOT cache record is either cached or not needed, return the cached values
1383
if (classChain && (record || !needClassChainRecord))
1384
{
1385
if (classChainRecord)
1386
*classChainRecord = record;
1387
return classChain;
1388
}
1389
1390
// Request missing class chain information from the client
1391
_stream->write(JITServer::MessageType::SharedCache_rememberClass, clazz, create, needClassChainRecord);
1392
auto recv = _stream->read<uintptr_t *, std::vector<J9Class *>, std::vector<J9Class *>,
1393
std::vector<JITServerHelpers::ClassInfoTuple>>();
1394
if (classChain)
1395
TR_ASSERT_FATAL(std::get<0>(recv) == classChain, "Received mismatching class chain: %p != %p",
1396
std::get<0>(recv), classChain);
1397
classChain = std::get<0>(recv);
1398
auto &ramClassChain = std::get<1>(recv);
1399
auto &uncachedRAMClasses = std::get<2>(recv);
1400
auto &uncachedClassInfos = std::get<3>(recv);
1401
1402
// Cache the result if the class chain was succesfully created at the client
1403
if (classChain && create)
1404
{
1405
if (needClassChainRecord)
1406
{
1407
JITServerHelpers::cacheRemoteROMClassBatch(clientData, uncachedRAMClasses, uncachedClassInfos);
1408
// This call will cache both the class chain and the AOT cache record in the client session
1409
record = clientData->getClassChainRecord(clazz, classChain, ramClassChain, _stream);
1410
if (classChainRecord)
1411
*classChainRecord = record;
1412
}
1413
else
1414
{
1415
OMR::CriticalSection classChainDataMapMonitor(clientData->getClassChainDataMapMonitor());
1416
cache.insert({ clazz, { classChain, NULL } });
1417
}
1418
}
1419
1420
return classChain;
1421
}
1422
1423
J9SharedClassCacheDescriptor *
1424
TR_J9JITServerSharedCache::getCacheDescriptorList()
1425
{
1426
auto *vmInfo = TR::compInfoPT->getClientData()->getOrCacheVMInfo(_stream);
1427
return vmInfo->_j9SharedClassCacheDescriptorList;
1428
}
1429
1430
uintptr_t
1431
TR_J9JITServerSharedCache::getClassChainOffsetIdentifyingLoader(TR_OpaqueClassBlock *clazz, uintptr_t **classChain)
1432
{
1433
TR_ASSERT(!classChain, "Must always be NULL at JITServer");
1434
TR_ASSERT(_stream, "stream must be initialized by now");
1435
1436
uintptr_t classChainOffset = 0;
1437
ClientSessionData *clientData = TR::compInfoPT->getClientData();
1438
JITServerHelpers::getAndCacheRAMClassInfo((J9Class *)clazz, clientData, _stream,
1439
JITServerHelpers::CLASSINFO_CLASS_CHAIN_OFFSET_IDENTIFYING_LOADER,
1440
(void *)&classChainOffset);
1441
// Test if cached value of `classChainOffset` is initialized. Ask the client if it's not.
1442
// This situation is possible if we cache ClassInfo during a non-AOT compilation.
1443
if (classChainOffset == 0)
1444
{
1445
// Request the class name identifying loader if this client uses AOT cache
1446
// (even if the result of this specific compilation won't be stored in AOT cache)
1447
bool getName = clientData->usesAOTCache();
1448
_stream->write(JITServer::MessageType::SharedCache_getClassChainOffsetIdentifyingLoader, clazz, getName);
1449
auto recv = _stream->read<uintptr_t, std::string>();
1450
classChainOffset = std::get<0>(recv);
1451
auto &className = std::get<1>(recv);
1452
1453
// If we got a valid value back, cache that
1454
if (classChainOffset)
1455
{
1456
OMR::CriticalSection getRemoteROMClass(clientData->getROMMapMonitor());
1457
auto it = clientData->getROMClassMap().find((J9Class *)clazz);
1458
if (it != clientData->getROMClassMap().end())
1459
{
1460
it->second._classChainOffsetIdentifyingLoader = classChainOffset;
1461
if (getName)
1462
it->second._classNameIdentifyingLoader = className;
1463
}
1464
}
1465
}
1466
return classChainOffset;
1467
}
1468
1469
void
1470
TR_J9JITServerSharedCache::addHint(J9Method * method, TR_SharedCacheHint theHint)
1471
{
1472
TR_ASSERT(_stream, "stream must be initialized by now");
1473
auto *vmInfo = TR::compInfoPT->getClientData()->getOrCacheVMInfo(_stream);
1474
if (vmInfo->_hasSharedClassCache)
1475
{
1476
_stream->write(JITServer::MessageType::SharedCache_addHint, method, theHint);
1477
_stream->read<JITServer::Void>();
1478
}
1479
}
1480
1481
const void *
1482
TR_J9JITServerSharedCache::storeSharedData(J9VMThread *vmThread, char *key, J9SharedDataDescriptor *descriptor)
1483
{
1484
TR_ASSERT(_stream, "stream must be initialized by now");
1485
std::string dataStr((char *) descriptor->address, descriptor->length);
1486
1487
_stream->write(JITServer::MessageType::SharedCache_storeSharedData, std::string(key, strlen(key)), *descriptor, dataStr);
1488
return std::get<0>(_stream->read<const void *>());
1489
}
1490
1491
#endif
1492
1493