Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/env/CHTable.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2021 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/CHTable.hpp"
24
25
#include "codegen/CodeGenerator.hpp"
26
#include "env/FrontEnd.hpp"
27
#include "env/CompilerEnv.hpp"
28
#include "env/KnownObjectTable.hpp"
29
#include "compile/CompilationTypes.hpp"
30
#include "compile/ResolvedMethod.hpp"
31
#include "compile/VirtualGuard.hpp"
32
#include "control/Options.hpp"
33
#include "control/Options_inlines.hpp"
34
#include "control/Recompilation.hpp"
35
#include "control/RecompilationInfo.hpp"
36
#include "env/CompilerEnv.hpp"
37
#include "env/PersistentCHTable.hpp"
38
#include "env/PersistentInfo.hpp"
39
#include "env/jittypes.h"
40
#include "env/j9method.h"
41
#include "env/ClassTableCriticalSection.hpp"
42
#include "env/VMAccessCriticalSection.hpp"
43
#include "env/VMJ9.h"
44
#include "env/VerboseLog.hpp"
45
#include "il/MethodSymbol.hpp"
46
#include "il/ResolvedMethodSymbol.hpp"
47
#include "il/Symbol.hpp"
48
#include "il/SymbolReference.hpp"
49
#include "infra/Array.hpp"
50
#include "infra/Assert.hpp"
51
#include "infra/List.hpp"
52
#include "optimizer/PreExistence.hpp"
53
#if defined(J9VM_OPT_JITSERVER)
54
#include "env/j9methodServer.hpp"
55
#include "control/JITServerCompilationThread.hpp"
56
#endif /* defined(J9VM_OPT_JITSERVER) */
57
58
void
59
TR_PreXRecompile::dumpInfo()
60
{
61
OMR::RuntimeAssumption::dumpInfo("TR_PreXRecompile");
62
TR_VerboseLog::write(" startPC=%p", _startPC);
63
}
64
65
void
66
TR::PatchNOPedGuardSite::dumpInfo()
67
{
68
OMR::RuntimeAssumption::dumpInfo("TR::PatchNOPedGuardSite");
69
TR_VerboseLog::write(" location=%p destination=%p", _location, _destination);
70
}
71
72
void
73
TR::PatchMultipleNOPedGuardSites::dumpInfo()
74
{
75
OMR::RuntimeAssumption::dumpInfo("TR::PatchMultipleNOPedGuardSites");
76
for (int i = 0; i < _patchSites->getSize(); ++i)
77
TR_VerboseLog::write(" %d location=%p destination=%p", i, _patchSites->getLocation(i), _patchSites->getDestination(i));
78
}
79
80
void
81
TR_PatchJNICallSite::dumpInfo()
82
{
83
OMR::RuntimeAssumption::dumpInfo("TR_PatchJNICallSite");
84
TR_VerboseLog::write(" pc=%p", _pc );
85
}
86
87
TR_PatchNOPedGuardSiteOnClassExtend *TR_PatchNOPedGuardSiteOnClassExtend::make(
88
TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, uint8_t *loc, uint8_t *dest, OMR::RuntimeAssumption **sentinel)
89
{
90
TR_PatchNOPedGuardSiteOnClassExtend *result = new (pm) TR_PatchNOPedGuardSiteOnClassExtend(pm, clazz, loc, dest);
91
result->addToRAT(pm, RuntimeAssumptionOnClassExtend, fe, sentinel);
92
return result;
93
}
94
95
TR_PatchNOPedGuardSiteOnMethodOverride *TR_PatchNOPedGuardSiteOnMethodOverride::make(
96
TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueMethodBlock *method, uint8_t *loc, uint8_t *dest, OMR::RuntimeAssumption **sentinel)
97
{
98
TR_PatchNOPedGuardSiteOnMethodOverride *result = new (pm) TR_PatchNOPedGuardSiteOnMethodOverride(pm, method, loc, dest);
99
result->addToRAT(pm, RuntimeAssumptionOnMethodOverride, fe, sentinel);
100
return result;
101
}
102
103
TR_PatchNOPedGuardSiteOnClassRedefinition *TR_PatchNOPedGuardSiteOnClassRedefinition::make(
104
TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, uint8_t *loc, uint8_t *dest, OMR::RuntimeAssumption **sentinel)
105
{
106
TR_PatchNOPedGuardSiteOnClassRedefinition *result = new (pm) TR_PatchNOPedGuardSiteOnClassRedefinition(pm, clazz, loc, dest);
107
result->addToRAT(pm, RuntimeAssumptionOnClassRedefinitionNOP, fe, sentinel);
108
return result;
109
}
110
111
TR_PatchMultipleNOPedGuardSitesOnClassRedefinition *TR_PatchMultipleNOPedGuardSitesOnClassRedefinition::make(
112
TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, TR::PatchSites *sites, OMR::RuntimeAssumption **sentinel)
113
{
114
TR_PatchMultipleNOPedGuardSitesOnClassRedefinition *result = new (pm) TR_PatchMultipleNOPedGuardSitesOnClassRedefinition(pm, clazz, sites);
115
sites->addReference();
116
result->addToRAT(pm, RuntimeAssumptionOnClassRedefinitionNOP, fe, sentinel);
117
return result;
118
}
119
120
TR_PatchNOPedGuardSiteOnStaticFinalFieldModification *TR_PatchNOPedGuardSiteOnStaticFinalFieldModification::make(
121
TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, uint8_t *loc, uint8_t *dest, OMR::RuntimeAssumption **sentinel)
122
{
123
TR_PatchNOPedGuardSiteOnStaticFinalFieldModification *result = new (pm) TR_PatchNOPedGuardSiteOnStaticFinalFieldModification(pm, clazz, loc, dest);
124
result->addToRAT(pm, RuntimeAssumptionOnStaticFinalFieldModification, fe, sentinel);
125
return result;
126
}
127
128
TR_PatchMultipleNOPedGuardSitesOnStaticFinalFieldModification *TR_PatchMultipleNOPedGuardSitesOnStaticFinalFieldModification::make(
129
TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, TR::PatchSites *sites, OMR::RuntimeAssumption **sentinel)
130
{
131
TR_PatchMultipleNOPedGuardSitesOnStaticFinalFieldModification *result = new (pm) TR_PatchMultipleNOPedGuardSitesOnStaticFinalFieldModification(pm, clazz, sites);
132
sites->addReference();
133
result->addToRAT(pm, RuntimeAssumptionOnStaticFinalFieldModification, fe, sentinel);
134
return result;
135
}
136
137
TR_PatchJNICallSite *TR_PatchJNICallSite::make(
138
TR_FrontEnd *fe, TR_PersistentMemory * pm, uintptr_t key, uint8_t *pc, OMR::RuntimeAssumption **sentinel)
139
{
140
TR_PatchJNICallSite *result = new (pm) TR_PatchJNICallSite(pm, key, pc);
141
result->addToRAT(pm, RuntimeAssumptionOnRegisterNative, fe, sentinel);
142
return result;
143
}
144
145
TR_PreXRecompileOnClassExtend *TR_PreXRecompileOnClassExtend::make(
146
TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueClassBlock *clazz, uint8_t *startPC, OMR::RuntimeAssumption **sentinel)
147
{
148
TR_PreXRecompileOnClassExtend *result = new (pm) TR_PreXRecompileOnClassExtend(pm, clazz, startPC);
149
result->addToRAT(pm, RuntimeAssumptionOnClassExtend, fe, sentinel);
150
return result;
151
}
152
153
TR_PreXRecompileOnMethodOverride *TR_PreXRecompileOnMethodOverride::make(
154
TR_FrontEnd *fe, TR_PersistentMemory *pm, TR_OpaqueMethodBlock *method, uint8_t *startPC, OMR::RuntimeAssumption **sentinel)
155
{
156
TR_PreXRecompileOnMethodOverride *result = new (pm) TR_PreXRecompileOnMethodOverride(pm, method, startPC);
157
result->addToRAT(pm, RuntimeAssumptionOnMethodOverride, fe, sentinel);
158
return result;
159
}
160
161
TR_PatchNOPedGuardSiteOnMutableCallSiteChange *TR_PatchNOPedGuardSiteOnMutableCallSiteChange::make(
162
TR_FrontEnd *fe, TR_PersistentMemory *pm, uintptr_t key, uint8_t *location, uint8_t *destination, OMR::RuntimeAssumption **sentinel)
163
{
164
TR_PatchNOPedGuardSiteOnMutableCallSiteChange *result = new (pm) TR_PatchNOPedGuardSiteOnMutableCallSiteChange(pm, key, location, destination);
165
result->addToRAT(pm, RuntimeAssumptionOnMutableCallSiteChange, fe, sentinel);
166
return result;
167
}
168
169
bool TR_CHTable::recompileOnClassExtend(TR::Compilation *c, TR_OpaqueClassBlock * classId)
170
{
171
// return true or false
172
// depending on whether the class was added to the list
173
//
174
c->setUsesPreexistence(true);
175
if (!_classes)
176
_classes = new (c->trHeapMemory()) TR_Array<TR_OpaqueClassBlock *>(c->trMemory(), 8);
177
if (!_classes->contains(classId))
178
_classes->add(classId);
179
else return false;
180
return true;
181
}
182
183
184
bool TR_CHTable::recompileOnNewClassExtend(TR::Compilation *c, TR_OpaqueClassBlock * classId)
185
{
186
// return true or false
187
// depending on whether the class was added to the list
188
//
189
c->setUsesPreexistence(true);
190
if (!_classesThatShouldNotBeNewlyExtended)
191
_classesThatShouldNotBeNewlyExtended = new (c->trHeapMemory()) TR_Array<TR_OpaqueClassBlock *>(c->trMemory(), 8);
192
if (!_classesThatShouldNotBeNewlyExtended->contains(classId))
193
_classesThatShouldNotBeNewlyExtended->add(classId);
194
else return false;
195
return true;
196
}
197
198
199
200
bool TR_CHTable::recompileOnMethodOverride(TR::Compilation *c, TR_ResolvedMethod *method)
201
{
202
// return true or false
203
// depending on whether the method was added to the list
204
//
205
c->setUsesPreexistence(true);
206
if (!_preXMethods)
207
_preXMethods = new (c->trHeapMemory()) TR_Array<TR_ResolvedMethod*>(c->trMemory(), 16);
208
209
int32_t last = _preXMethods->lastIndex();
210
bool addIt = true;
211
for (int32_t i = 0; i <= last; ++i)
212
{
213
if (_preXMethods->element(i)->getPersistentIdentifier() == method->getPersistentIdentifier())
214
{
215
addIt = false;
216
break;
217
}
218
}
219
220
if (addIt)
221
_preXMethods->add(method);
222
else
223
return false;
224
225
return true;
226
}
227
228
229
// Must hold classTableMonitor when calling this method
230
void TR_CHTable::cleanupNewlyExtendedInfo(TR::Compilation *comp)
231
{
232
if (_classesThatShouldNotBeNewlyExtended)
233
{
234
TR_PersistentCHTable *table = comp->getPersistentInfo()->getPersistentCHTable();
235
int32_t last = _classesThatShouldNotBeNewlyExtended->lastIndex();
236
for (int32_t i = 0; i <= last; ++i)
237
{
238
TR_OpaqueClassBlock * classId = _classesThatShouldNotBeNewlyExtended->element(i);
239
TR_PersistentClassInfo * cl = table->findClassInfo(classId);
240
// The class may have been unloaded during this compilation and the search may return NULL
241
// This method is called even if we abort the compilation. Hence, killing the
242
// compilation after a class unload (which we already do) is not enough
243
// If we get really unlucky a new class could be unloaded exactly in the place of the
244
// unloaded one (the window of time is very small for this to occur). However, resetting
245
// the flag for the newly loaded class is not going to create any problems (it's
246
// supposed to be reset to start with)
247
if (cl)
248
cl->resetShouldNotBeNewlyExtended(comp->getCompThreadID());
249
}
250
}
251
}
252
253
254
bool TR_CHTable::canSkipCommit(TR::Compilation *comp)
255
{
256
return comp->compileRelocatableCode() ||
257
(comp->getVirtualGuards().empty() &&
258
comp->getSideEffectGuardPatchSites()->empty() &&
259
!_preXMethods && !_classes && !_classesThatShouldNotBeNewlyExtended);
260
}
261
262
263
// Returning false here will fail this compilation!
264
//
265
bool TR_CHTable::commit(TR::Compilation *comp)
266
{
267
#if defined(J9VM_OPT_JITSERVER)
268
if (comp->isOutOfProcessCompilation())
269
{
270
return true; // Handled in outOfProcessCompilationEnd instead
271
}
272
#endif /* defined(J9VM_OPT_JITSERVER) */
273
if (canSkipCommit(comp))
274
return true;
275
276
TR::list<TR_VirtualGuard*> &vguards = comp->getVirtualGuards();
277
TR::list<TR_VirtualGuardSite*> *sideEffectPatchSites = comp->getSideEffectGuardPatchSites();
278
279
cleanupNewlyExtendedInfo(comp);
280
if (comp->getFailCHTableCommit())
281
return false;
282
283
TR_PersistentCHTable *table = comp->getPersistentInfo()->getPersistentCHTable();
284
TR_ResolvedMethod *currentMethod = comp->getCurrentMethod();
285
uint8_t *startPC = comp->cg()->getCodeStart();
286
TR_Hotness hotness = comp->getMethodHotness();
287
288
if (_preXMethods)
289
{
290
int32_t last = _preXMethods->lastIndex(), i;
291
for (i = 0; i <= last; ++i)
292
if (_preXMethods->element(i)->virtualMethodIsOverridden())
293
return false;
294
295
for (i = 0; i <= last; ++i)
296
{
297
TR_ResolvedMethod *resolvedMethod = _preXMethods->element(i);
298
TR_OpaqueMethodBlock *method = resolvedMethod->getPersistentIdentifier();
299
TR_PreXRecompileOnMethodOverride::make(comp->fe(), comp->trPersistentMemory(), method, startPC, comp->getMetadataAssumptionList());
300
comp->setHasMethodOverrideAssumptions();
301
}
302
}
303
304
if (_classes)
305
{
306
int32_t last = _classes->lastIndex();
307
for (int32_t i = 0; i <= last; ++i)
308
{
309
TR_OpaqueClassBlock * classId = _classes->element(i);
310
311
// check if we may have already added this class to the persistent table
312
//
313
bool alreadyAdded = false;
314
for (int32_t j = 0; j < i && !alreadyAdded; ++j)
315
{
316
TR_OpaqueClassBlock * other = _classes->element(j);
317
if (other == classId)
318
alreadyAdded = true;
319
}
320
321
if (!alreadyAdded)
322
{
323
if (comp->fe()->classHasBeenExtended(classId))
324
return false;
325
326
TR_PreXRecompileOnClassExtend::make(comp->fe(), comp->trPersistentMemory(), classId, startPC, comp->getMetadataAssumptionList());
327
comp->setHasClassExtendAssumptions();
328
}
329
}
330
}
331
332
if (_classesThatShouldNotBeNewlyExtended)
333
{
334
int32_t last = _classesThatShouldNotBeNewlyExtended->lastIndex();
335
336
// keep a list of classes that were set visited so that we can
337
// easily reset the visited flag later-on
338
VisitTracker tracker(comp->trMemory());
339
for (int32_t i = 0; i <= last; ++i)
340
{
341
TR_OpaqueClassBlock * classId = _classesThatShouldNotBeNewlyExtended->element(i);
342
TR_PersistentClassInfo * cl = table->findClassInfo(classId);
343
if (cl && !cl->hasBeenVisited()) // is it possible to have cl==0
344
{
345
tracker.visit(cl);
346
}
347
}
348
349
bool invalidAssumption = false;
350
auto it = tracker.iterator();
351
for (auto cl = it.getFirst(); cl; cl = it.getNext())
352
{
353
// If the class has been extended verify that was included in the original list
354
// Otherwise it means that the extension happened afterwards and we should fail this compilation
355
if (comp->fe()->classHasBeenExtended(cl->getClassId()))
356
{
357
for (TR_SubClass *subClass = cl->getFirstSubclass(); subClass; subClass = subClass->getNext())
358
{
359
TR_PersistentClassInfo *subClassInfo = subClass->getClassInfo();
360
if (!subClassInfo->hasBeenVisited())
361
{
362
invalidAssumption = true;
363
break;
364
}
365
}
366
}
367
368
if (invalidAssumption)
369
break;
370
371
TR_PreXRecompileOnClassExtend::make(comp->fe(), comp->trPersistentMemory(), cl->getClassId(), startPC, comp->getMetadataAssumptionList());
372
comp->setHasClassExtendAssumptions();
373
}
374
375
if (invalidAssumption) return false;
376
} // if (_classesThatShouldNotBeNewlyExtended)
377
378
// Check if the assumptions for static final field are still valid
379
// Returning false will cause CHTable opts to be disabled in the next compilation of this method,
380
// thus we abort the compilation here to avoid causing performance issues
381
TR_Array<TR_OpaqueClassBlock*> *clazzesOnStaticFinalFieldModification = comp->getClassesForStaticFinalFieldModification();
382
for (int i = 0; i < clazzesOnStaticFinalFieldModification->size(); ++i)
383
{
384
TR_OpaqueClassBlock* clazz = (*clazzesOnStaticFinalFieldModification)[i];
385
if (TR::Compiler->cls.classHasIllegalStaticFinalFieldModification(clazz))
386
{
387
if (TR::Options::isAnyVerboseOptionSet(TR_VerboseRuntimeAssumptions, TR_VerboseCompileEnd, TR_VerbosePerformance, TR_VerboseCompFailure))
388
{
389
TR_VerboseLog::writeLineLocked(TR_Vlog_FAILURE, "Failure while commiting static final field assumption for class %p for %s", clazz, comp->signature());
390
}
391
comp->failCompilation<TR::CompilationInterrupted>("Compilation interrupted: Static final field of a class has been modified");
392
}
393
}
394
395
if (!vguards.empty())
396
{
397
static bool dontGroupOSRAssumptions = (feGetEnv("TR_DontGroupOSRAssumptions") != NULL);
398
if (!dontGroupOSRAssumptions)
399
commitOSRVirtualGuards(comp, vguards);
400
401
for (auto info = vguards.begin(); info != vguards.end(); ++info)
402
{
403
List<TR_VirtualGuardSite> &sites = (*info)->getNOPSites();
404
if (sites.isEmpty())
405
continue;
406
407
// Commit the virtual guard itself
408
//
409
commitVirtualGuard(*info, sites, table, comp);
410
411
// Commit any inner guards that are assuming on this guard
412
//
413
ListIterator<TR_InnerAssumption> it(&((*info)->getInnerAssumptions()));
414
for (TR_InnerAssumption *inner = it.getFirst(); inner; inner = it.getNext())
415
commitVirtualGuard(inner->_guard, sites, table, comp);
416
}
417
}
418
419
if (!sideEffectPatchSites->empty())
420
table->commitSideEffectGuards(comp);
421
422
return true;
423
}
424
425
void
426
TR_CHTable::commitOSRVirtualGuards(TR::Compilation *comp, TR::list<TR_VirtualGuard*> &vguards)
427
{
428
// Count patch sites with OSR assumptions
429
int osrSites = 0;
430
TR_VirtualGuardSite *onlySite = NULL;
431
for (auto info = vguards.begin(); info != vguards.end(); ++info)
432
{
433
if ((*info)->getKind() == TR_OSRGuard || (*info)->mergedWithOSRGuard())
434
{
435
List<TR_VirtualGuardSite> &sites = (*info)->getNOPSites();
436
if (sites.getSize() > 0)
437
onlySite = sites.getListHead()->getData();
438
osrSites += sites.getSize();
439
}
440
}
441
442
TR_Array<TR_OpaqueClassBlock*> *clazzesForOSRRedefinition = comp->getClassesForOSRRedefinition();
443
TR_Array<TR_OpaqueClassBlock*> *clazzesForStaticFinalFieldModification = comp->getClassesForStaticFinalFieldModification();
444
if (osrSites == 0
445
|| (clazzesForOSRRedefinition->size() == 0
446
&& clazzesForStaticFinalFieldModification->size() == 0))
447
{
448
return;
449
}
450
else if (osrSites == 1)
451
{
452
// Only one patch point, create an assumption for each class
453
for (int i = 0; i < clazzesForOSRRedefinition->size(); ++i)
454
TR_PatchNOPedGuardSiteOnClassRedefinition
455
::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForOSRRedefinition)[i], onlySite->getLocation(), onlySite->getDestination(), comp->getMetadataAssumptionList());
456
457
for (int i = 0; i < clazzesForStaticFinalFieldModification->size(); ++i)
458
TR_PatchNOPedGuardSiteOnStaticFinalFieldModification
459
::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForStaticFinalFieldModification)[i], onlySite->getLocation(), onlySite->getDestination(), comp->getMetadataAssumptionList());
460
}
461
else if (osrSites > 1)
462
{
463
// Several points to patch, create collection
464
TR::PatchSites *points = new (comp->trPersistentMemory()) TR::PatchSites(comp->trPersistentMemory(), osrSites);
465
for (auto info = vguards.begin(); info != vguards.end(); ++info)
466
{
467
if ((*info)->getKind() == TR_OSRGuard || (*info)->mergedWithOSRGuard())
468
{
469
List<TR_VirtualGuardSite> &sites = (*info)->getNOPSites();
470
ListIterator<TR_VirtualGuardSite> it(&sites);
471
for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())
472
points->add(site->getLocation(), site->getDestination());
473
}
474
}
475
476
for (int i = 0; i < clazzesForOSRRedefinition->size(); ++i)
477
TR_PatchMultipleNOPedGuardSitesOnClassRedefinition
478
::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForOSRRedefinition)[i], points, comp->getMetadataAssumptionList());
479
480
for (int i = 0; i < clazzesForStaticFinalFieldModification->size(); ++i)
481
TR_PatchMultipleNOPedGuardSitesOnStaticFinalFieldModification
482
::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForStaticFinalFieldModification)[i], points, comp->getMetadataAssumptionList());
483
}
484
485
if (clazzesForOSRRedefinition->size() > 0)
486
comp->setHasClassRedefinitionAssumptions();
487
return;
488
}
489
490
void
491
TR_CHTable::commitVirtualGuard(TR_VirtualGuard *info, List<TR_VirtualGuardSite> &sites,
492
TR_PersistentCHTable *table, TR::Compilation *comp)
493
{
494
// If this is an OSR guard or another kind that has been marked as necessary to patch
495
// in OSR, add a runtime assumption for every class that generated fear
496
//
497
if (info->getKind() == TR_OSRGuard || info->mergedWithOSRGuard())
498
{
499
static bool dontGroupOSRAssumptions = (feGetEnv("TR_DontGroupOSRAssumptions") != NULL);
500
if (dontGroupOSRAssumptions)
501
{
502
TR_Array<TR_OpaqueClassBlock*> *clazzesForRedefinition = comp->getClassesForOSRRedefinition();
503
TR_Array<TR_OpaqueClassBlock*> *clazzesForStaticFinalFieldModification = comp->getClassesForStaticFinalFieldModification();
504
505
if (clazzesForRedefinition || clazzesForStaticFinalFieldModification)
506
{
507
ListIterator<TR_VirtualGuardSite> it(&sites);
508
for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())
509
{
510
for (uint32_t i = 0; i < clazzesForRedefinition->size(); ++i)
511
TR_PatchNOPedGuardSiteOnClassRedefinition
512
::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForRedefinition)[i], site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());
513
514
if (clazzesForRedefinition->size() > 0)
515
comp->setHasClassRedefinitionAssumptions();
516
517
// Add assumption for static final field folding
518
for (uint32_t i = 0; i < clazzesForStaticFinalFieldModification->size(); ++i)
519
TR_PatchNOPedGuardSiteOnStaticFinalFieldModification
520
::make(comp->fe(), comp->trPersistentMemory(), (*clazzesForStaticFinalFieldModification)[i], site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());
521
}
522
}
523
}
524
525
// if it's not real OSR guard then we need to register
526
// both the OSR site and the guard
527
if (!info->mergedWithOSRGuard())
528
return;
529
if (!info->isNopable())
530
return;
531
}
532
533
TR::SymbolReference *symRef = info->getSymbolReference();
534
TR::MethodSymbol *methodSymbol = symRef->getSymbol()->castToMethodSymbol();
535
TR::ResolvedMethodSymbol *resolvedMethodSymbol = methodSymbol->getResolvedMethodSymbol();
536
TR_ResolvedMethod *guardedMethod = 0;
537
TR_OpaqueClassBlock *guardedClass = 0;
538
bool nopAssumptionIsValid = true;
539
int32_t cpIndex = symRef->getCPIndex();
540
TR_ResolvedMethod *owningMethod = symRef->getOwningMethod(comp);
541
542
if ((info->getKind() == TR_HCRGuard) || info->mergedWithHCRGuard())
543
{
544
guardedClass = info->getThisClass();
545
ListIterator<TR_VirtualGuardSite> it(&sites);
546
for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())
547
{
548
TR_ASSERT(site->getLocation(), "assertion failure");
549
TR_PatchNOPedGuardSiteOnClassRedefinition
550
::make(comp->fe(), comp->trPersistentMemory(), guardedClass, site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());
551
comp->setHasClassRedefinitionAssumptions();
552
}
553
// if it's not real HCR guard then we need to register
554
// both the HCR site and the guard
555
if (!info->mergedWithHCRGuard())
556
return;
557
if (!info->isNopable())
558
return;
559
}
560
561
if (info->getKind() == TR_DummyGuard)
562
{
563
/* nothing to do */
564
}
565
else if (info->getKind() == TR_MutableCallSiteTargetGuard)
566
{
567
static char *dontInvalidateMCSTargetGuards = feGetEnv("TR_dontInvalidateMCSTargetGuards");
568
if (!dontInvalidateMCSTargetGuards)
569
{
570
#if defined(J9VM_OPT_JITSERVER)
571
// JITServer KOT: At the moment this method is called only by TR_CHTable::commit().
572
// TR_CHTable::commit() already checks comp->isOutOfProcessCompilation().
573
// Adding the following check as a precaution in case commitVirtualGuard() is called
574
// outside TR_CHTable::commit() in the future.
575
TR_ASSERT(!comp->isOutOfProcessCompilation(), "TR_CHTable::commitVirtualGuard() should not be called at the server\n");
576
#endif /* defined(J9VM_OPT_JITSERVER) */
577
uintptr_t *mcsReferenceLocation = info->mutableCallSiteObject();
578
TR::KnownObjectTable *knot = comp->getKnownObjectTable();
579
TR_ASSERT(knot, "MutableCallSiteTargetGuard requires the Known Object Table");
580
void *cookiePointer = comp->trPersistentMemory()->allocatePersistentMemory(1);
581
uintptr_t potentialCookie = (uintptr_t)(uintptr_t)cookiePointer;
582
uintptr_t cookie = 0;
583
584
TR::KnownObjectTable::Index currentIndex;
585
586
{
587
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
588
TR::VMAccessCriticalSection invalidateMCSTargetGuards(fej9);
589
currentIndex = fej9->mutableCallSiteEpoch(comp, *mcsReferenceLocation);
590
if (info->mutableCallSiteEpoch() == currentIndex)
591
cookie = fej9->mutableCallSiteCookie(*mcsReferenceLocation, potentialCookie);
592
else
593
nopAssumptionIsValid = false;
594
}
595
596
if (cookie != potentialCookie)
597
comp->trPersistentMemory()->freePersistentMemory(cookiePointer);
598
599
if (nopAssumptionIsValid)
600
{
601
ListIterator<TR_VirtualGuardSite> it(&sites);
602
for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())
603
{
604
TR_ASSERT(site->getLocation(), "assertion failure");
605
TR_PatchNOPedGuardSiteOnMutableCallSiteChange
606
::make(comp->fe(), comp->trPersistentMemory(), cookie, site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());
607
}
608
}
609
else if (comp->getOption(TR_TraceCG))
610
traceMsg(comp, "MutableCallSiteTargetGuard is already invalid. Expected epoch: obj%d Found: obj%d\n", info->mutableCallSiteEpoch(), currentIndex);
611
}
612
}
613
else if ((info->getKind() == TR_MethodEnterExitGuard) || (info->getKind() == TR_DirectMethodGuard))
614
{
615
/* nothing to do */
616
}
617
else if (info->getKind() == TR_BreakpointGuard)
618
{
619
if (comp->getOption(TR_DisableNopBreakpointGuard))
620
return;
621
TR_ResolvedMethod *breakpointedMethod = comp->getInlinedResolvedMethod(info->getCalleeIndex());
622
TR_OpaqueMethodBlock *method = breakpointedMethod->getPersistentIdentifier();
623
if (comp->fej9()->isMethodBreakpointed(method))
624
{
625
nopAssumptionIsValid = false;
626
}
627
else
628
{
629
ListIterator<TR_VirtualGuardSite> it(&sites);
630
for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())
631
{
632
TR_PatchNOPedGuardSiteOnMethodBreakPoint
633
::make(comp->fe(), comp->trPersistentMemory(), method, site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());
634
}
635
}
636
}
637
else if (info->getKind() == TR_ArrayStoreCheckGuard)
638
{
639
guardedClass = info->getThisClass();
640
if (comp->fe()->classHasBeenExtended(guardedClass))
641
nopAssumptionIsValid = false;
642
}
643
else if (!resolvedMethodSymbol)
644
{
645
TR_ASSERT(methodSymbol->isInterface() && info->getKind() == TR_InterfaceGuard, "assertion failure");
646
TR_OpaqueClassBlock *thisClass = info->getThisClass();
647
TR_ASSERT(thisClass, "assertion failure");
648
649
TR_ResolvedMethod *implementer = table->findSingleImplementer(thisClass, cpIndex, owningMethod, comp, true, TR_yes);
650
if (!implementer ||
651
(info->getTestType() == TR_VftTest && comp->fe()->classHasBeenExtended(implementer->containingClass())))
652
nopAssumptionIsValid = false;
653
else
654
TR_ClassQueries::addAnAssumptionForEachSubClass(table, table->findClassInfo(thisClass), sites, comp);
655
}
656
else if (info->getKind() == TR_NonoverriddenGuard && info->getTestType() != TR_VftTest)
657
{
658
TR_ASSERT(info->getTestType() == TR_NonoverriddenTest, "unexpected test type for a non-overridden guard.");
659
660
guardedMethod = resolvedMethodSymbol->getResolvedMethod();
661
if (guardedMethod->virtualMethodIsOverridden())
662
nopAssumptionIsValid = false;
663
}
664
else if ((!info->isInlineGuard() &&
665
!TR::Compiler->cls.isAbstractClass(comp, resolvedMethodSymbol->getResolvedMethod()->containingClass())) ||
666
(info->isInlineGuard() && info->getKind() == TR_HierarchyGuard && info->getTestType() == TR_MethodTest))
667
{
668
guardedMethod = resolvedMethodSymbol->getResolvedMethod();
669
TR_ASSERT(guardedMethod, "Method must have been found when creating assumption\n");
670
671
TR_DevirtualizedCallInfo *dc;
672
TR_OpaqueClassBlock *thisClass = info->isInlineGuard() ? info->getThisClass()
673
: ((dc = comp->findDevirtualizedCall(info->getCallNode())) ? dc->_thisType :
674
guardedMethod->classOfMethod());
675
676
//temp fix for defect 57599 until we find root cause
677
if (table->isOverriddenInThisHierarchy(guardedMethod, thisClass, symRef->getOffset(), comp))
678
nopAssumptionIsValid = false;
679
}
680
else if (info->isInlineGuard() &&
681
info->getTestType() == TR_VftTest &&
682
(info->getKind() == TR_NonoverriddenGuard || info->getKind() == TR_HierarchyGuard))
683
{
684
guardedClass = info->getThisClass();
685
if (comp->fe()->classHasBeenExtended(guardedClass))
686
nopAssumptionIsValid = false;
687
}
688
else if ((!info->isInlineGuard() &&
689
TR::Compiler->cls.isAbstractClass(comp, resolvedMethodSymbol->getResolvedMethod()->containingClass())) ||
690
(info->isInlineGuard() && info->getKind() == TR_AbstractGuard && info->getTestType() == TR_MethodTest))
691
{
692
TR_OpaqueClassBlock *thisClass = info->isInlineGuard() ? thisClass = info->getThisClass()
693
: resolvedMethodSymbol->getResolvedMethod()->containingClass();
694
if (table->findSingleAbstractImplementer(thisClass, symRef->getOffset(), owningMethod, comp, true))
695
TR_ClassQueries::addAnAssumptionForEachSubClass(table, table->findClassInfo(thisClass), sites, comp);
696
else
697
nopAssumptionIsValid = false;
698
}
699
else
700
{
701
TR_ASSERT(false, "should be unreachable");
702
nopAssumptionIsValid = false;
703
}
704
705
if (nopAssumptionIsValid)
706
{
707
ListIterator<TR_VirtualGuardSite> it(&sites);
708
for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())
709
{
710
TR_ASSERT(site->getLocation(), "assertion failure");
711
if (guardedClass)
712
{
713
TR_PatchNOPedGuardSiteOnClassExtend
714
::make(comp->fe(), comp->trPersistentMemory(), guardedClass, site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());
715
comp->setHasClassExtendAssumptions();
716
}
717
if (guardedMethod)
718
{
719
TR_PatchNOPedGuardSiteOnMethodOverride
720
::make(comp->fe(), comp->trPersistentMemory(), guardedMethod->getPersistentIdentifier(),
721
site->getLocation(), site->getDestination(), comp->getMetadataAssumptionList());
722
comp->setHasMethodOverrideAssumptions();
723
}
724
}
725
}
726
else // assumption is invalid
727
{
728
ListIterator<TR_VirtualGuardSite> it(&sites);
729
for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())
730
{
731
if (comp->getOption(TR_TraceCG))
732
traceMsg(comp, " Patching %p to %p\n", site->getLocation(), site->getDestination());
733
TR::PatchNOPedGuardSite::compensate(0, site->getLocation(), site->getDestination());
734
}
735
}
736
}
737
738
#if defined(J9VM_OPT_JITSERVER)
739
VirtualGuardInfoForCHTable getImportantVGuardInfo(TR::Compilation *comp, TR_VirtualGuard *vguard)
740
{
741
VirtualGuardInfoForCHTable info;
742
info._testType = vguard->getTestType();
743
info._kind = vguard->getKind();
744
info._calleeIndex = vguard->getCalleeIndex();
745
info._byteCodeIndex = vguard->getByteCodeIndex();
746
747
// info below is not used if there are no nop sites
748
if (vguard->getNOPSites().isEmpty())
749
return info;
750
751
TR::SymbolReference *symRef = vguard->getSymbolReference();
752
if (symRef)
753
{
754
TR::MethodSymbol *methodSymbol = symRef->getSymbol()->castToMethodSymbol();
755
TR::ResolvedMethodSymbol *resolvedMethodSymbol = methodSymbol->getResolvedMethodSymbol();
756
info._hasResolvedMethodSymbol = resolvedMethodSymbol != NULL;
757
info._cpIndex = symRef->getCPIndex();
758
info._owningMethod = static_cast<TR_ResolvedJ9JITServerMethod*>(symRef->getOwningMethod(comp))->getRemoteMirror();
759
info._isInterface = methodSymbol->isInterface();
760
info._guardedMethod = resolvedMethodSymbol ? static_cast<TR_ResolvedJ9JITServerMethod*>(resolvedMethodSymbol->getResolvedMethod())->getRemoteMirror() : NULL;
761
info._offset = symRef->getOffset();
762
763
info._isInlineGuard = vguard->isInlineGuard();
764
TR_DevirtualizedCallInfo *dc;
765
766
if (resolvedMethodSymbol)
767
info._guardedMethodThisClass = vguard->isInlineGuard()
768
? vguard->getThisClass()
769
: ((dc = comp->findDevirtualizedCall(vguard->getCallNode()))
770
? dc->_thisType
771
: resolvedMethodSymbol->getResolvedMethod()->classOfMethod());
772
}
773
774
info._thisClass = vguard->getThisClass();
775
info._mergedWithHCRGuard = vguard->mergedWithHCRGuard();
776
info._mergedWithOSRGuard = vguard->mergedWithOSRGuard();
777
778
info._mutableCallSiteObject = info._kind == TR_MutableCallSiteTargetGuard ? vguard->mutableCallSiteObject() : NULL;
779
info._mutableCallSiteEpoch = info._kind == TR_MutableCallSiteTargetGuard ? vguard->mutableCallSiteEpoch() : -1;
780
781
info._inlinedResolvedMethod = info._kind == TR_BreakpointGuard
782
? static_cast<TR_ResolvedJ9JITServerMethod *>(comp->getInlinedResolvedMethod(info._calleeIndex))->getRemoteMirror()
783
: NULL;
784
785
return info;
786
}
787
788
CHTableCommitData
789
TR_CHTable::computeDataForCHTableCommit(TR::Compilation *comp)
790
{
791
// collect info from TR_CHTable
792
std::vector<TR_OpaqueClassBlock*> classes = _classes
793
? std::vector<TR_OpaqueClassBlock*>(&(_classes->element(0)), (&(_classes->element(_classes->lastIndex()))) + 1)
794
: std::vector<TR_OpaqueClassBlock*>();
795
std::vector<TR_OpaqueClassBlock*> classesThatShouldNotBeNewlyExtended = _classesThatShouldNotBeNewlyExtended
796
? std::vector<TR_OpaqueClassBlock*>(&_classesThatShouldNotBeNewlyExtended->element(0), &_classesThatShouldNotBeNewlyExtended->element(_classesThatShouldNotBeNewlyExtended->lastIndex()) + 1)
797
: std::vector<TR_OpaqueClassBlock*>();
798
std::vector<TR_ResolvedMethod*> preXMethods(_preXMethods ? _preXMethods->size() : 0);
799
for (size_t i = 0; i < preXMethods.size(); i++)
800
{
801
TR_ResolvedMethod *method = _preXMethods->element(i);
802
TR_ResolvedJ9JITServerMethod *JITServerMethod = static_cast<TR_ResolvedJ9JITServerMethod*>(method);
803
preXMethods[i] = JITServerMethod->getRemoteMirror();
804
}
805
806
cleanupNewlyExtendedInfo(comp);
807
808
// collect virtual guard info
809
TR::list<TR_VirtualGuard*> &vguards = comp->getVirtualGuards();
810
std::vector<VirtualGuardForCHTable> serialVGuards;
811
serialVGuards.reserve(vguards.size());
812
813
for (TR_VirtualGuard* vguard : vguards)
814
{
815
VirtualGuardInfoForCHTable info = getImportantVGuardInfo(comp, vguard);
816
817
std::vector<TR_VirtualGuardSite> nopSites;
818
819
{
820
List<TR_VirtualGuardSite> &sites = vguard->getNOPSites();
821
ListIterator<TR_VirtualGuardSite> it(&sites);
822
for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())
823
nopSites.push_back(*site);
824
}
825
826
std::vector<VirtualGuardInfoForCHTable> innerAssumptions;
827
{
828
ListIterator<TR_InnerAssumption> it(&vguard->getInnerAssumptions());
829
for (TR_InnerAssumption *inner = it.getFirst(); inner; inner = it.getNext())
830
{
831
VirtualGuardInfoForCHTable innerInfo = getImportantVGuardInfo(comp, vguard);
832
innerAssumptions.push_back(innerInfo);
833
}
834
}
835
836
serialVGuards.push_back(std::make_tuple(info, nopSites, innerAssumptions));
837
}
838
839
TR::list<TR_VirtualGuardSite*> &sideEffectPatchSites = *comp->getSideEffectGuardPatchSites();
840
std::vector<TR_VirtualGuardSite> sideEffectPatchSitesVec;
841
for (TR_VirtualGuardSite *site : sideEffectPatchSites)
842
sideEffectPatchSitesVec.push_back(*site);
843
844
FlatClassLoadCheck compClassesThatShouldNotBeLoaded;
845
for (TR_ClassLoadCheck * clc = comp->getClassesThatShouldNotBeLoaded()->getFirst(); clc; clc = clc->getNext())
846
compClassesThatShouldNotBeLoaded.emplace_back(std::string(clc->_name, clc->_length));
847
848
FlatClassExtendCheck compClassesThatShouldNotBeNewlyExtended;
849
for (TR_ClassExtendCheck * cec = comp->getClassesThatShouldNotBeNewlyExtended()->getFirst(); cec; cec = cec->getNext())
850
compClassesThatShouldNotBeNewlyExtended.emplace_back(cec->_clazz);
851
852
auto *compClassesForOSRRedefinition = comp->getClassesForOSRRedefinition();
853
std::vector<TR_OpaqueClassBlock*> classesForOSRRedefinition(compClassesForOSRRedefinition->size());
854
for (int i = 0; i < compClassesForOSRRedefinition->size(); ++i)
855
classesForOSRRedefinition[i] = (*compClassesForOSRRedefinition)[i];
856
857
auto *compClassesForStaticFinalFieldModification = comp->getClassesForStaticFinalFieldModification();
858
std::vector<TR_OpaqueClassBlock*> classesForStaticFinalFieldModification(compClassesForStaticFinalFieldModification->size());
859
for (int i = 0; i < compClassesForStaticFinalFieldModification->size(); ++i)
860
classesForStaticFinalFieldModification[i] = (*compClassesForStaticFinalFieldModification)[i];
861
862
uint8_t *startPC = comp->cg()->getCodeStart();
863
864
return std::make_tuple(classes,
865
classesThatShouldNotBeNewlyExtended,
866
preXMethods,
867
sideEffectPatchSitesVec,
868
serialVGuards,
869
compClassesThatShouldNotBeLoaded,
870
compClassesThatShouldNotBeNewlyExtended,
871
classesForOSRRedefinition,
872
classesForStaticFinalFieldModification,
873
startPC);
874
}
875
#endif /* defined(J9VM_OPT_JITSERVER) */
876
877
// class used to collect all different implementations of a method
878
class CollectImplementors : public TR_SubclassVisitor
879
{
880
public:
881
CollectImplementors(TR::Compilation * comp, TR_OpaqueClassBlock *topClassId, TR_ResolvedMethod **implArray, int32_t maxCount,
882
TR_ResolvedMethod *callerMethod, int32_t slotOrIndex, TR_YesNoMaybe useGetResolvedInterfaceMethod = TR_maybe) : TR_SubclassVisitor(comp)
883
{
884
_comp = comp;
885
_topClassId = topClassId;
886
_implArray = implArray;
887
_callerMethod = callerMethod;
888
_maxCount = maxCount;
889
_slotOrIndex = slotOrIndex;
890
_count = 0;
891
_topClassIsInterface = TR::Compiler->cls.isInterfaceClass(comp, topClassId);
892
_maxNumVisitedSubClasses = comp->getOptions()->getMaxNumVisitedSubclasses();
893
_numVisitedSubClasses = 0;
894
_useGetResolvedInterfaceMethod = useGetResolvedInterfaceMethod;
895
}
896
897
virtual bool visitSubclass(TR_PersistentClassInfo *cl);
898
int32_t getCount() const { return _count;}
899
bool isInterface();
900
901
protected:
902
bool addImplementor(TR_ResolvedMethod *implementor);
903
904
TR_OpaqueClassBlock * _topClassId;
905
TR_ResolvedMethod ** _implArray;
906
TR_ResolvedMethod * _callerMethod;
907
int32_t _maxCount;
908
int32_t _slotOrIndex;
909
int32_t _count;
910
bool _topClassIsInterface;
911
int32_t _maxNumVisitedSubClasses;
912
int32_t _numVisitedSubClasses;
913
TR_YesNoMaybe _useGetResolvedInterfaceMethod;
914
};// end of class CollectImplementors
915
916
bool
917
CollectImplementors::isInterface()
918
{
919
bool useGetResolvedInterfaceMethod = _topClassIsInterface;
920
921
// refine if requested by a caller
922
if (_useGetResolvedInterfaceMethod != TR_maybe)
923
useGetResolvedInterfaceMethod = _useGetResolvedInterfaceMethod == TR_yes ? true : false;
924
return useGetResolvedInterfaceMethod;
925
}
926
927
bool
928
CollectImplementors::visitSubclass(TR_PersistentClassInfo *cl)
929
{
930
TR_OpaqueClassBlock *classId = cl->getClassId();
931
// verify that our subclass meets all conditions
932
if (TR::Compiler->cls.isConcreteClass(comp(), classId))
933
{
934
int32_t length;
935
char *clazzName = TR::Compiler->cls.classNameChars(comp(), classId, length);
936
TR_ResolvedMethod *method;
937
938
if (isInterface())
939
{
940
method = _callerMethod->getResolvedInterfaceMethod(comp(), classId, _slotOrIndex);
941
}
942
else
943
{
944
method = _callerMethod->getResolvedVirtualMethod(comp(), classId, _slotOrIndex);
945
}
946
947
++_numVisitedSubClasses;
948
if ((_numVisitedSubClasses > _maxNumVisitedSubClasses) || !method)
949
{
950
// set count greater than maxCount, to indicate failure and force exit
951
_count = _maxCount + 1;
952
stopTheWalk();
953
return false;
954
}
955
956
bool added = addImplementor(method);
957
if (added && _count >= _maxCount)
958
stopTheWalk();
959
}
960
return true;
961
}
962
963
bool
964
CollectImplementors::addImplementor(TR_ResolvedMethod *implementor)
965
{
966
TR_ASSERT_FATAL(_count < _maxCount, "Max implementor count exceeded: _maxCount = %d, _count = %d", _maxCount, _count);
967
968
// cannot add an unresolved implementor
969
if (!implementor)
970
return false;
971
// check to see if there are any duplicates
972
int32_t i;
973
for (i = 0; i < _count; ++i)
974
if (implementor->isSameMethod(_implArray[i]))
975
return false; // we already listed this method
976
// brand new implementor
977
_implArray[_count++] = implementor;
978
return true;
979
}
980
981
class CollectCompiledImplementors : public CollectImplementors
982
{
983
public:
984
CollectCompiledImplementors(TR::Compilation * comp, TR_OpaqueClassBlock *topClassId, TR_ResolvedMethod **implArray, int32_t maxCount,
985
TR_ResolvedMethod *callerMethod, int32_t slotOrIndex, TR_Hotness hotness, TR_YesNoMaybe useGetResolvedInterfaceMethod = TR_maybe) : CollectImplementors(comp, topClassId, implArray, maxCount+1, callerMethod, slotOrIndex, useGetResolvedInterfaceMethod)
986
{
987
_hotness = hotness;
988
}
989
virtual bool visitSubclass(TR_PersistentClassInfo *cl);
990
private:
991
TR_Hotness _hotness;
992
};
993
994
bool CollectCompiledImplementors::visitSubclass(TR_PersistentClassInfo *cl)
995
{
996
int32_t currentCount = _count;
997
if (CollectImplementors::visitSubclass(cl))
998
{
999
if (currentCount < _count)
1000
{
1001
if (!TR::Compiler->mtd.isCompiledMethod((_implArray[_count-1])->getPersistentIdentifier()))
1002
{
1003
_count -= 1;
1004
}
1005
else
1006
{
1007
TR_PersistentJittedBodyInfo * bodyInfo = ((TR_ResolvedJ9Method*) _implArray[_count - 1])->getExistingJittedBodyInfo();
1008
if (!bodyInfo || bodyInfo->getHotness() < _hotness)
1009
{
1010
_count -= 1;
1011
}
1012
if (_count >= _maxCount - 1)
1013
{
1014
stopTheWalk();
1015
}
1016
}
1017
}
1018
return true;
1019
}
1020
return false;
1021
}
1022
1023
void
1024
TR_ClassQueries::getSubClasses(TR_PersistentClassInfo *clazz,
1025
TR_ScratchList<TR_PersistentClassInfo> &list, TR_FrontEnd *fe, bool locked)
1026
{
1027
TR::ClassTableCriticalSection getSubClasses(fe, locked);
1028
1029
for (TR_SubClass * subClass = clazz->_subClasses.getFirst(); subClass; subClass = subClass->getNext())
1030
list.add(subClass->getClassInfo());
1031
}
1032
1033
1034
// this method will return the number of implementers stored in the given implArray
1035
// NOTE: if the number is larger than maxCount, it means that the collection failed
1036
// and we should not check the content of the implArray as it may contain bogus data
1037
int32_t
1038
TR_ClassQueries::collectImplementorsCapped(TR_PersistentClassInfo *clazz,
1039
TR_ResolvedMethod **implArray,
1040
int32_t maxCount, int32_t slotOrIndex,
1041
TR_ResolvedMethod *callerMethod,
1042
TR::Compilation *comp, bool locked,
1043
TR_YesNoMaybe useGetResolvedInterfaceMethod)
1044
{
1045
if (comp->getOption(TR_DisableCHOpts))
1046
return maxCount+1; // fail the collection
1047
1048
#if defined(J9VM_OPT_JITSERVER)
1049
if (comp->isOutOfProcessCompilation())
1050
{
1051
return static_cast<TR_ResolvedJ9JITServerMethod *>(callerMethod)->collectImplementorsCapped(
1052
clazz->getClassId(),
1053
maxCount,
1054
slotOrIndex,
1055
useGetResolvedInterfaceMethod,
1056
implArray);
1057
}
1058
#endif
1059
CollectImplementors collector(comp, clazz->getClassId(), implArray, maxCount, callerMethod, slotOrIndex, useGetResolvedInterfaceMethod);
1060
collector.visitSubclass(clazz);
1061
collector.visit(clazz->getClassId(), locked);
1062
return collector.getCount(); // return the number of implementers in the implArray
1063
}
1064
1065
int32_t
1066
TR_ClassQueries::collectCompiledImplementorsCapped(TR_PersistentClassInfo *clazz,
1067
TR_ResolvedMethod **implArray,
1068
int32_t maxCount, int32_t slotOrIndex,
1069
TR_ResolvedMethod *callerMethod,
1070
TR::Compilation *comp,
1071
TR_Hotness hotness, bool locked,
1072
TR_YesNoMaybe useGetResolvedInterfaceMethod)
1073
{
1074
if (comp->getOption(TR_DisableCHOpts))
1075
return maxCount+1; // fail the collection
1076
CollectCompiledImplementors collector(comp, clazz->getClassId(), implArray, maxCount, callerMethod, slotOrIndex, hotness, useGetResolvedInterfaceMethod);
1077
collector.visitSubclass(clazz);
1078
collector.visit(clazz->getClassId(), locked);
1079
return collector.getCount();
1080
}
1081
1082
void
1083
TR_ClassQueries::collectLeafs(TR_PersistentClassInfo *clazz,
1084
TR_ScratchList<TR_PersistentClassInfo> &leafs, TR::Compilation *comp, bool locked)
1085
{
1086
TR::ClassTableCriticalSection collectLeafs(comp->fe(), locked);
1087
1088
// keep a list of classes that were set visited so that we can
1089
// easily reset the visited flag later-on
1090
TR_CHTable::VisitTracker marked(comp->trMemory());
1091
1092
for (TR_SubClass *subClass = clazz->_subClasses.getFirst(); subClass; subClass = subClass->getNext())
1093
if (!subClass->getClassInfo()->hasBeenVisited())
1094
TR_ClassQueries::collectLeafsLocked(subClass->getClassInfo(), leafs, marked);
1095
}
1096
1097
void
1098
TR_ClassQueries::collectLeafsLocked(TR_PersistentClassInfo* clazz,
1099
TR_ScratchList<TR_PersistentClassInfo>& leafs,
1100
TR_CHTable::VisitTracker& marked)
1101
{
1102
marked.visit(clazz);
1103
TR_SubClass* subClass = clazz->_subClasses.getFirst();
1104
if (!subClass)
1105
leafs.add(clazz);
1106
else // visit all non-visited classes
1107
for (; subClass; subClass = subClass->getNext())
1108
if (!subClass->getClassInfo()->hasBeenVisited())
1109
TR_ClassQueries::collectLeafsLocked(subClass->getClassInfo(), leafs, marked);
1110
}
1111
1112
void
1113
TR_ClassQueries::collectAllSubClasses(TR_PersistentClassInfo *clazz,
1114
TR_ScratchList<TR_PersistentClassInfo> *leafs,
1115
TR::Compilation *comp, bool locked)
1116
{
1117
TR::ClassTableCriticalSection collectAllSubClasses(comp->fe(), locked);
1118
1119
// Defect 180426 We used to use the same 'leafs' list for both the result set and to track the list
1120
// of classes on which to call resetVisited(). This raises concerns about possible interactions
1121
// between invocations now that the reset list is held in TR::Compilation. To avoid problems
1122
// we're separating the two issues and using two lists.
1123
TR_CHTable::VisitTracker marked(comp->trMemory());
1124
1125
TR_ClassQueries::collectAllSubClassesLocked(clazz, leafs, marked); // walk
1126
}
1127
1128
/*
1129
* Recursively walk the class tree to find subclasses.
1130
*
1131
* clazz - the current class to find subclasses of.
1132
* leafs - the result set
1133
* marked - list of visited classes (used to clear the visited flags)
1134
*/
1135
void
1136
TR_ClassQueries::collectAllSubClassesLocked(TR_PersistentClassInfo* clazz,
1137
TR_ScratchList<TR_PersistentClassInfo>* leafs,
1138
TR_CHTable::VisitTracker& marked)
1139
{
1140
TR_SubClass * subClass = clazz->_subClasses.getFirst();
1141
1142
for (; subClass; subClass = subClass->getNext())
1143
{
1144
if (!subClass->getClassInfo()->hasBeenVisited())
1145
{
1146
TR_PersistentClassInfo *sc = subClass->getClassInfo();
1147
leafs->add(sc);
1148
marked.visit(sc);
1149
TR_ClassQueries::collectAllSubClassesLocked(sc, leafs, marked);
1150
}
1151
}
1152
}
1153
1154
// class used to collect first layer of non-interface subclasses
1155
class CollectNonIFSubClasses : public TR_SubclassVisitor
1156
{
1157
public:
1158
CollectNonIFSubClasses(TR::Compilation * comp, TR_ScratchList<TR_PersistentClassInfo> &leafs) :
1159
TR_SubclassVisitor(comp), _collection(leafs) {}
1160
virtual bool visitSubclass(TR_PersistentClassInfo *cl)
1161
{
1162
return (TR::Compiler->cls.isInterfaceClass(comp(), cl->getClassId()) ? true : (_collection.add(cl), false));
1163
}
1164
private:
1165
TR_ScratchList<TR_PersistentClassInfo> &_collection;
1166
};// end of class CollectNonIFSubClasses
1167
1168
void
1169
TR_ClassQueries::collectAllNonIFSubClasses(TR_PersistentClassInfo *clazz,
1170
TR_ScratchList<TR_PersistentClassInfo> &leafs, TR::Compilation *comp, bool locked)
1171
{
1172
CollectNonIFSubClasses collector(comp, leafs);
1173
collector.visit(clazz->getClassId(), locked);
1174
}
1175
1176
void
1177
TR_ClassQueries::addAnAssumptionForEachSubClass(TR_PersistentCHTable *table,
1178
TR_PersistentClassInfo *clazz,
1179
List<TR_VirtualGuardSite> &list,
1180
TR::Compilation *comp)
1181
{
1182
// Gather the subtree of classes rooted at clazz
1183
TR_ScratchList<TR_PersistentClassInfo> subTree(comp->trMemory());
1184
collectAllSubClasses(clazz, &subTree, comp);
1185
1186
// Add the root to the list
1187
subTree.add(clazz);
1188
1189
ListIterator<TR_VirtualGuardSite> it(&list);
1190
for (TR_VirtualGuardSite *site = it.getFirst(); site; site = it.getNext())
1191
{
1192
ListIterator<TR_PersistentClassInfo> classIt(&subTree);
1193
for (TR_PersistentClassInfo *sc = classIt.getFirst(); sc; sc = classIt.getNext())
1194
{
1195
TR_ASSERT(sc == table->findClassInfo(sc->getClassId()), "Class ID mismatch");
1196
TR_PatchNOPedGuardSiteOnClassExtend::make(comp->fe(), comp->trPersistentMemory(), sc->getClassId(),
1197
site->getLocation(),
1198
site->getDestination(),
1199
comp->getMetadataAssumptionList());
1200
comp->setHasClassExtendAssumptions();
1201
}
1202
}
1203
}
1204
1205
// class used to count all non-interface subclasses up to a maximum
1206
class CountNonIFSubClasses : public TR_SubclassVisitor
1207
{
1208
public:
1209
CountNonIFSubClasses(TR::Compilation * comp, int32_t maxCount) :
1210
TR_SubclassVisitor(comp), _maxCount(maxCount), _count(0) {}
1211
virtual bool visitSubclass(TR_PersistentClassInfo *cl)
1212
{
1213
if (!TR::Compiler->cls.isInterfaceClass(comp(), cl->getClassId()))
1214
if (++_count >= _maxCount)
1215
stopTheWalk();
1216
return true;
1217
}
1218
int32_t getCount() const { return _count; }
1219
private:
1220
int32_t _maxCount, _count;
1221
};// end of class CountNonIFSubClasses
1222
1223
int32_t
1224
TR_ClassQueries::countAllNonIFSubClassesWithDepth(TR_PersistentClassInfo *clazz,
1225
TR::Compilation *comp, int32_t maxcount, bool locked)
1226
{
1227
CountNonIFSubClasses collector(comp, maxcount);
1228
collector.visit(clazz->getClassId(), locked);
1229
return collector.getCount();
1230
}
1231
1232
1233
TR_SubclassVisitor::TR_SubclassVisitor(TR::Compilation * comp)
1234
: _comp(comp),
1235
_stopTheWalk(false),
1236
_depth(0)
1237
{
1238
static char * trace = feGetEnv("TR_TraceSubclassVisitor");
1239
_trace = (trace != 0);
1240
}
1241
1242
void
1243
TR_SubclassVisitor::visit(TR_OpaqueClassBlock * clazz, bool locked)
1244
{
1245
TR::ClassTableCriticalSection visit(fe(), locked);
1246
1247
TR_PersistentClassInfo * classInfo = comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfo(clazz);
1248
if (!classInfo)
1249
return;
1250
1251
// A class can be visited more than once if we're starting from an interface class or if we're starting from
1252
// java/lang/Object. The latter is because all interfaces extend java/lang/Object.
1253
// java/lang/Object has the property that it doesn't have a super class (classdepth == 0).
1254
//
1255
_mightVisitAClassMoreThanOnce = TR::Compiler->cls.isInterfaceClass(comp(), clazz) || TR::Compiler->cls.classDepthOf(clazz) == 0;
1256
1257
if (_trace && classInfo->getFirstSubclass())
1258
{
1259
int32_t len; char * s = TR::Compiler->cls.classNameChars(comp(), clazz, len);
1260
TR_VerboseLog::writeLine(TR_Vlog_INFO,"visiting subclasses for %.*s", len, s);
1261
}
1262
1263
TR_CHTable::VisitTracker visited(comp()->trMemory());
1264
visitSubclasses(classInfo, visited);
1265
}
1266
1267
void
1268
TR_SubclassVisitor::visitSubclasses(TR_PersistentClassInfo * classInfo, TR_CHTable::VisitTracker& visited)
1269
{
1270
++_depth;
1271
for (TR_SubClass * subclass = classInfo->getFirstSubclass(); subclass; subclass = subclass->getNext())
1272
{
1273
TR_PersistentClassInfo * subclassInfo = subclass->getClassInfo();
1274
if (!subclassInfo->hasBeenVisited())
1275
{
1276
if (_trace)
1277
{
1278
int32_t len; char * s = TR::Compiler->cls.classNameChars(comp(), subclassInfo->getClassId(), len);
1279
TR_VerboseLog::writeLine(TR_Vlog_INFO,"%*s%.*s", _depth, " ", len, s);
1280
}
1281
1282
if (_mightVisitAClassMoreThanOnce)
1283
{
1284
visited.visit(subclassInfo);
1285
}
1286
1287
bool recurse = visitSubclass(subclassInfo);
1288
if (recurse && !_stopTheWalk)
1289
visitSubclasses(subclassInfo, visited);
1290
1291
if (_stopTheWalk)
1292
break;
1293
}
1294
}
1295
--_depth;
1296
}
1297
1298