mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:07:11 +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
16 changed files with 110 additions and 377 deletions
|
@ -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);
|
||||||
|
|
|
@ -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}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}';
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue