Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/gc_realtime/IncrementalOverflow.cpp
5985 views
1
/*******************************************************************************
2
* Copyright (c) 1991, 2019 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
#include "omr.h"
24
#include "omrcfg.h"
25
26
#include "EnvironmentRealtime.hpp"
27
#include "GCExtensionsBase.hpp"
28
#include "HeapLinkedFreeHeader.hpp"
29
#include "HeapRegionManager.hpp"
30
#include "HeapRegionDescriptorRealtime.hpp"
31
#include "IncrementalOverflow.hpp"
32
#include "Packet.hpp"
33
#include "RealtimeGC.hpp"
34
#include "RealtimeMarkingScheme.hpp"
35
#include "WorkPackets.hpp"
36
37
38
/****************************************
39
* Initialization
40
****************************************
41
*/
42
43
MM_IncrementalOverflow *
44
MM_IncrementalOverflow::newInstance(MM_EnvironmentBase *env, MM_WorkPackets *workPackets)
45
{
46
MM_IncrementalOverflow *overflow;
47
48
overflow = (MM_IncrementalOverflow *)env->getForge()->allocate(sizeof(MM_IncrementalOverflow), MM_AllocationCategory::FIXED, OMR_GET_CALLSITE());
49
if (overflow) {
50
new(overflow) MM_IncrementalOverflow(env, workPackets);
51
if (!overflow->initialize(env)) {
52
overflow->kill(env);
53
overflow = NULL;
54
}
55
}
56
return overflow;
57
}
58
59
/**
60
* Initialize a MM_IncrementalOverflow object.
61
*
62
* @return true on success, false otherwise
63
*/
64
bool
65
MM_IncrementalOverflow::initialize(MM_EnvironmentBase *env)
66
{
67
if (!MM_WorkPacketOverflow::initialize(env)) {
68
return false;
69
}
70
71
_extensions = env->getExtensions();
72
73
return true;
74
}
75
76
/**
77
* Cleanup the resources for a MM_IncrementalOverflow object
78
*/
79
void
80
MM_IncrementalOverflow::tearDown(MM_EnvironmentBase *env)
81
{
82
MM_WorkPacketOverflow::tearDown(env);
83
}
84
85
/**
86
* Push the region to be overflowed onto the local cache. If it is already
87
* on the cache just return.
88
*/
89
MMINLINE void
90
MM_IncrementalOverflow::pushLocal(MM_EnvironmentBase *env, MM_HeapRegionDescriptorRealtime *region, MM_OverflowType type)
91
{
92
MM_EnvironmentRealtime *envRealtime = MM_EnvironmentRealtime::getEnvironment(env);
93
MM_HeapRegionDescriptorRealtime **cache = envRealtime->getOverflowCache();
94
95
/* If the local cache is full flush it */
96
if (envRealtime->getOverflowCacheUsedCount() >= envRealtime->getExtensions()->overflowCacheCount) {
97
flushLocal(envRealtime, type);
98
}
99
100
cache[envRealtime->getOverflowCacheUsedCount()] = region;
101
envRealtime->incrementOverflowCacheUsedCount();
102
}
103
104
/**
105
* Push the region onto the global overflow list.
106
* @note this function does not use any locks when manipulating the list. The caller
107
* is responsible for handling the lock.
108
*/
109
MMINLINE void
110
MM_IncrementalOverflow::pushNoLock(MM_EnvironmentBase *env, MM_HeapRegionDescriptorRealtime *region)
111
{
112
if (NULL == region->getNextOverflowRegion()) {
113
region->setNextOverflowRegion((MM_HeapRegionDescriptorRealtime *)((uintptr_t)_overflowList | 1));
114
_overflowList = region;
115
}
116
}
117
118
/**
119
* This functions pushes all of the regions from the local cache
120
* to the global cache. If these regions are being overflowed due to the workstack
121
* check for yielding before the flush begins.
122
*/
123
MMINLINE void
124
MM_IncrementalOverflow::flushLocal(MM_EnvironmentBase *env, MM_OverflowType type)
125
{
126
MM_EnvironmentRealtime *envRealtime = MM_EnvironmentRealtime::getEnvironment(env);
127
uintptr_t currentCount = envRealtime->getOverflowCacheUsedCount();
128
MM_HeapRegionDescriptorRealtime **cache = envRealtime->getOverflowCache();
129
uintptr_t count = 0;
130
131
omrthread_monitor_enter(_overflowListMonitor);
132
for (count = 0; count < currentCount; count++) {
133
MM_HeapRegionDescriptorRealtime *localRegion = cache[count];
134
pushNoLock(env, localRegion);
135
}
136
omrthread_monitor_exit(_overflowListMonitor);
137
envRealtime->resetOverflowCacheUsedCount();
138
}
139
140
/**
141
* Push a region onto the global overflow list.
142
*/
143
MMINLINE void
144
MM_IncrementalOverflow::push(MM_EnvironmentBase *env, MM_HeapRegionDescriptorRealtime *region)
145
{
146
omrthread_monitor_enter(_overflowListMonitor);
147
148
pushNoLock(env, region);
149
150
omrthread_monitor_exit(_overflowListMonitor);
151
}
152
153
/**
154
* Pop a region off of the global overflow list.
155
*/
156
MMINLINE MM_HeapRegionDescriptorRealtime *
157
MM_IncrementalOverflow::pop(MM_EnvironmentBase *env)
158
{
159
MM_HeapRegionDescriptorRealtime *region = NULL;
160
161
/* The _overflowListMonitor must be held while modifying the overflow list */
162
omrthread_monitor_enter(_overflowListMonitor);
163
164
if (NULL != _overflowList) {
165
region = _overflowList;
166
_overflowList = (MM_HeapRegionDescriptorRealtime*)((uintptr_t)region->getNextOverflowRegion() & ~1);
167
region->setNextOverflowRegion(NULL);
168
}
169
170
omrthread_monitor_exit(_overflowListMonitor);
171
172
return region;
173
}
174
175
/**
176
* Empty the packet by overflowing all if it's items
177
*
178
* @param env The current Environment
179
* @param packet The packet to empty
180
* @param type - ignored by incremental handler
181
*/
182
void
183
MM_IncrementalOverflow::emptyToOverflow(MM_EnvironmentBase *env, MM_Packet *packet, MM_OverflowType type)
184
{
185
void *item;
186
187
_extensions->globalGCStats.metronomeStats.incrementWorkPacketOverflowCount();
188
189
while(NULL != (item = packet->pop(env))) {
190
overflowItemInternal(env, item, type);
191
}
192
/* Finished overflowing this region so flush the remaining entries in the local cache */
193
flushLocal(env, type);
194
195
Assert_MM_true(packet->isEmpty());
196
197
_overflowThisGCCycle = 1;
198
}
199
200
/**
201
* Fill the packet from overflowed items
202
*
203
* @param env The current Environment
204
* @param packet The packet to fill
205
*/
206
void
207
MM_IncrementalOverflow::fillFromOverflow(MM_EnvironmentBase *env, MM_Packet *packet)
208
{
209
MM_EnvironmentRealtime *envRealtime = MM_EnvironmentRealtime::getEnvironment(env);
210
MM_HeapRegionDescriptorRealtime* region;
211
MM_RealtimeGC *realtimeGC = envRealtime->getExtensions()->realtimeGC;
212
MM_RealtimeMarkingScheme *markingScheme = realtimeGC->getMarkingScheme();
213
bool roomLeft = true;
214
215
while (roomLeft && ((region = pop(envRealtime)) != NULL)) {
216
if (region->isArraylet()) {
217
uintptr_t arrayletIndex = 0;
218
uintptr_t arrayletLeafLogSize = envRealtime->getOmrVM()->_arrayletLeafLogSize;
219
uintptr_t arrayletsPerRegion = envRealtime->getExtensions()->arrayletsPerRegion;
220
221
while (arrayletIndex < arrayletsPerRegion) {
222
if (region->isArrayletUsed(arrayletIndex)) {
223
/* Only return arraylets if they contain pointers (scan stack can't deal with base type
224
* leaves) and whose spine is marked to prevent the arraylet leaf elements from being kept
225
* alive (more floating garbage)
226
*/
227
omrobjectptr_t arrayletParent = (omrobjectptr_t)region->getArrayletParent(arrayletIndex);
228
if (_extensions->objectModel.isObjectArray(arrayletParent) && markingScheme->isMarked(arrayletParent)) {
229
uintptr_t* arraylet = region->getArraylet(arrayletIndex, arrayletLeafLogSize);
230
if (packet->isFull(envRealtime)) {
231
push(envRealtime, region);
232
roomLeft = false;
233
break;
234
}
235
packet->push(envRealtime, (void *)ARRAYLET_TO_ITEM(arraylet));
236
}
237
}
238
arrayletIndex += 1;
239
realtimeGC->_sched->condYieldFromGC(env);
240
}
241
} else if (region->isCanonical()) {
242
if (region->isSmall()) {
243
/* A small region is divided into cells.
244
* Iterate over the cells returning the objects contained within inuse cells
245
*/
246
uintptr_t numCells = region->getNumCells();
247
uintptr_t cellSize = region->getCellSize();
248
uintptr_t *baseAddress = (uintptr_t *)region->getLowAddress();
249
uintptr_t cellIndex = 0;
250
while(cellIndex < numCells) {
251
omrobjectptr_t object = (omrobjectptr_t)((uintptr_t)baseAddress + (cellIndex * cellSize));
252
if (!_extensions->objectModel.isDeadObject(object)) {
253
if(_extensions->objectModel.isOverflowBitSet(object)) {
254
if (packet->isFull(envRealtime)) {
255
push(envRealtime, region);
256
roomLeft = false;
257
break;
258
}
259
if(_extensions->objectModel.atomicClearOverflowBit(object)) {
260
packet->push(envRealtime, (void *)OBJECT_TO_ITEM(object));
261
}
262
}
263
cellIndex += 1;
264
} else {
265
cellIndex += (MM_HeapLinkedFreeHeader::getHeapLinkedFreeHeader(object)->getSize() / cellSize);
266
}
267
268
realtimeGC->_sched->condYieldFromGC(env);
269
}
270
/* ran off end of region */
271
} else if (region->isLarge()) {
272
/* A region that is both large and canonical contains exactly 1 object */
273
uintptr_t *cell = (uintptr_t *)region->getLowAddress();
274
omrobjectptr_t object = (omrobjectptr_t)cell;
275
if (_extensions->objectModel.isOverflowBitSet(object)) {
276
if (packet->isFull(envRealtime)) {
277
push(envRealtime, region);
278
roomLeft = false;
279
break;
280
}
281
if (_extensions->objectModel.atomicClearOverflowBit(object)) {
282
packet->push(envRealtime, (void *)OBJECT_TO_ITEM(object));
283
}
284
}
285
realtimeGC->_sched->condYieldFromGC(env);
286
}
287
}
288
}
289
}
290
291
/**
292
* Overflow the item. To overflow incremental items the object
293
* and the object's region have to both be marked as overflowed.
294
*
295
* @param env The current Environment
296
* @param item The item to overflow
297
* @param type - ignored by incremental handler
298
*/
299
void
300
MM_IncrementalOverflow::overflowItem(MM_EnvironmentBase *env, void *item, MM_OverflowType type)
301
{
302
_extensions->globalGCStats.metronomeStats.incrementObjectOverflowCount();
303
304
overflowItemInternal(env, item, type);
305
flushLocal(env, type);
306
307
_overflowThisGCCycle = 1;
308
}
309
310
/**
311
* Overflow the item. To overflow incremental items the object
312
* and the object's region have to both be marked as overflowed.
313
*
314
* @param env The current Environment
315
* @param item The item to overflow
316
* @param type - ignored by incremental handler
317
*/
318
MMINLINE void
319
MM_IncrementalOverflow::overflowItemInternal(MM_EnvironmentBase *env, void *item, MM_OverflowType type)
320
{
321
MM_HeapRegionManager *manager = _extensions->heap->getHeapRegionManager();
322
MM_HeapRegionDescriptorRealtime* region;
323
324
if (!IS_ITEM_ARRAYLET((uintptr_t)item)) {
325
/* Set overflow bit in the object's flags */
326
omrobjectptr_t objectPtr = ITEM_TO_OBJECT((uintptr_t)item);
327
if (!_extensions->objectModel.atomicSetOverflowBit(objectPtr)) {
328
return;
329
}
330
}
331
332
/* Arraylets are not individually marked, only the region they belong to */
333
/* TODO: Consider marking individual arraylet. For example, tag low bit of its spine back pointer),
334
* or even introduce arraylet flags in its region. */
335
336
/* For both arraylets and objects, mark the region as containing overflow objects */
337
region = (MM_HeapRegionDescriptorRealtime *)manager->tableDescriptorForAddress(item);
338
pushLocal(env, region, type);
339
}
340
341
void
342
MM_IncrementalOverflow::reset(MM_EnvironmentBase *env)
343
{
344
/* the _overflowListMonitor must be held while modifying the overflow list */
345
omrthread_monitor_enter(_overflowListMonitor);
346
_overflowList = NULL;
347
omrthread_monitor_exit(_overflowListMonitor);
348
}
349
350