Path: blob/master/runtime/gc_glue_java/MarkingDelegate.cpp
5990 views
/*******************************************************************************1* Copyright (c) 2017, 2022 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 "j9.h"23#include "j9cfg.h"24#include "j9class.h"25#include "j9consts.h"26#include "j9cp.h"27#include "j9modron.h"28#include "j9nongenerated.h"29#include "j2sever.h"30#include "omrcomp.h"31#include "omrsrp.h"3233#include "ClassHeapIterator.hpp"34#include "ClassLoaderIterator.hpp"35#include "ClassLoaderSegmentIterator.hpp"36#include "ClassModel.hpp"37#if defined(J9VM_GC_FINALIZATION)38#include "CollectorLanguageInterfaceImpl.hpp"39#endif /* defined(J9VM_GC_FINALIZATION) */40#include "ConfigurationDelegate.hpp"41#include "EnvironmentDelegate.hpp"42#include "FinalizableReferenceBuffer.hpp"43#include "GlobalCollector.hpp"44#include "Heap.hpp"45#include "HeapRegionDescriptorStandard.hpp"46#include "HeapRegionIteratorStandard.hpp"47#include "MarkingScheme.hpp"48#include "MarkingSchemeRootMarker.hpp"49#include "MarkingSchemeRootClearer.hpp"50#include "OwnableSynchronizerObjectList.hpp"51#include "ParallelDispatcher.hpp"52#include "ReferenceObjectBuffer.hpp"53#include "RootScanner.hpp"54#include "StackSlotValidator.hpp"55#include "Task.hpp"56#include "UnfinalizedObjectList.hpp"57#include "WorkPackets.hpp"5859#include "MarkingDelegate.hpp"6061/* Verify that leaf bit optimization build flags are defined identically for j9 and omr */62#if defined(J9VM_GC_LEAF_BITS) != defined(OMR_GC_LEAF_BITS)63#error "Build flags J9VM_GC_LEAF_BITS and OMR_GC_LEAF_BITS must enabled/disabled identically"64#endif /* defined(J9VM_GC_LEAF_BITS) */6566bool67MM_MarkingDelegate::initialize(MM_EnvironmentBase *env, MM_MarkingScheme *markingScheme)68{69_omrVM = env->getOmrVM();70_extensions = MM_GCExtensions::getExtensions(env);71_markingScheme = markingScheme;72#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)73_markMap = (_extensions->dynamicClassUnloading != MM_GCExtensions::DYNAMIC_CLASS_UNLOADING_NEVER) ? markingScheme->getMarkMap() : NULL;74#endif /* defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING) */75return true;76}77787980#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)81void82MM_MarkingDelegate::clearClassLoadersScannedFlag(MM_EnvironmentBase *env)83{84J9JavaVM *javaVM = (J9JavaVM*)env->getLanguageVM();8586/**87* ClassLoaders might be scanned already at concurrent stage.88* Clear the "scanned" flags of all classLoaders to scan them again89**/90GC_ClassLoaderIterator classLoaderIterator(javaVM->classLoaderBlocks);91J9ClassLoader *classLoader;92while ((classLoader = classLoaderIterator.nextSlot()) != NULL) {93classLoader->gcFlags &= ~J9_GC_CLASS_LOADER_SCANNED;94}9596/*97* Clear "scanned" flag for all classes in anonymous classloader98*/99classLoader = javaVM->anonClassLoader;100if (NULL != classLoader) {101GC_ClassLoaderSegmentIterator segmentIterator(classLoader, MEMORY_TYPE_RAM_CLASS);102J9MemorySegment *segment = NULL;103while (NULL != (segment = segmentIterator.nextSegment())) {104GC_ClassHeapIterator classHeapIterator(javaVM, segment);105J9Class *clazz = NULL;106while (NULL != (clazz = classHeapIterator.nextClass())) {107J9CLASS_EXTENDED_FLAGS_CLEAR(clazz, J9ClassGCScanned);108}109}110}111}112#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */113114void115MM_MarkingDelegate::mainSetupForWalk(MM_EnvironmentBase *env)116{117#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)118_markMap = NULL;119#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */120121/* treat all interned strings as roots for the purposes of a heap walk */122_collectStringConstantsEnabled = false;123}124125void126MM_MarkingDelegate::workerSetupForGC(MM_EnvironmentBase *env)127{128GC_Environment *gcEnv = env->getGCEnvironment();129gcEnv->_markJavaStats.clear();130#if defined(J9VM_GC_MODRON_SCAVENGER)131if (_extensions->scavengerEnabled) {132/* clear scavenger stats for correcting the ownableSynchronizerObjects stats, only in generational gc */133gcEnv->_scavengerJavaStats.clearOwnableSynchronizerCounts();134}135#endif /* defined(J9VM_GC_MODRON_SCAVENGER) */136#if defined(OMR_GC_MODRON_STANDARD) || defined(OMR_GC_REALTIME)137/* record that this thread is participating in this cycle */138env->_markStats._gcCount = env->_workPacketStats._gcCount = _extensions->globalGCStats.gcCount;139#endif /* defined(OMR_GC_MODRON_STANDARD) || defined(OMR_GC_REALTIME) */140}141142void143MM_MarkingDelegate::workerCompleteGC(MM_EnvironmentBase *env)144{145/* ensure that all buffers have been flushed before we start reference processing */146GC_Environment *gcEnv = env->getGCEnvironment();147gcEnv->_referenceObjectBuffer->flush(env);148149if (env->_currentTask->synchronizeGCThreadsAndReleaseSingleThread(env, UNIQUE_ID)) {150env->_cycleState->_referenceObjectOptions |= MM_CycleState::references_clear_soft;151env->_cycleState->_referenceObjectOptions |= MM_CycleState::references_clear_weak;152env->_currentTask->releaseSynchronizedGCThreads(env);153}154MM_MarkingSchemeRootClearer rootClearer(env, _markingScheme, this);155rootClearer.setStringTableAsRoot(!_collectStringConstantsEnabled);156rootClearer.scanClearable(env);157}158159void160MM_MarkingDelegate::workerCleanupAfterGC(MM_EnvironmentBase *env)161{162GC_Environment *gcEnv = env->getGCEnvironment();163Assert_MM_true(gcEnv->_referenceObjectBuffer->isEmpty());164165_extensions->markJavaStats.merge(&gcEnv->_markJavaStats);166#if defined(J9VM_GC_MODRON_SCAVENGER)167if (_extensions->scavengerEnabled) {168/* merge scavenger ownableSynchronizerObjects stats, only in generational gc */169_extensions->scavengerJavaStats.mergeOwnableSynchronizerCounts(&gcEnv->_scavengerJavaStats);170}171#endif /* defined(J9VM_GC_MODRON_SCAVENGER) */172}173174void175MM_MarkingDelegate::mainSetupForGC(MM_EnvironmentBase *env)176{177#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)178clearClassLoadersScannedFlag(env);179_markMap = (0 != _extensions->runtimeCheckDynamicClassUnloading) ? _markingScheme->getMarkMap() : NULL;180#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */181182_collectStringConstantsEnabled = _extensions->collectStringConstants;183}184185void186MM_MarkingDelegate::mainCleanupAfterGC(MM_EnvironmentBase *env)187{188#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)189_markMap = (_extensions->dynamicClassUnloading != MM_GCExtensions::DYNAMIC_CLASS_UNLOADING_NEVER) ? _markingScheme->getMarkMap() : NULL;190#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */191}192193void194MM_MarkingDelegate::startRootListProcessing(MM_EnvironmentBase *env)195{196/* Start unfinalized object and ownable synchronizer processing */197if (J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {198_shouldScanUnfinalizedObjects = false;199_shouldScanOwnableSynchronizerObjects = false;200MM_HeapRegionDescriptorStandard *region = NULL;201GC_HeapRegionIteratorStandard regionIterator(_extensions->heap->getHeapRegionManager());202while (NULL != (region = regionIterator.nextRegion())) {203MM_HeapRegionDescriptorStandardExtension *regionExtension = MM_ConfigurationDelegate::getHeapRegionDescriptorStandardExtension(env, region);204for (UDATA i = 0; i < regionExtension->_maxListIndex; i++) {205/* Start unfinalized object processing for region */206MM_UnfinalizedObjectList *unfinalizedObjectList = &(regionExtension->_unfinalizedObjectLists[i]);207unfinalizedObjectList->startUnfinalizedProcessing();208if (!unfinalizedObjectList->wasEmpty()) {209_shouldScanUnfinalizedObjects = true;210}211/* Start ownable synchronizer processing for region */212MM_OwnableSynchronizerObjectList *ownableSynchronizerObjectList = &(regionExtension->_ownableSynchronizerObjectLists[i]);213ownableSynchronizerObjectList->startOwnableSynchronizerProcessing();214if (!ownableSynchronizerObjectList->wasEmpty()) {215_shouldScanOwnableSynchronizerObjects = true;216}217}218}219}220}221222void223MM_MarkingDelegate::scanRoots(MM_EnvironmentBase *env, bool processLists)224{225if (processLists) {226startRootListProcessing(env);227}228229/* Reset MM_RootScanner base class for scanning */230MM_MarkingSchemeRootMarker rootMarker(env, _markingScheme, this);231rootMarker.setStringTableAsRoot(!_collectStringConstantsEnabled);232233#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)234/* Mark root set classes */235rootMarker.setClassDataAsRoots(!isDynamicClassUnloadingEnabled());236if (isDynamicClassUnloadingEnabled()) {237/* Setting the permanent class loaders to scanned without a locked operation is safe238* Class loaders will not be rescanned until a thread synchronize is executed239*/240if (env->isMainThread()) {241J9JavaVM * javaVM = (J9JavaVM*)env->getLanguageVM();242((J9ClassLoader *)javaVM->systemClassLoader)->gcFlags |= J9_GC_CLASS_LOADER_SCANNED;243_markingScheme->markObject(env, (omrobjectptr_t )((J9ClassLoader *)javaVM->systemClassLoader)->classLoaderObject);244if (javaVM->applicationClassLoader) {245((J9ClassLoader *)javaVM->applicationClassLoader)->gcFlags |= J9_GC_CLASS_LOADER_SCANNED;246_markingScheme->markObject(env, (omrobjectptr_t )((J9ClassLoader *)javaVM->applicationClassLoader)->classLoaderObject);247}248}249}250#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */251252/* Scan roots */253rootMarker.scanRoots(env);254}255256void257MM_MarkingDelegate::completeMarking(MM_EnvironmentBase *env)258{259#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)260if (isDynamicClassUnloadingEnabled()) {261J9ClassLoader *classLoader;262J9JavaVM * javaVM = (J9JavaVM*)env->getLanguageVM();263264if (env->_currentTask->synchronizeGCThreadsAndReleaseSingleThread(env, UNIQUE_ID)) {265_anotherClassMarkPass = false;266_anotherClassMarkLoopIteration = true;267env->_currentTask->releaseSynchronizedGCThreads(env);268}269270while (_anotherClassMarkLoopIteration) {271GC_ClassLoaderIterator classLoaderIterator(javaVM->classLoaderBlocks);272while ((classLoader = classLoaderIterator.nextSlot()) != NULL) {273/* We cannot go more granular (for example per class segment) since the class loader flag is changed */274/* Several threads might contend setting the value of the flags */275if (J9MODRON_HANDLE_NEXT_WORK_UNIT(env)) {276if (0 == (classLoader->gcFlags & J9_GC_CLASS_LOADER_DEAD)) {277if (J9CLASSLOADER_ANON_CLASS_LOADER == (classLoader->flags & J9CLASSLOADER_ANON_CLASS_LOADER)) {278/* Anonymous classloader should be scanned on level of classes every time */279GC_ClassLoaderSegmentIterator segmentIterator(classLoader, MEMORY_TYPE_RAM_CLASS);280J9MemorySegment *segment = NULL;281while (NULL != (segment = segmentIterator.nextSegment())) {282GC_ClassHeapIterator classHeapIterator(javaVM, segment);283J9Class *clazz = NULL;284while (NULL != (clazz = classHeapIterator.nextClass())) {285Assert_MM_true(!J9_ARE_ANY_BITS_SET(clazz->classDepthAndFlags, J9AccClassDying));286if ((0 == (J9CLASS_EXTENDED_FLAGS(clazz) & J9ClassGCScanned)) && _markingScheme->isMarked(clazz->classObject)) {287J9CLASS_EXTENDED_FLAGS_SET(clazz, J9ClassGCScanned);288289scanClass(env, clazz);290/* This may result in other class loaders being marked,291* so we have to do another pass292*/293_anotherClassMarkPass = true;294}295}296}297} else {298/* Check if the class loader has not been scanned but the class loader is live */299if ((0 == (classLoader->gcFlags & J9_GC_CLASS_LOADER_SCANNED)) && _markingScheme->isMarked(classLoader->classLoaderObject)) {300/* Flag the class loader as being scanned */301classLoader->gcFlags |= J9_GC_CLASS_LOADER_SCANNED;302303GC_ClassLoaderSegmentIterator segmentIterator(classLoader, MEMORY_TYPE_RAM_CLASS);304J9MemorySegment *segment = NULL;305J9Class *clazz = NULL;306while (NULL != (segment = segmentIterator.nextSegment())) {307GC_ClassHeapIterator classHeapIterator(javaVM, segment);308while (NULL != (clazz = classHeapIterator.nextClass())) {309scanClass(env, clazz);310/* This may result in other class loaders being marked,311* so we have to do another pass312*/313_anotherClassMarkPass = true;314}315}316317/* CMVC 131487 */318J9HashTableState walkState;319/*320* We believe that (NULL == classLoader->classHashTable) is set ONLY for DEAD class loader321* so, if this pointer happened to be NULL at this point let it crash here322*/323Assert_MM_true(NULL != classLoader->classHashTable);324clazz = javaVM->internalVMFunctions->hashClassTableStartDo(classLoader, &walkState, 0);325while (NULL != clazz) {326_markingScheme->markObjectNoCheck(env, (omrobjectptr_t )clazz->classObject);327_anotherClassMarkPass = true;328clazz = javaVM->internalVMFunctions->hashClassTableNextDo(&walkState);329}330331if (NULL != classLoader->moduleHashTable) {332J9HashTableState moduleWalkState;333J9Module **modulePtr = (J9Module**)hashTableStartDo(classLoader->moduleHashTable, &moduleWalkState);334while (NULL != modulePtr) {335J9Module * const module = *modulePtr;336337_markingScheme->markObjectNoCheck(env, (omrobjectptr_t )module->moduleObject);338if (NULL != module->moduleName) {339_markingScheme->markObjectNoCheck(env, (omrobjectptr_t )module->moduleName);340}341if (NULL != module->version) {342_markingScheme->markObjectNoCheck(env, (omrobjectptr_t )module->version);343}344modulePtr = (J9Module**)hashTableNextDo(&moduleWalkState);345}346347if (classLoader == javaVM->systemClassLoader) {348_markingScheme->markObjectNoCheck(env, (omrobjectptr_t )javaVM->unamedModuleForSystemLoader->moduleObject);349}350}351}352}353}354}355}356357/* In case some GC threads don't find a classLoader to work with (or are quick to finish with it)358* let them help empty out the generic work stack.359*/360_markingScheme->completeScan(env);361362/* have to stop the threads while resetting the flag, to prevent them rushing through another pass and363* losing an early "set flag"364*/365if (env->_currentTask->synchronizeGCThreadsAndReleaseSingleThread(env, UNIQUE_ID)) {366/* if work is complete, end loop */367_anotherClassMarkLoopIteration = _anotherClassMarkPass;368_anotherClassMarkPass = false;369env->_currentTask->releaseSynchronizedGCThreads(env);370}371}372}373#endif /* defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING) */374}375376void377MM_MarkingDelegate::scanClass(MM_EnvironmentBase *env, J9Class *clazz)378{379/* Note: Class loader objects are handled separately */380/*381* Scan and mark using GC_ClassIterator:382* - class object383* - class constant pool384* - class statics385* - class method types386* - class call sites387* - class varhandle method types388*389* As this function can be invoked during concurrent mark the slot is390* volatile so we must ensure that the compiler generates the correct391* code if markObject() is inlined.392*/393GC_ClassIterator classIterator(env, clazz, true);394while (volatile omrobjectptr_t *slotPtr = classIterator.nextSlot()) {395_markingScheme->markObject(env, *slotPtr);396}397398#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)399if (isDynamicClassUnloadingEnabled()) {400GC_ClassIteratorClassSlots classSlotIterator((J9JavaVM*)env->getLanguageVM(), clazz);401J9Class *classPtr;402while (NULL != (classPtr = classSlotIterator.nextSlot())) {403_markingScheme->markObject(env, classPtr->classObject);404}405}406#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */407}408409void410MM_MarkingDelegate::processReferenceList(MM_EnvironmentBase *env, MM_HeapRegionDescriptorStandard* region, omrobjectptr_t headOfList, MM_ReferenceStats *referenceStats)411{412/* no list can possibly contain more reference objects than there are bytes in a region. */413const UDATA maxObjects = region->getSize();414UDATA objectsVisited = 0;415GC_FinalizableReferenceBuffer buffer(_extensions);416#if defined(J9VM_GC_FINALIZATION)417bool finalizationRequired = false;418#endif /* defined(J9VM_GC_FINALIZATION) */419420omrobjectptr_t referenceObj = headOfList;421while (NULL != referenceObj) {422objectsVisited += 1;423referenceStats->_candidates += 1;424425Assert_MM_true(_markingScheme->isMarked(referenceObj));426Assert_MM_true(objectsVisited < maxObjects);427428omrobjectptr_t nextReferenceObj = _extensions->accessBarrier->getReferenceLink(referenceObj);429430GC_SlotObject referentSlotObject(_omrVM, J9GC_J9VMJAVALANGREFERENCE_REFERENT_ADDRESS(env, referenceObj));431432if (NULL != referentSlotObject.readReferenceFromSlot()) {433_markingScheme->fixupForwardedSlot(&referentSlotObject);434omrobjectptr_t referent = referentSlotObject.readReferenceFromSlot();435436UDATA referenceObjectType = J9CLASS_FLAGS(J9GC_J9OBJECT_CLAZZ(referenceObj, env)) & J9AccClassReferenceMask;437if (_markingScheme->isMarked(referent)) {438if (J9AccClassReferenceSoft == referenceObjectType) {439U_32 age = J9GC_J9VMJAVALANGSOFTREFERENCE_AGE(env, referenceObj);440if (age < _extensions->getMaxSoftReferenceAge()) {441/* Soft reference hasn't aged sufficiently yet - increment the age */442J9GC_J9VMJAVALANGSOFTREFERENCE_AGE(env, referenceObj) = age + 1;443}444}445} else {446/* transition the state to cleared */447Assert_MM_true(GC_ObjectModel::REF_STATE_INITIAL == J9GC_J9VMJAVALANGREFERENCE_STATE(env, referenceObj));448J9GC_J9VMJAVALANGREFERENCE_STATE(env, referenceObj) = GC_ObjectModel::REF_STATE_CLEARED;449450referenceStats->_cleared += 1;451452/* Phantom references keep it's referent alive in Java 8 and doesn't in Java 9 and later */453J9JavaVM * javaVM = (J9JavaVM*)env->getLanguageVM();454if ((J9AccClassReferencePhantom == referenceObjectType) && ((J2SE_VERSION(javaVM) & J2SE_VERSION_MASK) <= J2SE_18)) {455/* Phantom objects keep their referent - scanning will be done after the enqueuing */456_markingScheme->inlineMarkObject(env, referent);457} else {458referentSlotObject.writeReferenceToSlot(NULL);459}460461/* Check if the reference has a queue */462if (0 != J9GC_J9VMJAVALANGREFERENCE_QUEUE(env, referenceObj)) {463/* Reference object can be enqueued onto the finalizable list */464buffer.add(env, referenceObj);465referenceStats->_enqueued += 1;466#if defined(J9VM_GC_FINALIZATION)467/* inform global GC if finalization is required */468if (!finalizationRequired) {469MM_GlobalCollector *globalCollector = (MM_GlobalCollector *)_extensions->getGlobalCollector();470globalCollector->getGlobalCollectorDelegate()->setFinalizationRequired();471finalizationRequired = true;472}473#endif /* defined(J9VM_GC_FINALIZATION) */474}475}476}477478referenceObj = nextReferenceObj;479}480481buffer.flush(env);482}483484bool485MM_MarkingDelegate::processReference(MM_EnvironmentBase *env, omrobjectptr_t objectPtr)486{487bool isReferenceCleared = false;488bool referentMustBeMarked = false;489bool referentMustBeCleared = getReferenceStatus(env, objectPtr, &referentMustBeMarked, &isReferenceCleared);490491clearReference(env, objectPtr, isReferenceCleared, referentMustBeCleared);492493return referentMustBeMarked;494}495496bool497MM_MarkingDelegate::getReferenceStatus(MM_EnvironmentBase *env, omrobjectptr_t objectPtr, bool *referentMustBeMarked, bool *isReferenceCleared)498{499/*500* the method getReferenceStatus() is shared between STW gc and concurrent gc,501* during concurrent gc, the cycleState of the mutator thread might not be set,502* but if the cycleState of the thread is not set, we know it is in concurrent mode(not clearable phase).503*/504UDATA referenceObjectOptions = MM_CycleState::references_default;505if (NULL != env->_cycleState) {506referenceObjectOptions = env->_cycleState->_referenceObjectOptions;507}508509I_32 referenceState = J9GC_J9VMJAVALANGREFERENCE_STATE(env, objectPtr);510*isReferenceCleared = (GC_ObjectModel::REF_STATE_CLEARED == referenceState) || (GC_ObjectModel::REF_STATE_ENQUEUED == referenceState);511*referentMustBeMarked = *isReferenceCleared;512bool referentMustBeCleared = false;513514UDATA referenceObjectType = J9CLASS_FLAGS(J9GC_J9OBJECT_CLAZZ(objectPtr, env)) & J9AccClassReferenceMask;515switch (referenceObjectType) {516case J9AccClassReferenceWeak:517referentMustBeCleared = (0 != (referenceObjectOptions & MM_CycleState::references_clear_weak));518break;519case J9AccClassReferenceSoft:520referentMustBeCleared = (0 != (referenceObjectOptions & MM_CycleState::references_clear_soft));521*referentMustBeMarked = *referentMustBeMarked || (522((0 == (referenceObjectOptions & MM_CycleState::references_soft_as_weak))523&& ((UDATA)J9GC_J9VMJAVALANGSOFTREFERENCE_AGE(env, objectPtr) < _extensions->getDynamicMaxSoftReferenceAge())));524break;525case J9AccClassReferencePhantom:526referentMustBeCleared = (0 != (referenceObjectOptions & MM_CycleState::references_clear_phantom));527break;528default:529Assert_MM_unreachable();530}531532return referentMustBeCleared;533}534535void536MM_MarkingDelegate::clearReference(MM_EnvironmentBase *env, omrobjectptr_t objectPtr, bool isReferenceCleared, bool referentMustBeCleared)537{538if (referentMustBeCleared) {539/* Discovering this object at this stage in the GC indicates that it is being resurrected. Clear its referent slot. */540GC_SlotObject referentPtr(_omrVM, J9GC_J9VMJAVALANGREFERENCE_REFERENT_ADDRESS(env, objectPtr));541referentPtr.writeReferenceToSlot(NULL);542/* record that the reference has been cleared if it's not already in the cleared or enqueued state */543if (!isReferenceCleared) {544J9GC_J9VMJAVALANGREFERENCE_STATE(env, objectPtr) = GC_ObjectModel::REF_STATE_CLEARED;545}546} else {547/* we don't need to process cleared or enqueued references. */548if (!isReferenceCleared) {549/* for overflow case we assume only 3 active reference states(REF_STATE_INITIAL, REF_STATE_CLEARED, REF_STATE_ENQUEUED),550REF_STATE_REMEMBERED is only for balanced case, ReferenceCleared(REF_STATE_CLEARED, REF_STATE_ENQUEUED) notReferenceCleared(REF_STATE_INITIAL),551if any new states is added, should reconsider the logic */552env->getGCEnvironment()->_referenceObjectBuffer->add(env, objectPtr);553}554}555}556557fomrobject_t *558MM_MarkingDelegate::setupReferenceObjectScanner(MM_EnvironmentBase *env, omrobjectptr_t objectPtr, MM_MarkingSchemeScanReason reason)559{560bool isReferenceCleared = false;561bool referentMustBeMarked = false;562bool referentMustBeCleared = getReferenceStatus(env, objectPtr, &referentMustBeMarked, &isReferenceCleared);563564GC_SlotObject referentSlotObject(_omrVM, J9GC_J9VMJAVALANGREFERENCE_REFERENT_ADDRESS(env, objectPtr));565if (SCAN_REASON_PACKET == reason) {566clearReference(env, objectPtr, isReferenceCleared, referentMustBeCleared);567}568569fomrobject_t* referentSlotPtr = NULL;570if (!referentMustBeMarked) {571referentSlotPtr = referentSlotObject.readAddressFromSlot();572}573return referentSlotPtr;574}575576uintptr_t577MM_MarkingDelegate::setupPointerArrayScanner(MM_EnvironmentBase *env, omrobjectptr_t objectPtr, MM_MarkingSchemeScanReason reason, uintptr_t *sizeToDo, uintptr_t *slotsToDo)578{579uintptr_t startIndex = 0;580uintptr_t headerBytesToScan = 0;581uintptr_t workItem = (uintptr_t)env->_workStack.peek(env);582if (PACKET_ARRAY_SPLIT_TAG == (workItem & PACKET_ARRAY_SPLIT_TAG)) {583Assert_MM_true(SCAN_REASON_PACKET == reason);584env->_workStack.pop(env);585/* since we are putting extra tagged objects on the work stack we are responsible for ensuring that the object scanned586* count is correct. The MM_MarkingScheme::scanObject code will increment _objectScanned by 1 for EVERY object587* popped off of the work stack if the scan reason is SCAN_REASON_PACKET. This code is only executed during regular588* packet scanning.589*/590env->_markStats._objectsScanned -= 1;591/* only mark the class the first time we scan any array */592startIndex = workItem >> PACKET_ARRAY_SPLIT_SHIFT;593} else {594/* account for header size on first scan */595headerBytesToScan = _extensions->indexableObjectModel.getHeaderSize((J9IndexableObject *)objectPtr);596}597598uintptr_t slotsToScan = 0;599uintptr_t const referenceSize = env->compressObjectReferences() ? sizeof(uint32_t) : sizeof(uintptr_t);600uintptr_t maxSlotsToScan = OMR_MAX(*sizeToDo / referenceSize, 1);601Assert_MM_true(maxSlotsToScan > 0);602uintptr_t sizeInElements = _extensions->indexableObjectModel.getSizeInElements((J9IndexableObject *)objectPtr);603if (sizeInElements > 0) {604Assert_MM_true(startIndex < sizeInElements);605slotsToScan = sizeInElements - startIndex;606607/* pointer arrays are split into segments to improve parallelism. split amount is proportional to array size608* and inverse proportional to active thread count.609* additionally, the less busy we are, the smaller the split amount, while obeying specified minimum and maximum.610*/611612uintptr_t arraySplitSize = slotsToScan / (_extensions->dispatcher->activeThreadCount() + 2 * _markingScheme->getWorkPackets()->getThreadWaitCount());613arraySplitSize = OMR_MAX(arraySplitSize, _extensions->markingArraySplitMinimumAmount);614arraySplitSize = OMR_MIN(arraySplitSize, _extensions->markingArraySplitMaximumAmount);615616if ((slotsToScan > arraySplitSize) || (slotsToScan > maxSlotsToScan)) {617slotsToScan = OMR_MIN(arraySplitSize, maxSlotsToScan);618619/* immediately make the next chunk available for another thread to start processing */620uintptr_t nextIndex = startIndex + slotsToScan;621Assert_MM_true(nextIndex < sizeInElements);622void *element1 = (void *)objectPtr;623void *element2 = (void *)((nextIndex << PACKET_ARRAY_SPLIT_SHIFT) | PACKET_ARRAY_SPLIT_TAG);624Assert_MM_true(nextIndex == (((uintptr_t)element2) >> PACKET_ARRAY_SPLIT_SHIFT));625env->_workStack.push(env, element1, element2);626env->_workStack.flushOutputPacket(env);627MM_MarkJavaStats *markJavaStats = &(env->getGCEnvironment()->_markJavaStats);628markJavaStats->splitArraysProcessed += 1;629markJavaStats->splitArraysAmount += slotsToScan;630}631}632633*sizeToDo = headerBytesToScan + (slotsToScan * referenceSize);634*slotsToDo = slotsToScan;635return startIndex;636}637638639