Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/jcl/common/jclexception.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 1998, 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
#include "j2sever.h"
24
#include "j9.h"
25
#include "j9cp.h"
26
#include "jclexception.h"
27
#include "jvminit.h"
28
#include "objhelp.h"
29
#include "omrgcconsts.h"
30
#include "rommeth.h"
31
#include "vm_api.h"
32
#include "ut_j9jcl.h"
33
34
#include "VMHelpers.hpp"
35
36
extern "C" {
37
38
#if JAVA_SPEC_VERSION >= 11
39
static void setStackTraceElementFields(J9VMThread *vmThread, j9object_t element, J9ClassLoader *classLoader);
40
#endif /* JAVA_SPEC_VERSION >= 11 */
41
42
static UDATA getStackTraceIterator(J9VMThread * vmThread, void * voidUserData, UDATA bytecodeOffset, J9ROMClass * romClass, J9ROMMethod * romMethod, J9UTF8 * fileName, UDATA lineNumber, J9ClassLoader* classLoader, J9Class* ramClass);
43
44
/**
45
* Saves enough context into the StackTraceElement to allow printing later. For
46
* bootstrap classes we store a java/lang/String, for application classes a
47
* ProtectionDomain.
48
* @param vmThread
49
* @param stackTraceElement The StackTraceElement to update.
50
* @param classLoader The loader in which the ROM class is defined.
51
* @param romClass The ROM class whose path is to be determined.
52
* @return TRUE if the element was updated, FALSE otherwise.
53
* @note Assumes VM access
54
*/
55
static BOOLEAN
56
setStackTraceElementSource(J9VMThread* vmThread, j9object_t stackTraceElement, J9ClassLoader* classLoader, J9ROMClass* romClass)
57
{
58
J9InternalVMFunctions * vmFuncs = vmThread->javaVM->internalVMFunctions;
59
J9UTF8* name = J9ROMCLASS_CLASSNAME(romClass);
60
j9object_t element = stackTraceElement;
61
j9object_t heapClass, protectionDomain;
62
j9object_t string = NULL;
63
U_8 *path = NULL;
64
UDATA pathLen = 0;
65
66
J9Class* clazz = vmFuncs->internalFindClassUTF8(vmThread, J9UTF8_DATA(name), J9UTF8_LENGTH(name), classLoader, J9_FINDCLASS_FLAG_EXISTING_ONLY);
67
if (NULL == clazz) {
68
return FALSE;
69
}
70
71
/* For bootstrap loaders we can consult the classpath entries */
72
path = getClassLocation(vmThread, clazz, &pathLen);
73
if (NULL != path) {
74
PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, element);
75
string = vmThread->javaVM->memoryManagerFunctions->j9gc_createJavaLangString(vmThread, path, pathLen, 0);
76
element = POP_OBJECT_IN_SPECIAL_FRAME(vmThread);
77
if (NULL == string) {
78
/* exception is pending from the call */
79
return FALSE;
80
}
81
J9VMJAVALANGSTACKTRACEELEMENT_SET_SOURCE(vmThread, element, string);
82
return TRUE;
83
}
84
85
/* For application loaders we must consult the protection domain */
86
heapClass = J9VM_J9CLASS_TO_HEAPCLASS(clazz);
87
protectionDomain = J9VMJAVALANGCLASS_PROTECTIONDOMAIN(vmThread, heapClass);
88
J9VMJAVALANGSTACKTRACEELEMENT_SET_SOURCE(vmThread, element, protectionDomain);
89
return TRUE;
90
}
91
92
93
static UDATA
94
getStackTraceIterator(J9VMThread * vmThread, void * voidUserData, UDATA bytecodeOffset, J9ROMClass * romClass, J9ROMMethod * romMethod, J9UTF8 * fileName, UDATA lineNumber, J9ClassLoader* classLoader, J9Class* ramClass)
95
{
96
J9GetStackTraceUserData *userData = (J9GetStackTraceUserData*)voidUserData;
97
J9JavaVM * vm = vmThread->javaVM;
98
J9InternalVMFunctions const * vmFuncs = vm->internalVMFunctions;
99
J9MemoryManagerFunctions const * mmfns = vm->memoryManagerFunctions;
100
j9object_t element = NULL;
101
UDATA rc = TRUE;
102
const I_32 currentIndex = (I_32)userData->index;
103
104
/* If the stack trace is larger than the array, bail */
105
106
if (userData->index == userData->maxFrames) {
107
userData->index += 1; /* Indicate error */
108
return FALSE;
109
}
110
111
/* Prevent the current class from being unloaded during allocation */
112
PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, (NULL == classLoader) ? NULL : classLoader->classLoaderObject);
113
114
/* Create the new StackTraceElement and put it in the array at the correct index */
115
116
element = mmfns->J9AllocateObject(vmThread, userData->elementClass, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
117
if (NULL == element) {
118
rc = FALSE;
119
vmFuncs->setHeapOutOfMemoryError(vmThread);
120
} else {
121
j9array_t result = (j9array_t) PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 1);
122
J9JAVAARRAYOFOBJECT_STORE(vmThread, result, currentIndex, element);
123
userData->index += 1;
124
125
/* If there is a valid method at this frame, fill in the information for it in the StackTraceElement */
126
if (NULL != romMethod) {
127
J9UTF8 const * utfClassName = J9ROMCLASS_CLASSNAME(romClass);
128
j9object_t string = NULL;
129
130
PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, element);
131
132
/* Lookup the J9Class for this method if it can be found as it makes
133
* a number of the remaining operations faster. Code still needs to be
134
* able to handle the case where the J9Class cannot be found
135
*/
136
if (NULL != classLoader) {
137
if (NULL == ramClass) {
138
ramClass = vmFuncs->peekClassHashTable(vmThread, classLoader, J9UTF8_DATA(utfClassName), J9UTF8_LENGTH(utfClassName));
139
}
140
if (NULL != ramClass) {
141
/* ramClass can never be an array here as arrays can't define methods so we don't need to
142
* take them into account in the code below when writing the interned string back to
143
* the Class object.
144
*/
145
Assert_JCL_false(J9CLASS_IS_ARRAY(ramClass));
146
}
147
}
148
149
/* Fill in module name and version */
150
#if JAVA_SPEC_VERSION >= 11
151
if (NULL != classLoader) {
152
j9object_t classLoaderName = J9VMJAVALANGCLASSLOADER_CLASSLOADERNAME(vmThread, classLoader->classLoaderObject);
153
J9VMJAVALANGSTACKTRACEELEMENT_SET_CLASSLOADERNAME(vmThread, element, classLoaderName);
154
}
155
if (J9_ARE_NO_BITS_SET(vm->runtimeFlags, J9_RUNTIME_JAVA_BASE_MODULE_CREATED)) {
156
string = mmfns->j9gc_createJavaLangString(vmThread, (U_8 *)JAVA_BASE_MODULE, LITERAL_STRLEN(JAVA_BASE_MODULE), J9_STR_XLAT | J9_STR_TENURE);
157
if (NULL == string) {
158
rc = FALSE;
159
/* exception is pending from the call */
160
goto done;
161
}
162
element = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0);
163
J9VMJAVALANGSTACKTRACEELEMENT_SET_MODULENAME(vmThread, element, string);
164
165
string = mmfns->j9gc_createJavaLangString(vmThread, (U_8 *)JAVA_SPEC_VERSION_STRING, LITERAL_STRLEN(JAVA_SPEC_VERSION_STRING), J9_STR_XLAT | J9_STR_TENURE);
166
if (NULL == string) {
167
rc = FALSE;
168
/* exception is pending from the call */
169
goto done;
170
}
171
element = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0);
172
J9VMJAVALANGSTACKTRACEELEMENT_SET_MODULEVERSION(vmThread, element, string);
173
} else {
174
/* Fetch the J9Module from the j.l.Class->j.l.Module field if we have a class.
175
* Otherwise the more painful package-based lookup must be performed
176
*/
177
J9Module *module = NULL;
178
if (NULL != ramClass) {
179
j9object_t moduleObject = J9VMJAVALANGCLASS_MODULE(vmThread, ramClass->classObject);
180
module = (J9Module*)J9OBJECT_ADDRESS_LOAD(vmThread, moduleObject, vm->modulePointerOffset);
181
} else {
182
UDATA length = packageNameLength(romClass);
183
omrthread_monitor_enter(vm->classLoaderModuleAndLocationMutex);
184
module = vmFuncs->findModuleForPackage(vmThread, classLoader, J9UTF8_DATA(utfClassName), (U_32) length);
185
omrthread_monitor_exit(vm->classLoaderModuleAndLocationMutex);
186
}
187
if (NULL != module) {
188
J9VMJAVALANGSTACKTRACEELEMENT_SET_MODULENAME(vmThread, element, module->moduleName);
189
J9VMJAVALANGSTACKTRACEELEMENT_SET_MODULEVERSION(vmThread, element, module->version);
190
}
191
}
192
setStackTraceElementFields(vmThread, element, classLoader);
193
#endif /* JAVA_SPEC_VERSION >= 11 */
194
195
if (NULL != ramClass) {
196
/* Fill in method class */
197
string = VM_VMHelpers::getClassNameString(vmThread, J9VM_J9CLASS_TO_HEAPCLASS(ramClass), JNI_TRUE);
198
if (NULL == string) {
199
rc = FALSE;
200
/* exception is pending from the call */
201
goto done;
202
}
203
} else {
204
/* Can't peek all classes. Ie. anon/hidden classes or cases where classloader is NULL */
205
UDATA flags = J9_STR_XLAT | J9_STR_INTERN;
206
207
if (J9ROMCLASS_IS_ANON_OR_HIDDEN(romClass)) {
208
flags |= J9_STR_ANON_CLASS_NAME;
209
}
210
string = mmfns->j9gc_createJavaLangString(vmThread, J9UTF8_DATA(utfClassName), J9UTF8_LENGTH(utfClassName), flags);
211
}
212
element = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0);
213
J9VMJAVALANGSTACKTRACEELEMENT_SET_DECLARINGCLASS(vmThread, element, string);
214
215
/* Fill in method name */
216
string = mmfns->j9gc_createJavaLangStringWithUTFCache(vmThread, J9ROMMETHOD_NAME(romMethod));
217
if (NULL == string) {
218
rc = FALSE;
219
/* exception is pending from the call */
220
goto done;
221
}
222
element = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0);
223
J9VMJAVALANGSTACKTRACEELEMENT_SET_METHODNAME(vmThread, element, string);
224
225
/* Fill in file name, if any.
226
* Attempt to reuse the cached string if it is available. It may be found
227
* either in the Class object if it's be previous cached, or it may be found
228
* in the StackTraceElement[] if the previous filename is the same.
229
*
230
* The previous filename cache covers the case where multiple classes were
231
* defined in the same file.
232
*
233
* This avoids additional allocations during stack trace generation
234
*/
235
string = NULL;
236
if (NULL != ramClass) {
237
string = J9VMJAVALANGCLASS_FILENAMESTRING(vmThread, J9VM_J9CLASS_TO_HEAPCLASS(ramClass));
238
}
239
if ((NULL == string) && (NULL != fileName)) {
240
J9UTF8 *previousFileName = userData->previousFileName;
241
/* Use an == comparison here as the previousFileName may have been from
242
* a classloader that was unloaded. We can safely do an == comparison
243
* as we know the current class is deeper in the stack and can't have
244
* incorrectly been loaded into the space the previous loader was removed
245
* from. We can't do a string compare here but the == should be sufficient
246
* provided the utf8 interning is hitting on common strings.
247
*/
248
if (previousFileName == fileName) {
249
j9array_t result = (j9array_t) PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 2);
250
element = J9JAVAARRAYOFOBJECT_LOAD(vmThread, result, currentIndex - 1);
251
string = J9VMJAVALANGSTACKTRACEELEMENT_FILENAME(vmThread, element);
252
} else {
253
string = mmfns->j9gc_createJavaLangString(vmThread, J9UTF8_DATA(fileName), (U_32) J9UTF8_LENGTH(fileName), J9_STR_TENURE);
254
if (NULL == string) {
255
rc = FALSE;
256
/* exception is pending from the call */
257
goto done;
258
}
259
}
260
Assert_JCL_notNull(string);
261
if (NULL != ramClass) {
262
/* Update the cached fileNameString on the class so subsequent calls will find it */
263
J9VMJAVALANGCLASS_SET_FILENAMESTRING(vmThread, J9VM_J9CLASS_TO_HEAPCLASS(ramClass), string);
264
}
265
}
266
/* Update previous filename as it must always match the contents of the StackTraceElement[n-1]'s
267
* value. This means it must be null if the previous filename was null or we'll copy the wrong
268
* name into the StackTraceElement
269
*/
270
userData->previousFileName = fileName;
271
if (NULL != string) {
272
element = PEEK_OBJECT_IN_SPECIAL_FRAME(vmThread, 0);
273
J9VMJAVALANGSTACKTRACEELEMENT_SET_FILENAME(vmThread, element, string);
274
}
275
276
/* Fill in line number - Java wants -2 for natives, -1 for no line number (which will be 0 coming in from the iterator) */
277
if (J9_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccNative)) {
278
lineNumber = -2;
279
} else if (0 == lineNumber) {
280
lineNumber = -1;
281
}
282
J9VMJAVALANGSTACKTRACEELEMENT_SET_LINENUMBER(vmThread, element, (I_32) lineNumber);
283
284
if (J9_ARE_ANY_BITS_SET(vm->verboseLevel, VERBOSE_STACKTRACE)) {
285
setStackTraceElementSource(vmThread, element, classLoader, romClass);
286
}
287
288
done:
289
DROP_OBJECT_IN_SPECIAL_FRAME(vmThread);
290
} else {
291
/* Update previous filename as it must always match the contents of the StackTraceElement[n-1]'s
292
* value. This means it must be null if the previous filename was null or we'll copy the wrong
293
* name into the StackTraceElement. As we didn't have a ROMMethod here, nothing to fill in / process
294
* and so we reset the previousFileName.
295
*/
296
userData->previousFileName = NULL;
297
}
298
}
299
DROP_OBJECT_IN_SPECIAL_FRAME(vmThread);
300
301
return rc;
302
}
303
304
J9IndexableObject *
305
getStackTrace(J9VMThread * vmThread, j9object_t * exceptionAddr, UDATA pruneConstructors)
306
{
307
J9JavaVM * vm = vmThread->javaVM;
308
J9InternalVMFunctions * vmFuncs = vm->internalVMFunctions;
309
J9MemoryManagerFunctions * mmfns = vm->memoryManagerFunctions;
310
UDATA numberOfFrames;
311
J9Class * elementClass;
312
J9Class * arrayClass;
313
J9GetStackTraceUserData userData;
314
J9IndexableObject * result;
315
316
/* Note that exceptionAddr might be a pointer into the current thread's stack, so no java code is allowed to run
317
(nothing which could cause the stack to grow).
318
*/
319
320
retry:
321
322
/* Get the total number of entries in the trace */
323
324
numberOfFrames = vmFuncs->iterateStackTrace(vmThread, exceptionAddr, NULL, NULL, pruneConstructors);
325
326
/* Create the result array */
327
328
elementClass = J9VMJAVALANGSTACKTRACEELEMENT_OR_NULL(vm);
329
arrayClass = elementClass->arrayClass;
330
if (arrayClass == NULL) {
331
/* the first class in vm->arrayROMClasses is the array class for Objects */
332
arrayClass = vmFuncs->internalCreateArrayClass(vmThread,
333
(J9ROMArrayClass *) J9ROMIMAGEHEADER_FIRSTCLASS(vm->arrayROMClasses),
334
elementClass);
335
if (arrayClass == NULL) {
336
/* exception is pending from the call */
337
return NULL;
338
}
339
}
340
result = (j9array_t) mmfns->J9AllocateIndexableObject(
341
vmThread, arrayClass, (U_32)numberOfFrames, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
342
if (result == NULL) {
343
vmFuncs->setHeapOutOfMemoryError(vmThread);
344
return NULL;
345
}
346
347
/* Fill in the stack trace */
348
349
userData.elementClass = elementClass;
350
userData.index = 0;
351
userData.maxFrames = numberOfFrames;
352
userData.previousFileName = NULL;
353
PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, (j9object_t) result);
354
vmFuncs->iterateStackTrace(vmThread, exceptionAddr, getStackTraceIterator, &userData, pruneConstructors);
355
result = (j9array_t) POP_OBJECT_IN_SPECIAL_FRAME(vmThread);
356
357
/* If the stack trace sizes are inconsistent between pass 1 and 2, start again */
358
359
if (vmThread->currentException == NULL) {
360
if (userData.index != numberOfFrames) {
361
goto retry;
362
}
363
}
364
365
/* Return the result - any pending exception will be checked by the caller and the result discarded */
366
367
return result;
368
}
369
370
#if JAVA_SPEC_VERSION >= 11
371
/**
372
* Set the includeClassLoaderName and includeModuleVersion fields for a StackTraceElement.
373
*
374
* @param vmThread The VM thread.
375
* @param element The element to set fields for.
376
* @param classLoader The classloader to check.
377
*/
378
static void
379
setStackTraceElementFields(J9VMThread *vmThread, j9object_t element, J9ClassLoader *classLoader) {
380
J9JavaVM *vm = vmThread->javaVM;
381
BOOLEAN includeClassLoaderName = TRUE;
382
BOOLEAN includeModuleVersion = TRUE;
383
384
/**
385
* If the classloader is one of the Platform or Bootstrap built-in classloaders,
386
* don't include its name or module version in the stack trace. If it is the
387
* Application/System built-in classloader, don't include the class name, but
388
* include the module version.
389
*/
390
if ((NULL == classLoader)
391
|| (vm->extensionClassLoader == classLoader) // JRE: Platform ClassLoader
392
|| (vm->systemClassLoader == classLoader) // JRE: Bootstrap ClassLoader
393
) {
394
includeClassLoaderName = FALSE;
395
includeModuleVersion = FALSE;
396
} else if (vm->applicationClassLoader == classLoader) { // JRE: System ClassLoader
397
includeClassLoaderName = FALSE;
398
}
399
400
J9VMJAVALANGSTACKTRACEELEMENT_SET_INCLUDECLASSLOADERNAME(vmThread, element, (U_32) includeClassLoaderName);
401
J9VMJAVALANGSTACKTRACEELEMENT_SET_INCLUDEMODULEVERSION(vmThread, element, (U_32) includeModuleVersion);
402
}
403
#endif /* JAVA_SPEC_VERSION >= 11 */
404
405
} /* extern "C" */
406
407