Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/gc_base/RootScanner.hpp
5985 views
1
2
/*******************************************************************************
3
* Copyright (c) 1991, 2021 IBM Corp. and others
4
*
5
* This program and the accompanying materials are made available under
6
* the terms of the Eclipse Public License 2.0 which accompanies this
7
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
8
* or the Apache License, Version 2.0 which accompanies this distribution and
9
* is available at https://www.apache.org/licenses/LICENSE-2.0.
10
*
11
* This Source Code may also be made available under the following
12
* Secondary Licenses when the conditions for such availability set
13
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
14
* General Public License, version 2 with the GNU Classpath
15
* Exception [1] and GNU General Public License, version 2 with the
16
* OpenJDK Assembly Exception [2].
17
*
18
* [1] https://www.gnu.org/software/classpath/license.html
19
* [2] http://openjdk.java.net/legal/assembly-exception.html
20
*
21
* 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
22
*******************************************************************************/
23
24
/**
25
* @file
26
* @ingroup GC_Base
27
*/
28
29
#ifndef ROOTSCANNER_HPP_
30
#define ROOTSCANNER_HPP_
31
32
#include "j9.h"
33
#include "j9cfg.h"
34
#include "omr.h"
35
36
#include "BaseVirtual.hpp"
37
38
#include "EnvironmentBase.hpp"
39
#include "GCExtensions.hpp"
40
#include "JVMTIObjectTagTableIterator.hpp"
41
#include "ModronTypes.hpp"
42
#include "RootScannerTypes.h"
43
#include "Task.hpp"
44
#include "VMClassSlotIterator.hpp"
45
46
class GC_SlotObject;
47
class MM_MemoryPool;
48
class MM_CollectorLanguageInterfaceImpl;
49
50
/**
51
* General interface for scanning all object and class slots in the system that are not part of the heap.
52
*
53
* MM_RootScanner provides an abstract class that can be specialized to scan particular slots
54
* in the system, including all, root specific and clearable slots. The purpose of the class is
55
* to provide a central location for general slot scanners within Modron (e.g., root scanning,
56
* all slots do, etc).
57
*
58
* There are two levels of specialization for the scanner, structure walking and handling of elements.
59
* Structure walking specialization, where the implementer can override the way in which we walk elements,
60
* should be done rarely and in only extreme circumstances. Handling of elements can be specialized for all
61
* elements as well as for specific types of structures.
62
*
63
* The core routines to be reimplemented are doSlot(J9Object **), doClassSlot(J9Class *) and doClass(J9Class *).
64
* All other slot types are forwarded by default to these routines for processing. To handle structure slots in
65
* specific ways, the slot handler for that type should be overridden.
66
*
67
* @ingroup GC_Base
68
*/
69
class MM_RootScanner : public MM_BaseVirtual
70
{
71
/*
72
* Data members
73
*/
74
private:
75
76
protected:
77
MM_EnvironmentBase *_env;
78
MM_GCExtensions *_extensions;
79
MM_CollectorLanguageInterfaceImpl *_clij;
80
OMR_VM *_omrVM;
81
82
bool _stringTableAsRoot; /**< Treat the string table as a hard root */
83
bool _jniWeakGlobalReferencesTableAsRoot; /**< Treat JNI Weak References Table as a hard root */
84
bool _singleThread; /**< Should the iterator operate in single threaded mode */
85
86
bool _nurseryReferencesOnly; /**< Should the iterator only scan structures that currently contain nursery references */
87
bool _nurseryReferencesPossibly; /**< Should the iterator only scan structures that may contain nursery references */
88
bool _includeStackFrameClassReferences; /**< Should the iterator include Classes which have a method running on the stack */
89
#if defined(J9VM_GC_MODRON_SCAVENGER)
90
bool _includeRememberedSetReferences; /**< Should the iterator include references in the Remembered Set (if applicable) */
91
#endif /* J9VM_GC_MODRON_SCAVENGER */
92
bool _classDataAsRoots; /**< Should all classes (and class loaders) be treated as roots. Default true, should set to false when class unloading */
93
bool _includeJVMTIObjectTagTables; /**< Should the iterator include the JVMTIObjectTagTables. Default true, should set to false when doing JVMTI object walks */
94
#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)
95
bool _includeDoubleMap; /**< Enables doublemap should the GC policy be balanced. Default is false. */
96
#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */
97
bool _trackVisibleStackFrameDepth; /**< Should the stack walker be told to track the visible frame depth. Default false, should set to true when doing JVMTI walks that report stack slots */
98
99
U_64 _entityStartScanTime; /**< The start time of the scan of the current scanning entity, or 0 if no entity is being scanned. Defaults to 0. */
100
U_64 _entityIncrementStartTime; /**< Start time of current increment with a scan entity (Metronome may have several increment for each entity) */
101
U_64 _entityIncrementEndTime; /**< End time of the current increment */
102
RootScannerEntity _scanningEntity; /**< The root scanner entity that is currently being scanned. Defaults to RootScannerEntity_None. */
103
RootScannerEntity _lastScannedEntity; /**< The root scanner entity that was last scanned. Defaults to RootScannerEntity_None. */
104
105
/*
106
* Function members
107
*/
108
private:
109
/**
110
* Scan all fields of mixed object
111
* @param objectPtr address of object to scan
112
*/
113
void scanMixedObject(J9Object *objectPtr);
114
115
/**
116
* Scan all fields of pointer array object
117
* @param objectPtr address of object to scan
118
* @param memoryPool current memory pool
119
* @param manager current region manager
120
* @param memoryType memory type
121
*/
122
void scanArrayObject(MM_EnvironmentBase *env, J9Object *objectPtr, MM_MemoryPool *memoryPool, MM_HeapRegionManager *manager, UDATA memoryType);
123
124
protected:
125
/**
126
* Determine whether running method classes in stack frames should be walked.
127
* @return boolean determining whether running method classes in stack frames should be walked
128
*/
129
MMINLINE bool isStackFrameClassWalkNeeded() {
130
if (_nurseryReferencesOnly || _nurseryReferencesPossibly) {
131
return false;
132
}
133
return _includeStackFrameClassReferences;
134
}
135
136
/* Family of yielding methods to be overridden by incremental scanners such
137
* as the RealtimeRootScanner. The default implementations of these do
138
* nothing.
139
*/
140
141
/**
142
* Root scanning methods that have been incrementalized are responsible for
143
* calling this method periodically during class scan to check when they should
144
* yield.
145
* @return true if the GC should yield, false otherwise
146
*/
147
virtual bool shouldYieldFromClassScan(UDATA timeSlackNanoSec = 0);
148
149
/**
150
* Root scanning methods that have been incrementalized are responsible for
151
* calling this method periodically during string scan to check when they should
152
* yield.
153
* @return true if the GC should yield, false otherwise
154
*/
155
virtual bool shouldYieldFromStringScan();
156
157
/**
158
* Root scanning methods that have been incrementalized are responsible for
159
* calling this method periodically during monitor scan to check when they should
160
* yield.
161
* @return true if the GC should yield, false otherwise
162
*/
163
virtual bool shouldYieldFromMonitorScan();
164
165
/**
166
* Root scanning methods that have been incrementalized are responsible for
167
* calling this method periodically to check when they should yield.
168
* @return true if the GC should yield, false otherwise
169
*/
170
virtual bool shouldYield();
171
172
/**
173
* Root scanning methods that have been incrementalized should call this method
174
* after determining that it should yield and after releasing locks held during
175
* root processing. Upon returning from this method, the root scanner is
176
* responsible for re-acquiring necessary locks. The integrity of iterators
177
* and the semantics of atomicity are not ensured and must be examined on a
178
* case-by-case basis.
179
*/
180
virtual void yield();
181
182
/**
183
* Two in one method which amounts to yield if shouldYield is true.
184
* @return true if yielded, false otherwise
185
*/
186
virtual bool condYield(U_64 timeSlackNanoSec = 0);
187
188
virtual void flushRequiredNonAllocationCaches(MM_EnvironmentBase *envModron){}
189
190
/**
191
* Sets the currently scanned root entity to scanningEntity. This is mainly for
192
* debug purposes.
193
* @param scanningEntity The entity for which scanning has begun.
194
*/
195
MMINLINE void
196
reportScanningStarted(RootScannerEntity scanningEntity)
197
{
198
/* Ensures reportScanningEnded was called previously. */
199
assume0(RootScannerEntity_None == _scanningEntity);
200
_scanningEntity = scanningEntity;
201
202
if (_extensions->rootScannerStatsEnabled) {
203
OMRPORT_ACCESS_FROM_OMRVM(_omrVM);
204
_entityStartScanTime = omrtime_hires_clock();
205
_entityIncrementStartTime = _entityStartScanTime;
206
}
207
}
208
209
MMINLINE void updateScanStats(uint64_t endTime)
210
{
211
if (_entityIncrementStartTime >= endTime) {
212
/* overflow */
213
_env->_rootScannerStats._entityScanTime[_scanningEntity] += 1;
214
} else {
215
uint64_t duration = endTime - _entityIncrementStartTime;
216
_env->_rootScannerStats._entityScanTime[_scanningEntity] += duration;
217
if (duration > _env->_rootScannerStats._maxIncrementTime) {
218
_env->_rootScannerStats._maxIncrementTime = duration;
219
_env->_rootScannerStats._maxIncrementEntity = _scanningEntity;
220
}
221
}
222
}
223
224
/**
225
* Sets the currently scanned root entity to None and sets the last scanned root
226
* entity to scannedEntity. This is mainly for debug purposes.
227
* @param scannedEntity The entity for which scanning has ended.
228
*/
229
MMINLINE void
230
reportScanningEnded(RootScannerEntity scannedEntity)
231
{
232
/* Ensures scanning ended for the currently scanned entity. */
233
Assert_MM_true(_scanningEntity == scannedEntity);
234
235
if (_extensions->rootScannerStatsEnabled) {
236
OMRPORT_ACCESS_FROM_OMRVM(_omrVM);
237
uint64_t entityEndScanTime = omrtime_hires_clock();
238
239
_env->_rootScannerStats._statsUsed = true;
240
_extensions->rootScannerStatsUsed = true;
241
242
updateScanStats(entityEndScanTime);
243
244
_entityStartScanTime = 0;
245
/* In theory, it would be cleaner to reset _entityIncrementStartTime to 0, but sometimes increments could be dis-associated from any entity.
246
For example sync barrier between two entities. Since they can suspend, they will try to report the duration of the increment,
247
but the start point 0 would lead to invalid (too long duration). Hence, we set the start point to the current time, just in case it
248
is used be non-tracked increments.
249
*/
250
_entityIncrementStartTime = entityEndScanTime;
251
}
252
253
_lastScannedEntity = _scanningEntity;
254
_scanningEntity = RootScannerEntity_None;
255
}
256
257
/**
258
* Scans Modularity objects that are owned by a given class loader
259
* @param classLoader The class loader in question
260
*/
261
void scanModularityObjects(J9ClassLoader * classLoader);
262
263
public:
264
265
/**
266
* Maintain start/end increment times when scan is suspended. Add the diff (duration) to scan entity time.
267
* Also maintain max increment duration and its entity
268
*/
269
MMINLINE void
270
reportScanningSuspended()
271
{
272
if (_extensions->rootScannerStatsEnabled) {
273
OMRPORT_ACCESS_FROM_OMRVM(_omrVM);
274
_entityIncrementEndTime = omrtime_hires_clock();
275
276
updateScanStats(_entityIncrementEndTime);
277
}
278
}
279
280
/**
281
* Maintain start/end increment times, when scan is resumed.
282
*/
283
MMINLINE void
284
reportScanningResumed()
285
{
286
if (_extensions->rootScannerStatsEnabled) {
287
OMRPORT_ACCESS_FROM_OMRVM(_omrVM);
288
_entityIncrementStartTime = omrtime_hires_clock();
289
_entityIncrementEndTime = 0;
290
}
291
}
292
293
MM_RootScanner(MM_EnvironmentBase *env, bool singleThread = false)
294
: MM_BaseVirtual()
295
, _env(env)
296
, _extensions(MM_GCExtensions::getExtensions(env))
297
, _clij((MM_CollectorLanguageInterfaceImpl *)_extensions->collectorLanguageInterface)
298
, _omrVM(env->getOmrVM())
299
, _stringTableAsRoot(true)
300
, _jniWeakGlobalReferencesTableAsRoot(false)
301
, _singleThread(singleThread)
302
, _nurseryReferencesOnly(false)
303
, _nurseryReferencesPossibly(false)
304
, _includeStackFrameClassReferences(true)
305
#if defined(J9VM_GC_MODRON_SCAVENGER)
306
, _includeRememberedSetReferences(_extensions->scavengerEnabled ? true : false)
307
#endif /* J9VM_GC_MODRON_SCAVENGER */
308
, _classDataAsRoots(true)
309
, _includeJVMTIObjectTagTables(true)
310
#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)
311
, _includeDoubleMap(_extensions->indexableObjectModel.isDoubleMappingEnabled())
312
#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */
313
, _trackVisibleStackFrameDepth(false)
314
, _entityStartScanTime(0)
315
, _entityIncrementStartTime(0)
316
, _entityIncrementEndTime(0)
317
, _scanningEntity(RootScannerEntity_None)
318
, _lastScannedEntity(RootScannerEntity_None)
319
{
320
_typeId = __FUNCTION__;
321
322
OMRPORT_ACCESS_FROM_OMRVM(_omrVM);
323
_entityIncrementStartTime = omrtime_hires_clock();
324
325
}
326
327
/**
328
* Return codes from root scanner complete phase calls that are allowable by implementers.
329
*/
330
typedef enum {
331
complete_phase_OK = 0, /**< Continue scanning */
332
complete_phase_ABORT, /**< Abort all further scanning */
333
} CompletePhaseCode;
334
335
/** Set whether the string table should be treated as a hard root or not */
336
void setStringTableAsRoot(bool stringTableAsRoot) {
337
_stringTableAsRoot = stringTableAsRoot;
338
}
339
340
#if defined(J9VM_GC_MODRON_SCAVENGER)
341
/** Set whether the iterator will only scan structures which contain nursery references */
342
void setNurseryReferencesOnly(bool nurseryReferencesOnly) {
343
_nurseryReferencesOnly = nurseryReferencesOnly;
344
}
345
346
/** Set whether the iterator will only scan structures which may contain nursery references */
347
void setNurseryReferencesPossibly(bool nurseryReferencesPossibly) {
348
_nurseryReferencesPossibly = nurseryReferencesPossibly;
349
}
350
351
/** Set whether the iterator will scan the remembered set references (if applicable to the scan type) */
352
void setIncludeRememberedSetReferences(bool includeRememberedSetReferences) {
353
_includeRememberedSetReferences = includeRememberedSetReferences;
354
}
355
#endif /* J9VM_GC_MODRON_SCAVENGER */
356
357
/** Set whether the iterator will scan stack frames for the classes of running methods */
358
void setIncludeStackFrameClassReferences(bool includeStackFrameClassReferences) {
359
_includeStackFrameClassReferences = includeStackFrameClassReferences;
360
}
361
362
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
363
/** Set whether all classes and their classloaders (or only permanent ones) are considered roots */
364
void setClassDataAsRoots(bool classDataAsRoots) {
365
_classDataAsRoots = classDataAsRoots;
366
}
367
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
368
369
#if defined(J9VM_OPT_JVMTI)
370
/** Set whether the iterator will scan the JVMTIObjectTagTables (if applicable to the scan type) */
371
void setIncludeJVMTIObjectTagTables(bool includeJVMTIObjectTagTables) {
372
_includeJVMTIObjectTagTables = includeJVMTIObjectTagTables;
373
}
374
#endif /* J9VM_OPT_JVMTI */
375
376
/** Set whether the iterator will scan the JVMTIObjectTagTables (if applicable to the scan type) */
377
void setTrackVisibleStackFrameDepth(bool trackVisibleStackFrameDepth) {
378
_trackVisibleStackFrameDepth = trackVisibleStackFrameDepth;
379
}
380
381
/** General object slot handler to be reimplemented by specializing class. This handler is called for every reference to a J9Object. */
382
virtual void doSlot(J9Object** slotPtr) = 0;
383
384
/** General class slot handler to be reimplemented by specializing class. This handler is called for every reference to a J9Class. */
385
virtual void doClassSlot(J9Class *classPtr);
386
387
/** General class handler to be reimplemented by specializing class. This handler is called once per class. */
388
virtual void doClass(J9Class *clazz) = 0;
389
390
/**
391
* Scan object field
392
* @param slotObject for field
393
*/
394
virtual void doFieldSlot(GC_SlotObject * slotObject);
395
396
virtual void scanRoots(MM_EnvironmentBase *env);
397
virtual void scanClearable(MM_EnvironmentBase *env);
398
virtual void scanAllSlots(MM_EnvironmentBase *env);
399
400
#if defined(J9VM_GC_MODRON_SCAVENGER)
401
virtual void scanRememberedSet(MM_EnvironmentBase *env);
402
#endif /* J9VM_GC_MODRON_SCAVENGER */
403
404
virtual void scanClasses(MM_EnvironmentBase *env);
405
virtual void scanVMClassSlots(MM_EnvironmentBase *env);
406
407
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
408
void scanPermanentClasses(MM_EnvironmentBase *env);
409
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
410
virtual CompletePhaseCode scanClassesComplete(MM_EnvironmentBase *env);
411
412
virtual bool scanOneThread(MM_EnvironmentBase *env, J9VMThread* walkThread, void* localData);
413
414
virtual void scanClassLoaders(MM_EnvironmentBase *env);
415
virtual void scanThreads(MM_EnvironmentBase *env);
416
virtual void scanSingleThread(MM_EnvironmentBase *env, J9VMThread* walkThread);
417
#if defined(J9VM_GC_FINALIZATION)
418
virtual void scanFinalizableObjects(MM_EnvironmentBase *env);
419
virtual void scanUnfinalizedObjects(MM_EnvironmentBase *env);
420
#endif /* J9VM_GC_FINALIZATION */
421
422
/**
423
* @todo Provide function documentation
424
*
425
* @NOTE this can only be used as a READ-ONLY version of the ownableSynchronizerObjectList.
426
* If you need to modify elements with-in the list you will need to provide your own functionality.
427
* See MM_MarkingScheme::scanUnfinalizedObjects(MM_EnvironmentStandard *env) as an example
428
* which modifies elements within the list.
429
*/
430
virtual void scanOwnableSynchronizerObjects(MM_EnvironmentBase *env);
431
virtual void scanStringTable(MM_EnvironmentBase *env);
432
void scanJNIGlobalReferences(MM_EnvironmentBase *env);
433
virtual void scanJNIWeakGlobalReferences(MM_EnvironmentBase *env);
434
435
virtual void scanMonitorReferences(MM_EnvironmentBase *env);
436
virtual CompletePhaseCode scanMonitorReferencesComplete(MM_EnvironmentBase *env);
437
virtual void scanMonitorLookupCaches(MM_EnvironmentBase *env);
438
439
#if defined(J9VM_OPT_JVMTI)
440
void scanJVMTIObjectTagTables(MM_EnvironmentBase *env);
441
#endif /* J9VM_OPT_JVMTI */
442
443
#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)
444
/**
445
* Scans each heap region for arraylet leaves that contains a not NULL
446
* contiguous address. This address points to a contiguous representation
447
* of the arraylet associated with this leaf. Only arraylets that has been
448
* double mapped will contain such contiguous address, otherwise the
449
* address will be NULL
450
*
451
* @param env thread GC Environment
452
*/
453
void scanDoubleMappedObjects(MM_EnvironmentBase *env);
454
#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */
455
456
virtual void doClassLoader(J9ClassLoader *classLoader);
457
458
virtual void scanWeakReferenceObjects(MM_EnvironmentBase *env);
459
virtual CompletePhaseCode scanWeakReferencesComplete(MM_EnvironmentBase *env);
460
461
virtual void scanSoftReferenceObjects(MM_EnvironmentBase *env);
462
virtual void scanPhantomReferenceObjects(MM_EnvironmentBase *env);
463
virtual CompletePhaseCode scanSoftReferencesComplete(MM_EnvironmentBase *env);
464
virtual CompletePhaseCode scanPhantomReferencesComplete(MM_EnvironmentBase *env);
465
466
#if defined(J9VM_GC_FINALIZATION)
467
virtual void doFinalizableObject(J9Object *objectPtr) = 0;
468
/**
469
* Handle an unfinalized object
470
*
471
* @param objectPtr the unfinalized object
472
* @param list the list which this object belongs too.
473
*
474
* @NOTE If a subclass does not override this function to provide an implementation it must override
475
* scanUnfinalizedObjects so that this function is not called.
476
*/
477
virtual void doUnfinalizedObject(J9Object *objectPtr, MM_UnfinalizedObjectList *list);
478
virtual CompletePhaseCode scanUnfinalizedObjectsComplete(MM_EnvironmentBase *env);
479
#endif /* J9VM_GC_FINALIZATION */
480
481
/**
482
* @todo Provide function documentation
483
*/
484
virtual void doOwnableSynchronizerObject(J9Object *objectPtr, MM_OwnableSynchronizerObjectList *list);
485
486
/**
487
* @todo Provide function documentation
488
*/
489
virtual CompletePhaseCode scanOwnableSynchronizerObjectsComplete(MM_EnvironmentBase *env);
490
491
virtual void doMonitorReference(J9ObjectMonitor *objectMonitor, GC_HashTableIterator *monitorReferenceIterator);
492
virtual void doMonitorLookupCacheSlot(j9objectmonitor_t* slotPtr);
493
494
virtual void doJNIWeakGlobalReference(J9Object **slotPtr);
495
virtual void doJNIGlobalReferenceSlot(J9Object **slotPtr, GC_JNIGlobalReferenceIterator *jniGlobalReferenceIterator);
496
497
#if defined(J9VM_GC_MODRON_SCAVENGER)
498
virtual void doRememberedSetSlot(J9Object **slotPtr, GC_RememberedSetSlotIterator *rememberedSetSlotIterator);
499
#endif /* defined(J9VM_GC_MODRON_SCAVENGER) */
500
501
#if defined(J9VM_OPT_JVMTI)
502
virtual void doJVMTIObjectTagSlot(J9Object **slotPtr, GC_JVMTIObjectTagTableIterator *objectTagTableIterator);
503
#endif /* J9VM_OPT_JVMTI */
504
505
virtual void doStringTableSlot(J9Object **slotPtr, GC_StringTableIterator *stringTableIterator);
506
virtual void doStringCacheTableSlot(J9Object **slotPtr);
507
virtual void doVMClassSlot(J9Class *classPtr);
508
virtual void doVMThreadSlot(J9Object **slotPtr, GC_VMThreadIterator *vmThreadIterator);
509
#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)
510
/**
511
* Frees double mapped region associated to objectPtr (arraylet spine) if objectPtr
512
* is not live
513
*
514
* @param objectPtr[in] indexable object's spine
515
* @param identifier[in/out] identifier associated with object's spine, which contains
516
* doble mapped address and size
517
*/
518
virtual void doDoubleMappedObjectSlot(J9Object *objectPtr, struct J9PortVmemIdentifier *identifier);
519
#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */
520
521
/**
522
* Called for each object stack slot. Subclasses may override.
523
*
524
* @param slotPtr[in/out] a pointer to the stack slot or a copy of the stack slot.
525
* @param walkState[in] the J9StackWalkState
526
* @param stackLocation[in] the actual pointer to the stack slot. Use only for reporting.
527
*/
528
virtual void doStackSlot(J9Object **slotPtr, void *walkState, const void *stackLocation);
529
};
530
531
typedef struct StackIteratorData {
532
MM_RootScanner *rootScanner;
533
MM_EnvironmentBase *env;
534
} StackIteratorData;
535
536
#endif /* ROOTSCANNER_HPP_ */
537
538