Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/gc_vlhgc/CompressedCardTable.cpp
5985 views
1
2
/*******************************************************************************
3
* Copyright (c) 1991, 2021 IBM Corp. and others
4
*
5
* This program and the accompanying materials are made available under
6
* the terms of the Eclipse Public License 2.0 which accompanies this
7
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
8
* or the Apache License, Version 2.0 which accompanies this distribution and
9
* is available at https://www.apache.org/licenses/LICENSE-2.0.
10
*
11
* This Source Code may also be made available under the following
12
* Secondary Licenses when the conditions for such availability set
13
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
14
* General Public License, version 2 with the GNU Classpath
15
* Exception [1] and GNU General Public License, version 2 with the
16
* OpenJDK Assembly Exception [2].
17
*
18
* [1] https://www.gnu.org/software/classpath/license.html
19
* [2] http://openjdk.java.net/legal/assembly-exception.html
20
*
21
* 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-exception
22
*******************************************************************************/
23
24
/**
25
* @file
26
* @ingroup gc_vlhgc
27
*/
28
29
#include "j9.h"
30
#include "j9cfg.h"
31
#include "j9modron.h"
32
#include "ModronAssertions.h"
33
34
#include "CardCleaner.hpp"
35
#include "CardTable.hpp"
36
#include "CompressedCardTable.hpp"
37
#include "EnvironmentBase.hpp"
38
#include "GCExtensions.hpp"
39
#include "Heap.hpp"
40
#include "HeapRegionDescriptor.hpp"
41
42
/*
43
* Bit 1 meaning may be dirty (traditional) or clear (inverted)
44
* Both of this cases are supported in code
45
* just define COMPRESSED_CARD_TABLE_INVERTED if you want inverted version
46
*/
47
/* #define COMPRESSED_CARD_TABLE_INVERTED */
48
49
#if defined(COMPRESSED_CARD_TABLE_INVERTED)
50
51
#define AllCompressedCardsInWordClean UDATA_MAX
52
#define AllCompressedCardsInWordDirty 0
53
#define CompressedCardDirty 0
54
55
#else /* defined(COMPRESSED_CARD_TABLE_INVERTED) */
56
57
#define AllCompressedCardsInWordClean 0
58
#define AllCompressedCardsInWordDirty UDATA_MAX
59
#define CompressedCardDirty 1
60
61
#endif /* defined(COMPRESSED_CARD_TABLE_INVERTED) */
62
63
/*
64
* Number of cards per one compressed card table bit
65
* 1 means bit per card, so compressed card table has full information and no need to look at original card table element
66
* We can try to reduce size if compressed card table representing more then one card per bit however
67
* if compressed card table bit is set an original card must be checked as well
68
*/
69
#define COMPRESSED_CARD_TABLE_DIV 1
70
71
MM_CompressedCardTable *
72
MM_CompressedCardTable::newInstance(MM_EnvironmentBase *env, MM_Heap *heap)
73
{
74
MM_CompressedCardTable *compressedCardTable = (MM_CompressedCardTable *)env->getForge()->allocate(sizeof(MM_CompressedCardTable), MM_AllocationCategory::FIXED, J9_GET_CALLSITE());
75
if (NULL != compressedCardTable) {
76
new(compressedCardTable) MM_CompressedCardTable();
77
if (!compressedCardTable->initialize(env, heap)) {
78
compressedCardTable->kill(env);
79
compressedCardTable = NULL;
80
}
81
}
82
return compressedCardTable;
83
}
84
85
bool
86
MM_CompressedCardTable::initialize(MM_EnvironmentBase *env, MM_Heap *heap)
87
{
88
/* heap maximum physical range must be aligned with compressed card table word */
89
Assert_MM_true(0 == (heap->getMaximumPhysicalRange() % (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV * COMPRESSED_CARDS_PER_WORD)));
90
91
/* Calculate compressed card table size in bytes */
92
UDATA compressedCardTableSize = heap->getMaximumPhysicalRange() / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV * BITS_PER_BYTE);
93
94
/* Allocate compressed card table */
95
_compressedCardTable = (UDATA *)env->getForge()->allocate(compressedCardTableSize, MM_AllocationCategory::FIXED, J9_GET_CALLSITE());
96
97
_heapBase = (UDATA)heap->getHeapBase();
98
99
return (NULL != _compressedCardTable);
100
}
101
102
void
103
MM_CompressedCardTable::kill(MM_EnvironmentBase *env)
104
{
105
tearDown(env);
106
env->getForge()->free(this);
107
}
108
109
void
110
MM_CompressedCardTable::tearDown(MM_EnvironmentBase *env)
111
{
112
if (NULL != _compressedCardTable) {
113
env->getForge()->free(_compressedCardTable);
114
}
115
}
116
117
MMINLINE bool
118
MM_CompressedCardTable::isDirtyCardForPartialCollect(Card state)
119
{
120
bool result = false;
121
122
switch(state) {
123
case CARD_CLEAN:
124
case CARD_GMP_MUST_SCAN:
125
break;
126
case CARD_REMEMBERED_AND_GMP_SCAN:
127
case CARD_REMEMBERED:
128
case CARD_DIRTY:
129
case CARD_PGC_MUST_SCAN:
130
result = true;
131
break;
132
default:
133
Assert_MM_unreachable();
134
break;
135
}
136
137
return result;
138
}
139
140
void
141
MM_CompressedCardTable::setCompressedCardsDirtyForPartialCollect(void *startHeapAddress, void *endHeapAddress)
142
{
143
UDATA compressedCardStartOffset = ((UDATA)startHeapAddress - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);
144
UDATA compressedCardEndOffset = ((UDATA)endHeapAddress - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);
145
UDATA compressedCardStartIndex = compressedCardStartOffset / COMPRESSED_CARDS_PER_WORD;
146
UDATA compressedCardEndIndex = compressedCardEndOffset / COMPRESSED_CARDS_PER_WORD;
147
148
/*
149
* To simplify test logic assume here that given addresses are aligned to correspondent compressed card word border
150
* So no need to handle side pieces (no split of compressed card table words between regions)
151
* However put an assertions here
152
*/
153
Assert_MM_true(0 == (compressedCardStartOffset % COMPRESSED_CARDS_PER_WORD));
154
Assert_MM_true(0 == (compressedCardEndOffset % COMPRESSED_CARDS_PER_WORD));
155
156
UDATA i;
157
for (i = compressedCardStartIndex; i < compressedCardEndIndex; i++) {
158
_compressedCardTable[i] = AllCompressedCardsInWordDirty;
159
}
160
}
161
162
void
163
MM_CompressedCardTable::rebuildCompressedCardTableForPartialCollect(MM_EnvironmentBase *env, void *startHeapAddress, void *endHeapAddress)
164
{
165
MM_CardTable *cardTable = MM_GCExtensions::getExtensions(env)->cardTable;
166
Card *card = cardTable->heapAddrToCardAddr(env, startHeapAddress);
167
Card *cardLast = cardTable->heapAddrToCardAddr(env, endHeapAddress);
168
UDATA compressedCardStartOffset = ((UDATA)startHeapAddress - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);
169
UDATA compressedCardStartIndex = compressedCardStartOffset / COMPRESSED_CARDS_PER_WORD;
170
UDATA *compressedCard = &_compressedCardTable[compressedCardStartIndex];
171
UDATA mask = 1;
172
const UDATA endOfWord = ((UDATA)1) << (COMPRESSED_CARDS_PER_WORD - 1);
173
UDATA compressedCardWord = AllCompressedCardsInWordClean;
174
175
/*
176
* To simplify test logic assume here that given addresses are aligned to correspondent compressed card word border
177
* So no need to handle side pieces (no split of compressed card table words between regions)
178
* However put an assertion here
179
*/
180
Assert_MM_true(0 == (compressedCardStartOffset % COMPRESSED_CARDS_PER_WORD));
181
182
while (card < cardLast) {
183
184
#if (1 == COMPRESSED_CARD_TABLE_DIV)
185
186
Card state = *card++;
187
if (isDirtyCardForPartialCollect(state)) {
188
/* invert bit */
189
compressedCardWord ^= mask;
190
}
191
192
#else /* COMPRESSED_CARD_TABLE_DIV == 1 */
193
/*
194
* This implementation supports case for COMPRESSED_CARD_TABLE_DIV == 1 as well
195
* Special implementation above extracted with hope that it is faster
196
*/
197
Card *next = card + COMPRESSED_CARD_TABLE_DIV;
198
/* check cards responsible for this bit until first dirty or value found */
199
for (UDATA j = 0; j < COMPRESSED_CARD_TABLE_DIV; j++) {
200
Card state = *card++;
201
if (isDirtyCardForPartialCollect(state)) {
202
/* invert bit */
203
compressedCardWord ^= mask;
204
break;
205
}
206
}
207
/* rewind card pointer to first card for next bit */
208
card = next;
209
#endif /* COMPRESSED_CARD_TABLE_DIV == 1 */
210
211
if (mask == endOfWord) {
212
/* last bit in word handled - save word and prepare mask for next one */
213
*compressedCard++ = compressedCardWord;
214
mask = 1;
215
compressedCardWord = AllCompressedCardsInWordClean;
216
} else {
217
/* mask for next bit to handle */
218
mask = mask << 1;
219
}
220
}
221
222
/* end heap address must be aligned*/
223
Assert_MM_true(1 == mask);
224
}
225
226
bool
227
MM_CompressedCardTable::isCompressedCardDirtyForPartialCollect(MM_EnvironmentBase *env, void *heapAddr)
228
{
229
UDATA compressedCardOffset = ((UDATA)heapAddr - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);
230
UDATA compressedCardIndex = compressedCardOffset / COMPRESSED_CARDS_PER_WORD;
231
UDATA compressedCardWord = _compressedCardTable[compressedCardIndex];
232
bool cardDirty = false;
233
234
if (AllCompressedCardsInWordClean != compressedCardWord) {
235
UDATA bit = compressedCardOffset % COMPRESSED_CARDS_PER_WORD;
236
cardDirty = (CompressedCardDirty == ((compressedCardWord >> bit) & 1));
237
238
#if (COMPRESSED_CARD_TABLE_DIV > 1)
239
/*
240
* One bit of compressed card table is responsible for few cards
241
* so if fast check return true we should look at card itself
242
*/
243
if (cardDirty) {
244
MM_CardTable *cardTable = MM_GCExtensions::getExtensions(env)->cardTable;
245
Card *cardAddr = cardTable->heapAddrToCardAddr(env, heapAddr);
246
cardDirty = isDirtyCardForPartialCollect(*cardAddr);
247
}
248
#endif /* COMPRESSED_CARD_TABLE_DIV > 1 */
249
}
250
251
return cardDirty;
252
}
253
254
void
255
MM_CompressedCardTable::cleanCardsInRegion(MM_EnvironmentBase *env, MM_CardCleaner *cardCleaner, MM_HeapRegionDescriptor *region)
256
{
257
cleanCardsInRange(env, cardCleaner, region->getLowAddress(), region->getHighAddress());
258
}
259
260
void
261
MM_CompressedCardTable::cleanCardsInRange(MM_EnvironmentBase *env, MM_CardCleaner *cardCleaner, void *startHeapAddress, void *endHeapAddress)
262
{
263
UDATA compressedCardStartOffset = ((UDATA)startHeapAddress - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);
264
UDATA compressedCardEndOffset = ((UDATA)endHeapAddress - _heapBase) / (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);
265
UDATA compressedCardStartIndex = compressedCardStartOffset / COMPRESSED_CARDS_PER_WORD;
266
UDATA compressedCardEndIndex = compressedCardEndOffset / COMPRESSED_CARDS_PER_WORD;
267
268
/*
269
* To simplify test logic assume here that given addresses are aligned to correspondent compressed card word border
270
* So no need to handle side pieces (no split of compressed card table words between regions)
271
* However put an assertions here
272
*/
273
Assert_MM_true(0 == (compressedCardStartOffset % COMPRESSED_CARDS_PER_WORD));
274
Assert_MM_true(0 == (compressedCardEndOffset % COMPRESSED_CARDS_PER_WORD));
275
276
MM_CardTable *cardTable = MM_GCExtensions::getExtensions(env)->cardTable;
277
Card *card = cardTable->heapAddrToCardAddr(env, startHeapAddress);
278
U_8 *address = (U_8 *)startHeapAddress;
279
UDATA cardsCleaned = 0;
280
281
for (UDATA i = compressedCardStartIndex; i < compressedCardEndIndex; i++) {
282
UDATA compressedCardWord = _compressedCardTable[i];
283
if (AllCompressedCardsInWordClean != compressedCardWord) {
284
/* search for dirty cards - iterate bits */
285
for (UDATA j = 0; j < COMPRESSED_CARDS_PER_WORD; j++) {
286
if (CompressedCardDirty == (compressedCardWord & 1)) {
287
for (UDATA k = 0; k < COMPRESSED_CARD_TABLE_DIV; k++) {
288
/* clean card */
289
cardCleaner->clean(env, address, address + CARD_SIZE, card);
290
card += 1;
291
address += CARD_SIZE;
292
cardsCleaned += 1;
293
}
294
} else {
295
/* skip cards this bit responsible for */
296
card += COMPRESSED_CARD_TABLE_DIV;
297
address += (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV);
298
}
299
compressedCardWord >>= 1;
300
}
301
} else {
302
/* skip cards this word responsible for */
303
card += (COMPRESSED_CARD_TABLE_DIV * COMPRESSED_CARDS_PER_WORD);
304
address += (CARD_SIZE * COMPRESSED_CARD_TABLE_DIV * COMPRESSED_CARDS_PER_WORD);
305
}
306
}
307
308
env->_cardCleaningStats._cardsCleaned += cardsCleaned;
309
}
310
311
bool
312
MM_CompressedCardTable::isReady()
313
{
314
Assert_MM_true(_regionsProcessed <= _totalRegions);
315
316
bool result = (_regionsProcessed == _totalRegions);
317
if (result) {
318
/* need load sync at weak ordered platforms */
319
MM_AtomicOperations::loadSync();
320
}
321
322
return result;
323
}
324
325