Skip to content

Commit 393aeaf

Browse files
committed
8272586: emit abstract machine code in hs-err logs
8275031: runtime/ErrorHandling/MachCodeFramesInErrorFile.java fails when hsdis is present 8277102: Dubious PrintCompilation output Reviewed-by: mbaesken Backport-of: b60837a7d5d6f920d2fb968369564df155dc1018
1 parent d85a847 commit 393aeaf

File tree

6 files changed

+328
-44
lines changed

6 files changed

+328
-44
lines changed

src/hotspot/share/code/nmethod.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
#include "runtime/sharedRuntime.hpp"
6868
#include "runtime/signature.hpp"
6969
#include "runtime/sweeper.hpp"
70+
#include "runtime/threadWXSetters.inline.hpp"
7071
#include "runtime/vmThread.hpp"
7172
#include "utilities/align.hpp"
7273
#include "utilities/copy.hpp"
@@ -2573,7 +2574,7 @@ void nmethod::print(outputStream* st) const {
25732574
st->print("(n/a) ");
25742575
}
25752576

2576-
print_on(tty, NULL);
2577+
print_on(st, NULL);
25772578

25782579
if (WizardMode) {
25792580
st->print("((nmethod*) " INTPTR_FORMAT ") ", p2i(this));
@@ -2924,6 +2925,9 @@ void nmethod::decode2(outputStream* ost) const {
29242925
AbstractDisassembler::show_block_comment());
29252926
#endif
29262927

2928+
// Decoding an nmethod can write to a PcDescCache (see PcDescCache::add_pc_desc)
2929+
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current());)
2930+
29272931
st->cr();
29282932
this->print(st);
29292933
st->cr();
@@ -2933,7 +2937,10 @@ void nmethod::decode2(outputStream* ost) const {
29332937
//---< Print real disassembly >---
29342938
//----------------------------------
29352939
if (! use_compressed_format) {
2940+
st->print_cr("[Disassembly]");
29362941
Disassembler::decode(const_cast<nmethod*>(this), st);
2942+
st->bol();
2943+
st->print_cr("[/Disassembly]");
29372944
return;
29382945
}
29392946
#endif

src/hotspot/share/compiler/disassembler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ void Disassembler::decode(CodeBlob* cb, outputStream* st) {
887887
if (cb->is_nmethod()) {
888888
// If we have an nmethod at hand,
889889
// call the specialized decoder directly.
890-
decode((nmethod*)cb, st);
890+
((nmethod*)cb)->decode2(st);
891891
return;
892892
}
893893

src/hotspot/share/utilities/vmError.cpp

Lines changed: 125 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ Thread* VMError::_thread;
8585
address VMError::_pc;
8686
void* VMError::_siginfo;
8787
void* VMError::_context;
88+
bool VMError::_print_native_stack_used = false;
8889
const char* VMError::_filename;
8990
int VMError::_lineno;
9091
size_t VMError::_size;
@@ -240,6 +241,107 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt,
240241
#endif // ZERO
241242
}
242243

244+
/**
245+
* Adds `value` to `list` iff it's not already present and there is sufficient
246+
* capacity (i.e. length(list) < `list_capacity`). The length of the list
247+
* is the index of the first nullptr entry.
248+
*
249+
* @ return true if the value was added, false otherwise
250+
*/
251+
static bool add_if_absent(address value, address* list, int list_capacity) {
252+
for (int i = 0; i < list_capacity; i++) {
253+
if (list[i] == value) {
254+
return false;
255+
}
256+
if (list[i] == nullptr) {
257+
list[i] = value;
258+
if (i + 1 < list_capacity) {
259+
list[i + 1] = nullptr;
260+
}
261+
return true;
262+
}
263+
}
264+
return false;
265+
}
266+
267+
/**
268+
* Prints the VM generated code unit, if any, containing `pc` if it has not already
269+
* been printed. If the code unit is an InterpreterCodelet or StubCodeDesc, it is
270+
* only printed if `is_crash_pc` is true.
271+
*
272+
* @param printed array of code units that have already been printed (delimited by NULL entry)
273+
* @param printed_capacity the capacity of `printed`
274+
* @return true if the code unit was printed, false otherwise
275+
*/
276+
static bool print_code(outputStream* st, Thread* thread, address pc, bool is_crash_pc,
277+
address* printed, int printed_capacity) {
278+
if (Interpreter::contains(pc)) {
279+
if (is_crash_pc) {
280+
// The interpreter CodeBlob is very large so try to print the codelet instead.
281+
InterpreterCodelet* codelet = Interpreter::codelet_containing(pc);
282+
if (codelet != nullptr) {
283+
if (add_if_absent((address) codelet, printed, printed_capacity)) {
284+
codelet->print_on(st);
285+
Disassembler::decode(codelet->code_begin(), codelet->code_end(), st);
286+
return true;
287+
}
288+
}
289+
}
290+
} else {
291+
StubCodeDesc* desc = StubCodeDesc::desc_for(pc);
292+
if (desc != nullptr) {
293+
if (is_crash_pc) {
294+
if (add_if_absent((address) desc, printed, printed_capacity)) {
295+
desc->print_on(st);
296+
Disassembler::decode(desc->begin(), desc->end(), st);
297+
return true;
298+
}
299+
}
300+
} else if (thread != nullptr) {
301+
CodeBlob* cb = CodeCache::find_blob(pc);
302+
if (cb != nullptr && add_if_absent((address) cb, printed, printed_capacity)) {
303+
// Disassembling nmethod will incur resource memory allocation,
304+
// only do so when thread is valid.
305+
ResourceMark rm(thread);
306+
Disassembler::decode(cb, st);
307+
st->cr();
308+
return true;
309+
}
310+
}
311+
}
312+
return false;
313+
}
314+
315+
/**
316+
* Gets the caller frame of `fr`.
317+
*
318+
* @returns an invalid frame (i.e. fr.pc() === 0) if the caller cannot be obtained
319+
*/
320+
static frame next_frame(frame fr, Thread* t) {
321+
// Compiled code may use EBP register on x86 so it looks like
322+
// non-walkable C frame. Use frame.sender() for java frames.
323+
frame invalid;
324+
if (t != nullptr && t->is_Java_thread()) {
325+
// Catch very first native frame by using stack address.
326+
// For JavaThread stack_base and stack_size should be set.
327+
if (!t->is_in_full_stack((address)(fr.real_fp() + 1))) {
328+
return invalid;
329+
}
330+
if (fr.is_java_frame() || fr.is_native_frame() || fr.is_runtime_frame()) {
331+
RegisterMap map(t->as_Java_thread(), false); // No update
332+
return fr.sender(&map);
333+
} else {
334+
// is_first_C_frame() does only simple checks for frame pointer,
335+
// it will pass if java compiled code has a pointer in EBP.
336+
if (os::is_first_C_frame(&fr)) return invalid;
337+
return os::get_sender_for_C_frame(&fr);
338+
}
339+
} else {
340+
if (os::is_first_C_frame(&fr)) return invalid;
341+
return os::get_sender_for_C_frame(&fr);
342+
}
343+
}
344+
243345
void VMError::print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int buf_size) {
244346

245347
// see if it's a valid frame
@@ -257,26 +359,9 @@ void VMError::print_native_stack(outputStream* st, frame fr, Thread* t, char* bu
257359
}
258360
}
259361
st->cr();
260-
// Compiled code may use EBP register on x86 so it looks like
261-
// non-walkable C frame. Use frame.sender() for java frames.
262-
if (t && t->is_Java_thread()) {
263-
// Catch very first native frame by using stack address.
264-
// For JavaThread stack_base and stack_size should be set.
265-
if (!t->is_in_full_stack((address)(fr.real_fp() + 1))) {
266-
break;
267-
}
268-
if (fr.is_java_frame() || fr.is_native_frame() || fr.is_runtime_frame()) {
269-
RegisterMap map(t->as_Java_thread(), false); // No update
270-
fr = fr.sender(&map);
271-
} else {
272-
// is_first_C_frame() does only simple checks for frame pointer,
273-
// it will pass if java compiled code has a pointer in EBP.
274-
if (os::is_first_C_frame(&fr)) break;
275-
fr = os::get_sender_for_C_frame(&fr);
276-
}
277-
} else {
278-
if (os::is_first_C_frame(&fr)) break;
279-
fr = os::get_sender_for_C_frame(&fr);
362+
fr = next_frame(fr, t);
363+
if (fr.pc() == nullptr) {
364+
break;
280365
}
281366
}
282367

