Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/gc_check/CheckReporterTTY.cpp
5985 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
/**
24
* @file
25
* @ingroup GC_Check
26
*/
27
28
#include "CheckReporterTTY.hpp"
29
30
#include "Base.hpp"
31
#include "Check.hpp"
32
#include "CheckBase.hpp"
33
#include "CheckError.hpp"
34
#include "ObjectModel.hpp"
35
36
/**
37
* Human readable strings representing the invokee defined by #GCCheckInvokedBy.
38
*/
39
const static char *invokedByStrings[] = {
40
"unknown", /**<undefined */
41
"before global GC", /**<J9HOOK_GLOBAL_GC_START */
42
"after global GC", /**<J9HOOK_GLOBAL_GC_END */
43
"before global GC sweep", /**<J9HOOK_GLOBAL_GC_SWEEP_START */
44
"after global GC sweep", /**<J9HOOK_GLOBAL_GC_SWEEP_END */
45
"before local GC", /**<J9HOOK_LOCAL_GC_START */
46
"after local GC", /**<J9HOOK_LOCAL_GC_END */
47
"scavenger backout", /**<J9HOOK_SCAVENGER_BACK_OUT (J9HOOK_LOCAL_GC_END) */
48
"remembered set overflow", /**<J9HOOK_REMEMBEREDSET_OVERFLOW */
49
"manual invocation", /**< J9HOOK_INVOKE_GC_CHECK */
50
"from debugger" /**< via debugger extensions */
51
};
52
53
/**
54
* Human readable error strings corresponding to
55
* @ref GCCheckWalkStageErrorCodes from the various walk stages.
56
* Offset into this table is determined by error code returned by methods such as GC_Check::checkJ9ObjectPointer
57
*/
58
const static char *errorTypes[] = {
59
"no error", /* J9MODRON_GCCHK_RC_OK (0) */
60
"not aligned", /* J9MODRON_GCCHK_RC_UNALIGNED (1) */
61
"double array not aligned", /* J9MODRON_GCCHK_RC_DOUBLE_ARRAY_UNALIGNED (2) */
62
"object not in an object region", /* J9MODRON_GCCHK_RC_NOT_IN_OBJECT_REGION (3) */
63
"not in an object segment", /* J9MODRON_GCCHK_RC_NOT_FOUND (4) */
64
"overlaps segment boundary", /* J9MODRON_GCCHK_RC_INVALID_RANGE (5) */
65
"heap object on stack", /* J9MODRON_GCCHK_RC_STACK_OBJECT (6) */
66
"class pointer is null", /* J9MODRON_GCCHK_RC_NULL_CLASS_POINTER (7)*/
67
"class pointer not aligned", /* J9MODRON_GCCHK_RC_CLASS_POINTER_UNALIGNED (8)*/
68
"class pointer not in a class segment", /* J9MODRON_GCCHK_RC_CLASS_NOT_FOUND (9)*/
69
"class pointer overlaps segment boundary", /* J9MODRON_GCCHK_RC_CLASS_INVALID_RANGE (10) */
70
"class pointer of class is not java.lang.Class", /* J9MODRON_GCCHK_RC_CLASS_POINTER_NOT_JLCLASS (11) */
71
"class pointer on stack", /* J9MODRON_GCCHK_RC_CLASS_STACK_OBJECT (12) */
72
"invalid flags", /* J9MODRON_GCCHK_RC_INVALID_FLAGS (13) */
73
"in an old segment, old bit not set", /* J9MODRON_GCCHK_RC_OLD_SEGMENT_INVALID_FLAGS (14) */
74
"in a new segment, old or remembered bit set", /* J9MODRON_GCCHK_RC_NEW_SEGMENT_INVALID_FLAGS (15) */
75
"size of hole is too large or 0", /* J9MODRON_GCCHK_RC_DEAD_OBJECT_SIZE (16) */
76
"new pointer in old object without remembered bit set", /* J9MODRON_GCCHK_RC_NEW_POINTER_NOT_REMEMBERED (17) */
77
"not in an old segment or class segment", /* J9MODRON_GCCHK_RC_REMEMBERED_SET_WRONG_SEGMENT (18) */
78
"old bit or remembered bit not set", /* J9MODRON_GCCHK_RC_REMEMBERED_SET_FLAGS (19) */
79
"not in remembered set, new object reference", /* J9MODRON_GCCHK_RC_REMEMBERED_SET_OLD_OBJECT (20) */
80
"unused 21", /* J9MODRON_GCCHK_RC_UNUSED_21 (21) */
81
"unused 22", /* J9MODRON_GCCHK_RC_UNUSED_22 (22) */
82
"heap object has remembered bit set when cardtable active", /* J9MODRON_GCCHK_RC_HEAP_OBJECT_REMEMBERED (23) */
83
"new pointer in old object without card dirtied", /* J9MODRON_GCCHK_RC_NEW_POINTER_NOT_REMEMBERED_IN_CARD_TABLE (24) */
84
"dead object", /* J9MODRON_GCCHK_RC_DEAD_OBJECT (25) */
85
"class header invalid", /* J9MODRON_GCCHK_RC_J9CLASS_HEADER_INVALID (26) */
86
"class object not java.lang.Class", /* J9MODRON_GCCHK_RC_CLASS_OBJECT_NOT_JLCLASS (27) */
87
"scope internal pointer refers outside its scope", /* J9MODRON_GCCHK_RC_INTERNAL_POINTER_NOT_IN_SCOPE (28) */
88
"class pointer is in an undead class segment", /* J9MODRON_GCCHK_RC_CLASS_IS_UNDEAD (29) */
89
"class ramStatics field points to wrong object", /* J9MODRON_GCCHK_RC_CLASS_STATICS_FIELD_POINTS_WRONG_OBJECT (30) */
90
"class ramStatics must be NULL for hot swapped class", /* J9MODRON_GCCHK_RC_CLASS_HOT_SWAPPED_POINTS_TO_STATICS (31) */
91
"class ramStatics field points to object but out of GC scan range", /* J9MODRON_GCCHK_RC_CLASS_STATICS_REFERENCE_IS_NOT_IN_SCANNING_RANGE (32) */
92
"class ramStatics number of references not equal specified in ROM class", /* J9MODRON_GCCHK_RC_CLASS_STATICS_WRONG_NUMBER_OF_REFERENCES (33) */
93
"invalid indexable data address", /* J9MODRON_GCCHK_RC_INVALID_INDEXABLE_DATA_ADDRESS (34) */
94
"obsolete code 35", /* obsolete code (35) */
95
"obsolete code 36", /* obsolete code (36) */
96
"obsolete code 37", /* obsolete code (37) */
97
"class object not a subclass of java.util.concurrent.locks.AbstractOwnableSynchronizer", /* J9MODRON_GCCHK_RC_OWNABLE_SYNCHRONIZER_INVALID_CLASS (38) */
98
"array class can not be hot swapped", /* J9MODRON_GCCHK_RC_CLASS_HOT_SWAPPED_FOR_ARRAY (39) */
99
"replaced class has no hot swapped out flag set", /* J9MODRON_GCCHK_RC_REPLACED_CLASS_HAS_NO_HOTSWAP_FLAG (40) */
100
"object slot appears to contain a J9Class pointer", /* J9MODRON_GCCHK_RC_OBJECT_SLOT_POINTS_TO_J9CLASS (41) */
101
"Ownable Synchronizer Object is not attached to the list", /* J9MODRON_GCCHK_OWNABLE_SYNCHRONIZER_OBJECT_IS_NOT_ATTACHED_TO_THE_LIST (42) */
102
"Ownable Synchronizer List has a circular reference", /* J9MODRON_GCCHK_OWNABLE_SYNCHRONIZER_LIST_HAS_CIRCULAR_REFERENCE (43) */
103
"hole size is not aligned", /* J9MODRON_GCCHK_RC_DEAD_OBJECT_SIZE_NOT_ALIGNED (44) */
104
"hole next is not a hole", /* J9MODRON_GCCHK_RC_DEAD_OBJECT_NEXT_IS_NOT_HOLE (45) */
105
"hole next is outside of current region", /* J9MODRON_GCCHK_RC_DEAD_OBJECT_NEXT_IS_NOT_IN_REGION (46) */
106
"hole next is pointed inside of the hole", /* J9MODRON_GCCHK_RC_DEAD_OBJECT_NEXT_IS_POINTED_INSIDE (47) */
107
"class is unloaded", /* J9MODRON_GCCHK_RC_CLASS_IS_UNLOADED (48)*/
108
};
109
110
/**
111
* Create a new instance of the report object, using the specified port library.
112
*/
113
GC_CheckReporterTTY *
114
GC_CheckReporterTTY::newInstance(J9JavaVM *javaVM)
115
{
116
MM_Forge *forge = MM_GCExtensions::getExtensions(javaVM)->getForge();
117
118
GC_CheckReporterTTY *reporter = (GC_CheckReporterTTY *)forge->allocate(sizeof(GC_CheckReporterTTY), MM_AllocationCategory::DIAGNOSTIC, J9_GET_CALLSITE());
119
if (reporter) {
120
reporter = new(reporter) GC_CheckReporterTTY(javaVM);
121
}
122
return reporter;
123
}
124
125
/**
126
* Destroy the instance of the reporter.
127
*/
128
void
129
GC_CheckReporterTTY::kill()
130
{
131
MM_Forge *forge = MM_GCExtensions::getExtensions(_javaVM)->getForge();
132
forge->free(this);
133
}
134
135
/**
136
* Report an error to the terminal.
137
*
138
* Accepts an error object and outputs a report to the terminal.
139
* @param error The error to be reported
140
*/
141
void
142
GC_CheckReporterTTY::report(GC_CheckError *error)
143
{
144
PORT_ACCESS_FROM_PORT(_portLibrary);
145
146
if (!shouldReport(error)) {
147
return;
148
}
149
150
/* If slot is NULL, we are not scanning the slots of an object, but looking directly at an object/class on the heap. */
151
if (error->_slot) {
152
const void *slot = error->_slot;
153
UDATA slotValue;
154
155
if (error->_objectType == check_type_object) {
156
GC_SlotObject slotObj(_javaVM->omrVM, (fomrobject_t*)slot);
157
slotValue = (UDATA)slotObj.readReferenceFromSlot();
158
} else {
159
if (error->_objectType == check_type_thread) {
160
/* slots from thread stacks are always local */
161
slotValue = *((UDATA*)slot);
162
slot = error->_stackLocaition;
163
} else if(error->_objectType == check_type_unfinalized) {
164
slotValue = *((UDATA*)slot);
165
} else if(error->_objectType == check_type_finalizable) {
166
slotValue = *((UDATA*)slot);
167
} else if(error->_objectType == check_type_ownable_synchronizer) {
168
slotValue = *((UDATA*)slot);
169
} else {
170
slotValue = *((UDATA*)slot);
171
}
172
}
173
174
if (invocation_manual == error->_cycle->getInvoker()) {
175
j9tty_printf(PORTLIB, " <gc check (%zu): %s (%zu): %s: %sslot %p(%p) -> %p: %s>\n", error->_errorNumber, invokedByStrings[error->_cycle->getInvoker()], error->_cycle->getManualCheckNumber(), error->_check->getCheckName(), error->_elementName, error->_object, slot, slotValue, errorTypes[error->_errorCode]);
176
} else {
177
j9tty_printf(PORTLIB, " <gc check (%zu): %s: %s: %sslot %p(%p) -> %p: %s>\n", error->_errorNumber, invokedByStrings[error->_cycle->getInvoker()], error->_check->getCheckName(), error->_elementName, error->_object, slot, slotValue, errorTypes[error->_errorCode]);
178
}
179
} else {
180
if (invocation_manual == error->_cycle->getInvoker()) {
181
j9tty_printf(PORTLIB, " <gc check (%zu): %s (%zu): %s: %s%p: %s>\n", error->_errorNumber, invokedByStrings[error->_cycle->getInvoker()], error->_cycle->getManualCheckNumber(), error->_check->getCheckName(), error->_elementName, error->_object, errorTypes[error->_errorCode]);
182
} else {
183
j9tty_printf(PORTLIB, " <gc check (%zu): %s: %s: %s%p: %s>\n", error->_errorNumber, invokedByStrings[error->_cycle->getInvoker()], error->_check->getCheckName(), error->_elementName, error->_object, errorTypes[error->_errorCode]);
184
}
185
186
/* If the basic checks have been made (alignment, etc.) display header info. */
187
if (error->_objectType == check_type_object) {
188
reportObjectHeader(error, (J9Object*)error->_object, "");
189
}
190
}
191
}
192
193
/**
194
* Print an object header to the terminal.
195
*
196
* @param objectPtr the object whose header to print
197
* @param prefix a string to prefix the object with, e.g. "Previous", or NULL
198
* if no prefix is desired
199
*/
200
void
201
GC_CheckReporterTTY::reportObjectHeader(GC_CheckError *error, J9Object *objectPtr, const char *prefix)
202
{
203
MM_GCExtensionsBase* extensions = MM_GCExtensions::getExtensions(_javaVM);
204
const char *prefixString = prefix ? prefix : "";
205
UDATA headerSize = 0;
206
PORT_ACCESS_FROM_PORT(_portLibrary);
207
208
if (!shouldReport(error)) {
209
return;
210
}
211
212
if (extensions->objectModel.isDeadObject(objectPtr)) {
213
j9tty_printf(PORTLIB, " <gc check (%zu): %sHole %p header:", error->_errorNumber, prefixString, objectPtr);
214
headerSize = (UDATA)sizeof(MM_HeapLinkedFreeHeader);
215
} else {
216
const char *elementName = (UDATA) extensions->objectModel.isIndexable(objectPtr) ? "IObject" : "Object";
217
j9tty_printf(PORTLIB, " <gc check (%zu): %s%s %p header:", error->_errorNumber, prefixString, elementName, objectPtr);
218
headerSize = extensions->objectModel.getHeaderSize(objectPtr);
219
}
220
221
U_32* cursor = (U_32*) objectPtr;
222
for (UDATA i = 0; i < headerSize / sizeof(U_32); i++) {
223
j9tty_printf(PORTLIB, " %08X", *cursor);
224
cursor++;
225
}
226
227
j9tty_printf(PORTLIB, ">\n");
228
}
229
230
/**
231
* Print a class to the terminal.
232
*
233
* @param clazz the class to print
234
* @param prefix a string to prefix the class with, e.g. "Previous", or NULL
235
* if no prefix is desired
236
*/
237
void
238
GC_CheckReporterTTY::reportClass(GC_CheckError *error, J9Class *clazz, const char *prefix)
239
{
240
const char *prefixString = prefix ? prefix : "";
241
PORT_ACCESS_FROM_PORT(_portLibrary);
242
243
if (!shouldReport(error)) {
244
return;
245
}
246
247
j9tty_printf(PORTLIB, " <gc check (%zu): %sClass %p>\n",
248
error->_errorNumber,
249
prefixString,
250
clazz);
251
}
252
253
/**
254
* Report the fact that a fatal error has occurred.
255
*/
256
void
257
GC_CheckReporterTTY::reportFatalError(GC_CheckError *error)
258
{
259
PORT_ACCESS_FROM_PORT(_portLibrary);
260
261
j9tty_printf(PORTLIB, " <gc check (%zu): Cannot resolve problem detected on heap, aborting check>\n", error->_errorNumber);
262
}
263
264
/**
265
* Print to the terminal that an error has occurred while walking the heap.
266
*/
267
void
268
GC_CheckReporterTTY::reportHeapWalkError(GC_CheckError *error, GC_CheckElement previousObjectPtr1, GC_CheckElement previousObjectPtr2, GC_CheckElement previousObjectPtr3)
269
{
270
PORT_ACCESS_FROM_PORT(_portLibrary);
271
272
reportFatalError(error);
273
if (previousObjectPtr1.type != GC_CheckElement::type_none) {
274
reportGenericType(error, previousObjectPtr1, "Previous ");
275
if(previousObjectPtr2.type != GC_CheckElement::type_none) {
276
reportGenericType(error, previousObjectPtr2, "Previous ");
277
if(previousObjectPtr3.type != GC_CheckElement::type_none) {
278
reportGenericType(error, previousObjectPtr3, "Previous ");
279
}
280
}
281
} else {
282
j9tty_printf(PORTLIB, " <gc check (%zu): %p was first object encountered on heap>\n", error->_errorNumber, error->_object);
283
}
284
}
285
286
287