Path: blob/master/runtime/gc_realtime/IncrementalOverflow.cpp
5985 views
/*******************************************************************************1* Copyright (c) 1991, 2019 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 "omr.h"23#include "omrcfg.h"2425#include "EnvironmentRealtime.hpp"26#include "GCExtensionsBase.hpp"27#include "HeapLinkedFreeHeader.hpp"28#include "HeapRegionManager.hpp"29#include "HeapRegionDescriptorRealtime.hpp"30#include "IncrementalOverflow.hpp"31#include "Packet.hpp"32#include "RealtimeGC.hpp"33#include "RealtimeMarkingScheme.hpp"34#include "WorkPackets.hpp"353637/****************************************38* Initialization39****************************************40*/4142MM_IncrementalOverflow *43MM_IncrementalOverflow::newInstance(MM_EnvironmentBase *env, MM_WorkPackets *workPackets)44{45MM_IncrementalOverflow *overflow;4647overflow = (MM_IncrementalOverflow *)env->getForge()->allocate(sizeof(MM_IncrementalOverflow), MM_AllocationCategory::FIXED, OMR_GET_CALLSITE());48if (overflow) {49new(overflow) MM_IncrementalOverflow(env, workPackets);50if (!overflow->initialize(env)) {51overflow->kill(env);52overflow = NULL;53}54}55return overflow;56}5758/**59* Initialize a MM_IncrementalOverflow object.60*61* @return true on success, false otherwise62*/63bool64MM_IncrementalOverflow::initialize(MM_EnvironmentBase *env)65{66if (!MM_WorkPacketOverflow::initialize(env)) {67return false;68}6970_extensions = env->getExtensions();7172return true;73}7475/**76* Cleanup the resources for a MM_IncrementalOverflow object77*/78void79MM_IncrementalOverflow::tearDown(MM_EnvironmentBase *env)80{81MM_WorkPacketOverflow::tearDown(env);82}8384/**85* Push the region to be overflowed onto the local cache. If it is already86* on the cache just return.87*/88MMINLINE void89MM_IncrementalOverflow::pushLocal(MM_EnvironmentBase *env, MM_HeapRegionDescriptorRealtime *region, MM_OverflowType type)90{91MM_EnvironmentRealtime *envRealtime = MM_EnvironmentRealtime::getEnvironment(env);92MM_HeapRegionDescriptorRealtime **cache = envRealtime->getOverflowCache();9394/* If the local cache is full flush it */95if (envRealtime->getOverflowCacheUsedCount() >= envRealtime->getExtensions()->overflowCacheCount) {96flushLocal(envRealtime, type);97}9899cache[envRealtime->getOverflowCacheUsedCount()] = region;100envRealtime->incrementOverflowCacheUsedCount();101}102103/**104* Push the region onto the global overflow list.105* @note this function does not use any locks when manipulating the list. The caller106* is responsible for handling the lock.107*/108MMINLINE void109MM_IncrementalOverflow::pushNoLock(MM_EnvironmentBase *env, MM_HeapRegionDescriptorRealtime *region)110{111if (NULL == region->getNextOverflowRegion()) {112region->setNextOverflowRegion((MM_HeapRegionDescriptorRealtime *)((uintptr_t)_overflowList | 1));113_overflowList = region;114}115}116117/**118* This functions pushes all of the regions from the local cache119* to the global cache. If these regions are being overflowed due to the workstack120* check for yielding before the flush begins.121*/122MMINLINE void123MM_IncrementalOverflow::flushLocal(MM_EnvironmentBase *env, MM_OverflowType type)124{125MM_EnvironmentRealtime *envRealtime = MM_EnvironmentRealtime::getEnvironment(env);126uintptr_t currentCount = envRealtime->getOverflowCacheUsedCount();127MM_HeapRegionDescriptorRealtime **cache = envRealtime->getOverflowCache();128uintptr_t count = 0;129130omrthread_monitor_enter(_overflowListMonitor);131for (count = 0; count < currentCount; count++) {132MM_HeapRegionDescriptorRealtime *localRegion = cache[count];133pushNoLock(env, localRegion);134}135omrthread_monitor_exit(_overflowListMonitor);136envRealtime->resetOverflowCacheUsedCount();137}138139/**140* Push a region onto the global overflow list.141*/142MMINLINE void143MM_IncrementalOverflow::push(MM_EnvironmentBase *env, MM_HeapRegionDescriptorRealtime *region)144{145omrthread_monitor_enter(_overflowListMonitor);146147pushNoLock(env, region);148149omrthread_monitor_exit(_overflowListMonitor);150}151152/**153* Pop a region off of the global overflow list.154*/155MMINLINE MM_HeapRegionDescriptorRealtime *156MM_IncrementalOverflow::pop(MM_EnvironmentBase *env)157{158MM_HeapRegionDescriptorRealtime *region = NULL;159160/* The _overflowListMonitor must be held while modifying the overflow list */161omrthread_monitor_enter(_overflowListMonitor);162163if (NULL != _overflowList) {164region = _overflowList;165_overflowList = (MM_HeapRegionDescriptorRealtime*)((uintptr_t)region->getNextOverflowRegion() & ~1);166region->setNextOverflowRegion(NULL);167}168169omrthread_monitor_exit(_overflowListMonitor);170171return region;172}173174/**175* Empty the packet by overflowing all if it's items176*177* @param env The current Environment178* @param packet The packet to empty179* @param type - ignored by incremental handler180*/181void182MM_IncrementalOverflow::emptyToOverflow(MM_EnvironmentBase *env, MM_Packet *packet, MM_OverflowType type)183{184void *item;185186_extensions->globalGCStats.metronomeStats.incrementWorkPacketOverflowCount();187188while(NULL != (item = packet->pop(env))) {189overflowItemInternal(env, item, type);190}191/* Finished overflowing this region so flush the remaining entries in the local cache */192flushLocal(env, type);193194Assert_MM_true(packet->isEmpty());195196_overflowThisGCCycle = 1;197}198199/**200* Fill the packet from overflowed items201*202* @param env The current Environment203* @param packet The packet to fill204*/205void206MM_IncrementalOverflow::fillFromOverflow(MM_EnvironmentBase *env, MM_Packet *packet)207{208MM_EnvironmentRealtime *envRealtime = MM_EnvironmentRealtime::getEnvironment(env);209MM_HeapRegionDescriptorRealtime* region;210MM_RealtimeGC *realtimeGC = envRealtime->getExtensions()->realtimeGC;211MM_RealtimeMarkingScheme *markingScheme = realtimeGC->getMarkingScheme();212bool roomLeft = true;213214while (roomLeft && ((region = pop(envRealtime)) != NULL)) {215if (region->isArraylet()) {216uintptr_t arrayletIndex = 0;217uintptr_t arrayletLeafLogSize = envRealtime->getOmrVM()->_arrayletLeafLogSize;218uintptr_t arrayletsPerRegion = envRealtime->getExtensions()->arrayletsPerRegion;219220while (arrayletIndex < arrayletsPerRegion) {221if (region->isArrayletUsed(arrayletIndex)) {222/* Only return arraylets if they contain pointers (scan stack can't deal with base type223* leaves) and whose spine is marked to prevent the arraylet leaf elements from being kept224* alive (more floating garbage)225*/226omrobjectptr_t arrayletParent = (omrobjectptr_t)region->getArrayletParent(arrayletIndex);227if (_extensions->objectModel.isObjectArray(arrayletParent) && markingScheme->isMarked(arrayletParent)) {228uintptr_t* arraylet = region->getArraylet(arrayletIndex, arrayletLeafLogSize);229if (packet->isFull(envRealtime)) {230push(envRealtime, region);231roomLeft = false;232break;233}234packet->push(envRealtime, (void *)ARRAYLET_TO_ITEM(arraylet));235}236}237arrayletIndex += 1;238realtimeGC->_sched->condYieldFromGC(env);239}240} else if (region->isCanonical()) {241if (region->isSmall()) {242/* A small region is divided into cells.243* Iterate over the cells returning the objects contained within inuse cells244*/245uintptr_t numCells = region->getNumCells();246uintptr_t cellSize = region->getCellSize();247uintptr_t *baseAddress = (uintptr_t *)region->getLowAddress();248uintptr_t cellIndex = 0;249while(cellIndex < numCells) {250omrobjectptr_t object = (omrobjectptr_t)((uintptr_t)baseAddress + (cellIndex * cellSize));251if (!_extensions->objectModel.isDeadObject(object)) {252if(_extensions->objectModel.isOverflowBitSet(object)) {253if (packet->isFull(envRealtime)) {254push(envRealtime, region);255roomLeft = false;256break;257}258if(_extensions->objectModel.atomicClearOverflowBit(object)) {259packet->push(envRealtime, (void *)OBJECT_TO_ITEM(object));260}261}262cellIndex += 1;263} else {264cellIndex += (MM_HeapLinkedFreeHeader::getHeapLinkedFreeHeader(object)->getSize() / cellSize);265}266267realtimeGC->_sched->condYieldFromGC(env);268}269/* ran off end of region */270} else if (region->isLarge()) {271/* A region that is both large and canonical contains exactly 1 object */272uintptr_t *cell = (uintptr_t *)region->getLowAddress();273omrobjectptr_t object = (omrobjectptr_t)cell;274if (_extensions->objectModel.isOverflowBitSet(object)) {275if (packet->isFull(envRealtime)) {276push(envRealtime, region);277roomLeft = false;278break;279}280if (_extensions->objectModel.atomicClearOverflowBit(object)) {281packet->push(envRealtime, (void *)OBJECT_TO_ITEM(object));282}283}284realtimeGC->_sched->condYieldFromGC(env);285}286}287}288}289290/**291* Overflow the item. To overflow incremental items the object292* and the object's region have to both be marked as overflowed.293*294* @param env The current Environment295* @param item The item to overflow296* @param type - ignored by incremental handler297*/298void299MM_IncrementalOverflow::overflowItem(MM_EnvironmentBase *env, void *item, MM_OverflowType type)300{301_extensions->globalGCStats.metronomeStats.incrementObjectOverflowCount();302303overflowItemInternal(env, item, type);304flushLocal(env, type);305306_overflowThisGCCycle = 1;307}308309/**310* Overflow the item. To overflow incremental items the object311* and the object's region have to both be marked as overflowed.312*313* @param env The current Environment314* @param item The item to overflow315* @param type - ignored by incremental handler316*/317MMINLINE void318MM_IncrementalOverflow::overflowItemInternal(MM_EnvironmentBase *env, void *item, MM_OverflowType type)319{320MM_HeapRegionManager *manager = _extensions->heap->getHeapRegionManager();321MM_HeapRegionDescriptorRealtime* region;322323if (!IS_ITEM_ARRAYLET((uintptr_t)item)) {324/* Set overflow bit in the object's flags */325omrobjectptr_t objectPtr = ITEM_TO_OBJECT((uintptr_t)item);326if (!_extensions->objectModel.atomicSetOverflowBit(objectPtr)) {327return;328}329}330331/* Arraylets are not individually marked, only the region they belong to */332/* TODO: Consider marking individual arraylet. For example, tag low bit of its spine back pointer),333* or even introduce arraylet flags in its region. */334335/* For both arraylets and objects, mark the region as containing overflow objects */336region = (MM_HeapRegionDescriptorRealtime *)manager->tableDescriptorForAddress(item);337pushLocal(env, region, type);338}339340void341MM_IncrementalOverflow::reset(MM_EnvironmentBase *env)342{343/* the _overflowListMonitor must be held while modifying the overflow list */344omrthread_monitor_enter(_overflowListMonitor);345_overflowList = NULL;346omrthread_monitor_exit(_overflowListMonitor);347}348349350