@@ -85,6 +85,7 @@ Thread* VMError::_thread;
85
85
address VMError::_pc;
86
86
void * VMError::_siginfo;
87
87
void * VMError::_context;
88
+ bool VMError::_print_native_stack_used = false ;
88
89
const char * VMError::_filename;
89
90
int VMError::_lineno;
90
91
size_t VMError::_size;
@@ -240,6 +241,107 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt,
240
241
#endif // ZERO
241
242
}
242
243
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
+
243
345
void VMError::print_native_stack (outputStream* st, frame fr, Thread* t, char * buf, int buf_size) {
244
346
245
347
// see if it's a valid frame
@@ -257,26 +359,9 @@ void VMError::print_native_stack(outputStream* st, frame fr, Thread* t, char* bu
257
359
}
258
360
}
259
361
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 ;
280
365
}
281
366
}
282
367
@@ -746,6 +831,7 @@ void VMError::report(outputStream* st, bool _verbose) {
746
831
: os::current_frame ();
747
832
748
833
print_native_stack (st, fr, _thread, buf, sizeof (buf));
834
+ _print_native_stack_used = true ;
749
835
}
750
836
}
751
837
@@ -820,30 +906,28 @@ void VMError::report(outputStream* st, bool _verbose) {
820
906
st->cr ();
821
907
}
822
908
823
- STEP (" printing code blob if possible" )
909
+ STEP (" printing code blobs if possible" )
824
910
825
911
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++;
846
929
}
930
+ fr = next_frame (fr, _thread);
847
931
}
848
932
}
849
933
}
0 commit comments