Skip to content

[GR-34749] Continuation support independent of Project Loom. #4114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d83f446
Foundation for implementing continuations independent of Loom.
peter-hofer Nov 10, 2021
46c160d
Refactor to use internal Continuation interface.
peter-hofer Nov 15, 2021
88650f0
Implement elementary non-Loom continuation support.
peter-hofer Nov 19, 2021
b922d39
Introduce the notion of platform threads.
peter-hofer Dec 6, 2021
7418ff6
Support Thread.currentThread() for virtual threads.
peter-hofer Dec 7, 2021
d646ec5
Support yielding virtual threads.
peter-hofer Dec 7, 2021
b8a45a5
Park/unpark, interrupt, sleep in, and join with virtual threads.
peter-hofer Dec 7, 2021
4a30be1
Abstract away virtual threads implementation.
peter-hofer Dec 10, 2021
fb394b8
Monitors do not pin continuations because we implement them via Reent…
peter-hofer Dec 14, 2021
011f19b
Support pinning and do not permit yield with native frames.
peter-hofer Dec 14, 2021
65604d9
Separate Continuation and Loom Continuation classes and eliminate Jav…
peter-hofer Dec 14, 2021
4afa220
Ensure that virtual thread code is unreachable when disabled.
peter-hofer Dec 16, 2021
639cd85
Implement workaround for JavaThreads subclasses.
peter-hofer Dec 17, 2021
6ca3a0f
Safely initialize StoredContinuation with regard to GC.
peter-hofer Dec 22, 2021
9bfa2fa
Save and restore the state of stack overflow checks for continuations.
peter-hofer Dec 22, 2021
d71a566
Acquire a virtual thread's interrupt lock on the carrier thread to av…
peter-hofer Jan 7, 2022
3784a76
Do not use ThreadGroup for virtual threads.
peter-hofer Jan 10, 2022
2111ec9
Minor cleanups and improvements, and documentation.
peter-hofer Jan 26, 2022
c172e3c
Unsafe.unpark should be a no-op for null or virtual threads.
peter-hofer Jan 26, 2022
da1a0b9
Clear carrier interrupt in SubstrateVirtualThread.interrupted(), alwa…
peter-hofer Jan 26, 2022
bb7d175
Pin virtual threads when acquiring monitors via JNI.
peter-hofer Jan 28, 2022
56804e7
Split class PlatformThreads off from JavaThreads.
peter-hofer Jan 28, 2022
0f915d6
Rename VirtualThreads.get() to .singleton() for consistency.
peter-hofer Jan 31, 2022
6828076
Allocate StoredContinuation as array via paths specific to Serial GC.
peter-hofer Feb 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ protected Object allocateInstanceImpl(Word hub,
result = formatObject(hub, prototypeMarkWord, size, top, fillContents, emitMemoryBarrier, constantSize, profilingData.snippetCounters);
} else {
profilingData.snippetCounters.stub.inc();
result = callNewInstanceStub(hub, size);
result = callNewInstanceStub(hub);
}
profileAllocation(profilingData, size);
return verifyOop(result);
Expand Down Expand Up @@ -276,9 +276,7 @@ protected Object formatObject(Word hub,
} else if (REPLACEMENTS_ASSERTIONS_ENABLED && fillContents == FillContent.WITH_GARBAGE_IF_ASSERTIONS_ENABLED) {
fillWithGarbage(memory, headerSize, size, constantSize, false, false, snippetCounters);
}
if (emitMemoryBarrier) {
MembarNode.memoryBarrier(MembarNode.FenceKind.ALLOCATION_INIT, LocationIdentity.init());
}
emitMemoryBarrierIf(emitMemoryBarrier);
return memory.toObjectNonNull();
}

Expand Down Expand Up @@ -306,10 +304,14 @@ protected Object formatArray(Word hub,
} else if (REPLACEMENTS_ASSERTIONS_ENABLED && fillContents == FillContent.WITH_GARBAGE_IF_ASSERTIONS_ENABLED) {
fillWithGarbage(memory, fillStartOffset, allocationSize, false, maybeUnroll, supportsOptimizedFilling, snippetCounters);
}
emitMemoryBarrierIf(emitMemoryBarrier);
return memory.toObjectNonNull();
}

protected void emitMemoryBarrierIf(boolean emitMemoryBarrier) {
if (emitMemoryBarrier) {
MembarNode.memoryBarrier(MembarNode.FenceKind.ALLOCATION_INIT, LocationIdentity.init());
}
return memory.toObjectNonNull();
}

