[kernel] Remove obsolete AsyncMarker.SyncYielding and YieldStatement.isNative

AsyncMarker.SyncYielding and YieldStatement.isNative became
obsolete after async/async*/sync* kernel transformation was removed in
https://dart-review.googlesource.com/c/sdk/+/249944.

TEST=ci

Issue: https://github.com/dart-lang/sdk/issues/48378
Change-Id: I69ac994af77f7e403686750bf8df437868bf33fa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/249947
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
Alexander Markov 2022-07-11 18:20:45 +00:00 committed by Commit Bot
parent 3a45cf139b
commit 3a1229e56c
16 changed files with 110 additions and 377 deletions

View file

@ -434,10 +434,6 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation>
case ir.AsyncMarker.AsyncStar: case ir.AsyncMarker.AsyncStar:
recordReturnType(_types.asyncStarStreamType); recordReturnType(_types.asyncStarStreamType);
break; break;
case ir.AsyncMarker.SyncYielding:
failedAt(
_analyzedMember, "Unexpected async marker: ${node.asyncMarker}");
break;
} }
assert(_breaksFor.isEmpty); assert(_breaksFor.isEmpty);
assert(_continuesFor.isEmpty); assert(_continuesFor.isEmpty);

View file

@ -192,10 +192,6 @@ class ImpactBuilder extends StaticTypeVisitor implements ImpactRegistry {
} }
registerAsyncStar(elementType); registerAsyncStar(elementType);
break; break;
case ir.AsyncMarker.SyncYielding:
failedAt(CURRENT_ELEMENT_SPANNABLE,
"Unexpected async marker: ${asyncMarker}");
} }
} }

View file

