Path: blob/master/runtime/gc_vlhgc/ClassLoaderRememberedSet.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*******************************************************************************/21/**22* @file23* @ingroup gc_vlhgc24*/2526#include "ModronAssertions.h"2728#include "ClassLoaderRememberedSet.hpp"2930#include "AtomicOperations.hpp"31#include "ClassHeapIterator.hpp"32#include "ClassLoaderIterator.hpp"33#include "ClassLoaderSegmentIterator.hpp"34#include "EnvironmentBase.hpp"35#include "Forge.hpp"36#include "GCExtensions.hpp"37#include "HeapRegionManager.hpp"3839#define BITS_PER_UDATA (sizeof(UDATA) * 8)4041MM_ClassLoaderRememberedSet::MM_ClassLoaderRememberedSet(MM_EnvironmentBase *env)42: _extensions(MM_GCExtensions::getExtensions(env))43, _regionManager(_extensions->heapRegionManager)44, _bitVectorSize((_regionManager->getTableRegionCount() + BITS_PER_UDATA - 1) / BITS_PER_UDATA)45, _bitVectorPool(NULL)46, _bitsToClear(NULL)47{48_typeId = __FUNCTION__;49}5051MM_ClassLoaderRememberedSet*52MM_ClassLoaderRememberedSet::newInstance(MM_EnvironmentBase* env)53{54MM_ClassLoaderRememberedSet* classLoaderRememberedSet = (MM_ClassLoaderRememberedSet*)env->getForge()->allocate(sizeof(MM_ClassLoaderRememberedSet), MM_AllocationCategory::REMEMBERED_SET, J9_GET_CALLSITE());55if (classLoaderRememberedSet) {56new(classLoaderRememberedSet) MM_ClassLoaderRememberedSet(env);57if (!classLoaderRememberedSet->initialize(env)) {58classLoaderRememberedSet->kill(env);59classLoaderRememberedSet = NULL;60}61}62return classLoaderRememberedSet;63}6465bool66MM_ClassLoaderRememberedSet::initialize(MM_EnvironmentBase* env)67{68if (!_lock.initialize(env, &_extensions->lnrlOptions, "MM_ClassLoaderRememberedSet:_lock")) {69return false;70}7172if (_extensions->tarokEnableIncrementalClassGC) {73_bitVectorPool = pool_new(_bitVectorSize * sizeof(UDATA), 0, sizeof(UDATA), 0, J9_GET_CALLSITE(), OMRMEM_CATEGORY_MM, poolAllocateHelper, poolFreeHelper, this);74if (NULL == _bitVectorPool) {75return false;76}77_bitsToClear = (UDATA*)pool_newElement(_bitVectorPool);78if (NULL == _bitsToClear) {79return false;80}81} else {82/* don't allocate a bit vector pool since we won't be consulting it for class unloading */83_bitVectorPool = NULL;84}8586return true;87}8889void90MM_ClassLoaderRememberedSet::tearDown(MM_EnvironmentBase* env)91{92if (NULL != _bitVectorPool) {93pool_kill(_bitVectorPool);94_bitVectorPool = NULL;95_bitsToClear = NULL;96}97_lock.tearDown();98}99100void101MM_ClassLoaderRememberedSet::kill(MM_EnvironmentBase *env)102{103tearDown(env);104env->getForge()->free(this);105}106107void *108MM_ClassLoaderRememberedSet::poolAllocateHelper(void* userData, U_32 size, const char* callSite, U_32 memoryCategory, U_32 type, U_32* doInit)109{110/* We ignore the memoryCategory, type and doInit arguments */111MM_ClassLoaderRememberedSet *classLoaderRememberedSet = (MM_ClassLoaderRememberedSet*)userData;112MM_Forge* forge = classLoaderRememberedSet->_extensions->getForge();113return forge->allocate(size, MM_AllocationCategory::REMEMBERED_SET, callSite);114}115116void117MM_ClassLoaderRememberedSet::poolFreeHelper(void* userData, void* address, U_32 type)118{119/* we ignore the type argument */120MM_ClassLoaderRememberedSet *classLoaderRememberedSet = (MM_ClassLoaderRememberedSet*)userData;121MM_Forge* forge = classLoaderRememberedSet->_extensions->getForge();122forge->free(address);123}124125void126MM_ClassLoaderRememberedSet::rememberInstance(MM_EnvironmentBase* env, J9Object* object)127{128Assert_MM_true(NULL != object);129UDATA regionIndex = _regionManager->physicalTableDescriptorIndexForAddress(object);130131J9Class *clazz = J9GC_J9OBJECT_CLAZZ(object, env);132Assert_MM_mustBeClass(clazz);133134if (J9_ARE_ANY_BITS_SET(J9CLASS_EXTENDED_FLAGS(clazz), J9ClassIsAnonymous)) {135/* this is anonymous class - it should be remembered on class level */136/* class should not be unloaded otherwise gcLink is used to form list of unloaded classes */137Assert_MM_true(!J9_ARE_ANY_BITS_SET(clazz->classDepthAndFlags, J9AccClassDying));138rememberRegionInternal(env, regionIndex, (volatile UDATA *)&clazz->gcLink);139} else {140/* non-anonymous classloader */141J9ClassLoader *classLoader = clazz->classLoader;142Assert_MM_true(NULL != classLoader);143144/* check for overflow first */145if (UDATA_MAX != classLoader->gcRememberedSet) {146rememberRegionInternal(env, regionIndex, &classLoader->gcRememberedSet);147}148}149}150151void152MM_ClassLoaderRememberedSet::rememberRegionInternal(MM_EnvironmentBase* env, UDATA regionIndex, volatile UDATA *gcRememberedSetAddress)153{154UDATA taggedRegionIndex = asTaggedRegionIndex(regionIndex);155156bool success = false;157while (!success) {158UDATA gcRememberedSet = *gcRememberedSetAddress;159if (taggedRegionIndex == gcRememberedSet) {160/* this region is already remembered */161success = true;162} else if (isOverflowedRemememberedSet(gcRememberedSet)) {163/* this class loader is overflowed */164success = true;165} else if (0 == gcRememberedSet) {166success = (0 == MM_AtomicOperations::lockCompareExchange(gcRememberedSetAddress, 0, taggedRegionIndex));167} else if (isTaggedRegionIndex(gcRememberedSet)) {168/* another region is remembered -- inflate the remembered set to a bit vector */169installBitVector(env, gcRememberedSetAddress);170} else {171/* this remembered set must be an inflated bit vector */172setBit(env, (volatile UDATA*)gcRememberedSet, regionIndex);173success = true;174}175}176}177178void179MM_ClassLoaderRememberedSet::installBitVector(MM_EnvironmentBase* env, volatile UDATA *gcRememberedSetAddress)180{181_lock.acquire();182UDATA gcRememberedSet = *gcRememberedSetAddress;183if (isOverflowedRemememberedSet(gcRememberedSet)) {184/* this class loader overflowed in another thread - nothing to do */185} else if (!isTaggedRegionIndex(gcRememberedSet)) {186/* already inflated - nothing to do */187Assert_MM_true(0 != gcRememberedSet);188} else {189if (NULL == _bitVectorPool) {190Assert_MM_false(_extensions->tarokEnableIncrementalClassGC);191*gcRememberedSetAddress = UDATA_MAX;192} else {193volatile UDATA* bitVector = (volatile UDATA*)pool_newElement(_bitVectorPool);194if (NULL == bitVector) {195*gcRememberedSetAddress = UDATA_MAX;196} else {197*gcRememberedSetAddress = (UDATA)bitVector;198UDATA rememberedRegion = asUntaggedRegionIndex(gcRememberedSet);199setBit(env, bitVector, rememberedRegion);200}201}202}203_lock.release();204}205206void207MM_ClassLoaderRememberedSet::setBit(MM_EnvironmentBase* env, volatile UDATA* bitVector, UDATA bit)208{209UDATA wordIndex = bit / BITS_PER_UDATA;210UDATA bitIndex = bit % BITS_PER_UDATA;211UDATA bitMask = ((UDATA)1) << bitIndex;212213Assert_MM_true(wordIndex < _bitVectorSize);214215UDATA oldValue = bitVector[wordIndex];216while (0 == (oldValue & bitMask)) {217oldValue = MM_AtomicOperations::lockCompareExchange(&bitVector[wordIndex], oldValue, oldValue | bitMask);218}219}220221bool222MM_ClassLoaderRememberedSet::isBitSet(MM_EnvironmentBase* env, volatile UDATA* bitVector, UDATA bit)223{224UDATA wordIndex = bit / BITS_PER_UDATA;225UDATA bitIndex = bit % BITS_PER_UDATA;226UDATA bitMask = ((UDATA)1) << bitIndex;227228Assert_MM_true(wordIndex < _bitVectorSize);229230return bitMask == (bitVector[wordIndex] & bitMask);231}232233234bool235MM_ClassLoaderRememberedSet::isRemembered(MM_EnvironmentBase *env, J9ClassLoader *classLoader)236{237/* This call is for non-anonymous classloaders only. Anonymous classloader should be handled on classes level */238Assert_MM_true(!J9_ARE_ANY_BITS_SET(classLoader->flags, J9CLASSLOADER_ANON_CLASS_LOADER));239240return isRememberedInternal(env, classLoader->gcRememberedSet);241}242243bool244MM_ClassLoaderRememberedSet::isClassRemembered(MM_EnvironmentBase *env, J9Class *clazz)245{246/* remembering on class level is supported for anonymous classes only */247Assert_MM_true(J9_ARE_ANY_BITS_SET(J9CLASS_EXTENDED_FLAGS(clazz), J9ClassIsAnonymous));248/* class should not be unloaded otherwise gcLink is used to form list of unloaded classes */249Assert_MM_true(!J9_ARE_ANY_BITS_SET(clazz->classDepthAndFlags, J9AccClassDying));250251return isRememberedInternal(env, (UDATA)clazz->gcLink);252}253254bool255MM_ClassLoaderRememberedSet::isRememberedInternal(MM_EnvironmentBase *env, UDATA gcRememberedSet)256{257bool isRemembered = false;258if (0 == gcRememberedSet) {259/* this class loader is not remembered */260} else if (isOverflowedRemememberedSet(gcRememberedSet)) {261/* this class loader is overflowed */262isRemembered = true;263} else if (isTaggedRegionIndex(gcRememberedSet)) {264/* some region is remembered using the immediate encoding */265isRemembered = true;266} else {267/* a bit vector is installed. Check to see if it's all zero */268volatile UDATA* bitVector = (volatile UDATA*)gcRememberedSet;269for (UDATA i = 0; i < _bitVectorSize; i++) {270if (0 != bitVector[i]) {271isRemembered = true;272break;273}274}275}276return isRemembered;277}278279bool280MM_ClassLoaderRememberedSet::isInstanceRemembered(MM_EnvironmentBase *env, J9Object* object)281{282bool isRemembered = false;283Assert_MM_true(NULL != object);284285J9Class *clazz = J9GC_J9OBJECT_CLAZZ(object, env);286Assert_MM_mustBeClass(clazz);287288UDATA regionIndex = _regionManager->physicalTableDescriptorIndexForAddress(object);289if (J9_ARE_ANY_BITS_SET(J9CLASS_EXTENDED_FLAGS(clazz), J9ClassIsAnonymous)) {290/* class should not be unloaded otherwise gcLink is used to form list of unloaded classes */291Assert_MM_true(!J9_ARE_ANY_BITS_SET(clazz->classDepthAndFlags, J9AccClassDying));292isRemembered = isRegionRemembered(env, regionIndex, (UDATA)clazz->gcLink);293} else {294J9ClassLoader *classLoader = clazz->classLoader;295Assert_MM_true(NULL != classLoader);296isRemembered = isRegionRemembered(env, regionIndex, classLoader->gcRememberedSet);297}298return isRemembered;299}300301bool302MM_ClassLoaderRememberedSet::isRegionRemembered(MM_EnvironmentBase *env, UDATA regionIndex, UDATA gcRememberedSet)303{304bool isRemembered = false;305UDATA taggedRegionIndex = asTaggedRegionIndex(regionIndex);306307if (taggedRegionIndex == gcRememberedSet) {308/* this region is the only remembered region */309isRemembered = true;310} else if (isOverflowedRemememberedSet(gcRememberedSet)) {311/* this class loader is overflowed */312isRemembered = true;313} else if (0 == gcRememberedSet) {314/* nothing is remembered */315isRemembered = false;316} else if (isTaggedRegionIndex(gcRememberedSet)) {317/* another region is remembered */318isRemembered = false;319} else {320/* this remembered set must be an inflated bit vector */321isRemembered = isBitSet(env, (volatile UDATA*)gcRememberedSet, regionIndex);322}323324return isRemembered;325}326327void328MM_ClassLoaderRememberedSet::killRememberedSet(MM_EnvironmentBase *env, J9ClassLoader *classLoader)329{330Assert_MM_true(!J9_ARE_ANY_BITS_SET(classLoader->flags, J9CLASSLOADER_ANON_CLASS_LOADER));331332killRememberedSetInternal(env, classLoader->gcRememberedSet);333classLoader->gcRememberedSet = 0;334}335336void337MM_ClassLoaderRememberedSet::killRememberedSetInternal(MM_EnvironmentBase *env, UDATA gcRememberedSet)338{339if (0 == gcRememberedSet) {340/* nothing to do */341} else {342if (!isTaggedRegionIndex(gcRememberedSet)) {343/* inflated remembered set */344_lock.acquire();345Assert_MM_true(NULL != _bitVectorPool);346pool_removeElement(_bitVectorPool, (void*)gcRememberedSet);347_lock.release();348}349}350}351352void353MM_ClassLoaderRememberedSet::resetRegionsToClear(MM_EnvironmentBase *env)354{355Assert_MM_true(NULL != _bitsToClear);356memset(_bitsToClear, 0, _bitVectorSize * sizeof(UDATA));357}358359void360MM_ClassLoaderRememberedSet::prepareToClearRememberedSetForRegion(MM_EnvironmentBase *env, MM_HeapRegionDescriptor *region)361{362Assert_MM_true(NULL != _bitsToClear);363UDATA bitIndex = _regionManager->mapDescriptorToRegionTableIndex(region);364setBit(env, _bitsToClear, bitIndex);365}366367void368MM_ClassLoaderRememberedSet::clearRememberedSets(MM_EnvironmentBase *env)369{370J9JavaVM *javaVM = (J9JavaVM *)env->getLanguageVM();371Assert_MM_true(NULL != _bitsToClear);372GC_ClassLoaderIterator classLoaderIterator(javaVM->classLoaderBlocks);373J9ClassLoader *classLoader = NULL;374while(NULL != (classLoader = classLoaderIterator.nextSlot())) {375if(J9_ARE_ANY_BITS_SET(classLoader->flags, J9CLASSLOADER_ANON_CLASS_LOADER)) {376/* Anonymous classloader should be scanned on level of classes every time */377GC_ClassLoaderSegmentIterator segmentIterator(classLoader, MEMORY_TYPE_RAM_CLASS);378J9MemorySegment *segment = NULL;379while(NULL != (segment = segmentIterator.nextSegment())) {380GC_ClassHeapIterator classHeapIterator(javaVM, segment);381J9Class *clazz = NULL;382while(NULL != (clazz = classHeapIterator.nextClass())) {383/* class should not be unloaded otherwise gcLink is used to form list of unloaded classes */384Assert_MM_true(!J9_ARE_ANY_BITS_SET(clazz->classDepthAndFlags, J9AccClassDying));385clearRememberedSetsInternal(env, (volatile UDATA *)&clazz->gcLink);386}387}388} else {389clearRememberedSetsInternal(env, &classLoader->gcRememberedSet);390}391}392}393394void395MM_ClassLoaderRememberedSet::clearRememberedSetsInternal(MM_EnvironmentBase *env, volatile UDATA *gcRememberedSetAddress)396{397UDATA gcRememberedSet = *gcRememberedSetAddress;398if (0 == gcRememberedSet) {399/* this class loader is not remembered - do nothing */400} else if (isOverflowedRemememberedSet(gcRememberedSet)) {401/* this class loader is overflowed - do nothing */402} else if (isTaggedRegionIndex(gcRememberedSet)) {403/* some region is remembered using the immediate encoding */404UDATA regionIndex = asUntaggedRegionIndex(gcRememberedSet);405if (isBitSet(env, _bitsToClear, regionIndex)) {406/* the region is not preserved - clear it */407*gcRememberedSetAddress = 0;408}409} else {410/* a bit vector is installed */411volatile UDATA* bitVector = (volatile UDATA *)gcRememberedSet;412for (UDATA i = 0; i < _bitVectorSize; i++) {413if ((0 != _bitsToClear[i]) && (0 != bitVector[i])) {414bitVector[i] &= ~_bitsToClear[i];415}416}417}418}419420void421MM_ClassLoaderRememberedSet::setupBeforeGC(MM_EnvironmentBase *env)422{423/* mark the permanent class loaders as overflowed so that we can quickly short circuit remembering their instances */424J9JavaVM *javaVM = (J9JavaVM *)env->getLanguageVM();425426if (NULL != javaVM->systemClassLoader) {427killRememberedSet(env, javaVM->systemClassLoader);428javaVM->systemClassLoader->gcRememberedSet = UDATA_MAX;429}430431if (NULL != javaVM->applicationClassLoader) {432killRememberedSet(env, javaVM->applicationClassLoader);433javaVM->applicationClassLoader->gcRememberedSet = UDATA_MAX;434}435}436437438