Path: blob/master/runtime/gc_base/ReferenceChainWalker.cpp
5986 views
/*******************************************************************************1* Copyright (c) 1991, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* 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-exception20*******************************************************************************/2122#include "ReferenceChainWalker.hpp"2324#include "j9cfg.h"25#include "j9consts.h"26#include "omrgcconsts.h"27#include "j9cp.h"28#include "j9port.h"29#include "modron.h"30#include "omr.h"3132#include "ClassIteratorClassSlots.hpp"33#include "ClassIteratorDeclarationOrder.hpp"34#include "EnvironmentBase.hpp"35#include "Forge.hpp"36#include "GCExtensions.hpp"37#include "Heap.hpp"38#include "HeapRegionIterator.hpp"39#include "MixedObjectDeclarationOrderIterator.hpp"40#include "ModronAssertions.h"41#include "ObjectHeapBufferedIterator.hpp"42#include "ObjectModel.hpp"43#include "PointerArrayIterator.hpp"44#include "SlotObject.hpp"45#include "VMThreadIterator.hpp"4647class GC_HashTableIterator;48class GC_JVMTIObjectTagTableIterator;49class GC_VMClassSlotIterator;50class MM_HeapRegionDescriptor;51class MM_HeapRegionManager;52class MM_OwnableSynchronizerObjectList;53class MM_UnfinalizedObjectList;5455#define TEMP_RCW_STACK_SIZE (10 * 1024 * 1024)5657extern "C" {58/**59* Walk the reference chains starting at the root set, call user provided function.60* The user function will be called for each root with the type set to one of the61* J9GC_ROOT_TYPE_* values. A root may appear multiple times. The user function62* will be called for each reference once, with the type set to one of the63* J9GC_REFERENCE_TYPE_* values.64* @note This function requires the caller to already have exclusive.65* @param vmThread66* @param userCallback User function to be run for each root and reference67* @param userData Pointer to storage for userData.68*/69void70j9gc_ext_reachable_objects_do(71J9VMThread *vmThread,72J9MODRON_REFERENCE_CHAIN_WALKER_CALLBACK userCallback,73void *userData,74UDATA walkFlags)75{76MM_EnvironmentBase *env = MM_EnvironmentBase::getEnvironment(vmThread->omrVMThread);7778/* Make sure the heap is walkable (flush TLH's, secure heap integrity) */79vmThread->javaVM->memoryManagerFunctions->j9gc_flush_caches_for_walk(vmThread->javaVM);8081MM_ReferenceChainWalker referenceChainWalker(env, TEMP_RCW_STACK_SIZE, userCallback, userData);82if (referenceChainWalker.initialize(env)) {83#if defined(J9VM_OPT_JVMTI)84referenceChainWalker.setIncludeJVMTIObjectTagTables(0 == (walkFlags & J9_MU_WALK_SKIP_JVMTI_TAG_TABLES));85#endif /* J9VM_OPT_JVMTI */86referenceChainWalker.setTrackVisibleStackFrameDepth(0 != (walkFlags & J9_MU_WALK_TRACK_VISIBLE_FRAME_DEPTH));87referenceChainWalker.setPreindexInterfaceFields(0 != (walkFlags & J9_MU_WALK_PREINDEX_INTERFACE_FIELDS));88/* walker configuration complete. Scan objects... */89referenceChainWalker.scanReachableObjects(env);90referenceChainWalker.tearDown(env);91}92}9394/**95* Walk the reference chains starting at an object, call user provided function.96* The user function will be called for each reference once, with the type set to97* one of the J9GC_REFERENCE_TYPE_* values. An objects class and class loader are98* considered reachable.99* @note This function requires the caller to already have exclusive.100* @param vmThread101* @param userCallback User function to be run for each root and reference102* @param userData Pointer to storage for userData.103*/104void105j9gc_ext_reachable_from_object_do(106J9VMThread *vmThread,107J9Object *objectPtr,108J9MODRON_REFERENCE_CHAIN_WALKER_CALLBACK userCallback,109void *userData,110UDATA walkFlags)111{112MM_EnvironmentBase *env = MM_EnvironmentBase::getEnvironment(vmThread->omrVMThread);113114/* Make sure the heap is walkable (flush TLH's, secure heap integrity) */115vmThread->javaVM->memoryManagerFunctions->j9gc_flush_caches_for_walk(vmThread->javaVM);116117MM_ReferenceChainWalker referenceChainWalker(env, TEMP_RCW_STACK_SIZE, userCallback, userData);118if (referenceChainWalker.initialize(env)) {119referenceChainWalker.setPreindexInterfaceFields(0 != (walkFlags & J9_MU_WALK_PREINDEX_INTERFACE_FIELDS));120/* walker configuration complete. Scan objects... */121referenceChainWalker.scanReachableFromObject(env, objectPtr);122referenceChainWalker.tearDown(env);123}124}125} /* extern "C" */126127/**128* Initialized the internal structures.129* @param env130* @return true if successfully initialized.131*/132bool133MM_ReferenceChainWalker::initialize(MM_EnvironmentBase *env)134{135MM_GCExtensions *extensions = MM_GCExtensions::getExtensions(env);136_heap = _extensions->heap;137_heapBase = _heap->getHeapBase();138_heapTop = _heap->getHeapTop();139if (NULL == extensions->referenceChainWalkerMarkMap) {140/* first call - create a new Mark Map and initialize it */141_markMap = MM_ReferenceChainWalkerMarkMap::newInstance(env, _heap->getMaximumPhysicalRange());142if (NULL != _markMap) {143extensions->referenceChainWalkerMarkMap = _markMap;144}145} else {146/* mark map is already created, just zero it */147_markMap = extensions->referenceChainWalkerMarkMap;148_markMap->clearMap(env);149}150151bool result = (NULL != _markMap);152153if (result) {154_queue = (J9Object **)env->getForge()->allocate(_queueSlots * sizeof(J9Object **), MM_AllocationCategory::REFERENCES, J9_GET_CALLSITE());155if(NULL != _queue) {156_queueEnd = _queue + _queueSlots;157_queueCurrent = _queue;158} else {159result = false;160}161}162return result;163}164165/**166* Cleans up the internal structures.167* @param env168*/169void170MM_ReferenceChainWalker::tearDown(MM_EnvironmentBase *env)171{172if (NULL != _queue) {173env->getForge()->free(_queue);174_queue = NULL;175_queueEnd = NULL;176_queueCurrent = NULL;177}178179/* Mark Map should not be released here and stay active - will be released in MM_GCExtensions::tearDown */180}181182/**183* Main handler for each slot. Calls the <code>_userCallback</code> for each slot184* and adds the slot to queue for scanning.185* @param slotPtr pointer to the slot186* @param type root or reference type (J9GC_ROOT_TYPE_* or J9GC_REFERENCE_TYPE_*)187* @param index an index identifying the slot within the sourceObj188* @param sourceObj the object which contains this slot, or NULL if a root189*/190void191MM_ReferenceChainWalker::doSlot(J9Object **slotPtr, IDATA type, IDATA index, J9Object *sourceObj)192{193jvmtiIterationControl returnCode;194J9Object *objectPtr = *slotPtr;195196if ((NULL == objectPtr) || _isTerminating) {197return;198}199200/* call the call back before the object is corrupted */201returnCode = _userCallback(slotPtr, sourceObj, _userData, type, index, isMarked(objectPtr) ? 1 : 0);202203if (JVMTI_ITERATION_CONTINUE == returnCode) {204pushObject(objectPtr);205} else if (JVMTI_ITERATION_ABORT == returnCode) {206_isTerminating = true;207clearQueue();208}209}210211/**212* Main handler for each class slot. Calls the <code>_userCallback</code> for each slot213* and adds the slot to queue for scanning.214* @param slotPtr pointer to the class slot215* @param type root or reference type (J9GC_ROOT_TYPE_* or J9GC_REFERENCE_TYPE_*)216* @param index an index identifying the slot within the sourceObj217* @param sourceObj the object which contains this slot, or NULL if a root218*/219void220MM_ReferenceChainWalker::doClassSlot(J9Class *classPtr, IDATA type, IDATA index, J9Object *sourceObj)221{222if (NULL != classPtr) {223/* NOTE: this "O-slot" is actually a pointer to a local variable in this224* function. As such, any changes written back into it will be lost.225* Since no-one writes back into the slot in classes-on-heap VMs this is226* OK. We should simplify this code once classes-on-heap is enabled227* everywhere.228*/229J9Object* clazzObject = J9VM_J9CLASS_TO_HEAPCLASS(classPtr);230doSlot(&clazzObject, type, index, sourceObj);231}232}233234/**235* Main handler for field slots. Decodes the field and forwards to <code>doSlot</code>.236* If the slot is modified by the callback, stores the modified value back into the field.237* @param slotPtr pointer to the field slot238* @param type root or reference type (J9GC_ROOT_TYPE_* or J9GC_REFERENCE_TYPE_*)239* @param index an index identifying the slot within the sourceObj240* @param sourceObj the object which contains this slot241*/242void243MM_ReferenceChainWalker::doFieldSlot(GC_SlotObject *slotObject, IDATA type, IDATA index, J9Object *sourceObj)244{245/* decode the field value into an object pointer */246j9object_t fieldValue = slotObject->readReferenceFromSlot();247248doSlot(&fieldValue, type, index, sourceObj);249250/* write the value back into the field in case the callback changed it */251slotObject->writeReferenceToSlot(fieldValue);252}253254/**255* Clears the queue256*/257void258MM_ReferenceChainWalker::clearQueue()259{260_queueCurrent = _queue;261_hasOverflowed = false;262}263264/**265* Adds the object to the queue for scanning of its slots266* @param objectPtr the object to add to the queue267*/268void269MM_ReferenceChainWalker::pushObject(J9Object *objectPtr)270{271/* only add the object to the queue if it hasn't been scanned and isn't already queued */272if (!isMarked(objectPtr)) {273/* ensure there is room in the queue */274if (_queueCurrent < _queueEnd) {275setMarked(objectPtr);276*_queueCurrent = objectPtr;277_queueCurrent += 1;278} else {279/* if we overflow, dump half the objects from the queue and tag them for finding later */280_hasOverflowed = true;281setOverflow(objectPtr);282for (UDATA i = _queueSlots / 2; i > 0; i--) {283J9Object *objPtr = popObject();284setOverflow(objPtr);285}286}287}288}289290/**291* Get the next object off the queue for processing292* @return NULL if the queue is empty293*/294J9Object *295MM_ReferenceChainWalker::popObject()296{297J9Object *objectPtr;298299if (_queueCurrent == _queue) {300/* the queue is empty, check if there are overflow objects */301while (_hasOverflowed && !_isProcessingOverflow) {302/* We can completely clear out the overflow now. Field ordering has been keep303* via the ordering of doSlot calls. This is done here as it keeps the queue304* and overflow separate from the scanning.305*/306307_isProcessingOverflow = true;308309/* Reset the overflow flag, so we can determine if we overflow again */310_hasOverflowed = false;311312findOverflowObjects();313314_isProcessingOverflow = false;315}316return NULL;317}318319_queueCurrent--;320objectPtr = *_queueCurrent;321return objectPtr;322}323324/**325* Scan the remaining objects on the queue. On return the queue will be empty.326*/327void328MM_ReferenceChainWalker::completeScan()329{330J9Object *objectPtr;331332while (NULL != (objectPtr = popObject())) {333scanObject(objectPtr);334}335}336337/**338* Scan an object's slots. This will also add the reference to the objects class.339* @param objectPtr the object to scan340*/341void342MM_ReferenceChainWalker::scanObject(J9Object *objectPtr)343{344/* add the object's class for scanning */345J9Class* clazz = J9GC_J9OBJECT_CLAZZ(objectPtr, _extensions);346doClassSlot(clazz, J9GC_REFERENCE_TYPE_CLASS, -1, objectPtr);347348switch(_extensions->objectModel.getScanType(objectPtr)) {349case GC_ObjectModel::SCAN_MIXED_OBJECT_LINKED:350case GC_ObjectModel::SCAN_ATOMIC_MARKABLE_REFERENCE_OBJECT:351case GC_ObjectModel::SCAN_MIXED_OBJECT:352case GC_ObjectModel::SCAN_OWNABLESYNCHRONIZER_OBJECT:353case GC_ObjectModel::SCAN_CLASS_OBJECT:354case GC_ObjectModel::SCAN_CLASSLOADER_OBJECT:355scanMixedObject(objectPtr);356break;357case GC_ObjectModel::SCAN_POINTER_ARRAY_OBJECT:358scanPointerArrayObject((J9IndexableObject *)objectPtr);359break;360case GC_ObjectModel::SCAN_REFERENCE_MIXED_OBJECT:361scanReferenceMixedObject(objectPtr);362break;363case GC_ObjectModel::SCAN_PRIMITIVE_ARRAY_OBJECT:364/* nothing to do */365break;366default:367Assert_MM_unreachable();368}369370if (J9GC_IS_INITIALIZED_HEAPCLASS((J9VMThread*)_env->getLanguageVMThread(), objectPtr)) {371scanClass(J9VM_J9CLASS_FROM_HEAPCLASS((J9VMThread*)_env->getLanguageVMThread(), objectPtr));372}373}374375/**376* @todo Provide function documentation377*/378void379MM_ReferenceChainWalker::scanMixedObject(J9Object *objectPtr)380{381GC_MixedObjectDeclarationOrderIterator objectIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm), objectPtr, _shouldPreindexInterfaceFields);382383while(GC_SlotObject *slotObject = objectIterator.nextSlot()) {384doFieldSlot(slotObject, J9GC_REFERENCE_TYPE_FIELD, objectIterator.getIndex(), objectPtr);385}386}387388/**389* @todo Provide function documentation390*/391void392MM_ReferenceChainWalker::scanPointerArrayObject(J9IndexableObject *objectPtr)393{394GC_PointerArrayIterator pointerArrayIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm), (J9Object *)objectPtr);395396while(GC_SlotObject *slotObject = pointerArrayIterator.nextSlot()) {397doFieldSlot(slotObject, J9GC_REFERENCE_TYPE_ARRAY, pointerArrayIterator.getIndex(), (J9Object *)objectPtr);398}399}400401/**402* @todo Provide function documentation403*/404void405MM_ReferenceChainWalker::scanReferenceMixedObject(J9Object *objectPtr)406{407GC_MixedObjectDeclarationOrderIterator objectIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm), objectPtr, _shouldPreindexInterfaceFields);408409while(GC_SlotObject *slotObject = objectIterator.nextSlot()) {410doFieldSlot(slotObject, J9GC_REFERENCE_TYPE_WEAK_REFERENCE, objectIterator.getIndex(), objectPtr);411}412}413414/**415* @todo Provide function documentation416*/417void418MM_ReferenceChainWalker::scanClass(J9Class *clazz)419{420J9Object* referrer = J9VM_J9CLASS_TO_HEAPCLASS(clazz);421422GC_ClassIteratorDeclarationOrder classIterator(static_cast<J9JavaVM*>(_omrVM->_language_vm), clazz, _shouldPreindexInterfaceFields);423while(volatile j9object_t *slot = classIterator.nextSlot()) {424IDATA refType = classIterator.getSlotReferenceType();425IDATA index = classIterator.getIndex();426427/* discard volatile since we must be in stop-the-world mode */428doSlot((j9object_t*)slot, refType, index, referrer);429}430431GC_ClassIteratorClassSlots classIteratorClassSlots(static_cast<J9JavaVM*>(_omrVM->_language_vm), clazz);432while (J9Class *classPtr = classIteratorClassSlots.nextSlot()) {433switch (classIteratorClassSlots.getState()) {434case classiteratorclassslots_state_constant_pool:435doClassSlot(classPtr, J9GC_REFERENCE_TYPE_CONSTANT_POOL, classIteratorClassSlots.getIndex(), referrer);436break;437case classiteratorclassslots_state_superclasses:438doClassSlot(classPtr, J9GC_REFERENCE_TYPE_SUPERCLASS, classIteratorClassSlots.getIndex(), referrer);439break;440case classiteratorclassslots_state_interfaces:441doClassSlot(classPtr, J9GC_REFERENCE_TYPE_INTERFACE, classIteratorClassSlots.getIndex(), referrer);442break;443case classiteratorclassslots_state_array_class_slots:444doClassSlot(classPtr, J9GC_REFERENCE_TYPE_CLASS_ARRAY_CLASS, classIteratorClassSlots.getIndex(), referrer);445break;446case classiteratorclassslots_state_flattened_class_cache_slots:447doClassSlot(classPtr, J9GC_REFERENCE_TYPE_CLASS_FCC, classIteratorClassSlots.getIndex(), referrer);448break;449default:450doClassSlot(classPtr, J9GC_REFERENCE_TYPE_UNKNOWN, classIteratorClassSlots.getIndex(), referrer);451break;452}453}454455/* GC_ClassIteratorDeclarationOrder does not iterate the classLoader slot, we want to report the reference */456J9Object **slot = J9GC_J9CLASSLOADER_CLASSLOADEROBJECT_EA(clazz->classLoader);457doSlot(slot, J9GC_REFERENCE_TYPE_CLASSLOADER, -1, referrer);458}459460/**461* Finds objects in the heap that were overflowed, adds them back to the queue, and completes a scan.462*/463void464MM_ReferenceChainWalker::findOverflowObjects()465{466MM_Heap *heap = _extensions->heap;467MM_HeapRegionManager *regionManager = heap->getHeapRegionManager();468GC_HeapRegionIterator regionIterator(regionManager);469470MM_HeapRegionDescriptor *region = NULL;471while(NULL != (region = regionIterator.nextRegion())) {472GC_ObjectHeapBufferedIterator objectHeapIterator(_extensions, region);473474J9Object *object = NULL;475while((object = objectHeapIterator.nextObject()) != NULL) {476if (isOverflow(object)) {477clearOverflow(object);478pushObject(object);479completeScan();480}481}482}483}484485/**486* @todo Provide function documentation487*/488void489MM_ReferenceChainWalker::doSlot(J9Object **slotPtr) {490doSlot(slotPtr, J9GC_ROOT_TYPE_UNKNOWN, -1, NULL);491}492493/**494* Process a class slot pointer.495* @param slotPtr a pointer to a class slot496*/497void498MM_ReferenceChainWalker::doClassSlot(J9Class *classPtr)499{500doClassSlot(classPtr, J9GC_ROOT_TYPE_CLASS, -1, NULL);501}502503/**504* @todo Provide function documentation505*/506void507MM_ReferenceChainWalker::doClass(J9Class *clazz) {508doClassSlot(clazz);509}510511512/**513* @todo Provide function documentation514*/515void516MM_ReferenceChainWalker::doClassLoader(J9ClassLoader *classLoader)517{518doSlot(J9GC_J9CLASSLOADER_CLASSLOADEROBJECT_EA(classLoader), J9GC_ROOT_TYPE_CLASSLOADER, -1, NULL);519}520521#if defined(J9VM_GC_FINALIZATION)522/**523* @todo Provide function documentation524*/525void526MM_ReferenceChainWalker::doUnfinalizedObject(J9Object *objectPtr, MM_UnfinalizedObjectList *list)527{528J9Object *object = objectPtr;529doSlot(&object, J9GC_ROOT_TYPE_UNFINALIZED_OBJECT, -1, NULL);530}531#endif /* J9VM_GC_FINALIZATION */532533void534MM_ReferenceChainWalker::doOwnableSynchronizerObject(J9Object *objectPtr, MM_OwnableSynchronizerObjectList *list)535{536J9Object *object = objectPtr;537doSlot(&object, J9GC_ROOT_TYPE_OWNABLE_SYNCHRONIZER_OBJECT, -1, NULL);538}539540/**541* @todo Provide function documentation542*/543void544MM_ReferenceChainWalker::doMonitorReference(J9ObjectMonitor *objectMonitor, GC_HashTableIterator *monitorReferenceIterator)545{546J9ThreadAbstractMonitor * monitor = (J9ThreadAbstractMonitor*)objectMonitor->monitor;547doSlot((J9Object **)& monitor->userData, J9GC_ROOT_TYPE_MONITOR, -1, NULL);548}549550/**551* @todo Provide function documentation552*/553void554MM_ReferenceChainWalker::doJNIWeakGlobalReference(J9Object **slotPtr)555{556doSlot(slotPtr, J9GC_ROOT_TYPE_JNI_WEAK_GLOBAL, -1, NULL);557}558559#if defined(J9VM_GC_MODRON_SCAVENGER)560/**561* @todo Provide function documentation562*/563void564MM_ReferenceChainWalker::doRememberedSetSlot(J9Object **slotPtr, GC_RememberedSetSlotIterator *rememberedSetSlotIterator)565{566doSlot(slotPtr, J9GC_ROOT_TYPE_REMEMBERED_SET, -1, NULL);567}568#endif /* defined(J9VM_GC_MODRON_SCAVENGER) */569570/**571* @todo Provide function documentation572*/573void574MM_ReferenceChainWalker::doStringTableSlot(J9Object **slotPtr, GC_StringTableIterator *stringTableIterator)575{576doSlot(slotPtr, J9GC_ROOT_TYPE_STRING_TABLE, -1, NULL);577}578579/**580* @todo Provide function documentation581*/582void583MM_ReferenceChainWalker::doVMClassSlot(J9Class *classPtr)584{585doClassSlot(classPtr, J9GC_ROOT_TYPE_VM_CLASS_SLOT, -1, NULL);586}587588/**589* @todo Provide function documentation590*/591void592MM_ReferenceChainWalker::doStackSlot(J9Object **slotPtr, void *walkState, const void* stackLocation)593{594J9Object *slotValue = *slotPtr;595596/* Only report heap objects */597598if (isHeapObject(slotValue) && !_heap->objectIsInGap(slotValue)) {599doSlot(slotPtr, J9GC_ROOT_TYPE_STACK_SLOT, -1, (J9Object *)walkState);600}601}602603#if defined(J9VM_OPT_JVMTI)604/**605* @todo Provide function documentation606*/607void608MM_ReferenceChainWalker::doJVMTIObjectTagSlot(J9Object **slotPtr, GC_JVMTIObjectTagTableIterator *objectTagTableIterator)609{610doSlot(slotPtr, J9GC_ROOT_TYPE_JVMTI_TAG_REF, -1, NULL);611}612#endif /* J9VM_OPT_JVMTI */613614/**615* @todo Provide function documentation616*/617void618MM_ReferenceChainWalker::doVMThreadSlot(J9Object **slotPtr, GC_VMThreadIterator *vmThreadIterator)619{620J9Object *slotValue = *slotPtr;621622switch(vmThreadIterator->getState()) {623case vmthreaditerator_state_slots:624doSlot(slotPtr, J9GC_ROOT_TYPE_THREAD_SLOT, -1, NULL);625break;626case vmthreaditerator_state_jni_slots:627doSlot(slotPtr, J9GC_ROOT_TYPE_JNI_LOCAL, -1, NULL);628break;629#if defined(J9VM_INTERP_HOT_CODE_REPLACEMENT)630case vmthreaditerator_state_monitor_records:631if (isHeapObject(slotValue) && !_heap->objectIsInGap(slotValue)) {632doSlot(slotPtr, J9GC_ROOT_TYPE_THREAD_MONITOR, -1, NULL);633}634break;635#endif636default:637doSlot(slotPtr, J9GC_ROOT_TYPE_UNKNOWN, -1, NULL);638break;639}640}641642#if defined(J9VM_GC_FINALIZATION)643/**644* @todo Provide function documentation645*/646void647MM_ReferenceChainWalker::doFinalizableObject(J9Object *objectPtr)648{649J9Object *object = objectPtr;650doSlot(&object, J9GC_ROOT_TYPE_FINALIZABLE_OBJECT, -1, NULL);651}652#endif /* J9VM_GC_FINALIZATION */653654/**655* @todo Provide function documentation656*/657void658MM_ReferenceChainWalker::doJNIGlobalReferenceSlot(J9Object **slotPtr, GC_JNIGlobalReferenceIterator *jniGlobalReferenceIterator)659{660doSlot(slotPtr, J9GC_ROOT_TYPE_JNI_GLOBAL, -1, NULL);661}662663664