@ -58,7 +58,6 @@ AsyncMarker getAsyncMarker(ir.FunctionNode node) {
return AsyncMarker.SYNC; return AsyncMarker.SYNC;
case ir.AsyncMarker.SyncStar: case ir.AsyncMarker.SyncStar:
return AsyncMarker.SYNC_STAR; return AsyncMarker.SYNC_STAR;
case ir.AsyncMarker.SyncYielding:
default: default:
throw UnsupportedError( throw UnsupportedError(
"Async marker ${node.asyncMarker} is not supported."); "Async marker ${node.asyncMarker} is not supported.");

View file

@ -76,8 +76,7 @@ import '../messages.dart' as messages show getLocationFromUri;
import '../modifier.dart' import '../modifier.dart'
show Modifier, constMask, covariantMask, finalMask, lateMask, requiredMask; show Modifier, constMask, covariantMask, finalMask, lateMask, requiredMask;
import '../names.dart' show emptyName, minusName, plusName; import '../names.dart' show emptyName, minusName, plusName;
import '../problems.dart' import '../problems.dart' show internalProblem, unhandled, unsupported;
show internalProblem, unexpected, unhandled, unsupported;
import '../scope.dart'; import '../scope.dart';
import '../source/diet_parser.dart'; import '../source/diet_parser.dart';
import '../source/source_class_builder.dart'; import '../source/source_class_builder.dart';
@ -1415,9 +1414,6 @@ class BodyBuilder extends StackListenerImpl
case AsyncMarker.Sync: case AsyncMarker.Sync:
break; // skip break; // skip
case AsyncMarker.SyncYielding:
unexpected("async, async*, sync, or sync*", "$asyncModifier",
member.charOffset, uri);
} }
if (problem != null) { if (problem != null) {

View file

@ -147,7 +147,7 @@ type CanonicalName {
type ComponentFile { type ComponentFile {
UInt32 magic = 0x90ABCDEF; UInt32 magic = 0x90ABCDEF;
UInt32 formatVersion = 82; UInt32 formatVersion = 83;
Byte[10] shortSdkHash; Byte[10] shortSdkHash;
List<String> problemsAsJson; // Described in problems.md. List<String> problemsAsJson; // Described in problems.md.
Library[] libraries; Library[] libraries;
@ -510,8 +510,7 @@ enum AsyncMarker {
Sync, Sync,
SyncStar, SyncStar,
Async, Async,
AsyncStar, AsyncStar
SyncYielding
} }
*/ */
@ -1398,7 +1397,7 @@ type TryFinally extends Statement {
type YieldStatement extends Statement { type YieldStatement extends Statement {
Byte tag = 77; Byte tag = 77;
FileOffset fileOffset; FileOffset fileOffset;
Byte flags (isYieldStar, isNative); Byte flags (isYieldStar);
Expression expression; Expression expression;
} }

View file

@ -3956,43 +3956,6 @@ enum AsyncMarker {
SyncStar, SyncStar,
Async, Async,
AsyncStar, AsyncStar,
// `SyncYielding` is a marker that tells Dart VM that this function is an
// artificial closure introduced by an async transformer which desugared all
// async syntax into a combination of native yields and helper method calls.
//
// Native yields (formatted as `[yield]`) are semantically close to
// `yield x` statement: they denote a yield/resume point within a function
// but are completely decoupled from the notion of iterators. When
// execution of the closure reaches `[yield] x` it stops and return the
// value of `x` to the caller. If closure is called again it continues
// to the next statement after this yield as if it was suspended and resumed.
//
// Consider this example:
//
// g() {
// var :await_jump_var = 0;
// var :await_ctx_var;
//
// f(x) yielding {
// [yield] '${x}:0';
// [yield] '${x}:1';
// [yield] '${x}:2';
// }
//
// return f;
// }
//
// print(f('a')); /* prints 'a:0', :await_jump_var = 1 */
// print(f('b')); /* prints 'b:1', :await_jump_var = 2 */
// print(f('c')); /* prints 'c:2', :await_jump_var = 3 */
//
// Note: currently Dart VM implicitly relies on async transformer to
// inject certain artificial variables into g (like `:await_jump_var`).
// As such SyncYielding and native yield are not intended to be used on their
// own, but are rather an implementation artifact of the async transformer
// itself.
SyncYielding,
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -10523,33 +10486,23 @@ class TryFinally extends Statement {
} }
/// Statement of form `yield x` or `yield* x`. /// Statement of form `yield x` or `yield* x`.
///
/// For native yield semantics see `AsyncMarker.SyncYielding`.
class YieldStatement extends Statement { class YieldStatement extends Statement {
Expression expression; Expression expression;
int flags = 0; int flags = 0;
YieldStatement(this.expression, YieldStatement(this.expression, {bool isYieldStar: false}) {
{bool isYieldStar: false, bool isNative: false}) {
expression.parent = this; expression.parent = this;
this.isYieldStar = isYieldStar; this.isYieldStar = isYieldStar;
this.isNative = isNative;
} }
static const int FlagYieldStar = 1 << 0; static const int FlagYieldStar = 1 << 0;
static const int FlagNative = 1 << 1;
bool get isYieldStar => flags & FlagYieldStar != 0; bool get isYieldStar => flags & FlagYieldStar != 0;
bool get isNative => flags & FlagNative != 0;
void set isYieldStar(bool value) { void set isYieldStar(bool value) {
flags = value ? (flags | FlagYieldStar) : (flags & ~FlagYieldStar); flags = value ? (flags | FlagYieldStar) : (flags & ~FlagYieldStar);
} }
void set isNative(bool value) {
flags = value ? (flags | FlagNative) : (flags & ~FlagNative);
}
@override @override
R accept<R>(StatementVisitor<R> v) => v.visitYieldStatement(this); R accept<R>(StatementVisitor<R> v) => v.visitYieldStatement(this);

View file

@ -2895,8 +2895,7 @@ class BinaryBuilder {
int offset = readOffset(); int offset = readOffset();
int flags = readByte(); int flags = readByte();
return new YieldStatement(readExpression(), return new YieldStatement(readExpression(),
isYieldStar: flags & YieldStatement.FlagYieldStar != 0, isYieldStar: flags & YieldStatement.FlagYieldStar != 0)
isNative: flags & YieldStatement.FlagNative != 0)
..fileOffset = offset; ..fileOffset = offset;
} }

View file

@ -179,7 +179,7 @@ class Tag {
/// Internal version of kernel binary format. /// Internal version of kernel binary format.
/// Bump it when making incompatible changes in kernel binaries. /// Bump it when making incompatible changes in kernel binaries.
/// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md. /// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
static const int BinaryFormatVersion = 82; static const int BinaryFormatVersion = 83;
} }
abstract class ConstantTag { abstract class ConstantTag {

View file

@ -818,8 +818,6 @@ class Printer extends Visitor<void> with VisitorVoidMixin {
return 'async'; return 'async';
case AsyncMarker.AsyncStar: case AsyncMarker.AsyncStar:
return 'async*'; return 'async*';
case AsyncMarker.SyncYielding:
return 'yielding';
default: default:
return '<Invalid async marker: $marker>'; return '<Invalid async marker: $marker>';
} }
@ -2414,8 +2412,6 @@ class Printer extends Visitor<void> with VisitorVoidMixin {
writeIndentation(); writeIndentation();
if (node.isYieldStar) { if (node.isYieldStar) {
writeWord('yield*'); writeWord('yield*');
} else if (node.isNative) {
writeWord('[yield]');
} else { } else {
writeWord('yield'); writeWord('yield');
} }

View file

@ -363,26 +363,6 @@ class TypeCheckingVisitor
case AsyncMarker.AsyncStar: case AsyncMarker.AsyncStar:
return null; return null;
case AsyncMarker.SyncYielding:
// The SyncStar transform wraps the original function body twice,
// where the inner most function returns bool.
TreeNode? parent = function.parent;
while (parent is! FunctionNode) {
parent = parent!.parent;
}
FunctionNode enclosingFunction = parent;
if (enclosingFunction.dartAsyncMarker == AsyncMarker.Sync) {
parent = enclosingFunction.parent;
while (parent is! FunctionNode) {
parent = parent!.parent;
}
enclosingFunction = parent;
if (enclosingFunction.dartAsyncMarker == AsyncMarker.SyncStar) {
return coreTypes.boolLegacyRawType;
}
}
return null;
default: default:
throw 'Unexpected async marker: ${function.asyncMarker}'; throw 'Unexpected async marker: ${function.asyncMarker}';
} }
@ -405,9 +385,6 @@ class TypeCheckingVisitor
} }
return const DynamicType(); return const DynamicType();
case AsyncMarker.SyncYielding:
return function.returnType;
default: default:
throw 'Unexpected async marker: ${function.asyncMarker}'; throw 'Unexpected async marker: ${function.asyncMarker}';
} }

View file

@ -528,7 +528,6 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
switch (currentAsyncMarker) { switch (currentAsyncMarker) {
case AsyncMarker.Sync: case AsyncMarker.Sync:
case AsyncMarker.Async: case AsyncMarker.Async:
case AsyncMarker.SyncYielding:
// ok // ok
break; break;
case AsyncMarker.SyncStar: case AsyncMarker.SyncStar:
@ -556,7 +555,6 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
break; break;
case AsyncMarker.SyncStar: case AsyncMarker.SyncStar:
case AsyncMarker.AsyncStar: case AsyncMarker.AsyncStar:
case AsyncMarker.SyncYielding:
// ok // ok
break; break;
} }

View file

@ -363,17 +363,6 @@ class _VariablesInfoCollector extends RecursiveVisitor {
final function = node.function; final function = node.function;
function.accept(this); function.accept(this);
if (function.asyncMarker == AsyncMarker.SyncYielding) {
// Mark parameters of synthetic async_op closures as captured
// to make sure their updates at yield points are taken into account.
for (var v in function.positionalParameters) {
_captureVariable(v);
}
for (var v in function.namedParameters) {
_captureVariable(v);
}
}
activeStatements = savedActiveStatements; activeStatements = savedActiveStatements;
numVariablesAtActiveStatements = savedNumVariablesAtActiveStatements; numVariablesAtActiveStatements = savedNumVariablesAtActiveStatements;
numVariablesAtFunctionEntry = savedNumVariablesAtFunctionEntry; numVariablesAtFunctionEntry = savedNumVariablesAtFunctionEntry;

View file

@ -5303,188 +5303,108 @@ Fragment StreamingFlowGraphBuilder::BuildYieldStatement(
const uint8_t flags = ReadByte(); // read flags. const uint8_t flags = ReadByte(); // read flags.
if ((flags & kYieldStatementFlagNative) == 0) { Fragment instructions;
Fragment instructions; const bool is_yield_star = (flags & kYieldStatementFlagYieldStar) != 0;
const bool is_yield_star = (flags & kYieldStatementFlagYieldStar) != 0;
// Load :suspend_state variable using low-level FP-relative load // Load :suspend_state variable using low-level FP-relative load
// in order to avoid confusing SSA construction (which cannot // in order to avoid confusing SSA construction (which cannot
// track its value as it is modified implicitly by stubs). // track its value as it is modified implicitly by stubs).
LocalVariable* suspend_state = parsed_function()->suspend_state_var(); LocalVariable* suspend_state = parsed_function()->suspend_state_var();
ASSERT(suspend_state != nullptr); ASSERT(suspend_state != nullptr);
instructions += IntConstant(0); instructions += IntConstant(0);
instructions += B->LoadFpRelativeSlot( instructions += B->LoadFpRelativeSlot(
compiler::target::frame_layout.FrameSlotForVariable(suspend_state) * compiler::target::frame_layout.FrameSlotForVariable(suspend_state) *
compiler::target::kWordSize, compiler::target::kWordSize,
CompileType::Dynamic(), kTagged); CompileType::Dynamic(), kTagged);
instructions += LoadNativeField(Slot::SuspendState_function_data()); instructions += LoadNativeField(Slot::SuspendState_function_data());
instructions += BuildExpression(); // read expression.
if (NeedsDebugStepCheck(parsed_function()->function(), pos)) {
instructions += DebugStepCheck(pos);
}
if (parsed_function()->function().IsCompactAsyncStarFunction()) {
// In the async* functions, 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;
// }
//
auto& add_method = Function::ZoneHandle(Z);
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(TokenPosition::kNoSource, 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->Suspend(pos, SuspendInstr::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->Suspend(pos, SuspendInstr::StubId::kYieldAsyncStar);
instructions += Drop();
}
} else if (parsed_function()->function().IsCompactSyncStarFunction()) {
// In the sync* functions, generate the following code for yield <expr>:
//
// _SyncStarIterator iterator = :suspend_state._functionData;
// iterator._current = <expr>;
// suspend();
//
// Generate the following code for yield* <expr>:
//
// _SyncStarIterator iterator = :suspend_state._functionData;
// iterator._yieldStarIterable = <expr>;
// suspend();
//
auto& field = Field::ZoneHandle(Z);
if (is_yield_star) {
field = IG->object_store()->sync_star_iterator_yield_star_iterable();
} else {
field = IG->object_store()->sync_star_iterator_current();
}
instructions += B->StoreInstanceFieldGuarded(field);
instructions += NullConstant();
instructions += B->Suspend(pos, SuspendInstr::StubId::kYieldSyncStar);
instructions += Drop();
} else {
UNREACHABLE();
}
return instructions;
}
ASSERT(flags == kYieldStatementFlagNative); // Must have been desugared.
// Setup yield/continue point:
//
// ...
// :await_jump_var = index;
// :await_ctx_var = :current_context_var
// return <expr>
//
// Continuation<index>:
// Drop(1)
// ...
//
// BuildGraphOfFunction will create a dispatch that jumps to
// Continuation<:await_jump_var> upon entry to the function.
//
const intptr_t new_yield_pos = yield_continuations().length() + 1;
Fragment instructions = IntConstant(new_yield_pos);
instructions +=
StoreLocal(TokenPosition::kNoSource, scopes()->yield_jump_variable);
instructions += Drop();
instructions += LoadLocal(parsed_function()->current_context_var());
instructions +=
StoreLocal(TokenPosition::kNoSource, scopes()->yield_context_variable);
instructions += Drop();
instructions += BuildExpression(); // read expression. instructions += BuildExpression(); // read expression.
instructions += Return(pos, new_yield_pos); if (NeedsDebugStepCheck(parsed_function()->function(), pos)) {
instructions += DebugStepCheck(pos);
// Note: DropTempsInstr serves as an anchor instruction. It will not
// be linked into the resulting graph.
DropTempsInstr* anchor = new (Z) DropTempsInstr(0, nullptr);
yield_continuations().Add(YieldContinuation(anchor, CurrentTryIndex()));
Fragment continuation(instructions.entry, anchor);
RELEASE_ASSERT(parsed_function()->function().IsAsyncClosure() ||
parsed_function()->function().IsAsyncGenClosure() ||
parsed_function()->function().IsSyncGenClosure());
// TODO(43900): Only emit this when needed.
{
// Our sync-yielding functions can be invoked with either a yield result or
// with an non-null exception & stacktrace.
//
// We detect the case we're in based on the nullability of stacktrace in
//
// :sync_op(:iterator, [:exception, :stack_trace]) { }
//
// or:
//
// :async_op(:result_or_exception, :stack_trace) { }
//
const auto& fun = parsed_function()->function();
LocalVariable* exception_var =
parsed_function()->ParameterVariable(fun.IsSyncGenClosure() ? 2 : 1);
LocalVariable* stack_trace_var =
parsed_function()->ParameterVariable(fun.IsSyncGenClosure() ? 3 : 2);
ASSERT(stack_trace_var->name().ptr() ==
Symbols::StackTraceParameter().ptr());
TargetEntryInstr* no_error;
TargetEntryInstr* error;
continuation += LoadLocal(stack_trace_var);
continuation += BranchIfNull(&no_error, &error);
Fragment rethrow(/*instruction=*/error);
rethrow += LoadLocal(exception_var);
rethrow += LoadLocal(stack_trace_var);
rethrow += RethrowException(pos, kInvalidTryIndex);
Drop();
// Set current to the end of the no_error branch.
continuation = Fragment(/*entry=*/continuation.entry, /*current=*/no_error);
} }
return continuation; if (parsed_function()->function().IsCompactAsyncStarFunction()) {
// In the async* functions, 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;
// }
//
auto& add_method = Function::ZoneHandle(Z);
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(TokenPosition::kNoSource, 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->Suspend(pos, SuspendInstr::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->Suspend(pos, SuspendInstr::StubId::kYieldAsyncStar);
instructions += Drop();
}
} else if (parsed_function()->function().IsCompactSyncStarFunction()) {
// In the sync* functions, generate the following code for yield <expr>:
//
// _SyncStarIterator iterator = :suspend_state._functionData;
// iterator._current = <expr>;
// suspend();
//
// Generate the following code for yield* <expr>:
//
// _SyncStarIterator iterator = :suspend_state._functionData;
// iterator._yieldStarIterable = <expr>;
// suspend();
//
auto& field = Field::ZoneHandle(Z);
if (is_yield_star) {
field = IG->object_store()->sync_star_iterator_yield_star_iterable();
} else {
field = IG->object_store()->sync_star_iterator_current();
}
instructions += B->StoreInstanceFieldGuarded(field);
instructions += NullConstant();
instructions += B->Suspend(pos, SuspendInstr::StubId::kYieldSyncStar);
instructions += Drop();
} else {
UNREACHABLE();
}
return instructions;
} }
Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration( Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration(
@ -5667,10 +5587,8 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
function.set_is_visible(true); function.set_is_visible(true);
ASSERT(function.IsCompactSyncStarFunction()); ASSERT(function.IsCompactSyncStarFunction());
} else { } else {
ASSERT((function_node_helper.async_marker_ == ASSERT(function_node_helper.async_marker_ ==
FunctionNodeHelper::kSync) || FunctionNodeHelper::kSync);
(function_node_helper.async_marker_ ==
FunctionNodeHelper::kSyncYielding));
function.set_is_debuggable(function_node_helper.dart_async_marker_ == function.set_is_debuggable(function_node_helper.dart_async_marker_ ==
FunctionNodeHelper::kSync); FunctionNodeHelper::kSync);
switch (function_node_helper.dart_async_marker_) { switch (function_node_helper.dart_async_marker_) {
@ -5687,8 +5605,7 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
// no special modifier // no special modifier
break; break;
} }
function.set_is_generated_body(function_node_helper.async_marker_ == function.set_is_generated_body(false);
FunctionNodeHelper::kSyncYielding);
// sync* functions contain two nested synthetic functions, // sync* functions contain two nested synthetic functions,
// the first of which (sync_op_gen) is a regular sync function so we // the first of which (sync_op_gen) is a regular sync function so we
// need to manually label it generated: // need to manually label it generated:

View file

@ -307,7 +307,6 @@ class FunctionNodeHelper {
kSyncStar = 1, kSyncStar = 1,
kAsync = 2, kAsync = 2,
kAsyncStar = 3, kAsyncStar = 3,
kSyncYielding = 4,
}; };
explicit FunctionNodeHelper(KernelReaderHelper* helper) { explicit FunctionNodeHelper(KernelReaderHelper* helper) {

View file

@ -570,50 +570,6 @@ void ScopeBuilder::VisitFunctionNode() {
first_body_token_position_ = helper_.reader_.min_position(); first_body_token_position_ = helper_.reader_.min_position();
} }
// Ensure that :await_jump_var, :await_ctx_var, :async_op, :is_sync and
// :async_future are captured.
if (function_node_helper.async_marker_ == FunctionNodeHelper::kSyncYielding) {
{
LocalVariable* temp = nullptr;
LookupCapturedVariableByName(
(depth_.function_ == 0) ? &result_->yield_jump_variable : &temp,
Symbols::AwaitJumpVar());
}
{
LocalVariable* temp = nullptr;
LookupCapturedVariableByName(
(depth_.function_ == 0) ? &result_->yield_context_variable : &temp,
Symbols::AwaitContextVar());
}
{
LocalVariable* temp =
scope_->LookupVariable(Symbols::AsyncOperation(), true);
if (temp != nullptr) {
scope_->CaptureVariable(temp);
}
}
{
LocalVariable* temp =
scope_->LookupVariable(Symbols::AsyncFuture(), true);
if (temp != nullptr) {
scope_->CaptureVariable(temp);
}
}
{
LocalVariable* temp = scope_->LookupVariable(Symbols::is_sync(), true);
if (temp != nullptr) {
scope_->CaptureVariable(temp);
}
}
{
LocalVariable* temp =
scope_->LookupVariable(Symbols::ControllerStream(), true);
if (temp != nullptr) {
scope_->CaptureVariable(temp);
}
}
}
// Mark known chained futures such as _Future::timeout()'s _future. // Mark known chained futures such as _Future::timeout()'s _future.
if (function.recognized_kind() == MethodRecognizer::kFutureTimeout && if (function.recognized_kind() == MethodRecognizer::kFutureTimeout &&
depth_.function_ == 1) { depth_.function_ == 1) {
@ -1289,20 +1245,8 @@ void ScopeBuilder::VisitStatement() {
} }
case kYieldStatement: { case kYieldStatement: {
helper_.ReadPosition(); // read position. helper_.ReadPosition(); // read position.
word flags = helper_.ReadByte(); // read flags. helper_.ReadByte(); // read flags.
VisitExpression(); // read expression. VisitExpression(); // read expression.
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; return;
} }
case kVariableDeclaration: case kVariableDeclaration:
@ -1635,13 +1579,6 @@ void ScopeBuilder::AddVariableDeclarationParameter(
variable->set_is_explicit_covariant_parameter(); variable->set_is_explicit_covariant_parameter();
} }
// The :sync_op and :async_op continuations are called multiple times. So we
// don't want the parameters from the first invocation to get stored in the
// context and reused on later invocations with different parameters.
if (current_function_async_marker_ == FunctionNodeHelper::kSyncYielding) {
variable->set_is_forced_stack();
}
const bool needs_covariant_check_in_method = const bool needs_covariant_check_in_method =
helper.IsCovariant() || helper.IsCovariant() ||
(helper.IsGenericCovariantImpl() && (helper.IsGenericCovariantImpl() &&
@ -1730,23 +1667,6 @@ void ScopeBuilder::AddExceptionVariable(
intptr_t nesting_depth) { intptr_t nesting_depth) {
LocalVariable* v = NULL; LocalVariable* v = NULL;
// If we are inside a function with yield points then Kernel transformer
// could have lifted some of the auxiliary exception variables into the
// context to preserve them across yield points because they might
// be needed for rethrow.
// Check if it did and capture such variables instead of introducing
// new local ones.
// Note: function that wrap kSyncYielding function does not contain
// its own try/catches.
if (current_function_async_marker_ == FunctionNodeHelper::kSyncYielding) {
ASSERT(current_function_scope_->parent() != NULL);
v = current_function_scope_->parent()->LocalLookupVariable(
GenerateName(prefix, nesting_depth - 1));
if (v != NULL) {
scope_->CaptureVariable(v);
}
}
// No need to create variables for try/catch-statements inside // No need to create variables for try/catch-statements inside
// nested functions. // nested functions.
if (depth_.function_ > 0) return; if (depth_.function_ > 0) return;

View file

@ -20,8 +20,8 @@ namespace kernel {
static const uint32_t kMagicProgramFile = 0x90ABCDEFu; static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
// Both version numbers are inclusive. // Both version numbers are inclusive.
static const uint32_t kMinSupportedKernelFormatVersion = 82; static const uint32_t kMinSupportedKernelFormatVersion = 83;
static const uint32_t kMaxSupportedKernelFormatVersion = 82; static const uint32_t kMaxSupportedKernelFormatVersion = 83;
// Keep in sync with package:kernel/lib/binary/tag.dart // Keep in sync with package:kernel/lib/binary/tag.dart
#define KERNEL_TAG_LIST(V) \ #define KERNEL_TAG_LIST(V) \
@ -218,7 +218,6 @@ enum InstanceInvocationFlags {
// Keep in sync with package:kernel/lib/ast.dart // Keep in sync with package:kernel/lib/ast.dart
enum YieldStatementFlags { enum YieldStatementFlags {
kYieldStatementFlagYieldStar = 1 << 0, kYieldStatementFlagYieldStar = 1 << 0,
kYieldStatementFlagNative = 1 << 1,
}; };
// Keep in sync with package:kernel/lib/ast.dart // Keep in sync with package:kernel/lib/ast.dart