Path: blob/master/runtime/gc_base/RootScanner.hpp
5985 views
1/*******************************************************************************2* Copyright (c) 1991, 2021 IBM Corp. and others3*4* This program and the accompanying materials are made available under5* the terms of the Eclipse Public License 2.0 which accompanies this6* 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 and8* is available at https://www.apache.org/licenses/LICENSE-2.0.9*10* This Source Code may also be made available under the following11* Secondary Licenses when the conditions for such availability set12* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU13* General Public License, version 2 with the GNU Classpath14* Exception [1] and GNU General Public License, version 2 with the15* OpenJDK Assembly Exception [2].16*17* [1] https://www.gnu.org/software/classpath/license.html18* [2] http://openjdk.java.net/legal/assembly-exception.html19*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-exception21*******************************************************************************/2223/**24* @file25* @ingroup GC_Base26*/2728#ifndef ROOTSCANNER_HPP_29#define ROOTSCANNER_HPP_3031#include "j9.h"32#include "j9cfg.h"33#include "omr.h"3435#include "BaseVirtual.hpp"3637#include "EnvironmentBase.hpp"38#include "GCExtensions.hpp"39#include "JVMTIObjectTagTableIterator.hpp"40#include "ModronTypes.hpp"41#include "RootScannerTypes.h"42#include "Task.hpp"43#include "VMClassSlotIterator.hpp"4445class GC_SlotObject;46class MM_MemoryPool;47class MM_CollectorLanguageInterfaceImpl;4849/**50* General interface for scanning all object and class slots in the system that are not part of the heap.51*52* MM_RootScanner provides an abstract class that can be specialized to scan particular slots53* in the system, including all, root specific and clearable slots. The purpose of the class is54* to provide a central location for general slot scanners within Modron (e.g., root scanning,55* all slots do, etc).56*57* There are two levels of specialization for the scanner, structure walking and handling of elements.58* Structure walking specialization, where the implementer can override the way in which we walk elements,59* should be done rarely and in only extreme circumstances. Handling of elements can be specialized for all60* elements as well as for specific types of structures.61*62* The core routines to be reimplemented are doSlot(J9Object **), doClassSlot(J9Class *) and doClass(J9Class *).63* All other slot types are forwarded by default to these routines for processing. To handle structure slots in64* specific ways, the slot handler for that type should be overridden.65*66* @ingroup GC_Base67*/68class MM_RootScanner : public MM_BaseVirtual69{70/*71* Data members72*/73private:7475protected:76MM_EnvironmentBase *_env;77MM_GCExtensions *_extensions;78MM_CollectorLanguageInterfaceImpl *_clij;79OMR_VM *_omrVM;8081bool _stringTableAsRoot; /**< Treat the string table as a hard root */82bool _jniWeakGlobalReferencesTableAsRoot; /**< Treat JNI Weak References Table as a hard root */83bool _singleThread; /**< Should the iterator operate in single threaded mode */8485bool _nurseryReferencesOnly; /**< Should the iterator only scan structures that currently contain nursery references */86bool _nurseryReferencesPossibly; /**< Should the iterator only scan structures that may contain nursery references */87bool _includeStackFrameClassReferences; /**< Should the iterator include Classes which have a method running on the stack */88#if defined(J9VM_GC_MODRON_SCAVENGER)89bool _includeRememberedSetReferences; /**< Should the iterator include references in the Remembered Set (if applicable) */90#endif /* J9VM_GC_MODRON_SCAVENGER */91bool _classDataAsRoots; /**< Should all classes (and class loaders) be treated as roots. Default true, should set to false when class unloading */92bool _includeJVMTIObjectTagTables; /**< Should the iterator include the JVMTIObjectTagTables. Default true, should set to false when doing JVMTI object walks */93#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)94bool _includeDoubleMap; /**< Enables doublemap should the GC policy be balanced. Default is false. */95#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */96bool _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 */9798U_64 _entityStartScanTime; /**< The start time of the scan of the current scanning entity, or 0 if no entity is being scanned. Defaults to 0. */99U_64 _entityIncrementStartTime; /**< Start time of current increment with a scan entity (Metronome may have several increment for each entity) */100U_64 _entityIncrementEndTime; /**< End time of the current increment */101RootScannerEntity _scanningEntity; /**< The root scanner entity that is currently being scanned. Defaults to RootScannerEntity_None. */102RootScannerEntity _lastScannedEntity; /**< The root scanner entity that was last scanned. Defaults to RootScannerEntity_None. */103104/*105* Function members106*/107private:108/**109* Scan all fields of mixed object110* @param objectPtr address of object to scan111*/112void scanMixedObject(J9Object *objectPtr);113114/**115* Scan all fields of pointer array object116* @param objectPtr address of object to scan117* @param memoryPool current memory pool118* @param manager current region manager119* @param memoryType memory type120*/121void scanArrayObject(MM_EnvironmentBase *env, J9Object *objectPtr, MM_MemoryPool *memoryPool, MM_HeapRegionManager *manager, UDATA memoryType);122123protected:124/**125* Determine whether running method classes in stack frames should be walked.126* @return boolean determining whether running method classes in stack frames should be walked127*/128MMINLINE bool isStackFrameClassWalkNeeded() {129if (_nurseryReferencesOnly || _nurseryReferencesPossibly) {130return false;131}132return _includeStackFrameClassReferences;133}134135/* Family of yielding methods to be overridden by incremental scanners such136* as the RealtimeRootScanner. The default implementations of these do137* nothing.138*/139140/**141* Root scanning methods that have been incrementalized are responsible for142* calling this method periodically during class scan to check when they should143* yield.144* @return true if the GC should yield, false otherwise145*/146virtual bool shouldYieldFromClassScan(UDATA timeSlackNanoSec = 0);147148/**149* Root scanning methods that have been incrementalized are responsible for150* calling this method periodically during string scan to check when they should151* yield.152* @return true if the GC should yield, false otherwise153*/154virtual bool shouldYieldFromStringScan();155156/**157* Root scanning methods that have been incrementalized are responsible for158* calling this method periodically during monitor scan to check when they should159* yield.160* @return true if the GC should yield, false otherwise161*/162virtual bool shouldYieldFromMonitorScan();163164/**165* Root scanning methods that have been incrementalized are responsible for166* calling this method periodically to check when they should yield.167* @return true if the GC should yield, false otherwise168*/169virtual bool shouldYield();170171/**172* Root scanning methods that have been incrementalized should call this method173* after determining that it should yield and after releasing locks held during174* root processing. Upon returning from this method, the root scanner is175* responsible for re-acquiring necessary locks. The integrity of iterators176* and the semantics of atomicity are not ensured and must be examined on a177* case-by-case basis.178*/179virtual void yield();180181/**182* Two in one method which amounts to yield if shouldYield is true.183* @return true if yielded, false otherwise184*/185virtual bool condYield(U_64 timeSlackNanoSec = 0);186187virtual void flushRequiredNonAllocationCaches(MM_EnvironmentBase *envModron){}188189/**190* Sets the currently scanned root entity to scanningEntity. This is mainly for191* debug purposes.192* @param scanningEntity The entity for which scanning has begun.193*/194MMINLINE void195reportScanningStarted(RootScannerEntity scanningEntity)196{197/* Ensures reportScanningEnded was called previously. */198assume0(RootScannerEntity_None == _scanningEntity);199_scanningEntity = scanningEntity;200201if (_extensions->rootScannerStatsEnabled) {202OMRPORT_ACCESS_FROM_OMRVM(_omrVM);203_entityStartScanTime = omrtime_hires_clock();204_entityIncrementStartTime = _entityStartScanTime;205}206}207208MMINLINE void updateScanStats(uint64_t endTime)209{210if (_entityIncrementStartTime >= endTime) {211/* overflow */212_env->_rootScannerStats._entityScanTime[_scanningEntity] += 1;213} else {214uint64_t duration = endTime - _entityIncrementStartTime;215_env->_rootScannerStats._entityScanTime[_scanningEntity] += duration;216if (duration > _env->_rootScannerStats._maxIncrementTime) {217_env->_rootScannerStats._maxIncrementTime = duration;218_env->_rootScannerStats._maxIncrementEntity = _scanningEntity;219}220}221}222223/**224* Sets the currently scanned root entity to None and sets the last scanned root225* entity to scannedEntity. This is mainly for debug purposes.226* @param scannedEntity The entity for which scanning has ended.227*/228MMINLINE void229reportScanningEnded(RootScannerEntity scannedEntity)230{231/* Ensures scanning ended for the currently scanned entity. */232Assert_MM_true(_scanningEntity == scannedEntity);233234if (_extensions->rootScannerStatsEnabled) {235OMRPORT_ACCESS_FROM_OMRVM(_omrVM);236uint64_t entityEndScanTime = omrtime_hires_clock();237238_env->_rootScannerStats._statsUsed = true;239_extensions->rootScannerStatsUsed = true;240241updateScanStats(entityEndScanTime);242243_entityStartScanTime = 0;244/* In theory, it would be cleaner to reset _entityIncrementStartTime to 0, but sometimes increments could be dis-associated from any entity.245For example sync barrier between two entities. Since they can suspend, they will try to report the duration of the increment,246but the start point 0 would lead to invalid (too long duration). Hence, we set the start point to the current time, just in case it247is used be non-tracked increments.248*/249_entityIncrementStartTime = entityEndScanTime;250}251252_lastScannedEntity = _scanningEntity;253_scanningEntity = RootScannerEntity_None;254}255256/**257* Scans Modularity objects that are owned by a given class loader258* @param classLoader The class loader in question259*/260void scanModularityObjects(J9ClassLoader * classLoader);261262public:263264/**265* Maintain start/end increment times when scan is suspended. Add the diff (duration) to scan entity time.266* Also maintain max increment duration and its entity267*/268MMINLINE void269reportScanningSuspended()270{271if (_extensions->rootScannerStatsEnabled) {272OMRPORT_ACCESS_FROM_OMRVM(_omrVM);273_entityIncrementEndTime = omrtime_hires_clock();274275updateScanStats(_entityIncrementEndTime);276}277}278279/**280* Maintain start/end increment times, when scan is resumed.281*/282MMINLINE void283reportScanningResumed()284{285if (_extensions->rootScannerStatsEnabled) {286OMRPORT_ACCESS_FROM_OMRVM(_omrVM);287_entityIncrementStartTime = omrtime_hires_clock();288_entityIncrementEndTime = 0;289}290}291292MM_RootScanner(MM_EnvironmentBase *env, bool singleThread = false)293: MM_BaseVirtual()294, _env(env)295, _extensions(MM_GCExtensions::getExtensions(env))296, _clij((MM_CollectorLanguageInterfaceImpl *)_extensions->collectorLanguageInterface)297, _omrVM(env->getOmrVM())298, _stringTableAsRoot(true)299, _jniWeakGlobalReferencesTableAsRoot(false)300, _singleThread(singleThread)301, _nurseryReferencesOnly(false)302, _nurseryReferencesPossibly(false)303, _includeStackFrameClassReferences(true)304#if defined(J9VM_GC_MODRON_SCAVENGER)305, _includeRememberedSetReferences(_extensions->scavengerEnabled ? true : false)306#endif /* J9VM_GC_MODRON_SCAVENGER */307, _classDataAsRoots(true)308, _includeJVMTIObjectTagTables(true)309#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)310, _includeDoubleMap(_extensions->indexableObjectModel.isDoubleMappingEnabled())311#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */312, _trackVisibleStackFrameDepth(false)313, _entityStartScanTime(0)314, _entityIncrementStartTime(0)315, _entityIncrementEndTime(0)316, _scanningEntity(RootScannerEntity_None)317, _lastScannedEntity(RootScannerEntity_None)318{319_typeId = __FUNCTION__;320321OMRPORT_ACCESS_FROM_OMRVM(_omrVM);322_entityIncrementStartTime = omrtime_hires_clock();323324}325326/**327* Return codes from root scanner complete phase calls that are allowable by implementers.328*/329typedef enum {330complete_phase_OK = 0, /**< Continue scanning */331complete_phase_ABORT, /**< Abort all further scanning */332} CompletePhaseCode;333334/** Set whether the string table should be treated as a hard root or not */335void setStringTableAsRoot(bool stringTableAsRoot) {336_stringTableAsRoot = stringTableAsRoot;337}338339#if defined(J9VM_GC_MODRON_SCAVENGER)340/** Set whether the iterator will only scan structures which contain nursery references */341void setNurseryReferencesOnly(bool nurseryReferencesOnly) {342_nurseryReferencesOnly = nurseryReferencesOnly;343}344345/** Set whether the iterator will only scan structures which may contain nursery references */346void setNurseryReferencesPossibly(bool nurseryReferencesPossibly) {347_nurseryReferencesPossibly = nurseryReferencesPossibly;348}349350/** Set whether the iterator will scan the remembered set references (if applicable to the scan type) */351void setIncludeRememberedSetReferences(bool includeRememberedSetReferences) {352_includeRememberedSetReferences = includeRememberedSetReferences;353}354#endif /* J9VM_GC_MODRON_SCAVENGER */355356/** Set whether the iterator will scan stack frames for the classes of running methods */357void setIncludeStackFrameClassReferences(bool includeStackFrameClassReferences) {358_includeStackFrameClassReferences = includeStackFrameClassReferences;359}360361#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)362/** Set whether all classes and their classloaders (or only permanent ones) are considered roots */363void setClassDataAsRoots(bool classDataAsRoots) {364_classDataAsRoots = classDataAsRoots;365}366#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */367368#if defined(J9VM_OPT_JVMTI)369/** Set whether the iterator will scan the JVMTIObjectTagTables (if applicable to the scan type) */370void setIncludeJVMTIObjectTagTables(bool includeJVMTIObjectTagTables) {371_includeJVMTIObjectTagTables = includeJVMTIObjectTagTables;372}373#endif /* J9VM_OPT_JVMTI */374375/** Set whether the iterator will scan the JVMTIObjectTagTables (if applicable to the scan type) */376void setTrackVisibleStackFrameDepth(bool trackVisibleStackFrameDepth) {377_trackVisibleStackFrameDepth = trackVisibleStackFrameDepth;378}379380/** General object slot handler to be reimplemented by specializing class. This handler is called for every reference to a J9Object. */381virtual void doSlot(J9Object** slotPtr) = 0;382383/** General class slot handler to be reimplemented by specializing class. This handler is called for every reference to a J9Class. */384virtual void doClassSlot(J9Class *classPtr);385386/** General class handler to be reimplemented by specializing class. This handler is called once per class. */387virtual void doClass(J9Class *clazz) = 0;388389/**390* Scan object field391* @param slotObject for field392*/393virtual void doFieldSlot(GC_SlotObject * slotObject);394395virtual void scanRoots(MM_EnvironmentBase *env);396virtual void scanClearable(MM_EnvironmentBase *env);397virtual void scanAllSlots(MM_EnvironmentBase *env);398399#if defined(J9VM_GC_MODRON_SCAVENGER)400virtual void scanRememberedSet(MM_EnvironmentBase *env);401#endif /* J9VM_GC_MODRON_SCAVENGER */402403virtual void scanClasses(MM_EnvironmentBase *env);404virtual void scanVMClassSlots(MM_EnvironmentBase *env);405406#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)407void scanPermanentClasses(MM_EnvironmentBase *env);408#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */409virtual CompletePhaseCode scanClassesComplete(MM_EnvironmentBase *env);410411virtual bool scanOneThread(MM_EnvironmentBase *env, J9VMThread* walkThread, void* localData);412413virtual void scanClassLoaders(MM_EnvironmentBase *env);414virtual void scanThreads(MM_EnvironmentBase *env);415virtual void scanSingleThread(MM_EnvironmentBase *env, J9VMThread* walkThread);416#if defined(J9VM_GC_FINALIZATION)417virtual void scanFinalizableObjects(MM_EnvironmentBase *env);418virtual void scanUnfinalizedObjects(MM_EnvironmentBase *env);419#endif /* J9VM_GC_FINALIZATION */420421/**422* @todo Provide function documentation423*424* @NOTE this can only be used as a READ-ONLY version of the ownableSynchronizerObjectList.425* If you need to modify elements with-in the list you will need to provide your own functionality.426* See MM_MarkingScheme::scanUnfinalizedObjects(MM_EnvironmentStandard *env) as an example427* which modifies elements within the list.428*/429virtual void scanOwnableSynchronizerObjects(MM_EnvironmentBase *env);430virtual void scanStringTable(MM_EnvironmentBase *env);431void scanJNIGlobalReferences(MM_EnvironmentBase *env);432virtual void scanJNIWeakGlobalReferences(MM_EnvironmentBase *env);433434virtual void scanMonitorReferences(MM_EnvironmentBase *env);435virtual CompletePhaseCode scanMonitorReferencesComplete(MM_EnvironmentBase *env);436virtual void scanMonitorLookupCaches(MM_EnvironmentBase *env);437438#if defined(J9VM_OPT_JVMTI)439void scanJVMTIObjectTagTables(MM_EnvironmentBase *env);440#endif /* J9VM_OPT_JVMTI */441442#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)443/**444* Scans each heap region for arraylet leaves that contains a not NULL445* contiguous address. This address points to a contiguous representation446* of the arraylet associated with this leaf. Only arraylets that has been447* double mapped will contain such contiguous address, otherwise the448* address will be NULL449*450* @param env thread GC Environment451*/452void scanDoubleMappedObjects(MM_EnvironmentBase *env);453#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */454455virtual void doClassLoader(J9ClassLoader *classLoader);456457virtual void scanWeakReferenceObjects(MM_EnvironmentBase *env);458virtual CompletePhaseCode scanWeakReferencesComplete(MM_EnvironmentBase *env);459460virtual void scanSoftReferenceObjects(MM_EnvironmentBase *env);461virtual void scanPhantomReferenceObjects(MM_EnvironmentBase *env);462virtual CompletePhaseCode scanSoftReferencesComplete(MM_EnvironmentBase *env);463virtual CompletePhaseCode scanPhantomReferencesComplete(MM_EnvironmentBase *env);464465#if defined(J9VM_GC_FINALIZATION)466virtual void doFinalizableObject(J9Object *objectPtr) = 0;467/**468* Handle an unfinalized object469*470* @param objectPtr the unfinalized object471* @param list the list which this object belongs too.472*473* @NOTE If a subclass does not override this function to provide an implementation it must override474* scanUnfinalizedObjects so that this function is not called.475*/476virtual void doUnfinalizedObject(J9Object *objectPtr, MM_UnfinalizedObjectList *list);477virtual CompletePhaseCode scanUnfinalizedObjectsComplete(MM_EnvironmentBase *env);478#endif /* J9VM_GC_FINALIZATION */479480/**481* @todo Provide function documentation482*/483virtual void doOwnableSynchronizerObject(J9Object *objectPtr, MM_OwnableSynchronizerObjectList *list);484485/**486* @todo Provide function documentation487*/488virtual CompletePhaseCode scanOwnableSynchronizerObjectsComplete(MM_EnvironmentBase *env);489490virtual void doMonitorReference(J9ObjectMonitor *objectMonitor, GC_HashTableIterator *monitorReferenceIterator);491virtual void doMonitorLookupCacheSlot(j9objectmonitor_t* slotPtr);492493virtual void doJNIWeakGlobalReference(J9Object **slotPtr);494virtual void doJNIGlobalReferenceSlot(J9Object **slotPtr, GC_JNIGlobalReferenceIterator *jniGlobalReferenceIterator);495496#if defined(J9VM_GC_MODRON_SCAVENGER)497virtual void doRememberedSetSlot(J9Object **slotPtr, GC_RememberedSetSlotIterator *rememberedSetSlotIterator);498#endif /* defined(J9VM_GC_MODRON_SCAVENGER) */499500#if defined(J9VM_OPT_JVMTI)501virtual void doJVMTIObjectTagSlot(J9Object **slotPtr, GC_JVMTIObjectTagTableIterator *objectTagTableIterator);502#endif /* J9VM_OPT_JVMTI */503504virtual void doStringTableSlot(J9Object **slotPtr, GC_StringTableIterator *stringTableIterator);505virtual void doStringCacheTableSlot(J9Object **slotPtr);506virtual void doVMClassSlot(J9Class *classPtr);507virtual void doVMThreadSlot(J9Object **slotPtr, GC_VMThreadIterator *vmThreadIterator);508#if defined(J9VM_GC_ENABLE_DOUBLE_MAP)509/**510* Frees double mapped region associated to objectPtr (arraylet spine) if objectPtr511* is not live512*513* @param objectPtr[in] indexable object's spine514* @param identifier[in/out] identifier associated with object's spine, which contains515* doble mapped address and size516*/517virtual void doDoubleMappedObjectSlot(J9Object *objectPtr, struct J9PortVmemIdentifier *identifier);518#endif /* J9VM_GC_ENABLE_DOUBLE_MAP */519520/**521* Called for each object stack slot. Subclasses may override.522*523* @param slotPtr[in/out] a pointer to the stack slot or a copy of the stack slot.524* @param walkState[in] the J9StackWalkState525* @param stackLocation[in] the actual pointer to the stack slot. Use only for reporting.526*/527virtual void doStackSlot(J9Object **slotPtr, void *walkState, const void *stackLocation);528};529530typedef struct StackIteratorData {531MM_RootScanner *rootScanner;532MM_EnvironmentBase *env;533} StackIteratorData;534535#endif /* ROOTSCANNER_HPP_ */536537538