[vm] New implementation of sync* based on suspend/resume stubs

Issue: https://github.com/dart-lang/sdk/issues/48378
Change-Id: I7f4b6b56d914a617dfd7ac724cd4414532073b4c
TEST=ci
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/249141
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2022-06-27 18:19:12 +00:00 committed by Commit Bot
parent ee86c92975
commit 77ea9820aa
53 changed files with 3604 additions and 3163 deletions

View file

@ -10,18 +10,7 @@ extension Extension on core::int {
method asyncStarMethod = self::Extension|asyncStarMethod;
tearoff asyncStarMethod = self::Extension|get#asyncStarMethod;
}
static method Extension|syncStarMethod(lowered final core::int #this) → dynamic /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
static method Extension|syncStarMethod(lowered final core::int #this) → dynamic sync* {}
static method Extension|get#syncStarMethod(lowered final core::int #this) → () → dynamic
return () → dynamic => self::Extension|syncStarMethod(#this);
static method Extension|asyncMethod(lowered final core::int #this) → dynamic async /* futureValueType= dynamic */ {}

View file

@ -12,47 +12,13 @@ static method asyncString() → asy::Future<core::String> async /* futureValueTy
static method asyncString2() → asy::Future<core::String> async /* futureValueType= core::String */ {
return self::asyncString();
}
static method syncStarString() → core::Iterable<core::String> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = "foo";
[yield] true;
}
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::syncStarString2();
[yield] true;
}
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::stringList;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::String>(:sync_op_gen);
static method syncStarString() → core::Iterable<core::String> sync* {
yield "foo";
yield* self::syncStarString2();
yield* self::stringList;
}
static method syncStarString2() → core::Iterable<core::String> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = "foo";
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::String>(:sync_op_gen);
static method syncStarString2() → core::Iterable<core::String> sync* {
yield "foo";
}
static method asyncStarString() → asy::Stream<core::String> async* {
yield "foo";

View file

@ -2,40 +2,12 @@ library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
static method getElements() → core::Iterable<core::int> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
core::Iterable<core::int> elements;
elements = (() → core::Iterable<core::int> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = 7;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::int>(:sync_op_gen);
})(){() → core::Iterable<core::int>};
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = elements;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::int>(:sync_op_gen);
static method getElements() → core::Iterable<core::int> sync* {
core::Iterable<core::int> elements;
elements = (() → core::Iterable<core::int> sync* {
yield 7;
})(){() → core::Iterable<core::int>};
yield* elements;
}
static method main() → dynamic
return core::print(self::getElements());

View file

@ -3,22 +3,8 @@ import self as self;
import "dart:core" as core;
static method main() → dynamic {
() →* core::Iterable<Null>* f = () → core::Iterable<Null>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = null;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<Null>(:sync_op_gen);
() →* core::Iterable<Null>* f = () → core::Iterable<Null>* sync* {
yield null;
};
core::Iterable<dynamic>* y = f(){() →* core::Iterable<Null>*};
core::Iterable<core::String*>* z = f(){() →* core::Iterable<Null>*};

View file

@ -3,26 +3,9 @@ import self as self;
import "dart:core" as core;
static method test() → dynamic {
() →* core::Iterable<core::num*>* f = () → core::Iterable<core::num*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = 1;
[yield] true;
}
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = core::_GrowableList::_literal2<core::num*>(3, 4.0);
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::num*>(:sync_op_gen);
() →* core::Iterable<core::num*>* f = () → core::Iterable<core::num*>* sync* {
yield 1;
yield* core::_GrowableList::_literal2<core::num*>(3, 4.0);
};
core::Iterable<core::num*>* g = f(){() →* core::Iterable<core::num*>*};
core::Iterable<core::int*>* h = f(){() →* core::Iterable<core::num*>*} as{TypeError} core::Iterable<core::int*>*;

View file

@ -97,42 +97,19 @@ static method foo() → asy::Stream<core::List<core::int*>*>* async* {
^" in core::_GrowableList::•<dynamic>(0) as{TypeError} asy::Stream<core::List<core::int*>*>*;
yield* self::MyStream::•<core::List<core::int*>*>();
}
static method bar() → core::Iterable<core::Map<core::int*, core::int*>*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = core::Map::•<core::int*, core::int*>();
[yield] true;
}
{
:iterator.{core::_SyncIterator::_current} = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:23:63: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Map<int, int>'.
static method bar() → core::Iterable<core::Map<core::int*, core::int*>*>* sync* {
yield core::Map::•<core::int*, core::int*>();
yield invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:23:63: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Map<int, int>'.
- 'List' is from 'dart:core'.
- 'Map' is from 'dart:core'.
yield /*error:YIELD_OF_INVALID_TYPE*/ /*@typeArgs=dynamic*/ [];
^" in core::_GrowableList::•<dynamic>(0) as{TypeError} core::Map<core::int*, core::int*>*;
[yield] true;
}
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:24:79: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'Iterable<Map<int, int>>'.
yield* invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:24:79: Error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'Iterable<Map<int, int>>'.
- 'Map' is from 'dart:core'.
- 'Iterable' is from 'dart:core'.
yield* /*error:YIELD_OF_INVALID_TYPE*/ new /*@ typeArgs=dynamic, dynamic */ Map();
^" in core::Map::•<dynamic, dynamic>() as{TypeError} core::Iterable<core::Map<core::int*, core::int*>*>*;
[yield] true;
}
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = core::_GrowableList::•<core::Map<core::int*, core::int*>*>(0);
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::Map<core::int*, core::int*>*>(:sync_op_gen);
yield* core::_GrowableList::•<core::Map<core::int*, core::int*>*>(0);
}
static method main() → dynamic {}

View file

@ -14,22 +14,8 @@ static method test() → dynamic {
function f3() → asy::Future<core::int*>* async /* futureValueType= core::int* */ {
return 42;
}
function f4() → core::Iterable<core::int*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = 42;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::int*>(:sync_op_gen);
function f4() → core::Iterable<core::int*>* sync* {
yield 42;
}
function f5() → asy::Stream<core::int*>* async* {
yield 42;

View file

@ -24,39 +24,11 @@ static method main() → dynamic {
return /*@ returnType=dynamic */ (/*@ type=dynamic */ x) => x;
^" in ((dynamic x) → dynamic => x) as{TypeError} FutureOr<(core::int*) →* core::int*>*;
}
function c() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = (core::int* x) → core::int* => x;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<(core::int*) →* core::int*>(:sync_op_gen);
function c() → core::Iterable<(core::int*) →* core::int*>* sync* {
yield(core::int* x) → core::int* => x;
}
function d() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = core::_GrowableList::_literal1<(core::int*) →* core::int*>((core::int* x) → core::int* => x);
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<(core::int*) →* core::int*>(:sync_op_gen);
function d() → core::Iterable<(core::int*) →* core::int*>* sync* {
yield* core::_GrowableList::_literal1<(core::int*) →* core::int*>((core::int* x) → core::int* => x);
}
function e() → asy::Stream<(core::int*) →* core::int*>* async* {
yield(core::int* x) → core::int* => x;

View file

@ -23,39 +23,11 @@ static method b() → asy::Future<(core::int*) →* core::int*>* async /* future
return /*@ returnType=dynamic */ (/*@ type=dynamic */ x) => x;
^" in ((dynamic x) → dynamic => x) as{TypeError} FutureOr<(core::int*) →* core::int*>*;
}
static method c() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = (core::int* x) → core::int* => x;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<(core::int*) →* core::int*>(:sync_op_gen);
static method c() → core::Iterable<(core::int*) →* core::int*>* sync* {
yield(core::int* x) → core::int* => x;
}
static method d() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = core::_GrowableList::_literal1<(core::int*) →* core::int*>((core::int* x) → core::int* => x);
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<(core::int*) →* core::int*>(:sync_op_gen);
static method d() → core::Iterable<(core::int*) →* core::int*>* sync* {
yield* core::_GrowableList::_literal1<(core::int*) →* core::int*>((core::int* x) → core::int* => x);
}
static method e() → asy::Stream<(core::int*) →* core::int*>* async* {
yield(core::int* x) → core::int* => x;

View file

@ -42,80 +42,24 @@ import "dart:core" as core;
static method getNull() → dynamic
return null;
static method getIterableNull() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = null;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
static method getIterableNull() → core::Iterable<dynamic> sync* {
yield null;
}
static method getIterableBool() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = true;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
static method getIterableBool() → core::Iterable<core::bool> sync* {
yield true;
}
static method test1() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
static method test1() → core::Iterable<core::bool> sync* {
yield self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
}
static method test2() → core::Iterable<core::bool>
return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::Iterable<core::bool>;
static method test3() → core::bool
return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
static method test4() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:21:10: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
static method test4() → core::Iterable<core::bool> sync* {
yield* invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:21:10: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
- 'Iterable' is from 'dart:core'.
yield* getIterableNull(); // error
^" in self::getIterableNull() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
static method test5() → core::Iterable<core::bool>
return invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:24:27: Error: A value of type 'Iterable<dynamic>' can't be returned from a function with return type 'Iterable<bool>'.
@ -124,64 +68,22 @@ Iterable<bool> test5() => getIterableNull(); // error
^" in self::getIterableNull() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
static method test6() → core::Iterable<core::bool>
return self::getIterableBool();
static method test7() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool();
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
static method test7() → core::Iterable<core::bool> sync* {
yield* self::getIterableBool();
}
static method test() → dynamic async /* futureValueType= dynamic */ {
function test1() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
function test1() → core::Iterable<core::bool> sync* {
yield self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
}
function test2() → core::Iterable<core::bool>
return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::Iterable<core::bool>;
function test3() → core::bool
return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
function test4() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:38:12: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
function test4() → core::Iterable<core::bool> sync* {
yield* invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:38:12: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
- 'Iterable' is from 'dart:core'.
yield* getIterableNull(); // error
^" in self::getIterableNull() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
function test5() → core::Iterable<core::bool>
return invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:41:29: Error: A value of type 'Iterable<dynamic>' can't be returned from a function with return type 'Iterable<bool>'.
@ -190,86 +92,30 @@ static method test() → dynamic async /* futureValueType= dynamic */ {
^" in self::getIterableNull() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
function test6() → core::Iterable<core::bool>
return self::getIterableBool();
function test7() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool();
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
function test7() → core::Iterable<core::bool> sync* {
yield* self::getIterableBool();
}
core::Iterable<core::bool> var1 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:49:5: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
- 'Iterable' is from 'dart:core'.
})(); // error
^" in (() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = self::getNull();
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
^" in (() → core::Iterable<dynamic> sync* {
yield self::getNull();
})(){() → core::Iterable<dynamic>} as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
core::Iterable<core::bool> var2 = (() → dynamic => self::getNull())(){() → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::Iterable<core::bool>;
core::bool var3 = (() → dynamic => self::getNull())(){() → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
core::Iterable<core::bool> var4 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:54:5: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
- 'Iterable' is from 'dart:core'.
})(); // error
^" in (() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableNull();
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
^" in (() → core::Iterable<dynamic> sync* {
yield* self::getIterableNull();
})(){() → core::Iterable<dynamic>} as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
core::Iterable<core::bool> var5 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:55:50: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
- 'Iterable' is from 'dart:core'.
Iterable<bool> var5 = (() => getIterableNull())(); // error
^" in (() → core::Iterable<dynamic> => self::getIterableNull())(){() → core::Iterable<dynamic>} as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
core::Iterable<core::bool> var6 = (() → core::Iterable<core::bool> => self::getIterableBool())(){() → core::Iterable<core::bool>};
core::Iterable<core::bool> var7 = (() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool();
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
core::Iterable<core::bool> var7 = (() → core::Iterable<core::bool> sync* {
yield* self::getIterableBool();
})(){() → core::Iterable<core::bool>};
}
static method main() → dynamic {}

View file

@ -42,80 +42,24 @@ import "dart:core" as core;
static method getNull() → dynamic
return null;
static method getIterableNull() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = null;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
static method getIterableNull() → core::Iterable<dynamic> sync* {
yield null;
}
static method getIterableBool() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = true;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
static method getIterableBool() → core::Iterable<core::bool> sync* {
yield true;
}
static method test1() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
static method test1() → core::Iterable<core::bool> sync* {
yield self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
}
static method test2() → core::Iterable<core::bool>
return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::Iterable<core::bool>;
static method test3() → core::bool
return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
static method test4() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:21:10: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
static method test4() → core::Iterable<core::bool> sync* {
yield* invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:21:10: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
- 'Iterable' is from 'dart:core'.
yield* getIterableNull(); // error
^" in self::getIterableNull() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
static method test5() → core::Iterable<core::bool>
return invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:24:27: Error: A value of type 'Iterable<dynamic>' can't be returned from a function with return type 'Iterable<bool>'.
@ -124,64 +68,22 @@ Iterable<bool> test5() => getIterableNull(); // error
^" in self::getIterableNull() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
static method test6() → core::Iterable<core::bool>
return self::getIterableBool();
static method test7() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool();
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
static method test7() → core::Iterable<core::bool> sync* {
yield* self::getIterableBool();
}
static method test() → dynamic async /* futureValueType= dynamic */ {
function test1() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
function test1() → core::Iterable<core::bool> sync* {
yield self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
}
function test2() → core::Iterable<core::bool>
return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::Iterable<core::bool>;
function test3() → core::bool
return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
function test4() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:38:12: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
function test4() → core::Iterable<core::bool> sync* {
yield* invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:38:12: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
- 'Iterable' is from 'dart:core'.
yield* getIterableNull(); // error
^" in self::getIterableNull() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
function test5() → core::Iterable<core::bool>
return invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:41:29: Error: A value of type 'Iterable<dynamic>' can't be returned from a function with return type 'Iterable<bool>'.
@ -190,86 +92,30 @@ static method test() → dynamic async /* futureValueType= dynamic */ {
^" in self::getIterableNull() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
function test6() → core::Iterable<core::bool>
return self::getIterableBool();
function test7() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool();
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
function test7() → core::Iterable<core::bool> sync* {
yield* self::getIterableBool();
}
core::Iterable<core::bool> var1 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:49:5: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
- 'Iterable' is from 'dart:core'.
})(); // error
^" in (() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = self::getNull();
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
^" in (() → core::Iterable<dynamic> sync* {
yield self::getNull();
})(){() → core::Iterable<dynamic>} as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
core::Iterable<core::bool> var2 = (() → dynamic => self::getNull())(){() → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::Iterable<core::bool>;
core::bool var3 = (() → dynamic => self::getNull())(){() → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
core::Iterable<core::bool> var4 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:54:5: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
- 'Iterable' is from 'dart:core'.
})(); // error
^" in (() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableNull();
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
^" in (() → core::Iterable<dynamic> sync* {
yield* self::getIterableNull();
})(){() → core::Iterable<dynamic>} as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
core::Iterable<core::bool> var5 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:55:50: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
- 'Iterable' is from 'dart:core'.
Iterable<bool> var5 = (() => getIterableNull())(); // error
^" in (() → core::Iterable<dynamic> => self::getIterableNull())(){() → core::Iterable<dynamic>} as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
core::Iterable<core::bool> var6 = (() → core::Iterable<core::bool> => self::getIterableBool())(){() → core::Iterable<core::bool>};
core::Iterable<core::bool> var7 = (() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool();
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
core::Iterable<core::bool> var7 = (() → core::Iterable<core::bool> sync* {
yield* self::getIterableBool();
})(){() → core::Iterable<core::bool>};
}
static method main() → dynamic {}

