Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/gc_check/CheckCycle.cpp
5990 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
#include <string.h>
25
26
#include "vendor_version.h"
27
#include "CheckCycle.hpp"
28
#include "CheckClassHeap.hpp"
29
#include "CheckClassLoaders.hpp"
30
#include "CheckEngine.hpp"
31
#include "CheckFinalizableList.hpp"
32
#include "CheckJNIGlobalReferences.hpp"
33
#include "CheckJNIWeakGlobalReferences.hpp"
34
#include "CheckJVMTIObjectTagTables.hpp"
35
#include "CheckMonitorTable.hpp"
36
#include "CheckObjectHeap.hpp"
37
#include "CheckOwnableSynchronizerList.hpp"
38
#include "CheckRememberedSet.hpp"
39
#include "CheckStringTable.hpp"
40
#include "CheckUnfinalizedList.hpp"
41
#include "CheckVMClassSlots.hpp"
42
#include "CheckVMThreads.hpp"
43
#include "CheckVMThreadStacks.hpp"
44
#include "FixDeadObjects.hpp"
45
#include "GCExtensionsBase.hpp"
46
47
#define TOTAL_NUM_CHECKS (sizeof(GC_CheckCycle::funcArray) / sizeof(GC_CheckCycle::funcStruct))
48
const GC_CheckCycle::funcStruct GC_CheckCycle::funcArray[] = {
49
/* move ownablesynchronizer check before objectheap check in order to ownablesynchronizer check runs after objectheap check(the checks in stack, last in first out)
50
* for ownablesynchronizer consistency check, which defends on both ownablesynchronizer check before objectheap check. the verify consistency only at the end of ownablesynchronizer check.
51
*/
52
{"ownablesynchronizer", J9MODRON_GCCHK_SCAN_OWNABLE_SYNCHRONIZER, GC_CheckOwnableSynchronizerList::newInstance},
53
{"objectheap", J9MODRON_GCCHK_SCAN_OBJECT_HEAP, GC_CheckObjectHeap::newInstance},
54
{"classheap", J9MODRON_GCCHK_SCAN_CLASS_HEAP, GC_CheckClassHeap::newInstance},
55
#if defined(J9VM_GC_GENERATIONAL)
56
{"rememberedset", J9MODRON_GCCHK_SCAN_REMEMBERED_SET, GC_CheckRememberedSet::newInstance},
57
#endif
58
#if defined(J9VM_GC_FINALIZATION)
59
{"unfinalized", J9MODRON_GCCHK_SCAN_UNFINALIZED, GC_CheckUnfinalizedList::newInstance},
60
{"finalizable", J9MODRON_GCCHK_SCAN_FINALIZABLE, GC_CheckFinalizableList::newInstance},
61
#endif
62
{"stringtable", J9MODRON_GCCHK_SCAN_STRING_TABLE, GC_CheckStringTable::newInstance},
63
{"classloaders", J9MODRON_GCCHK_SCAN_CLASS_LOADERS, GC_CheckClassLoaders::newInstance},
64
{"jniglobalrefs", J9MODRON_GCCHK_SCAN_JNI_GLOBAL_REFERENCES, GC_CheckJNIGlobalReferences::newInstance},
65
{"jniweakglobalrefs", J9MODRON_GCCHK_SCAN_JNI_WEAK_GLOBAL_REFERENCES, GC_CheckJNIWeakGlobalReferences::newInstance},
66
#if defined(J9VM_OPT_JVMTI)
67
{"jvmtiobjecttagtables", J9MODRON_GCCHK_SCAN_JVMTI_OBJECT_TAG_TABLES, GC_CheckJVMTIObjectTagTables::newInstance},
68
#endif
69
{"vmclassslots", J9MODRON_GCCHK_SCAN_VM_CLASS_SLOTS, GC_CheckVMClassSlots::newInstance},
70
{"monitortable", J9MODRON_GCCHK_SCAN_MONITOR_TABLE, GC_CheckMonitorTable::newInstance},
71
{"vmthreads", J9MODRON_GCCHK_SCAN_VMTHREADS, GC_CheckVMThreads::newInstance},
72
{"threadstacks", J9MODRON_GCCHK_SCAN_THREADSTACKS, GC_CheckVMThreadStacks::newInstance}
73
};
74
75
/**
76
* Provide user help.
77
* Display GC_Check command line option help.
78
*/
79
void
80
GC_CheckCycle::printHelp(J9PortLibrary *portLib)
81
{
82
PORT_ACCESS_FROM_PORT(portLib);
83
84
j9tty_printf(PORTLIB, "gcchk for J9, Version " J9JVM_VERSION_STRING "\n");
85
j9tty_printf(PORTLIB, J9_COPYRIGHT_STRING "\n\n");
86
j9tty_printf(PORTLIB, "Usage: -Xcheck:gc[:scanOption,...][:verifyOption,...][:miscOption,...]\n");
87
j9tty_printf(PORTLIB, "scan options (default is all):\n");
88
j9tty_printf(PORTLIB, " all all object and VM slots\n");
89
j9tty_printf(PORTLIB, " none\n");
90
91
/* print the name of each check supported */
92
for(UDATA i = 0; i < TOTAL_NUM_CHECKS; i++) {
93
j9tty_printf(PORTLIB, " %s\n", funcArray[i].name);
94
}
95
96
j9tty_printf(PORTLIB, " heap object and class heaps\n");
97
j9tty_printf(PORTLIB, " novmthreads\n");
98
j9tty_printf(PORTLIB, " help print this screen\n");
99
100
j9tty_printf(PORTLIB, "\nverify options (default is all):\n");
101
j9tty_printf(PORTLIB, " all\n");
102
j9tty_printf(PORTLIB, " none\n");
103
j9tty_printf(PORTLIB, " classslot\n");
104
j9tty_printf(PORTLIB, " range\n");
105
j9tty_printf(PORTLIB, " flags\n");
106
107
j9tty_printf(PORTLIB, "\nmisc options (default is verbose,check):\n");
108
j9tty_printf(PORTLIB, " verbose\n");
109
j9tty_printf(PORTLIB, " quiet\n");
110
j9tty_printf(PORTLIB, " scan\n");
111
j9tty_printf(PORTLIB, " noscan\n");
112
j9tty_printf(PORTLIB, " check\n");
113
j9tty_printf(PORTLIB, " nocheck\n");
114
j9tty_printf(PORTLIB, " maxErrors=X\n");
115
116
j9tty_printf(PORTLIB, " abort\n");
117
j9tty_printf(PORTLIB, " noabort\n");
118
j9tty_printf(PORTLIB, " dumpstack\n");
119
j9tty_printf(PORTLIB, " nodumpstack\n");
120
j9tty_printf(PORTLIB, " interval=X\n");
121
j9tty_printf(PORTLIB, " globalinterval=X\n");
122
#if defined(J9VM_GC_MODRON_SCAVENGER)
123
j9tty_printf(PORTLIB, " localinterval=X\n");
124
#endif /* J9VM_GC_MODRON_SCAVENGER */
125
j9tty_printf(PORTLIB, " startindex=x\n");
126
#if defined(J9VM_GC_MODRON_SCAVENGER)
127
j9tty_printf(PORTLIB, " scavengerbackout\n");
128
j9tty_printf(PORTLIB, " suppresslocal\n");
129
#endif /* J9VM_GC_MODRON_SCAVENGER */
130
j9tty_printf(PORTLIB, " suppressglobal\n");
131
#if defined(J9VM_GC_GENERATIONAL)
132
j9tty_printf(PORTLIB, " rememberedsetoverflow\n");
133
#endif /* J9VM_GC_GENERATIONAL */
134
j9tty_printf(PORTLIB, "\n");
135
}
136
137
/**
138
* Generate the list of checks to perform in this cycle
139
* Iterates over the scanFlags UDATA, instantiating a GC_Check subtype for
140
* each bit turned on and adding it to the list.
141
*
142
* @param scanFlags Bit vector containing a bit for each type of check we're
143
* going to run.
144
*/
145
void
146
GC_CheckCycle::generateCheckList(UDATA scanFlags)
147
{
148
/* Iterate over funcArray dereferencing the function pointer of the checks we want to instantiate */
149
for(UDATA i = 0; i < TOTAL_NUM_CHECKS; i++) {
150
if(scanFlags & funcArray[i].bitmask) {
151
/* we've found a check we need to instantiate */
152
GC_Check *check = (funcArray[i].function)(_javaVM, _engine);
153
/* add it to the list of checks */
154
if(check) {
155
check->setNext(_checks);
156
check->setBitId(funcArray[i].bitmask);
157
_checks = check;
158
}
159
}
160
}
161
}
162
163
/**
164
* Parse command line.
165
* Parse the command line for GCCheck options.
166
*
167
* @param options a string containing the user-supplied options
168
*/
169
bool
170
GC_CheckCycle::initialize(const char *options)
171
{
172
GCCHK_Extensions *extensions = (GCCHK_Extensions *)((MM_GCExtensions*)_javaVM->gcExtensions)->gcchkExtensions;
173
UDATA scanFlags = 0, checkFlags = 0, miscFlags;
174
char *scan_start = (char *)options;
175
const char *scan_limit = options + strlen(options);
176
177
/* set the default miscFlags */
178
miscFlags = J9MODRON_GCCHK_VERBOSE | J9MODRON_GCCHK_MISC_CHECK;
179
180
/* parse supplied options */
181
top:
182
while (scan_start < scan_limit) {
183
184
/* ignore separators */
185
try_scan(&scan_start, ",");
186
187
if (try_scan(&scan_start, "all")) {
188
scanFlags |= J9MODRON_GCCHK_SCAN_ALL_SLOTS;
189
continue;
190
}
191
192
if (try_scan(&scan_start, "none")) {
193
scanFlags &= ~J9MODRON_GCCHK_SCAN_ALL_SLOTS;
194
continue;
195
}
196
197
/* search for a supported check */
198
for(UDATA i = 0; i < TOTAL_NUM_CHECKS; i++) {
199
if (try_scan(&scan_start, funcArray[i].name)) {
200
scanFlags |= funcArray[i].bitmask;
201
goto top; /* we want to 'break' from the for-loop and 'continue' the while, so a goto is needed */
202
}
203
}
204
205
/* now do the special compound options (that affect more than one check) */
206
if (try_scan(&scan_start, "heap")) {
207
scanFlags |= J9MODRON_GCCHK_SCAN_OBJECT_HEAP | J9MODRON_GCCHK_SCAN_CLASS_HEAP;
208
continue;
209
}
210
211
if (try_scan(&scan_start, "novmthreads")) {
212
scanFlags &= ~J9MODRON_GCCHK_SCAN_VMTHREADS;
213
continue;
214
}
215
216
/* When ':' is encountered, everything that follows is a check option */
217
if (try_scan(&scan_start, ":")) {
218
while (scan_start < scan_limit) {
219
/* ignore separators */
220
try_scan(&scan_start, ",");
221
222
if (try_scan(&scan_start, "all")) {
223
checkFlags |= J9MODRON_GCCHK_VERIFY_ALL;
224
continue;
225
}
226
227
if (try_scan(&scan_start, "none")) {
228
checkFlags &= ~J9MODRON_GCCHK_VERIFY_ALL;
229
continue;
230
}
231
232
if (try_scan(&scan_start, "classslot")) {
233
checkFlags |= J9MODRON_GCCHK_VERIFY_CLASS_SLOT;
234
continue;
235
}
236
237
if (try_scan(&scan_start, "range")) {
238
checkFlags |= J9MODRON_GCCHK_VERIFY_RANGE;
239
continue;
240
}
241
242
if (try_scan(&scan_start, "flags")) {
243
checkFlags |= J9MODRON_GCCHK_VERIFY_FLAGS;
244
continue;
245
}
246
247
/* Another ':' signals the start of misc options */
248
if (try_scan(&scan_start, ":")) {
249
while (scan_start < scan_limit) {
250
/* ignore separators */
251
try_scan(&scan_start, ",");
252
253
if (try_scan(&scan_start, "verbose")) {
254
miscFlags |= J9MODRON_GCCHK_VERBOSE;
255
continue;
256
}
257
258
if (try_scan(&scan_start, "manual")) {
259
miscFlags |= J9MODRON_GCCHK_MANUAL;
260
continue;
261
}
262
263
if (try_scan(&scan_start, "quiet")) {
264
miscFlags &= ~J9MODRON_GCCHK_VERBOSE;
265
miscFlags |= J9MODRON_GCCHK_MISC_QUIET;
266
continue;
267
}
268
269
if (try_scan(&scan_start, "scan")) {
270
miscFlags |= J9MODRON_GCCHK_MISC_SCAN;
271
continue;
272
}
273
274
if (try_scan(&scan_start, "noscan")) {
275
miscFlags &= ~J9MODRON_GCCHK_MISC_SCAN;
276
continue;
277
}
278
279
if (try_scan(&scan_start, "check")) {
280
miscFlags |= J9MODRON_GCCHK_MISC_CHECK;
281
continue;
282
}
283
284
if (try_scan(&scan_start, "nocheck")) {
285
miscFlags &= ~J9MODRON_GCCHK_MISC_CHECK;
286
continue;
287
}
288
289
if (try_scan(&scan_start, "maxerrors=")) {
290
UDATA max;
291
scan_udata(&scan_start, &max);
292
_engine->setMaxErrorsToReport(max);
293
continue;
294
}
295
296
if (try_scan(&scan_start, "darkmatter")) {
297
miscFlags |= J9MODRON_GCCHK_MISC_DARKMATTER;
298
continue;
299
}
300
301
#if defined(J9VM_GC_MODRON_SCAVENGER) || defined(J9VM_GC_VLHGC)
302
if (try_scan(&scan_start, "midscavenge")) {
303
miscFlags |= J9MODRON_GCCHK_MISC_MIDSCAVENGE;
304
continue;
305
}
306
307
if (try_scan(&scan_start, "indexabledataaddress")) {
308
miscFlags |= J9MODRON_GCCHK_VALID_INDEXABLE_DATA_ADDRESS;
309
continue;
310
}
311
#endif /* J9VM_GC_MODRON_SCAVENGER || defined(J9VM_GC_VLHGC) */
312
313
if (try_scan(&scan_start, "abort")) {
314
miscFlags |= J9MODRON_GCCHK_MISC_ABORT;
315
continue;
316
}
317
318
if (try_scan(&scan_start, "noabort")) {
319
miscFlags &= ~J9MODRON_GCCHK_MISC_ABORT;
320
continue;
321
}
322
323
if (try_scan(&scan_start, "dumpstack")) {
324
miscFlags |= J9MODRON_GCCHK_MISC_ALWAYS_DUMP_STACK;
325
continue;
326
}
327
328
if (try_scan(&scan_start, "nodumpstack")) {
329
miscFlags &= ~J9MODRON_GCCHK_MISC_ALWAYS_DUMP_STACK;
330
continue;
331
}
332
333
if (try_scan(&scan_start, "interval=")) {
334
scan_udata(&scan_start, &extensions->gcInterval);
335
miscFlags |= J9MODRON_GCCHK_INTERVAL;
336
continue;
337
}
338
#if defined(J9VM_GC_MODRON_SCAVENGER)
339
if (try_scan(&scan_start, "localinterval=")) {
340
scan_udata(&scan_start, &extensions->localGcInterval);
341
miscFlags |= J9MODRON_GCCHK_LOCAL_INTERVAL;
342
continue;
343
}
344
#endif /* J9VM_GC_MODRON_SCAVENGER */
345
346
if (try_scan(&scan_start, "globalinterval=")) {
347
scan_udata(&scan_start, &extensions->globalGcInterval);
348
miscFlags |= J9MODRON_GCCHK_GLOBAL_INTERVAL;
349
continue;
350
}
351
352
if (try_scan(&scan_start, "startindex=")) {
353
scan_udata(&scan_start, &extensions->gcStartIndex);
354
miscFlags |= J9MODRON_GCCHK_START_INDEX;
355
continue;
356
}
357
358
#if defined(J9VM_GC_MODRON_SCAVENGER)
359
if (try_scan(&scan_start, "scavengerbackout")) {
360
miscFlags |= J9MODRON_GCCHK_SCAVENGER_BACKOUT;
361
continue;
362
}
363
364
if (try_scan(&scan_start, "suppresslocal")) {
365
miscFlags |= J9MODRON_GCCHK_SUPPRESS_LOCAL;
366
continue;
367
}
368
#endif /* J9VM_GC_MODRON_SCAVENGER */
369
370
if (try_scan(&scan_start, "suppressglobal")) {
371
miscFlags |= J9MODRON_GCCHK_SUPPRESS_GLOBAL;
372
continue;
373
}
374
375
#if defined(J9VM_GC_GENERATIONAL)
376
if (try_scan(&scan_start, "rememberedsetoverflow")) {
377
miscFlags |= J9MODRON_GCCHK_REMEMBEREDSET_OVERFLOW;
378
continue;
379
}
380
#endif /* J9VM_GC_GENERATIONAL */
381
/* Nothing matched */
382
goto failure;
383
}
384
/* Reached end */
385
goto done;
386
}
387
/* Nothing matched */
388
goto failure;
389
}
390
/* Reached end */
391
goto done;
392
}
393
394
goto failure;
395
}
396
397
done:
398
/* Set defaults if user did not specify */
399
if (0 == scanFlags) {
400
scanFlags = J9MODRON_GCCHK_SCAN_ALL_SLOTS;
401
}
402
if (0 == checkFlags) {
403
checkFlags = J9MODRON_GCCHK_VERIFY_ALL;
404
}
405
406
generateCheckList(scanFlags);
407
_checkFlags = checkFlags;
408
_miscFlags = miscFlags;
409
410
if (J9MODRON_GCCHK_SCAN_OBJECT_HEAP == (scanFlags & J9MODRON_GCCHK_SCAN_OBJECT_HEAP)) {
411
/* initialize OwnableSynchronizerCount On Object Heap for ownableSynchronizer consistency check */
412
_engine->initializeOwnableSynchronizerCountOnHeap();
413
}
414
if (J9MODRON_GCCHK_SCAN_OWNABLE_SYNCHRONIZER == (scanFlags & J9MODRON_GCCHK_SCAN_OWNABLE_SYNCHRONIZER)) {
415
/* initialize OwnableSynchronizerCount On Lists for ownableSynchronizer consistency check */
416
_engine->initializeOwnableSynchronizerCountOnList();
417
}
418
419
return true;
420
421
failure:
422
/* no match */
423
scan_failed(_portLibrary, "gcchk", scan_start);
424
printHelp(_portLibrary);
425
426
return false;
427
}
428
429
void
430
GC_CheckCycle::run(GCCheckInvokedBy invokedBy, UDATA filterFlags)
431
{
432
_invokedBy = invokedBy;
433
_engine->startCheckCycle(_javaVM, this);
434
435
GC_Check *mover = _checks;
436
while(mover) {
437
/* Use this mover (checker) only if its bitmask set in the filter flags */
438
if (mover->getBitId() == (filterFlags & mover->getBitId())) {
439
bool check = (J9MODRON_GCCHK_MISC_CHECK == (_miscFlags & J9MODRON_GCCHK_MISC_CHECK));
440
bool scan = (J9MODRON_GCCHK_MISC_SCAN == (_miscFlags & J9MODRON_GCCHK_MISC_SCAN));
441
mover->run(check, scan);
442
}
443
mover = mover->getNext();
444
}
445
if (_miscFlags & J9MODRON_GCCHK_MISC_ABORT) {
446
if (_errorCount > 0) {
447
abort();
448
}
449
}
450
_engine->endCheckCycle(_javaVM);
451
}
452
453
/**
454
* Fix up dead objects.
455
*
456
* This routine fixes up any dead objects in the heap so that the checkJ9ObjectPointer()
457
* method can identify dead objects by virtue of the fact that their class
458
* pointer is unaligned, ie low_tagged.
459
*
460
* This is not necessary if the Object Map is available as we can perform the
461
* necessary check by calling the memory manager j9gc_ext_is_liveObject() function
462
*
463
*/
464
void
465
GC_CheckCycle::fixDeadObjects(GCCheckInvokedBy invokedBy)
466
{
467
_invokedBy = invokedBy;
468
GC_FixDeadObjects fixer = GC_FixDeadObjects(_javaVM, _engine);
469
fixer.run(true, false);
470
}
471
472
GC_CheckCycle *
473
GC_CheckCycle::newInstance(J9JavaVM *javaVM, GC_CheckEngine *engine, const char *args, UDATA manualCountInvocation)
474
{
475
MM_Forge *forge = MM_GCExtensions::getExtensions(javaVM)->getForge();
476
477
GC_CheckCycle *checkCycle = (GC_CheckCycle *) forge->allocate(sizeof(GC_CheckCycle), MM_AllocationCategory::DIAGNOSTIC, J9_GET_CALLSITE());
478
if(checkCycle) {
479
new(checkCycle) GC_CheckCycle(javaVM, engine, manualCountInvocation);
480
if (!checkCycle->initialize(args)) {
481
checkCycle = NULL;
482
}
483
}
484
return checkCycle;
485
}
486
487
void
488
GC_CheckCycle::kill()
489
{
490
MM_Forge *forge = MM_GCExtensions::getExtensions(_javaVM)->getForge();
491
492
/* free the list of checks */
493
GC_Check *mover = _checks;
494
while(mover) {
495
mover = mover->getNext();
496
_checks->kill();
497
_checks = mover;
498
}
499
500
/* then this object itself */
501
forge->free(this);
502
}
503
504