mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[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:
parent
ee86c92975
commit
77ea9820aa
|
@ -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 */ {}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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>*};
|
||||
|
|
|
@ -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*>*;
|
||||
|
|
|
@ -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 {}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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*/ {
|
||||
|
|
|
@ -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*/ {
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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>};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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!;
|
||||
}
|
||||
|
|
|
@ -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::•();
|
||||
|
|
|
@ -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''
|
||||
|
|
|
@ -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''
|
||||
|
|
|
@ -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''
|
||||
|
|
|
@ -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''
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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
|
@ -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) \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace dart {
|
|||
V(BreakpointRuntimeHandler) \
|
||||
V(SingleStepHandler) \
|
||||
V(CloneContext) \
|
||||
V(CloneSuspendState) \
|
||||
V(DoubleToInteger) \
|
||||
V(FixCallersTarget) \
|
||||
V(FixCallersTargetMonomorphic) \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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") \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue