Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/gc_base/RootScanner.cpp
5986 views
1
/*******************************************************************************
2
* Copyright (c) 1991, 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 <stdlib.h>
24
#include <stdio.h>
25
#include <limits.h> // or <climits> for CHAR_BIT
26
#include <string.h> // memcpy
27
28
#include "j9cfg.h"
29
#include "j9.h"
30
#if defined(J9VM_OPT_JVMTI)
31
#include "jvmtiInternal.h"
32
#endif /* defined(J9VM_OPT_JVMTI) */
33
34
#include "RootScanner.hpp"
35
36
#include "ClassIterator.hpp"
37
#include "ClassHeapIterator.hpp"
38
#include "ClassLoaderIterator.hpp"
39
#include "Debug.hpp"
40
#include "EnvironmentBase.hpp"
41
#if defined(J9VM_GC_FINALIZATION)
42
#include "FinalizeListManager.hpp"
43
#endif /* J9VM_GC_FINALIZATION*/
44
#include "Heap.hpp"
45
#include "HeapRegionDescriptor.hpp"
46
#include "HeapRegionIterator.hpp"
47
#include "HeapRegionManager.hpp"
48
#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)
49
#include "HeapRegionIteratorVLHGC.hpp"
50
#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */
51
#include "MemoryPool.hpp"
52
#include "MemorySubSpace.hpp"
53
#include "MemorySpace.hpp"
54
#include "MixedObjectIterator.hpp"
55
#include "ModronTypes.hpp"
56
#include "ObjectAccessBarrier.hpp"
57
#include "ObjectHeapIteratorAddressOrderedList.hpp"
58
#include "ObjectModel.hpp"
59
#include "OwnableSynchronizerObjectList.hpp"
60
#include "ParallelDispatcher.hpp"
61
#include "PointerArrayIterator.hpp"
62
#include "SlotObject.hpp"
63
#include "StringTable.hpp"
64
#include "StringTableIncrementalIterator.hpp"
65
#include "Task.hpp"
66
#include "UnfinalizedObjectList.hpp"
67
#include "VMClassSlotIterator.hpp"
68
#include "VMInterface.hpp"
69
#include "VMThreadListIterator.hpp"
70
#include "VMThreadIterator.hpp"
71
72
/**
73
* @todo Provide function documentation
74
*/
75
void
76
MM_RootScanner::doClassLoader(J9ClassLoader *classLoader)
77
{
78
doSlot(J9GC_J9CLASSLOADER_CLASSLOADEROBJECT_EA(classLoader));
79
80
scanModularityObjects(classLoader);
81
}
82
83
void
84
MM_RootScanner::scanModularityObjects(J9ClassLoader * classLoader)
85
{
86
if (NULL != classLoader->moduleHashTable) {
87
J9HashTableState moduleWalkState;
88
J9JavaVM *javaVM = static_cast<J9JavaVM*>(_omrVM->_language_vm);
89
J9Module **modulePtr = (J9Module**)hashTableStartDo(classLoader->moduleHashTable, &moduleWalkState);
90
while (NULL != modulePtr) {
91
J9Module * const module = *modulePtr;
92
93
doSlot(&module->moduleObject);
94
if (NULL != module->moduleName) {
95
doSlot(&module->moduleName);
96
}
97
if (NULL != module->version) {
98
doSlot(&module->version);
99
}
100
modulePtr = (J9Module**)hashTableNextDo(&moduleWalkState);
101
}
102
103
if (classLoader == javaVM->systemClassLoader) {
104
doSlot(&javaVM->unamedModuleForSystemLoader->moduleObject);
105
}
106
}
107
}
108
109
/**
110
* @todo Provide function documentation
111
*/
112
MM_RootScanner::CompletePhaseCode
113
MM_RootScanner::scanWeakReferencesComplete(MM_EnvironmentBase *env)
114
{
115
return complete_phase_OK;
116
}
117
118
119
/**
120
* @todo Provide function documentation
121
*/
122
MM_RootScanner::CompletePhaseCode
123
MM_RootScanner::scanSoftReferencesComplete(MM_EnvironmentBase *env)
124
{
125
return complete_phase_OK;
126
}
127
128
/**
129
* @todo Provide function documentation
130
*/
131
MM_RootScanner::CompletePhaseCode
132
MM_RootScanner::scanPhantomReferencesComplete(MM_EnvironmentBase *env)
133
{
134
return complete_phase_OK;
135
}
136
137
#if defined(J9VM_GC_FINALIZATION)
138
void
139
MM_RootScanner::doUnfinalizedObject(J9Object *objectPtr, MM_UnfinalizedObjectList *list)
140
{
141
/* This function needs to be overridden if the default implementation of scanUnfinalizedObjects
142
* is used.
143
*/
144
Assert_MM_unreachable();
145
}
146
147
/**
148
* @todo Provide function documentation
149
*/
150
MM_RootScanner::CompletePhaseCode
151
MM_RootScanner::scanUnfinalizedObjectsComplete(MM_EnvironmentBase *env)
152
{
153
return complete_phase_OK;
154
}
155
#endif /* J9VM_GC_FINALIZATION */
156
157
void
158
MM_RootScanner::doOwnableSynchronizerObject(J9Object *objectPtr, MM_OwnableSynchronizerObjectList *list)
159
{
160
/* This function needs to be overridden if the default implementation of scanOwnableSynchronizerObjects
161
* is used.
162
*/
163
Assert_MM_unreachable();
164
}
165
166
MM_RootScanner::CompletePhaseCode
167
MM_RootScanner::scanOwnableSynchronizerObjectsComplete(MM_EnvironmentBase *env)
168
{
169
return complete_phase_OK;
170
}
171
172
/**
173
* @todo Provide function documentation
174
*/
175
void
176
MM_RootScanner::doMonitorReference(J9ObjectMonitor *objectMonitor, GC_HashTableIterator *monitorReferenceIterator)
177
{
178
J9ThreadAbstractMonitor * monitor = (J9ThreadAbstractMonitor*)objectMonitor->monitor;
179
doSlot((J9Object **)& monitor->userData);
180
}
181
182
MM_RootScanner::CompletePhaseCode
183
MM_RootScanner::scanMonitorReferencesComplete(MM_EnvironmentBase *env)
184
{
185
return complete_phase_OK;
186
}
187
188
189
/**
190
* @todo Provide function documentation
191
*/
192
void
193
MM_RootScanner::doMonitorLookupCacheSlot(j9objectmonitor_t* slotPtr)
194
{
195
if(0 != *slotPtr) {
196
*slotPtr = 0;
197
}
198
}
199
200
201
/**
202
* @todo Provide function documentation
203
*/
204
void
205
MM_RootScanner::doJNIWeakGlobalReference(J9Object **slotPtr)
206
{
207
doSlot(slotPtr);
208
}
209
210
#if defined(J9VM_GC_MODRON_SCAVENGER)
211
/**
212
* @todo Provide function documentation
213
*/
214
void
215
MM_RootScanner::doRememberedSetSlot(J9Object **slotPtr, GC_RememberedSetSlotIterator *rememberedSetSlotIterator)
216
{
217
doSlot(slotPtr);
218
}
219
#endif /* defined(J9VM_GC_MODRON_SCAVENGER) */
220
221
/**
222
* @todo Provide function documentation
223
*/
224
void
225
MM_RootScanner::doStringTableSlot(J9Object **slotPtr, GC_StringTableIterator *stringTableIterator)
226
{
227
doSlot(slotPtr);
228
}
229
230
#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)
231
void
232
MM_RootScanner::doDoubleMappedObjectSlot(J9Object *objectPtr, struct J9PortVmemIdentifier *identifier)
233
{
234
/* No need to call doSlot() here since there's nothing to update */
235
}
236
#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */
237
238
/**
239
* @Perform operation on the given string cache table slot.
240
* @String table cache contains cached entries of string table, it's
241
* @a subset of string table entries.
242
*/
243
void
244
MM_RootScanner::doStringCacheTableSlot(J9Object **slotPtr)
245
{
246
doSlot(slotPtr);
247
}
248
249
/**
250
* @todo Provide function documentation
251
*/
252
void
253
MM_RootScanner::doVMClassSlot(J9Class *classPtr)
254
{
255
doClassSlot(classPtr);
256
}
257
258
/**
259
* General object field slot handler to be reimplemented by specializing class. This handler is called
260
* for every reference through an instance field.
261
* Implementation for slotObject input format
262
* @param slotObject Input field for scan in slotObject format
263
*/
264
void
265
MM_RootScanner::doFieldSlot(GC_SlotObject *slotObject)
266
{
267
J9Object* object = slotObject->readReferenceFromSlot();
268
doSlot(&object);
269
slotObject->writeReferenceToSlot(object);
270
}
271
272
#if defined(J9VM_OPT_JVMTI)
273
/**
274
* @todo Provide function documentation
275
*/
276
void
277
MM_RootScanner::doJVMTIObjectTagSlot(J9Object **slotPtr, GC_JVMTIObjectTagTableIterator *objectTagTableIterator)
278
{
279
doSlot(slotPtr);
280
}
281
#endif /* J9VM_OPT_JVMTI */
282
283
/**
284
* @todo Provide function documentation
285
*/
286
void
287
MM_RootScanner::scanClasses(MM_EnvironmentBase *env)
288
{
289
reportScanningStarted(RootScannerEntity_Classes);
290
291
GC_SegmentIterator segmentIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm)->classMemorySegments, MEMORY_TYPE_RAM_CLASS);
292
293
while(J9MemorySegment *segment = segmentIterator.nextSegment()) {
294
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
295
GC_ClassHeapIterator classHeapIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm), segment);
296
J9Class *clazz = NULL;
297
while(NULL != (clazz = classHeapIterator.nextClass())) {
298
doClass(clazz);
299
if (shouldYieldFromClassScan(100000)) {
300
yield();
301
}
302
}
303
}
304
}
305
306
condYield();
307
308
reportScanningEnded(RootScannerEntity_Classes);
309
}
310
311
/**
312
* Scan through the slots in the VM containing known classes
313
*/
314
void
315
MM_RootScanner::scanVMClassSlots(MM_EnvironmentBase *env)
316
{
317
/* VM Class Slot Iterator */
318
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
319
reportScanningStarted(RootScannerEntity_VMClassSlots);
320
321
GC_VMClassSlotIterator classSlotIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm));
322
J9Class *classPtr;
323
324
while (NULL != (classPtr = classSlotIterator.nextSlot())) {
325
doVMClassSlot(classPtr);
326
}
327
328
reportScanningEnded(RootScannerEntity_VMClassSlots);
329
}
330
}
331
332
/**
333
* General class slot handler to be reimplemented by specializing class.
334
* This handler is called for every reference to a J9Class.
335
*/
336
void
337
MM_RootScanner::doClassSlot(J9Class *classPtr)
338
{
339
/* ignore class slots by default */
340
}
341
342
/**
343
* @todo Provide function documentation
344
*/
345
void
346
MM_RootScanner::doStackSlot(J9Object **slotPtr, void *walkState, const void* stackLocation)
347
{
348
/* ensure that this isn't a slot pointing into the gap (only matters for split heap VMs) */
349
if (!_extensions->heap->objectIsInGap(*slotPtr)) {
350
doSlot(slotPtr);
351
}
352
}
353
354
/**
355
* @todo Provide function documentation
356
*/
357
void
358
MM_RootScanner::doVMThreadSlot(J9Object **slotPtr, GC_VMThreadIterator *vmThreadIterator)
359
{
360
doSlot(slotPtr);
361
}
362
363
/**
364
* @todo Provide function documentation
365
*/
366
void
367
MM_RootScanner::doJNIGlobalReferenceSlot(J9Object **slotPtr, GC_JNIGlobalReferenceIterator *jniGlobalReferenceIterator)
368
{
369
doSlot(slotPtr);
370
}
371
372
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
373
/**
374
* Scan all classes which will never be unloaded (those that
375
* were loaded either by the system class loader or the application
376
* class loader).
377
*/
378
void
379
MM_RootScanner::scanPermanentClasses(MM_EnvironmentBase *env)
380
{
381
reportScanningStarted(RootScannerEntity_PermanentClasses);
382
383
J9MemorySegment *segment = NULL;
384
J9Class *clazz = NULL;
385
386
/* Do systemClassLoader */
387
if (NULL != static_cast<J9JavaVM*>(_omrVM->_language_vm)->systemClassLoader) {
388
GC_ClassLoaderSegmentIterator segmentIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm)->systemClassLoader, MEMORY_TYPE_RAM_CLASS);
389
while(NULL != (segment = segmentIterator.nextSegment())) {
390
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
391
GC_ClassHeapIterator classHeapIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm), segment);
392
while(NULL != (clazz = classHeapIterator.nextClass())) {
393
doClass(clazz);
394
if (shouldYieldFromClassScan(100000)) {
395
yield();
396
}
397
}
398
}
399
}
400
}
401
402
/* Do applicationClassLoader */
403
if (NULL != static_cast<J9JavaVM*>(_omrVM->_language_vm)->applicationClassLoader) {
404
GC_ClassLoaderSegmentIterator segmentIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm)->applicationClassLoader, MEMORY_TYPE_RAM_CLASS);
405
while(NULL != (segment = segmentIterator.nextSegment())) {
406
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
407
GC_ClassHeapIterator classHeapIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm), segment);
408
while(NULL != (clazz = classHeapIterator.nextClass())) {
409
doClass(clazz);
410
if (shouldYieldFromClassScan(100000)) {
411
yield();
412
}
413
}
414
}
415
}
416
}
417
418
condYield();
419
420
reportScanningEnded(RootScannerEntity_PermanentClasses);
421
}
422
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
423
424
/**
425
* Checkpoint signalling completion of scanning of class data (classes and classloaders).
426
* This checkpoint is called once for any larger scanning phase
427
* which includes class scanning.
428
* @see scanClasses
429
* @see scanPermanentClasses
430
*/
431
MM_RootScanner::CompletePhaseCode
432
MM_RootScanner::scanClassesComplete(MM_EnvironmentBase *env)
433
{
434
return complete_phase_OK;
435
}
436
437
/**
438
* @todo Provide function documentation
439
*/
440
void
441
MM_RootScanner::scanClassLoaders(MM_EnvironmentBase *env)
442
{
443
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
444
reportScanningStarted(RootScannerEntity_ClassLoaders);
445
446
J9ClassLoader *classLoader;
447
448
GC_ClassLoaderIterator classLoaderIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm)->classLoaderBlocks);
449
while((classLoader = classLoaderIterator.nextSlot()) != NULL) {
450
doClassLoader(classLoader);
451
}
452
453
reportScanningEnded(RootScannerEntity_ClassLoaders);
454
}
455
}
456
457
/**
458
* @todo Provide function documentation
459
*/
460
void
461
stackSlotIterator(J9JavaVM *javaVM, J9Object **slot, void *localData, J9StackWalkState *walkState, const void *stackLocation)
462
{
463
StackIteratorData *data = (StackIteratorData *)localData;
464
data->rootScanner->doStackSlot(slot, walkState, stackLocation);
465
}
466
467
/**
468
* @todo Provide function documentation
469
*
470
* This function iterates through all the threads, calling scanOneThread on each one that
471
* should be scanned. The scanOneThread function scans exactly one thread and returns
472
* either true (if it took an action that requires the thread list iterator to return to
473
* the beginning) or false (if the thread list iterator should just continue with the next
474
* thread).
475
*/
476
void
477
MM_RootScanner::scanThreads(MM_EnvironmentBase *env)
478
{
479
reportScanningStarted(RootScannerEntity_Threads);
480
481
/* TODO This assumes that while exclusive vm access is held the thread
482
* list is also locked.
483
*/
484
485
GC_VMThreadListIterator vmThreadListIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm));
486
StackIteratorData localData;
487
488
localData.rootScanner = this;
489
localData.env = env;
490
491
while(J9VMThread *walkThread = vmThreadListIterator.nextVMThread()) {
492
if (_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
493
if (scanOneThread(env, walkThread, (void*) &localData)) {
494
vmThreadListIterator.reset(static_cast<J9JavaVM*>(_omrVM->_language_vm)->mainThread);
495
}
496
}
497
}
498
499
reportScanningEnded(RootScannerEntity_Threads);
500
}
501
502
/**
503
* This function scans exactly one thread for potential roots. It is designed as
504
* an overridable subroutine of the primary functions scanThreads and scanSingleThread.
505
* @param walkThead the thread to be scanned
506
* @param localData opaque data to be passed to the stack walker callback function.
507
* The root scanner fixes that callback function to the stackSlotIterator function
508
* defined above
509
* @return true if the thread scan included an action that requires the thread list
510
* iterator to begin over again at the beginning, false otherwise. This implementation
511
* always returns false but an overriding implementation may take actions that require
512
* a true return (for example, RealtimeRootScanner returns true if it yielded after the
513
* scan, allowing other threads to run and perhaps be created or terminated).
514
**/
515
bool
516
MM_RootScanner::scanOneThread(MM_EnvironmentBase *env, J9VMThread* walkThread, void* localData)
517
{
518
GC_VMThreadIterator vmThreadIterator(walkThread);
519
520
while(J9Object **slot = vmThreadIterator.nextSlot()) {
521
doVMThreadSlot(slot, &vmThreadIterator);
522
}
523
524
GC_VMThreadStackSlotIterator::scanSlots((J9VMThread *)env->getOmrVMThread()->_language_vmthread, walkThread, localData, stackSlotIterator, isStackFrameClassWalkNeeded(), _trackVisibleStackFrameDepth);
525
return false;
526
}
527
528
/**
529
* This function scans exactly one thread for potential roots.
530
* @param walkThead the thread to be scanned
531
**/
532
void
533
MM_RootScanner::scanSingleThread(MM_EnvironmentBase *env, J9VMThread* walkThread)
534
{
535
StackIteratorData localData;
536
localData.rootScanner = this;
537
localData.env = env;
538
scanOneThread(env, walkThread, &localData);
539
}
540
541
#if defined(J9VM_GC_FINALIZATION)
542
/**
543
* @todo Provide function documentation
544
*/
545
void
546
MM_RootScanner::scanFinalizableObjects(MM_EnvironmentBase *env)
547
{
548
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
549
reportScanningStarted(RootScannerEntity_FinalizableObjects);
550
551
GC_FinalizeListManager * finalizeListManager = _extensions->finalizeListManager;
552
{
553
/* walk finalizable objects loaded by the system class loader */
554
j9object_t systemObject = finalizeListManager->peekSystemFinalizableObject();
555
while (NULL != systemObject) {
556
doFinalizableObject(systemObject);
557
systemObject = finalizeListManager->peekNextSystemFinalizableObject(systemObject);
558
}
559
}
560
561
{
562
/* walk finalizable objects loaded by all other class loaders*/
563
j9object_t defaultObject = finalizeListManager->peekDefaultFinalizableObject();
564
while (NULL != defaultObject) {
565
doFinalizableObject(defaultObject);
566
defaultObject = finalizeListManager->peekNextDefaultFinalizableObject(defaultObject);
567
}
568
}
569
570
{
571
/* walk reference objects */
572
j9object_t referenceObject = finalizeListManager->peekReferenceObject();
573
while (NULL != referenceObject) {
574
doFinalizableObject(referenceObject);
575
referenceObject = finalizeListManager->peekNextReferenceObject(referenceObject);
576
}
577
}
578
579
reportScanningEnded(RootScannerEntity_FinalizableObjects);
580
}
581
}
582
#endif /* J9VM_GC_FINALIZATION */
583
584
/**
585
* @todo Provide function documentation
586
*/
587
void
588
MM_RootScanner::scanJNIGlobalReferences(MM_EnvironmentBase *env)
589
{
590
/* JNI Global References */
591
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
592
reportScanningStarted(RootScannerEntity_JNIGlobalReferences);
593
594
GC_JNIGlobalReferenceIterator jniGlobalReferenceIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm)->jniGlobalReferences);
595
J9Object **slot;
596
597
while((slot = (J9Object **)jniGlobalReferenceIterator.nextSlot()) != NULL) {
598
doJNIGlobalReferenceSlot(slot, &jniGlobalReferenceIterator);
599
}
600
601
reportScanningEnded(RootScannerEntity_JNIGlobalReferences);
602
}
603
}
604
605
/**
606
* @todo Provide function documentation
607
*/
608
void
609
MM_RootScanner::scanStringTable(MM_EnvironmentBase *env)
610
{
611
MM_StringTable *stringTable = _extensions->getStringTable();
612
reportScanningStarted(RootScannerEntity_StringTable);
613
bool isMetronomeGC = _extensions->isMetronomeGC();
614
615
/* String Table */
616
for (UDATA tableIndex = 0; tableIndex < stringTable->getTableCount(); tableIndex++) {
617
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
618
619
if (isMetronomeGC) {
620
GC_StringTableIncrementalIterator stringTableIterator(stringTable->getTable(tableIndex));
621
J9Object **slot = NULL;
622
623
stringTableIterator.disableTableGrowth();
624
while (stringTableIterator.nextIncrement()) {
625
while (NULL != (slot = (J9Object **)stringTableIterator.nextSlot())) {
626
doStringTableSlot(slot, &stringTableIterator);
627
}
628
if (shouldYieldFromStringScan()) {
629
yield();
630
}
631
}
632
stringTableIterator.enableTableGrowth();
633
} else {
634
GC_StringTableIterator stringTableIterator(stringTable->getTable(tableIndex));
635
J9Object **slot = NULL;
636
while (NULL != (slot = (J9Object **)stringTableIterator.nextSlot())) {
637
doStringTableSlot(slot, &stringTableIterator);
638
}
639
}
640
}
641
}
642
643
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
644
j9object_t *stringCacheTable = stringTable->getStringInternCache();
645
UDATA cacheTableIndex = 0;
646
for (; cacheTableIndex < MM_StringTable::getCacheSize(); cacheTableIndex++) {
647
doStringCacheTableSlot(&stringCacheTable[cacheTableIndex]);
648
}
649
}
650
651
reportScanningEnded(RootScannerEntity_StringTable);
652
}
653
654
/**
655
* Scan the weak reference list.
656
* @note Extra locking for NHRTs can be omitted, because it is impossible for
657
* an NHRT to create a reference object that will live longer than its referent;
658
* thus reference objects created by NHRTs do not need to go on the list.
659
*/
660
void
661
MM_RootScanner::scanWeakReferenceObjects(MM_EnvironmentBase *env)
662
{
663
}
664
665
/**
666
* Scan the soft reference list.
667
* @note Extra locking for NHRTs can be omitted, because it is impossible for
668
* an NHRT to create a reference object that will live longer than its referent;
669
* thus reference objects created by NHRTs do not need to go on the list.
670
*/
671
void
672
MM_RootScanner::scanSoftReferenceObjects(MM_EnvironmentBase *env)
673
{
674
}
675
676
/**
677
* Scan the phantom reference list.
678
* @note Extra locking for NHRTs can be omitted, because it is impossible for
679
* an NHRT to create a reference object that will live longer than its referent;
680
* thus reference objects created by NHRTs do not need to go on the list.
681
*/
682
void
683
MM_RootScanner::scanPhantomReferenceObjects(MM_EnvironmentBase *env)
684
{
685
}
686
687
#if defined(J9VM_GC_FINALIZATION)
688
/**
689
* @todo Provide function documentation
690
*
691
* @NOTE this can only be used as a READ-ONLY version of the unfinalizedObjectList.
692
* If you need to modify elements with-in the list you will need to provide your own functionality.
693
* See MM_MarkingScheme::scanUnfinalizedObjects(MM_EnvironmentStandard *env) as an example
694
* which modifies elements within the list.
695
*/
696
void
697
MM_RootScanner::scanUnfinalizedObjects(MM_EnvironmentBase *env)
698
{
699
reportScanningStarted(RootScannerEntity_UnfinalizedObjects);
700
701
MM_ObjectAccessBarrier *barrier = _extensions->accessBarrier;
702
MM_UnfinalizedObjectList *unfinalizedObjectList = _extensions->unfinalizedObjectLists;
703
while(NULL != unfinalizedObjectList) {
704
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
705
J9Object *objectPtr = unfinalizedObjectList->getHeadOfList();
706
while (NULL != objectPtr) {
707
doUnfinalizedObject(objectPtr, unfinalizedObjectList);
708
objectPtr = barrier->getFinalizeLink(objectPtr);
709
}
710
}
711
unfinalizedObjectList = unfinalizedObjectList->getNextList();
712
}
713
714
reportScanningEnded(RootScannerEntity_UnfinalizedObjects);
715
}
716
#endif /* J9VM_GC_FINALIZATION */
717
718
void
719
MM_RootScanner::scanOwnableSynchronizerObjects(MM_EnvironmentBase *env)
720
{
721
reportScanningStarted(RootScannerEntity_OwnableSynchronizerObjects);
722
723
MM_ObjectAccessBarrier *barrier = _extensions->accessBarrier;
724
MM_OwnableSynchronizerObjectList *ownableSynchronizerObjectList = _extensions->getOwnableSynchronizerObjectLists();
725
while(NULL != ownableSynchronizerObjectList) {
726
if (_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
727
J9Object *objectPtr = ownableSynchronizerObjectList->getHeadOfList();
728
while (NULL != objectPtr) {
729
doOwnableSynchronizerObject(objectPtr, ownableSynchronizerObjectList);
730
objectPtr = barrier->getOwnableSynchronizerLink(objectPtr);
731
}
732
}
733
ownableSynchronizerObjectList = ownableSynchronizerObjectList->getNextList();
734
}
735
736
reportScanningEnded(RootScannerEntity_OwnableSynchronizerObjects);
737
}
738
739
/**
740
* Scan the per-thread object monitor lookup caches.
741
* Note that this is not a root since the cache contains monitors from the global monitor table
742
* which will be scanned by scanMonitorReferences. It should be scanned first, however, since
743
* scanMonitorReferences may destroy monitors that appear in caches.
744
*/
745
void
746
MM_RootScanner::scanMonitorLookupCaches(MM_EnvironmentBase *env)
747
{
748
reportScanningStarted(RootScannerEntity_MonitorLookupCaches);
749
GC_VMThreadListIterator vmThreadListIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm));
750
while (J9VMThread *walkThread = vmThreadListIterator.nextVMThread()) {
751
if (_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
752
j9objectmonitor_t *objectMonitorLookupCache = walkThread->objectMonitorLookupCache;
753
UDATA cacheIndex = 0;
754
for (; cacheIndex < J9VMTHREAD_OBJECT_MONITOR_CACHE_SIZE; cacheIndex++) {
755
doMonitorLookupCacheSlot(&objectMonitorLookupCache[cacheIndex]);
756
}
757
}
758
}
759
reportScanningEnded(RootScannerEntity_MonitorLookupCaches);
760
}
761
762
/**
763
* @todo Provide function documentation
764
*/
765
void
766
MM_RootScanner::scanMonitorReferences(MM_EnvironmentBase *env)
767
{
768
reportScanningStarted(RootScannerEntity_MonitorReferences);
769
770
J9ObjectMonitor *objectMonitor = NULL;
771
J9MonitorTableListEntry *monitorTableList = static_cast<J9JavaVM*>(_omrVM->_language_vm)->monitorTableList;
772
while (NULL != monitorTableList) {
773
J9HashTable *table = monitorTableList->monitorTable;
774
if (NULL != table) {
775
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
776
GC_HashTableIterator iterator(table);
777
while (NULL != (objectMonitor = (J9ObjectMonitor *)iterator.nextSlot())) {
778
doMonitorReference(objectMonitor, &iterator);
779
}
780
}
781
}
782
monitorTableList = monitorTableList->next;
783
}
784
785
reportScanningEnded(RootScannerEntity_MonitorReferences);
786
}
787
788
/**
789
* @todo Provide function documentation
790
*/
791
void
792
MM_RootScanner::scanJNIWeakGlobalReferences(MM_EnvironmentBase *env)
793
{
794
if (_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
795
reportScanningStarted(RootScannerEntity_JNIWeakGlobalReferences);
796
797
GC_JNIWeakGlobalReferenceIterator jniWeakGlobalReferenceIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm)->jniWeakGlobalReferences);
798
J9Object **slot;
799
800
while((slot = (J9Object **)jniWeakGlobalReferenceIterator.nextSlot()) != NULL) {
801
doJNIWeakGlobalReference(slot);
802
}
803
804
reportScanningEnded(RootScannerEntity_JNIWeakGlobalReferences);
805
}
806
}
807
808
#if defined(J9VM_GC_MODRON_SCAVENGER)
809
/**
810
* @todo Provide function documentation
811
*/
812
void
813
MM_RootScanner::scanRememberedSet(MM_EnvironmentBase *env)
814
{
815
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
816
reportScanningStarted(RootScannerEntity_RememberedSet);
817
818
MM_SublistPuddle *puddle;
819
J9Object **slotPtr;
820
GC_RememberedSetIterator rememberedSetIterator(&_extensions->rememberedSet);
821
822
while((puddle = rememberedSetIterator.nextList()) != NULL) {
823
GC_RememberedSetSlotIterator rememberedSetSlotIterator(puddle);
824
while((slotPtr = (J9Object **)rememberedSetSlotIterator.nextSlot()) != NULL) {
825
doRememberedSetSlot(slotPtr, &rememberedSetSlotIterator);
826
}
827
}
828
829
reportScanningEnded(RootScannerEntity_RememberedSet);
830
}
831
}
832
#endif /* J9VM_GC_MODRON_SCAVENGER */
833
834
#if defined(J9VM_OPT_JVMTI)
835
/**
836
* Scan the JVMTI tag tables for object references
837
*/
838
void
839
MM_RootScanner::scanJVMTIObjectTagTables(MM_EnvironmentBase *env)
840
{
841
if(_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
842
reportScanningStarted(RootScannerEntity_JVMTIObjectTagTables);
843
844
J9JVMTIData * jvmtiData = J9JVMTI_DATA_FROM_VM(static_cast<J9JavaVM*>(_omrVM->_language_vm));
845
J9JVMTIEnv * jvmtiEnv;
846
J9Object **slotPtr;
847
if (NULL != jvmtiData) {
848
/* TODO: When JVMTI is supported in RTSJ, this structure needs to be locked
849
* when it is being scanned
850
*/
851
GC_JVMTIObjectTagTableListIterator objectTagTableList(jvmtiData->environments);
852
while(NULL != (jvmtiEnv = (J9JVMTIEnv *)objectTagTableList.nextSlot())) {
853
if (NULL != jvmtiEnv->objectTagTable) {
854
GC_JVMTIObjectTagTableIterator objectTagTableIterator(jvmtiEnv->objectTagTable);
855
while(NULL != (slotPtr = (J9Object **)objectTagTableIterator.nextSlot())) {
856
doJVMTIObjectTagSlot(slotPtr, &objectTagTableIterator);
857
}
858
}
859
}
860
}
861
862
reportScanningEnded(RootScannerEntity_JVMTIObjectTagTables);
863
}
864
}
865
#endif /* J9VM_OPT_JVMTI */
866
867
#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)
868
void
869
MM_RootScanner::scanDoubleMappedObjects(MM_EnvironmentBase *env)
870
{
871
if (_singleThread || J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {
872
GC_HeapRegionIteratorVLHGC regionIterator(_extensions->heap->getHeapRegionManager());
873
MM_HeapRegionDescriptorVLHGC *region = NULL;
874
reportScanningStarted(RootScannerEntity_DoubleMappedObjects);
875
while (NULL != (region = regionIterator.nextRegion())) {
876
if (region->isArrayletLeaf()) {
877
J9Object *spineObject = (J9Object *)region->_allocateData.getSpine();
878
Assert_MM_true(NULL != spineObject);
879
J9PortVmemIdentifier *arrayletDoublemapID = &region->_arrayletDoublemapID;
880
if (NULL != arrayletDoublemapID->address) {
881
doDoubleMappedObjectSlot(spineObject, arrayletDoublemapID);
882
}
883
}
884
}
885
reportScanningEnded(RootScannerEntity_DoubleMappedObjects);
886
}
887
}
888
#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */
889
890
/**
891
* Scan all root set references from the VM into the heap.
892
* For all slots that are hard root references into the heap, the appropriate slot handler will be called.
893
* @note This includes all references to classes.
894
*/
895
void
896
MM_RootScanner::scanRoots(MM_EnvironmentBase *env)
897
{
898
if (_classDataAsRoots || _nurseryReferencesOnly || _nurseryReferencesPossibly) {
899
/* The classLoaderObject of a class loader might be in the nursery, but a class loader
900
* can never be in the remembered set, so include class loaders here.
901
*/
902
scanClassLoaders(env);
903
}
904
905
if (!_nurseryReferencesOnly && !_nurseryReferencesPossibly) {
906
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
907
if (_classDataAsRoots) {
908
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
909
scanClasses(env);
910
/* We are scanning all classes, no need to include stack frame references */
911
setIncludeStackFrameClassReferences(false);
912
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
913
} else {
914
scanPermanentClasses(env);
915
setIncludeStackFrameClassReferences(true);
916
}
917
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
918
919
if(complete_phase_ABORT == scanClassesComplete(env)) {
920
return ;
921
}
922
}
923
924
scanThreads(env);
925
#if defined(J9VM_GC_FINALIZATION)
926
scanFinalizableObjects(env);
927
#endif /* J9VM_GC_FINALIZATION */
928
scanJNIGlobalReferences(env);
929
930
if (_jniWeakGlobalReferencesTableAsRoot) {
931
/* JNI Weak Global References table should be scanned as a hard root */
932
scanJNIWeakGlobalReferences(env);
933
}
934
935
/* In the RT configuration, We can skip scanning the string table because
936
all interned strings are in immortal memory and will not move. */
937
if(_stringTableAsRoot && (!_nurseryReferencesOnly && !_nurseryReferencesPossibly)){
938
scanStringTable(env);
939
}
940
}
941
942
/**
943
* Scan all clearable root set references from the VM into the heap.
944
* For all slots that are clearable root references into the heap, the appropriate slot handler will be
945
* called.
946
* @note This includes all references to classes.
947
*/
948
void
949
MM_RootScanner::scanClearable(MM_EnvironmentBase *env)
950
{
951
/* This may result in more marking, if aged soft references could not be enqueued. */
952
scanSoftReferenceObjects(env);
953
if(complete_phase_ABORT == scanSoftReferencesComplete(env)) {
954
return ;
955
}
956
957
scanWeakReferenceObjects(env);
958
if(complete_phase_ABORT == scanWeakReferencesComplete(env)) {
959
return ;
960
}
961
962
#if defined(J9VM_GC_FINALIZATION)
963
/* This may result in more marking, but any weak references
964
* must be cleared before, or at the same time as, the referent
965
* is moved to the finalizable list.
966
*/
967
scanUnfinalizedObjects(env);
968
if(complete_phase_ABORT == scanUnfinalizedObjectsComplete(env)) {
969
return ;
970
}
971
#endif /* J9VM_GC_FINALIZATION */
972
973
if (!_jniWeakGlobalReferencesTableAsRoot) {
974
/* Skip Clearable phase if it was treated as a hard root already */
975
scanJNIWeakGlobalReferences(env);
976
}
977
978
scanPhantomReferenceObjects(env);
979
if(complete_phase_ABORT == scanPhantomReferencesComplete(env)) {
980
return ;
981
}
982
983
/*
984
* clear the following private references once resurrection is completed
985
*/
986
scanMonitorLookupCaches(env);
987
scanMonitorReferences(env);
988
if(complete_phase_ABORT == scanMonitorReferencesComplete(env)) {
989
return ;
990
}
991
992
if(!_stringTableAsRoot && (!_nurseryReferencesOnly && !_nurseryReferencesPossibly)) {
993
scanStringTable(env);
994
}
995
996
scanOwnableSynchronizerObjects(env);
997
998
#if defined(J9VM_GC_MODRON_SCAVENGER)
999
/* Remembered set is clearable in a generational system -- if an object in old
1000
* space dies, and it pointed to an object in new space, it needs to be removed
1001
* from the remembered set.
1002
* This must after any other marking might occur, e.g. phantom references.
1003
*/
1004
if(_includeRememberedSetReferences && !_nurseryReferencesOnly && !_nurseryReferencesPossibly) {
1005
scanRememberedSet(env);
1006
}
1007
#endif /* J9VM_GC_MODRON_SCAVENGER */
1008
1009
#if defined(J9VM_OPT_JVMTI)
1010
if(_includeJVMTIObjectTagTables) {
1011
scanJVMTIObjectTagTables(env);
1012
}
1013
#endif /* J9VM_OPT_JVMTI */
1014
1015
#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)
1016
if (_includeDoubleMap) {
1017
scanDoubleMappedObjects(env);
1018
}
1019
#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */
1020
}
1021
1022
/**
1023
* Scan all slots which contain references into the heap.
1024
* @note this includes class references.
1025
*/
1026
void
1027
MM_RootScanner::scanAllSlots(MM_EnvironmentBase *env)
1028
{
1029
if(!_nurseryReferencesOnly && !_nurseryReferencesPossibly) {
1030
scanClasses(env);
1031
scanVMClassSlots(env);
1032
}
1033
1034
scanClassLoaders(env);
1035
1036
scanThreads(env);
1037
#if defined(J9VM_GC_FINALIZATION)
1038
scanFinalizableObjects(env);
1039
#endif /* J9VM_GC_FINALIZATION */
1040
scanJNIGlobalReferences(env);
1041
1042
if(!_nurseryReferencesOnly && !_nurseryReferencesPossibly) {
1043
scanStringTable(env);
1044
}
1045
1046
scanWeakReferenceObjects(env);
1047
scanSoftReferenceObjects(env);
1048
scanPhantomReferenceObjects(env);
1049
1050
#if defined(J9VM_GC_FINALIZATION)
1051
scanUnfinalizedObjects(env);
1052
#endif /* J9VM_GC_FINALIZATION */
1053
1054
scanMonitorReferences(env);
1055
scanJNIWeakGlobalReferences(env);
1056
1057
#if defined(J9VM_GC_MODRON_SCAVENGER)
1058
if(_includeRememberedSetReferences && !_nurseryReferencesOnly && !_nurseryReferencesPossibly) {
1059
scanRememberedSet(env);
1060
}
1061
#endif /* J9VM_GC_MODRON_SCAVENGER */
1062
1063
#if defined(J9VM_OPT_JVMTI)
1064
if(_includeJVMTIObjectTagTables) {
1065
scanJVMTIObjectTagTables(env);
1066
}
1067
#endif /* J9VM_OPT_JVMTI */
1068
1069
#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)
1070
if (_includeDoubleMap) {
1071
scanDoubleMappedObjects(env);
1072
}
1073
#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */
1074
1075
scanOwnableSynchronizerObjects(env);
1076
}
1077
1078
bool
1079
MM_RootScanner::shouldYieldFromClassScan(UDATA timeSlackNanoSec)
1080
{
1081
return false;
1082
}
1083
1084
bool
1085
MM_RootScanner::shouldYieldFromStringScan()
1086
{
1087
return false;
1088
}
1089
1090
bool
1091
MM_RootScanner::shouldYieldFromMonitorScan()
1092
{
1093
return false;
1094
}
1095
1096
bool
1097
MM_RootScanner::shouldYield()
1098
{
1099
return false;
1100
}
1101
1102
void
1103
MM_RootScanner::yield()
1104
{
1105
}
1106
1107
bool
1108
MM_RootScanner::condYield(U_64 timeSlackNanoSec)
1109
{
1110
bool yielded = shouldYield();
1111
1112
if (yielded) {
1113
yield();
1114
}
1115
1116
return yielded;
1117
}
1118
1119