Tue, 17 Oct 2017 12:58:25 +0800
merge
1 /*
2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
25 #include "precompiled.hpp"
26 #include "classfile/systemDictionary.hpp"
27 #include "code/codeCache.hpp"
28 #include "code/icBuffer.hpp"
29 #include "code/nmethod.hpp"
30 #include "code/vtableStubs.hpp"
31 #include "compiler/compileBroker.hpp"
32 #include "compiler/disassembler.hpp"
33 #include "gc_implementation/shared/markSweep.hpp"
34 #include "gc_interface/collectedHeap.hpp"
35 #include "interpreter/bytecodeHistogram.hpp"
36 #include "interpreter/interpreter.hpp"
37 #include "memory/resourceArea.hpp"
38 #include "memory/universe.hpp"
39 #include "oops/oop.inline.hpp"
40 #include "prims/privilegedStack.hpp"
41 #include "runtime/arguments.hpp"
42 #include "runtime/frame.hpp"
43 #include "runtime/java.hpp"
44 #include "runtime/sharedRuntime.hpp"
45 #include "runtime/stubCodeGenerator.hpp"
46 #include "runtime/stubRoutines.hpp"
47 #include "runtime/thread.inline.hpp"
48 #include "runtime/vframe.hpp"
49 #include "services/heapDumper.hpp"
50 #include "utilities/defaultStream.hpp"
51 #include "utilities/events.hpp"
52 #include "utilities/top.hpp"
53 #include "utilities/vmError.hpp"
54 #ifdef TARGET_OS_FAMILY_linux
55 # include "os_linux.inline.hpp"
56 #endif
57 #ifdef TARGET_OS_FAMILY_solaris
58 # include "os_solaris.inline.hpp"
59 #endif
60 #ifdef TARGET_OS_FAMILY_windows
61 # include "os_windows.inline.hpp"
62 #endif
63 #ifdef TARGET_OS_FAMILY_bsd
64 # include "os_bsd.inline.hpp"
65 #endif
67 #ifndef ASSERT
68 # ifdef _DEBUG
69 // NOTE: don't turn the lines below into a comment -- if you're getting
70 // a compile error here, change the settings to define ASSERT
71 ASSERT should be defined when _DEBUG is defined. It is not intended to be used for debugging
72 functions that do not slow down the system too much and thus can be left in optimized code.
73 On the other hand, the code should not be included in a production version.
74 # endif // _DEBUG
75 #endif // ASSERT
78 #ifdef _DEBUG
79 # ifndef ASSERT
80 configuration error: ASSERT must be defined in debug version
81 # endif // ASSERT
82 #endif // _DEBUG
85 #ifdef PRODUCT
86 # if -defined _DEBUG || -defined ASSERT
87 configuration error: ASSERT et al. must not be defined in PRODUCT version
88 # endif
89 #endif // PRODUCT
91 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
93 FormatBufferResource::FormatBufferResource(const char * format, ...)
94 : FormatBufferBase((char*)resource_allocate_bytes(RES_BUFSZ)) {
95 va_list argp;
96 va_start(argp, format);
97 jio_vsnprintf(_buf, RES_BUFSZ, format, argp);
98 va_end(argp);
99 }
101 ATTRIBUTE_PRINTF(1, 2)
102 void warning(const char* format, ...) {
103 if (PrintWarnings) {
104 FILE* const err = defaultStream::error_stream();
105 jio_fprintf(err, "%s warning: ", VM_Version::vm_name());
106 va_list ap;
107 va_start(ap, format);
108 vfprintf(err, format, ap);
109 va_end(ap);
110 fputc('\n', err);
111 }
112 if (BreakAtWarning) BREAKPOINT;
113 }
115 #ifndef PRODUCT
117 #define is_token_break(ch) (isspace(ch) || (ch) == ',')
119 static const char* last_file_name = NULL;
120 static int last_line_no = -1;
122 // assert/guarantee/... may happen very early during VM initialization.
123 // Don't rely on anything that is initialized by Threads::create_vm(). For
124 // example, don't use tty.
125 bool error_is_suppressed(const char* file_name, int line_no) {
126 // The following 1-element cache requires that passed-in
127 // file names are always only constant literals.
128 if (file_name == last_file_name && line_no == last_line_no) return true;
130 int file_name_len = (int)strlen(file_name);
131 char separator = os::file_separator()[0];
132 const char* base_name = strrchr(file_name, separator);
133 if (base_name == NULL)
134 base_name = file_name;
136 // scan the SuppressErrorAt option
137 const char* cp = SuppressErrorAt;
138 for (;;) {
139 const char* sfile;
140 int sfile_len;
141 int sline;
142 bool noisy;
143 while ((*cp) != '\0' && is_token_break(*cp)) cp++;
144 if ((*cp) == '\0') break;
145 sfile = cp;
146 while ((*cp) != '\0' && !is_token_break(*cp) && (*cp) != ':') cp++;
147 sfile_len = cp - sfile;
148 if ((*cp) == ':') cp++;
149 sline = 0;
150 while ((*cp) != '\0' && isdigit(*cp)) {
151 sline *= 10;
152 sline += (*cp) - '0';
153 cp++;
154 }
155 // "file:line!" means the assert suppression is not silent
156 noisy = ((*cp) == '!');
157 while ((*cp) != '\0' && !is_token_break(*cp)) cp++;
158 // match the line
159 if (sline != 0) {
160 if (sline != line_no) continue;
161 }
162 // match the file
163 if (sfile_len > 0) {
164 const char* look = file_name;
165 const char* look_max = file_name + file_name_len - sfile_len;
166 const char* foundp;
167 bool match = false;
168 while (!match
169 && (foundp = strchr(look, sfile[0])) != NULL
170 && foundp <= look_max) {
171 match = true;
172 for (int i = 1; i < sfile_len; i++) {
173 if (sfile[i] != foundp[i]) {
174 match = false;
175 break;
176 }
177 }
178 look = foundp + 1;
179 }
180 if (!match) continue;
181 }
182 // got a match!
183 if (noisy) {
184 fdStream out(defaultStream::output_fd());
185 out.print_raw("[error suppressed at ");
186 out.print_raw(base_name);
187 char buf[16];
188 jio_snprintf(buf, sizeof(buf), ":%d]", line_no);
189 out.print_raw_cr(buf);
190 } else {
191 // update 1-element cache for fast silent matches
192 last_file_name = file_name;
193 last_line_no = line_no;
194 }
195 return true;
196 }
198 if (!is_error_reported()) {
199 // print a friendly hint:
200 fdStream out(defaultStream::output_fd());
201 out.print_raw_cr("# To suppress the following error report, specify this argument");
202 out.print_raw ("# after -XX: or in .hotspotrc: SuppressErrorAt=");
203 out.print_raw (base_name);
204 char buf[16];
205 jio_snprintf(buf, sizeof(buf), ":%d", line_no);
206 out.print_raw_cr(buf);
207 }
208 return false;
209 }
211 #undef is_token_break
213 #else
215 // Place-holder for non-existent suppression check:
216 #define error_is_suppressed(file_name, line_no) (false)
218 #endif // !PRODUCT
220 void report_vm_error(const char* file, int line, const char* error_msg,
221 const char* detail_msg)
222 {
223 if (Debugging || error_is_suppressed(file, line)) return;
224 Thread* const thread = ThreadLocalStorage::get_thread_slow();
225 VMError err(thread, file, line, error_msg, detail_msg);
226 err.report_and_die();
227 }
229 void report_fatal(const char* file, int line, const char* message)
230 {
231 report_vm_error(file, line, "fatal error", message);
232 }
234 void report_vm_out_of_memory(const char* file, int line, size_t size,
235 VMErrorType vm_err_type, const char* message) {
236 if (Debugging) return;
238 Thread* thread = ThreadLocalStorage::get_thread_slow();
239 VMError(thread, file, line, size, vm_err_type, message).report_and_die();
241 // The UseOSErrorReporting option in report_and_die() may allow a return
242 // to here. If so then we'll have to figure out how to handle it.
243 guarantee(false, "report_and_die() should not return here");
244 }
246 void report_should_not_call(const char* file, int line) {
247 report_vm_error(file, line, "ShouldNotCall()");
248 }
250 void report_should_not_reach_here(const char* file, int line) {
251 report_vm_error(file, line, "ShouldNotReachHere()");
252 }
254 void report_unimplemented(const char* file, int line) {
255 report_vm_error(file, line, "Unimplemented()");
256 }
258 void report_untested(const char* file, int line, const char* message) {
259 #ifndef PRODUCT
260 warning("Untested: %s in %s: %d\n", message, file, line);
261 #endif // !PRODUCT
262 }
264 void report_out_of_shared_space(SharedSpaceType shared_space) {
265 static const char* name[] = {
266 "native memory for metadata",
267 "shared read only space",
268 "shared read write space",
269 "shared miscellaneous data space",
270 "shared miscellaneous code space"
271 };
272 static const char* flag[] = {
273 "Metaspace",
274 "SharedReadOnlySize",
275 "SharedReadWriteSize",
276 "SharedMiscDataSize",
277 "SharedMiscCodeSize"
278 };
280 warning("\nThe %s is not large enough\n"
281 "to preload requested classes. Use -XX:%s=<size>\n"
282 "to increase the initial size of %s.\n",
283 name[shared_space], flag[shared_space], name[shared_space]);
284 exit(2);
285 }
287 void report_java_out_of_memory(const char* message) {
288 static jint out_of_memory_reported = 0;
290 // A number of threads may attempt to report OutOfMemoryError at around the
291 // same time. To avoid dumping the heap or executing the data collection
292 // commands multiple times we just do it once when the first threads reports
293 // the error.
294 if (Atomic::cmpxchg(1, &out_of_memory_reported, 0) == 0) {
295 // create heap dump before OnOutOfMemoryError commands are executed
296 if (HeapDumpOnOutOfMemoryError) {
297 tty->print_cr("java.lang.OutOfMemoryError: %s", message);
298 HeapDumper::dump_heap_from_oome();
299 }
301 if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
302 VMError err(message);
303 err.report_java_out_of_memory();
304 }
305 }
306 }
308 static bool error_reported = false;
310 // call this when the VM is dying--it might loosen some asserts
311 void set_error_reported() {
312 error_reported = true;
313 }
315 bool is_error_reported() {
316 return error_reported;
317 }
319 #ifndef PRODUCT
320 #include <signal.h>
322 void test_error_handler() {
323 uintx test_num = ErrorHandlerTest;
324 if (test_num == 0) return;
326 // If asserts are disabled, use the corresponding guarantee instead.
327 size_t n = test_num;
328 NOT_DEBUG(if (n <= 2) n += 2);
330 const char* const str = "hello";
331 const size_t num = (size_t)os::vm_page_size();
333 const char* const eol = os::line_separator();
334 const char* const msg = "this message should be truncated during formatting";
335 char * const dataPtr = NULL; // bad data pointer
336 const void (*funcPtr)(void) = (const void(*)()) 0xF; // bad function pointer
338 // Keep this in sync with test/runtime/6888954/vmerrors.sh.
339 switch (n) {
340 case 1: assert(str == NULL, "expected null");
341 case 2: assert(num == 1023 && *str == 'X',
342 err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
343 case 3: guarantee(str == NULL, "expected null");
344 case 4: guarantee(num == 1023 && *str == 'X',
345 err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
346 case 5: fatal("expected null");
347 case 6: fatal(err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
348 case 7: fatal(err_msg("%s%s# %s%s# %s%s# %s%s# %s%s# "
349 "%s%s# %s%s# %s%s# %s%s# %s%s# "
350 "%s%s# %s%s# %s%s# %s%s# %s",
351 msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
352 msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
353 msg, eol, msg, eol, msg, eol, msg, eol, msg));
354 case 8: vm_exit_out_of_memory(num, OOM_MALLOC_ERROR, "ChunkPool::allocate");
355 case 9: ShouldNotCallThis();
356 case 10: ShouldNotReachHere();
357 case 11: Unimplemented();
358 // There's no guarantee the bad data pointer will crash us
359 // so "break" out to the ShouldNotReachHere().
360 case 12: *dataPtr = '\0'; break;
361 // There's no guarantee the bad function pointer will crash us
362 // so "break" out to the ShouldNotReachHere().
363 case 13: (*funcPtr)(); break;
365 default: tty->print_cr("ERROR: %d: unexpected test_num value.", n);
366 }
367 ShouldNotReachHere();
368 }
369 #endif // !PRODUCT
371 // ------ helper functions for debugging go here ------------
373 // All debug entries should be wrapped with a stack allocated
374 // Command object. It makes sure a resource mark is set and
375 // flushes the logfile to prevent file sharing problems.
377 class Command : public StackObj {
378 private:
379 ResourceMark rm;
380 ResetNoHandleMark rnhm;
381 HandleMark hm;
382 bool debug_save;
383 public:
384 static int level;
385 Command(const char* str) {
386 debug_save = Debugging;
387 Debugging = true;
388 if (level++ > 0) return;
389 tty->cr();
390 tty->print_cr("\"Executing %s\"", str);
391 }
393 ~Command() {
394 tty->flush();
395 Debugging = debug_save;
396 level--;
397 }
398 };
400 int Command::level = 0;
402 #ifndef PRODUCT
404 extern "C" void blob(CodeBlob* cb) {
405 Command c("blob");
406 cb->print();
407 }
410 extern "C" void dump_vtable(address p) {
411 Command c("dump_vtable");
412 Klass* k = (Klass*)p;
413 InstanceKlass::cast(k)->vtable()->print();
414 }
417 extern "C" void nm(intptr_t p) {
418 // Actually we look through all CodeBlobs (the nm name has been kept for backwards compatability)
419 Command c("nm");
420 CodeBlob* cb = CodeCache::find_blob((address)p);
421 if (cb == NULL) {
422 tty->print_cr("NULL");
423 } else {
424 cb->print();
425 }
426 }
429 extern "C" void disnm(intptr_t p) {
430 Command c("disnm");
431 CodeBlob* cb = CodeCache::find_blob((address) p);
432 nmethod* nm = cb->as_nmethod_or_null();
433 if (nm) {
434 nm->print();
435 Disassembler::decode(nm);
436 } else {
437 cb->print();
438 Disassembler::decode(cb);
439 }
440 }
443 extern "C" void printnm(intptr_t p) {
444 char buffer[256];
445 sprintf(buffer, "printnm: " INTPTR_FORMAT, p);
446 Command c(buffer);
447 CodeBlob* cb = CodeCache::find_blob((address) p);
448 if (cb->is_nmethod()) {
449 nmethod* nm = (nmethod*)cb;
450 nm->print_nmethod(true);
451 }
452 }
455 extern "C" void universe() {
456 Command c("universe");
457 Universe::print();
458 }
461 extern "C" void verify() {
462 // try to run a verify on the entire system
463 // note: this may not be safe if we're not at a safepoint; for debugging,
464 // this manipulates the safepoint settings to avoid assertion failures
465 Command c("universe verify");
466 bool safe = SafepointSynchronize::is_at_safepoint();
467 if (!safe) {
468 tty->print_cr("warning: not at safepoint -- verify may fail");
469 SafepointSynchronize::set_is_at_safepoint();
470 }
471 // Ensure Eden top is correct before verification
472 Universe::heap()->prepare_for_verify();
473 Universe::verify();
474 if (!safe) SafepointSynchronize::set_is_not_at_safepoint();
475 }
478 extern "C" void pp(void* p) {
479 Command c("pp");
480 FlagSetting fl(PrintVMMessages, true);
481 FlagSetting f2(DisplayVMOutput, true);
482 if (Universe::heap()->is_in(p)) {
483 oop obj = oop(p);
484 obj->print();
485 } else {
486 tty->print(PTR_FORMAT, p);
487 }
488 }
491 // pv: print vm-printable object
492 extern "C" void pa(intptr_t p) { ((AllocatedObj*) p)->print(); }
493 extern "C" void findpc(intptr_t x);
495 #endif // !PRODUCT
497 extern "C" void ps() { // print stack
498 if (Thread::current() == NULL) return;
499 Command c("ps");
502 // Prints the stack of the current Java thread
503 JavaThread* p = JavaThread::active();
504 tty->print(" for thread: ");
505 p->print();
506 tty->cr();
508 if (p->has_last_Java_frame()) {
509 // If the last_Java_fp is set we are in C land and
510 // can call the standard stack_trace function.
511 #ifdef PRODUCT
512 p->print_stack();
513 } else {
514 tty->print_cr("Cannot find the last Java frame, printing stack disabled.");
515 #else // !PRODUCT
516 p->trace_stack();
517 } else {
518 frame f = os::current_frame();
519 RegisterMap reg_map(p);
520 f = f.sender(®_map);
521 tty->print("(guessing starting frame id=%#p based on current fp)\n", f.id());
522 p->trace_stack_from(vframe::new_vframe(&f, ®_map, p));
523 pd_ps(f);
524 #endif // PRODUCT
525 }
527 }
529 extern "C" void pfl() {
530 // print frame layout
531 Command c("pfl");
532 JavaThread* p = JavaThread::active();
533 tty->print(" for thread: ");
534 p->print();
535 tty->cr();
536 if (p->has_last_Java_frame()) {
537 p->print_frame_layout();
538 }
539 }
541 #ifndef PRODUCT
543 extern "C" void psf() { // print stack frames
544 {
545 Command c("psf");
546 JavaThread* p = JavaThread::active();
547 tty->print(" for thread: ");
548 p->print();
549 tty->cr();
550 if (p->has_last_Java_frame()) {
551 p->trace_frames();
552 }
553 }
554 }
557 extern "C" void threads() {
558 Command c("threads");
559 Threads::print(false, true);
560 }
563 extern "C" void psd() {
564 Command c("psd");
565 SystemDictionary::print();
566 }
569 extern "C" void safepoints() {
570 Command c("safepoints");
571 SafepointSynchronize::print_state();
572 }
574 #endif // !PRODUCT
576 extern "C" void pss() { // print all stacks
577 if (Thread::current() == NULL) return;
578 Command c("pss");
579 Threads::print(true, PRODUCT_ONLY(false) NOT_PRODUCT(true));
580 }
582 #ifndef PRODUCT
584 extern "C" void debug() { // to set things up for compiler debugging
585 Command c("debug");
586 WizardMode = true;
587 PrintVMMessages = PrintCompilation = true;
588 PrintInlining = PrintAssembly = true;
589 tty->flush();
590 }
593 extern "C" void ndebug() { // undo debug()
594 Command c("ndebug");
595 PrintCompilation = false;
596 PrintInlining = PrintAssembly = false;
597 tty->flush();
598 }
601 extern "C" void flush() {
602 Command c("flush");
603 tty->flush();
604 }
606 extern "C" void events() {
607 Command c("events");
608 Events::print();
609 }
611 extern "C" Method* findm(intptr_t pc) {
612 Command c("findm");
613 nmethod* nm = CodeCache::find_nmethod((address)pc);
614 return (nm == NULL) ? (Method*)NULL : nm->method();
615 }
618 extern "C" nmethod* findnm(intptr_t addr) {
619 Command c("findnm");
620 return CodeCache::find_nmethod((address)addr);
621 }
623 // Another interface that isn't ambiguous in dbx.
624 // Can we someday rename the other find to hsfind?
625 extern "C" void hsfind(intptr_t x) {
626 Command c("hsfind");
627 os::print_location(tty, x, false);
628 }
631 extern "C" void find(intptr_t x) {
632 Command c("find");
633 os::print_location(tty, x, false);
634 }
637 extern "C" void findpc(intptr_t x) {
638 Command c("findpc");
639 os::print_location(tty, x, true);
640 }
643 // Need method pointer to find bcp, when not in permgen.
644 extern "C" void findbcp(intptr_t method, intptr_t bcp) {
645 Command c("findbcp");
646 Method* mh = (Method*)method;
647 if (!mh->is_native()) {
648 tty->print_cr("bci_from(%p) = %d; print_codes():",
649 mh, mh->bci_from(address(bcp)));
650 mh->print_codes_on(tty);
651 }
652 }
654 // int versions of all methods to avoid having to type type casts in the debugger
656 void pp(intptr_t p) { pp((void*)p); }
657 void pp(oop p) { pp((void*)p); }
659 void help() {
660 Command c("help");
661 tty->print_cr("basic");
662 tty->print_cr(" pp(void* p) - try to make sense of p");
663 tty->print_cr(" pv(intptr_t p)- ((PrintableResourceObj*) p)->print()");
664 tty->print_cr(" ps() - print current thread stack");
665 tty->print_cr(" pss() - print all thread stacks");
666 tty->print_cr(" pm(int pc) - print Method* given compiled PC");
667 tty->print_cr(" findm(intptr_t pc) - finds Method*");
668 tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it");
669 tty->print_cr(" pns(void* sp, void* fp, void* pc) - print native (i.e. mixed) stack trace. E.g.");
670 tty->print_cr(" pns($sp, $rbp, $pc) on Linux/amd64 and Solaris/amd64 or");
671 tty->print_cr(" pns($sp, $ebp, $pc) on Linux/x86 or");
672 tty->print_cr(" pns($sp, 0, $pc) on Linux/ppc64 or");
673 tty->print_cr(" pns($sp + 0x7ff, 0, $pc) on Solaris/SPARC");
674 tty->print_cr(" - in gdb do 'set overload-resolution off' before calling pns()");
675 tty->print_cr(" - in dbx do 'frame 1' before calling pns()");
677 tty->print_cr("misc.");
678 tty->print_cr(" flush() - flushes the log file");
679 tty->print_cr(" events() - dump events from ring buffers");
682 tty->print_cr("compiler debugging");
683 tty->print_cr(" debug() - to set things up for compiler debugging");
684 tty->print_cr(" ndebug() - undo debug");
685 }
687 #endif // !PRODUCT
689 void print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int buf_size) {
691 // see if it's a valid frame
692 if (fr.pc()) {
693 st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
695 int count = 0;
696 while (count++ < StackPrintLimit) {
697 fr.print_on_error(st, buf, buf_size);
698 st->cr();
699 // Compiled code may use EBP register on x86 so it looks like
700 // non-walkable C frame. Use frame.sender() for java frames.
701 if (t && t->is_Java_thread()) {
702 // Catch very first native frame by using stack address.
703 // For JavaThread stack_base and stack_size should be set.
704 if (!t->on_local_stack((address)(fr.real_fp() + 1))) {
705 break;
706 }
707 if (fr.is_java_frame() || fr.is_native_frame() || fr.is_runtime_frame()) {
708 RegisterMap map((JavaThread*)t, false); // No update
709 fr = fr.sender(&map);
710 } else {
711 fr = os::get_sender_for_C_frame(&fr);
712 }
713 } else {
714 // is_first_C_frame() does only simple checks for frame pointer,
715 // it will pass if java compiled code has a pointer in EBP.
716 if (os::is_first_C_frame(&fr)) break;
717 fr = os::get_sender_for_C_frame(&fr);
718 }
719 }
721 if (count > StackPrintLimit) {
722 st->print_cr("...<more frames>...");
723 }
725 st->cr();
726 }
727 }
729 #ifndef PRODUCT
731 extern "C" void pns(void* sp, void* fp, void* pc) { // print native stack
732 Command c("pns");
733 static char buf[O_BUFLEN];
734 Thread* t = ThreadLocalStorage::get_thread_slow();
735 // Call generic frame constructor (certain arguments may be ignored)
736 frame fr(sp, fp, pc);
737 print_native_stack(tty, fr, t, buf, sizeof(buf));
738 }
740 #endif // !PRODUCT