mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[vm] New async*/yield/yield* implementation based on suspend/resume stubs
TEST=ci Issue: https://github.com/dart-lang/sdk/issues/48378 Change-Id: I0c2ca9269b2c8f008a79c139a0ce10231996732d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/242923 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
0d5d34a2ed
commit
4075e8b3f9
|
@ -1371,7 +1371,7 @@ type TryFinally extends Statement {
|
|||
type YieldStatement extends Statement {
|
||||
Byte tag = 77;
|
||||
FileOffset fileOffset;
|
||||
Byte flags (isYieldStar);
|
||||
Byte flags (isYieldStar, isNative);
|
||||
Expression expression;
|
||||
}
|
||||
|
||||
|
|
|
@ -158,9 +158,16 @@ class RecursiveContinuationRewriter extends RemovingTransformer {
|
|||
return node;
|
||||
}
|
||||
case AsyncMarker.AsyncStar:
|
||||
return new AsyncStarFunctionRewriter(
|
||||
helper, node, staticTypeContext, desugarAsync)
|
||||
.rewrite();
|
||||
if (desugarAsync) {
|
||||
return new AsyncStarFunctionRewriter(
|
||||
helper, node, staticTypeContext, desugarAsync)
|
||||
.rewrite();
|
||||
} else {
|
||||
node.transformOrRemoveChildren(new RecursiveContinuationRewriter(
|
||||
helper, staticTypeContext, desugarAsync,
|
||||
desugarAwaitFor: true));
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,9 @@ class ExceptionHandlerList : public ZoneAllocated {
|
|||
};
|
||||
|
||||
explicit ExceptionHandlerList(const Function& function)
|
||||
: list_(), has_async_handler_(function.IsCompactAsyncFunction()) {}
|
||||
: list_(),
|
||||
has_async_handler_(function.IsCompactAsyncFunction() ||
|
||||
function.IsCompactAsyncStarFunction()) {}
|
||||
|
||||
intptr_t Length() const { return list_.length(); }
|
||||
|
||||
|
|
|
@ -376,7 +376,7 @@ void FlowGraphCompiler::EmitPrologue() {
|
|||
} else if (parsed_function().suspend_state_var() != nullptr) {
|
||||
// Initialize synthetic :suspend_state variable early
|
||||
// as it may be accessed by GC and exception handling before
|
||||
// InitAsync stub is called.
|
||||
// InitSuspendableFunction stub is called.
|
||||
const intptr_t slot_index =
|
||||
compiler::target::frame_layout.FrameSlotForVariable(
|
||||
parsed_function().suspend_state_var());
|
||||
|
|
|
@ -366,7 +366,7 @@ void FlowGraphCompiler::EmitPrologue() {
|
|||
} else if (parsed_function().suspend_state_var() != nullptr) {
|
||||
// Initialize synthetic :suspend_state variable early
|
||||
// as it may be accessed by GC and exception handling before
|
||||
// InitAsync stub is called.
|
||||
// InitSuspendableFunction stub is called.
|
||||
const intptr_t slot_index =
|
||||
compiler::target::frame_layout.FrameSlotForVariable(
|
||||
parsed_function().suspend_state_var());
|
||||
|
|
|
@ -453,7 +453,7 @@ void FlowGraphCompiler::EmitPrologue() {
|
|||
} else if (parsed_function().suspend_state_var() != nullptr) {
|
||||
// Initialize synthetic :suspend_state variable early
|
||||
// as it may be accessed by GC and exception handling before
|
||||
// InitAsync stub is called.
|
||||
// InitSuspendableFunction stub is called.
|
||||
const intptr_t slot_index =
|
||||
compiler::target::frame_layout.FrameSlotForVariable(
|
||||
parsed_function().suspend_state_var());
|
||||
|
|
|
@ -360,7 +360,7 @@ void FlowGraphCompiler::EmitPrologue() {
|
|||
} else if (parsed_function().suspend_state_var() != nullptr) {
|
||||
// Initialize synthetic :suspend_state variable early
|
||||
// as it may be accessed by GC and exception handling before
|
||||
// InitAsync stub is called.
|
||||
// InitSuspendableFunction stub is called.
|
||||
const intptr_t slot_index =
|
||||
compiler::target::frame_layout.FrameSlotForVariable(
|
||||
parsed_function().suspend_state_var());
|
||||
|
|
|
@ -372,7 +372,7 @@ void FlowGraphCompiler::EmitPrologue() {
|
|||
} else if (parsed_function().suspend_state_var() != nullptr) {
|
||||
// Initialize synthetic :suspend_state variable early
|
||||
// as it may be accessed by GC and exception handling before
|
||||
// InitAsync stub is called.
|
||||
// InitSuspendableFunction stub is called.
|
||||
const intptr_t slot_index =
|
||||
compiler::target::frame_layout.FrameSlotForVariable(
|
||||
parsed_function().suspend_state_var());
|
||||
|
|
|
@ -6901,16 +6901,25 @@ void RawStoreFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
}
|
||||
|
||||
const Code& ReturnInstr::GetReturnStub(FlowGraphCompiler* compiler) const {
|
||||
ASSERT(compiler->parsed_function().function().IsCompactAsyncFunction());
|
||||
if (!value()->Type()->CanBeFuture()) {
|
||||
return Code::ZoneHandle(compiler->zone(),
|
||||
compiler->isolate_group()
|
||||
->object_store()
|
||||
->return_async_not_future_stub());
|
||||
const Function& function = compiler->parsed_function().function();
|
||||
ASSERT(function.IsSuspendableFunction());
|
||||
if (function.IsCompactAsyncFunction()) {
|
||||
if (!value()->Type()->CanBeFuture()) {
|
||||
return Code::ZoneHandle(compiler->zone(),
|
||||
compiler->isolate_group()
|
||||
->object_store()
|
||||
->return_async_not_future_stub());
|
||||
}
|
||||
return Code::ZoneHandle(
|
||||
compiler->zone(),
|
||||
compiler->isolate_group()->object_store()->return_async_stub());
|
||||
} else if (function.IsCompactAsyncStarFunction()) {
|
||||
return Code::ZoneHandle(
|
||||
compiler->zone(),
|
||||
compiler->isolate_group()->object_store()->return_async_star_stub());
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
return Code::ZoneHandle(
|
||||
compiler->zone(),
|
||||
compiler->isolate_group()->object_store()->return_async_stub());
|
||||
}
|
||||
|
||||
void NativeReturnInstr::EmitReturnMoves(FlowGraphCompiler* compiler) {
|
||||
|
@ -7230,10 +7239,12 @@ LocationSummary* Call1ArgStubInstr::MakeLocationSummary(Zone* zone,
|
|||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
switch (stub_id_) {
|
||||
case StubId::kInitAsync:
|
||||
case StubId::kInitAsyncStar:
|
||||
locs->set_in(0, Location::RegisterLocation(
|
||||
InitSuspendableFunctionStubABI::kTypeArgsReg));
|
||||
break;
|
||||
case StubId::kAwaitAsync:
|
||||
case StubId::kAwait:
|
||||
case StubId::kYieldAsyncStar:
|
||||
locs->set_in(0, Location::RegisterLocation(SuspendStubABI::kArgumentReg));
|
||||
break;
|
||||
}
|
||||
|
@ -7248,15 +7259,21 @@ void Call1ArgStubInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
case StubId::kInitAsync:
|
||||
stub = object_store->init_async_stub();
|
||||
break;
|
||||
case StubId::kAwaitAsync:
|
||||
stub = object_store->await_async_stub();
|
||||
case StubId::kAwait:
|
||||
stub = object_store->await_stub();
|
||||
break;
|
||||
case StubId::kInitAsyncStar:
|
||||
stub = object_store->init_async_star_stub();
|
||||
break;
|
||||
case StubId::kYieldAsyncStar:
|
||||
stub = object_store->yield_async_star_stub();
|
||||
break;
|
||||
}
|
||||
compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
|
||||
locs(), deopt_id(), env());
|
||||
|
||||
#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_IA32)
|
||||
if (stub_id_ == StubId::kAwaitAsync) {
|
||||
if ((stub_id_ == StubId::kAwait) || (stub_id_ == StubId::kYieldAsyncStar)) {
|
||||
// On x86 (X64 and IA32) mismatch between calls and returns
|
||||
// significantly regresses performance. So suspend stub
|
||||
// does not return directly to the caller. Instead, a small
|
||||
|
|
|
@ -9567,8 +9567,10 @@ class SimdOpInstr : public Definition {
|
|||
class Call1ArgStubInstr : public TemplateDefinition<1, Throws> {
|
||||
public:
|
||||
enum class StubId {
|
||||
kAwait,
|
||||
kInitAsync,
|
||||
kAwaitAsync,
|
||||
kInitAsyncStar,
|
||||
kYieldAsyncStar,
|
||||
};
|
||||
|
||||
Call1ArgStubInstr(const InstructionSource& source,
|
||||
|
|
|
@ -484,7 +484,7 @@ void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
ASSERT(result == CallingConventions::kReturnFpuReg);
|
||||
}
|
||||
|
||||
if (compiler->parsed_function().function().IsCompactAsyncFunction()) {
|
||||
if (compiler->parsed_function().function().IsSuspendableFunction()) {
|
||||
ASSERT(compiler->flow_graph().graph_entry()->NeedsFrame());
|
||||
const Code& stub = GetReturnStub(compiler);
|
||||
compiler->EmitJumpToStub(stub);
|
||||
|
|
|
@ -411,7 +411,7 @@ void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
ASSERT(result == CallingConventions::kReturnFpuReg);
|
||||
}
|
||||
|
||||
if (compiler->parsed_function().function().IsCompactAsyncFunction()) {
|
||||
if (compiler->parsed_function().function().IsSuspendableFunction()) {
|
||||
ASSERT(compiler->flow_graph().graph_entry()->NeedsFrame());
|
||||
const Code& stub = GetReturnStub(compiler);
|
||||
compiler->EmitJumpToStub(stub);
|
||||
|
|
|
@ -233,7 +233,7 @@ void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
Register result = locs()->in(0).reg();
|
||||
ASSERT(result == EAX);
|
||||
|
||||
if (compiler->parsed_function().function().IsCompactAsyncFunction()) {
|
||||
if (compiler->parsed_function().function().IsSuspendableFunction()) {
|
||||
ASSERT(compiler->flow_graph().graph_entry()->NeedsFrame());
|
||||
const Code& stub = GetReturnStub(compiler);
|
||||
compiler->EmitJumpToStub(stub);
|
||||
|
|
|
@ -1362,8 +1362,14 @@ void Call1ArgStubInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|||
case StubId::kInitAsync:
|
||||
name = "InitAsync";
|
||||
break;
|
||||
case StubId::kAwaitAsync:
|
||||
name = "AwaitAsync";
|
||||
case StubId::kAwait:
|
||||
name = "Await";
|
||||
break;
|
||||
case StubId::kInitAsyncStar:
|
||||
name = "InitAsyncStar";
|
||||
break;
|
||||
case StubId::kYieldAsyncStar:
|
||||
name = "YieldAsyncStar";
|
||||
break;
|
||||
}
|
||||
f->Printf("%s(", name);
|
||||
|
|
|
@ -464,7 +464,7 @@ void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
ASSERT(result == CallingConventions::kReturnFpuReg);
|
||||
}
|
||||
|
||||
if (compiler->parsed_function().function().IsCompactAsyncFunction()) {
|
||||
if (compiler->parsed_function().function().IsSuspendableFunction()) {
|
||||
ASSERT(compiler->flow_graph().graph_entry()->NeedsFrame());
|
||||
const Code& stub = GetReturnStub(compiler);
|
||||
compiler->EmitJumpToStub(stub);
|
||||
|
|
|
@ -338,7 +338,7 @@ void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
ASSERT(result == CallingConventions::kReturnFpuReg);
|
||||
}
|
||||
|
||||
if (compiler->parsed_function().function().IsCompactAsyncFunction()) {
|
||||
if (compiler->parsed_function().function().IsSuspendableFunction()) {
|
||||
ASSERT(compiler->flow_graph().graph_entry()->NeedsFrame());
|
||||
const Code& stub = GetReturnStub(compiler);
|
||||
compiler->EmitJumpToStub(stub);
|
||||
|
|
|
@ -2814,7 +2814,7 @@ void LoadFieldInstr::InferRange(RangeAnalysis* analysis, Range* range) {
|
|||
case Slot::Kind::kFunctionType_parameter_types:
|
||||
case Slot::Kind::kFunctionType_type_parameters:
|
||||
case Slot::Kind::kInstance_native_fields_array:
|
||||
case Slot::Kind::kSuspendState_future:
|
||||
case Slot::Kind::kSuspendState_function_data:
|
||||
case Slot::Kind::kSuspendState_then_callback:
|
||||
case Slot::Kind::kSuspendState_error_callback:
|
||||
case Slot::Kind::kTypedDataView_typed_data:
|
||||
|
|
|
@ -243,7 +243,7 @@ bool Slot::IsImmutableLengthSlot() const {
|
|||
case Slot::Kind::kFunctionType_named_parameter_names:
|
||||
case Slot::Kind::kFunctionType_parameter_types:
|
||||
case Slot::Kind::kFunctionType_type_parameters:
|
||||
case Slot::Kind::kSuspendState_future:
|
||||
case Slot::Kind::kSuspendState_function_data:
|
||||
case Slot::Kind::kSuspendState_then_callback:
|
||||
case Slot::Kind::kSuspendState_error_callback:
|
||||
case Slot::Kind::kType_arguments:
|
||||
|
|
|
@ -73,7 +73,7 @@ class ParsedFunction;
|
|||
V(ImmutableLinkedHashBase, UntaggedLinkedHashBase, index, \
|
||||
TypedDataUint32Array, VAR) \
|
||||
V(Instance, UntaggedInstance, native_fields_array, Dynamic, VAR) \
|
||||
V(SuspendState, UntaggedSuspendState, future, Dynamic, VAR) \
|
||||
V(SuspendState, UntaggedSuspendState, function_data, Dynamic, VAR) \
|
||||
V(SuspendState, UntaggedSuspendState, then_callback, Closure, VAR) \
|
||||
V(SuspendState, UntaggedSuspendState, error_callback, Closure, VAR) \
|
||||
V(Type, UntaggedType, arguments, TypeArguments, FINAL) \
|
||||
|
|
|
@ -684,6 +684,24 @@ Fragment StreamingFlowGraphBuilder::InitSuspendableFunction(
|
|||
body += B->Call1ArgStub(TokenPosition::kNoSource,
|
||||
Call1ArgStubInstr::StubId::kInitAsync);
|
||||
body += Drop();
|
||||
} else if (dart_function.IsCompactAsyncStarFunction()) {
|
||||
const auto& result_type =
|
||||
AbstractType::Handle(Z, dart_function.result_type());
|
||||
auto& type_args = TypeArguments::ZoneHandle(Z);
|
||||
if (result_type.IsType() &&
|
||||
(result_type.type_class() == IG->object_store()->stream_class())) {
|
||||
ASSERT(result_type.IsFinalized());
|
||||
type_args = result_type.arguments();
|
||||
}
|
||||
|
||||
body += TranslateInstantiatedTypeArguments(type_args);
|
||||
body += B->Call1ArgStub(TokenPosition::kNoSource,
|
||||
Call1ArgStubInstr::StubId::kInitAsyncStar);
|
||||
body += Drop();
|
||||
body += NullConstant();
|
||||
body += B->Call1ArgStub(TokenPosition::kNoSource,
|
||||
Call1ArgStubInstr::StubId::kYieldAsyncStar);
|
||||
body += Drop();
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
@ -4322,7 +4340,8 @@ Fragment StreamingFlowGraphBuilder::BuildLibraryPrefixAction(
|
|||
|
||||
Fragment StreamingFlowGraphBuilder::BuildAwaitExpression(
|
||||
TokenPosition* position) {
|
||||
ASSERT(parsed_function()->function().IsCompactAsyncFunction());
|
||||
ASSERT(parsed_function()->function().IsCompactAsyncFunction() ||
|
||||
parsed_function()->function().IsCompactAsyncStarFunction());
|
||||
Fragment instructions;
|
||||
|
||||
const TokenPosition pos = ReadPosition(); // read file offset.
|
||||
|
@ -4330,7 +4349,7 @@ Fragment StreamingFlowGraphBuilder::BuildAwaitExpression(
|
|||
|
||||
instructions += BuildExpression(); // read operand.
|
||||
|
||||
instructions += B->Call1ArgStub(pos, Call1ArgStubInstr::StubId::kAwaitAsync);
|
||||
instructions += B->Call1ArgStub(pos, Call1ArgStubInstr::StubId::kAwait);
|
||||
return instructions;
|
||||
}
|
||||
|
||||
|
@ -5228,8 +5247,83 @@ Fragment StreamingFlowGraphBuilder::BuildYieldStatement(
|
|||
const TokenPosition pos = ReadPosition(); // read position.
|
||||
if (position != nullptr) *position = pos;
|
||||
|
||||
uint8_t flags = ReadByte(); // read flags.
|
||||
ASSERT(flags == kNativeYieldFlags); // Must have been desugared.
|
||||
const uint8_t flags = ReadByte(); // read flags.
|
||||
|
||||
if ((flags & kYieldStatementFlagNative) == 0) {
|
||||
Fragment instructions;
|
||||
// Generate the following code for yield <expr>:
|
||||
//
|
||||
// _AsyncStarStreamController controller = :suspend_state._functionData;
|
||||
// if (controller.add(<expr>)) {
|
||||
// return;
|
||||
// }
|
||||
// suspend();
|
||||
//
|
||||
// Generate the following code for yield* <expr>:
|
||||
//
|
||||
// _AsyncStarStreamController controller = :suspend_state._functionData;
|
||||
// controller.addStream(<expr>);
|
||||
// if (suspend()) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
|
||||
// Load :suspend_state variable using low-level FP-relative load
|
||||
// in order to avoid confusing SSA construction (which cannot
|
||||
// track its value as it is modified implicitly by stubs).
|
||||
LocalVariable* suspend_state = parsed_function()->suspend_state_var();
|
||||
ASSERT(suspend_state != nullptr);
|
||||
instructions += IntConstant(0);
|
||||
instructions += B->LoadFpRelativeSlot(
|
||||
compiler::target::frame_layout.FrameSlotForVariable(suspend_state) *
|
||||
compiler::target::kWordSize,
|
||||
CompileType::Dynamic(), kTagged);
|
||||
instructions += LoadNativeField(Slot::SuspendState_function_data());
|
||||
|
||||
instructions += BuildExpression(); // read expression.
|
||||
|
||||
auto& add_method = Function::ZoneHandle(Z);
|
||||
const bool is_yield_star = (flags & kYieldStatementFlagYieldStar) != 0;
|
||||
if (is_yield_star) {
|
||||
add_method =
|
||||
IG->object_store()->async_star_stream_controller_add_stream();
|
||||
} else {
|
||||
add_method = IG->object_store()->async_star_stream_controller_add();
|
||||
}
|
||||
instructions += StaticCall(pos, add_method, 2, ICData::kNoRebind);
|
||||
|
||||
if (is_yield_star) {
|
||||
// Discard result of _AsyncStarStreamController.addStream().
|
||||
instructions += Drop();
|
||||
// Suspend and test value passed to the resumed async* body.
|
||||
instructions += NullConstant();
|
||||
instructions +=
|
||||
B->Call1ArgStub(pos, Call1ArgStubInstr::StubId::kYieldAsyncStar);
|
||||
} else {
|
||||
// Test value returned by _AsyncStarStreamController.add().
|
||||
}
|
||||
|
||||
TargetEntryInstr* exit;
|
||||
TargetEntryInstr* continue_execution;
|
||||
instructions += BranchIfTrue(&exit, &continue_execution, false);
|
||||
|
||||
Fragment do_exit(exit);
|
||||
do_exit += TranslateFinallyFinalizers(nullptr, -1);
|
||||
do_exit += NullConstant();
|
||||
do_exit += Return(TokenPosition::kNoSource);
|
||||
|
||||
instructions = Fragment(instructions.entry, continue_execution);
|
||||
if (!is_yield_star) {
|
||||
instructions += NullConstant();
|
||||
instructions +=
|
||||
B->Call1ArgStub(pos, Call1ArgStubInstr::StubId::kYieldAsyncStar);
|
||||
instructions += Drop();
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
ASSERT(flags == kYieldStatementFlagNative); // Must have been desugared.
|
||||
|
||||
// Setup yield/continue point:
|
||||
//
|
||||
|
@ -5476,6 +5570,16 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
|
|||
function.set_is_inlinable(false);
|
||||
function.set_is_visible(true);
|
||||
ASSERT(function.IsCompactAsyncFunction());
|
||||
} else if (function_node_helper.async_marker_ ==
|
||||
FunctionNodeHelper::kAsyncStar) {
|
||||
if (!FLAG_precompiled_mode) {
|
||||
FATAL("Compact async* functions are only supported in AOT mode.");
|
||||
}
|
||||
function.set_modifier(UntaggedFunction::kAsyncGen);
|
||||
function.set_is_debuggable(true);
|
||||
function.set_is_inlinable(false);
|
||||
function.set_is_visible(true);
|
||||
ASSERT(function.IsCompactAsyncStarFunction());
|
||||
} else {
|
||||
ASSERT((function_node_helper.async_marker_ ==
|
||||
FunctionNodeHelper::kSync) ||
|
||||
|
@ -5514,6 +5618,7 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
|
|||
function.set_is_inlinable(!FLAG_lazy_async_stacks);
|
||||
}
|
||||
ASSERT(!function.IsCompactAsyncFunction());
|
||||
ASSERT(!function.IsCompactAsyncStarFunction());
|
||||
}
|
||||
|
||||
// If the start token position is synthetic, the end token position
|
||||
|
|
|
@ -834,7 +834,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
|
|||
V(LinkedHashBase_getIndex, LinkedHashBase_index) \
|
||||
V(LinkedHashBase_getUsedData, LinkedHashBase_used_data) \
|
||||
V(ObjectArrayLength, Array_length) \
|
||||
V(SuspendState_getFuture, SuspendState_future) \
|
||||
V(SuspendState_getFunctionData, SuspendState_function_data) \
|
||||
V(SuspendState_getThenCallback, SuspendState_then_callback) \
|
||||
V(SuspendState_getErrorCallback, SuspendState_error_callback) \
|
||||
V(TypedDataViewOffsetInBytes, TypedDataView_offset_in_bytes) \
|
||||
|
@ -852,7 +852,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
|
|||
V(NativeFinalizer_setCallback, NativeFinalizer_callback) \
|
||||
V(LinkedHashBase_setData, LinkedHashBase_data) \
|
||||
V(LinkedHashBase_setIndex, LinkedHashBase_index) \
|
||||
V(SuspendState_setFuture, SuspendState_future) \
|
||||
V(SuspendState_setFunctionData, SuspendState_function_data) \
|
||||
V(SuspendState_setThenCallback, SuspendState_then_callback) \
|
||||
V(SuspendState_setErrorCallback, SuspendState_error_callback) \
|
||||
V(WeakProperty_setKey, WeakProperty_key) \
|
||||
|
|
|
@ -89,7 +89,7 @@ ScopeBuildingResult* ScopeBuilder::BuildScopes() {
|
|||
scope_->set_begin_token_pos(function.token_pos());
|
||||
scope_->set_end_token_pos(function.end_token_pos());
|
||||
|
||||
if (function.IsCompactAsyncFunction()) {
|
||||
if (function.IsSuspendableFunction()) {
|
||||
LocalVariable* suspend_state_var =
|
||||
MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
||||
Symbols::SuspendStateVar(), AbstractType::dynamic_type());
|
||||
|
@ -1276,15 +1276,16 @@ void ScopeBuilder::VisitStatement() {
|
|||
word flags = helper_.ReadByte(); // read flags.
|
||||
VisitExpression(); // read expression.
|
||||
|
||||
ASSERT(flags == kNativeYieldFlags);
|
||||
if (depth_.function_ == 0) {
|
||||
AddSwitchVariable();
|
||||
// Promote all currently visible local variables into the context.
|
||||
// TODO(27590) CaptureLocalVariables promotes to many variables into
|
||||
// the scope. Mark those variables as stack_local.
|
||||
// TODO(27590) we don't need to promote those variables that are
|
||||
// not used across yields.
|
||||
scope_->CaptureLocalVariables(current_function_scope_);
|
||||
if ((flags & kYieldStatementFlagNative) != 0) {
|
||||
if (depth_.function_ == 0) {
|
||||
AddSwitchVariable();
|
||||
// Promote all currently visible local variables into the context.
|
||||
// TODO(27590) CaptureLocalVariables promotes to many variables into
|
||||
// the scope. Mark those variables as stack_local.
|
||||
// TODO(27590) we don't need to promote those variables that are
|
||||
// not used across yields.
|
||||
scope_->CaptureLocalVariables(current_function_scope_);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -83,8 +83,10 @@ namespace dart {
|
|||
V(::, copyRangeFromUint8ListToOneByteString, \
|
||||
CopyRangeFromUint8ListToOneByteString, 0x19a1bf41) \
|
||||
V(_StringBase, _interpolate, StringBaseInterpolate, 0x7da2a580) \
|
||||
V(_SuspendState, get:_future, SuspendState_getFuture, 0x0e2a7e73) \
|
||||
V(_SuspendState, set:_future, SuspendState_setFuture, 0x179923b0) \
|
||||
V(_SuspendState, get:_functionData, SuspendState_getFunctionData, \
|
||||
0x7290026e) \
|
||||
V(_SuspendState, set:_functionData, SuspendState_setFunctionData, \
|
||||
0x2b6668ab) \
|
||||
V(_SuspendState, get:_thenCallback, SuspendState_getThenCallback, \
|
||||
0xff1dccec) \
|
||||
V(_SuspendState, set:_thenCallback, SuspendState_setThenCallback, \
|
||||
|
@ -95,7 +97,9 @@ namespace dart {
|
|||
0x4935f88c) \
|
||||
V(_SuspendState, _createAsyncCallbacks, SuspendState_createAsyncCallbacks, \
|
||||
0x4add6c13) \
|
||||
V(_SuspendState, _resume, SuspendState_resume, 0x93d8c5e8) \
|
||||
V(_SuspendState, _createAsyncStarCallback, \
|
||||
SuspendState_createAsyncStarCallback, 0xfa7537e4) \
|
||||
V(_SuspendState, _resume, SuspendState_resume, 0xc738e9d2) \
|
||||
V(_IntegerImplementation, toDouble, IntegerToDouble, 0x97728b46) \
|
||||
V(_Double, _add, DoubleAdd, 0xea666327) \
|
||||
V(_Double, _sub, DoubleSub, 0x28474c2e) \
|
||||
|
|
|
@ -992,7 +992,7 @@ class SuspendState : public AllStatic {
|
|||
public:
|
||||
static word frame_size_offset();
|
||||
static word pc_offset();
|
||||
static word future_offset();
|
||||
static word function_data_offset();
|
||||
static word then_callback_offset();
|
||||
static word error_callback_offset();
|
||||
static word payload_offset();
|
||||
|
@ -1239,9 +1239,14 @@ class Thread : public AllStatic {
|
|||
static word random_offset();
|
||||
|
||||
static word suspend_state_init_async_entry_point_offset();
|
||||
static word suspend_state_await_async_entry_point_offset();
|
||||
static word suspend_state_await_entry_point_offset();
|
||||
static word suspend_state_return_async_entry_point_offset();
|
||||
static word suspend_state_return_async_not_future_entry_point_offset();
|
||||
|
||||
static word suspend_state_init_async_star_entry_point_offset();
|
||||
static word suspend_state_yield_async_star_entry_point_offset();
|
||||
static word suspend_state_return_async_star_entry_point_offset();
|
||||
|
||||
static word suspend_state_handle_exception_entry_point_offset();
|
||||
|
||||
static word OffsetFromThread(const dart::Object& object);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -192,7 +192,7 @@
|
|||
FIELD(SubtypeTestCache, cache_offset) \
|
||||
FIELD(SuspendState, error_callback_offset) \
|
||||
FIELD(SuspendState, frame_size_offset) \
|
||||
FIELD(SuspendState, future_offset) \
|
||||
FIELD(SuspendState, function_data_offset) \
|
||||
FIELD(SuspendState, payload_offset) \
|
||||
FIELD(SuspendState, pc_offset) \
|
||||
FIELD(SuspendState, then_callback_offset) \
|
||||
|
@ -281,10 +281,13 @@
|
|||
\
|
||||
FIELD(Thread, stack_overflow_shared_without_fpu_regs_stub_offset) \
|
||||
FIELD(Thread, store_buffer_block_offset) \
|
||||
FIELD(Thread, suspend_state_await_async_entry_point_offset) \
|
||||
FIELD(Thread, suspend_state_await_entry_point_offset) \
|
||||
FIELD(Thread, suspend_state_init_async_entry_point_offset) \
|
||||
FIELD(Thread, suspend_state_return_async_entry_point_offset) \
|
||||
FIELD(Thread, suspend_state_return_async_not_future_entry_point_offset) \
|
||||
FIELD(Thread, suspend_state_init_async_star_entry_point_offset) \
|
||||
FIELD(Thread, suspend_state_yield_async_star_entry_point_offset) \
|
||||
FIELD(Thread, suspend_state_return_async_star_entry_point_offset) \
|
||||
FIELD(Thread, suspend_state_handle_exception_entry_point_offset) \
|
||||
FIELD(Thread, top_exit_frame_info_offset) \
|
||||
FIELD(Thread, top_offset) \
|
||||
|
|
|
@ -1287,7 +1287,7 @@ void StubCodeCompiler::GenerateSuspendStub(
|
|||
const Register kTemp = SuspendStubABI::kTempReg;
|
||||
const Register kFrameSize = SuspendStubABI::kFrameSizeReg;
|
||||
const Register kSuspendState = SuspendStubABI::kSuspendStateReg;
|
||||
const Register kFuture = SuspendStubABI::kFutureReg;
|
||||
const Register kFunctionData = SuspendStubABI::kFunctionDataReg;
|
||||
const Register kSrcFrame = SuspendStubABI::kSrcFrameReg;
|
||||
const Register kDstFrame = SuspendStubABI::kDstFrameReg;
|
||||
Label alloc_slow_case, alloc_done, init_done, old_gen_object, call_await;
|
||||
|
@ -1308,7 +1308,7 @@ void StubCodeCompiler::GenerateSuspendStub(
|
|||
__ CompareClassId(kSuspendState, kSuspendStateCid, kTemp);
|
||||
__ BranchIf(EQUAL, &init_done);
|
||||
|
||||
__ MoveRegister(kFuture, kSuspendState);
|
||||
__ MoveRegister(kFunctionData, kSuspendState);
|
||||
__ Comment("Allocate SuspendState");
|
||||
|
||||
// Check for allocation tracing.
|
||||
|
@ -1361,8 +1361,8 @@ void StubCodeCompiler::GenerateSuspendStub(
|
|||
FieldAddress(kSuspendState, target::SuspendState::frame_size_offset()));
|
||||
__ StoreCompressedIntoObjectNoBarrier(
|
||||
kSuspendState,
|
||||
FieldAddress(kSuspendState, target::SuspendState::future_offset()),
|
||||
kFuture);
|
||||
FieldAddress(kSuspendState, target::SuspendState::function_data_offset()),
|
||||
kFunctionData);
|
||||
|
||||
{
|
||||
#if defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_RISCV32) || \
|
||||
|
@ -1474,8 +1474,8 @@ void StubCodeCompiler::GenerateSuspendStub(
|
|||
__ PushRegister(kFrameSize); // Save frame size.
|
||||
__ PushObject(NullObject()); // Make space on stack for the return value.
|
||||
__ SmiTag(kFrameSize);
|
||||
__ PushRegister(kFrameSize); // Pass frame size to runtime entry.
|
||||
__ PushRegister(kFuture); // Pass future.
|
||||
__ PushRegister(kFrameSize); // Pass frame size to runtime entry.
|
||||
__ PushRegister(kFunctionData); // Pass function data.
|
||||
__ CallRuntime(kAllocateSuspendStateRuntimeEntry, 2);
|
||||
__ Drop(2); // Drop arguments
|
||||
__ PopRegister(kSuspendState); // Get result.
|
||||
|
@ -1502,10 +1502,15 @@ void StubCodeCompiler::GenerateSuspendStub(
|
|||
__ Jump(&call_await);
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateAwaitAsyncStub(Assembler* assembler) {
|
||||
void StubCodeCompiler::GenerateAwaitStub(Assembler* assembler) {
|
||||
GenerateSuspendStub(assembler,
|
||||
target::Thread::suspend_state_await_entry_point_offset());
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateYieldAsyncStarStub(Assembler* assembler) {
|
||||
GenerateSuspendStub(
|
||||
assembler,
|
||||
target::Thread::suspend_state_await_async_entry_point_offset());
|
||||
target::Thread::suspend_state_yield_async_star_entry_point_offset());
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateInitSuspendableFunctionStub(
|
||||
|
@ -1531,6 +1536,12 @@ void StubCodeCompiler::GenerateInitAsyncStub(Assembler* assembler) {
|
|||
assembler, target::Thread::suspend_state_init_async_entry_point_offset());
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateInitAsyncStarStub(Assembler* assembler) {
|
||||
GenerateInitSuspendableFunctionStub(
|
||||
assembler,
|
||||
target::Thread::suspend_state_init_async_star_entry_point_offset());
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateResumeStub(Assembler* assembler) {
|
||||
const Register kSuspendState = ResumeStubABI::kSuspendStateReg;
|
||||
const Register kTemp = ResumeStubABI::kTempReg;
|
||||
|
@ -1674,6 +1685,12 @@ void StubCodeCompiler::GenerateReturnAsyncNotFutureStub(Assembler* assembler) {
|
|||
suspend_state_return_async_not_future_entry_point_offset());
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateReturnAsyncStarStub(Assembler* assembler) {
|
||||
GenerateReturnStub(
|
||||
assembler,
|
||||
target::Thread::suspend_state_return_async_star_entry_point_offset());
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateAsyncExceptionHandlerStub(Assembler* assembler) {
|
||||
const Register kSuspendState = AsyncExceptionHandlerStubABI::kSuspendStateReg;
|
||||
ASSERT(kSuspendState != kExceptionObjectReg);
|
||||
|
|
|
@ -532,18 +532,18 @@ struct DoubleToIntegerStubABI {
|
|||
static const Register kResultReg = R0;
|
||||
};
|
||||
|
||||
// ABI for SuspendStub (AwaitAsyncStub).
|
||||
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub).
|
||||
struct SuspendStubABI {
|
||||
static const Register kArgumentReg = R0;
|
||||
static const Register kTempReg = R1;
|
||||
static const Register kFrameSizeReg = R2;
|
||||
static const Register kSuspendStateReg = R3;
|
||||
static const Register kFutureReg = R4;
|
||||
static const Register kFunctionDataReg = R4;
|
||||
static const Register kSrcFrameReg = R8;
|
||||
static const Register kDstFrameReg = R9;
|
||||
};
|
||||
|
||||
// ABI for InitSuspendableFunctionStub (InitAsyncStub).
|
||||
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub).
|
||||
struct InitSuspendableFunctionStubABI {
|
||||
static const Register kTypeArgsReg = R0;
|
||||
};
|
||||
|
@ -563,7 +563,8 @@ struct ResumeStubABI {
|
|||
static const Register kStackTraceReg = R4;
|
||||
};
|
||||
|
||||
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub).
|
||||
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
|
||||
// ReturnAsyncStarStub).
|
||||
struct ReturnStubABI {
|
||||
static const Register kSuspendStateReg = R2;
|
||||
};
|
||||
|
|
|
@ -366,18 +366,18 @@ struct DoubleToIntegerStubABI {
|
|||
static const Register kResultReg = R0;
|
||||
};
|
||||
|
||||
// ABI for SuspendStub (AwaitAsyncStub).
|
||||
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub).
|
||||
struct SuspendStubABI {
|
||||
static const Register kArgumentReg = R0;
|
||||
static const Register kTempReg = R1;
|
||||
static const Register kFrameSizeReg = R2;
|
||||
static const Register kSuspendStateReg = R3;
|
||||
static const Register kFutureReg = R4;
|
||||
static const Register kFunctionDataReg = R4;
|
||||
static const Register kSrcFrameReg = R5;
|
||||
static const Register kDstFrameReg = R6;
|
||||
};
|
||||
|
||||
// ABI for InitSuspendableFunctionStub (InitAsyncStub).
|
||||
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub).
|
||||
struct InitSuspendableFunctionStubABI {
|
||||
static const Register kTypeArgsReg = R0;
|
||||
};
|
||||
|
@ -397,7 +397,8 @@ struct ResumeStubABI {
|
|||
static const Register kStackTraceReg = R4;
|
||||
};
|
||||
|
||||
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub).
|
||||
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
|
||||
// ReturnAsyncStarStub).
|
||||
struct ReturnStubABI {
|
||||
static const Register kSuspendStateReg = R2;
|
||||
};
|
||||
|
|
|
@ -260,16 +260,16 @@ struct DoubleToIntegerStubABI {
|
|||
static const Register kResultReg = EAX;
|
||||
};
|
||||
|
||||
// ABI for SuspendStub (AwaitAsyncStub).
|
||||
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub).
|
||||
struct SuspendStubABI {
|
||||
static const Register kArgumentReg = EAX;
|
||||
static const Register kTempReg = EDX;
|
||||
static const Register kFrameSizeReg = ECX;
|
||||
static const Register kSuspendStateReg = EBX;
|
||||
static const Register kFutureReg = EDI;
|
||||
static const Register kFunctionDataReg = EDI;
|
||||
// Can reuse THR.
|
||||
static const Register kSrcFrameReg = ESI;
|
||||
// Can reuse kFutureReg.
|
||||
// Can reuse kFunctionDataReg.
|
||||
static const Register kDstFrameReg = EDI;
|
||||
|
||||
// Number of bytes to skip after
|
||||
|
@ -278,7 +278,7 @@ struct SuspendStubABI {
|
|||
static const intptr_t kResumePcDistance = 5;
|
||||
};
|
||||
|
||||
// ABI for InitSuspendableFunctionStub (InitAsyncStub).
|
||||
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub).
|
||||
struct InitSuspendableFunctionStubABI {
|
||||
static const Register kTypeArgsReg = EAX;
|
||||
};
|
||||
|
@ -298,7 +298,8 @@ struct ResumeStubABI {
|
|||
static const Register kStackTraceReg = EDI;
|
||||
};
|
||||
|
||||
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub).
|
||||
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
|
||||
// ReturnAsyncStarStub).
|
||||
struct ReturnStubABI {
|
||||
static const Register kSuspendStateReg = EBX;
|
||||
};
|
||||
|
|
|
@ -378,18 +378,18 @@ struct DoubleToIntegerStubABI {
|
|||
static constexpr Register kResultReg = A0;
|
||||
};
|
||||
|
||||
// ABI for SuspendStub (AwaitAsyncStub).
|
||||
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub).
|
||||
struct SuspendStubABI {
|
||||
static const Register kArgumentReg = A0;
|
||||
static const Register kTempReg = T0;
|
||||
static const Register kFrameSizeReg = T1;
|
||||
static const Register kSuspendStateReg = T2;
|
||||
static const Register kFutureReg = T3;
|
||||
static const Register kFunctionDataReg = T3;
|
||||
static const Register kSrcFrameReg = T4;
|
||||
static const Register kDstFrameReg = T5;
|
||||
};
|
||||
|
||||
// ABI for InitSuspendableFunctionStub (InitAsyncStub).
|
||||
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub).
|
||||
struct InitSuspendableFunctionStubABI {
|
||||
static const Register kTypeArgsReg = A0;
|
||||
};
|
||||
|
@ -409,7 +409,8 @@ struct ResumeStubABI {
|
|||
static const Register kStackTraceReg = T4;
|
||||
};
|
||||
|
||||
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub).
|
||||
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
|
||||
// ReturnAsyncStarStub).
|
||||
struct ReturnStubABI {
|
||||
static const Register kSuspendStateReg = T1;
|
||||
};
|
||||
|
|
|
@ -335,13 +335,13 @@ struct DoubleToIntegerStubABI {
|
|||
static const Register kResultReg = RAX;
|
||||
};
|
||||
|
||||
// ABI for SuspendStub (AwaitAsyncStub).
|
||||
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub).
|
||||
struct SuspendStubABI {
|
||||
static const Register kArgumentReg = RAX;
|
||||
static const Register kTempReg = RDX;
|
||||
static const Register kFrameSizeReg = RCX;
|
||||
static const Register kSuspendStateReg = RBX;
|
||||
static const Register kFutureReg = R8;
|
||||
static const Register kFunctionDataReg = R8;
|
||||
static const Register kSrcFrameReg = RSI;
|
||||
static const Register kDstFrameReg = RDI;
|
||||
|
||||
|
@ -351,7 +351,7 @@ struct SuspendStubABI {
|
|||
static const intptr_t kResumePcDistance = 5;
|
||||
};
|
||||
|
||||
// ABI for InitSuspendableFunctionStub (InitAsyncStub).
|
||||
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub).
|
||||
struct InitSuspendableFunctionStubABI {
|
||||
static const Register kTypeArgsReg = RAX;
|
||||
};
|
||||
|
@ -371,7 +371,8 @@ struct ResumeStubABI {
|
|||
static const Register kStackTraceReg = RDI;
|
||||
};
|
||||
|
||||
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub).
|
||||
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
|
||||
// ReturnAsyncStarStub).
|
||||
struct ReturnStubABI {
|
||||
static const Register kSuspendStateReg = RBX;
|
||||
};
|
||||
|
|
|
@ -56,8 +56,6 @@ class StringIndex {
|
|||
int value_;
|
||||
};
|
||||
|
||||
const uint8_t kNativeYieldFlags = 0x2;
|
||||
|
||||
enum LogicalOperator { kAnd, kOr };
|
||||
|
||||
struct ProgramBinary {
|
||||
|
|
|
@ -212,6 +212,12 @@ enum InstanceInvocationFlags {
|
|||
kInstanceInvocationFlagBoundsSafe = 1 << 1,
|
||||
};
|
||||
|
||||
// Keep in sync with package:kernel/lib/ast.dart
|
||||
enum YieldStatementFlags {
|
||||
kYieldStatementFlagYieldStar = 1 << 0,
|
||||
kYieldStatementFlagNative = 1 << 1,
|
||||
};
|
||||
|
||||
// Keep in sync with package:kernel/lib/ast.dart
|
||||
enum class NamedTypeFlags : uint8_t {
|
||||
kIsRequired = 1 << 0,
|
||||
|
|
|
@ -2039,6 +2039,16 @@ void KernelLoader::LoadProcedure(const Library& library,
|
|||
function.set_is_inlinable(false);
|
||||
function.set_is_visible(true);
|
||||
ASSERT(function.IsCompactAsyncFunction());
|
||||
} else if (function_node_helper.async_marker_ ==
|
||||
FunctionNodeHelper::kAsyncStar) {
|
||||
if (!FLAG_precompiled_mode) {
|
||||
FATAL("Compact async* functions are only supported in AOT mode.");
|
||||
}
|
||||
function.set_modifier(UntaggedFunction::kAsyncGen);
|
||||
function.set_is_debuggable(true);
|
||||
function.set_is_inlinable(false);
|
||||
function.set_is_visible(true);
|
||||
ASSERT(function.IsCompactAsyncStarFunction());
|
||||
} else {
|
||||
ASSERT(function_node_helper.async_marker_ == FunctionNodeHelper::kSync);
|
||||
function.set_is_debuggable(function_node_helper.dart_async_marker_ ==
|
||||
|
@ -2063,6 +2073,7 @@ void KernelLoader::LoadProcedure(const Library& library,
|
|||
break;
|
||||
}
|
||||
ASSERT(!function.IsCompactAsyncFunction());
|
||||
ASSERT(!function.IsCompactAsyncStarFunction());
|
||||
}
|
||||
|
||||
if (!native_name.IsNull()) {
|
||||
|
|
|
@ -26036,7 +26036,7 @@ DEFINE_FLAG_HANDLER(DwarfStackTracesHandler,
|
|||
"symbolize stack traces in the precompiled runtime.");
|
||||
|
||||
SuspendStatePtr SuspendState::New(intptr_t frame_size,
|
||||
const Instance& future,
|
||||
const Instance& function_data,
|
||||
Heap::Space space) {
|
||||
SuspendState& result = SuspendState::Handle();
|
||||
{
|
||||
|
@ -26047,7 +26047,7 @@ SuspendStatePtr SuspendState::New(intptr_t frame_size,
|
|||
result ^= raw;
|
||||
result.set_frame_size(frame_size);
|
||||
result.set_pc(0);
|
||||
result.set_future(future);
|
||||
result.set_function_data(function_data);
|
||||
}
|
||||
return result.ptr();
|
||||
}
|
||||
|
@ -26061,8 +26061,8 @@ void SuspendState::set_pc(uword pc) const {
|
|||
StoreNonPointer(&untag()->pc_, pc);
|
||||
}
|
||||
|
||||
void SuspendState::set_future(const Instance& future) const {
|
||||
untag()->set_future(future.ptr());
|
||||
void SuspendState::set_function_data(const Instance& function_data) const {
|
||||
untag()->set_function_data(function_data.ptr());
|
||||
}
|
||||
|
||||
const char* SuspendState::ToCString() const {
|
||||
|
|
|
@ -3171,7 +3171,7 @@ class Function : public Object {
|
|||
// Returns true if parameters of this function are copied into the frame
|
||||
// in the function prologue.
|
||||
bool MakesCopyOfParameters() const {
|
||||
return HasOptionalParameters() || IsCompactAsyncFunction();
|
||||
return HasOptionalParameters() || IsSuspendableFunction();
|
||||
}
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
@ -3570,12 +3570,25 @@ class Function : public Object {
|
|||
return modifier() == UntaggedFunction::kAsync;
|
||||
}
|
||||
|
||||
// TODO(alexmarkov): replace this predicate with IsAsyncFunction() after
|
||||
// old async functions are removed.
|
||||
// TODO(dartbug.com/48378): replace this predicate with IsAsyncFunction()
|
||||
// after old async functions are removed.
|
||||
bool IsCompactAsyncFunction() const {
|
||||
return IsAsyncFunction() && is_debuggable();
|
||||
}
|
||||
|
||||
// TODO(dartbug.com/48378): replace this predicate with IsAsyncGenerator()
|
||||
// after old async* functions are removed.
|
||||
bool IsCompactAsyncStarFunction() const {
|
||||
return IsAsyncGenerator() && is_debuggable();
|
||||
}
|
||||
|
||||
// Returns true for functions which execution can be suspended
|
||||
// using Suspend/Resume stubs. Such functions have an artificial
|
||||
// :suspend_state local variable at the fixed location of the frame.
|
||||
bool IsSuspendableFunction() const {
|
||||
return IsCompactAsyncFunction() || IsCompactAsyncStarFunction();
|
||||
}
|
||||
|
||||
// Recognise synthetic sync-yielding functions like the inner-most:
|
||||
// user_func /* was async */ {
|
||||
// :async_op(..) yielding {
|
||||
|
@ -11804,8 +11817,8 @@ class SuspendState : public Instance {
|
|||
return OFFSET_OF(UntaggedSuspendState, frame_size_);
|
||||
}
|
||||
static intptr_t pc_offset() { return OFFSET_OF(UntaggedSuspendState, pc_); }
|
||||
static intptr_t future_offset() {
|
||||
return OFFSET_OF(UntaggedSuspendState, future_);
|
||||
static intptr_t function_data_offset() {
|
||||
return OFFSET_OF(UntaggedSuspendState, function_data_);
|
||||
}
|
||||
static intptr_t then_callback_offset() {
|
||||
return OFFSET_OF(UntaggedSuspendState, then_callback_);
|
||||
|
@ -11818,10 +11831,10 @@ class SuspendState : public Instance {
|
|||
}
|
||||
|
||||
static SuspendStatePtr New(intptr_t frame_size,
|
||||
const Instance& future,
|
||||
const Instance& function_data,
|
||||
Heap::Space space = Heap::kNew);
|
||||
|
||||
InstancePtr future() const { return untag()->future(); }
|
||||
InstancePtr function_data() const { return untag()->function_data(); }
|
||||
uword pc() const { return untag()->pc_; }
|
||||
|
||||
// Returns Code object corresponding to the suspended function.
|
||||
|
@ -11830,7 +11843,7 @@ class SuspendState : public Instance {
|
|||
private:
|
||||
void set_frame_size(intptr_t frame_size) const;
|
||||
void set_pc(uword pc) const;
|
||||
void set_future(const Instance& future) const;
|
||||
void set_function_data(const Instance& function_data) const;
|
||||
|
||||
FINAL_HEAP_OBJECT_IMPLEMENTATION(SuspendState, Instance);
|
||||
friend class Class;
|
||||
|
|
|
@ -286,8 +286,17 @@ void ObjectStore::InitKnownObjects() {
|
|||
cls =
|
||||
async_lib.LookupClassAllowPrivate(Symbols::_AsyncStarStreamController());
|
||||
ASSERT(!cls.IsNull());
|
||||
RELEASE_ASSERT(cls.EnsureIsFinalized(thread) == Error::null());
|
||||
set_async_star_stream_controller(cls);
|
||||
|
||||
function = cls.LookupFunctionAllowPrivate(Symbols::add());
|
||||
ASSERT(!function.IsNull());
|
||||
set_async_star_stream_controller_add(function);
|
||||
|
||||
function = cls.LookupFunctionAllowPrivate(Symbols::addStream());
|
||||
ASSERT(!function.IsNull());
|
||||
set_async_star_stream_controller_add_stream(function);
|
||||
|
||||
if (FLAG_async_debugger) {
|
||||
// Disable debugging and inlining of all functions on the
|
||||
// _AsyncStarStreamController class.
|
||||
|
@ -301,6 +310,10 @@ void ObjectStore::InitKnownObjects() {
|
|||
}
|
||||
}
|
||||
|
||||
cls = async_lib.LookupClassAllowPrivate(Symbols::Stream());
|
||||
ASSERT(!cls.IsNull());
|
||||
set_stream_class(cls);
|
||||
|
||||
cls = async_lib.LookupClassAllowPrivate(Symbols::_SuspendState());
|
||||
ASSERT(!cls.IsNull());
|
||||
const auto& error = cls.EnsureIsFinalized(thread);
|
||||
|
@ -310,9 +323,9 @@ void ObjectStore::InitKnownObjects() {
|
|||
ASSERT(!function.IsNull());
|
||||
set_suspend_state_init_async(function);
|
||||
|
||||
function = cls.LookupFunctionAllowPrivate(Symbols::_awaitAsync());
|
||||
function = cls.LookupFunctionAllowPrivate(Symbols::_await());
|
||||
ASSERT(!function.IsNull());
|
||||
set_suspend_state_await_async(function);
|
||||
set_suspend_state_await(function);
|
||||
|
||||
function = cls.LookupFunctionAllowPrivate(Symbols::_returnAsync());
|
||||
ASSERT(!function.IsNull());
|
||||
|
@ -322,6 +335,18 @@ void ObjectStore::InitKnownObjects() {
|
|||
ASSERT(!function.IsNull());
|
||||
set_suspend_state_return_async_not_future(function);
|
||||
|
||||
function = cls.LookupFunctionAllowPrivate(Symbols::_initAsyncStar());
|
||||
ASSERT(!function.IsNull());
|
||||
set_suspend_state_init_async_star(function);
|
||||
|
||||
function = cls.LookupFunctionAllowPrivate(Symbols::_yieldAsyncStar());
|
||||
ASSERT(!function.IsNull());
|
||||
set_suspend_state_yield_async_star(function);
|
||||
|
||||
function = cls.LookupFunctionAllowPrivate(Symbols::_returnAsyncStar());
|
||||
ASSERT(!function.IsNull());
|
||||
set_suspend_state_return_async_star(function);
|
||||
|
||||
function = cls.LookupFunctionAllowPrivate(Symbols::_handleException());
|
||||
ASSERT(!function.IsNull());
|
||||
set_suspend_state_handle_exception(function);
|
||||
|
|
|
@ -165,15 +165,21 @@ class ObjectPointerVisitor;
|
|||
RW(Function, simple_instance_of_true_function) \
|
||||
RW(Function, simple_instance_of_false_function) \
|
||||
RW(Function, async_star_move_next_helper) \
|
||||
RW(Function, async_star_stream_controller_add) \
|
||||
RW(Function, async_star_stream_controller_add_stream) \
|
||||
RW(Function, complete_on_async_return) \
|
||||
RW(Function, complete_with_no_future_on_async_return) \
|
||||
RW(Function, complete_on_async_error) \
|
||||
RW(Function, suspend_state_init_async) \
|
||||
RW(Function, suspend_state_await_async) \
|
||||
RW(Function, suspend_state_await) \
|
||||
RW(Function, suspend_state_return_async) \
|
||||
RW(Function, suspend_state_return_async_not_future) \
|
||||
RW(Function, suspend_state_init_async_star) \
|
||||
RW(Function, suspend_state_yield_async_star) \
|
||||
RW(Function, suspend_state_return_async_star) \
|
||||
RW(Function, suspend_state_handle_exception) \
|
||||
RW(Class, async_star_stream_controller) \
|
||||
RW(Class, stream_class) \
|
||||
ARW_RELAXED(Smi, future_timeout_future_index) \
|
||||
ARW_RELAXED(Smi, future_wait_future_index) \
|
||||
RW(CompressedStackMaps, canonicalized_stack_map_entries) \
|
||||
|
@ -244,11 +250,14 @@ class ObjectPointerVisitor;
|
|||
RW(Code, type_parameter_tts_stub) \
|
||||
RW(Code, unreachable_tts_stub) \
|
||||
RW(Code, slow_tts_stub) \
|
||||
RW(Code, await_async_stub) \
|
||||
RW(Code, await_stub) \
|
||||
RW(Code, init_async_stub) \
|
||||
RW(Code, resume_stub) \
|
||||
RW(Code, return_async_stub) \
|
||||
RW(Code, return_async_not_future_stub) \
|
||||
RW(Code, init_async_star_stub) \
|
||||
RW(Code, yield_async_star_stub) \
|
||||
RW(Code, return_async_star_stub) \
|
||||
RW(Array, dispatch_table_code_entries) \
|
||||
RW(GrowableObjectArray, instructions_tables) \
|
||||
RW(Array, obfuscation_map) \
|
||||
|
@ -324,11 +333,14 @@ class ObjectPointerVisitor;
|
|||
DO(init_instance_field_stub, InitInstanceField) \
|
||||
DO(init_late_instance_field_stub, InitLateInstanceField) \
|
||||
DO(init_late_final_instance_field_stub, InitLateFinalInstanceField) \
|
||||
DO(await_async_stub, AwaitAsync) \
|
||||
DO(await_stub, Await) \
|
||||
DO(init_async_stub, InitAsync) \
|
||||
DO(resume_stub, Resume) \
|
||||
DO(return_async_stub, ReturnAsync) \
|
||||
DO(return_async_not_future_stub, ReturnAsyncNotFuture) \
|
||||
DO(init_async_star_stub, InitAsyncStar) \
|
||||
DO(yield_async_star_stub, YieldAsyncStar) \
|
||||
DO(return_async_star_stub, ReturnAsyncStar) \
|
||||
DO(instance_of_stub, InstanceOf)
|
||||
|
||||
#define ISOLATE_OBJECT_STORE_FIELD_LIST(R_, RW) \
|
||||
|
|
|
@ -3292,10 +3292,15 @@ class UntaggedSuspendState : public UntaggedInstance {
|
|||
intptr_t frame_size_;
|
||||
uword pc_;
|
||||
|
||||
COMPRESSED_POINTER_FIELD(InstancePtr, future)
|
||||
// Holds function-specific object which is returned from
|
||||
// SuspendState.init* method.
|
||||
// For async functions: _Future instance.
|
||||
// For async* functions: _AsyncStarStreamController instance.
|
||||
COMPRESSED_POINTER_FIELD(InstancePtr, function_data)
|
||||
|
||||
COMPRESSED_POINTER_FIELD(ClosurePtr, then_callback)
|
||||
COMPRESSED_POINTER_FIELD(ClosurePtr, error_callback)
|
||||
VISIT_FROM(future)
|
||||
VISIT_FROM(function_data)
|
||||
VISIT_TO(error_callback)
|
||||
|
||||
public:
|
||||
|
|
|
@ -191,7 +191,7 @@ namespace dart {
|
|||
F(RegExp, two_byte_sticky_) \
|
||||
F(RegExp, external_one_byte_sticky_) \
|
||||
F(RegExp, external_two_byte_sticky_) \
|
||||
F(SuspendState, future_) \
|
||||
F(SuspendState, function_data_) \
|
||||
F(SuspendState, then_callback_) \
|
||||
F(SuspendState, error_callback_) \
|
||||
F(WeakProperty, key_) \
|
||||
|
|
|
@ -711,13 +711,14 @@ DEFINE_RUNTIME_ENTRY(CloneContext, 1) {
|
|||
|
||||
// Allocate a SuspendState object.
|
||||
// Arg0: frame size.
|
||||
// Arg1: future.
|
||||
// Arg1: function data.
|
||||
// Return value: newly allocated object.
|
||||
DEFINE_RUNTIME_ENTRY(AllocateSuspendState, 2) {
|
||||
const Smi& frame_size = Smi::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
const Instance& future = Instance::CheckedHandle(zone, arguments.ArgAt(1));
|
||||
const Instance& function_data =
|
||||
Instance::CheckedHandle(zone, arguments.ArgAt(1));
|
||||
const SuspendState& result = SuspendState::Handle(
|
||||
zone, SuspendState::New(frame_size.Value(), future,
|
||||
zone, SuspendState::New(frame_size.Value(), function_data,
|
||||
SpaceForRuntimeAllocation()));
|
||||
arguments.SetReturn(result);
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ CallerClosureFinder::CallerClosureFinder(Zone* zone)
|
|||
callback_instance_(Object::Handle(zone)),
|
||||
future_impl_class(Class::Handle(zone)),
|
||||
future_listener_class(Class::Handle(zone)),
|
||||
async_start_stream_controller_class(Class::Handle(zone)),
|
||||
async_star_stream_controller_class(Class::Handle(zone)),
|
||||
stream_controller_class(Class::Handle(zone)),
|
||||
sync_stream_controller_class(Class::Handle(zone)),
|
||||
controller_subscription_class(Class::Handle(zone)),
|
||||
|
@ -95,9 +95,9 @@ CallerClosureFinder::CallerClosureFinder(Zone* zone)
|
|||
async_lib.LookupClassAllowPrivate(Symbols::_FutureListener());
|
||||
ASSERT(!future_listener_class.IsNull());
|
||||
// - async*:
|
||||
async_start_stream_controller_class =
|
||||
async_star_stream_controller_class =
|
||||
async_lib.LookupClassAllowPrivate(Symbols::_AsyncStarStreamController());
|
||||
ASSERT(!async_start_stream_controller_class.IsNull());
|
||||
ASSERT(!async_star_stream_controller_class.IsNull());
|
||||
stream_controller_class =
|
||||
async_lib.LookupClassAllowPrivate(Symbols::_StreamController());
|
||||
ASSERT(!stream_controller_class.IsNull());
|
||||
|
@ -130,7 +130,7 @@ CallerClosureFinder::CallerClosureFinder(Zone* zone)
|
|||
ASSERT(!future_listener_result_field.IsNull());
|
||||
// - async*:
|
||||
controller_controller_field =
|
||||
async_start_stream_controller_class.LookupFieldAllowPrivate(
|
||||
async_star_stream_controller_class.LookupFieldAllowPrivate(
|
||||
Symbols::controller());
|
||||
ASSERT(!controller_controller_field.IsNull());
|
||||
state_field =
|
||||
|
@ -163,14 +163,19 @@ ClosurePtr CallerClosureFinder::GetCallerInFutureImpl(const Object& future) {
|
|||
|
||||
ClosurePtr CallerClosureFinder::FindCallerInAsyncGenClosure(
|
||||
const Context& receiver_context) {
|
||||
// Get the async* _StreamController.
|
||||
// Get the async* _AsyncStarStreamController.
|
||||
context_entry_ = receiver_context.At(Context::kControllerIndex);
|
||||
ASSERT(context_entry_.IsInstance());
|
||||
ASSERT(context_entry_.GetClassId() ==
|
||||
async_start_stream_controller_class.id());
|
||||
return FindCallerInAsyncStarStreamController(context_entry_);
|
||||
}
|
||||
|
||||
const Instance& controller = Instance::Cast(context_entry_);
|
||||
controller_ = controller.GetField(controller_controller_field);
|
||||
ClosurePtr CallerClosureFinder::FindCallerInAsyncStarStreamController(
|
||||
const Object& async_star_stream_controller) {
|
||||
ASSERT(async_star_stream_controller.IsInstance());
|
||||
ASSERT(async_star_stream_controller.GetClassId() ==
|
||||
async_star_stream_controller_class.id());
|
||||
|
||||
controller_ = Instance::Cast(async_star_stream_controller)
|
||||
.GetField(controller_controller_field);
|
||||
ASSERT(!controller_.IsNull());
|
||||
ASSERT(controller_.GetClassId() == sync_stream_controller_class.id());
|
||||
|
||||
|
@ -269,8 +274,15 @@ ClosurePtr CallerClosureFinder::FindCaller(const Closure& receiver_closure) {
|
|||
|
||||
ClosurePtr CallerClosureFinder::FindCallerFromSuspendState(
|
||||
const SuspendState& suspend_state) {
|
||||
future_ = suspend_state.future();
|
||||
return GetCallerInFutureImpl(future_);
|
||||
context_entry_ = suspend_state.function_data();
|
||||
if (context_entry_.GetClassId() == future_impl_class.id()) {
|
||||
return GetCallerInFutureImpl(context_entry_);
|
||||
} else if (context_entry_.GetClassId() ==
|
||||
async_star_stream_controller_class.id()) {
|
||||
return FindCallerInAsyncStarStreamController(context_entry_);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
ClosurePtr CallerClosureFinder::UnwrapAsyncThen(const Closure& closure) {
|
||||
|
@ -289,14 +301,15 @@ ClosurePtr CallerClosureFinder::UnwrapAsyncThen(const Closure& closure) {
|
|||
|
||||
bool CallerClosureFinder::IsCompactAsyncCallback(const Function& function) {
|
||||
parent_function_ = function.parent_function();
|
||||
return parent_function_.recognized_kind() ==
|
||||
MethodRecognizer::kSuspendState_createAsyncCallbacks;
|
||||
auto kind = parent_function_.recognized_kind();
|
||||
return (kind == MethodRecognizer::kSuspendState_createAsyncCallbacks) ||
|
||||
(kind == MethodRecognizer::kSuspendState_createAsyncStarCallback);
|
||||
}
|
||||
|
||||
SuspendStatePtr CallerClosureFinder::GetSuspendStateFromAsyncCallback(
|
||||
const Closure& closure) {
|
||||
ASSERT(IsCompactAsyncCallback(Function::Handle(closure.function())));
|
||||
// Async handler only captures the receiver (SuspendState).
|
||||
// Async/async* handler only captures the receiver (SuspendState).
|
||||
receiver_context_ = closure.context();
|
||||
RELEASE_ASSERT(receiver_context_.num_variables() == 1);
|
||||
return SuspendState::RawCast(receiver_context_.At(0));
|
||||
|
@ -469,7 +482,8 @@ ClosurePtr StackTraceUtils::ClosureFromFrameFunction(
|
|||
return Closure::null();
|
||||
}
|
||||
|
||||
if (function.IsCompactAsyncFunction()) {
|
||||
if (function.IsCompactAsyncFunction() ||
|
||||
function.IsCompactAsyncStarFunction()) {
|
||||
auto& suspend_state = Object::Handle(
|
||||
zone, *reinterpret_cast<ObjectPtr*>(LocalVarAddress(
|
||||
frame->fp(), runtime_frame_layout.FrameSlotForVariableIndex(
|
||||
|
|
|
@ -31,6 +31,12 @@ class CallerClosureFinder {
|
|||
// Returns either the `onData` or the Future awaiter.
|
||||
ClosurePtr FindCallerInAsyncGenClosure(const Context& receiver_context);
|
||||
|
||||
// Find caller closure from an _AsyncStarStreamController instance
|
||||
// corresponding to async* function.
|
||||
// Returns either the `onData` or the Future awaiter.
|
||||
ClosurePtr FindCallerInAsyncStarStreamController(
|
||||
const Object& async_star_stream_controller);
|
||||
|
||||
// Find caller closure from a function receiver closure.
|
||||
// For async* functions, async functions, `Future.timeout` and `Future.wait`,
|
||||
// we can do this by finding and following their awaited Futures.
|
||||
|
@ -40,11 +46,11 @@ class CallerClosureFinder {
|
|||
ClosurePtr FindCallerFromSuspendState(const SuspendState& suspend_state);
|
||||
|
||||
// Returns true if given closure function is a Future callback
|
||||
// corresponding to an async function.
|
||||
// corresponding to an async/async* function or async* body callback.
|
||||
bool IsCompactAsyncCallback(const Function& function);
|
||||
|
||||
// Returns SuspendState from the given Future callback which corresponds
|
||||
// to an async function.
|
||||
// Returns SuspendState from the given callback which corresponds
|
||||
// to an async/async* function.
|
||||
SuspendStatePtr GetSuspendStateFromAsyncCallback(const Closure& closure);
|
||||
|
||||
// Finds the awaited Future from an async function receiver closure.
|
||||
|
@ -88,7 +94,7 @@ class CallerClosureFinder {
|
|||
|
||||
Class& future_impl_class;
|
||||
Class& future_listener_class;
|
||||
Class& async_start_stream_controller_class;
|
||||
Class& async_star_stream_controller_class;
|
||||
Class& stream_controller_class;
|
||||
Class& sync_stream_controller_class;
|
||||
Class& controller_subscription_class;
|
||||
|
|
|
@ -149,11 +149,14 @@ namespace dart {
|
|||
V(InstantiateTypeArgumentsMayShareInstantiatorTA) \
|
||||
V(InstantiateTypeArgumentsMayShareFunctionTA) \
|
||||
V(NoSuchMethodDispatcher) \
|
||||
V(AwaitAsync) \
|
||||
V(Await) \
|
||||
V(InitAsync) \
|
||||
V(Resume) \
|
||||
V(ReturnAsync) \
|
||||
V(ReturnAsyncNotFuture) \
|
||||
V(InitAsyncStar) \
|
||||
V(YieldAsyncStar) \
|
||||
V(ReturnAsyncStar) \
|
||||
V(AsyncExceptionHandler) \
|
||||
V(UnknownDartCode)
|
||||
|
||||
|
|
|
@ -241,6 +241,7 @@ class ObjectPointerVisitor;
|
|||
V(SpaceWhereNewLine, " where\n") \
|
||||
V(StackOverflowError, "StackOverflowError") \
|
||||
V(StackTraceParameter, ":stack_trace") \
|
||||
V(Stream, "Stream") \
|
||||
V(StringBase, "_StringBase") \
|
||||
V(Struct, "Struct") \
|
||||
V(SubtypeTestCache, "SubtypeTestCache") \
|
||||
|
@ -410,7 +411,7 @@ class ObjectPointerVisitor;
|
|||
V(_WeakProperty, "_WeakProperty") \
|
||||
V(_WeakReferenceImpl, "_WeakReferenceImpl") \
|
||||
V(_typedDataBase, "_typedDataBase") \
|
||||
V(_awaitAsync, "_awaitAsync") \
|
||||
V(_await, "_await") \
|
||||
V(_classRangeCheck, "_classRangeCheck") \
|
||||
V(_ensureScheduleImmediate, "_ensureScheduleImmediate") \
|
||||
V(_future, "_future") \
|
||||
|
@ -420,6 +421,7 @@ class ObjectPointerVisitor;
|
|||
V(_handleNativeFinalizerMessage, "_handleNativeFinalizerMessage") \
|
||||
V(_hasValue, "_hasValue") \
|
||||
V(_initAsync, "_initAsync") \
|
||||
V(_initAsyncStar, "_initAsyncStar") \
|
||||
V(_instanceOf, "_instanceOf") \
|
||||
V(_listGetAt, "_listGetAt") \
|
||||
V(_listLength, "_listLength") \
|
||||
|
@ -439,6 +441,7 @@ class ObjectPointerVisitor;
|
|||
V(_resultOrListeners, "_resultOrListeners") \
|
||||
V(_returnAsync, "_returnAsync") \
|
||||
V(_returnAsyncNotFuture, "_returnAsyncNotFuture") \
|
||||
V(_returnAsyncStar, "_returnAsyncStar") \
|
||||
V(_runExtension, "_runExtension") \
|
||||
V(_runPendingImmediateCallback, "_runPendingImmediateCallback") \
|
||||
V(_scanFlags, "_scanFlags") \
|
||||
|
@ -451,6 +454,9 @@ class ObjectPointerVisitor;
|
|||
V(_toString, "_toString") \
|
||||
V(_varData, "_varData") \
|
||||
V(_wordCharacterMap, "_wordCharacterMap") \
|
||||
V(_yieldAsyncStar, "_yieldAsyncStar") \
|
||||
V(add, "add") \
|
||||
V(addStream, "addStream") \
|
||||
V(callback, "callback") \
|
||||
V(capture_length, ":capture_length") \
|
||||
V(capture_start_index, ":capture_start_index") \
|
||||
|
|
|
@ -168,9 +168,12 @@ class Thread;
|
|||
|
||||
#define CACHED_FUNCTION_ENTRY_POINTS_LIST(V) \
|
||||
V(suspend_state_init_async) \
|
||||
V(suspend_state_await_async) \
|
||||
V(suspend_state_await) \
|
||||
V(suspend_state_return_async) \
|
||||
V(suspend_state_return_async_not_future) \
|
||||
V(suspend_state_init_async_star) \
|
||||
V(suspend_state_yield_async_star) \
|
||||
V(suspend_state_return_async_star) \
|
||||
V(suspend_state_handle_exception)
|
||||
|
||||
// This assertion marks places which assume that boolean false immediate
|
||||
|
|
|
@ -110,7 +110,7 @@ void _asyncStarMoveNextHelper(var stream) {
|
|||
class _AsyncStarStreamController<T> {
|
||||
@pragma("vm:entry-point")
|
||||
StreamController<T> controller;
|
||||
Function asyncStarBody;
|
||||
Function? asyncStarBody;
|
||||
bool isAdding = false;
|
||||
bool onListenReceived = false;
|
||||
bool isScheduled = false;
|
||||
|
@ -127,7 +127,7 @@ class _AsyncStarStreamController<T> {
|
|||
Stream<T> get stream {
|
||||
final Stream<T> local = controller.stream;
|
||||
if (local is _StreamImpl<T>) {
|
||||
local._generator = asyncStarBody;
|
||||
local._generator = asyncStarBody!;
|
||||
}
|
||||
return local;
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ class _AsyncStarStreamController<T> {
|
|||
isSuspendedAtYield = false;
|
||||
final bool? argument = continuationArgument;
|
||||
continuationArgument = null;
|
||||
asyncStarBody(argument, null);
|
||||
asyncStarBody!(argument, null);
|
||||
}
|
||||
|
||||
void scheduleGenerator() {
|
||||
|
@ -158,6 +158,7 @@ class _AsyncStarStreamController<T> {
|
|||
// controller.add(e);
|
||||
// suspend;
|
||||
// if (controller.isCancelled) return;
|
||||
@pragma("vm:entry-point", "call")
|
||||
bool add(T event) {
|
||||
if (!onListenReceived) _fatal("yield before stream is listened to");
|
||||
if (isSuspendedAtYield) _fatal("unexpected yield");
|
||||
|
@ -174,6 +175,7 @@ class _AsyncStarStreamController<T> {
|
|||
// Adds the elements of stream into this controller's stream.
|
||||
// The generator will be scheduled again when all of the
|
||||
// elements of the added stream have been consumed.
|
||||
@pragma("vm:entry-point", "call")
|
||||
void addStream(Stream<T> stream) {
|
||||
if (!onListenReceived) _fatal("yield before stream is listened to");
|
||||
|
||||
|
@ -327,7 +329,7 @@ class _SuspendState {
|
|||
@pragma("vm:invisible")
|
||||
static Object? _initAsync<T>() {
|
||||
if (_trace) print('_initAsync<$T>');
|
||||
return new _Future<T>();
|
||||
return _Future<T>();
|
||||
}
|
||||
|
||||
@pragma("vm:invisible")
|
||||
|
@ -371,14 +373,14 @@ class _SuspendState {
|
|||
|
||||
@pragma("vm:entry-point", "call")
|
||||
@pragma("vm:invisible")
|
||||
Object? _awaitAsync(Object? object) {
|
||||
Object? _await(Object? object) {
|
||||
if (_trace) print('_awaitAsync (object=$object)');
|
||||
if (_thenCallback == null) {
|
||||
_createAsyncCallbacks();
|
||||
}
|
||||
_awaitHelper(object, unsafeCast<dynamic Function(dynamic)>(_thenCallback),
|
||||
unsafeCast<dynamic Function(Object, StackTrace)>(_errorCallback));
|
||||
return _future;
|
||||
return _functionData;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point", "call")
|
||||
|
@ -391,7 +393,7 @@ class _SuspendState {
|
|||
_Future future;
|
||||
bool isSync = true;
|
||||
if (suspendState is _SuspendState) {
|
||||
future = suspendState._future;
|
||||
future = unsafeCast<_Future>(suspendState._functionData);
|
||||
} else {
|
||||
future = unsafeCast<_Future>(suspendState);
|
||||
isSync = false;
|
||||
|
@ -411,7 +413,7 @@ class _SuspendState {
|
|||
_Future future;
|
||||
bool isSync = true;
|
||||
if (suspendState is _SuspendState) {
|
||||
future = suspendState._future;
|
||||
future = unsafeCast<_Future>(suspendState._functionData);
|
||||
} else {
|
||||
future = unsafeCast<_Future>(suspendState);
|
||||
isSync = false;
|
||||
|
@ -422,31 +424,79 @@ class _SuspendState {
|
|||
|
||||
@pragma("vm:entry-point", "call")
|
||||
@pragma("vm:invisible")
|
||||
static Future _handleException(
|
||||
static Object? _initAsyncStar<T>() {
|
||||
if (_trace) print('_initAsyncStar<$T>');
|
||||
return _AsyncStarStreamController<T>(null);
|
||||
}
|
||||
|
||||
@pragma("vm:invisible")
|
||||
@pragma("vm:recognized", "other")
|
||||
_createAsyncStarCallback(_AsyncStarStreamController controller) {
|
||||
controller.asyncStarBody = (value, _) {
|
||||
if (_trace) print('asyncStarBody callback (value=$value)');
|
||||
_resume(value, null, null);
|
||||
};
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point", "call")
|
||||
@pragma("vm:invisible")
|
||||
Object? _yieldAsyncStar(Object? object) {
|
||||
final controller = unsafeCast<_AsyncStarStreamController>(_functionData);
|
||||
if (controller.asyncStarBody == null) {
|
||||
_createAsyncStarCallback(controller);
|
||||
return controller.stream;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point", "call")
|
||||
@pragma("vm:invisible")
|
||||
static void _returnAsyncStar(Object suspendState, Object? returnValue) {
|
||||
if (_trace) {
|
||||
print('_returnAsyncStar (suspendState=$suspendState, '
|
||||
'returnValue=$returnValue)');
|
||||
}
|
||||
final controller = unsafeCast<_AsyncStarStreamController>(
|
||||
unsafeCast<_SuspendState>(suspendState)._functionData);
|
||||
controller.close();
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point", "call")
|
||||
@pragma("vm:invisible")
|
||||
static Object? _handleException(
|
||||
Object suspendState, Object exception, StackTrace stackTrace) {
|
||||
if (_trace) {
|
||||
print('_handleException (suspendState=$suspendState, '
|
||||
'exception=$exception, stackTrace=$stackTrace)');
|
||||
}
|
||||
_Future future;
|
||||
Object? functionData;
|
||||
bool isSync = true;
|
||||
if (suspendState is _SuspendState) {
|
||||
future = suspendState._future;
|
||||
functionData = suspendState._functionData;
|
||||
} else {
|
||||
future = unsafeCast<_Future>(suspendState);
|
||||
functionData = suspendState;
|
||||
isSync = false;
|
||||
}
|
||||
_completeOnAsyncError(future, exception, stackTrace, isSync);
|
||||
return future;
|
||||
if (functionData is _Future) {
|
||||
// async function.
|
||||
_completeOnAsyncError(functionData, exception, stackTrace, isSync);
|
||||
} else if (functionData is _AsyncStarStreamController) {
|
||||
// async* function.
|
||||
functionData.addError(exception, stackTrace);
|
||||
functionData.close();
|
||||
} else {
|
||||
throw 'Unexpected function data ${functionData.runtimeType} $functionData';
|
||||
}
|
||||
return functionData;
|
||||
}
|
||||
|
||||
@pragma("vm:recognized", "other")
|
||||
@pragma("vm:prefer-inline")
|
||||
external set _future(_Future value);
|
||||
external set _functionData(Object value);
|
||||
|
||||
@pragma("vm:recognized", "other")
|
||||
@pragma("vm:prefer-inline")
|
||||
external _Future get _future;
|
||||
external Object get _functionData;
|
||||
|
||||
@pragma("vm:recognized", "other")
|
||||
@pragma("vm:prefer-inline")
|
||||
|
@ -467,5 +517,5 @@ class _SuspendState {
|
|||
@pragma("vm:recognized", "other")
|
||||
@pragma("vm:never-inline")
|
||||
external void _resume(
|
||||
dynamic value, Object? exception, StackTrace? stackTrace);
|
||||
Object? value, Object? exception, StackTrace? stackTrace);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue