diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index b6099c2ebcc..049c454c241 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -255,11 +255,11 @@ JVM_ExpandStackFrameInfo(JNIEnv *env, jobject obj); JNIEXPORT jobject JNICALL JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jint mode, 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 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); JNIEXPORT void JNICALL diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index b18795f47f7..e8c97351a5f 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -565,7 +565,7 @@ JVM_END JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jint mode, 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()) { 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)); objArrayHandle frames_array_h(THREAD, fa); - int limit = start_index + frame_count; - if (frames_array_h->length() < limit) { + if (frames_array_h->length() < buffer_size) { 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, - frame_count, start_index, frames_array_h, CHECK_NULL); + buffer_size, start_index, frames_array_h, CHECK_NULL); return JNIHandles::make_local(THREAD, result); JVM_END 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)) // frames array is a ClassFrameInfo[] array when only getting caller reference, // 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)); objArrayHandle frames_array_h(THREAD, fa); - int limit = start_index+frame_count; - if (frames_array_h->length() < limit) { + if (frames_array_h->length() < buffer_size) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers"); } 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); JVM_END diff --git a/src/hotspot/share/prims/stackwalk.cpp b/src/hotspot/share/prims/stackwalk.cpp index 619f64085a0..3d5a56fb9c4 100644 --- a/src/hotspot/share/prims/stackwalk.cpp +++ b/src/hotspot/share/prims/stackwalk.cpp @@ -152,7 +152,7 @@ BaseFrameStream* BaseFrameStream::from_current(JavaThread* thread, jlong magic, // Parameters: // mode Restrict which frames to be decoded. // 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. // frames_array Buffer to store stack frame information in, starting at start_index. // 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. // int StackWalk::fill_in_frames(jint mode, BaseFrameStream& stream, - int max_nframes, int start_index, + int buffer_size, int start_index, objArrayHandle frames_array, int& end_index, TRAPS) { log_debug(stackwalk)("fill_in_frames limit=%d start=%d frames length=%d", - max_nframes, start_index, frames_array->length()); - assert(max_nframes > 0, "invalid max_nframes"); - assert(start_index + max_nframes <= frames_array->length(), "oob"); + buffer_size, start_index, frames_array->length()); + assert(buffer_size > 0, "invalid buffer_size"); + assert(buffer_size <= frames_array->length(), "oob"); int frames_decoded = 0; 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 // not set) and when StackWalker::getCallerClass is called - LogTarget(Debug, stackwalk) lt; if (!ShowHiddenFrames && skip_hidden_frames(mode)) { if (method->is_hidden()) { - if (lt.is_enabled()) { - ResourceMark rm(THREAD); - LogStream ls(lt); - ls.print(" skip hidden method: "); - method->print_short_name(&ls); - ls.cr(); - } + log_debug(stackwalk)(" skip hidden method: %s", stream.method()->external_name()); - // 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; continue; } } int index = end_index++; - if (lt.is_enabled()) { - 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 + log_debug(stackwalk)(" frame %d: %s bci %d", index, stream.method()->external_name(), stream.bci()); 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++; - // 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 (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; } @@ -398,7 +376,7 @@ void LiveFrameStream::fill_live_stackframe(Handle stackFrame, // mode Stack walking mode. // 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). -// frame_count Number of frames to be traversed. +// buffer_size Buffer size. // start_index Start index to the user-supplied buffers. // frames_array Buffer to store stack frame info in, starting at start_index. // 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. // 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) { ResourceMark rm(THREAD); HandleMark hm(THREAD); // needed to store a continuation in the RegisterMap 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; if (lt.is_enabled()) { ResourceMark rm(THREAD); @@ -438,17 +416,17 @@ oop StackWalk::walk(Handle stackStream, jint mode, int skip_frames, Handle cont_ RegisterMap::WalkContinuation::include) : RegisterMap(cont(), RegisterMap::UpdateMap::include); 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); } else { 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); } } 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) { 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) { break; } - - 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(); - } + log_debug(stackwalk)(" skip %s", stream.method()->external_name()); stream.next(); } // stack frame has been traversed individually and resume stack walk // from the stack frame at depth == skip_frames. for (int n=0; n < skip_frames && !stream.at_end(); stream.next(), n++) { - 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(); - } + log_debug(stackwalk)(" skip %s", stream.method()->external_name()); } } @@ -491,7 +454,7 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream, int numFrames = 0; if (!stream.at_end()) { 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); if (numFrames < 1) { 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); args.push_long(stream.address_value()); args.push_int(skip_frames); - args.push_int(frame_count); + args.push_int(numFrames); args.push_int(start_index); args.push_int(end_index); @@ -535,14 +498,15 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream, // stackStream StackStream object // mode Stack walking mode. // 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. // 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, - int frame_count, int start_index, + int last_batch_count, int buffer_size, int start_index, objArrayHandle frames_array, 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); } - log_debug(stackwalk)("StackWalk::fetchNextBatch frame_count %d existing_stream " - PTR_FORMAT " start %d frames %d", - frame_count, p2i(existing_stream), start_index, frames_array->length()); + log_debug(stackwalk)("StackWalk::fetchNextBatch last_batch_count %d buffer_size %d existing_stream " + PTR_FORMAT " start %d", last_batch_count, + buffer_size, p2i(existing_stream), start_index, frames_array->length()); int end_index = start_index; - if (frame_count <= 0) { - return end_index; // No operation. + if (buffer_size <= start_index) { + return 0; // No operation. } - int count = frame_count + start_index; - assert (frames_array->length() >= count, "not enough space in buffers"); + assert (frames_array->length() >= buffer_size, "frames_array length < buffer_size"); BaseFrameStream& stream = (*existing_stream); 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 // processing of the stack. 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()) { - 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); - 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); } - return end_index; + return numFrames; } } - return end_index; + return 0; } void StackWalk::setContinuation(Handle stackStream, jlong magic, objArrayHandle frames_array, Handle cont, TRAPS) { diff --git a/src/hotspot/share/prims/stackwalk.hpp b/src/hotspot/share/prims/stackwalk.hpp index f918c4427a6..39890e3f158 100644 --- a/src/hotspot/share/prims/stackwalk.hpp +++ b/src/hotspot/share/prims/stackwalk.hpp @@ -143,7 +143,7 @@ public: class StackWalk : public AllStatic { private: static int fill_in_frames(jint mode, BaseFrameStream& stream, - int max_nframes, int start_index, + int buffer_size, int start_index, objArrayHandle frames_array, int& end_index, TRAPS); @@ -160,15 +160,15 @@ public: } 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); 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); 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); static void setContinuation(Handle stackStream, jlong magic, objArrayHandle frames_array, diff --git a/src/java.base/share/classes/java/lang/StackStreamFactory.java b/src/java.base/share/classes/java/lang/StackStreamFactory.java index b9ad5ba6cc7..339e0cc11fc 100644 --- a/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ b/src/java.base/share/classes/java/lang/StackStreamFactory.java @@ -192,10 +192,10 @@ final class StackStreamFactory { * * 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 */ - protected abstract int batchSize(int lastBatchFrameCount); + protected abstract int batchSize(int lastBatchSize); /* * 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. */ protected int getNextBatchSize() { - int lastBatchSize = depth == 0 ? 0 : frameBuffer.curBatchFrameCount(); + int lastBatchSize = depth == 0 ? 0 : frameBuffer.currentBatchSize(); int nextBatchSize = batchSize(lastBatchSize); if (isDebug) { System.err.println("last batch size = " + lastBatchSize + @@ -312,19 +312,19 @@ final class StackStreamFactory { * 2. reuse or expand the allocated buffers * 3. create specialized StackFrame objects */ - private Object doStackWalk(long anchor, int skipFrames, int batchSize, - int bufStartIndex, int bufEndIndex) { + private Object doStackWalk(long anchor, int skipFrames, int numFrames, + int bufStartIndex, int bufEndIndex) { checkState(NEW); frameBuffer.check(skipFrames); if (isDebug) { - System.err.format("doStackWalk: skip %d start %d end %d%n", - skipFrames, bufStartIndex, bufEndIndex); + System.err.format("doStackWalk: skip %d start %d end %d nframes %d%n", + skipFrames, bufStartIndex, bufEndIndex, numFrames); } 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 return consumeFrames(); @@ -334,10 +334,8 @@ final class StackStreamFactory { * Get next batch of stack frames. */ private int getNextBatch() { - int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize()); - if (!frameBuffer.isActive() - || (nextBatchSize <= 0) + || (depth == maxDepth) || (frameBuffer.isAtBottom() && !hasMoreContinuations())) { if (isDebug) { System.out.format(" more stack walk done%n"); @@ -346,11 +344,21 @@ final class StackStreamFactory { 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 (isDebug) { + System.out.format(" set continuation to %s%n", continuation.getParent()); + } setContinuation(continuation.getParent()); } - int numFrames = fetchStackFrames(nextBatchSize); + int numFrames = fetchStackFrames(); if (numFrames == 0 && !hasMoreContinuations()) { frameBuffer.freeze(); // done stack walking } @@ -415,34 +423,35 @@ final class StackStreamFactory { return callStackWalk(mode, 0, contScope, continuation, - frameBuffer.curBatchFrameCount(), + frameBuffer.currentBatchSize(), frameBuffer.startIndex(), 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 - * @return number of frames fetched in this batch + * When it reaches the bottom of a continuation, i.e. Continuation::enter, + * 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(); - frameBuffer.resize(startIndex, batchSize); - int endIndex = fetchStackFrames(mode, anchor, batchSize, - startIndex, - frameBuffer.frames()); + // If the last batch didn't fetch any frames, keep the current batch size. + int lastBatchFrameCount = frameBuffer.numFrames(); + int batchSize = getNextBatchSize(); + frameBuffer.resize(batchSize); + + int numFrames = fetchStackFrames(mode, anchor, lastBatchFrameCount, + batchSize, startIndex, + frameBuffer.frames()); if (isDebug) { - System.out.format(" more stack walk requesting %d got %d to %d frames%n", - batchSize, frameBuffer.startIndex(), endIndex); - } - - int numFrames = endIndex - startIndex; - - if (numFrames > 0) { - frameBuffer.setBatch(depth, startIndex, endIndex); + System.out.format(" more stack walk got %d frames start %d batch size %d%n", + numFrames, frameBuffer.startIndex(), batchSize); } + frameBuffer.setBatch(depth, startIndex, numFrames); return numFrames; } @@ -454,7 +463,7 @@ final class StackStreamFactory { * @param skipframes number of frames to be skipped before filling the frame buffer. * @param contScope the continuation scope to walk. * @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 frames Either a {@link ClassFrameInfo} array, if mode is {@link #CLASS_INFO_ONLY} * or a {@link StackFrameInfo} (or derivative) array otherwise. @@ -462,7 +471,7 @@ final class StackStreamFactory { */ private native R callStackWalk(int mode, int skipframes, ContinuationScope contScope, Continuation continuation, - int batchSize, int startIndex, + int bufferSize, int startIndex, T[] frames); /** @@ -470,15 +479,16 @@ final class StackStreamFactory { * * @param mode mode of stack walking * @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 frames Either a {@link ClassFrameInfo} array, if mode is {@link #CLASS_INFO_ONLY} * 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, - int batchSize, int startIndex, + private native int fetchStackFrames(int mode, long anchor, int lastBatchFrameCount, + int bufferSize, int startIndex, T[] frames); private native void setContinuation(long anchor, T[] frames, Continuation cont); @@ -537,16 +547,18 @@ final class StackStreamFactory { } @Override - protected int batchSize(int lastBatchFrameCount) { - if (lastBatchFrameCount == 0) { + protected int batchSize(int lastBatchSize) { + if (lastBatchSize == 0) { // First batch, use estimateDepth if not exceed the large batch size int initialBatchSize = Math.max(walker.estimateDepth()+RESERVED_ELEMENTS, MIN_BATCH_SIZE); return Math.min(initialBatchSize, LARGE_BATCH_SIZE); } else { - if (lastBatchFrameCount > BATCH_SIZE) { - return lastBatchFrameCount; + // expand only if last batch was full and the buffer size <= 32 + // to minimize the number of unneeded frames decoded. + if (lastBatchSize > BATCH_SIZE || !frameBuffer.isFull()) { + return lastBatchSize; } else { - return Math.min(lastBatchFrameCount*2, BATCH_SIZE); + return Math.min(lastBatchSize*2, BATCH_SIZE); } } } @@ -638,21 +650,20 @@ final class StackStreamFactory { } @Override - void resize(int startIndex, int elements) { + void resize(int size) { if (!isActive()) throw new IllegalStateException("inactive frame buffer can't be resized"); - assert startIndex == START_POS : - "bad start index " + startIndex + " expected " + START_POS; + assert startIndex() == START_POS : + "bad start index " + startIndex() + " expected " + START_POS; - int size = startIndex+elements; if (stackFrames.length < size) { T[] newFrames = allocateArray(size); // copy initial magic... - System.arraycopy(stackFrames, 0, newFrames, 0, startIndex); + System.arraycopy(stackFrames, 0, newFrames, 0, startIndex()); stackFrames = newFrames; } - fill(stackFrames, startIndex, size); + fill(stackFrames, startIndex(), size); currentBatchSize = size; } @@ -762,7 +773,7 @@ final class StackStreamFactory { } @Override - protected int batchSize(int lastBatchFrameCount) { + protected int batchSize(int lastBatchSize) { // this method is only called when the caller class is not found in // the first batch. getCallerClass may be invoked via core reflection. // 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 int currentBatchSize; // current batch size 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) { if (initialBatchSize < MIN_BATCH_SIZE) { 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. - * The next batch will start at the given startIndex with the maximum number - * of elements. * *
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 elements the number of elements for the next batch to fill in. + * @param size new batch size * */ - abstract void resize(int startIndex, int elements); + abstract void resize(int size); /** * Return the class at the given position in the current batch. @@ -871,8 +878,8 @@ final class StackStreamFactory { // ------ FrameBuffer implementation ------ - final int curBatchFrameCount() { - return currentBatchSize-START_POS; + final int currentBatchSize() { + return currentBatchSize; } /* @@ -882,6 +889,15 @@ final class StackStreamFactory { 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. */ @@ -892,10 +908,14 @@ final class StackStreamFactory { /* * 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() { - 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) { int index = origin-1; 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; } @@ -941,17 +961,16 @@ final class StackStreamFactory { } /* - * Set the start and end index of a new batch of stack frames that have - * been filled in this frame buffer. + * Set a new batch of stack frames that have been filled in this frame buffer. */ - final void setBatch(int depth, int startIndex, int endIndex) { - if (startIndex <= 0 || endIndex <= 0) + final void setBatch(int depth, int startIndex, int numFrames) { + if (startIndex <= 0 || numFrames < 0) throw new IllegalArgumentException("startIndex=" + startIndex - + " endIndex=" + endIndex); + + " numFrames=" + numFrames); this.origin = startIndex; - this.fence = endIndex; - for (int i = START_POS; i < fence; i++) { + this.fence = startIndex + numFrames; + for (int i = startIndex; i < fence; 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 origin++; diff --git a/src/java.base/share/native/libjava/StackStreamFactory.c b/src/java.base/share/native/libjava/StackStreamFactory.c index b53cb539c3e..a04ffbd21e6 100644 --- a/src/java.base/share/native/libjava/StackStreamFactory.c +++ b/src/java.base/share/native/libjava/StackStreamFactory.c @@ -56,10 +56,10 @@ JNIEXPORT jboolean JNICALL Java_java_lang_StackStreamFactory_checkStackWalkModes */ JNIEXPORT jobject JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk (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, - 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 (JNIEnv *env, jobject stackstream, jint mode, jlong anchor, - jint batchSize, jint startIndex, + int lastBatchFrameCount, jint bufferSize, jint startIndex, jobjectArray frames) { - return JVM_MoreStackWalk(env, stackstream, mode, anchor, batchSize, + return JVM_MoreStackWalk(env, stackstream, mode, anchor, lastBatchFrameCount, bufferSize, startIndex, frames); } diff --git a/test/jdk/jdk/internal/vm/Continuation/Scoped.java b/test/jdk/jdk/internal/vm/Continuation/Scoped.java index 0d96aecdea0..b034243d596 100644 --- a/test/jdk/jdk/internal/vm/Continuation/Scoped.java +++ b/test/jdk/jdk/internal/vm/Continuation/Scoped.java @@ -74,15 +74,15 @@ public class Scoped { frames = cont.stackWalker().walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); 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())); 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())); 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())); 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())); 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())); 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); }