8284161: Implementation of Virtual Threads (Preview)

Co-authored-by: Ron Pressler <rpressler@openjdk.org>
Co-authored-by: Alan Bateman <alanb@openjdk.org>
Co-authored-by: Erik Österlund <eosterlund@openjdk.org>
Co-authored-by: Andrew Haley <aph@openjdk.org>
Co-authored-by: Rickard Bäckman <rbackman@openjdk.org>
Co-authored-by: Markus Grönlund <mgronlun@openjdk.org>
Co-authored-by: Leonid Mesnik <lmesnik@openjdk.org>
Co-authored-by: Serguei Spitsyn <sspitsyn@openjdk.org>
Co-authored-by: Chris Plummer <cjplummer@openjdk.org>
Co-authored-by: Coleen Phillimore <coleenp@openjdk.org>
Co-authored-by: Robbin Ehn <rehn@openjdk.org>
Co-authored-by: Stefan Karlsson <stefank@openjdk.org>
Co-authored-by: Thomas Schatzl <tschatzl@openjdk.org>
Co-authored-by: Sergey Kuksenko <skuksenko@openjdk.org>
Reviewed-by: lancea, eosterlund, rehn, sspitsyn, stefank, tschatzl, dfuchs, lmesnik, dcubed, kevinw, amenkov, dlong, mchung, psandoz, bpb, coleenp, smarks, egahlin, mseledtsov, coffeys, darcy
This commit is contained in:
Alan Bateman 2022-05-07 08:06:16 +00:00
parent 5212535a27
commit 9583e3657e
1133 changed files with 95935 additions and 8335 deletions

View file

@ -41,6 +41,8 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.internal.vm.Continuation;
import jdk.internal.vm.ContinuationScope;
import sun.security.action.GetPropertyAction;
import static java.lang.StackStreamFactory.WalkerState.*;
@ -126,6 +128,8 @@ final class StackStreamFactory {
protected int depth; // traversed stack depth
protected FrameBuffer<? extends T> frameBuffer;
protected long anchor;
protected final ContinuationScope contScope;
protected Continuation continuation;
// buffers to fill in stack frame information
protected AbstractStackWalker(StackWalker walker, int mode) {
@ -137,6 +141,14 @@ final class StackStreamFactory {
this.walker = walker;
this.maxDepth = maxDepth;
this.depth = 0;
ContinuationScope scope = walker.getContScope();
if (scope == null && thread.isVirtual()) {
this.contScope = VirtualThread.continuationScope();
this.continuation = null;
} else {
this.contScope = scope;
this.continuation = walker.getContinuation();
}
}
private int toStackWalkMode(StackWalker walker, int mode) {
@ -236,6 +248,12 @@ final class StackStreamFactory {
*/
final R walk() {
checkState(NEW);
return (continuation != null)
? Continuation.wrapWalk(continuation, contScope, this::walkHelper)
: walkHelper();
}
private final R walkHelper() {
try {
// VM will need to stabilize the stack before walking. It will invoke
// the AbstractStackWalker::doStackWalk method once it fetches the first batch.
@ -311,7 +329,10 @@ final class StackStreamFactory {
*/
private int getNextBatch() {
int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize());
if (!frameBuffer.isActive() || nextBatchSize <= 0) {
if (!frameBuffer.isActive()
|| (nextBatchSize <= 0)
|| (frameBuffer.isAtBottom() && !hasMoreContinuations())) {
if (isDebug) {
System.out.format(" more stack walk done%n");
}
@ -319,7 +340,26 @@ final class StackStreamFactory {
return 0;
}
return fetchStackFrames(nextBatchSize);
if (frameBuffer.isAtBottom() && hasMoreContinuations()) {
setContinuation(continuation.getParent());
}
int numFrames = fetchStackFrames(nextBatchSize);
if (numFrames == 0 && !hasMoreContinuations()) {
frameBuffer.freeze(); // done stack walking
}
return numFrames;
}
private boolean hasMoreContinuations() {
return (continuation != null)
&& (continuation.getScope() != contScope)
&& (continuation.getParent() != null);
}
private void setContinuation(Continuation cont) {
this.continuation = cont;
setContinuation(anchor, frameBuffer.frames(), cont);
}
/*
@ -368,6 +408,7 @@ final class StackStreamFactory {
initFrameBuffer();
return callStackWalk(mode, 0,
contScope, continuation,
frameBuffer.curBatchFrameCount(),
frameBuffer.startIndex(),
frameBuffer.frames());
@ -390,10 +431,10 @@ final class StackStreamFactory {
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.freeze(); // done stack walking
} else {
if (numFrames > 0) {
frameBuffer.setBatch(depth, startIndex, endIndex);
}
return numFrames;
@ -405,6 +446,8 @@ final class StackStreamFactory {
*
* @param mode mode of stack walking
* @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 startIndex start index of the frame buffers to be filled.
* @param frames Either a Class<?> array, if mode is {@link #FILL_CLASS_REFS_ONLY}
@ -412,6 +455,7 @@ final class StackStreamFactory {
* @return Result of AbstractStackWalker::doStackWalk
*/
private native R callStackWalk(long mode, int skipframes,
ContinuationScope contScope, Continuation continuation,
int batchSize, int startIndex,
T[] frames);
@ -430,6 +474,8 @@ final class StackStreamFactory {
private native int fetchStackFrames(long mode, long anchor,
int batchSize, int startIndex,
T[] frames);
private native void setContinuation(long anchor, T[] frames, Continuation cont);
}
/*
@ -497,6 +543,12 @@ final class StackStreamFactory {
final Class<?> at(int index) {
return stackFrames[index].declaringClass();
}
@Override
final boolean filter(int index) {
return stackFrames[index].declaringClass() == Continuation.class
&& "yield0".equals(stackFrames[index].getMethodName());
}
}
final Function<? super Stream<StackFrame>, ? extends T> function; // callback
@ -633,6 +685,9 @@ final class StackStreamFactory {
@Override
final Class<?> at(int index) { return classes[index];}
@Override
final boolean filter(int index) { return false; }
// ------ subclass may override the following methods -------
/**
@ -765,6 +820,12 @@ final class StackStreamFactory {
final Class<?> at(int index) {
return stackFrames[index].declaringClass();
}
@Override
final boolean filter(int index) {
return stackFrames[index].declaringClass() == Continuation.class
&& "yield0".equals(stackFrames[index].getMethodName());
}
}
LiveStackInfoTraverser(StackWalker walker,
@ -834,6 +895,13 @@ final class StackStreamFactory {
*/
abstract Class<?> at(int index);
/**
* Filter out frames at the top of a batch
* @param index the position of the frame.
* @return true if the frame should be skipped
*/
abstract boolean filter(int index);
// ------ subclass may override the following methods -------
/*
@ -881,7 +949,15 @@ final class StackStreamFactory {
* it is done for traversal. All stack frames have been traversed.
*/
final boolean isActive() {
return origin > 0 && (fence == 0 || origin < fence || fence == currentBatchSize);
return origin > 0; // && (fence == 0 || origin < fence || fence == currentBatchSize);
}
/*
* Tests if this frame buffer is at the end of the stack
* and all frames have been traversed.
*/
final boolean isAtBottom() {
return origin > 0 && origin >= fence && fence < currentBatchSize;
}
/**
@ -929,16 +1005,13 @@ final class StackStreamFactory {
this.origin = startIndex;
this.fence = endIndex;
if (depth == 0 && fence > 0) {
// filter the frames due to the stack stream implementation
for (int i = START_POS; i < fence; i++) {
Class<?> c = at(i);
if (isDebug) System.err.format(" frame %d: %s%n", i, c);
if (filterStackWalkImpl(c)) {
origin++;
} else {
break;
}
for (int i = START_POS; 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
|| filter(i)) {
origin++;
} else {
break;
}
}
}