Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/gc_vlhgc/ClassLoaderRememberedSet.cpp
5986 views
1
/*******************************************************************************
2
* Copyright (c) 1991, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* 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 and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
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-exception
21
*******************************************************************************/
22
/**
23
* @file
24
* @ingroup gc_vlhgc
25
*/
26
27
#include "ModronAssertions.h"
28
29
#include "ClassLoaderRememberedSet.hpp"
30
31
#include "AtomicOperations.hpp"
32
#include "ClassHeapIterator.hpp"
33
#include "ClassLoaderIterator.hpp"
34
#include "ClassLoaderSegmentIterator.hpp"
35
#include "EnvironmentBase.hpp"
36
#include "Forge.hpp"
37
#include "GCExtensions.hpp"
38
#include "HeapRegionManager.hpp"
39
40
#define BITS_PER_UDATA (sizeof(UDATA) * 8)
41
42
MM_ClassLoaderRememberedSet::MM_ClassLoaderRememberedSet(MM_EnvironmentBase *env)
43
: _extensions(MM_GCExtensions::getExtensions(env))
44
, _regionManager(_extensions->heapRegionManager)
45
, _bitVectorSize((_regionManager->getTableRegionCount() + BITS_PER_UDATA - 1) / BITS_PER_UDATA)
46
, _bitVectorPool(NULL)
47
, _bitsToClear(NULL)
48
{
49
_typeId = __FUNCTION__;
50
}
51
52
MM_ClassLoaderRememberedSet*
53
MM_ClassLoaderRememberedSet::newInstance(MM_EnvironmentBase* env)
54
{
55
MM_ClassLoaderRememberedSet* classLoaderRememberedSet = (MM_ClassLoaderRememberedSet*)env->getForge()->allocate(sizeof(MM_ClassLoaderRememberedSet), MM_AllocationCategory::REMEMBERED_SET, J9_GET_CALLSITE());
56
if (classLoaderRememberedSet) {
57
new(classLoaderRememberedSet) MM_ClassLoaderRememberedSet(env);
58
if (!classLoaderRememberedSet->initialize(env)) {
59
classLoaderRememberedSet->kill(env);
60
classLoaderRememberedSet = NULL;
61
}
62
}
63
return classLoaderRememberedSet;
64
}
65
66
bool
67
MM_ClassLoaderRememberedSet::initialize(MM_EnvironmentBase* env)
68
{
69
if (!_lock.initialize(env, &_extensions->lnrlOptions, "MM_ClassLoaderRememberedSet:_lock")) {
70
return false;
71
}
72
73
if (_extensions->tarokEnableIncrementalClassGC) {
74
_bitVectorPool = pool_new(_bitVectorSize * sizeof(UDATA), 0, sizeof(UDATA), 0, J9_GET_CALLSITE(), OMRMEM_CATEGORY_MM, poolAllocateHelper, poolFreeHelper, this);
75
if (NULL == _bitVectorPool) {
76
return false;
77
}
78
_bitsToClear = (UDATA*)pool_newElement(_bitVectorPool);
79
if (NULL == _bitsToClear) {
80
return false;
81
}
82
} else {
83
/* don't allocate a bit vector pool since we won't be consulting it for class unloading */
84
_bitVectorPool = NULL;
85
}
86
87
return true;
88
}
89
90
void
91
MM_ClassLoaderRememberedSet::tearDown(MM_EnvironmentBase* env)
92
{
93
if (NULL != _bitVectorPool) {
94
pool_kill(_bitVectorPool);
95
_bitVectorPool = NULL;
96
_bitsToClear = NULL;
97
}
98
_lock.tearDown();
99
}
100
101
void
102
MM_ClassLoaderRememberedSet::kill(MM_EnvironmentBase *env)
103
{
104
tearDown(env);
105
env->getForge()->free(this);
106
}
107
108
void *
109
MM_ClassLoaderRememberedSet::poolAllocateHelper(void* userData, U_32 size, const char* callSite, U_32 memoryCategory, U_32 type, U_32* doInit)
110
{
111
/* We ignore the memoryCategory, type and doInit arguments */
112
MM_ClassLoaderRememberedSet *classLoaderRememberedSet = (MM_ClassLoaderRememberedSet*)userData;
113
MM_Forge* forge = classLoaderRememberedSet->_extensions->getForge();
114
return forge->allocate(size, MM_AllocationCategory::REMEMBERED_SET, callSite);
115
}
116
117
void
118
MM_ClassLoaderRememberedSet::poolFreeHelper(void* userData, void* address, U_32 type)
119
{
120
/* we ignore the type argument */
121
MM_ClassLoaderRememberedSet *classLoaderRememberedSet = (MM_ClassLoaderRememberedSet*)userData;
122
MM_Forge* forge = classLoaderRememberedSet->_extensions->getForge();
123
forge->free(address);
124
}
125
126
void
127
MM_ClassLoaderRememberedSet::rememberInstance(MM_EnvironmentBase* env, J9Object* object)
128
{
129
Assert_MM_true(NULL != object);
130
UDATA regionIndex = _regionManager->physicalTableDescriptorIndexForAddress(object);
131
132
J9Class *clazz = J9GC_J9OBJECT_CLAZZ(object, env);
133
Assert_MM_mustBeClass(clazz);
134
135
if (J9_ARE_ANY_BITS_SET(J9CLASS_EXTENDED_FLAGS(clazz), J9ClassIsAnonymous)) {
136
/* this is anonymous class - it should be remembered on class level */
137
/* class should not be unloaded otherwise gcLink is used to form list of unloaded classes */
138
Assert_MM_true(!J9_ARE_ANY_BITS_SET(clazz->classDepthAndFlags, J9AccClassDying));
139
rememberRegionInternal(env, regionIndex, (volatile UDATA *)&clazz->gcLink);
140
} else {
141
/* non-anonymous classloader */
142
J9ClassLoader *classLoader = clazz->classLoader;
143
Assert_MM_true(NULL != classLoader);
144
145
/* check for overflow first */
146
if (UDATA_MAX != classLoader->gcRememberedSet) {
147
rememberRegionInternal(env, regionIndex, &classLoader->gcRememberedSet);
148
}
149
}
150
}
151
152
void
153
MM_ClassLoaderRememberedSet::rememberRegionInternal(MM_EnvironmentBase* env, UDATA regionIndex, volatile UDATA *gcRememberedSetAddress)
154
{
155
UDATA taggedRegionIndex = asTaggedRegionIndex(regionIndex);
156
157
bool success = false;
158
while (!success) {
159
UDATA gcRememberedSet = *gcRememberedSetAddress;
160
if (taggedRegionIndex == gcRememberedSet) {
161
/* this region is already remembered */
162
success = true;
163
} else if (isOverflowedRemememberedSet(gcRememberedSet)) {
164
/* this class loader is overflowed */
165
success = true;
166
} else if (0 == gcRememberedSet) {
167
success = (0 == MM_AtomicOperations::lockCompareExchange(gcRememberedSetAddress, 0, taggedRegionIndex));
168
} else if (isTaggedRegionIndex(gcRememberedSet)) {
169
/* another region is remembered -- inflate the remembered set to a bit vector */
170
installBitVector(env, gcRememberedSetAddress);
171
} else {
172
/* this remembered set must be an inflated bit vector */
173
setBit(env, (volatile UDATA*)gcRememberedSet, regionIndex);
174
success = true;
175
}
176
}
177
}
178
179
void
180
MM_ClassLoaderRememberedSet::installBitVector(MM_EnvironmentBase* env, volatile UDATA *gcRememberedSetAddress)
181
{
182
_lock.acquire();
183
UDATA gcRememberedSet = *gcRememberedSetAddress;
184
if (isOverflowedRemememberedSet(gcRememberedSet)) {
185
/* this class loader overflowed in another thread - nothing to do */
186
} else if (!isTaggedRegionIndex(gcRememberedSet)) {
187
/* already inflated - nothing to do */
188
Assert_MM_true(0 != gcRememberedSet);
189
} else {
190
if (NULL == _bitVectorPool) {
191
Assert_MM_false(_extensions->tarokEnableIncrementalClassGC);
192
*gcRememberedSetAddress = UDATA_MAX;
193
} else {
194
volatile UDATA* bitVector = (volatile UDATA*)pool_newElement(_bitVectorPool);
195
if (NULL == bitVector) {
196
*gcRememberedSetAddress = UDATA_MAX;
197
} else {
198
*gcRememberedSetAddress = (UDATA)bitVector;
199
UDATA rememberedRegion = asUntaggedRegionIndex(gcRememberedSet);
200
setBit(env, bitVector, rememberedRegion);
201
}
202
}
203
}
204
_lock.release();
205
}
206
207
void
208
MM_ClassLoaderRememberedSet::setBit(MM_EnvironmentBase* env, volatile UDATA* bitVector, UDATA bit)
209
{
210
UDATA wordIndex = bit / BITS_PER_UDATA;
211
UDATA bitIndex = bit % BITS_PER_UDATA;
212
UDATA bitMask = ((UDATA)1) << bitIndex;
213
214
Assert_MM_true(wordIndex < _bitVectorSize);
215
216
UDATA oldValue = bitVector[wordIndex];
217
while (0 == (oldValue & bitMask)) {
218
oldValue = MM_AtomicOperations::lockCompareExchange(&bitVector[wordIndex], oldValue, oldValue | bitMask);
219
}
220
}
221
222
bool
223
MM_ClassLoaderRememberedSet::isBitSet(MM_EnvironmentBase* env, volatile UDATA* bitVector, UDATA bit)
224
{
225
UDATA wordIndex = bit / BITS_PER_UDATA;
226
UDATA bitIndex = bit % BITS_PER_UDATA;
227
UDATA bitMask = ((UDATA)1) << bitIndex;
228
229
Assert_MM_true(wordIndex < _bitVectorSize);
230
231
return bitMask == (bitVector[wordIndex] & bitMask);
232
}
233
234
235
bool
236
MM_ClassLoaderRememberedSet::isRemembered(MM_EnvironmentBase *env, J9ClassLoader *classLoader)
237
{
238
/* This call is for non-anonymous classloaders only. Anonymous classloader should be handled on classes level */
239
Assert_MM_true(!J9_ARE_ANY_BITS_SET(classLoader->flags, J9CLASSLOADER_ANON_CLASS_LOADER));
240
241
return isRememberedInternal(env, classLoader->gcRememberedSet);
242
}
243
244
bool
245
MM_ClassLoaderRememberedSet::isClassRemembered(MM_EnvironmentBase *env, J9Class *clazz)
246
{
247
/* remembering on class level is supported for anonymous classes only */
248
Assert_MM_true(J9_ARE_ANY_BITS_SET(J9CLASS_EXTENDED_FLAGS(clazz), J9ClassIsAnonymous));
249
/* class should not be unloaded otherwise gcLink is used to form list of unloaded classes */
250
Assert_MM_true(!J9_ARE_ANY_BITS_SET(clazz->classDepthAndFlags, J9AccClassDying));
251
252
return isRememberedInternal(env, (UDATA)clazz->gcLink);
253
}
254
255
bool
256
MM_ClassLoaderRememberedSet::isRememberedInternal(MM_EnvironmentBase *env, UDATA gcRememberedSet)
257
{
258
bool isRemembered = false;
259
if (0 == gcRememberedSet) {
260
/* this class loader is not remembered */
261
} else if (isOverflowedRemememberedSet(gcRememberedSet)) {
262
/* this class loader is overflowed */
263
isRemembered = true;
264
} else if (isTaggedRegionIndex(gcRememberedSet)) {
265
/* some region is remembered using the immediate encoding */
266
isRemembered = true;
267
} else {
268
/* a bit vector is installed. Check to see if it's all zero */
269
volatile UDATA* bitVector = (volatile UDATA*)gcRememberedSet;
270
for (UDATA i = 0; i < _bitVectorSize; i++) {
271
if (0 != bitVector[i]) {
272
isRemembered = true;
273
break;
274
}
275
}
276
}
277
return isRemembered;
278
}
279
280
bool
281
MM_ClassLoaderRememberedSet::isInstanceRemembered(MM_EnvironmentBase *env, J9Object* object)
282
{
283
bool isRemembered = false;
284
Assert_MM_true(NULL != object);
285
286
J9Class *clazz = J9GC_J9OBJECT_CLAZZ(object, env);
287
Assert_MM_mustBeClass(clazz);
288
289
UDATA regionIndex = _regionManager->physicalTableDescriptorIndexForAddress(object);
290
if (J9_ARE_ANY_BITS_SET(J9CLASS_EXTENDED_FLAGS(clazz), J9ClassIsAnonymous)) {
291
/* class should not be unloaded otherwise gcLink is used to form list of unloaded classes */
292
Assert_MM_true(!J9_ARE_ANY_BITS_SET(clazz->classDepthAndFlags, J9AccClassDying));
293
isRemembered = isRegionRemembered(env, regionIndex, (UDATA)clazz->gcLink);
294
} else {
295
J9ClassLoader *classLoader = clazz->classLoader;
296
Assert_MM_true(NULL != classLoader);
297
isRemembered = isRegionRemembered(env, regionIndex, classLoader->gcRememberedSet);
298
}
299
return isRemembered;
300
}
301
302
bool
303
MM_ClassLoaderRememberedSet::isRegionRemembered(MM_EnvironmentBase *env, UDATA regionIndex, UDATA gcRememberedSet)
304
{
305
bool isRemembered = false;
306
UDATA taggedRegionIndex = asTaggedRegionIndex(regionIndex);
307
308
if (taggedRegionIndex == gcRememberedSet) {
309
/* this region is the only remembered region */
310
isRemembered = true;
311
} else if (isOverflowedRemememberedSet(gcRememberedSet)) {
312
/* this class loader is overflowed */
313
isRemembered = true;
314
} else if (0 == gcRememberedSet) {
315
/* nothing is remembered */
316
isRemembered = false;
317
} else if (isTaggedRegionIndex(gcRememberedSet)) {
318
/* another region is remembered */
319
isRemembered = false;
320
} else {
321
/* this remembered set must be an inflated bit vector */
322
isRemembered = isBitSet(env, (volatile UDATA*)gcRememberedSet, regionIndex);
323
}
324
325
return isRemembered;
326
}
327
328
void
329
MM_ClassLoaderRememberedSet::killRememberedSet(MM_EnvironmentBase *env, J9ClassLoader *classLoader)
330
{
331
Assert_MM_true(!J9_ARE_ANY_BITS_SET(classLoader->flags, J9CLASSLOADER_ANON_CLASS_LOADER));
332
333
killRememberedSetInternal(env, classLoader->gcRememberedSet);
334
classLoader->gcRememberedSet = 0;
335
}
336
337
void
338
MM_ClassLoaderRememberedSet::killRememberedSetInternal(MM_EnvironmentBase *env, UDATA gcRememberedSet)
339
{
340
if (0 == gcRememberedSet) {
341
/* nothing to do */
342
} else {
343
if (!isTaggedRegionIndex(gcRememberedSet)) {
344
/* inflated remembered set */
345
_lock.acquire();
346
Assert_MM_true(NULL != _bitVectorPool);
347
pool_removeElement(_bitVectorPool, (void*)gcRememberedSet);
348
_lock.release();
349
}
350
}
351
}
352
353
void
354
MM_ClassLoaderRememberedSet::resetRegionsToClear(MM_EnvironmentBase *env)
355
{
356
Assert_MM_true(NULL != _bitsToClear);
357
memset(_bitsToClear, 0, _bitVectorSize * sizeof(UDATA));
358
}
359
360
void
361
MM_ClassLoaderRememberedSet::prepareToClearRememberedSetForRegion(MM_EnvironmentBase *env, MM_HeapRegionDescriptor *region)
362
{
363
Assert_MM_true(NULL != _bitsToClear);
364
UDATA bitIndex = _regionManager->mapDescriptorToRegionTableIndex(region);
365
setBit(env, _bitsToClear, bitIndex);
366
}
367
368
void
369
MM_ClassLoaderRememberedSet::clearRememberedSets(MM_EnvironmentBase *env)
370
{
371
J9JavaVM *javaVM = (J9JavaVM *)env->getLanguageVM();
372
Assert_MM_true(NULL != _bitsToClear);
373
GC_ClassLoaderIterator classLoaderIterator(javaVM->classLoaderBlocks);
374
J9ClassLoader *classLoader = NULL;
375
while(NULL != (classLoader = classLoaderIterator.nextSlot())) {
376
if(J9_ARE_ANY_BITS_SET(classLoader->flags, J9CLASSLOADER_ANON_CLASS_LOADER)) {
377
/* Anonymous classloader should be scanned on level of classes every time */
378
GC_ClassLoaderSegmentIterator segmentIterator(classLoader, MEMORY_TYPE_RAM_CLASS);
379
J9MemorySegment *segment = NULL;
380
while(NULL != (segment = segmentIterator.nextSegment())) {
381
GC_ClassHeapIterator classHeapIterator(javaVM, segment);
382
J9Class *clazz = NULL;
383
while(NULL != (clazz = classHeapIterator.nextClass())) {
384
/* class should not be unloaded otherwise gcLink is used to form list of unloaded classes */
385
Assert_MM_true(!J9_ARE_ANY_BITS_SET(clazz->classDepthAndFlags, J9AccClassDying));
386
clearRememberedSetsInternal(env, (volatile UDATA *)&clazz->gcLink);
387
}
388
}
389
} else {
390
clearRememberedSetsInternal(env, &classLoader->gcRememberedSet);
391
}
392
}
393
}
394
395
void
396
MM_ClassLoaderRememberedSet::clearRememberedSetsInternal(MM_EnvironmentBase *env, volatile UDATA *gcRememberedSetAddress)
397
{
398
UDATA gcRememberedSet = *gcRememberedSetAddress;
399
if (0 == gcRememberedSet) {
400
/* this class loader is not remembered - do nothing */
401
} else if (isOverflowedRemememberedSet(gcRememberedSet)) {
402
/* this class loader is overflowed - do nothing */
403
} else if (isTaggedRegionIndex(gcRememberedSet)) {
404
/* some region is remembered using the immediate encoding */
405
UDATA regionIndex = asUntaggedRegionIndex(gcRememberedSet);
406
if (isBitSet(env, _bitsToClear, regionIndex)) {
407
/* the region is not preserved - clear it */
408
*gcRememberedSetAddress = 0;
409
}
410
} else {
411
/* a bit vector is installed */
412
volatile UDATA* bitVector = (volatile UDATA *)gcRememberedSet;
413
for (UDATA i = 0; i < _bitVectorSize; i++) {
414
if ((0 != _bitsToClear[i]) && (0 != bitVector[i])) {
415
bitVector[i] &= ~_bitsToClear[i];
416
}
417
}
418
}
419
}
420
421
void
422
MM_ClassLoaderRememberedSet::setupBeforeGC(MM_EnvironmentBase *env)
423
{
424
/* mark the permanent class loaders as overflowed so that we can quickly short circuit remembering their instances */
425
J9JavaVM *javaVM = (J9JavaVM *)env->getLanguageVM();
426
427
if (NULL != javaVM->systemClassLoader) {
428
killRememberedSet(env, javaVM->systemClassLoader);
429
javaVM->systemClassLoader->gcRememberedSet = UDATA_MAX;
430
}
431
432
if (NULL != javaVM->applicationClassLoader) {
433
killRememberedSet(env, javaVM->applicationClassLoader);
434
javaVM->applicationClassLoader->gcRememberedSet = UDATA_MAX;
435
}
436
}
437
438