From f9327d3baca2e2a2bb5a0c773fd8a2de7c245635 Mon Sep 17 00:00:00 2001 From: Clement Skau Date: Wed, 4 Dec 2019 12:47:48 +0000 Subject: [PATCH] [SDK] Adds --lazy-async-stack support for async*. Bug: https://github.com/dart-lang/sdk/issues/39525 Change-Id: I53cd334243649901ea8e0f9799d9f41c126e3627 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/126729 Commit-Queue: Clement Skau Reviewed-by: Martin Kustermann --- .../lib/transformations/continuation.dart | 4 +- pkg/vm/lib/bytecode/local_vars.dart | 26 ++- .../tests/vm/dart/causal_stacks/utils.dart | 187 ++++++++++++++++++ runtime/vm/compiler/frontend/scope_builder.cc | 3 +- runtime/vm/object.h | 1 + runtime/vm/scopes.cc | 11 +- runtime/vm/stack_trace.cc | 120 +++++++++-- runtime/vm/symbols.h | 9 + sdk/lib/_internal/vm/lib/async_patch.dart | 1 + sdk/lib/async/stream_controller.dart | 9 +- sdk/lib/async/stream_impl.dart | 1 + .../lib/_internal/vm/lib/async_patch.dart | 1 + sdk_nnbd/lib/async/stream_controller.dart | 9 +- sdk_nnbd/lib/async/stream_impl.dart | 1 + 14 files changed, 359 insertions(+), 24 deletions(-) diff --git a/pkg/kernel/lib/transformations/continuation.dart b/pkg/kernel/lib/transformations/continuation.dart index 367e1e714306..bc0727695942 100644 --- a/pkg/kernel/lib/transformations/continuation.dart +++ b/pkg/kernel/lib/transformations/continuation.dart @@ -18,6 +18,7 @@ class ContinuationVariables { static const asyncCompleter = ':async_completer'; static const awaitContextVar = ':await_ctx_var'; static const asyncStackTraceVar = ':async_stack_trace'; + static const controller = ':controller'; static const controllerStreamVar = ':controller_stream'; static const exceptionParam = ':exception'; static const stackTraceParam = ':stack_trace'; @@ -965,7 +966,8 @@ class AsyncStarFunctionRewriter extends AsyncRewriterBase { final elementType = elementTypeFromReturnType(helper.streamClass); // _AsyncStarStreamController :controller; - controllerVariable = new VariableDeclaration(":controller", + controllerVariable = new VariableDeclaration( + ContinuationVariables.controller, type: new InterfaceType(helper.asyncStarStreamControllerClass, staticTypeContext.nullable, [elementType])); statements.add(controllerVariable); diff --git a/pkg/vm/lib/bytecode/local_vars.dart b/pkg/vm/lib/bytecode/local_vars.dart index ad0d67527be9..0e5957716995 100644 --- a/pkg/vm/lib/bytecode/local_vars.dart +++ b/pkg/vm/lib/bytecode/local_vars.dart @@ -19,6 +19,7 @@ import '../metadata/direct_call.dart' show DirectCallMetadata; // Keep in sync with runtime/vm/object.h:Context::kAwaitJumpVarIndex. const int awaitJumpVarContextIndex = 0; const int asyncCompleterContextIndex = 1; +const int controllerContextIndex = 1; class LocalVariables { final _scopes = new Map(); @@ -443,12 +444,17 @@ class _ScopeBuilder extends RecursiveVisitor { ._getVarDesc(_currentFrame .getSyntheticVar(ContinuationVariables.awaitJumpVar)) .moveToScope(_currentScope); - } - if (_currentFrame.dartAsyncMarker == AsyncMarker.Async) { - locals - ._getVarDesc(_currentFrame - .getSyntheticVar(ContinuationVariables.asyncCompleter)) - .moveToScope(_currentScope); + if (_currentFrame.dartAsyncMarker == AsyncMarker.Async) { + locals + ._getVarDesc(_currentFrame + .getSyntheticVar(ContinuationVariables.asyncCompleter)) + .moveToScope(_currentScope); + } else if (_currentFrame.dartAsyncMarker == AsyncMarker.AsyncStar) { + locals + ._getVarDesc(_currentFrame + .getSyntheticVar(ContinuationVariables.controller)) + .moveToScope(_currentScope); + } } } @@ -1110,6 +1116,12 @@ class _Allocator extends RecursiveVisitor { assert(locals._getVarDesc(asyncCompleter).index == asyncCompleterContextIndex); } + if (_currentFrame.dartAsyncMarker == AsyncMarker.AsyncStar) { + final controller = + _currentFrame.getSyntheticVar(ContinuationVariables.controller); + _allocateVariable(controller); + assert(locals._getVarDesc(controller).index == controllerContextIndex); + } _allocateParameters(node, function); _allocateSpecialVariables(); @@ -1172,6 +1184,8 @@ class _Allocator extends RecursiveVisitor { assert(locals._getVarDesc(node).index == awaitJumpVarContextIndex); } else if (node.name == ContinuationVariables.asyncCompleter) { assert(locals._getVarDesc(node).index == asyncCompleterContextIndex); + } else if (node.name == ContinuationVariables.controller) { + assert(locals._getVarDesc(node).index == controllerContextIndex); } else { _allocateVariable(node); } diff --git a/runtime/tests/vm/dart/causal_stacks/utils.dart b/runtime/tests/vm/dart/causal_stacks/utils.dart index 3060172c0386..6d4ccc29b049 100644 --- a/runtime/tests/vm/dart/causal_stacks/utils.dart +++ b/runtime/tests/vm/dart/causal_stacks/utils.dart @@ -96,6 +96,37 @@ Future nonAsyncNoStack1() async => await nonAsyncNoStack2(); Future nonAsyncNoStack2() async => Future.value(0).then((_) => throwAsync()); +// ---- +// Scenario: async*: +// ---- + +Future awaitEveryAsyncStarThrowSync() async { + await for (Future v in asyncStarThrowSync()) { + await v; + } +} + +Stream asyncStarThrowSync() async* { + for (int i = 0; i < 2; i++) { + await i; + yield throwSync(); + } +} + +Future awaitEveryAsyncStarThrowAsync() async { + await for (Future v in asyncStarThrowAsync()) { + await v; + } +} + +Stream asyncStarThrowAsync() async* { + for (int i = 0; i < 2; i++) { + await i; + yield Future.value(i); + await throwAsync(); + } +} + // Helpers: void assertStack(List expects, StackTrace stackTrace) { @@ -354,6 +385,93 @@ Future doTestsCausal() async { await doTestAwait(nonAsyncNoStack, nonAsyncNoStackExpected); await doTestAwaitThen(nonAsyncNoStack, nonAsyncNoStackExpected); await doTestAwaitCatchError(nonAsyncNoStack, nonAsyncNoStackExpected); + + final asyncStarThrowSyncExpected = const [ + r'^#0 throwSync \(.*/utils.dart:(16|16:3)\)$', + r'^#1 asyncStarThrowSync \(.*/utils.dart:(112|112:11)\)$', + r'^$', + r'^#2 awaitEveryAsyncStarThrowSync \(.+\)$', + ]; + await doTestAwait( + awaitEveryAsyncStarThrowSync, + asyncStarThrowSyncExpected + + const [ + r'^#3 doTestAwait \(.+\)$', + r'^#4 doTestsCausal \(.+\)$', + r'^$', + r'^#5 main \(.+\)$', + r'^#6 _startIsolate. \(.+\)$', + r'^#7 _RawReceivePortImpl._handleMessage \(.+\)$', + r'^$', + ]); + await doTestAwaitThen( + awaitEveryAsyncStarThrowSync, + asyncStarThrowSyncExpected + + const [ + r'^#3 doTestAwaitThen \(.+\)$', + r'^#4 doTestsCausal \(.+\)$', + r'^$', + r'^#5 main \(.+\)$', + r'^#6 _startIsolate. \(.+\)$', + r'^#7 _RawReceivePortImpl._handleMessage \(.+\)$', + r'^$', + ]); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowSync, + asyncStarThrowSyncExpected + + const [ + r'^#3 doTestAwaitCatchError \(.+\)$', + r'^#4 doTestsCausal \(.+\)$', + r'^$', + r'^#5 main \(.+\)$', + r'^#6 _startIsolate. \(.+\)$', + r'^#7 _RawReceivePortImpl._handleMessage \(.+\)$', + r'^$', + ]); + + final asyncStarThrowAsyncExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:(21|21:3)\)$', + r'^$', + r'^#1 asyncStarThrowAsync \(.*/utils.dart:(126|126:11)\)$', + r'^$', + r'^#2 awaitEveryAsyncStarThrowAsync \(.+\)$', + ]; + await doTestAwait( + awaitEveryAsyncStarThrowAsync, + asyncStarThrowAsyncExpected + + const [ + r'^#3 doTestAwait \(.+\)$', + r'^#4 doTestsCausal \(.+\)$', + r'^$', + r'^#5 main \(.+\)$', + r'^#6 _startIsolate. \(.+\)$', + r'^#7 _RawReceivePortImpl._handleMessage \(.+\)$', + r'^$', + ]); + await doTestAwaitThen( + awaitEveryAsyncStarThrowAsync, + asyncStarThrowAsyncExpected + + const [ + r'^#3 doTestAwaitThen \(.+\)$', + r'^#4 doTestsCausal \(.+\)$', + r'^$', + r'^#5 main \(.+\)$', + r'^#6 _startIsolate. \(.+\)$', + r'^#7 _RawReceivePortImpl._handleMessage \(.+\)$', + r'^$', + ]); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowAsync, + asyncStarThrowAsyncExpected + + const [ + r'^#3 doTestAwaitCatchError \(.+\)$', + r'^#4 doTestsCausal \(.+\)$', + r'^$', + r'^#5 main \(.+\)$', + r'^#6 _startIsolate. \(.+\)$', + r'^#7 _RawReceivePortImpl._handleMessage \(.+\)$', + r'^$', + ]); } // For: --no-causal-async-stacks @@ -586,6 +704,47 @@ Future doTestsNoCausal() async { await doTestAwait(nonAsyncNoStack, nonAsyncNoStackExpected); await doTestAwaitThen(nonAsyncNoStack, nonAsyncNoStackExpected); await doTestAwaitCatchError(nonAsyncNoStack, nonAsyncNoStackExpected); + + final asyncStarThrowSyncExpected = const [ + r'^#0 throwSync \(.+/utils.dart:(16|16:3)\)$', + r'^#1 asyncStarThrowSync \(.+/utils.dart:(112|112:11)\)$', + r'^#2 _RootZone.runUnary \(.+\)$', + r'^#3 _FutureListener.handleValue \(.+\)$', + r'^#4 Future._propagateToListeners.handleValueCallback \(.+\)$', + r'^#5 Future._propagateToListeners \(.+\)$', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#6 Future.(_addListener|_prependListeners). \(.+\)$', + r'^#7 _microtaskLoop \(.+\)$', + r'^#8 _startMicrotaskLoop \(.+\)$', + r'^#9 _runPendingImmediateCallback \(.+\)$', + r'^#10 _RawReceivePortImpl._handleMessage \(.+\)$', + r'^$', + ]; + await doTestAwait(awaitEveryAsyncStarThrowSync, asyncStarThrowSyncExpected); + await doTestAwaitThen( + awaitEveryAsyncStarThrowSync, asyncStarThrowSyncExpected); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowSync, asyncStarThrowSyncExpected); + + final asyncStarThrowAsyncExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:(21|21:3)\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + r'^$', + ]; + await doTestAwait(awaitEveryAsyncStarThrowAsync, asyncStarThrowAsyncExpected); + await doTestAwaitThen( + awaitEveryAsyncStarThrowAsync, asyncStarThrowAsyncExpected); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowAsync, asyncStarThrowAsyncExpected); } // For: --lazy-async-stacks @@ -744,4 +903,32 @@ Future doTestsLazy() async { const [ r'^$', ]); + + final asyncStarThrowSyncExpected = const [ + r'^#0 throwSync \(.+/utils.dart:(16|16:3)\)$', + r'^#1 asyncStarThrowSync \(.+/utils.dart:(112|112:11)\)$', + r'^$', + // Non-visible _onData frame. + r'^$', + r'^$', + ]; + await doTestAwait(awaitEveryAsyncStarThrowSync, asyncStarThrowSyncExpected); + await doTestAwaitThen( + awaitEveryAsyncStarThrowSync, asyncStarThrowSyncExpected); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowSync, asyncStarThrowSyncExpected); + + final asyncStarThrowAsyncExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:(21|21:3)\)$', + r'^$', + r'^#1 asyncStarThrowAsync \(.*/utils.dart:(0|126|126:5)\)$', + r'^$', + // Non-visible _onData frame. + r'^$', + ]; + await doTestAwait(awaitEveryAsyncStarThrowAsync, asyncStarThrowAsyncExpected); + await doTestAwaitThen( + awaitEveryAsyncStarThrowAsync, asyncStarThrowAsyncExpected); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowAsync, asyncStarThrowAsyncExpected); } diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc index 391a04b32ef8..66348aaa3a62 100644 --- a/runtime/vm/compiler/frontend/scope_builder.cc +++ b/runtime/vm/compiler/frontend/scope_builder.cc @@ -1280,7 +1280,8 @@ void ScopeBuilder::VisitVariableDeclaration() { // This way we can allocate them in the outermost context at fixed indices, // allowing support for --lazy-async-stacks implementation to find awaiters. if (name.Equals(Symbols::AwaitJumpVar()) || - name.Equals(Symbols::AsyncCompleter())) { + name.Equals(Symbols::AsyncCompleter()) || + name.Equals(Symbols::Controller())) { scope_->parent()->AddVariable(variable); } else { scope_->AddVariable(variable); diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 402e025e54d6..bc8e4614f1c4 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -6036,6 +6036,7 @@ class Context : public Object { static const intptr_t kAwaitJumpVarIndex = 0; static const intptr_t kAsyncCompleterIndex = 1; + static const intptr_t kControllerIndex = 1; static intptr_t variable_offset(intptr_t context_index) { return OFFSET_OF_RETURNED_VALUE(RawContext, data) + diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc index 27031de495e1..bd68c5ef8488 100644 --- a/runtime/vm/scopes.cc +++ b/runtime/vm/scopes.cc @@ -210,6 +210,7 @@ VariableIndex LocalScope::AllocateVariables(VariableIndex first_parameter_index, LocalVariable* await_jump_var = nullptr; LocalVariable* async_completer = nullptr; + LocalVariable* controller = nullptr; for (intptr_t i = 0; i < num_variables(); i++) { LocalVariable* variable = VariableAt(i); if (variable->owner() == this) { @@ -218,6 +219,8 @@ VariableIndex LocalScope::AllocateVariables(VariableIndex first_parameter_index, await_jump_var = variable; } else if (variable->name().Equals(Symbols::AsyncCompleter())) { async_completer = variable; + } else if (variable->name().Equals(Symbols::Controller())) { + controller = variable; } } } @@ -234,6 +237,11 @@ VariableIndex LocalScope::AllocateVariables(VariableIndex first_parameter_index, *found_captured_variables = true; ASSERT(async_completer->index().value() == Context::kAsyncCompleterIndex); } + if (controller != nullptr) { + AllocateContextVariable(controller, &context_owner); + *found_captured_variables = true; + ASSERT(controller->index().value() == Context::kControllerIndex); + } while (pos < num_parameters) { LocalVariable* parameter = VariableAt(pos); @@ -263,7 +271,8 @@ VariableIndex LocalScope::AllocateVariables(VariableIndex first_parameter_index, if (variable->owner() == this) { if (variable->is_captured()) { // Skip the two variables already pre-allocated above. - if (variable != await_jump_var && variable != async_completer) { + if (variable != await_jump_var && variable != async_completer && + variable != controller) { AllocateContextVariable(variable, &context_owner); *found_captured_variables = true; } diff --git a/runtime/vm/stack_trace.cc b/runtime/vm/stack_trace.cc index ed287737441b..9581646e8a8c 100644 --- a/runtime/vm/stack_trace.cc +++ b/runtime/vm/stack_trace.cc @@ -11,6 +11,10 @@ namespace dart { +// Keep in sync with +// sdk/lib/async/stream_controller.dart:_StreamController._STATE_SUBSCRIBED. +const intptr_t kStreamController_StateSubscribed = 1; + RawClosure* FindClosureInFrame(RawObject** last_object_in_caller, const Function& function, bool is_interpreted) { @@ -98,14 +102,27 @@ class CallerClosureFinder { future_(Object::Handle(zone)), listener_(Object::Handle(zone)), callback_(Object::Handle(zone)), + controller_(Object::Handle(zone)), + state_(Object::Handle(zone)), + var_data_(Object::Handle(zone)), future_impl_class(Class::Handle(zone)), async_await_completer_class(Class::Handle(zone)), future_listener_class(Class::Handle(zone)), + async_start_stream_controller_class(Class::Handle(zone)), + stream_controller_class(Class::Handle(zone)), + controller_subscription_class(Class::Handle(zone)), + buffering_stream_subscription_class(Class::Handle(zone)), + async_stream_controller_class(Class::Handle(zone)), completer_future_field(Field::Handle(zone)), future_result_or_listeners_field(Field::Handle(zone)), - callback_field(Field::Handle(zone)) { + callback_field(Field::Handle(zone)), + controller_controller_field(Field::Handle(zone)), + var_data_field(Field::Handle(zone)), + state_field(Field::Handle(zone)), + on_data_field(Field::Handle(zone)) { const auto& async_lib = Library::Handle(zone, Library::AsyncLibrary()); - // Look up classes. + // Look up classes: + // - async: future_impl_class = async_lib.LookupClassAllowPrivate(Symbols::FutureImpl()); ASSERT(!future_impl_class.IsNull()); @@ -115,7 +132,25 @@ class CallerClosureFinder { future_listener_class = async_lib.LookupClassAllowPrivate(Symbols::_FutureListener()); ASSERT(!future_listener_class.IsNull()); - // Look up fields. + // - async*: + async_start_stream_controller_class = async_lib.LookupClassAllowPrivate( + Symbols::_AsyncStarStreamController()); + ASSERT(!async_start_stream_controller_class.IsNull()); + stream_controller_class = + async_lib.LookupClassAllowPrivate(Symbols::_StreamController()); + ASSERT(!stream_controller_class.IsNull()); + async_stream_controller_class = + async_lib.LookupClassAllowPrivate(Symbols::_AsyncStreamController()); + ASSERT(!async_stream_controller_class.IsNull()); + controller_subscription_class = + async_lib.LookupClassAllowPrivate(Symbols::_ControllerSubscription()); + ASSERT(!controller_subscription_class.IsNull()); + buffering_stream_subscription_class = async_lib.LookupClassAllowPrivate( + Symbols::_BufferingStreamSubscription()); + ASSERT(!buffering_stream_subscription_class.IsNull()); + + // Look up fields: + // - async: completer_future_field = async_await_completer_class.LookupFieldAllowPrivate(Symbols::_future()); ASSERT(!completer_future_field.IsNull()); @@ -126,18 +161,24 @@ class CallerClosureFinder { callback_field = future_listener_class.LookupFieldAllowPrivate(Symbols::callback()); ASSERT(!callback_field.IsNull()); + // - async*: + controller_controller_field = + async_start_stream_controller_class.LookupFieldAllowPrivate( + Symbols::controller()); + ASSERT(!controller_controller_field.IsNull()); + state_field = + stream_controller_class.LookupFieldAllowPrivate(Symbols::_state()); + ASSERT(!state_field.IsNull()); + var_data_field = + stream_controller_class.LookupFieldAllowPrivate(Symbols::_varData()); + ASSERT(!var_data_field.IsNull()); + on_data_field = buffering_stream_subscription_class.LookupFieldAllowPrivate( + Symbols::_onData()); + ASSERT(!on_data_field.IsNull()); } - RawClosure* FindCaller(const Closure& receiver_closure) { - receiver_function_ = receiver_closure.function(); - if (!receiver_function_.IsAsyncClosure() && - !receiver_function_.IsAsyncGenClosure()) { - return Closure::null(); - } - - receiver_context_ = receiver_closure.context(); - context_entry_ = receiver_context_.At(Context::kAsyncCompleterIndex); - + RawClosure* FindCallerInAsyncClosure(const Context& receiver_context) { + context_entry_ = receiver_context.At(Context::kAsyncCompleterIndex); ASSERT(context_entry_.IsInstance()); ASSERT(context_entry_.GetClassId() == async_await_completer_class.id()); @@ -162,20 +203,73 @@ class CallerClosureFinder { return Closure::Cast(callback_).raw(); } + RawClosure* FindCallerInAsyncGenClosure(const Context& receiver_context) { + context_entry_ = receiver_context.At(Context::kControllerIndex); + ASSERT(context_entry_.IsInstance()); + ASSERT(context_entry_.GetClassId() == + async_start_stream_controller_class.id()); + + const Instance& controller = Instance::Cast(context_entry_); + controller_ = controller.GetField(controller_controller_field); + ASSERT(!controller_.IsNull()); + ASSERT(controller_.GetClassId() == async_stream_controller_class.id()); + + state_ = Instance::Cast(controller_).GetField(state_field); + ASSERT(state_.IsSmi()); + if (Smi::Cast(state_).Value() != kStreamController_StateSubscribed) { + return Closure::null(); + } + + var_data_ = Instance::Cast(controller_).GetField(var_data_field); + ASSERT(var_data_.GetClassId() == controller_subscription_class.id()); + + callback_ = Instance::Cast(var_data_).GetField(on_data_field); + ASSERT(callback_.IsClosure()); + + return Closure::Cast(callback_).raw(); + } + + RawClosure* FindCaller(const Closure& receiver_closure) { + receiver_function_ = receiver_closure.function(); + receiver_context_ = receiver_closure.context(); + + if (receiver_function_.IsAsyncClosure()) { + return FindCallerInAsyncClosure(receiver_context_); + } else if (receiver_function_.IsAsyncGenClosure()) { + return FindCallerInAsyncGenClosure(receiver_context_); + } + + return Closure::null(); + } + private: Context& receiver_context_; Function& receiver_function_; + Object& context_entry_; Object& future_; Object& listener_; Object& callback_; + Object& controller_; + Object& state_; + Object& var_data_; Class& future_impl_class; Class& async_await_completer_class; Class& future_listener_class; + Class& async_start_stream_controller_class; + Class& stream_controller_class; + Class& controller_subscription_class; + Class& buffering_stream_subscription_class; + Class& async_stream_controller_class; + Field& completer_future_field; Field& future_result_or_listeners_field; Field& callback_field; + Field& controller_controller_field; + Field& var_data_field; + Field& state_field; + Field& on_data_field; }; void StackTraceUtils::CollectFramesLazy( diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h index ff63c444f8ac..3f47d8f47f33 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h @@ -61,6 +61,7 @@ class ObjectPointerVisitor; V(ConstructorStacktracePrefix, "new ") \ V(Context, "Context") \ V(ContextScope, "ContextScope") \ + V(Controller, ":controller") \ V(ControllerStream, ":controller_stream") \ V(Current, "current") \ V(CurrentContextVar, ":current_context_var") \ @@ -252,6 +253,7 @@ class ObjectPointerVisitor; V(StackTraceParameter, ":stack_trace") \ V(StackTraceVar, ":stack_trace_var") \ V(Stream, "stream") \ + V(StreamController, "StreamController") \ V(StreamIterator, "StreamIterator") \ V(StreamIteratorConstructor, "StreamIterator.") \ V(StringBase, "_StringBase") \ @@ -300,7 +302,9 @@ class ObjectPointerVisitor; V(_AsyncStarListenHelper, "_asyncStarListenHelper") \ V(_AsyncStarStreamController, "_AsyncStarStreamController") \ V(_AsyncStarStreamControllerConstructor, "_AsyncStarStreamController.") \ + V(_AsyncStreamController, "_AsyncStreamController") \ V(_Awaiter, "_awaiter") \ + V(_BufferingStreamSubscription, "_BufferingStreamSubscription") \ V(_ByteBuffer, "_ByteBuffer") \ V(_ByteBufferDot_New, "_ByteBuffer._New") \ V(_ByteDataView, "_ByteDataView") \ @@ -311,6 +315,7 @@ class ObjectPointerVisitor; V(_CombinatorMirror, "_CombinatorMirror") \ V(_CompileTimeError, "_CompileTimeError") \ V(_CompleteOnAsyncReturn, "_completeOnAsyncReturn") \ + V(_ControllerSubscription, "_ControllerSubscription") \ V(_DeletedEnumPrefix, "Deleted enum value from ") \ V(_DeletedEnumSentinel, "_deleted_enum_sentinel") \ V(_Double, "_Double") \ @@ -386,6 +391,7 @@ class ObjectPointerVisitor; V(_SourceLocation, "_SourceLocation") \ V(_SpecialTypeMirror, "_SpecialTypeMirror") \ V(_StackTrace, "_StackTrace") \ + V(_StreamController, "_StreamController") \ V(_StreamImpl, "_StreamImpl") \ V(_String, "String") \ V(_SyncIterable, "_SyncIterable") \ @@ -424,6 +430,7 @@ class ObjectPointerVisitor; V(_instanceOf, "_instanceOf") \ V(_lookupHandler, "_lookupHandler") \ V(_name, "_name") \ + V(_onData, "_onData") \ V(_rehashObjects, "_rehashObjects") \ V(_resultOrListeners, "_resultOrListeners") \ V(_runExtension, "_runExtension") \ @@ -434,6 +441,7 @@ class ObjectPointerVisitor; V(_simpleInstanceOfTrue, "_simpleInstanceOfTrue") \ V(_stackTrace, "_stackTrace") \ V(_state, "_state") \ + V(_varData, "_varData") \ V(_wordCharacterMap, "_wordCharacterMap") \ V(add, "add") \ V(callback, "callback") \ @@ -442,6 +450,7 @@ class ObjectPointerVisitor; V(char_in_capture, ":char_in_capture") \ V(char_in_match, ":char_in_match") \ V(clear, "clear") \ + V(controller, "controller") \ V(current_character, ":current_character") \ V(current_position, ":current_position") \ V(getID, "getID") \ diff --git a/sdk/lib/_internal/vm/lib/async_patch.dart b/sdk/lib/_internal/vm/lib/async_patch.dart index 374947ded21b..c4266f445721 100644 --- a/sdk/lib/_internal/vm/lib/async_patch.dart +++ b/sdk/lib/_internal/vm/lib/async_patch.dart @@ -134,6 +134,7 @@ void _asyncStarMoveNextHelper(var stream) { // async* generator functions. @pragma("vm:entry-point") class _AsyncStarStreamController { + @pragma("vm:entry-point") StreamController controller; Function asyncStarBody; bool isAdding = false; diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart index f2854a943ba4..50e9aa340028 100644 --- a/sdk/lib/async/stream_controller.dart +++ b/sdk/lib/async/stream_controller.dart @@ -409,7 +409,12 @@ abstract class _StreamController implements _StreamControllerBase { /** The controller is in its initial state with no subscription. */ static const int _STATE_INITIAL = 0; - /** The controller has a subscription, but hasn't been closed or canceled. */ + /** + * The controller has a subscription, but hasn't been closed or canceled. + * + * Keep in sync with + * runtime/vm/stack_trace.cc:kStreamController_StateSubscribed. + */ static const int _STATE_SUBSCRIBED = 1; /** The subscription is canceled. */ static const int _STATE_CANCELED = 2; @@ -447,9 +452,11 @@ abstract class _StreamController implements _StreamControllerBase { * * When [_state] is [_STATE_CANCELED] the field is currently not used. */ + @pragma("vm:entry-point") var _varData; /** Current state of the controller. */ + @pragma("vm:entry-point") int _state = _STATE_INITIAL; /** diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart index b3969fcaf697..0b7cc5a6b56f 100644 --- a/sdk/lib/async/stream_impl.dart +++ b/sdk/lib/async/stream_impl.dart @@ -89,6 +89,7 @@ class _BufferingStreamSubscription static const int _STATE_PAUSE_COUNT = 128; /* Event handlers provided in constructor. */ + @pragma("vm:entry-point") _DataHandler _onData; Function _onError; _DoneHandler _onDone; diff --git a/sdk_nnbd/lib/_internal/vm/lib/async_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/async_patch.dart index 2edf7c2110f9..fa10ad4da018 100644 --- a/sdk_nnbd/lib/_internal/vm/lib/async_patch.dart +++ b/sdk_nnbd/lib/_internal/vm/lib/async_patch.dart @@ -134,6 +134,7 @@ void _asyncStarMoveNextHelper(var stream) { // async* generator functions. @pragma("vm:entry-point") class _AsyncStarStreamController { + @pragma("vm:entry-point") StreamController controller; Function asyncStarBody; bool isAdding = false; diff --git a/sdk_nnbd/lib/async/stream_controller.dart b/sdk_nnbd/lib/async/stream_controller.dart index 9303b8615e9e..6f09d5d46a9e 100644 --- a/sdk_nnbd/lib/async/stream_controller.dart +++ b/sdk_nnbd/lib/async/stream_controller.dart @@ -407,7 +407,12 @@ abstract class _StreamController implements _StreamControllerBase { /** The controller is in its initial state with no subscription. */ static const int _STATE_INITIAL = 0; - /** The controller has a subscription, but hasn't been closed or canceled. */ + /** + * The controller has a subscription, but hasn't been closed or canceled. + * + * Keep in sync with + * runtime/vm/stack_trace.cc:kStreamController_StateSubscribed. + */ static const int _STATE_SUBSCRIBED = 1; /** The subscription is canceled. */ static const int _STATE_CANCELED = 2; @@ -446,9 +451,11 @@ abstract class _StreamController implements _StreamControllerBase { * When [_state] is [_STATE_CANCELED] the field is currently not used, * and will contain `null`. */ + @pragma("vm:entry-point") Object? _varData; /** Current state of the controller. */ + @pragma("vm:entry-point") int _state = _STATE_INITIAL; /** diff --git a/sdk_nnbd/lib/async/stream_impl.dart b/sdk_nnbd/lib/async/stream_impl.dart index 5011a82e2430..f8a443744e64 100644 --- a/sdk_nnbd/lib/async/stream_impl.dart +++ b/sdk_nnbd/lib/async/stream_impl.dart @@ -87,6 +87,7 @@ class _BufferingStreamSubscription static const int _STATE_PAUSE_COUNT = 128; /* Event handlers provided in constructor. */ + @pragma("vm:entry-point") _DataHandler _onData; Function _onError; _DoneHandler _onDone;