public void emitPrefetchAllocate(Word address, boolean isArray) {
Expand Down Expand Up @@ -351,11 +353,6 @@ public void emitPrefetchAllocate(Word address, boolean isArray) {

public abstract void initializeObjectHeader(Word memory, Word hub, Word prototypeMarkWord, boolean isArray);

@SuppressWarnings("unused")
protected Object callNewInstanceStub(Word hub, UnsignedWord size) {
return callNewInstanceStub(hub);
}

protected abstract Object callNewInstanceStub(Word hub);

protected abstract Object callNewArrayStub(Word hub, int length, int fillStartOffset);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import java.util.ArrayList;
import java.util.List;

import com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets;
import org.graalvm.compiler.api.replacements.Fold;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.SuppressFBWarnings;
Expand Down Expand Up @@ -58,6 +57,7 @@
import com.oracle.svm.core.genscavenge.ThreadLocalAllocation.Descriptor;
import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader;
import com.oracle.svm.core.genscavenge.remset.RememberedSet;
import com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets;
import com.oracle.svm.core.heap.GC;
import com.oracle.svm.core.heap.Heap;
import com.oracle.svm.core.heap.NoAllocationVerifier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
import static com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets.TLAB_END_IDENTITY;
import static com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets.TLAB_TOP_IDENTITY;

import com.oracle.svm.core.SubstrateGCOptions;
import com.oracle.svm.core.threadlocal.FastThreadLocalWord;
import org.graalvm.compiler.api.replacements.Fold;
import org.graalvm.compiler.replacements.AllocationSnippets.FillContent;
import org.graalvm.compiler.word.Word;
Expand All @@ -46,6 +44,7 @@
import org.graalvm.word.UnsignedWord;
import org.graalvm.word.WordFactory;

import com.oracle.svm.core.SubstrateGCOptions;
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.annotate.RestrictHeapAccess;
import com.oracle.svm.core.annotate.Uninterruptible;
Expand All @@ -65,6 +64,7 @@
import com.oracle.svm.core.threadlocal.FastThreadLocal;
import com.oracle.svm.core.threadlocal.FastThreadLocalBytes;
import com.oracle.svm.core.threadlocal.FastThreadLocalFactory;
import com.oracle.svm.core.threadlocal.FastThreadLocalWord;
import com.oracle.svm.core.util.VMError;

/**
Expand Down Expand Up @@ -157,7 +157,7 @@ private static Descriptor getTlab() {
}

@SubstrateForeignCallTarget(stubCallingConvention = false)
private static Object slowPathNewInstance(Word objectHeader, UnsignedWord size) {
private static Object slowPathNewInstance(Word objectHeader) {
/*
* Avoid stack overflow errors while producing memory chunks, because that could leave the
* heap in an inconsistent state.
Expand All @@ -166,9 +166,7 @@ private static Object slowPathNewInstance(Word objectHeader, UnsignedWord size)
try {
DynamicHub hub = ObjectHeaderImpl.getObjectHeaderImpl().dynamicHubFromObjectHeader(objectHeader);

// the instance either is a frame instance or the size can be read from the hub
assert hub.isStoredContinuationClass() || size.equal(hub.getLayoutEncoding());
Object result = slowPathNewInstanceWithoutAllocating(hub, size);
Object result = slowPathNewInstanceWithoutAllocating(hub);
runSlowPathHooks();
return result;
} finally {
Expand All @@ -188,14 +186,14 @@ private static void runSlowPathHooks() {
}

@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate in the implementation of allocation.")
private static Object slowPathNewInstanceWithoutAllocating(DynamicHub hub, UnsignedWord size) {
private static Object slowPathNewInstanceWithoutAllocating(DynamicHub hub) {
DeoptTester.disableDeoptTesting();
try {
HeapImpl.exitIfAllocationDisallowed("ThreadLocalAllocation.allocateNewInstance", DynamicHub.toClass(hub).getName());
GCImpl.getGCImpl().maybeCollectOnAllocation();

AlignedHeader newTlab = HeapImpl.getChunkProvider().produceAlignedChunk();
return allocateInstanceInNewTlab(hub, size, newTlab);
return allocateInstanceInNewTlab(hub, newTlab);
} finally {
DeoptTester.enableDeoptTesting();
}
Expand Down Expand Up @@ -262,7 +260,8 @@ private static Object slowPathNewArrayWithoutAllocating(DynamicHub hub, int leng
}

@Uninterruptible(reason = "Holds uninitialized memory.")
private static Object allocateInstanceInNewTlab(DynamicHub hub, UnsignedWord size, AlignedHeader newTlabChunk) {
private static Object allocateInstanceInNewTlab(DynamicHub hub, AlignedHeader newTlabChunk) {
UnsignedWord size = LayoutEncoding.getInstanceSize(hub.getLayoutEncoding());
Pointer memory = allocateRawMemoryInNewTlab(size, newTlabChunk);
return FormatObjectNode.formatObject(memory, DynamicHub.toClass(hub), false, FillContent.WITH_ZEROES, true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import com.oracle.svm.core.genscavenge.remset.RememberedSet;
import com.oracle.svm.core.graal.snippets.NodeLoweringProvider;
import com.oracle.svm.core.graal.snippets.SubstrateTemplates;
import com.oracle.svm.core.heap.StoredContinuation;
import com.oracle.svm.core.option.HostedOptionKey;
import com.oracle.svm.core.util.Counter;
import com.oracle.svm.core.util.CounterFeature;
Expand Down Expand Up @@ -88,7 +89,7 @@ static BarrierSnippetCounters counters() {
}

public void registerLowerings(Map<Class<? extends Node>, NodeLoweringProvider<?>> lowerings) {
PostWriteBarrierLowering lowering = new PostWriteBarrierLowering();
PostWriteBarrierLowering lowering = new PostWriteBarrierLowering(providers);
lowerings.put(SerialWriteBarrier.class, lowering);
// write barriers are currently always imprecise
lowerings.put(SerialArrayRangeWriteBarrier.class, lowering);
Expand Down Expand Up @@ -133,6 +134,11 @@ public static void postWriteBarrierSnippet(Object object, @ConstantParameter boo

private class PostWriteBarrierLowering implements NodeLoweringProvider<WriteBarrier> {
private final SnippetInfo postWriteBarrierSnippet = snippet(BarrierSnippets.class, "postWriteBarrierSnippet", CARD_REMEMBERED_SET_LOCATION);
private final ResolvedJavaType storedContinuationType;

PostWriteBarrierLowering(Providers providers) {
storedContinuationType = providers.getMetaAccess().lookupJavaType(StoredContinuation.class);
}

@Override
public void lower(WriteBarrier barrier, LoweringTool tool) {
Expand All @@ -148,6 +154,7 @@ public void lower(WriteBarrier barrier, LoweringTool tool) {
* For simplicity, we exclude all interface types.
*/
ResolvedJavaType baseType = StampTool.typeOrNull(address.getBase());
assert baseType == null || !storedContinuationType.isAssignableFrom(baseType) : "StoredContinuation should be effectively immutable and references only be written by GC";
boolean alwaysAlignedChunk = baseType != null && !baseType.isArray() && !baseType.isJavaLangObject() && !baseType.isInterface();

args.add("object", address.getBase());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@
*/
package com.oracle.svm.core.genscavenge.graal;

import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;

import java.util.Map;

import org.graalvm.compiler.api.replacements.Snippet;
import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.PiNode;
import org.graalvm.compiler.nodes.SnippetAnchorNode;
import org.graalvm.compiler.nodes.StructuredGraph;
Expand All @@ -51,13 +55,19 @@
import com.oracle.svm.core.genscavenge.graal.nodes.FormatArrayNode;
import com.oracle.svm.core.genscavenge.graal.nodes.FormatObjectNode;
import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider;
import com.oracle.svm.core.graal.nodes.NewStoredContinuationNode;
import com.oracle.svm.core.graal.snippets.NodeLoweringProvider;
import com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets;
import com.oracle.svm.core.heap.Heap;
import com.oracle.svm.core.heap.StoredContinuation;
import com.oracle.svm.core.heap.StoredContinuationImpl;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.LayoutEncoding;
import com.oracle.svm.core.meta.SharedType;
import com.oracle.svm.core.meta.SubstrateObjectConstant;
import com.oracle.svm.core.snippets.SnippetRuntime;
import com.oracle.svm.core.snippets.SnippetRuntime.SubstrateForeignCallDescriptor;
import com.oracle.svm.core.thread.Continuation;

final class GenScavengeAllocationSnippets extends SubstrateAllocationSnippets {
private static final SubstrateForeignCallDescriptor SLOW_NEW_INSTANCE = SnippetRuntime.findForeignCall(ThreadLocalAllocation.class, "slowPathNewInstance", true);
Expand Down Expand Up @@ -94,14 +104,33 @@ public Object formatArraySnippet(Word memory, DynamicHub hub, int length, boolea
int layoutEncoding = hubNonNull.getLayoutEncoding();
UnsignedWord size = LayoutEncoding.getArraySize(layoutEncoding, length);
Word objectHeader = encodeAsObjectHeader(hubNonNull, rememberedSet, unaligned);
return formatArray(objectHeader, WordFactory.nullPointer(), size, length, memory, fillContents, fillStartOffset,
emitMemoryBarrier, false, supportsBulkZeroing, supportsOptimizedFilling, snippetCounters);
Object obj = formatArray(objectHeader, WordFactory.nullPointer(), size, length, memory, fillContents, fillStartOffset,
false, false, supportsBulkZeroing, supportsOptimizedFilling, snippetCounters);
if (probability(SLOW_PATH_PROBABILITY, Continuation.isSupported() && hub == DynamicHub.fromClass(StoredContinuation.class))) {
finishFormatStoredContinuation(obj);
}
emitMemoryBarrierIf(emitMemoryBarrier);
return obj;
}

private static Word encodeAsObjectHeader(DynamicHub hub, boolean rememberedSet, boolean unaligned) {
return ObjectHeaderImpl.encodeAsObjectHeader(hub, rememberedSet, unaligned);
}

@Snippet
public Object allocateStoredContinuationInstance(@Snippet.NonNullParameter DynamicHub hub, int size, @ConstantParameter AllocationProfilingData profilingData) {
int baseOffset = StoredContinuationImpl.PAYLOAD_OFFSET;
Object result = allocateArrayImpl(encodeAsTLABObjectHeader(hub), WordFactory.nullPointer(), size, baseOffset, 0,
FillContent.WITH_GARBAGE_IF_ASSERTIONS_ENABLED, baseOffset, false, false, false, false, profilingData);
finishFormatStoredContinuation(result);
emitMemoryBarrierIf(true);
return PiNode.piCastToSnippetReplaceeStamp(result);
}

private static void finishFormatStoredContinuation(Object obj) {
StoredContinuationImpl.initializeNewlyAllocated(obj);
}

@Override
public void initializeObjectHeader(Word memory, Word objectHeader, Word prototypeMarkWord, boolean isArray) {
Heap.getHeap().getObjectHeader().initializeHeaderOfNewObject(memory, objectHeader);
Expand Down Expand Up @@ -150,12 +179,14 @@ protected SubstrateForeignCallDescriptor getSlowNewArrayStub() {
public static class Templates extends SubstrateAllocationSnippets.Templates {
private final SnippetInfo formatObject;
private final SnippetInfo formatArray;
private final SnippetInfo allocateStoredContinuationInstance;

Templates(SubstrateAllocationSnippets receiver, OptionValues options, SnippetCounter.Group.Factory groupFactory, Providers providers) {
super(receiver, options, groupFactory, providers);

formatObject = snippet(GenScavengeAllocationSnippets.class, "formatObjectSnippet", null, receiver);
formatArray = snippet(GenScavengeAllocationSnippets.class, "formatArraySnippet", null, receiver);
allocateStoredContinuationInstance = snippet(GenScavengeAllocationSnippets.class, "allocateStoredContinuationInstance", null, receiver, ALLOCATION_LOCATIONS);
}

@Override
Expand All @@ -167,6 +198,9 @@ public void registerLowerings(Map<Class<? extends Node>, NodeLoweringProvider<?>

FormatArrayLowering formatArrayLowering = new FormatArrayLowering();
lowerings.put(FormatArrayNode.class, formatArrayLowering);

NewStoredContinuationLowering newStoredContinuationLowering = new NewStoredContinuationLowering();
lowerings.put(NewStoredContinuationNode.class, newStoredContinuationLowering);
}

private class FormatObjectLowering implements NodeLoweringProvider<FormatObjectNode> {
Expand Down Expand Up @@ -209,5 +243,28 @@ public void lower(FormatArrayNode node, LoweringTool tool) {
template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
}
}

private class NewStoredContinuationLowering implements NodeLoweringProvider<NewStoredContinuationNode> {
@Override
public void lower(NewStoredContinuationNode node, LoweringTool tool) {
StructuredGraph graph = node.graph();

if (graph.getGuardsStage() != StructuredGraph.GuardsStage.AFTER_FSA) {
return;
}

DynamicHub hub = ((SharedType) tool.getMetaAccess().lookupJavaType(StoredContinuation.class)).getHub();
assert hub.isStoredContinuationClass();

ConstantNode hubConstant = ConstantNode.forConstant(SubstrateObjectConstant.forObject(hub), providers.getMetaAccess(), graph);

Arguments args = new Arguments(allocateStoredContinuationInstance, graph.getGuardsStage(), tool.getLoweringStage());
args.add("hub", hubConstant);
args.add("size", node.getSize());
args.addConst("profilingData", getProfilingData(node, null));

template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
}
}
}
}
Loading