mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[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:
parent
3a45cf139b
commit
3a1229e56c
|
@ -434,10 +434,6 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation>
|
|||
case ir.AsyncMarker.AsyncStar:
|
||||
recordReturnType(_types.asyncStarStreamType);
|
||||
break;
|
||||
case ir.AsyncMarker.SyncYielding:
|
||||
failedAt(
|
||||
_analyzedMember, "Unexpected async marker: ${node.asyncMarker}");
|
||||
break;
|
||||
}
|
||||
assert(_breaksFor.isEmpty);
|
||||
assert(_continuesFor.isEmpty);
|
||||
|
|
|
@ -192,10 +192,6 @@ class ImpactBuilder extends StaticTypeVisitor implements ImpactRegistry {
|
|||
}
|
||||
registerAsyncStar(elementType);
|
||||
break;
|
||||
|
||||
case ir.AsyncMarker.SyncYielding:
|
||||
failedAt(CURRENT_ELEMENT_SPANNABLE,
|
||||
"Unexpected async marker: ${asyncMarker}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ AsyncMarker getAsyncMarker(ir.FunctionNode node) {
|
|||
return AsyncMarker.SYNC;
|
||||
case ir.AsyncMarker.SyncStar:
|
||||
return AsyncMarker.SYNC_STAR;
|
||||
case ir.AsyncMarker.SyncYielding:
|
||||
default:
|
||||
throw UnsupportedError(
|
||||
"Async marker ${node.asyncMarker} is not supported.");
|
||||
|
|
|
@ -76,8 +76,7 @@ import '../messages.dart' as messages show getLocationFromUri;
|
|||
import '../modifier.dart'
|
||||
show Modifier, constMask, covariantMask, finalMask, lateMask, requiredMask;
|
||||
import '../names.dart' show emptyName, minusName, plusName;
|
||||
import '../problems.dart'
|
||||
show internalProblem, unexpected, unhandled, unsupported;
|
||||
import '../problems.dart' show internalProblem, unhandled, unsupported;
|
||||
import '../scope.dart';
|
||||
import '../source/diet_parser.dart';
|
||||
import '../source/source_class_builder.dart';
|
||||
|
@ -1415,9 +1414,6 @@ class BodyBuilder extends StackListenerImpl
|
|||
|
||||
case AsyncMarker.Sync:
|
||||
break; // skip
|
||||
case AsyncMarker.SyncYielding:
|
||||
unexpected("async, async*, sync, or sync*", "$asyncModifier",
|
||||
member.charOffset, uri);
|
||||
}
|
||||
|
||||
if (problem != null) {
|
||||
|
|
|
@ -147,7 +147,7 @@ type CanonicalName {
|
|||
|
||||
type ComponentFile {
|
||||
UInt32 magic = 0x90ABCDEF;
|
||||
UInt32 formatVersion = 82;
|
||||
UInt32 formatVersion = 83;
|
||||
Byte[10] shortSdkHash;
|
||||
List<String> problemsAsJson; // Described in problems.md.
|
||||
Library[] libraries;
|
||||
|
@ -510,8 +510,7 @@ enum AsyncMarker {
|
|||
Sync,
|
||||
SyncStar,
|
||||
Async,
|
||||
AsyncStar,
|
||||
SyncYielding
|
||||
AsyncStar
|
||||
}
|
||||
*/
|
||||
|
||||
|
@ -1398,7 +1397,7 @@ type TryFinally extends Statement {
|
|||
type YieldStatement extends Statement {
|
||||
Byte tag = 77;
|
||||
FileOffset fileOffset;
|
||||
Byte flags (isYieldStar, isNative);
|
||||
Byte flags (isYieldStar);
|
||||
Expression expression;
|
||||
}
|
||||
|
||||
|
|
|
@ -3956,43 +3956,6 @@ enum AsyncMarker {
|
|||
SyncStar,
|
||||
Async,
|
||||
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`.
|
||||
///
|
||||
/// For native yield semantics see `AsyncMarker.SyncYielding`.
|
||||
class YieldStatement extends Statement {
|
||||
Expression expression;
|
||||
int flags = 0;
|
||||
|
||||
YieldStatement(this.expression,
|
||||
{bool isYieldStar: false, bool isNative: false}) {
|
||||
YieldStatement(this.expression, {bool isYieldStar: false}) {
|
||||
expression.parent = this;
|
||||
this.isYieldStar = isYieldStar;
|
||||
this.isNative = isNative;
|
||||
}
|
||||
|
||||
static const int FlagYieldStar = 1 << 0;
|
||||
static const int FlagNative = 1 << 1;
|
||||
|
||||
bool get isYieldStar => flags & FlagYieldStar != 0;
|
||||
bool get isNative => flags & FlagNative != 0;
|
||||
|
||||
void set isYieldStar(bool value) {
|
||||
flags = value ? (flags | FlagYieldStar) : (flags & ~FlagYieldStar);
|
||||
}
|
||||
|
||||
void set isNative(bool value) {
|
||||
flags = value ? (flags | FlagNative) : (flags & ~FlagNative);
|
||||
}
|
||||
|
||||
@override
|
||||
R accept<R>(StatementVisitor<R> v) => v.visitYieldStatement(this);
|
||||
|
||||
|
|
|
@ -2895,8 +2895,7 @@ class BinaryBuilder {
|
|||
int offset = readOffset();
|
||||
int flags = readByte();
|
||||
return new YieldStatement(readExpression(),
|
||||
isYieldStar: flags & YieldStatement.FlagYieldStar != 0,
|
||||
isNative: flags & YieldStatement.FlagNative != 0)
|
||||
isYieldStar: flags & YieldStatement.FlagYieldStar != 0)
|
||||
..fileOffset = offset;
|
||||
}
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ class Tag {
|
|||
/// Internal version of kernel binary format.
|
||||
/// Bump it when making incompatible changes in kernel binaries.
|
||||
/// 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 {
|
||||
|
|
|
@ -818,8 +818,6 @@ class Printer extends Visitor<void> with VisitorVoidMixin {
|
|||
return 'async';
|
||||
case AsyncMarker.AsyncStar:
|
||||
return 'async*';
|
||||
case AsyncMarker.SyncYielding:
|
||||
return 'yielding';
|
||||
default:
|
||||
return '<Invalid async marker: $marker>';
|
||||
}
|
||||
|
@ -2414,8 +2412,6 @@ class Printer extends Visitor<void> with VisitorVoidMixin {
|
|||
writeIndentation();
|
||||
if (node.isYieldStar) {
|
||||
writeWord('yield*');
|
||||
} else if (node.isNative) {
|
||||
writeWord('[yield]');
|
||||
} else {
|
||||
writeWord('yield');
|
||||
}
|
||||
|
|
|
@ -363,26 +363,6 @@ class TypeCheckingVisitor
|
|||
case AsyncMarker.AsyncStar:
|
||||
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:
|
||||
throw 'Unexpected async marker: ${function.asyncMarker}';
|
||||
}
|
||||
|
@ -405,9 +385,6 @@ class TypeCheckingVisitor
|
|||
}
|
||||
return const DynamicType();
|
||||
|
||||
case AsyncMarker.SyncYielding:
|
||||
return function.returnType;
|
||||
|
||||
default:
|
||||
throw 'Unexpected async marker: ${function.asyncMarker}';
|
||||
}
|
||||
|
|
|
@ -528,7 +528,6 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
|
|||
switch (currentAsyncMarker) {
|
||||
case AsyncMarker.Sync:
|
||||
case AsyncMarker.Async:
|
||||
case AsyncMarker.SyncYielding:
|
||||
// ok
|
||||
break;
|
||||
case AsyncMarker.SyncStar:
|
||||
|
@ -556,7 +555,6 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
|
|||
break;
|
||||
case AsyncMarker.SyncStar:
|
||||
case AsyncMarker.AsyncStar:
|
||||
case AsyncMarker.SyncYielding:
|
||||
// ok
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -363,17 +363,6 @@ class _VariablesInfoCollector extends RecursiveVisitor {
|
|||
final function = node.function;
|
||||
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;
|
||||
numVariablesAtActiveStatements = savedNumVariablesAtActiveStatements;
|
||||
numVariablesAtFunctionEntry = savedNumVariablesAtFunctionEntry;
|
||||
|
|
|
@ -5303,188 +5303,108 @@ Fragment StreamingFlowGraphBuilder::BuildYieldStatement(
|
|||
|
||||
const uint8_t flags = ReadByte(); // read flags.
|
||||
|
||||
if ((flags & kYieldStatementFlagNative) == 0) {
|
||||
Fragment instructions;
|
||||
const bool is_yield_star = (flags & kYieldStatementFlagYieldStar) != 0;
|
||||
Fragment instructions;
|
||||
const bool is_yield_star = (flags & kYieldStatementFlagYieldStar) != 0;
|
||||
|
||||
// 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());
|
||||
// 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.
|
||||
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 += Return(pos, new_yield_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);
|
||||
if (NeedsDebugStepCheck(parsed_function()->function(), pos)) {
|
||||
instructions += DebugStepCheck(pos);
|
||||
}
|
||||
|
||||
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(
|
||||
|
@ -5667,10 +5587,8 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
|
|||
function.set_is_visible(true);
|
||||
ASSERT(function.IsCompactSyncStarFunction());
|
||||
} else {
|
||||
ASSERT((function_node_helper.async_marker_ ==
|
||||
FunctionNodeHelper::kSync) ||
|
||||
(function_node_helper.async_marker_ ==
|
||||
FunctionNodeHelper::kSyncYielding));
|
||||
ASSERT(function_node_helper.async_marker_ ==
|
||||
FunctionNodeHelper::kSync);
|
||||
function.set_is_debuggable(function_node_helper.dart_async_marker_ ==
|
||||
FunctionNodeHelper::kSync);
|
||||
switch (function_node_helper.dart_async_marker_) {
|
||||
|
@ -5687,8 +5605,7 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
|
|||
// no special modifier
|
||||
break;
|
||||
}
|
||||
function.set_is_generated_body(function_node_helper.async_marker_ ==
|
||||
FunctionNodeHelper::kSyncYielding);
|
||||
function.set_is_generated_body(false);
|
||||
// sync* functions contain two nested synthetic functions,
|
||||
// the first of which (sync_op_gen) is a regular sync function so we
|
||||
// need to manually label it generated:
|
||||
|
|
|
@ -307,7 +307,6 @@ class FunctionNodeHelper {
|
|||
kSyncStar = 1,
|
||||
kAsync = 2,
|
||||
kAsyncStar = 3,
|
||||
kSyncYielding = 4,
|
||||
};
|
||||
|
||||
explicit FunctionNodeHelper(KernelReaderHelper* helper) {
|
||||
|
|
|
@ -570,50 +570,6 @@ void ScopeBuilder::VisitFunctionNode() {
|
|||
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.
|
||||
if (function.recognized_kind() == MethodRecognizer::kFutureTimeout &&
|
||||
depth_.function_ == 1) {
|
||||
|
@ -1289,20 +1245,8 @@ void ScopeBuilder::VisitStatement() {
|
|||
}
|
||||
case kYieldStatement: {
|
||||
helper_.ReadPosition(); // read position.
|
||||
word flags = helper_.ReadByte(); // read flags.
|
||||
helper_.ReadByte(); // read flags.
|
||||
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;
|
||||
}
|
||||
case kVariableDeclaration:
|
||||
|
@ -1635,13 +1579,6 @@ void ScopeBuilder::AddVariableDeclarationParameter(
|
|||
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 =
|
||||
helper.IsCovariant() ||
|
||||
(helper.IsGenericCovariantImpl() &&
|
||||
|
@ -1730,23 +1667,6 @@ void ScopeBuilder::AddExceptionVariable(
|
|||
intptr_t nesting_depth) {
|
||||
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
|
||||
// nested functions.
|
||||
if (depth_.function_ > 0) return;
|
||||
|
|
|
@ -20,8 +20,8 @@ namespace kernel {
|
|||
static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
|
||||
|
||||
// Both version numbers are inclusive.
|
||||
static const uint32_t kMinSupportedKernelFormatVersion = 82;
|
||||
static const uint32_t kMaxSupportedKernelFormatVersion = 82;
|
||||
static const uint32_t kMinSupportedKernelFormatVersion = 83;
|
||||
static const uint32_t kMaxSupportedKernelFormatVersion = 83;
|
||||
|
||||
// Keep in sync with package:kernel/lib/binary/tag.dart
|
||||
#define KERNEL_TAG_LIST(V) \
|
||||
|
@ -218,7 +218,6 @@ enum InstanceInvocationFlags {
|
|||
// 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
|
||||
|
|
Loading…
Reference in a new issue