View file

@ -104,18 +104,7 @@ static method returnAsync6() → asy::Future<core::int?> async /* futureValueTyp
return null;
}
static method returnAsync7() → asy::Future<core::int?> async /* futureValueType= core::int? */ {}
static method yieldSync() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
static method yieldSync() → core::Iterable<dynamic> sync* {}
static method yieldAsync() → asy::Stream<dynamic> async* {}
static method caseReturn1(self::Enum e) → self::Enum {
switch(e) /*isExplicitlyExhaustive*/ {
@ -184,18 +173,7 @@ static method localFunctions() → dynamic {
return null;
}
function returnAsync7() → asy::Future<core::int?> async /* futureValueType= core::int? */ {}
function yieldSync() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
function yieldSync() → core::Iterable<dynamic> sync* {}
function yieldAsync() → asy::Stream<dynamic> async* {}
function caseReturn1(self::Enum e) → self::Enum {
switch(e) /*isExplicitlyExhaustive*/ {

View file

@ -105,18 +105,7 @@ static method returnAsync6() → asy::Future<core::int?> async /* futureValueTyp
return null;
}
static method returnAsync7() → asy::Future<core::int?> async /* futureValueType= core::int? */ {}
static method yieldSync() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
static method yieldSync() → core::Iterable<dynamic> sync* {}
static method yieldAsync() → asy::Stream<dynamic> async* {}
static method caseReturn1(self::Enum e) → self::Enum {
switch(e) /*isExplicitlyExhaustive*/ {
@ -188,18 +177,7 @@ static method localFunctions() → dynamic {
return null;
}
function returnAsync7() → asy::Future<core::int?> async /* futureValueType= core::int? */ {}
function yieldSync() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
function yieldSync() → core::Iterable<dynamic> sync* {}
function yieldAsync() → asy::Stream<dynamic> async* {}
function caseReturn1(self::Enum e) → self::Enum {
switch(e) /*isExplicitlyExhaustive*/ {

View file

@ -21,48 +21,16 @@ library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
static method f() → dynamic /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
invalid-expression "pkg/front_end/testcases/regress/issue_29983.dart:7:3: Error: 'sync*' and 'async*' can't return a value.
static method f() → dynamic sync* {
invalid-expression "pkg/front_end/testcases/regress/issue_29983.dart:7:3: Error: 'sync*' and 'async*' can't return a value.
return missing;
^";
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
static method g() → dynamic /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
invalid-expression "pkg/front_end/testcases/regress/issue_29983.dart:11:14: Error: 'sync*' and 'async*' can't return a value.
static method g() → dynamic sync*
invalid-expression "pkg/front_end/testcases/regress/issue_29983.dart:11:14: Error: 'sync*' and 'async*' can't return a value.
g() sync* => dummy;
^";
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
static method h() → dynamic /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
(() → core::String => "return")(){() → core::String};
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
static method h() → dynamic sync* {
(() → core::String => "return")(){() → core::String};
}
static method main() → dynamic {}

View file

@ -40,22 +40,8 @@ static method main() → dynamic async /* futureValueType= dynamic */ {
if(!(:for-iterator.{asy::_StreamIterator::_subscription}{asy::StreamSubscription<dynamic>?} == null))
await :for-iterator.{asy::_StreamIterator::cancel}(){() → asy::Future<dynamic>};
}
function f_sync_star() → core::int /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = 42;
[yield] true;
}
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
function f_sync_star() → core::int sync* {
yield 42;
}
{
core::Iterator<dynamic> :sync-for-iterator = ((f_sync_star(){() → core::int} as{ForNonNullableByDefault} dynamic) as{TypeError,ForDynamic,ForNonNullableByDefault} core::Iterable<dynamic>).{core::Iterable::iterator}{core::Iterator<dynamic>};

View file

@ -553,6 +553,7 @@ abstract class Target {
Class? concreteStringLiteralClass(CoreTypes coreTypes, String value) => null;
Class? concreteAsyncResultClass(CoreTypes coreTypes) => null;
Class? concreteSyncStarResultClass(CoreTypes coreTypes) => null;
ConstantsBackend get constantsBackend;

View file

@ -41,6 +41,7 @@ class VmTarget extends Target {
Class? _twoByteString;
Class? _smi;
Class? _double; // _Double, not double.
Class? _syncStarIterable;
VmTarget(this.flags);
@ -208,7 +209,7 @@ class VmTarget extends Target {
bool productMode = environmentDefines!["dart.vm.product"] == "true";
transformAsync.transformProcedure(
new TypeEnvironment(coreTypes, hierarchy), procedure,
productMode: productMode, desugarAsync: flags.supportMirrors);
productMode: productMode, desugarAsync: !flags.compactAsync);
logger?.call("Transformed async functions");
lowering.transformProcedure(
@ -500,6 +501,12 @@ class VmTarget extends Target {
Class? concreteAsyncResultClass(CoreTypes coreTypes) =>
coreTypes.futureImplClass;
@override
Class? concreteSyncStarResultClass(CoreTypes coreTypes) {
return _syncStarIterable ??=
coreTypes.index.getClass('dart:async', '_SyncStarIterable');
}
@override
ConstantsBackend get constantsBackend => const ConstantsBackend();

View file

@ -143,9 +143,15 @@ class RecursiveContinuationRewriter extends RemovingTransformer {
helper, staticTypeContext, desugarAsync));
return node;
case AsyncMarker.SyncStar:
return new SyncStarFunctionRewriter(
helper, node, staticTypeContext, desugarAsync)
.rewrite();
if (desugarAsync) {
return new SyncStarFunctionRewriter(
helper, node, staticTypeContext, desugarAsync)
.rewrite();
} else {
node.transformOrRemoveChildren(new RecursiveContinuationRewriter(
helper, staticTypeContext, desugarAsync));
return node;
}
case AsyncMarker.Async:
if (desugarAsync) {
return new AsyncFunctionRewriter(

View file

@ -788,10 +788,19 @@ class SummaryCollector extends RecursiveResultVisitor<TypeExpr?> {
: _typesBuilder.fromStaticType(function.returnType, false);
break;
case AsyncMarker.AsyncStar:
case AsyncMarker.SyncStar:
_summary.result =
_typesBuilder.fromStaticType(function.returnType, false);
break;
case AsyncMarker.SyncStar:
final Class? concreteClass =
target.concreteSyncStarResultClass(_environment.coreTypes);
_summary.result = (concreteClass != null)
? _entryPointsListener
.addAllocatedClass(concreteClass)
.cls
.concreteType
: _typesBuilder.fromStaticType(function.returnType, false);
break;
default:
_summary.result = _returnValue!;
}

View file

@ -13,48 +13,27 @@ class MyFinalizable extends core::Object implements ffi::Finalizable {
}
static method doSomething() → core::int
return 3;
static method useFinalizableSyncStar(ffi::Finalizable finalizable) → core::Iterable<core::int> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
ffi::Finalizable finalizable = finalizable;
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
[@vm.call-site-attributes.metadata=receiverType:dart.core::_SyncIterator<dynamic>?] :iterator.{core::_SyncIterator::_current} = block {
final core::int :expressionValueWrappedFinalizable = self::doSomething();
_in::reachabilityFence(finalizable);
} =>:expressionValueWrappedFinalizable;
[yield] true;
}
final self::MyFinalizable finalizable2 = new self::MyFinalizable::•();
{
[@vm.call-site-attributes.metadata=receiverType:dart.core::_SyncIterator<dynamic>?] :iterator.{core::_SyncIterator::_current} = block {
final core::int :expressionValueWrappedFinalizable = 5;
_in::reachabilityFence(finalizable);
_in::reachabilityFence(finalizable2);
} =>:expressionValueWrappedFinalizable;
[yield] true;
}
final self::MyFinalizable finalizable3 = new self::MyFinalizable::•();
{
[@vm.call-site-attributes.metadata=receiverType:dart.core::_SyncIterator<dynamic>?] :iterator.{core::_SyncIterator::_current} = block {
final core::int :expressionValueWrappedFinalizable = 10;
_in::reachabilityFence(finalizable);
_in::reachabilityFence(finalizable2);
_in::reachabilityFence(finalizable3);
} =>:expressionValueWrappedFinalizable;
[yield] true;
}
_in::reachabilityFence(finalizable2);
_in::reachabilityFence(finalizable3);
_in::reachabilityFence(finalizable);
}
return false;
}
return :sync_op;
}
return new core::_SyncIterable::•<core::int>(:sync_op_gen);
static method useFinalizableSyncStar(ffi::Finalizable finalizable) → core::Iterable<core::int> sync* {
yield block {
final core::int :expressionValueWrappedFinalizable = self::doSomething();
_in::reachabilityFence(finalizable);
} =>:expressionValueWrappedFinalizable;
final self::MyFinalizable finalizable2 = new self::MyFinalizable::•();
yield block {
final core::int :expressionValueWrappedFinalizable = 5;
_in::reachabilityFence(finalizable);
_in::reachabilityFence(finalizable2);
} =>:expressionValueWrappedFinalizable;
final self::MyFinalizable finalizable3 = new self::MyFinalizable::•();
yield block {
final core::int :expressionValueWrappedFinalizable = 10;
_in::reachabilityFence(finalizable);
_in::reachabilityFence(finalizable2);
_in::reachabilityFence(finalizable3);
} =>:expressionValueWrappedFinalizable;
_in::reachabilityFence(finalizable2);
_in::reachabilityFence(finalizable3);
_in::reachabilityFence(finalizable);
}
static method main() → void {
final self::MyFinalizable finalizable = new self::MyFinalizable::•();

View file

@ -36,7 +36,6 @@ List<String> expected = [
"$file:${LINE + 2}:5", // on 'print'
"$file:${LINE + 1}:25", // on 'generator' (in 'for' line)
"$file:${LINE + 6}:10", // after 'generator' (definition line)
"$file:${LINE + 10}:11", // on '+' in 'x + y'
"$file:${LINE + 10}:3", // on yield
@ -45,7 +44,6 @@ List<String> expected = [
"$file:${LINE + 2}:5", // on 'print'
"$file:${LINE + 1}:25", // on 'generator' (in 'for' line)
"$file:${LINE + 6}:10", // after 'generator' (definition line)
"$file:${LINE + 11}:1", // on ending '}' of 'generator'
"$file:${LINE + 4}:1", // on ending '}' of 'code''

View file

@ -37,7 +37,6 @@ List<String> expected = [
"$file:${LINE + 2}:5", // on 'print'
"$file:${LINE + 1}:25", // on 'generator' (in 'for' line)
"$file:${LINE + 6}:10", // after 'generator' (definition line)
"$file:${LINE + 10}:13", // on '+' in 'z = x + y'
"$file:${LINE + 11}:3", // on yield
@ -46,7 +45,6 @@ List<String> expected = [
"$file:${LINE + 2}:5", // on 'print'
"$file:${LINE + 1}:25", // on 'generator' (in 'for' line)
"$file:${LINE + 6}:10", // after 'generator' (definition line)
"$file:${LINE + 12}:1", // on ending '}' of 'generator'
"$file:${LINE + 4}:1", // on ending '}' of 'code''

View file

@ -36,7 +36,6 @@ List<String> expected = [
"$file:${LINE + 2}:5", // on 'print'
"$file:${LINE + 1}:25", // on 'generator' (in 'for' line)
"$file:${LINE + 6}:10", // after 'generator' (definition line)
"$file:${LINE + 10}:11", // on '+' in 'x + y'
"$file:${LINE + 10}:3", // on yield
@ -45,7 +44,6 @@ List<String> expected = [
"$file:${LINE + 2}:5", // on 'print'
"$file:${LINE + 1}:25", // on 'generator' (in 'for' line)
"$file:${LINE + 6}:10", // after 'generator' (definition line)
"$file:${LINE + 11}:1", // on ending '}' of 'generator'
"$file:${LINE + 4}:1", // on ending '}' of 'code''

View file

@ -37,7 +37,6 @@ List<String> expected = [
"$file:${LINE + 2}:5", // on 'print'
"$file:${LINE + 1}:25", // on 'generator' (in 'for' line)
"$file:${LINE + 6}:10", // after 'generator' (definition line)
"$file:${LINE + 10}:13", // on '+' in 'z = x + y'
"$file:${LINE + 11}:3", // on yield
@ -46,7 +45,6 @@ List<String> expected = [
"$file:${LINE + 2}:5", // on 'print'
"$file:${LINE + 1}:25", // on 'generator' (in 'for' line)
"$file:${LINE + 6}:10", // after 'generator' (definition line)
"$file:${LINE + 12}:1", // on ending '}' of 'generator'
"$file:${LINE + 4}:1", // on ending '}' of 'code''

View file

@ -2715,11 +2715,21 @@ void Assembler::CopyMemoryWords(Register src,
Register dst,
Register size,
Register temp) {
RELEASE_ASSERT(src == ESI);
RELEASE_ASSERT(dst == EDI);
RELEASE_ASSERT(size == ECX);
shrl(size, Immediate(target::kWordSizeLog2));
rep_movsd();
// This loop is equivalent to
// shrl(size, Immediate(target::kWordSizeLog2));
// rep_movsd();
// but shows better performance on certain micro-benchmarks.
Label loop, done;
cmpl(size, Immediate(0));
j(EQUAL, &done, kNearJump);
Bind(&loop);
movl(temp, Address(src, 0));
addl(src, Immediate(target::kWordSize));
movl(Address(dst, 0), temp);
addl(dst, Immediate(target::kWordSize));
subl(size, Immediate(target::kWordSize));
j(NOT_ZERO, &loop, kNearJump);
Bind(&done);
}
void Assembler::PushCodeObject() {

View file

@ -2306,11 +2306,21 @@ void Assembler::CopyMemoryWords(Register src,
Register dst,
Register size,
Register temp) {
RELEASE_ASSERT(src == RSI);
RELEASE_ASSERT(dst == RDI);
RELEASE_ASSERT(size == RCX);
shrq(size, Immediate(target::kWordSizeLog2));
rep_movsq();
// This loop is equivalent to
// shrq(size, Immediate(target::kWordSizeLog2));
// rep_movsq()
// but shows better performance on certain micro-benchmarks.
Label loop, done;
cmpq(size, Immediate(0));
j(EQUAL, &done, kNearJump);
Bind(&loop);
movq(temp, Address(src, 0));
addq(src, Immediate(target::kWordSize));
movq(Address(dst, 0), temp);
addq(dst, Immediate(target::kWordSize));
subq(size, Immediate(target::kWordSize));
j(NOT_ZERO, &loop, kNearJump);
Bind(&done);
}
void Assembler::GenerateUnRelocatedPcRelativeCall(intptr_t offset_into_target) {

View file

@ -6850,6 +6850,10 @@ const Code& ReturnInstr::GetReturnStub(FlowGraphCompiler* compiler) const {
return Code::ZoneHandle(
compiler->zone(),
compiler->isolate_group()->object_store()->return_async_star_stub());
} else if (function.IsCompactSyncStarFunction()) {
return Code::ZoneHandle(
compiler->zone(),
compiler->isolate_group()->object_store()->return_sync_star_stub());
} else {
UNREACHABLE();
}
@ -7293,8 +7297,13 @@ LocationSummary* Call1ArgStubInstr::MakeLocationSummary(Zone* zone,
LocationSummary* locs = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
switch (stub_id_) {
case StubId::kCloneSuspendState:
locs->set_in(
0, Location::RegisterLocation(CloneSuspendStateStubABI::kSourceReg));
break;
case StubId::kInitAsync:
case StubId::kInitAsyncStar:
case StubId::kInitSyncStar:
locs->set_in(0, Location::RegisterLocation(
InitSuspendableFunctionStubABI::kTypeArgsReg));
break;
@ -7307,12 +7316,18 @@ void Call1ArgStubInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ObjectStore* object_store = compiler->isolate_group()->object_store();
Code& stub = Code::ZoneHandle(compiler->zone());
switch (stub_id_) {
case StubId::kCloneSuspendState:
stub = object_store->clone_suspend_state_stub();
break;
case StubId::kInitAsync:
stub = object_store->init_async_stub();
break;
case StubId::kInitAsyncStar:
stub = object_store->init_async_star_stub();
break;
case StubId::kInitSyncStar:
stub = object_store->init_sync_star_stub();
break;
}
compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
locs(), deopt_id(), env());
@ -7341,6 +7356,9 @@ void SuspendInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
case StubId::kYieldAsyncStar:
stub = object_store->yield_async_star_stub();
break;
case StubId::kYieldSyncStar:
stub = object_store->yield_sync_star_stub();
break;
}
compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
locs(), deopt_id(), env());

View file

@ -9583,8 +9583,10 @@ class SimdOpInstr : public Definition {
class Call1ArgStubInstr : public TemplateDefinition<1, Throws> {
public:
enum class StubId {
kCloneSuspendState,
kInitAsync,
kInitAsyncStar,
kInitSyncStar,
};
Call1ArgStubInstr(const InstructionSource& source,
@ -9624,6 +9626,7 @@ class SuspendInstr : public TemplateDefinition<1, Throws> {
enum class StubId {
kAwait,
kYieldAsyncStar,
kYieldSyncStar,
};
SuspendInstr(const InstructionSource& source,

View file

@ -1367,12 +1367,18 @@ void TailCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
void Call1ArgStubInstr::PrintOperandsTo(BaseTextBuffer* f) const {
const char* name = "";
switch (stub_id_) {
case StubId::kCloneSuspendState:
name = "CloneSuspendState";
break;
case StubId::kInitAsync:
name = "InitAsync";
break;
case StubId::kInitAsyncStar:
name = "InitAsyncStar";
break;
case StubId::kInitSyncStar:
name = "InitSyncStar";
break;
}
f->Printf("%s(", name);
operand()->PrintTo(f);
@ -1388,6 +1394,9 @@ void SuspendInstr::PrintOperandsTo(BaseTextBuffer* f) const {
case StubId::kYieldAsyncStar:
name = "YieldAsyncStar";
break;
case StubId::kYieldSyncStar:
name = "YieldSyncStar";
break;
}
f->Printf("%s(", name);
operand()->PrintTo(f);

View file

@ -702,6 +702,30 @@ Fragment StreamingFlowGraphBuilder::InitSuspendableFunction(
body += B->Suspend(TokenPosition::kNoSource,
SuspendInstr::StubId::kYieldAsyncStar);
body += Drop();
} else if (dart_function.IsCompactSyncStarFunction()) {
const auto& result_type =
AbstractType::Handle(Z, dart_function.result_type());
auto& type_args = TypeArguments::ZoneHandle(Z);
if (result_type.IsType() &&
(result_type.type_class() == IG->object_store()->iterable_class())) {
ASSERT(result_type.IsFinalized());
type_args = result_type.arguments();
}
body += TranslateInstantiatedTypeArguments(type_args);
body += B->Call1ArgStub(TokenPosition::kNoSource,
Call1ArgStubInstr::StubId::kInitSyncStar);
body += Drop();
body += NullConstant();
body += B->Suspend(TokenPosition::kNoSource,
SuspendInstr::StubId::kYieldSyncStar);
body += Drop();
// Clone context if there are any captured parameter variables, so
// each invocation of .iterator would get its own copy of parameters.
const LocalScope* scope = parsed_function()->scope();
if (scope->num_context_variables() > 0) {
body += CloneContext(scope->context_slots());
}
}
return body;
}
@ -5279,22 +5303,7 @@ Fragment StreamingFlowGraphBuilder::BuildYieldStatement(
if ((flags & kYieldStatementFlagNative) == 0) {
Fragment instructions;
// Generate the following code for yield <expr>:
//
// _AsyncStarStreamController controller = :suspend_state._functionData;
// if (controller.add(<expr>)) {
// return;
// }
// suspend();
//
// Generate the following code for yield* <expr>:
//
// _AsyncStarStreamController controller = :suspend_state._functionData;
// controller.addStream(<expr>);
// if (suspend()) {
// return;
// }
//
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
@ -5313,41 +5322,85 @@ Fragment StreamingFlowGraphBuilder::BuildYieldStatement(
instructions += DebugStepCheck(pos);
}
auto& add_method = Function::ZoneHandle(Z);
const bool is_yield_star = (flags & kYieldStatementFlagYieldStar) != 0;
if (is_yield_star) {
add_method =
IG->object_store()->async_star_stream_controller_add_stream();
} else {
add_method = IG->object_store()->async_star_stream_controller_add();
}
instructions +=
StaticCall(TokenPosition::kNoSource, add_method, 2, ICData::kNoRebind);
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;
// }
//
if (is_yield_star) {
// Discard result of _AsyncStarStreamController.addStream().
instructions += Drop();
// Suspend and test value passed to the resumed async* body.
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::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 += B->Suspend(pos, SuspendInstr::StubId::kYieldSyncStar);
instructions += Drop();
} else {
UNREACHABLE();
}
return instructions;
@ -5604,6 +5657,13 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
function.set_is_inlinable(false);
function.set_is_visible(true);
ASSERT(function.IsCompactAsyncStarFunction());
} else if (function_node_helper.async_marker_ ==
FunctionNodeHelper::kSyncStar) {
function.set_modifier(UntaggedFunction::kSyncGen);
function.set_is_debuggable(true);
function.set_is_inlinable(false);
function.set_is_visible(true);
ASSERT(function.IsCompactSyncStarFunction());
} else {
ASSERT((function_node_helper.async_marker_ ==
FunctionNodeHelper::kSync) ||
@ -5632,7 +5692,8 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
// need to manually label it generated:
if (function.parent_function() != Function::null()) {
const auto& parent = Function::Handle(function.parent_function());
if (parent.IsSyncGenerator()) {
if (parent.IsSyncGenerator() &&
!parent.IsCompactSyncStarFunction()) {
function.set_is_generated_body(true);
}
}
@ -5643,6 +5704,7 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
}
ASSERT(!function.IsCompactAsyncFunction());
ASSERT(!function.IsCompactAsyncStarFunction());
ASSERT(!function.IsCompactSyncStarFunction());
}
// If the start token position is synthetic, the end token position

View file

@ -901,6 +901,7 @@ bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
const MethodRecognizer::Kind kind = function.recognized_kind();
switch (kind) {
case MethodRecognizer::kSuspendState_clone:
case MethodRecognizer::kSuspendState_resume:
case MethodRecognizer::kTypedData_ByteDataView_factory:
case MethodRecognizer::kTypedData_Int8ArrayView_factory:
@ -1049,6 +1050,13 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
const MethodRecognizer::Kind kind = function.recognized_kind();
switch (kind) {
case MethodRecognizer::kSuspendState_clone: {
ASSERT_EQUAL(function.NumParameters(), 1);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += Call1ArgStub(TokenPosition::kNoSource,
Call1ArgStubInstr::StubId::kCloneSuspendState);
break;
}
case MethodRecognizer::kSuspendState_resume: {
const Code& resume_stub =
Code::ZoneHandle(Z, IG->object_store()->resume_stub());

View file

@ -95,11 +95,12 @@ namespace dart {
0xaeca06ef) \
V(_SuspendState, set:_errorCallback, SuspendState_setErrorCallback, \
0xc40903ac) \
V(_SuspendState, _clone, SuspendState_clone, 0xae1a40a0) \
V(_SuspendState, _createAsyncCallbacks, SuspendState_createAsyncCallbacks, \
0x68be1bf3) \
V(_SuspendState, _createAsyncStarCallback, \
SuspendState_createAsyncStarCallback, 0xfa7537e4) \
V(_SuspendState, _resume, SuspendState_resume, 0xc738e9d2) \
V(_SuspendState, _resume, SuspendState_resume, 0x5d7a8489) \
V(_IntegerImplementation, toDouble, IntegerToDouble, 0x97728b46) \
V(_Double, _add, DoubleAdd, 0xea666327) \
V(_Double, _sub, DoubleSub, 0x28474c2e) \

View file

@ -1212,6 +1212,7 @@ class Thread : public AllStatic {
static word return_async_not_future_stub_offset();
static word return_async_star_stub_offset();
static word return_async_stub_offset();
static word return_sync_star_stub_offset();
static word stack_overflow_shared_without_fpu_regs_entry_point_offset();
static word stack_overflow_shared_without_fpu_regs_stub_offset();
static word stack_overflow_shared_with_fpu_regs_entry_point_offset();
@ -1260,6 +1261,10 @@ class Thread : public AllStatic {
static word suspend_state_yield_async_star_entry_point_offset();
static word suspend_state_return_async_star_entry_point_offset();
static word suspend_state_init_sync_star_entry_point_offset();
static word suspend_state_yield_sync_star_entry_point_offset();
static word suspend_state_return_sync_star_entry_point_offset();
static word suspend_state_handle_exception_entry_point_offset();
static word OffsetFromThread(const dart::Object& object);
@ -1291,10 +1296,13 @@ class ObjectStore : public AllStatic {
static word suspend_state_handle_exception_offset();
static word suspend_state_init_async_offset();
static word suspend_state_init_async_star_offset();
static word suspend_state_init_sync_star_offset();
static word suspend_state_return_async_offset();
static word suspend_state_return_async_not_future_offset();
static word suspend_state_return_async_star_offset();
static word suspend_state_return_sync_star_offset();
static word suspend_state_yield_async_star_offset();
static word suspend_state_yield_sync_star_offset();
};
class Isolate : public AllStatic {

File diff suppressed because it is too large Load diff

View file

@ -181,10 +181,13 @@
FIELD(ObjectStore, suspend_state_handle_exception_offset) \
FIELD(ObjectStore, suspend_state_init_async_offset) \
FIELD(ObjectStore, suspend_state_init_async_star_offset) \
FIELD(ObjectStore, suspend_state_init_sync_star_offset) \
FIELD(ObjectStore, suspend_state_return_async_offset) \
FIELD(ObjectStore, suspend_state_return_async_not_future_offset) \
FIELD(ObjectStore, suspend_state_return_async_star_offset) \
FIELD(ObjectStore, suspend_state_return_sync_star_offset) \
FIELD(ObjectStore, suspend_state_yield_async_star_offset) \
FIELD(ObjectStore, suspend_state_yield_sync_star_offset) \
FIELD(OneByteString, data_offset) \
FIELD(PointerBase, data_offset) \
FIELD(Pointer, type_arguments_offset) \
@ -278,6 +281,7 @@
FIELD(Thread, return_async_not_future_stub_offset) \
FIELD(Thread, return_async_star_stub_offset) \
FIELD(Thread, return_async_stub_offset) \
FIELD(Thread, return_sync_star_stub_offset) \
\
FIELD(Thread, object_null_offset) \
FIELD(Thread, predefined_symbols_address_offset) \
@ -302,6 +306,9 @@
FIELD(Thread, suspend_state_init_async_star_entry_point_offset) \
FIELD(Thread, suspend_state_yield_async_star_entry_point_offset) \
FIELD(Thread, suspend_state_return_async_star_entry_point_offset) \
FIELD(Thread, suspend_state_init_sync_star_entry_point_offset) \
FIELD(Thread, suspend_state_yield_sync_star_entry_point_offset) \
FIELD(Thread, suspend_state_return_sync_star_entry_point_offset) \
FIELD(Thread, suspend_state_handle_exception_entry_point_offset) \
FIELD(Thread, top_exit_frame_info_offset) \
FIELD(Thread, top_offset) \

View file

@ -1298,6 +1298,85 @@ static void CallDartCoreLibraryFunction(
}
}
// Helper to generate allocation of _SuspendState instance.
// Initializes tags, frame_capacity and frame_size.
// Other fields are not initialized.
//
// Input:
// frame_size_reg: size of the frame payload in bytes.
// Output:
// result_reg: allocated instance.
// Clobbers:
// result_reg, temp_reg.
static void GenerateAllocateSuspendState(Assembler* assembler,
Label* slow_case,
Register result_reg,
Register frame_size_reg,
Register temp_reg) {
// Check for allocation tracing.
NOT_IN_PRODUCT(
__ MaybeTraceAllocation(kSuspendStateCid, slow_case, temp_reg));
// Compute the rounded instance size.
const intptr_t fixed_size_plus_alignment_padding =
(target::SuspendState::HeaderSize() +
target::SuspendState::FrameSizeGrowthGap() * target::kWordSize +
target::ObjectAlignment::kObjectAlignment - 1);
__ AddImmediate(temp_reg, frame_size_reg, fixed_size_plus_alignment_padding);
__ AndImmediate(temp_reg, -target::ObjectAlignment::kObjectAlignment);
// Now allocate the object.
__ LoadFromOffset(result_reg, Address(THR, target::Thread::top_offset()));
__ AddRegisters(temp_reg, result_reg);
// Check if the allocation fits into the remaining space.
__ CompareWithMemoryValue(temp_reg,
Address(THR, target::Thread::end_offset()));
__ BranchIf(UNSIGNED_GREATER_EQUAL, slow_case);
// Successfully allocated the object, now update top to point to
// next object start and initialize the object.
__ StoreToOffset(temp_reg, Address(THR, target::Thread::top_offset()));
__ SubRegisters(temp_reg, result_reg);
__ AddImmediate(result_reg, kHeapObjectTag);
if (!FLAG_precompiled_mode) {
// Use rounded object size to calculate and save frame capacity.
__ AddImmediate(temp_reg, temp_reg,
-target::SuspendState::payload_offset());
__ StoreToOffset(
temp_reg, FieldAddress(result_reg,
target::SuspendState::frame_capacity_offset()));
// Restore rounded object size.
__ AddImmediate(temp_reg, temp_reg, target::SuspendState::payload_offset());
}
// Calculate the size tag.
{
Label size_tag_overflow, done;
__ CompareImmediate(temp_reg, target::UntaggedObject::kSizeTagMaxSizeTag);
__ BranchIf(UNSIGNED_GREATER, &size_tag_overflow, Assembler::kNearJump);
__ LslImmediate(temp_reg,
target::UntaggedObject::kTagBitsSizeTagPos -
target::ObjectAlignment::kObjectAlignmentLog2);
__ Jump(&done, Assembler::kNearJump);
__ Bind(&size_tag_overflow);
// Set overflow size tag value.
__ LoadImmediate(temp_reg, 0);
__ Bind(&done);
uword tags = target::MakeTagWordForNewSpaceObject(kSuspendStateCid, 0);
__ OrImmediate(temp_reg, tags);
__ StoreToOffset(
temp_reg,
FieldAddress(result_reg, target::Object::tags_offset())); // Tags.
}
__ StoreToOffset(
frame_size_reg,
FieldAddress(result_reg, target::SuspendState::frame_size_offset()));
}
void StubCodeCompiler::GenerateSuspendStub(
Assembler* assembler,
intptr_t suspend_entry_point_offset_in_thread,
@ -1350,65 +1429,9 @@ void StubCodeCompiler::GenerateSuspendStub(
__ Comment("Allocate SuspendState");
__ MoveRegister(kFunctionData, kSuspendState);
// Check for allocation tracing.
NOT_IN_PRODUCT(
__ MaybeTraceAllocation(kSuspendStateCid, &alloc_slow_case, kTemp));
GenerateAllocateSuspendState(assembler, &alloc_slow_case, kSuspendState,
kFrameSize, kTemp);
// Compute the rounded instance size.
const intptr_t fixed_size_plus_alignment_padding =
(target::SuspendState::HeaderSize() +
target::SuspendState::FrameSizeGrowthGap() * target::kWordSize +
target::ObjectAlignment::kObjectAlignment - 1);
__ AddImmediate(kTemp, kFrameSize, fixed_size_plus_alignment_padding);
__ AndImmediate(kTemp, -target::ObjectAlignment::kObjectAlignment);
// Now allocate the object.
__ LoadFromOffset(kSuspendState, Address(THR, target::Thread::top_offset()));
__ AddRegisters(kTemp, kSuspendState);
// Check if the allocation fits into the remaining space.
__ CompareWithMemoryValue(kTemp, Address(THR, target::Thread::end_offset()));
__ BranchIf(UNSIGNED_GREATER_EQUAL, &alloc_slow_case);
// Successfully allocated the object, now update top to point to
// next object start and initialize the object.
__ StoreToOffset(kTemp, Address(THR, target::Thread::top_offset()));
__ SubRegisters(kTemp, kSuspendState);
__ AddImmediate(kSuspendState, kHeapObjectTag);
if (!FLAG_precompiled_mode) {
// Use rounded object size to calculate and save frame capacity.
__ AddImmediate(kTemp, kTemp, -target::SuspendState::payload_offset());
__ StoreToOffset(
kTemp, FieldAddress(kSuspendState,
target::SuspendState::frame_capacity_offset()));
// Restore rounded object size.
__ AddImmediate(kTemp, kTemp, target::SuspendState::payload_offset());
}
// Calculate the size tag.
{
Label size_tag_overflow, done;
__ CompareImmediate(kTemp, target::UntaggedObject::kSizeTagMaxSizeTag);
__ BranchIf(UNSIGNED_GREATER, &size_tag_overflow, Assembler::kNearJump);
__ LslImmediate(kTemp, target::UntaggedObject::kTagBitsSizeTagPos -
target::ObjectAlignment::kObjectAlignmentLog2);
__ Jump(&done, Assembler::kNearJump);
__ Bind(&size_tag_overflow);
// Set overflow size tag value.
__ LoadImmediate(kTemp, 0);
__ Bind(&done);
uword tags = target::MakeTagWordForNewSpaceObject(kSuspendStateCid, 0);
__ OrImmediate(kTemp, tags);
__ StoreToOffset(
kTemp,
FieldAddress(kSuspendState, target::Object::tags_offset())); // Tags.
}
__ StoreToOffset(
kFrameSize,
FieldAddress(kSuspendState, target::SuspendState::frame_size_offset()));
__ StoreCompressedIntoObjectNoBarrier(
kSuspendState,
FieldAddress(kSuspendState, target::SuspendState::function_data_offset()),
@ -1592,6 +1615,13 @@ void StubCodeCompiler::GenerateYieldAsyncStarStub(Assembler* assembler) {
target::ObjectStore::suspend_state_yield_async_star_offset());
}
void StubCodeCompiler::GenerateYieldSyncStarStub(Assembler* assembler) {
GenerateSuspendStub(
assembler,
target::Thread::suspend_state_yield_sync_star_entry_point_offset(),
target::ObjectStore::suspend_state_yield_sync_star_offset());
}
void StubCodeCompiler::GenerateInitSuspendableFunctionStub(
Assembler* assembler,
intptr_t init_entry_point_offset_in_thread,
@ -1626,6 +1656,13 @@ void StubCodeCompiler::GenerateInitAsyncStarStub(Assembler* assembler) {
target::ObjectStore::suspend_state_init_async_star_offset());
}
void StubCodeCompiler::GenerateInitSyncStarStub(Assembler* assembler) {
GenerateInitSuspendableFunctionStub(
assembler,
target::Thread::suspend_state_init_sync_star_entry_point_offset(),
target::ObjectStore::suspend_state_init_sync_star_offset());
}
void StubCodeCompiler::GenerateResumeStub(Assembler* assembler) {
const Register kSuspendState = ResumeStubABI::kSuspendStateReg;
const Register kTemp = ResumeStubABI::kTempReg;
@ -1864,6 +1901,14 @@ void StubCodeCompiler::GenerateReturnAsyncStarStub(Assembler* assembler) {
target::Thread::return_async_star_stub_offset());
}
void StubCodeCompiler::GenerateReturnSyncStarStub(Assembler* assembler) {
GenerateReturnStub(
assembler,
target::Thread::suspend_state_return_sync_star_entry_point_offset(),
target::ObjectStore::suspend_state_return_sync_star_offset(),
target::Thread::return_sync_star_stub_offset());
}
void StubCodeCompiler::GenerateAsyncExceptionHandlerStub(Assembler* assembler) {
const Register kSuspendState = AsyncExceptionHandlerStubABI::kSuspendStateReg;
ASSERT(kSuspendState != kExceptionObjectReg);
@ -1915,6 +1960,102 @@ void StubCodeCompiler::GenerateAsyncExceptionHandlerStub(Assembler* assembler) {
__ Breakpoint();
}
void StubCodeCompiler::GenerateCloneSuspendStateStub(Assembler* assembler) {
const Register kSource = CloneSuspendStateStubABI::kSourceReg;
const Register kDestination = CloneSuspendStateStubABI::kDestinationReg;
const Register kTemp = CloneSuspendStateStubABI::kTempReg;
const Register kFrameSize = CloneSuspendStateStubABI::kFrameSizeReg;
const Register kSrcFrame = CloneSuspendStateStubABI::kSrcFrameReg;
const Register kDstFrame = CloneSuspendStateStubABI::kDstFrameReg;
Label alloc_slow_case;
#ifdef DEBUG
{
// Can only clone _SuspendState objects with copied frames.
Label okay;
__ LoadFromOffset(kTemp,
FieldAddress(kSource, target::SuspendState::pc_offset()));
__ CompareImmediate(kTemp, 0);
__ BranchIf(NOT_EQUAL, &okay);
__ Breakpoint();
__ Bind(&okay);
}
#endif
__ LoadFromOffset(
kFrameSize,
FieldAddress(kSource, target::SuspendState::frame_size_offset()));
GenerateAllocateSuspendState(assembler, &alloc_slow_case, kDestination,
kFrameSize, kTemp);
// Copy pc.
__ LoadFromOffset(kTemp,
FieldAddress(kSource, target::SuspendState::pc_offset()));
__ StoreToOffset(
kTemp, FieldAddress(kDestination, target::SuspendState::pc_offset()));
// Copy function_data.
__ LoadCompressedFieldFromOffset(
kTemp, kSource, target::SuspendState::function_data_offset());
__ StoreCompressedIntoObjectNoBarrier(
kDestination,
FieldAddress(kDestination, target::SuspendState::function_data_offset()),
kTemp);
// Copy then_callback.
__ LoadCompressedFieldFromOffset(
kTemp, kSource, target::SuspendState::then_callback_offset());
__ StoreCompressedIntoObjectNoBarrier(
kDestination,
FieldAddress(kDestination, target::SuspendState::then_callback_offset()),
kTemp);
// Copy error_callback.
__ LoadCompressedFieldFromOffset(
kTemp, kSource, target::SuspendState::error_callback_offset());
__ StoreCompressedIntoObjectNoBarrier(
kDestination,
FieldAddress(kDestination, target::SuspendState::error_callback_offset()),
kTemp);
// Copy payload frame.
if (kSrcFrame == THR) {
__ PushRegister(THR);
}
const uword offset = target::SuspendState::payload_offset() - kHeapObjectTag;
__ AddImmediate(kSrcFrame, kSource, offset);
__ AddImmediate(kDstFrame, kDestination, offset);
__ CopyMemoryWords(kSrcFrame, kDstFrame, kFrameSize, kTemp);
if (kSrcFrame == THR) {
__ PopRegister(THR);
}
// Update value of :suspend_state variable in the copied frame
// for the new SuspendState.
__ LoadFromOffset(
kTemp,
FieldAddress(kDestination, target::SuspendState::frame_size_offset()));
__ AddRegisters(kTemp, kDestination);
__ StoreToOffset(kDestination,
FieldAddress(kTemp, target::SuspendState::payload_offset() +
SuspendStateFpOffset()));
__ MoveRegister(CallingConventions::kReturnReg, kDestination);
__ Ret();
__ Bind(&alloc_slow_case);
__ Comment("CloneSuspendState slow case");
__ EnterStubFrame();
__ PushObject(NullObject()); // Make space on stack for the return value.
__ PushRegister(kSource);
__ CallRuntime(kCloneSuspendStateRuntimeEntry, 1);
__ Drop(1); // Drop argument
__ PopRegister(CallingConventions::kReturnReg); // Get result.
__ LeaveStubFrame();
__ Ret();
}
} // namespace compiler
} // namespace dart

View file

@ -533,7 +533,7 @@ struct DoubleToIntegerStubABI {
static const Register kResultReg = R0;
};
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub).
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub, YieldSyncStarStub).
struct SuspendStubABI {
static const Register kArgumentReg = R0;
static const Register kTempReg = R1;
@ -544,7 +544,8 @@ struct SuspendStubABI {
static const Register kDstFrameReg = R9;
};
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub).
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub,
// InitSyncStarStub).
struct InitSuspendableFunctionStubABI {
static const Register kTypeArgsReg = R0;
};
@ -566,7 +567,7 @@ struct ResumeStubABI {
};
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
// ReturnAsyncStarStub).
// ReturnAsyncStarStub, ReturnSyncStarStub).
struct ReturnStubABI {
static const Register kSuspendStateReg = R2;
};
@ -576,6 +577,16 @@ struct AsyncExceptionHandlerStubABI {
static const Register kSuspendStateReg = R2;
};
// ABI for CloneSuspendStateStub.
struct CloneSuspendStateStubABI {
static const Register kSourceReg = R0;
static const Register kDestinationReg = R1;
static const Register kTempReg = R2;
static const Register kFrameSizeReg = R3;
static const Register kSrcFrameReg = R4;
static const Register kDstFrameReg = R8;
};
// ABI for DispatchTableNullErrorStub and consequently for all dispatch
// table calls (though normal functions will not expect or use this
// register). This ABI is added to distinguish memory corruption errors from

View file

@ -367,7 +367,7 @@ struct DoubleToIntegerStubABI {
static const Register kResultReg = R0;
};
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub).
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub, YieldSyncStarStub).
struct SuspendStubABI {
static const Register kArgumentReg = R0;
static const Register kTempReg = R1;
@ -378,7 +378,8 @@ struct SuspendStubABI {
static const Register kDstFrameReg = R6;
};
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub).
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub,
// InitSyncStarStub).
struct InitSuspendableFunctionStubABI {
static const Register kTypeArgsReg = R0;
};
@ -400,7 +401,7 @@ struct ResumeStubABI {
};
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
// ReturnAsyncStarStub).
// ReturnAsyncStarStub, ReturnSyncStarStub).
struct ReturnStubABI {
static const Register kSuspendStateReg = R2;
};
@ -410,6 +411,16 @@ struct AsyncExceptionHandlerStubABI {
static const Register kSuspendStateReg = R2;
};
// ABI for CloneSuspendStateStub.
struct CloneSuspendStateStubABI {
static const Register kSourceReg = R0;
static const Register kDestinationReg = R1;
static const Register kTempReg = R2;
static const Register kFrameSizeReg = R3;
static const Register kSrcFrameReg = R4;
static const Register kDstFrameReg = R5;
};
// ABI for DispatchTableNullErrorStub and consequently for all dispatch
// table calls (though normal functions will not expect or use this
// register). This ABI is added to distinguish memory corruption errors from

View file

@ -263,7 +263,7 @@ struct DoubleToIntegerStubABI {
static const Register kResultReg = EAX;
};
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub).
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub, YieldSyncStarStub).
struct SuspendStubABI {
static const Register kArgumentReg = EAX;
static const Register kTempReg = EDX;
@ -281,7 +281,8 @@ struct SuspendStubABI {
static const intptr_t kResumePcDistance = 4;
};
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub).
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub,
// InitSyncStarStub).
struct InitSuspendableFunctionStubABI {
static const Register kTypeArgsReg = EAX;
};
@ -305,7 +306,7 @@ struct ResumeStubABI {
};
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
// ReturnAsyncStarStub).
// ReturnAsyncStarStub, ReturnSyncStarStub).
struct ReturnStubABI {
static const Register kSuspendStateReg = EBX;
};
@ -315,6 +316,17 @@ struct AsyncExceptionHandlerStubABI {
static const Register kSuspendStateReg = EBX;
};
// ABI for CloneSuspendStateStub.
struct CloneSuspendStateStubABI {
static const Register kSourceReg = EAX;
static const Register kDestinationReg = EBX;
static const Register kTempReg = EDX;
static const Register kFrameSizeReg = ECX;
// Can reuse THR.
static const Register kSrcFrameReg = ESI;
static const Register kDstFrameReg = EDI;
};
// ABI for DispatchTableNullErrorStub and consequently for all dispatch
// table calls (though normal functions will not expect or use this
// register). This ABI is added to distinguish memory corruption errors from

View file

@ -377,7 +377,7 @@ struct DoubleToIntegerStubABI {
static constexpr Register kResultReg = A0;
};
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub).
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub, YieldSyncStarStub).
struct SuspendStubABI {
static const Register kArgumentReg = A0;
static const Register kTempReg = T0;
@ -388,7 +388,8 @@ struct SuspendStubABI {
static const Register kDstFrameReg = T5;
};
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub).
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub,
// InitSyncStarStub).
struct InitSuspendableFunctionStubABI {
static const Register kTypeArgsReg = A0;
};
@ -410,7 +411,7 @@ struct ResumeStubABI {
};
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
// ReturnAsyncStarStub).
// ReturnAsyncStarStub, ReturnSyncStarStub).
struct ReturnStubABI {
static const Register kSuspendStateReg = T1;
};
@ -420,6 +421,16 @@ struct AsyncExceptionHandlerStubABI {
static const Register kSuspendStateReg = T1;
};
// ABI for CloneSuspendStateStub.
struct CloneSuspendStateStubABI {
static const Register kSourceReg = A0;
static const Register kDestinationReg = A1;
static const Register kTempReg = T0;
static const Register kFrameSizeReg = T1;
static const Register kSrcFrameReg = T2;
static const Register kDstFrameReg = T3;
};
// ABI for DispatchTableNullErrorStub and consequently for all dispatch
// table calls (though normal functions will not expect or use this
// register). This ABI is added to distinguish memory corruption errors from

View file

@ -338,7 +338,7 @@ struct DoubleToIntegerStubABI {
static const Register kResultReg = RAX;
};
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub).
// ABI for SuspendStub (AwaitStub, YieldAsyncStarStub, YieldSyncStarStub).
struct SuspendStubABI {
static const Register kArgumentReg = RAX;
static const Register kTempReg = RDX;
@ -354,7 +354,8 @@ struct SuspendStubABI {
static const intptr_t kResumePcDistance = 5;
};
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub).
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub,
// InitSyncStarStub).
struct InitSuspendableFunctionStubABI {
static const Register kTypeArgsReg = RAX;
};
@ -376,7 +377,7 @@ struct ResumeStubABI {
};
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
// ReturnAsyncStarStub).
// ReturnAsyncStarStub, ReturnSyncStarStub).
struct ReturnStubABI {
static const Register kSuspendStateReg = RBX;
};
@ -386,6 +387,16 @@ struct AsyncExceptionHandlerStubABI {
static const Register kSuspendStateReg = RBX;
};
// ABI for CloneSuspendStateStub.
struct CloneSuspendStateStubABI {
static const Register kSourceReg = RAX;
static const Register kDestinationReg = RBX;
static const Register kTempReg = RDX;
static const Register kFrameSizeReg = RCX;
static const Register kSrcFrameReg = RSI;
static const Register kDstFrameReg = RDI;
};
// ABI for DispatchTableNullErrorStub and consequently for all dispatch
// table calls (though normal functions will not expect or use this
// register). This ABI is added to distinguish memory corruption errors from

View file

@ -2049,6 +2049,13 @@ void KernelLoader::LoadProcedure(const Library& library,
function.set_is_inlinable(false);
function.set_is_visible(true);
ASSERT(function.IsCompactAsyncStarFunction());
} else if (function_node_helper.async_marker_ ==
FunctionNodeHelper::kSyncStar) {
function.set_modifier(UntaggedFunction::kSyncGen);
function.set_is_debuggable(true);
function.set_is_inlinable(false);
function.set_is_visible(true);
ASSERT(function.IsCompactSyncStarFunction());
} else {
ASSERT(function_node_helper.async_marker_ == FunctionNodeHelper::kSync);
function.set_is_debuggable(function_node_helper.dart_async_marker_ ==
@ -2074,6 +2081,7 @@ void KernelLoader::LoadProcedure(const Library& library,
}
ASSERT(!function.IsCompactAsyncFunction());
ASSERT(!function.IsCompactAsyncStarFunction());
ASSERT(!function.IsCompactSyncStarFunction());
}
if (!native_name.IsNull()) {

View file

@ -26086,6 +26086,40 @@ SuspendStatePtr SuspendState::New(intptr_t frame_size,
return result.ptr();
}
SuspendStatePtr SuspendState::Clone(Thread* thread,
const SuspendState& src,
Heap::Space space) {
ASSERT(src.pc() != 0);
Zone* zone = thread->zone();
const intptr_t frame_size = src.frame_size();
const SuspendState& dst = SuspendState::Handle(
zone,
SuspendState::New(frame_size, Instance::Handle(zone, src.function_data()),
space));
dst.set_then_callback(Closure::Handle(zone, src.then_callback()));
dst.set_error_callback(Closure::Handle(zone, src.error_callback()));
{
NoSafepointScope no_safepoint;
memmove(dst.payload(), src.payload(), frame_size);
// Update value of :suspend_state variable in the copied frame.
const uword fp = reinterpret_cast<uword>(dst.payload() + frame_size);
*reinterpret_cast<ObjectPtr*>(
LocalVarAddress(fp, runtime_frame_layout.FrameSlotForVariableIndex(
kSuspendStateVarIndex))) = dst.ptr();
dst.set_pc(src.pc());
// Trigger write barrier if needed.
if (dst.ptr()->IsOldObject()) {
if (!dst.untag()->IsRemembered()) {
dst.untag()->EnsureInRememberedSet(thread);
}
if (thread->is_marking()) {
thread->DeferredMarkingStackAddObject(dst.ptr());
}
}
}
return dst.ptr();
}
#if !defined(DART_PRECOMPILED_RUNTIME)
void SuspendState::set_frame_capacity(intptr_t frame_capcity) const {
ASSERT(frame_capcity >= 0);
@ -26106,6 +26140,14 @@ void SuspendState::set_function_data(const Instance& function_data) const {
untag()->set_function_data(function_data.ptr());
}
void SuspendState::set_then_callback(const Closure& then_callback) const {
untag()->set_then_callback(then_callback.ptr());
}
void SuspendState::set_error_callback(const Closure& error_callback) const {
untag()->set_error_callback(error_callback.ptr());
}
const char* SuspendState::ToCString() const {
return "SuspendState";
}

View file

@ -3596,11 +3596,18 @@ class Function : public Object {
return IsAsyncGenerator() && is_debuggable();
}
// TODO(dartbug.com/48378): replace this predicate with IsSyncGenerator()
// after old sync* functions are removed.
bool IsCompactSyncStarFunction() const {
return IsSyncGenerator() && is_debuggable();
}
// Returns true for functions which execution can be suspended
// using Suspend/Resume stubs. Such functions have an artificial
// :suspend_state local variable at the fixed location of the frame.
bool IsSuspendableFunction() const {
return IsCompactAsyncFunction() || IsCompactAsyncStarFunction();
return IsCompactAsyncFunction() || IsCompactAsyncStarFunction() ||
IsCompactSyncStarFunction();
}
// Recognise synthetic sync-yielding functions like the inner-most:
@ -11865,10 +11872,22 @@ class SuspendState : public Instance {
const Instance& function_data,
Heap::Space space = Heap::kNew);
// Makes a copy of [src] object.
// The object should be holding a suspended frame.
static SuspendStatePtr Clone(Thread* thread,
const SuspendState& src,
Heap::Space space = Heap::kNew);
uword pc() const { return untag()->pc_; }
intptr_t frame_size() const { return untag()->frame_size_; }
InstancePtr function_data() const {
return untag()->function_data();
}
ClosurePtr then_callback() const { return untag()->then_callback(); }
ClosurePtr error_callback() const {
return untag()->error_callback();
}
@ -11886,6 +11905,8 @@ class SuspendState : public Instance {
void set_then_callback(const Closure& then_callback) const;
void set_error_callback(const Closure& error_callback) const;
uint8_t* payload() const { return untag()->payload(); }
FINAL_HEAP_OBJECT_IMPLEMENTATION(SuspendState, Instance);
friend class Class;
};

View file

@ -352,10 +352,34 @@ void ObjectStore::InitKnownObjects() {
ASSERT(!function.IsNull());
set_suspend_state_return_async_star(function);
function = cls.LookupFunctionAllowPrivate(Symbols::_initSyncStar());
ASSERT(!function.IsNull());
set_suspend_state_init_sync_star(function);
function = cls.LookupFunctionAllowPrivate(Symbols::_yieldSyncStar());
ASSERT(!function.IsNull());
set_suspend_state_yield_sync_star(function);
function = cls.LookupFunctionAllowPrivate(Symbols::_returnSyncStar());
ASSERT(!function.IsNull());
set_suspend_state_return_sync_star(function);
function = cls.LookupFunctionAllowPrivate(Symbols::_handleException());
ASSERT(!function.IsNull());
set_suspend_state_handle_exception(function);
cls = async_lib.LookupClassAllowPrivate(Symbols::_SyncStarIterator());
ASSERT(!cls.IsNull());
RELEASE_ASSERT(cls.EnsureIsFinalized(thread) == Error::null());
field = cls.LookupFieldAllowPrivate(Symbols::_current());
ASSERT(!field.IsNull());
set_sync_star_iterator_current(field);
field = cls.LookupFieldAllowPrivate(Symbols::_yieldStarIterable());
ASSERT(!field.IsNull());
set_sync_star_iterator_yield_star_iterable(field);
const Library& core_lib = Library::Handle(zone, core_library());
cls = core_lib.LookupClassAllowPrivate(Symbols::_CompileTimeError());
ASSERT(!cls.IsNull());
@ -383,6 +407,10 @@ void ObjectStore::InitKnownObjects() {
ASSERT(!cls.IsNull());
set_expando_class(cls);
cls = core_lib.LookupClassAllowPrivate(Symbols::Iterable());
ASSERT(!cls.IsNull());
set_iterable_class(cls);
// Cache the core private functions used for fast instance of checks.
simple_instance_of_function_ =
PrivateObjectLookup(Symbols::_simpleInstanceOf());

View file

@ -126,6 +126,7 @@ class ObjectPointerVisitor;
RW(Class, float64x2_class) \
RW(Class, error_class) \
RW(Class, expando_class) \
RW(Class, iterable_class) \
RW(Class, weak_property_class) \
RW(Class, weak_reference_class) \
RW(Class, finalizer_class) \
@ -177,10 +178,15 @@ class ObjectPointerVisitor;
RW(Function, suspend_state_init_async_star) \
RW(Function, suspend_state_yield_async_star) \
RW(Function, suspend_state_return_async_star) \
RW(Function, suspend_state_init_sync_star) \
RW(Function, suspend_state_yield_sync_star) \
RW(Function, suspend_state_return_sync_star) \
RW(Function, suspend_state_handle_exception) \
RW(Class, async_star_stream_controller) \
RW(Class, stream_class) \
RW(Field, async_star_stream_controller_async_star_body) \
RW(Field, sync_star_iterator_current) \
RW(Field, sync_star_iterator_yield_star_iterable) \
ARW_RELAXED(Smi, future_timeout_future_index) \
ARW_RELAXED(Smi, future_wait_future_index) \
RW(CompressedStackMaps, canonicalized_stack_map_entries) \
@ -252,6 +258,7 @@ class ObjectPointerVisitor;
RW(Code, unreachable_tts_stub) \
RW(Code, slow_tts_stub) \
RW(Code, await_stub) \
RW(Code, clone_suspend_state_stub) \
RW(Code, init_async_stub) \
RW(Code, resume_stub) \
RW(Code, return_async_stub) \
@ -259,6 +266,9 @@ class ObjectPointerVisitor;
RW(Code, init_async_star_stub) \
RW(Code, yield_async_star_stub) \
RW(Code, return_async_star_stub) \
RW(Code, init_sync_star_stub) \
RW(Code, yield_sync_star_stub) \
RW(Code, return_sync_star_stub) \
RW(Array, dispatch_table_code_entries) \
RW(GrowableObjectArray, instructions_tables) \
RW(Array, obfuscation_map) \
@ -336,6 +346,7 @@ class ObjectPointerVisitor;
DO(init_late_instance_field_stub, InitLateInstanceField) \
DO(init_late_final_instance_field_stub, InitLateFinalInstanceField) \
DO(await_stub, Await) \
DO(clone_suspend_state_stub, CloneSuspendState) \
DO(init_async_stub, InitAsync) \
DO(resume_stub, Resume) \
DO(return_async_stub, ReturnAsync) \
@ -343,6 +354,9 @@ class ObjectPointerVisitor;
DO(init_async_star_stub, InitAsyncStar) \
DO(yield_async_star_stub, YieldAsyncStar) \
DO(return_async_star_stub, ReturnAsyncStar) \
DO(init_sync_star_stub, InitSyncStar) \
DO(yield_sync_star_stub, YieldSyncStar) \
DO(return_sync_star_stub, ReturnSyncStar) \
DO(instance_of_stub, InstanceOf)
#define ISOLATE_OBJECT_STORE_FIELD_LIST(R_, RW) \

View file

@ -744,6 +744,17 @@ DEFINE_RUNTIME_ENTRY(AllocateSuspendState, 2) {
arguments.SetReturn(result);
}
// Makes a copy of the given SuspendState object, including the payload frame.
// Arg0: the SuspendState object to be cloned.
// Return value: newly allocated object.
DEFINE_RUNTIME_ENTRY(CloneSuspendState, 1) {
const SuspendState& src =
SuspendState::CheckedHandle(zone, arguments.ArgAt(0));
const SuspendState& dst = SuspendState::Handle(
zone, SuspendState::Clone(thread, src, SpaceForRuntimeAllocation()));
arguments.SetReturn(dst);
}
// Helper routine for tracing a type check.
static void PrintTypeCheck(const char* message,
const Instance& instance,

View file

@ -23,6 +23,7 @@ namespace dart {
V(BreakpointRuntimeHandler) \
V(SingleStepHandler) \
V(CloneContext) \
V(CloneSuspendState) \
V(DoubleToInteger) \
V(FixCallersTarget) \
V(FixCallersTargetMonomorphic) \

View file

@ -556,7 +556,7 @@ void SourceReport::VisitFunction(JSONArray* jsarr, const Function& func) {
// We skip compiled sync generators. Once a sync generator has been compiled,
// there is another function with the same range which actually contains the
// user code.
if (!func.IsSyncGenerator()) {
if (!func.IsSyncGenerator() || func.IsSuspendableFunction()) {
JSONObject range(jsarr);
range.AddProperty("scriptIndex", script_index);
range.AddProperty("startPos", begin_pos);

View file

@ -158,7 +158,11 @@ namespace dart {
V(InitAsyncStar) \
V(YieldAsyncStar) \
V(ReturnAsyncStar) \
V(InitSyncStar) \
V(YieldSyncStar) \
V(ReturnSyncStar) \
V(AsyncExceptionHandler) \
V(CloneSuspendState) \
V(UnknownDartCode)
} // namespace dart

View file

@ -187,6 +187,7 @@ class ObjectPointerVisitor;
V(InterpolateSingle, "_interpolateSingle") \
V(InvocationMirror, "_InvocationMirror") \
V(IsolateSpawnException, "IsolateSpawnException") \
V(Iterable, "Iterable") \
V(Iterator, "iterator") \
V(KernelProgramInfo, "KernelProgramInfo") \
V(LanguageError, "LanguageError") \
@ -383,6 +384,7 @@ class ObjectPointerVisitor;
V(_String, "String") \
V(_SuspendState, "_SuspendState") \
V(_SyncIterator, "_SyncIterator") \
V(_SyncStarIterator, "_SyncStarIterator") \
V(_SyncStreamController, "_SyncStreamController") \
V(_TransferableTypedDataImpl, "_TransferableTypedDataImpl") \
V(_Type, "_Type") \
@ -413,6 +415,7 @@ class ObjectPointerVisitor;
V(_typedDataBase, "_typedDataBase") \
V(_await, "_await") \
V(_classRangeCheck, "_classRangeCheck") \
V(_current, "_current") \
V(_ensureScheduleImmediate, "_ensureScheduleImmediate") \
V(_future, "_future") \
V(_handleException, "_handleException") \
@ -422,6 +425,7 @@ class ObjectPointerVisitor;
V(_hasValue, "_hasValue") \
V(_initAsync, "_initAsync") \
V(_initAsyncStar, "_initAsyncStar") \
V(_initSyncStar, "_initSyncStar") \
V(_instanceOf, "_instanceOf") \
V(_listGetAt, "_listGetAt") \
V(_listLength, "_listLength") \
@ -442,6 +446,7 @@ class ObjectPointerVisitor;
V(_returnAsync, "_returnAsync") \
V(_returnAsyncNotFuture, "_returnAsyncNotFuture") \
V(_returnAsyncStar, "_returnAsyncStar") \
V(_returnSyncStar, "_returnSyncStar") \
V(_runExtension, "_runExtension") \
V(_runPendingImmediateCallback, "_runPendingImmediateCallback") \
V(_scanFlags, "_scanFlags") \
@ -455,6 +460,8 @@ class ObjectPointerVisitor;
V(_varData, "_varData") \
V(_wordCharacterMap, "_wordCharacterMap") \
V(_yieldAsyncStar, "_yieldAsyncStar") \
V(_yieldStarIterable, "_yieldStarIterable") \
V(_yieldSyncStar, "_yieldSyncStar") \
V(add, "add") \
V(addStream, "addStream") \
V(asyncStarBody, "asyncStarBody") \

View file

@ -137,6 +137,8 @@ class Thread;
StubCode::ReturnAsyncNotFuture().ptr(), nullptr) \
V(CodePtr, return_async_star_stub_, StubCode::ReturnAsyncStar().ptr(), \
nullptr) \
V(CodePtr, return_sync_star_stub_, StubCode::ReturnSyncStar().ptr(), \
nullptr) \
V(CodePtr, stack_overflow_shared_without_fpu_regs_stub_, \
StubCode::StackOverflowSharedWithoutFPURegs().ptr(), nullptr) \
V(CodePtr, stack_overflow_shared_with_fpu_regs_stub_, \
@ -182,6 +184,9 @@ class Thread;
V(suspend_state_init_async_star) \
V(suspend_state_yield_async_star) \
V(suspend_state_return_async_star) \
V(suspend_state_init_sync_star) \
V(suspend_state_yield_sync_star) \
V(suspend_state_return_sync_star) \
V(suspend_state_handle_exception)
// This assertion marks places which assume that boolean false immediate

View file

@ -551,6 +551,35 @@ class _SuspendState {
return functionData;
}
@pragma("vm:entry-point", "call")
@pragma("vm:invisible")
static Object? _initSyncStar<T>() {
if (_trace) print('_initSyncStar<$T>');
return _SyncStarIterable<T>();
}
@pragma("vm:entry-point", "call")
@pragma("vm:invisible")
Object? _yieldSyncStar(Object? object) {
if (_trace) print('_yieldSyncStar($object)');
final data = _functionData;
if (data is _SyncStarIterable) {
data._stateAtStart = this;
return data;
} else {
// Update state in the iterator in case SuspendState was reallocated.
unsafeCast<_SyncStarIterator>(data)._state = this;
}
return true;
}
@pragma("vm:entry-point", "call")
@pragma("vm:invisible")
static bool _returnSyncStar(Object suspendState, Object? returnValue) {
if (_trace) print('_returnSyncStar');
return false;
}
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
external set _functionData(Object value);
@ -577,6 +606,125 @@ class _SuspendState {
@pragma("vm:recognized", "other")
@pragma("vm:never-inline")
external void _resume(
external Object? _resume(
Object? value, Object? exception, StackTrace? stackTrace);
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
external _SuspendState _clone();
}
class _SyncStarIterable<T> extends Iterable<T> {
_SuspendState? _stateAtStart;
_SyncStarIterable();
Iterator<T> get iterator {
return _SyncStarIterator<T>(_stateAtStart!._clone());
}
}
class _SyncStarIterator<T> implements Iterator<T> {
_SuspendState? _state;
Iterator<T>? _yieldStarIterator;
// Stack of suspended sync* methods.
List<_SuspendState>? _stack;
// sync* method sets either _yieldStarIterable
// or _current before suspending.
@pragma("vm:entry-point")
T? _current;
@pragma("vm:entry-point")
Iterable<T>? _yieldStarIterable;
@override
T get current => _current as T;
_SyncStarIterator(_SuspendState state) : _state = state {
state._functionData = this;
}
@pragma('vm:prefer-inline')
bool _handleSyncStarMethodCompletion() {
_current = null;
_state = null;
final stack = _stack;
if (stack != null && stack.isNotEmpty) {
_state = stack.removeLast();
return true;
}
return false;
}
@override
bool moveNext() {
if (_state == null) {
return false;
}
Object? pendingException;
StackTrace? pendingStackTrace;
while (true) {
// First delegate to an active nested iterator (if any).
final iterator = _yieldStarIterator;
if (iterator != null) {
try {
if (iterator.moveNext()) {
_current = iterator.current;
return true;
}
} catch (exception, stackTrace) {
pendingException = exception;
pendingStackTrace = stackTrace;
}
_yieldStarIterator = null;
}
try {
// Resume current sync* method in order to move to the next value.
final bool hasMore =
_state!._resume(null, pendingException, pendingStackTrace) as bool;
pendingException = null;
pendingStackTrace = null;
if (!hasMore) {
if (_handleSyncStarMethodCompletion()) {
continue;
}
return false;
}
} catch (exception, stackTrace) {
pendingException = exception;
pendingStackTrace = stackTrace;
if (_handleSyncStarMethodCompletion()) {
continue;
}
rethrow;
}
// Case: yield* some_iterator.
final iterable = _yieldStarIterable;
if (iterable != null) {
if (iterable is _SyncStarIterable) {
// We got a recursive yield* of sync* function. Instead of creating
// a new iterator we replace our current _state (remembering the
// current _state for later resumption).
final stack = (_stack ??= []);
stack.add(_state!);
final nestedState =
unsafeCast<_SyncStarIterable>(iterable)._stateAtStart!._clone();
nestedState._functionData = this;
_state = nestedState;
} else {
_yieldStarIterator = iterable.iterator;
}
_yieldStarIterable = null;
_current = null;
// Fetch the next item.
continue;
}
return true;
}
}
}