Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/control/JitDump.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2020, 2022 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 "control/JitDump.hpp"
24
25
#include "codegen/CodeGenerator.hpp"
26
#include "env/VMJ9.h"
27
#include "control/MethodToBeCompiled.hpp"
28
#include "control/CompilationRuntime.hpp"
29
#include "control/CompilationThread.hpp"
30
#include "env/ut_j9jit.h"
31
#include "env/VMAccessCriticalSection.hpp"
32
#include "ilgen/J9ByteCodeIlGenerator.hpp"
33
#include "nls/j9dmpnls.h"
34
#if defined(J9VM_OPT_JITSERVER)
35
#include "control/JITServerCompilationThread.hpp"
36
#include "control/JITServerHelpers.hpp"
37
#include "runtime/JITServerAOTCache.hpp"
38
#include "runtime/JITServerAOTDeserializer.hpp"
39
#include "runtime/JITServerIProfiler.hpp"
40
#include "runtime/JITServerStatisticsThread.hpp"
41
#include "runtime/Listener.hpp"
42
#if defined(LINUX)
43
#include <malloc.h> // for malloc_stats() (Linux glibc only)
44
#endif /* defined(LINUX) */
45
#endif /* defined(J9VM_OPT_JITSERVER) */
46
47
48
struct ILOfCrashedThreadParamenters
49
{
50
ILOfCrashedThreadParamenters(J9VMThread *vmThread, TR::Compilation *comp, TR::FILE *jitdumpFile)
51
: vmThread(vmThread), comp(comp), jitdumpFile(jitdumpFile)
52
{}
53
54
/// The JVM thread backing the crashed thread
55
J9VMThread *vmThread;
56
57
/// The compilation object extracted from the crashed thread
58
TR::Compilation *comp;
59
60
/// The jitdump file to trace the IL of the crashed thread to
61
TR::FILE *jitdumpFile;
62
};
63
64
static uintptr_t
65
traceILOfCrashedThreadProtected(struct J9PortLibrary *portLib, void *handler_arg)
66
{
67
auto p = *static_cast<ILOfCrashedThreadParamenters*>(handler_arg);
68
69
TR_J9ByteCodeIlGenerator bci(p.comp->ilGenRequest().details(), p.comp->getMethodSymbol(),
70
TR_J9VMBase::get(p.vmThread->javaVM->jitConfig, p.vmThread), p.comp, p.comp->getSymRefTab());
71
bci.printByteCodes();
72
73
// This call will reset the previously recorded symbol reference size to 0, thus indicating to the debug object that
74
// we should print all the symbol references in the symbol reference table when tracing the trees. By default the
75
// debug object will only print new symbol references since the last time they were printed. Here we are in a
76
// crashed thread state so we can safely reset this coutner so we print all the symbol references.
77
p.comp->setPrevSymRefTabSize(0);
78
p.comp->dumpMethodTrees("Trees");
79
80
if ((p.vmThread->omrVMThread->vmState & J9VMSTATE_JIT_CODEGEN) == J9VMSTATE_JIT_CODEGEN)
81
{
82
TR_Debug *debug = p.comp->getDebug();
83
debug->dumpMethodInstrs(p.jitdumpFile, "Post Binary Instructions", false, true);
84
debug->print(p.jitdumpFile, p.comp->cg()->getSnippetList());
85
debug->dumpMixedModeDisassembly();
86
}
87
else if ((p.vmThread->omrVMThread->vmState & J9VMSTATE_JIT_OPTIMIZER) == J9VMSTATE_JIT_OPTIMIZER)
88
{
89
// Tree verification is only valid during optimizations as it relies on consistent node counts which are only
90
// valid before codegen, since the codegen will decrement the node counts as part of instruction selection
91
p.comp->verifyTrees();
92
p.comp->verifyBlocks();
93
}
94
95
return 0;
96
}
97
98
static void
99
traceILOfCrashedThread(J9VMThread *vmThread, TR::Compilation *comp, TR::FILE *jitdumpFile)
100
{
101
PORT_ACCESS_FROM_VMC(vmThread);
102
j9nls_printf(PORTLIB, J9NLS_INFO | J9NLS_STDERR, J9NLS_DMP_JIT_TRACE_IL_CRASHED_THREAD);
103
104
bool alreadyHaveVMAccess = ((vmThread->publicFlags & J9_PUBLIC_FLAGS_VM_ACCESS) != 0);
105
bool haveAcquiredVMAccess = false;
106
if (!alreadyHaveVMAccess)
107
{
108
if (0 == vmThread->javaVM->internalVMFunctions->internalTryAcquireVMAccessWithMask(vmThread, J9_PUBLIC_FLAGS_HALT_THREAD_ANY_NO_JAVA_SUSPEND))
109
{
110
haveAcquiredVMAccess = true;
111
}
112
}
113
114
comp->setOutFile(jitdumpFile);
115
116
TR_Debug *debug = comp->findOrCreateDebug();
117
debug->setFile(jitdumpFile);
118
119
TR::Options *options = comp->getOptions();
120
options->setOption(TR_TraceAll);
121
options->setOption(TR_TraceKnownObjectGraph);
122
123
trfprintf(jitdumpFile, "<ilOfCrashedThread>\n");
124
125
ILOfCrashedThreadParamenters p(vmThread, comp, jitdumpFile);
126
127
U_32 flags = J9PORT_SIG_FLAG_MAY_RETURN |
128
J9PORT_SIG_FLAG_SIGSEGV | J9PORT_SIG_FLAG_SIGFPE |
129
J9PORT_SIG_FLAG_SIGILL | J9PORT_SIG_FLAG_SIGBUS | J9PORT_SIG_FLAG_SIGTRAP;
130
131
uintptr_t result = 0;
132
j9sig_protect(traceILOfCrashedThreadProtected, static_cast<void *>(&p),
133
jitDumpSignalHandler,
134
vmThread, flags, &result);
135
136
trfprintf(jitdumpFile, "</ilOfCrashedThread>\n");
137
138
if (!alreadyHaveVMAccess && haveAcquiredVMAccess)
139
{
140
vmThread->javaVM->internalVMFunctions->internalReleaseVMAccess(vmThread);
141
}
142
}
143
144
static void
145
jitDumpRecompileWithTracing(J9VMThread *vmThread, J9Method *ramMethod, TR::CompilationInfo *compInfo, TR_Hotness optLevel, bool isProfilingCompile, TR::Options *optionsFromOriginalCompile, bool isAOTBody, void *oldStartPC, TR::FILE *jitdumpFile)
146
{
147
PORT_ACCESS_FROM_VMC(vmThread);
148
J9Class *clazz;
149
J9ROMMethod *romMethod;
150
J9UTF8 *methName, *methSig, *className;
151
#if defined(J9VM_OPT_JITSERVER)
152
if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER)
153
{
154
TR_J9VMBase *fej9 = reinterpret_cast<TR_J9VMBase *>(TR_J9VMBase::get(compInfo->getJITConfig(), vmThread, TR_J9VMBase::J9_SERVER_VM));
155
if (!fej9->vmThreadIsCompilationThread())
156
{
157
trfprintf(jitdumpFile, "JitDump for a non-compilation thread on JITServer is not supported.\n");
158
return;
159
}
160
161
clazz = reinterpret_cast<J9Class *>(fej9->getClassOfMethod(reinterpret_cast<TR_OpaqueMethodBlock *>(ramMethod)));
162
romMethod = JITServerHelpers::romMethodOfRamMethod(ramMethod);
163
methName = J9ROMMETHOD_NAME(romMethod);
164
methSig = J9ROMMETHOD_SIGNATURE(romMethod);
165
className = J9ROMCLASS_CLASSNAME(TR::Compiler->cls.romClassOf(reinterpret_cast<TR_OpaqueClassBlock *>(clazz)));
166
}
167
else
168
#endif
169
{
170
clazz = J9_CLASS_FROM_METHOD(ramMethod);
171
romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(ramMethod);
172
methName = J9ROMMETHOD_NAME(romMethod);
173
methSig = J9ROMMETHOD_SIGNATURE(romMethod);
174
className = J9ROMCLASS_CLASSNAME(clazz->romClass);
175
}
176
177
j9nls_printf(PORTLIB, J9NLS_INFO | J9NLS_STDERR, J9NLS_DMP_JIT_RECOMPILING_METHOD,
178
(UDATA)J9UTF8_LENGTH(className), J9UTF8_DATA(className),
179
(UDATA)J9UTF8_LENGTH(methName), J9UTF8_DATA(methName),
180
(UDATA)J9UTF8_LENGTH(methSig), J9UTF8_DATA(methSig));
181
182
Trc_JIT_DumpCompilingMethod(vmThread, ramMethod, optLevel, oldStartPC);
183
184
// The request to use a trace log gets passed to the compilation via the optimization plan. The options object
185
// created before the compile is issued will use the trace log we provide to initialize IL tracing.
186
TR_OptimizationPlan *plan = NULL;
187
#if defined(J9VM_OPT_JITSERVER)
188
// JITServer will create a new optimization plan on the client
189
if (compInfo->getPersistentInfo()->getRemoteCompilationMode() != JITServer::SERVER)
190
#endif
191
{
192
plan = TR_OptimizationPlan::alloc(optLevel);
193
if (NULL == plan)
194
{
195
j9nls_printf(PORTLIB, J9NLS_INFO | J9NLS_STDERR, J9NLS_DMP_JIT_OPTIMIZATION_PLAN);
196
return;
197
}
198
199
plan->setInsertInstrumentation(isProfilingCompile);
200
plan->setLogCompilation(jitdumpFile);
201
}
202
203
trfprintf(jitdumpFile, "<recompilation>\n");
204
205
// Set the VM state of the crashed thread so the diagnostic thread can use consume it
206
compInfo->setVMStateOfCrashedThread(vmThread->omrVMThread->vmState);
207
208
J9::JitDumpMethodDetails details(ramMethod, optionsFromOriginalCompile, isAOTBody);
209
auto queued = false;
210
auto rc = compilationOK;
211
#if defined(J9VM_OPT_JITSERVER)
212
if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER)
213
{
214
// Inform the client that the compilation thread has crashed and send it
215
// a pointer to the JitDump file, so that it can request
216
// a JitDump recompilation from the server with an updated plan and method details.
217
TR_MethodToBeCompiled *entry = TR::compInfoPT->getMethodBeingCompiled();
218
JITServer::ServerStream *stream = entry->_stream;
219
stream->write(JITServer::MessageType::compilationThreadCrashed, jitdumpFile);
220
stream->read<JITServer::Void>();
221
{
222
// Add an entry to the compilation queue using the current stream,
223
// and immediatelly set its method details as JitDump method details,
224
// so that only the diagnostic thread can compile it.
225
OMR::CriticalSection compilationMonitorLock(compInfo->getCompilationMonitor());
226
227
compInfo->requeueOutOfProcessEntry(entry);
228
entry->_methodDetails = TR::IlGeneratorMethodDetails::clone(entry->_methodDetailsStorage, details);
229
queued = true;
230
}
231
// Wait for the recompilation to finish
232
entry->acquireSlotMonitor(vmThread);
233
entry->getMonitor()->wait();
234
entry->releaseSlotMonitor(vmThread);
235
}
236
else
237
#endif
238
{
239
compInfo->compileMethod(vmThread, details, oldStartPC, TR_no, &rc, &queued, plan);
240
}
241
242
trfprintf(jitdumpFile, "</recompilation rc=%d queued=%d>\n", rc, queued);
243
244
if (!queued
245
#if defined(J9VM_OPT_JITSERVER)
246
&& compInfo->getPersistentInfo()->getRemoteCompilationMode() != JITServer::SERVER
247
#endif
248
)
249
{
250
TR_OptimizationPlan::freeOptimizationPlan(plan);
251
}
252
}
253
254
uintptr_t
255
jitDumpSignalHandler(struct J9PortLibrary *portLibrary, uint32_t gpType, void *gpInfo, void *handler_arg)
256
{
257
PORT_ACCESS_FROM_VMC(reinterpret_cast<J9VMThread*>(handler_arg));
258
j9nls_printf(PORTLIB, J9NLS_INFO | J9NLS_STDERR, J9NLS_DMP_JIT_RECURSIVE_CRASH);
259
return J9PORT_SIG_EXCEPTION_RETURN;
260
}
261
262
static UDATA
263
jitDumpStackFrameIterator(J9VMThread *currentThread, J9StackWalkState *walkState)
264
{
265
Trc_JIT_DumpWalkingFrame(currentThread);
266
267
if (NULL != walkState->jitInfo)
268
{
269
auto *bodyInfo = reinterpret_cast<TR_PersistentJittedBodyInfo *>(walkState->jitInfo->bodyInfo);
270
if (NULL != bodyInfo)
271
{
272
jitDumpRecompileWithTracing(
273
currentThread,
274
walkState->method,
275
reinterpret_cast<TR::CompilationInfo*>(walkState->userData1),
276
bodyInfo->getHotness(),
277
bodyInfo->getIsProfilingBody(),
278
NULL,
279
bodyInfo->getIsAotedBody(),
280
bodyInfo->getStartPCAfterPreviousCompile(),
281
reinterpret_cast<TR::FILE*>(walkState->userData2)
282
);
283
}
284
}
285
286
return J9_STACKWALK_KEEP_ITERATING;
287
}
288
289
omr_error_t
290
runJitdump(char *label, J9RASdumpContext *context, J9RASdumpAgent *agent)
291
{
292
PORT_ACCESS_FROM_VMC(context);
293
294
J9VMThread *crashedThread = context->javaVM->internalVMFunctions->currentVMThread(context->javaVM);
295
Trc_JIT_DumpStart(crashedThread);
296
297
#if defined(J9VM_OPT_JITSERVER)
298
if (context && context->javaVM && context->javaVM->jitConfig)
299
{
300
J9JITConfig *jitConfig = context->javaVM->jitConfig;
301
TR::CompilationInfo *compInfo = TR::CompilationInfo::get(context->javaVM->jitConfig);
302
if (compInfo)
303
{
304
static char *isPrintJITServerMsgStats = feGetEnv("TR_PrintJITServerMsgStats");
305
if (isPrintJITServerMsgStats)
306
JITServerHelpers::printJITServerMsgStats(jitConfig, compInfo);
307
308
static char *isPrintJITServerCHTableStats = feGetEnv("TR_PrintJITServerCHTableStats");
309
if (isPrintJITServerCHTableStats)
310
JITServerHelpers::printJITServerCHTableStats(jitConfig, compInfo);
311
312
static char *isPrintJITServerIPMsgStats = feGetEnv("TR_PrintJITServerIPMsgStats");
313
if (isPrintJITServerIPMsgStats)
314
{
315
if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER)
316
{
317
TR_J9VMBase *vmj9 = (TR_J9VMBase *)TR_J9VMBase::get(context->javaVM->jitConfig, NULL);
318
JITServerIProfiler *iProfiler = (JITServerIProfiler *)vmj9->getIProfiler();
319
iProfiler->printStats();
320
}
321
}
322
323
static char *isPrintJITServerAOTCacheStats = feGetEnv("TR_PrintJITServerAOTCacheStats");
324
if (isPrintJITServerAOTCacheStats)
325
{
326
if (auto aotCacheMap = compInfo->getJITServerAOTCacheMap())
327
aotCacheMap->printStats(stderr);
328
if (auto deserializer = compInfo->getJITServerAOTDeserializer())
329
deserializer->printStats(stderr);
330
}
331
332
#if defined(LINUX)
333
static char *isPrintJITServerMallocStats = feGetEnv("TR_PrintJITServerMallocStats");
334
if (isPrintJITServerMallocStats)
335
malloc_stats();
336
#endif /* defined(LINUX) */
337
}
338
}
339
#endif /* defined(J9VM_OPT_JITSERVER) */
340
341
char *crashedThreadName = getOMRVMThreadName(crashedThread->omrVMThread);
342
j9nls_printf(PORTLIB, J9NLS_INFO | J9NLS_STDERR, J9NLS_DMP_OCCURRED_THREAD_NAME_ID, "JIT", crashedThreadName, crashedThread);
343
releaseOMRVMThreadName(crashedThread->omrVMThread);
344
345
J9JITConfig *jitConfig = crashedThread->javaVM->jitConfig;
346
if (NULL == jitConfig)
347
{
348
j9nls_printf(PORTLIB, J9NLS_ERROR | J9NLS_STDERR, J9NLS_DMP_ERROR_IN_DUMP_STR, "JIT", "Could not locate J9JITConfig");
349
return OMR_ERROR_INTERNAL;
350
}
351
352
TR::CompilationInfo *compInfo = TR::CompilationInfo::get(jitConfig);
353
if (NULL == compInfo)
354
{
355
j9nls_printf(PORTLIB, J9NLS_ERROR | J9NLS_STDERR, J9NLS_DMP_ERROR_IN_DUMP_STR, "JIT", "Could not locate TR::CompilationInfo");
356
return OMR_ERROR_INTERNAL;
357
}
358
359
TR_J9VMBase *frontendOfThread = TR_J9VMBase::get(jitConfig, crashedThread);
360
if (NULL == frontendOfThread)
361
{
362
j9nls_printf(PORTLIB, J9NLS_ERROR | J9NLS_STDERR, J9NLS_DMP_ERROR_IN_DUMP_STR, "JIT", "Could not locate TR_J9VMBase");
363
return OMR_ERROR_INTERNAL;
364
}
365
366
TR::Options *options = TR::Options::getCmdLineOptions();
367
if (NULL == options)
368
{
369
j9nls_printf(PORTLIB, J9NLS_ERROR | J9NLS_STDERR, J9NLS_DMP_ERROR_IN_DUMP_STR, "JIT", "Could not locate TR::Options");
370
return OMR_ERROR_INTERNAL;
371
}
372
373
// To avoid a deadlock, release compilation monitor until we are no longer holding it
374
while (compInfo->getCompilationMonitor()->owned_by_self())
375
{
376
compInfo->releaseCompMonitor(crashedThread);
377
}
378
379
// Release other monitors as well. In particular CHTable and classUnloadMonitor must not be held.
380
while (TR::MonitorTable::get()->getClassTableMutex()->owned_by_self())
381
{
382
frontendOfThread->releaseClassTableMutex(false);
383
}
384
385
TR::CompilationInfoPerThread *threadCompInfo = compInfo->getCompInfoForThread(crashedThread);
386
if (NULL != threadCompInfo)
387
{
388
TR_MethodToBeCompiled *methodBeingCompiled = threadCompInfo->getMethodBeingCompiled();
389
390
// If we are currently compiling a method, wake everyone waiting for it to compile
391
if (NULL != methodBeingCompiled && NULL != methodBeingCompiled->getMonitor())
392
{
393
methodBeingCompiled->getMonitor()->enter();
394
methodBeingCompiled->getMonitor()->notifyAll();
395
methodBeingCompiled->getMonitor()->exit();
396
397
j9nls_printf(PORTLIB, J9NLS_INFO | J9NLS_STDERR, J9NLS_DMP_JIT_NOTIFIED_WAITING_THREADS);
398
}
399
400
#if defined(J9VM_OPT_JITSERVER)
401
if (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER)
402
{
403
// Release the class unload RW mutex
404
auto serverCompInfo = static_cast<TR::CompilationInfoPerThreadRemote *>(threadCompInfo);
405
while (serverCompInfo->getClassUnloadReadMutexDepth() > 0)
406
{
407
serverCompInfo->getClientData()->readReleaseClassUnloadRWMutex(serverCompInfo);
408
}
409
}
410
#endif
411
412
// Release the class unload RW mutex
413
while (TR::MonitorTable::get()->getClassUnloadMonitorHoldCount(threadCompInfo->getCompThreadId()) > 0)
414
{
415
TR::MonitorTable::get()->readReleaseClassUnloadMonitor(threadCompInfo->getCompThreadId());
416
}
417
}
418
419
TR::CompilationInfoPerThread *recompilationThreadInfo = compInfo->getCompilationInfoForDiagnosticThread();
420
if (NULL == recompilationThreadInfo)
421
{
422
j9nls_printf(PORTLIB, J9NLS_ERROR | J9NLS_STDERR, J9NLS_DMP_ERROR_IN_DUMP_STR, "JIT", "Could not locate the diagnostic thread info");
423
return OMR_ERROR_INTERNAL;
424
}
425
426
auto *recompilationThread = recompilationThreadInfo->getCompilationThread();
427
if (NULL == recompilationThread)
428
{
429
j9nls_printf(PORTLIB, J9NLS_ERROR | J9NLS_STDERR, J9NLS_DMP_ERROR_IN_DUMP_STR, "JIT", "Could not locate the diagnostic thread");
430
return OMR_ERROR_INTERNAL;
431
}
432
433
compInfo->acquireCompMonitor(crashedThread);
434
compInfo->getPersistentInfo()->setDisableFurtherCompilation(true);
435
compInfo->purgeMethodQueue(compilationFailure);
436
compInfo->releaseCompMonitor(crashedThread);
437
438
recompilationThreadInfo->resumeCompilationThread();
439
440
TR::FILE *jitdumpFile = trfopen(label, "ab", false);
441
if (NULL == jitdumpFile)
442
{
443
j9nls_printf(PORTLIB, J9NLS_ERROR | J9NLS_STDERR, J9NLS_DMP_NO_OPEN_READ, label);
444
return OMR_ERROR_INTERNAL;
445
}
446
447
trfprintf(jitdumpFile,
448
"<?xml version=\"1.0\" standalone=\"no\"?>\n"
449
"<jitDump>\n"
450
);
451
452
try
453
{
454
// Process user defined options first. The user can specify any method signature to be recompiled at an arbitrary
455
// dump event. This is typically used for debugging purposes so we process this option first if it exists.
456
if (NULL != agent->dumpOptions)
457
{
458
const char *indexOfDot = strchr(agent->dumpOptions, '.');
459
const char *indexOfParen = strchr(agent->dumpOptions, '(');
460
461
if ((NULL != indexOfDot) && (NULL != indexOfParen))
462
{
463
TR::VMAccessCriticalSection findUserMethod(TR_J9VMBase::get(jitConfig, crashedThread));
464
465
const char *className = agent->dumpOptions;
466
U_32 classNameLength = static_cast<U_32>(indexOfDot - agent->dumpOptions);
467
const char *methodName = indexOfDot + 1;
468
U_32 methodNameLength = static_cast<U_32>(indexOfParen - methodName);
469
const char *methodSig = indexOfParen;
470
U_32 methodSigLength = strlen(methodSig);
471
472
J9MethodFromSignatureWalkState state;
473
J9Method *userMethod = allMethodsFromSignatureStartDo(&state, context->javaVM, 0, className, classNameLength, methodName, methodNameLength, methodSig, methodSigLength);
474
while (NULL != userMethod)
475
{
476
J9JITExceptionTable *metadata = jitConfig->jitGetExceptionTableFromPC(crashedThread, reinterpret_cast<UDATA>(userMethod->extra));
477
if (NULL != metadata)
478
{
479
auto *bodyInfo = reinterpret_cast<TR_PersistentJittedBodyInfo *>(metadata->bodyInfo);
480
if (NULL != bodyInfo)
481
{
482
if (NULL == threadCompInfo)
483
{
484
// We are an application thread
485
jitDumpRecompileWithTracing(
486
crashedThread,
487
userMethod,
488
compInfo,
489
bodyInfo->getHotness(),
490
bodyInfo->getIsProfilingBody(),
491
NULL,
492
bodyInfo->getIsAotedBody(),
493
bodyInfo->getStartPCAfterPreviousCompile(),
494
jitdumpFile
495
);
496
}
497
else
498
{
499
// We are a compilation thread
500
501
// See comment below for the same call on why this is needed
502
TR::CompilationInfoPerThreadBase::UninterruptibleOperation jitDumpForCrashedCompilationThread(*threadCompInfo);
503
504
// See comment below for the same call on why this is needed
505
TR::VMAccessCriticalSection requestSynchronousCompilation(TR_J9VMBase::get(jitConfig, crashedThread));
506
507
jitDumpRecompileWithTracing(
508
crashedThread,
509
userMethod,
510
compInfo,
511
bodyInfo->getHotness(),
512
bodyInfo->getIsProfilingBody(),
513
NULL,
514
bodyInfo->getIsAotedBody(),
515
bodyInfo->getStartPCAfterPreviousCompile(),
516
jitdumpFile
517
);
518
}
519
}
520
}
521
userMethod = allMethodsFromSignatureNextDo(&state);
522
}
523
allMethodsFromSignatureEndDo(&state);
524
}
525
}
526
527
if (NULL == threadCompInfo)
528
{
529
// We are an application thread
530
531
if (NULL != crashedThread->gpInfo)
532
{
533
// The stack walker may not be able to walk the stack if the crash did not happen on a transition frame. In
534
// such cases the stack walker will resume walking the stack on the last known valid point, which will be a
535
// transition frame further up the stack (ex. INT -> JIT transition frame). This will result in the stack
536
// walker potentially skipping some JIT methods on the backtrace. This is not desirable. Chances are high
537
// that the crash happen because of a miscompilation in the first JIT compiled method on the stack, so it
538
// is imperative that we recompile the method we actually crashed in.
539
const char *name;
540
void *value;
541
U_32 infoType = j9sig_info(crashedThread->gpInfo, J9PORT_SIG_CONTROL, J9PORT_SIG_CONTROL_PC, &name, &value);
542
543
if (J9PORT_SIG_VALUE_ADDRESS == infoType)
544
{
545
J9JITExceptionTable *metadata = jitConfig->jitGetExceptionTableFromPC(crashedThread, *reinterpret_cast<UDATA*>(value));
546
if (NULL != metadata)
547
{
548
auto *bodyInfo = reinterpret_cast<TR_PersistentJittedBodyInfo *>(metadata->bodyInfo);
549
if (NULL != bodyInfo)
550
{
551
jitDumpRecompileWithTracing(
552
crashedThread,
553
metadata->ramMethod,
554
compInfo,
555
bodyInfo->getHotness(),
556
bodyInfo->getIsProfilingBody(),
557
NULL,
558
bodyInfo->getIsAotedBody(),
559
bodyInfo->getStartPCAfterPreviousCompile(),
560
jitdumpFile
561
);
562
}
563
}
564
}
565
}
566
567
J9StackWalkState walkState;
568
walkState.userData1 = compInfo;
569
walkState.userData2 = jitdumpFile;
570
walkState.walkThread = crashedThread;
571
walkState.skipCount = 0;
572
walkState.maxFrames = 16;
573
walkState.flags = (
574
J9_STACKWALK_VISIBLE_ONLY |
575
J9_STACKWALK_SKIP_INLINES |
576
J9_STACKWALK_COUNT_SPECIFIED |
577
J9_STACKWALK_ITERATE_FRAMES |
578
J9_STACKWALK_NO_ERROR_REPORT
579
);
580
walkState.frameWalkFunction = jitDumpStackFrameIterator;
581
582
crashedThread->javaVM->walkStackFrames(crashedThread, &walkState);
583
}
584
else
585
{
586
// We are a compilation thread
587
588
// Printing the crashed thread trees or any similar operation on the crashed thread may result in having to
589
// acquire VM access (ex. to get a class signature). Other VM events, such as VM shutdown or the GC unloading
590
// classes may cause compilations to be interrupted. Because the crashed thread is not a diagnostic thread,
591
// the call to print the crashed thread IL may get interrupted and the jitdump will be incomplete. We prevent
592
// this from occuring by disallowing interruptions until we are done generating the jitdump.
593
TR::CompilationInfoPerThreadBase::UninterruptibleOperation jitDumpForCrashedCompilationThread(*threadCompInfo);
594
595
TR::Compilation *comp = threadCompInfo->getCompilation();
596
if (NULL == comp)
597
{
598
j9nls_printf(PORTLIB, J9NLS_ERROR | J9NLS_STDERR, J9NLS_DMP_ERROR_IN_DUMP_STR, "JIT", "Could not locate the compilation object");
599
trfclose(jitdumpFile);
600
return OMR_ERROR_INTERNAL;
601
}
602
603
#if defined(J9VM_OPT_JITSERVER)
604
if (comp->isOutOfProcessCompilation())
605
{
606
// Inform the client that JitDump has started and is about to trace IL of the crashed thread
607
TR_MethodToBeCompiled *entry = threadCompInfo->getMethodBeingCompiled();
608
JITServer::ServerStream *stream = entry->_stream;
609
stream->write(JITServer::MessageType::jitDumpPrintIL, JITServer::Void());
610
stream->read<JITServer::Void>();
611
}
612
#endif
613
614
traceILOfCrashedThread(crashedThread, comp, jitdumpFile);
615
616
TR_MethodToBeCompiled *methodBeingCompiled = threadCompInfo->getMethodBeingCompiled();
617
if (NULL != methodBeingCompiled && methodBeingCompiled->getMethodDetails().isOrdinaryMethod())
618
{
619
j9nls_printf(PORTLIB, J9NLS_INFO | J9NLS_STDERR, J9NLS_DMP_JIT_ORDINARY_METHOD);
620
621
{
622
// The current thread is a compilation thread which may or may not currently hold VM access. The request
623
// for recompilation to generate the jitdump will be performed synchronously for which the code path we
624
// will take will be the same as if we were an application thread. We will take the synchronous request
625
// path in `compileOnSeparateThread` which ends up releasing VM access prior to waiting on the diagnostic
626
// thread to finish the queued compile. To avoid deadlocks we must acquire VM access here.
627
TR::VMAccessCriticalSection requestSynchronousCompilation(TR_J9VMBase::get(jitConfig, crashedThread));
628
629
// request the compilation
630
jitDumpRecompileWithTracing(
631
crashedThread,
632
(J9Method *)(comp->getCurrentMethod()->getPersistentIdentifier()),
633
compInfo,
634
(TR_Hotness)comp->getOptLevel(),
635
comp->isProfilingCompilation(),
636
comp->getOptions(),
637
comp->compileRelocatableCode(),
638
methodBeingCompiled->_oldStartPC,
639
jitdumpFile
640
);
641
}
642
}
643
}
644
}
645
catch (const std::exception &e)
646
{
647
const char *exceptionName;
648
649
#if defined(J9ZOS390)
650
// Compiling with -Wc,lp64 results in a crash on z/OS when trying
651
// to call the what() virtual method of the exception.
652
exceptionName = "std::exception";
653
#else
654
exceptionName = e.what();
655
#endif
656
657
trfprintf(jitdumpFile, "\n=== EXCEPTION THROWN (%s) ===\n", exceptionName);
658
}
659
660
trfprintf(jitdumpFile, "</jitDump>\n");
661
trfflush(jitdumpFile);
662
trfclose(jitdumpFile);
663
664
recompilationThreadInfo->suspendCompilationThread();
665
666
compInfo->getPersistentInfo()->setDisableFurtherCompilation(false);
667
668
return OMR_ERROR_NONE;
669
}
670
671