@@ -746,6 +831,7 @@ void VMError::report(outputStream* st, bool _verbose) {
746831
: os::current_frame();
747832

748833
print_native_stack(st, fr, _thread, buf, sizeof(buf));
834+
_print_native_stack_used = true;
749835
}
750836
}
751837

@@ -820,30 +906,28 @@ void VMError::report(outputStream* st, bool _verbose) {
820906
st->cr();
821907
}
822908

823-
STEP("printing code blob if possible")
909+
STEP("printing code blobs if possible")
824910

825911
if (_verbose && _context) {
826-
CodeBlob* cb = CodeCache::find_blob(_pc);
827-
if (cb != NULL) {
828-
if (Interpreter::contains(_pc)) {
829-
// The interpreter CodeBlob is very large so try to print the codelet instead.
830-
InterpreterCodelet* codelet = Interpreter::codelet_containing(_pc);
831-
if (codelet != NULL) {
832-
codelet->print_on(st);
833-
Disassembler::decode(codelet->code_begin(), codelet->code_end(), st);
834-
}
835-
} else {
836-
StubCodeDesc* desc = StubCodeDesc::desc_for(_pc);
837-
if (desc != NULL) {
838-
desc->print_on(st);
839-
Disassembler::decode(desc->begin(), desc->end(), st);
840-
} else if (_thread != NULL) {
841-
// Disassembling nmethod will incur resource memory allocation,
842-
// only do so when thread is valid.
843-
ResourceMark rm(_thread);
844-
Disassembler::decode(cb, st);
845-
st->cr();
912+
if (!_print_native_stack_used) {
913+
// Only try print code of the crashing frame since
914+
// we cannot walk the native stack using next_frame.
915+
const int printed_capacity = 1;
916+
address printed_singleton = nullptr;
917+
address* printed = &printed_singleton;
918+
print_code(st, _thread, _pc, true, printed, 1);
919+
} else {
920+
// Print up to the first 5 unique code units on the stack
921+
const int printed_capacity = 5;
922+
address printed[printed_capacity];
923+
printed[0] = nullptr; // length(list) == index of first nullptr
924+
925+
frame fr = os::fetch_frame_from_context(_context);
926+
for (int count = 0; count < printed_capacity && fr.pc() != nullptr; ) {
927+
if (print_code(st, _thread, fr.pc(), fr.pc() == _pc, printed, printed_capacity)) {
928+
count++;
846929
}
930+
fr = next_frame(fr, _thread);
847931
}
848932
}
849933
}

src/hotspot/share/utilities/vmError.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ class VMError : public AllStatic {
5151
static void* _context; // ContextRecord on Windows,
5252
// ucontext_t on Solaris/Linux
5353

54+
// records if VMError::print_native_stack was used to
55+
// print the native stack instead of os::platform_print_native_stack
56+
static bool _print_native_stack_used;
57+
5458
// additional info for VM internal errors
5559
static const char* _filename;
5660
static int _lineno;

test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,16 @@ private void check(CompileCodeTestCase testCase) {
101101
// Therefore compare strings 2 and 3.
102102
String str2 = CompilerToVMHelper.disassembleCodeBlob(installedCode);
103103
String str3 = CompilerToVMHelper.disassembleCodeBlob(installedCode);
104-
Asserts.assertEQ(str2, str3,
104+
String[] str2Lines = str2.split(System.lineSeparator());
105+
String[] str3Lines = str3.split(System.lineSeparator());
106+
// skip the first two lines since it contains a timestamp that may vary from different invocations
107+
// <empty-line>
108+
// Compiled method (c2) 309 463 4 compiler.jvmci.compilerToVM.CompileCodeTestCase$Dummy::staticMethod (1 bytes)
109+
// <empty-line>
110+
// Compiled method (c2) 310 463 4 compiler.jvmci.compilerToVM.CompileCodeTestCase$Dummy::staticMethod (1 bytes)
111+
for (int i = 2; i < str2Lines.length; i++) {
112+
Asserts.assertEQ(str2Lines[i], str3Lines[i],
105113
testCase + " : 3nd invocation returned different value from 2nd");
114+
}
106115
}
107116
}

0 commit comments

Comments
 (0)