8316456: StackWalker may skip Continuation::yield0 frame mistakenly
Reviewed-by: rpressler, pchilanomate
This commit is contained in:
parent
041510dc21
commit
c72f00463f
@ -255,11 +255,11 @@ JVM_ExpandStackFrameInfo(JNIEnv *env, jobject obj);
|
|||||||
JNIEXPORT jobject JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jint mode,
|
JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jint mode,
|
||||||
jint skip_frames, jobject contScope, jobject cont,
|
jint skip_frames, jobject contScope, jobject cont,
|
||||||
jint frame_count, jint start_index, jobjectArray frames);
|
jint buffer_size, jint start_index, jobjectArray frames);
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jint mode, jlong anchor,
|
JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jint mode, jlong anchor,
|
||||||
jint frame_count, jint start_index,
|
jint last_batch_count, jint buffer_size, jint start_index,
|
||||||
jobjectArray frames);
|
jobjectArray frames);
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
|
@ -565,7 +565,7 @@ JVM_END
|
|||||||
|
|
||||||
JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jint mode,
|
JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jint mode,
|
||||||
jint skip_frames, jobject contScope, jobject cont,
|
jint skip_frames, jobject contScope, jobject cont,
|
||||||
jint frame_count, jint start_index, jobjectArray frames))
|
jint buffer_size, jint start_index, jobjectArray frames))
|
||||||
if (!thread->has_last_Java_frame()) {
|
if (!thread->has_last_Java_frame()) {
|
||||||
THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: no stack trace", nullptr);
|
THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: no stack trace", nullptr);
|
||||||
}
|
}
|
||||||
@ -579,19 +579,18 @@ JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jint mode
|
|||||||
objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames));
|
objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames));
|
||||||
objArrayHandle frames_array_h(THREAD, fa);
|
objArrayHandle frames_array_h(THREAD, fa);
|
||||||
|
|
||||||
int limit = start_index + frame_count;
|
if (frames_array_h->length() < buffer_size) {
|
||||||
if (frames_array_h->length() < limit) {
|
|
||||||
THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers", nullptr);
|
THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers", nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
oop result = StackWalk::walk(stackStream_h, mode, skip_frames, contScope_h, cont_h,
|
oop result = StackWalk::walk(stackStream_h, mode, skip_frames, contScope_h, cont_h,
|
||||||
frame_count, start_index, frames_array_h, CHECK_NULL);
|
buffer_size, start_index, frames_array_h, CHECK_NULL);
|
||||||
return JNIHandles::make_local(THREAD, result);
|
return JNIHandles::make_local(THREAD, result);
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
|
|
||||||
JVM_ENTRY(jint, JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jint mode, jlong anchor,
|
JVM_ENTRY(jint, JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jint mode, jlong anchor,
|
||||||
jint frame_count, jint start_index,
|
jint last_batch_count, jint buffer_size, jint start_index,
|
||||||
jobjectArray frames))
|
jobjectArray frames))
|
||||||
// frames array is a ClassFrameInfo[] array when only getting caller reference,
|
// frames array is a ClassFrameInfo[] array when only getting caller reference,
|
||||||
// and a StackFrameInfo[] array (or derivative) otherwise. It should never
|
// and a StackFrameInfo[] array (or derivative) otherwise. It should never
|
||||||
@ -599,13 +598,12 @@ JVM_ENTRY(jint, JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jint mode, j
|
|||||||
objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames));
|
objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames));
|
||||||
objArrayHandle frames_array_h(THREAD, fa);
|
objArrayHandle frames_array_h(THREAD, fa);
|
||||||
|
|
||||||
int limit = start_index+frame_count;
|
if (frames_array_h->length() < buffer_size) {
|
||||||
if (frames_array_h->length() < limit) {
|
|
||||||
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers");
|
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers");
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream));
|
Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream));
|
||||||
return StackWalk::fetchNextBatch(stackStream_h, mode, anchor, frame_count,
|
return StackWalk::fetchNextBatch(stackStream_h, mode, anchor, last_batch_count, buffer_size,
|
||||||
start_index, frames_array_h, THREAD);
|
start_index, frames_array_h, THREAD);
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ BaseFrameStream* BaseFrameStream::from_current(JavaThread* thread, jlong magic,
|
|||||||
// Parameters:
|
// Parameters:
|
||||||
// mode Restrict which frames to be decoded.
|
// mode Restrict which frames to be decoded.
|
||||||
// BaseFrameStream stream of frames
|
// BaseFrameStream stream of frames
|
||||||
// max_nframes Maximum number of frames to be filled.
|
// buffer_size Buffer size
|
||||||
// start_index Start index to the user-supplied buffers.
|
// start_index Start index to the user-supplied buffers.
|
||||||
// frames_array Buffer to store stack frame information in, starting at start_index.
|
// frames_array Buffer to store stack frame information in, starting at start_index.
|
||||||
// frames array is a ClassFrameInfo[] array when only getting caller
|
// frames array is a ClassFrameInfo[] array when only getting caller
|
||||||
@ -163,13 +163,13 @@ BaseFrameStream* BaseFrameStream::from_current(JavaThread* thread, jlong magic,
|
|||||||
// Returns the number of frames whose information was transferred into the buffers.
|
// Returns the number of frames whose information was transferred into the buffers.
|
||||||
//
|
//
|
||||||
int StackWalk::fill_in_frames(jint mode, BaseFrameStream& stream,
|
int StackWalk::fill_in_frames(jint mode, BaseFrameStream& stream,
|
||||||
int max_nframes, int start_index,
|
int buffer_size, int start_index,
|
||||||
objArrayHandle frames_array,
|
objArrayHandle frames_array,
|
||||||
int& end_index, TRAPS) {
|
int& end_index, TRAPS) {
|
||||||
log_debug(stackwalk)("fill_in_frames limit=%d start=%d frames length=%d",
|
log_debug(stackwalk)("fill_in_frames limit=%d start=%d frames length=%d",
|
||||||
max_nframes, start_index, frames_array->length());
|
buffer_size, start_index, frames_array->length());
|
||||||
assert(max_nframes > 0, "invalid max_nframes");
|
assert(buffer_size > 0, "invalid buffer_size");
|
||||||
assert(start_index + max_nframes <= frames_array->length(), "oob");
|
assert(buffer_size <= frames_array->length(), "oob");
|
||||||
|
|
||||||
int frames_decoded = 0;
|
int frames_decoded = 0;
|
||||||
for (; !stream.at_end(); stream.next()) {
|
for (; !stream.at_end(); stream.next()) {
|
||||||
@ -186,49 +186,27 @@ int StackWalk::fill_in_frames(jint mode, BaseFrameStream& stream,
|
|||||||
|
|
||||||
// skip hidden frames for default StackWalker option (i.e. SHOW_HIDDEN_FRAMES
|
// skip hidden frames for default StackWalker option (i.e. SHOW_HIDDEN_FRAMES
|
||||||
// not set) and when StackWalker::getCallerClass is called
|
// not set) and when StackWalker::getCallerClass is called
|
||||||
LogTarget(Debug, stackwalk) lt;
|
|
||||||
if (!ShowHiddenFrames && skip_hidden_frames(mode)) {
|
if (!ShowHiddenFrames && skip_hidden_frames(mode)) {
|
||||||
if (method->is_hidden()) {
|
if (method->is_hidden()) {
|
||||||
if (lt.is_enabled()) {
|
log_debug(stackwalk)(" skip hidden method: %s", stream.method()->external_name());
|
||||||
ResourceMark rm(THREAD);
|
|
||||||
LogStream ls(lt);
|
|
||||||
ls.print(" skip hidden method: ");
|
|
||||||
method->print_short_name(&ls);
|
|
||||||
ls.cr();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We end a batch on continuation bottom to let the Java side skip top frames of the next one
|
// End a batch on continuation bottom to let the Java side to set the continuation to its parent and continue
|
||||||
if (stream.continuation() != nullptr && method->intrinsic_id() == vmIntrinsics::_Continuation_enter) break;
|
if (stream.continuation() != nullptr && method->intrinsic_id() == vmIntrinsics::_Continuation_enter) break;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = end_index++;
|
int index = end_index++;
|
||||||
if (lt.is_enabled()) {
|
log_debug(stackwalk)(" frame %d: %s bci %d", index, stream.method()->external_name(), stream.bci());
|
||||||
ResourceMark rm(THREAD);
|
|
||||||
LogStream ls(lt);
|
|
||||||
ls.print(" %d: frame method: ", index);
|
|
||||||
method->print_short_name(&ls);
|
|
||||||
ls.print_cr(" bci=%d", stream.bci());
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill in StackFrameInfo and initialize MemberName
|
|
||||||
stream.fill_frame(index, frames_array, methodHandle(THREAD, method), CHECK_0);
|
stream.fill_frame(index, frames_array, methodHandle(THREAD, method), CHECK_0);
|
||||||
|
|
||||||
if (lt.is_enabled()) {
|
|
||||||
ResourceMark rm(THREAD);
|
|
||||||
LogStream ls(lt);
|
|
||||||
ls.print(" %d: done frame method: ", index);
|
|
||||||
method->print_short_name(&ls);
|
|
||||||
}
|
|
||||||
frames_decoded++;
|
frames_decoded++;
|
||||||
|
|
||||||
// We end a batch on continuation bottom to let the Java side skip top frames of the next one
|
// End a batch on continuation bottom to let the Java side to set the continuation to its parent and continue
|
||||||
if (stream.continuation() != nullptr && method->intrinsic_id() == vmIntrinsics::_Continuation_enter) break;
|
if (stream.continuation() != nullptr && method->intrinsic_id() == vmIntrinsics::_Continuation_enter) break;
|
||||||
|
|
||||||
if (frames_decoded >= max_nframes) break;
|
if (end_index >= buffer_size) break;
|
||||||
}
|
}
|
||||||
log_debug(stackwalk)("fill_in_frames done frames_decoded=%d at_end=%d", frames_decoded, stream.at_end());
|
log_debug(stackwalk)("fill_in_frames returns %d at_end=%d", frames_decoded, stream.at_end());
|
||||||
|
|
||||||
return frames_decoded;
|
return frames_decoded;
|
||||||
}
|
}
|
||||||
@ -398,7 +376,7 @@ void LiveFrameStream::fill_live_stackframe(Handle stackFrame,
|
|||||||
// mode Stack walking mode.
|
// mode Stack walking mode.
|
||||||
// skip_frames Number of frames to be skipped.
|
// skip_frames Number of frames to be skipped.
|
||||||
// cont_scope Continuation scope to walk (if not in this scope, we'll walk all the way).
|
// cont_scope Continuation scope to walk (if not in this scope, we'll walk all the way).
|
||||||
// frame_count Number of frames to be traversed.
|
// buffer_size Buffer size.
|
||||||
// start_index Start index to the user-supplied buffers.
|
// start_index Start index to the user-supplied buffers.
|
||||||
// frames_array Buffer to store stack frame info in, starting at start_index.
|
// frames_array Buffer to store stack frame info in, starting at start_index.
|
||||||
// frames array is a ClassFrameInfo[] array when only getting caller
|
// frames array is a ClassFrameInfo[] array when only getting caller
|
||||||
@ -408,13 +386,13 @@ void LiveFrameStream::fill_live_stackframe(Handle stackFrame,
|
|||||||
// Returns Object returned from AbstractStackWalker::doStackWalk call.
|
// Returns Object returned from AbstractStackWalker::doStackWalk call.
|
||||||
//
|
//
|
||||||
oop StackWalk::walk(Handle stackStream, jint mode, int skip_frames, Handle cont_scope, Handle cont,
|
oop StackWalk::walk(Handle stackStream, jint mode, int skip_frames, Handle cont_scope, Handle cont,
|
||||||
int frame_count, int start_index, objArrayHandle frames_array,
|
int buffer_size, int start_index, objArrayHandle frames_array,
|
||||||
TRAPS) {
|
TRAPS) {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
HandleMark hm(THREAD); // needed to store a continuation in the RegisterMap
|
HandleMark hm(THREAD); // needed to store a continuation in the RegisterMap
|
||||||
|
|
||||||
JavaThread* jt = THREAD;
|
JavaThread* jt = THREAD;
|
||||||
log_debug(stackwalk)("Start walking: mode " INT32_FORMAT_X " skip %d frames batch size %d", mode, skip_frames, frame_count);
|
log_debug(stackwalk)("Start walking: mode " INT32_FORMAT_X " skip %d frames, buffer size %d", mode, skip_frames, buffer_size);
|
||||||
LogTarget(Debug, stackwalk) lt;
|
LogTarget(Debug, stackwalk) lt;
|
||||||
if (lt.is_enabled()) {
|
if (lt.is_enabled()) {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
@ -438,17 +416,17 @@ oop StackWalk::walk(Handle stackStream, jint mode, int skip_frames, Handle cont_
|
|||||||
RegisterMap::WalkContinuation::include)
|
RegisterMap::WalkContinuation::include)
|
||||||
: RegisterMap(cont(), RegisterMap::UpdateMap::include);
|
: RegisterMap(cont(), RegisterMap::UpdateMap::include);
|
||||||
LiveFrameStream stream(jt, ®Map, cont_scope, cont);
|
LiveFrameStream stream(jt, ®Map, cont_scope, cont);
|
||||||
return fetchFirstBatch(stream, stackStream, mode, skip_frames, frame_count,
|
return fetchFirstBatch(stream, stackStream, mode, skip_frames, buffer_size,
|
||||||
start_index, frames_array, THREAD);
|
start_index, frames_array, THREAD);
|
||||||
} else {
|
} else {
|
||||||
JavaFrameStream stream(jt, mode, cont_scope, cont);
|
JavaFrameStream stream(jt, mode, cont_scope, cont);
|
||||||
return fetchFirstBatch(stream, stackStream, mode, skip_frames, frame_count,
|
return fetchFirstBatch(stream, stackStream, mode, skip_frames, buffer_size,
|
||||||
start_index, frames_array, THREAD);
|
start_index, frames_array, THREAD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
|
oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
|
||||||
jint mode, int skip_frames, int frame_count,
|
jint mode, int skip_frames, int buffer_size,
|
||||||
int start_index, objArrayHandle frames_array, TRAPS) {
|
int start_index, objArrayHandle frames_array, TRAPS) {
|
||||||
methodHandle m_doStackWalk(THREAD, Universe::do_stack_walk_method());
|
methodHandle m_doStackWalk(THREAD, Universe::do_stack_walk_method());
|
||||||
|
|
||||||
@ -461,29 +439,14 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
|
|||||||
ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass) {
|
ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
log_debug(stackwalk)(" skip %s", stream.method()->external_name());
|
||||||
LogTarget(Debug, stackwalk) lt;
|
|
||||||
if (lt.is_enabled()) {
|
|
||||||
ResourceMark rm(THREAD);
|
|
||||||
LogStream ls(lt);
|
|
||||||
ls.print(" skip ");
|
|
||||||
stream.method()->print_short_name(&ls);
|
|
||||||
ls.cr();
|
|
||||||
}
|
|
||||||
stream.next();
|
stream.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// stack frame has been traversed individually and resume stack walk
|
// stack frame has been traversed individually and resume stack walk
|
||||||
// from the stack frame at depth == skip_frames.
|
// from the stack frame at depth == skip_frames.
|
||||||
for (int n=0; n < skip_frames && !stream.at_end(); stream.next(), n++) {
|
for (int n=0; n < skip_frames && !stream.at_end(); stream.next(), n++) {
|
||||||
LogTarget(Debug, stackwalk) lt;
|
log_debug(stackwalk)(" skip %s", stream.method()->external_name());
|
||||||
if (lt.is_enabled()) {
|
|
||||||
ResourceMark rm(THREAD);
|
|
||||||
LogStream ls(lt);
|
|
||||||
ls.print(" skip ");
|
|
||||||
stream.method()->print_short_name(&ls);
|
|
||||||
ls.cr();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,7 +454,7 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
|
|||||||
int numFrames = 0;
|
int numFrames = 0;
|
||||||
if (!stream.at_end()) {
|
if (!stream.at_end()) {
|
||||||
KeepStackGCProcessedMark keep_stack(THREAD);
|
KeepStackGCProcessedMark keep_stack(THREAD);
|
||||||
numFrames = fill_in_frames(mode, stream, frame_count, start_index,
|
numFrames = fill_in_frames(mode, stream, buffer_size, start_index,
|
||||||
frames_array, end_index, CHECK_NULL);
|
frames_array, end_index, CHECK_NULL);
|
||||||
if (numFrames < 1) {
|
if (numFrames < 1) {
|
||||||
THROW_MSG_(vmSymbols::java_lang_InternalError(), "stack walk: decode failed", nullptr);
|
THROW_MSG_(vmSymbols::java_lang_InternalError(), "stack walk: decode failed", nullptr);
|
||||||
@ -506,7 +469,7 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
|
|||||||
JavaCallArguments args(stackStream);
|
JavaCallArguments args(stackStream);
|
||||||
args.push_long(stream.address_value());
|
args.push_long(stream.address_value());
|
||||||
args.push_int(skip_frames);
|
args.push_int(skip_frames);
|
||||||
args.push_int(frame_count);
|
args.push_int(numFrames);
|
||||||
args.push_int(start_index);
|
args.push_int(start_index);
|
||||||
args.push_int(end_index);
|
args.push_int(end_index);
|
||||||
|
|
||||||
@ -535,14 +498,15 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
|
|||||||
// stackStream StackStream object
|
// stackStream StackStream object
|
||||||
// mode Stack walking mode.
|
// mode Stack walking mode.
|
||||||
// magic Must be valid value to continue the stack walk
|
// magic Must be valid value to continue the stack walk
|
||||||
// frame_count Number of frames to be decoded.
|
// last_batch_count Number of frames fetched in the last batch.
|
||||||
|
// buffer_size Buffer size.
|
||||||
// start_index Start index to the user-supplied buffers.
|
// start_index Start index to the user-supplied buffers.
|
||||||
// frames_array Buffer to store StackFrame in, starting at start_index.
|
// frames_array Buffer to store StackFrame in, starting at start_index.
|
||||||
//
|
//
|
||||||
// Returns the end index of frame filled in the buffer.
|
// Returns the number of frames filled in the buffer.
|
||||||
//
|
//
|
||||||
jint StackWalk::fetchNextBatch(Handle stackStream, jint mode, jlong magic,
|
jint StackWalk::fetchNextBatch(Handle stackStream, jint mode, jlong magic,
|
||||||
int frame_count, int start_index,
|
int last_batch_count, int buffer_size, int start_index,
|
||||||
objArrayHandle frames_array,
|
objArrayHandle frames_array,
|
||||||
TRAPS)
|
TRAPS)
|
||||||
{
|
{
|
||||||
@ -556,16 +520,15 @@ jint StackWalk::fetchNextBatch(Handle stackStream, jint mode, jlong magic,
|
|||||||
THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is null", 0L);
|
THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is null", 0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug(stackwalk)("StackWalk::fetchNextBatch frame_count %d existing_stream "
|
log_debug(stackwalk)("StackWalk::fetchNextBatch last_batch_count %d buffer_size %d existing_stream "
|
||||||
PTR_FORMAT " start %d frames %d",
|
PTR_FORMAT " start %d", last_batch_count,
|
||||||
frame_count, p2i(existing_stream), start_index, frames_array->length());
|
buffer_size, p2i(existing_stream), start_index, frames_array->length());
|
||||||
int end_index = start_index;
|
int end_index = start_index;
|
||||||
if (frame_count <= 0) {
|
if (buffer_size <= start_index) {
|
||||||
return end_index; // No operation.
|
return 0; // No operation.
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = frame_count + start_index;
|
assert (frames_array->length() >= buffer_size, "frames_array length < buffer_size");
|
||||||
assert (frames_array->length() >= count, "not enough space in buffers");
|
|
||||||
|
|
||||||
BaseFrameStream& stream = (*existing_stream);
|
BaseFrameStream& stream = (*existing_stream);
|
||||||
if (!stream.at_end()) {
|
if (!stream.at_end()) {
|
||||||
@ -574,17 +537,27 @@ jint StackWalk::fetchNextBatch(Handle stackStream, jint mode, jlong magic,
|
|||||||
// peeking at a few frames. Take the cost of flushing out any pending deferred GC
|
// peeking at a few frames. Take the cost of flushing out any pending deferred GC
|
||||||
// processing of the stack.
|
// processing of the stack.
|
||||||
KeepStackGCProcessedMark keep_stack(jt);
|
KeepStackGCProcessedMark keep_stack(jt);
|
||||||
stream.next(); // advance past the last frame decoded in previous batch
|
|
||||||
|
// Advance past the last frame decoded in the previous batch.
|
||||||
|
// If the last batch is empty, it means that the last batch returns after
|
||||||
|
// it advanced the frame it previously decoded as it reaches the bottom of
|
||||||
|
// the continuation and it returns to let Java side set the continuation.
|
||||||
|
// Now this batch starts right at the first frame of another continuation.
|
||||||
|
if (last_batch_count > 0) {
|
||||||
|
log_debug(stackwalk)("advanced past %s", stream.method()->external_name());
|
||||||
|
stream.next();
|
||||||
|
}
|
||||||
|
|
||||||
if (!stream.at_end()) {
|
if (!stream.at_end()) {
|
||||||
int n = fill_in_frames(mode, stream, frame_count, start_index,
|
int numFrames = fill_in_frames(mode, stream, buffer_size, start_index,
|
||||||
frames_array, end_index, CHECK_0);
|
frames_array, end_index, CHECK_0);
|
||||||
if (n < 1 && !skip_hidden_frames(mode)) {
|
if (numFrames < 1 && !skip_hidden_frames(mode)) {
|
||||||
THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: later decode failed", 0L);
|
THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: later decode failed", 0L);
|
||||||
}
|
}
|
||||||
return end_index;
|
return numFrames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return end_index;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackWalk::setContinuation(Handle stackStream, jlong magic, objArrayHandle frames_array, Handle cont, TRAPS) {
|
void StackWalk::setContinuation(Handle stackStream, jlong magic, objArrayHandle frames_array, Handle cont, TRAPS) {
|
||||||
|
@ -143,7 +143,7 @@ public:
|
|||||||
class StackWalk : public AllStatic {
|
class StackWalk : public AllStatic {
|
||||||
private:
|
private:
|
||||||
static int fill_in_frames(jint mode, BaseFrameStream& stream,
|
static int fill_in_frames(jint mode, BaseFrameStream& stream,
|
||||||
int max_nframes, int start_index,
|
int buffer_size, int start_index,
|
||||||
objArrayHandle frames_array,
|
objArrayHandle frames_array,
|
||||||
int& end_index, TRAPS);
|
int& end_index, TRAPS);
|
||||||
|
|
||||||
@ -160,15 +160,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static oop walk(Handle stackStream, jint mode, int skip_frames, Handle cont_scope, Handle cont,
|
static oop walk(Handle stackStream, jint mode, int skip_frames, Handle cont_scope, Handle cont,
|
||||||
int frame_count, int start_index, objArrayHandle frames_array,
|
int buffer_size, int start_index, objArrayHandle frames_array,
|
||||||
TRAPS);
|
TRAPS);
|
||||||
|
|
||||||
static oop fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
|
static oop fetchFirstBatch(BaseFrameStream& stream, Handle stackStream,
|
||||||
jint mode, int skip_frames, int frame_count,
|
jint mode, int skip_frames, int buffer_size,
|
||||||
int start_index, objArrayHandle frames_array, TRAPS);
|
int start_index, objArrayHandle frames_array, TRAPS);
|
||||||
|
|
||||||
static jint fetchNextBatch(Handle stackStream, jint mode, jlong magic,
|
static jint fetchNextBatch(Handle stackStream, jint mode, jlong magic,
|
||||||
int frame_count, int start_index,
|
int last_batch_count, int buffer_size, int start_index,
|
||||||
objArrayHandle frames_array, TRAPS);
|
objArrayHandle frames_array, TRAPS);
|
||||||
|
|
||||||
static void setContinuation(Handle stackStream, jlong magic, objArrayHandle frames_array,
|
static void setContinuation(Handle stackStream, jlong magic, objArrayHandle frames_array,
|
||||||
|
@ -192,10 +192,10 @@ final class StackStreamFactory {
|
|||||||
*
|
*
|
||||||
* Subclass should override this method to change the batch size
|
* Subclass should override this method to change the batch size
|
||||||
*
|
*
|
||||||
* @param lastBatchFrameCount number of frames in the last batch; or zero
|
* @param lastBatchSize last batch size
|
||||||
* @return suggested batch size
|
* @return suggested batch size
|
||||||
*/
|
*/
|
||||||
protected abstract int batchSize(int lastBatchFrameCount);
|
protected abstract int batchSize(int lastBatchSize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the next batch size, always >= minimum batch size
|
* Returns the next batch size, always >= minimum batch size
|
||||||
@ -203,7 +203,7 @@ final class StackStreamFactory {
|
|||||||
* Subclass may override this method if the minimum batch size is different.
|
* Subclass may override this method if the minimum batch size is different.
|
||||||
*/
|
*/
|
||||||
protected int getNextBatchSize() {
|
protected int getNextBatchSize() {
|
||||||
int lastBatchSize = depth == 0 ? 0 : frameBuffer.curBatchFrameCount();
|
int lastBatchSize = depth == 0 ? 0 : frameBuffer.currentBatchSize();
|
||||||
int nextBatchSize = batchSize(lastBatchSize);
|
int nextBatchSize = batchSize(lastBatchSize);
|
||||||
if (isDebug) {
|
if (isDebug) {
|
||||||
System.err.println("last batch size = " + lastBatchSize +
|
System.err.println("last batch size = " + lastBatchSize +
|
||||||
@ -312,19 +312,19 @@ final class StackStreamFactory {
|
|||||||
* 2. reuse or expand the allocated buffers
|
* 2. reuse or expand the allocated buffers
|
||||||
* 3. create specialized StackFrame objects
|
* 3. create specialized StackFrame objects
|
||||||
*/
|
*/
|
||||||
private Object doStackWalk(long anchor, int skipFrames, int batchSize,
|
private Object doStackWalk(long anchor, int skipFrames, int numFrames,
|
||||||
int bufStartIndex, int bufEndIndex) {
|
int bufStartIndex, int bufEndIndex) {
|
||||||
checkState(NEW);
|
checkState(NEW);
|
||||||
|
|
||||||
frameBuffer.check(skipFrames);
|
frameBuffer.check(skipFrames);
|
||||||
|
|
||||||
if (isDebug) {
|
if (isDebug) {
|
||||||
System.err.format("doStackWalk: skip %d start %d end %d%n",
|
System.err.format("doStackWalk: skip %d start %d end %d nframes %d%n",
|
||||||
skipFrames, bufStartIndex, bufEndIndex);
|
skipFrames, bufStartIndex, bufEndIndex, numFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.anchor = anchor; // set anchor for this bulk stack frame traversal
|
this.anchor = anchor; // set anchor for this bulk stack frame traversal
|
||||||
frameBuffer.setBatch(depth, bufStartIndex, bufEndIndex);
|
frameBuffer.setBatch(depth, bufStartIndex, numFrames);
|
||||||
|
|
||||||
// traverse all frames and perform the action on the stack frames, if specified
|
// traverse all frames and perform the action on the stack frames, if specified
|
||||||
return consumeFrames();
|
return consumeFrames();
|
||||||
@ -334,10 +334,8 @@ final class StackStreamFactory {
|
|||||||
* Get next batch of stack frames.
|
* Get next batch of stack frames.
|
||||||
*/
|
*/
|
||||||
private int getNextBatch() {
|
private int getNextBatch() {
|
||||||
int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize());
|
|
||||||
|
|
||||||
if (!frameBuffer.isActive()
|
if (!frameBuffer.isActive()
|
||||||
|| (nextBatchSize <= 0)
|
|| (depth == maxDepth)
|
||||||
|| (frameBuffer.isAtBottom() && !hasMoreContinuations())) {
|
|| (frameBuffer.isAtBottom() && !hasMoreContinuations())) {
|
||||||
if (isDebug) {
|
if (isDebug) {
|
||||||
System.out.format(" more stack walk done%n");
|
System.out.format(" more stack walk done%n");
|
||||||
@ -346,11 +344,21 @@ final class StackStreamFactory {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VM ends the batch when it reaches the bottom of a continuation
|
||||||
|
// i.e. Continuation::enter. The stack walker will set the continuation
|
||||||
|
// to its parent to continue.
|
||||||
|
// Note that the current batch could have no stack frame filled. This could
|
||||||
|
// happen when Continuation::enter is the last element of the frame buffer
|
||||||
|
// filled in the last batch and it needs to fetch another batch in order to
|
||||||
|
// detect reaching the bottom.
|
||||||
if (frameBuffer.isAtBottom() && hasMoreContinuations()) {
|
if (frameBuffer.isAtBottom() && hasMoreContinuations()) {
|
||||||
|
if (isDebug) {
|
||||||
|
System.out.format(" set continuation to %s%n", continuation.getParent());
|
||||||
|
}
|
||||||
setContinuation(continuation.getParent());
|
setContinuation(continuation.getParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
int numFrames = fetchStackFrames(nextBatchSize);
|
int numFrames = fetchStackFrames();
|
||||||
if (numFrames == 0 && !hasMoreContinuations()) {
|
if (numFrames == 0 && !hasMoreContinuations()) {
|
||||||
frameBuffer.freeze(); // done stack walking
|
frameBuffer.freeze(); // done stack walking
|
||||||
}
|
}
|
||||||
@ -415,34 +423,35 @@ final class StackStreamFactory {
|
|||||||
|
|
||||||
return callStackWalk(mode, 0,
|
return callStackWalk(mode, 0,
|
||||||
contScope, continuation,
|
contScope, continuation,
|
||||||
frameBuffer.curBatchFrameCount(),
|
frameBuffer.currentBatchSize(),
|
||||||
frameBuffer.startIndex(),
|
frameBuffer.startIndex(),
|
||||||
frameBuffer.frames());
|
frameBuffer.frames());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetches stack frames.
|
* Fetches a new batch of stack frames. This method returns
|
||||||
|
* the number of stack frames filled in this batch.
|
||||||
*
|
*
|
||||||
* @param batchSize number of elements of the frame buffers for this batch
|
* When it reaches the bottom of a continuation, i.e. Continuation::enter,
|
||||||
* @return number of frames fetched in this batch
|
* VM ends the batch and let the stack walker to set the continuation
|
||||||
|
* to its parent and continue the stack walking. It may return zero.
|
||||||
*/
|
*/
|
||||||
private int fetchStackFrames(int batchSize) {
|
private int fetchStackFrames() {
|
||||||
int startIndex = frameBuffer.startIndex();
|
int startIndex = frameBuffer.startIndex();
|
||||||
frameBuffer.resize(startIndex, batchSize);
|
|
||||||
|
|
||||||
int endIndex = fetchStackFrames(mode, anchor, batchSize,
|
// If the last batch didn't fetch any frames, keep the current batch size.
|
||||||
startIndex,
|
int lastBatchFrameCount = frameBuffer.numFrames();
|
||||||
frameBuffer.frames());
|
int batchSize = getNextBatchSize();
|
||||||
|
frameBuffer.resize(batchSize);
|
||||||
|
|
||||||
|
int numFrames = fetchStackFrames(mode, anchor, lastBatchFrameCount,
|
||||||
|
batchSize, startIndex,
|
||||||
|
frameBuffer.frames());
|
||||||
if (isDebug) {
|
if (isDebug) {
|
||||||
System.out.format(" more stack walk requesting %d got %d to %d frames%n",
|
System.out.format(" more stack walk got %d frames start %d batch size %d%n",
|
||||||
batchSize, frameBuffer.startIndex(), endIndex);
|
numFrames, frameBuffer.startIndex(), batchSize);
|
||||||
}
|
|
||||||
|
|
||||||
int numFrames = endIndex - startIndex;
|
|
||||||
|
|
||||||
if (numFrames > 0) {
|
|
||||||
frameBuffer.setBatch(depth, startIndex, endIndex);
|
|
||||||
}
|
}
|
||||||
|
frameBuffer.setBatch(depth, startIndex, numFrames);
|
||||||
return numFrames;
|
return numFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,7 +463,7 @@ final class StackStreamFactory {
|
|||||||
* @param skipframes number of frames to be skipped before filling the frame buffer.
|
* @param skipframes number of frames to be skipped before filling the frame buffer.
|
||||||
* @param contScope the continuation scope to walk.
|
* @param contScope the continuation scope to walk.
|
||||||
* @param continuation the continuation to walk, or {@code null} if walking a thread.
|
* @param continuation the continuation to walk, or {@code null} if walking a thread.
|
||||||
* @param batchSize the batch size, max. number of elements to be filled in the frame buffers.
|
* @param bufferSize the buffer size
|
||||||
* @param startIndex start index of the frame buffers to be filled.
|
* @param startIndex start index of the frame buffers to be filled.
|
||||||
* @param frames Either a {@link ClassFrameInfo} array, if mode is {@link #CLASS_INFO_ONLY}
|
* @param frames Either a {@link ClassFrameInfo} array, if mode is {@link #CLASS_INFO_ONLY}
|
||||||
* or a {@link StackFrameInfo} (or derivative) array otherwise.
|
* or a {@link StackFrameInfo} (or derivative) array otherwise.
|
||||||
@ -462,7 +471,7 @@ final class StackStreamFactory {
|
|||||||
*/
|
*/
|
||||||
private native R callStackWalk(int mode, int skipframes,
|
private native R callStackWalk(int mode, int skipframes,
|
||||||
ContinuationScope contScope, Continuation continuation,
|
ContinuationScope contScope, Continuation continuation,
|
||||||
int batchSize, int startIndex,
|
int bufferSize, int startIndex,
|
||||||
T[] frames);
|
T[] frames);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -470,15 +479,16 @@ final class StackStreamFactory {
|
|||||||
*
|
*
|
||||||
* @param mode mode of stack walking
|
* @param mode mode of stack walking
|
||||||
* @param anchor
|
* @param anchor
|
||||||
* @param batchSize the batch size, max. number of elements to be filled in the frame buffers.
|
* @param lastBatchFrameCount the number of frames filled in the last batch.
|
||||||
|
* @param bufferSize the buffer size
|
||||||
* @param startIndex start index of the frame buffers to be filled.
|
* @param startIndex start index of the frame buffers to be filled.
|
||||||
* @param frames Either a {@link ClassFrameInfo} array, if mode is {@link #CLASS_INFO_ONLY}
|
* @param frames Either a {@link ClassFrameInfo} array, if mode is {@link #CLASS_INFO_ONLY}
|
||||||
* or a {@link StackFrameInfo} (or derivative) array otherwise.
|
* or a {@link StackFrameInfo} (or derivative) array otherwise.
|
||||||
*
|
*
|
||||||
* @return the end index to the frame buffers
|
* @return the number of frames filled in this batch
|
||||||
*/
|
*/
|
||||||
private native int fetchStackFrames(int mode, long anchor,
|
private native int fetchStackFrames(int mode, long anchor, int lastBatchFrameCount,
|
||||||
int batchSize, int startIndex,
|
int bufferSize, int startIndex,
|
||||||
T[] frames);
|
T[] frames);
|
||||||
|
|
||||||
private native void setContinuation(long anchor, T[] frames, Continuation cont);
|
private native void setContinuation(long anchor, T[] frames, Continuation cont);
|
||||||
@ -537,16 +547,18 @@ final class StackStreamFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int batchSize(int lastBatchFrameCount) {
|
protected int batchSize(int lastBatchSize) {
|
||||||
if (lastBatchFrameCount == 0) {
|
if (lastBatchSize == 0) {
|
||||||
// First batch, use estimateDepth if not exceed the large batch size
|
// First batch, use estimateDepth if not exceed the large batch size
|
||||||
int initialBatchSize = Math.max(walker.estimateDepth()+RESERVED_ELEMENTS, MIN_BATCH_SIZE);
|
int initialBatchSize = Math.max(walker.estimateDepth()+RESERVED_ELEMENTS, MIN_BATCH_SIZE);
|
||||||
return Math.min(initialBatchSize, LARGE_BATCH_SIZE);
|
return Math.min(initialBatchSize, LARGE_BATCH_SIZE);
|
||||||
} else {
|
} else {
|
||||||
if (lastBatchFrameCount > BATCH_SIZE) {
|
// expand only if last batch was full and the buffer size <= 32
|
||||||
return lastBatchFrameCount;
|
// to minimize the number of unneeded frames decoded.
|
||||||
|
if (lastBatchSize > BATCH_SIZE || !frameBuffer.isFull()) {
|
||||||
|
return lastBatchSize;
|
||||||
} else {
|
} else {
|
||||||
return Math.min(lastBatchFrameCount*2, BATCH_SIZE);
|
return Math.min(lastBatchSize*2, BATCH_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -638,21 +650,20 @@ final class StackStreamFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void resize(int startIndex, int elements) {
|
void resize(int size) {
|
||||||
if (!isActive())
|
if (!isActive())
|
||||||
throw new IllegalStateException("inactive frame buffer can't be resized");
|
throw new IllegalStateException("inactive frame buffer can't be resized");
|
||||||
|
|
||||||
assert startIndex == START_POS :
|
assert startIndex() == START_POS :
|
||||||
"bad start index " + startIndex + " expected " + START_POS;
|
"bad start index " + startIndex() + " expected " + START_POS;
|
||||||
|
|
||||||
int size = startIndex+elements;
|
|
||||||
if (stackFrames.length < size) {
|
if (stackFrames.length < size) {
|
||||||
T[] newFrames = allocateArray(size);
|
T[] newFrames = allocateArray(size);
|
||||||
// copy initial magic...
|
// copy initial magic...
|
||||||
System.arraycopy(stackFrames, 0, newFrames, 0, startIndex);
|
System.arraycopy(stackFrames, 0, newFrames, 0, startIndex());
|
||||||
stackFrames = newFrames;
|
stackFrames = newFrames;
|
||||||
}
|
}
|
||||||
fill(stackFrames, startIndex, size);
|
fill(stackFrames, startIndex(), size);
|
||||||
currentBatchSize = size;
|
currentBatchSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -762,7 +773,7 @@ final class StackStreamFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int batchSize(int lastBatchFrameCount) {
|
protected int batchSize(int lastBatchSize) {
|
||||||
// this method is only called when the caller class is not found in
|
// this method is only called when the caller class is not found in
|
||||||
// the first batch. getCallerClass may be invoked via core reflection.
|
// the first batch. getCallerClass may be invoked via core reflection.
|
||||||
// So increase the next batch size as there may be implementation-specific
|
// So increase the next batch size as there may be implementation-specific
|
||||||
@ -803,8 +814,7 @@ final class StackStreamFactory {
|
|||||||
// buffers for VM to fill stack frame info
|
// buffers for VM to fill stack frame info
|
||||||
int currentBatchSize; // current batch size
|
int currentBatchSize; // current batch size
|
||||||
int origin; // index to the current traversed stack frame
|
int origin; // index to the current traversed stack frame
|
||||||
int fence; // index to the last frame in the current batch
|
int fence; // index past the last frame of the current batch
|
||||||
|
|
||||||
FrameBuffer(int initialBatchSize) {
|
FrameBuffer(int initialBatchSize) {
|
||||||
if (initialBatchSize < MIN_BATCH_SIZE) {
|
if (initialBatchSize < MIN_BATCH_SIZE) {
|
||||||
throw new IllegalArgumentException(initialBatchSize +
|
throw new IllegalArgumentException(initialBatchSize +
|
||||||
@ -830,16 +840,13 @@ final class StackStreamFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes the buffers for VM to fill in the next batch of stack frames.
|
* Resizes the buffers for VM to fill in the next batch of stack frames.
|
||||||
* The next batch will start at the given startIndex with the maximum number
|
|
||||||
* of elements.
|
|
||||||
*
|
*
|
||||||
* <p> Subclass may override this method to manage the allocated buffers.
|
* <p> Subclass may override this method to manage the allocated buffers.
|
||||||
*
|
*
|
||||||
* @param startIndex the start index for the first frame of the next batch to fill in.
|
* @param size new batch size
|
||||||
* @param elements the number of elements for the next batch to fill in.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
abstract void resize(int startIndex, int elements);
|
abstract void resize(int size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the class at the given position in the current batch.
|
* Return the class at the given position in the current batch.
|
||||||
@ -871,8 +878,8 @@ final class StackStreamFactory {
|
|||||||
|
|
||||||
// ------ FrameBuffer implementation ------
|
// ------ FrameBuffer implementation ------
|
||||||
|
|
||||||
final int curBatchFrameCount() {
|
final int currentBatchSize() {
|
||||||
return currentBatchSize-START_POS;
|
return currentBatchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -882,6 +889,15 @@ final class StackStreamFactory {
|
|||||||
return origin >= fence || (origin == START_POS && fence == 0);
|
return origin >= fence || (origin == START_POS && fence == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the number of stack frames filled in the current batch
|
||||||
|
*/
|
||||||
|
final int numFrames() {
|
||||||
|
if (!isActive())
|
||||||
|
throw new IllegalStateException();
|
||||||
|
return fence - startIndex();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Freezes this frame buffer. The stack stream source is done fetching.
|
* Freezes this frame buffer. The stack stream source is done fetching.
|
||||||
*/
|
*/
|
||||||
@ -892,10 +908,14 @@ final class StackStreamFactory {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Tests if this frame buffer is active. It is inactive when
|
* Tests if this frame buffer is active. It is inactive when
|
||||||
* it is done for traversal. All stack frames have been traversed.
|
* it is done for traversal.
|
||||||
*/
|
*/
|
||||||
final boolean isActive() {
|
final boolean isActive() {
|
||||||
return origin > 0; // && (fence == 0 || origin < fence || fence == currentBatchSize);
|
return origin > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean isFull() {
|
||||||
|
return fence == currentBatchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -918,7 +938,7 @@ final class StackStreamFactory {
|
|||||||
if (isDebug) {
|
if (isDebug) {
|
||||||
int index = origin-1;
|
int index = origin-1;
|
||||||
System.out.format(" next frame at %d: %s (origin %d fence %d)%n", index,
|
System.out.format(" next frame at %d: %s (origin %d fence %d)%n", index,
|
||||||
Objects.toString(c), index, fence);
|
c.getName(), index, fence);
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -941,17 +961,16 @@ final class StackStreamFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the start and end index of a new batch of stack frames that have
|
* Set a new batch of stack frames that have been filled in this frame buffer.
|
||||||
* been filled in this frame buffer.
|
|
||||||
*/
|
*/
|
||||||
final void setBatch(int depth, int startIndex, int endIndex) {
|
final void setBatch(int depth, int startIndex, int numFrames) {
|
||||||
if (startIndex <= 0 || endIndex <= 0)
|
if (startIndex <= 0 || numFrames < 0)
|
||||||
throw new IllegalArgumentException("startIndex=" + startIndex
|
throw new IllegalArgumentException("startIndex=" + startIndex
|
||||||
+ " endIndex=" + endIndex);
|
+ " numFrames=" + numFrames);
|
||||||
|
|
||||||
this.origin = startIndex;
|
this.origin = startIndex;
|
||||||
this.fence = endIndex;
|
this.fence = startIndex + numFrames;
|
||||||
for (int i = START_POS; i < fence; i++) {
|
for (int i = startIndex; i < fence; i++) {
|
||||||
if (isDebug) System.err.format(" frame %d: %s%n", i, at(i));
|
if (isDebug) System.err.format(" frame %d: %s%n", i, at(i));
|
||||||
if (depth == 0 && filterStackWalkImpl(at(i))) { // filter the frames due to the stack stream implementation
|
if (depth == 0 && filterStackWalkImpl(at(i))) { // filter the frames due to the stack stream implementation
|
||||||
origin++;
|
origin++;
|
||||||
|
@ -56,10 +56,10 @@ JNIEXPORT jboolean JNICALL Java_java_lang_StackStreamFactory_checkStackWalkModes
|
|||||||
*/
|
*/
|
||||||
JNIEXPORT jobject JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk
|
JNIEXPORT jobject JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk
|
||||||
(JNIEnv *env, jobject stackstream, jint mode, jint skipFrames, jobject contScope, jobject cont,
|
(JNIEnv *env, jobject stackstream, jint mode, jint skipFrames, jobject contScope, jobject cont,
|
||||||
jint batchSize, jint startIndex, jobjectArray frames)
|
jint bufferSize, jint startIndex, jobjectArray frames)
|
||||||
{
|
{
|
||||||
return JVM_CallStackWalk(env, stackstream, mode, skipFrames, contScope, cont,
|
return JVM_CallStackWalk(env, stackstream, mode, skipFrames, contScope, cont,
|
||||||
batchSize, startIndex, frames);
|
bufferSize, startIndex, frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -69,10 +69,10 @@ JNIEXPORT jobject JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWa
|
|||||||
*/
|
*/
|
||||||
JNIEXPORT jint JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames
|
JNIEXPORT jint JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames
|
||||||
(JNIEnv *env, jobject stackstream, jint mode, jlong anchor,
|
(JNIEnv *env, jobject stackstream, jint mode, jlong anchor,
|
||||||
jint batchSize, jint startIndex,
|
int lastBatchFrameCount, jint bufferSize, jint startIndex,
|
||||||
jobjectArray frames)
|
jobjectArray frames)
|
||||||
{
|
{
|
||||||
return JVM_MoreStackWalk(env, stackstream, mode, anchor, batchSize,
|
return JVM_MoreStackWalk(env, stackstream, mode, anchor, lastBatchFrameCount, bufferSize,
|
||||||
startIndex, frames);
|
startIndex, frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,15 +74,15 @@ public class Scoped {
|
|||||||
|
|
||||||
frames = cont.stackWalker().walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
frames = cont.stackWalker().walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
||||||
System.out.println("No scope: " + frames);
|
System.out.println("No scope: " + frames);
|
||||||
assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter"));
|
assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "yield0", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter"));
|
||||||
|
|
||||||
frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), A).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), A).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
||||||
System.out.println("A: " + frames);
|
System.out.println("A: " + frames);
|
||||||
assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter"));
|
assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "yield0", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter"));
|
||||||
|
|
||||||
frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), B).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), B).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
||||||
System.out.println("B: " + frames);
|
System.out.println("B: " + frames);
|
||||||
assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter"));
|
assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "yield0", "run", "bar", "lambda$foo$8", "run", "enter0", "enter"));
|
||||||
|
|
||||||
frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), C).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), C).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
||||||
System.out.println("C: " + frames);
|
System.out.println("C: " + frames);
|
||||||
@ -90,11 +90,11 @@ public class Scoped {
|
|||||||
|
|
||||||
frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), K).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), K).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
||||||
System.out.println("K: " + frames);
|
System.out.println("K: " + frames);
|
||||||
assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter"));
|
assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "yield0", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter"));
|
||||||
|
|
||||||
frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), null).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), null).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
|
||||||
System.out.println("null: " + frames);
|
System.out.println("null: " + frames);
|
||||||
assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter"));
|
assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "yield0", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter"));
|
||||||
}
|
}
|
||||||
assertEquals(res.get(), 2);
|
assertEquals(res.get(), 2);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user