35 #include "runtime/javaCalls.hpp" |
35 #include "runtime/javaCalls.hpp" |
36 #include "runtime/vframe.hpp" |
36 #include "runtime/vframe.hpp" |
37 #include "utilities/globalDefinitions.hpp" |
37 #include "utilities/globalDefinitions.hpp" |
38 |
38 |
39 // setup and cleanup actions |
39 // setup and cleanup actions |
40 void StackWalkAnchor::setup_magic_on_entry(objArrayHandle frames_array) { |
40 void JavaFrameStream::setup_magic_on_entry(objArrayHandle frames_array) { |
41 frames_array->obj_at_put(magic_pos, _thread->threadObj()); |
41 frames_array->obj_at_put(magic_pos, _thread->threadObj()); |
42 _anchor = address_value(); |
42 _anchor = address_value(); |
43 assert(check_magic(frames_array), "invalid magic"); |
43 assert(check_magic(frames_array), "invalid magic"); |
44 } |
44 } |
45 |
45 |
46 bool StackWalkAnchor::check_magic(objArrayHandle frames_array) { |
46 bool JavaFrameStream::check_magic(objArrayHandle frames_array) { |
47 oop m1 = frames_array->obj_at(magic_pos); |
47 oop m1 = frames_array->obj_at(magic_pos); |
48 jlong m2 = _anchor; |
48 jlong m2 = _anchor; |
49 if (m1 == _thread->threadObj() && m2 == address_value()) return true; |
49 if (m1 == _thread->threadObj() && m2 == address_value()) return true; |
50 return false; |
50 return false; |
51 } |
51 } |
52 |
52 |
53 bool StackWalkAnchor::cleanup_magic_on_exit(objArrayHandle frames_array) { |
53 bool JavaFrameStream::cleanup_magic_on_exit(objArrayHandle frames_array) { |
54 bool ok = check_magic(frames_array); |
54 bool ok = check_magic(frames_array); |
55 frames_array->obj_at_put(magic_pos, NULL); |
55 frames_array->obj_at_put(magic_pos, NULL); |
56 _anchor = 0L; |
56 _anchor = 0L; |
57 return ok; |
57 return ok; |
58 } |
58 } |
59 |
59 |
60 // Returns StackWalkAnchor for the current stack being traversed. |
60 // Returns JavaFrameStream for the current stack being traversed. |
61 // |
61 // |
62 // Parameters: |
62 // Parameters: |
63 // thread Current Java thread. |
63 // thread Current Java thread. |
64 // magic Magic value used for each stack walking |
64 // magic Magic value used for each stack walking |
65 // frames_array User-supplied buffers. The 0th element is reserved |
65 // frames_array User-supplied buffers. The 0th element is reserved |
66 // to this StackWalkAnchor to use |
66 // to this JavaFrameStream to use |
67 // |
67 // |
68 StackWalkAnchor* StackWalkAnchor::from_current(JavaThread* thread, jlong magic, |
68 JavaFrameStream* JavaFrameStream::from_current(JavaThread* thread, jlong magic, |
69 objArrayHandle frames_array) |
69 objArrayHandle frames_array) |
70 { |
70 { |
71 assert(thread != NULL && thread->is_Java_thread(), ""); |
71 assert(thread != NULL && thread->is_Java_thread(), ""); |
72 oop m1 = frames_array->obj_at(magic_pos); |
72 oop m1 = frames_array->obj_at(magic_pos); |
73 if (m1 != thread->threadObj()) return NULL; |
73 if (m1 != thread->threadObj()) return NULL; |
74 if (magic == 0L) return NULL; |
74 if (magic == 0L) return NULL; |
75 StackWalkAnchor* anchor = (StackWalkAnchor*) (intptr_t) magic; |
75 JavaFrameStream* stream = (JavaFrameStream*) (intptr_t) magic; |
76 if (!anchor->is_valid_in(thread, frames_array)) return NULL; |
76 if (!stream->is_valid_in(thread, frames_array)) return NULL; |
77 return anchor; |
77 return stream; |
78 } |
78 } |
79 |
79 |
80 // Unpacks one or more frames into user-supplied buffers. |
80 // Unpacks one or more frames into user-supplied buffers. |
81 // Updates the end index, and returns the number of unpacked frames. |
81 // Updates the end index, and returns the number of unpacked frames. |
82 // Always start with the existing vfst.method and bci. |
82 // Always start with the existing vfst.method and bci. |
83 // Do not call vfst.next to advance over the last returned value. |
83 // Do not call vfst.next to advance over the last returned value. |
84 // In other words, do not leave any stale data in the vfst. |
84 // In other words, do not leave any stale data in the vfst. |
85 // |
85 // |
86 // Parameters: |
86 // Parameters: |
87 // mode Restrict which frames to be decoded. |
87 // mode Restrict which frames to be decoded. |
88 // vfst vFrameStream. |
88 // JavaFrameStream stream of javaVFrames |
89 // max_nframes Maximum number of frames to be filled. |
89 // max_nframes Maximum number of frames to be filled. |
90 // start_index Start index to the user-supplied buffers. |
90 // start_index Start index to the user-supplied buffers. |
91 // frames_array Buffer to store Class or StackFrame in, starting at start_index. |
91 // frames_array Buffer to store Class or StackFrame in, starting at start_index. |
92 // frames array is a Class<?>[] array when only getting caller |
92 // frames array is a Class<?>[] array when only getting caller |
93 // reference, and a StackFrameInfo[] array (or derivative) |
93 // reference, and a StackFrameInfo[] array (or derivative) |
94 // otherwise. It should never be null. |
94 // otherwise. It should never be null. |
95 // end_index End index to the user-supplied buffers with unpacked frames. |
95 // end_index End index to the user-supplied buffers with unpacked frames. |
96 // |
96 // |
97 // Returns the number of frames whose information was transferred into the buffers. |
97 // Returns the number of frames whose information was transferred into the buffers. |
98 // |
98 // |
99 int StackWalk::fill_in_frames(jlong mode, vframeStream& vfst, |
99 int StackWalk::fill_in_frames(jlong mode, JavaFrameStream& stream, |
100 int max_nframes, int start_index, |
100 int max_nframes, int start_index, |
101 objArrayHandle frames_array, |
101 objArrayHandle frames_array, |
102 int& end_index, TRAPS) { |
102 int& end_index, TRAPS) { |
103 if (TraceStackWalk) { |
103 if (TraceStackWalk) { |
104 tty->print_cr("fill_in_frames limit=%d start=%d frames length=%d", |
104 tty->print_cr("fill_in_frames limit=%d start=%d frames length=%d", |
131 |
131 |
132 // fill in StackFrameInfo and initialize MemberName |
132 // fill in StackFrameInfo and initialize MemberName |
133 if (live_frame_info(mode)) { |
133 if (live_frame_info(mode)) { |
134 assert (use_frames_array(mode), "Bad mode for get live frame"); |
134 assert (use_frames_array(mode), "Bad mode for get live frame"); |
135 Handle stackFrame(frames_array->obj_at(index)); |
135 Handle stackFrame(frames_array->obj_at(index)); |
136 fill_live_stackframe(stackFrame, method, bci, vfst.java_frame(), CHECK_0); |
136 fill_live_stackframe(stackFrame, method, bci, stream.java_frame(), CHECK_0); |
137 } else if (need_method_info(mode)) { |
137 } else if (need_method_info(mode)) { |
138 assert (use_frames_array(mode), "Bad mode for get stack frame"); |
138 assert (use_frames_array(mode), "Bad mode for get stack frame"); |
139 Handle stackFrame(frames_array->obj_at(index)); |
139 Handle stackFrame(frames_array->obj_at(index)); |
140 fill_stackframe(stackFrame, method, bci); |
140 fill_stackframe(stackFrame, method, bci); |
141 } else { |
141 } else { |
307 Klass* stackWalker_klass = SystemDictionary::StackWalker_klass(); |
308 Klass* stackWalker_klass = SystemDictionary::StackWalker_klass(); |
308 Klass* abstractStackWalker_klass = SystemDictionary::AbstractStackWalker_klass(); |
309 Klass* abstractStackWalker_klass = SystemDictionary::AbstractStackWalker_klass(); |
309 |
310 |
310 methodHandle m_doStackWalk(THREAD, Universe::do_stack_walk_method()); |
311 methodHandle m_doStackWalk(THREAD, Universe::do_stack_walk_method()); |
311 |
312 |
312 // Open up a traversable stream onto my stack. |
313 // Setup traversal onto my stack. |
313 // This stream will be made available by *reference* to the inner Java call. |
314 RegisterMap regMap(jt, true); |
314 StackWalkAnchor anchor(jt); |
315 JavaFrameStream stream(jt, ®Map); |
315 vframeStream& vfst = anchor.vframe_stream(); |
|
316 |
|
317 { |
316 { |
318 while (!vfst.at_end()) { |
317 while (!stream.at_end()) { |
319 InstanceKlass* ik = vfst.method()->method_holder(); |
318 InstanceKlass* ik = stream.method()->method_holder(); |
320 if (ik != stackWalker_klass && |
319 if (ik != stackWalker_klass && |
321 ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass) { |
320 ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass) { |
322 break; |
321 break; |
323 } |
322 } |
324 |
323 |
325 if (TraceStackWalk) { |
324 if (TraceStackWalk) { |
326 tty->print(" skip "); vfst.method()->print_short_name(); tty->print("\n"); |
325 tty->print(" skip "); stream.method()->print_short_name(); tty->print("\n"); |
327 } |
326 } |
328 vfst.next(); |
327 stream.next(); |
329 } |
328 } |
330 |
329 |
331 // stack frame has been traversed individually and resume stack walk |
330 // stack frame has been traversed individually and resume stack walk |
332 // from the stack frame at depth == skip_frames. |
331 // from the stack frame at depth == skip_frames. |
333 for (int n=0; n < skip_frames && !vfst.at_end(); vfst.next(), n++) { |
332 for (int n=0; n < skip_frames && !stream.at_end(); stream.next(), n++) { |
334 if (TraceStackWalk) { |
333 if (TraceStackWalk) { |
335 tty->print(" skip "); vfst.method()->print_short_name(); |
334 tty->print(" skip "); stream.method()->print_short_name(); |
336 tty->print_cr(" frame id: " PTR_FORMAT " pc: " PTR_FORMAT, |
335 tty->print_cr(" frame id: " PTR_FORMAT " pc: " PTR_FORMAT, |
337 p2i(vfst.frame_id()), p2i(vfst.frame_pc())); |
336 p2i(stream.java_frame()->fr().id()), |
|
337 p2i(stream.java_frame()->fr().pc())); |
338 } |
338 } |
339 } |
339 } |
340 } |
340 } |
341 |
341 |
342 // The Method* pointer in the vfst has a very short shelf life. Grab it now. |
|
343 int end_index = start_index; |
342 int end_index = start_index; |
344 int numFrames = 0; |
343 int numFrames = 0; |
345 if (!vfst.at_end()) { |
344 if (!stream.at_end()) { |
346 numFrames = fill_in_frames(mode, vfst, frame_count, start_index, |
345 numFrames = fill_in_frames(mode, stream, frame_count, start_index, |
347 frames_array, end_index, CHECK_NULL); |
346 frames_array, end_index, CHECK_NULL); |
348 if (numFrames < 1) { |
347 if (numFrames < 1) { |
349 THROW_MSG_(vmSymbols::java_lang_InternalError(), "stack walk: decode failed", NULL); |
348 THROW_MSG_(vmSymbols::java_lang_InternalError(), "stack walk: decode failed", NULL); |
350 } |
349 } |
351 } |
350 } |
354 // Java method java.lang.StackStreamFactory.AbstractStackWalker::doStackWalk |
353 // Java method java.lang.StackStreamFactory.AbstractStackWalker::doStackWalk |
355 // which calls the implementation to consume the stack frames. |
354 // which calls the implementation to consume the stack frames. |
356 // When JVM_CallStackWalk returns, it invalidates the stack stream. |
355 // When JVM_CallStackWalk returns, it invalidates the stack stream. |
357 JavaValue result(T_OBJECT); |
356 JavaValue result(T_OBJECT); |
358 JavaCallArguments args(stackStream); |
357 JavaCallArguments args(stackStream); |
359 args.push_long(anchor.address_value()); |
358 args.push_long(stream.address_value()); |
360 args.push_int(skip_frames); |
359 args.push_int(skip_frames); |
361 args.push_int(frame_count); |
360 args.push_int(frame_count); |
362 args.push_int(start_index); |
361 args.push_int(start_index); |
363 args.push_int(end_index); |
362 args.push_int(end_index); |
364 |
363 |
365 // Link the thread and vframe stream into the callee-visible object |
364 // Link the thread and vframe stream into the callee-visible object |
366 anchor.setup_magic_on_entry(frames_array); |
365 stream.setup_magic_on_entry(frames_array); |
367 |
366 |
368 JavaCalls::call(&result, m_doStackWalk, &args, THREAD); |
367 JavaCalls::call(&result, m_doStackWalk, &args, THREAD); |
369 |
368 |
370 // Do this before anything else happens, to disable any lingering stream objects |
369 // Do this before anything else happens, to disable any lingering stream objects |
371 bool ok = anchor.cleanup_magic_on_exit(frames_array); |
370 bool ok = stream.cleanup_magic_on_exit(frames_array); |
372 |
371 |
373 // Throw pending exception if we must |
372 // Throw pending exception if we must |
374 (void) (CHECK_NULL); |
373 (void) (CHECK_NULL); |
375 |
374 |
376 if (!ok) { |
375 if (!ok) { |
377 THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers on exit", NULL); |
376 THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers on exit", NULL); |
378 } |
377 } |
379 |
378 |
380 // Return normally |
379 // Return normally |
381 return (oop)result.get_jobject(); |
380 return (oop)result.get_jobject(); |
382 |
|
383 } |
381 } |
384 |
382 |
385 // Walk the next batch of stack frames |
383 // Walk the next batch of stack frames |
386 // |
384 // |
387 // Parameters: |
385 // Parameters: |
398 int frame_count, int start_index, |
396 int frame_count, int start_index, |
399 objArrayHandle frames_array, |
397 objArrayHandle frames_array, |
400 TRAPS) |
398 TRAPS) |
401 { |
399 { |
402 JavaThread* jt = (JavaThread*)THREAD; |
400 JavaThread* jt = (JavaThread*)THREAD; |
403 StackWalkAnchor* existing_anchor = StackWalkAnchor::from_current(jt, magic, frames_array); |
401 JavaFrameStream* existing_stream = JavaFrameStream::from_current(jt, magic, frames_array); |
404 if (existing_anchor == NULL) { |
402 if (existing_stream == NULL) { |
405 THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers", 0L); |
403 THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers", 0L); |
406 } |
404 } |
407 |
405 |
408 if (frames_array.is_null()) { |
406 if (frames_array.is_null()) { |
409 THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", 0L); |
407 THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", 0L); |
410 } |
408 } |
411 |
409 |
412 if (TraceStackWalk) { |
410 if (TraceStackWalk) { |
413 tty->print_cr("StackWalk::moreFrames frame_count %d existing_anchor " PTR_FORMAT " start %d frames %d", |
411 tty->print_cr("StackWalk::moreFrames frame_count %d existing_stream " PTR_FORMAT " start %d frames %d", |
414 frame_count, p2i(existing_anchor), start_index, frames_array->length()); |
412 frame_count, p2i(existing_stream), start_index, frames_array->length()); |
415 } |
413 } |
416 int end_index = start_index; |
414 int end_index = start_index; |
417 if (frame_count <= 0) { |
415 if (frame_count <= 0) { |
418 return end_index; // No operation. |
416 return end_index; // No operation. |
419 } |
417 } |
420 |
418 |
421 int count = frame_count + start_index; |
419 int count = frame_count + start_index; |
422 assert (frames_array->length() >= count, "not enough space in buffers"); |
420 assert (frames_array->length() >= count, "not enough space in buffers"); |
423 |
421 |
424 StackWalkAnchor& anchor = (*existing_anchor); |
422 JavaFrameStream& stream = (*existing_stream); |
425 vframeStream& vfst = anchor.vframe_stream(); |
423 if (!stream.at_end()) { |
426 if (!vfst.at_end()) { |
424 stream.next(); // advance past the last frame decoded in previous batch |
427 vfst.next(); // this was the last frame decoded in the previous batch |
425 if (!stream.at_end()) { |
428 if (!vfst.at_end()) { |
426 int n = fill_in_frames(mode, stream, frame_count, start_index, |
429 int n = fill_in_frames(mode, vfst, frame_count, start_index, |
|
430 frames_array, end_index, CHECK_0); |
427 frames_array, end_index, CHECK_0); |
431 if (n < 1) { |
428 if (n < 1) { |
432 THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: later decode failed", 0L); |
429 THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: later decode failed", 0L); |
433 } |
430 } |
434 return end_index; |
431 return end_index; |