Path: blob/master/runtime/gc_vlhgc/CompressedCardTable.cpp
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_vlhgc26*/2728#include "j9.h"29#include "j9cfg.h"30#include "j9modron.h"31#include "ModronAssertions.h"3233#include "CardCleaner.hpp"34#include "CardTable.hpp"35#include "CompressedCardTable.hpp"36#include "EnvironmentBase.hpp"37#include "GCExtensions.hpp"38#include "Heap.hpp"39#include "HeapRegionDescriptor.hpp"4041/*42* Bit 1 meaning may be dirty (traditional) or clear (inverted)43* Both of this cases are supported in code44* just define COMPRESSED_CARD_TABLE_INVERTED if you want inverted version45*/46/* #define COMPRESSED_CARD_TABLE_INVERTED */4748#if defined(COMPRESSED_CARD_TABLE_INVERTED)4950#define AllCompressedCardsInWordClean UDATA_MAX51#define AllCompressedCardsInWordDirty 052#define CompressedCardDirty 05354#else /* defined(COMPRESSED_CARD_TABLE_INVERTED) */5556#define AllCompressedCardsInWordClean 057#define AllCompressedCardsInWordDirty UDATA_MAX58#define CompressedCardDirty 15960#endif /* defined(COMPRESSED_CARD_TABLE_INVERTED) */6162/*63* Number of cards per one compressed card table bit64* 1 means bit per card, so compressed card table has full information and no need to look at original card table element65* We can try to reduce size if compressed card table representing more then one card per bit however66* if compressed card table bit is set an original card must be checked as well67*/68#define COMPRESSED_CARD_TABLE_DIV 16970MM_CompressedCardTable *71MM_CompressedCardTable::newInstance(MM_EnvironmentBase *env, MM_Heap *heap)72{73MM_CompressedCardTable *compressedCardTable = (MM_CompressedCardTable *)env->getForge()->allocate(sizeof(MM_CompressedCardTable), MM_AllocationCategory::FIXED, J9_GET_CALLSITE());74if (NULL != compressedCardTable) {75new(compressedCardTable) MM_CompressedCardTable();76if (!compressedCardTable->initialize(env, heap)) {77compressedCardTable->kill(env);78compressedCardTable = NULL;79}80}81return compressedCardTable;82}8384bool85MM_CompressedCardTable::initialize(MM_EnvironmentBase *env, MM_Heap *heap)86{87/* heap maximum physical range must be aligned with compressed card table word */88Assert_MM_true(0 == (heap->getMaximumPhysicalRange() % (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV * COMPRESSED_CARDS_PER_WORD)));8990/* Calculate compressed card table size in bytes */91UDATA compressedCardTableSize = heap->getMaximumPhysicalRange() / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV * BITS_PER_BYTE);9293/* Allocate compressed card table */94_compressedCardTable = (UDATA *)env->getForge()->allocate(compressedCardTableSize, MM_AllocationCategory::FIXED, J9_GET_CALLSITE());9596_heapBase = (UDATA)heap->getHeapBase();9798return (NULL != _compressedCardTable);99}100101void102MM_CompressedCardTable::kill(MM_EnvironmentBase *env)103{104tearDown(env);105env->getForge()->free(this);106}107108void109MM_CompressedCardTable::tearDown(MM_EnvironmentBase *env)110{111if (NULL != _compressedCardTable) {112env->getForge()->free(_compressedCardTable);113}114}115116MMINLINE bool117MM_CompressedCardTable::isDirtyCardForPartialCollect(Card state)118{119bool result = false;120121switch(state) {122case CARD_CLEAN:123case CARD_GMP_MUST_SCAN:124break;125case CARD_REMEMBERED_AND_GMP_SCAN:126case CARD_REMEMBERED:127case CARD_DIRTY:128case CARD_PGC_MUST_SCAN:129result = true;130break;131default:132Assert_MM_unreachable();133break;134}135136return result;137}138139void140MM_CompressedCardTable::setCompressedCardsDirtyForPartialCollect(void *startHeapAddress, void *endHeapAddress)141{142UDATA compressedCardStartOffset = ((UDATA)startHeapAddress - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);143UDATA compressedCardEndOffset = ((UDATA)endHeapAddress - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);144UDATA compressedCardStartIndex = compressedCardStartOffset / COMPRESSED_CARDS_PER_WORD;145UDATA compressedCardEndIndex = compressedCardEndOffset / COMPRESSED_CARDS_PER_WORD;146147/*148* To simplify test logic assume here that given addresses are aligned to correspondent compressed card word border149* So no need to handle side pieces (no split of compressed card table words between regions)150* However put an assertions here151*/152Assert_MM_true(0 == (compressedCardStartOffset % COMPRESSED_CARDS_PER_WORD));153Assert_MM_true(0 == (compressedCardEndOffset % COMPRESSED_CARDS_PER_WORD));154155UDATA i;156for (i = compressedCardStartIndex; i < compressedCardEndIndex; i++) {157_compressedCardTable[i] = AllCompressedCardsInWordDirty;158}159}160161void162MM_CompressedCardTable::rebuildCompressedCardTableForPartialCollect(MM_EnvironmentBase *env, void *startHeapAddress, void *endHeapAddress)163{164MM_CardTable *cardTable = MM_GCExtensions::getExtensions(env)->cardTable;165Card *card = cardTable->heapAddrToCardAddr(env, startHeapAddress);166Card *cardLast = cardTable->heapAddrToCardAddr(env, endHeapAddress);167UDATA compressedCardStartOffset = ((UDATA)startHeapAddress - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);168UDATA compressedCardStartIndex = compressedCardStartOffset / COMPRESSED_CARDS_PER_WORD;169UDATA *compressedCard = &_compressedCardTable[compressedCardStartIndex];170UDATA mask = 1;171const UDATA endOfWord = ((UDATA)1) << (COMPRESSED_CARDS_PER_WORD - 1);172UDATA compressedCardWord = AllCompressedCardsInWordClean;173174/*175* To simplify test logic assume here that given addresses are aligned to correspondent compressed card word border176* So no need to handle side pieces (no split of compressed card table words between regions)177* However put an assertion here178*/179Assert_MM_true(0 == (compressedCardStartOffset % COMPRESSED_CARDS_PER_WORD));180181while (card < cardLast) {182183#if (1 == COMPRESSED_CARD_TABLE_DIV)184185Card state = *card++;186if (isDirtyCardForPartialCollect(state)) {187/* invert bit */188compressedCardWord ^= mask;189}190191#else /* COMPRESSED_CARD_TABLE_DIV == 1 */192/*193* This implementation supports case for COMPRESSED_CARD_TABLE_DIV == 1 as well194* Special implementation above extracted with hope that it is faster195*/196Card *next = card + COMPRESSED_CARD_TABLE_DIV;197/* check cards responsible for this bit until first dirty or value found */198for (UDATA j = 0; j < COMPRESSED_CARD_TABLE_DIV; j++) {199Card state = *card++;200if (isDirtyCardForPartialCollect(state)) {201/* invert bit */202compressedCardWord ^= mask;203break;204}205}206/* rewind card pointer to first card for next bit */207card = next;208#endif /* COMPRESSED_CARD_TABLE_DIV == 1 */209210if (mask == endOfWord) {211/* last bit in word handled - save word and prepare mask for next one */212*compressedCard++ = compressedCardWord;213mask = 1;214compressedCardWord = AllCompressedCardsInWordClean;215} else {216/* mask for next bit to handle */217mask = mask << 1;218}219}220221/* end heap address must be aligned*/222Assert_MM_true(1 == mask);223}224225bool226MM_CompressedCardTable::isCompressedCardDirtyForPartialCollect(MM_EnvironmentBase *env, void *heapAddr)227{228UDATA compressedCardOffset = ((UDATA)heapAddr - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);229UDATA compressedCardIndex = compressedCardOffset / COMPRESSED_CARDS_PER_WORD;230UDATA compressedCardWord = _compressedCardTable[compressedCardIndex];231bool cardDirty = false;232233if (AllCompressedCardsInWordClean != compressedCardWord) {234UDATA bit = compressedCardOffset % COMPRESSED_CARDS_PER_WORD;235cardDirty = (CompressedCardDirty == ((compressedCardWord >> bit) & 1));236237#if (COMPRESSED_CARD_TABLE_DIV > 1)238/*239* One bit of compressed card table is responsible for few cards240* so if fast check return true we should look at card itself241*/242if (cardDirty) {243MM_CardTable *cardTable = MM_GCExtensions::getExtensions(env)->cardTable;244Card *cardAddr = cardTable->heapAddrToCardAddr(env, heapAddr);245cardDirty = isDirtyCardForPartialCollect(*cardAddr);246}247#endif /* COMPRESSED_CARD_TABLE_DIV > 1 */248}249250return cardDirty;251}252253void254MM_CompressedCardTable::cleanCardsInRegion(MM_EnvironmentBase *env, MM_CardCleaner *cardCleaner, MM_HeapRegionDescriptor *region)255{256cleanCardsInRange(env, cardCleaner, region->getLowAddress(), region->getHighAddress());257}258259void260MM_CompressedCardTable::cleanCardsInRange(MM_EnvironmentBase *env, MM_CardCleaner *cardCleaner, void *startHeapAddress, void *endHeapAddress)261{262UDATA compressedCardStartOffset = ((UDATA)startHeapAddress - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);263UDATA compressedCardEndOffset = ((UDATA)endHeapAddress - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);264UDATA compressedCardStartIndex = compressedCardStartOffset / COMPRESSED_CARDS_PER_WORD;265UDATA compressedCardEndIndex = compressedCardEndOffset / COMPRESSED_CARDS_PER_WORD;266267/*268* To simplify test logic assume here that given addresses are aligned to correspondent compressed card word border269* So no need to handle side pieces (no split of compressed card table words between regions)270* However put an assertions here271*/272Assert_MM_true(0 == (compressedCardStartOffset % COMPRESSED_CARDS_PER_WORD));273Assert_MM_true(0 == (compressedCardEndOffset % COMPRESSED_CARDS_PER_WORD));274275MM_CardTable *cardTable = MM_GCExtensions::getExtensions(env)->cardTable;276Card *card = cardTable->heapAddrToCardAddr(env, startHeapAddress);277U_8 *address = (U_8 *)startHeapAddress;278UDATA cardsCleaned = 0;279280for (UDATA i = compressedCardStartIndex; i < compressedCardEndIndex; i++) {281UDATA compressedCardWord = _compressedCardTable[i];282if (AllCompressedCardsInWordClean != compressedCardWord) {283/* search for dirty cards - iterate bits */284for (UDATA j = 0; j < COMPRESSED_CARDS_PER_WORD; j++) {285if (CompressedCardDirty == (compressedCardWord & 1)) {286for (UDATA k = 0; k < COMPRESSED_CARD_TABLE_DIV; k++) {287/* clean card */288cardCleaner->clean(env, address, address + CARD_SIZE, card);289card += 1;290address += CARD_SIZE;291cardsCleaned += 1;292}293} else {294/* skip cards this bit responsible for */295card += COMPRESSED_CARD_TABLE_DIV;296address += (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);297}298compressedCardWord >>= 1;299}300} else {301/* skip cards this word responsible for */302card += (COMPRESSED_CARD_TABLE_DIV * COMPRESSED_CARDS_PER_WORD);303address += (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV * COMPRESSED_CARDS_PER_WORD);304}305}306307env->_cardCleaningStats._cardsCleaned += cardsCleaned;308}309310bool311MM_CompressedCardTable::isReady()312{313Assert_MM_true(_regionsProcessed <= _totalRegions);314315bool result = (_regionsProcessed == _totalRegions);316if (result) {317/* need load sync at weak ordered platforms */318MM_AtomicOperations::loadSync();319}320321return result;322}323324325