This separates VariableDeclaration from Statement. VariableDeclaration no longer implements Statement and variable declared in a block or in a for-statement are now wrapped by a VariableStatement.
Currently there are two VariableStatement implementations; LegacyVariableStatement for variables in the current model, called LegacyVariable, and VariableInitialization for variables used in the new, still experimental, encoding that supports scope computation.
This CL is a step towards realigning the AST nodes to the new model in which each kind of variable has its own distinct subclass. (LocalVariable, PositionalParameter, NamedParameter, SyntheticVariable, etc.)
Note that it is not the intent to use VariableStatement in ForStatement going forward but that will be handled in a follow-up.
TEST=existing.
Change-Id: I5b309cd62c9b138f95b74fb054686edffa49a393
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/502681
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Set up a cancellation Completer that we forward errors to if the stream
has been cancelled.
Also add `isDone` which will avoid forwarding registering the
cancellation logic if the stream has already finished.
Fixes test
co19/Language/Expressions/Function_Invocation/async_generator_invokation_t10.dart
on wasm targets. This test already passes for all other backends.
Fixes: https://github.com/dart-lang/sdk/issues/63123
Change-Id: I8a3d87c3ea7b4ebb3a7b82ab064fb57034aa6f4a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/495200
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
The change in [0] increased the language version of pkg/dart2wasm. That
in return changes how the package is formatted by the autoformatter.
This CL runs now the formatter to re-format the code. Unfortunately this
makes blame lists worse. But not doing it will make us have to disable
auto-formatting before saving files which is very annoying.
[0] https://dart-review.googlesource.com/c/sdk/+/487944
Change-Id: I6953fe0d6a824b2b79a26bbadb0bb977cec70b7a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/490821
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
TFA has handling of the `LoadLibrary` & `CheckLibraryIsLoaded` nodes. It
does logic based on them. For example it will ensure to that if one of
these nodes is retained in the AST that we also retain the deferred
library itself as well as the deferred library import.
For now dart2wasm lowered those two nodes during modular
transformations. This means TFA didn't see those nodes and weird things
can happen (e.g. a `checkLibraryLoad()` call without that library
existing anymore). Other interesting things that can happen: TFA
sees only one call to `checklibraryLoad` and constant propagates
the argument into the body & changes signature, ...
We could keep the existing behavior and make TFA aware of the dart2wasm
lowering (directly which is very hacky or via e.g. `Target`
indirection). Though this seems too complex.
So instead of making TFA aware of the lowerings, we move them to be
after TFA. Though we want precise TFA results if we don't use deferred
loading. So the approach is: If we actually need the runtime functions
we'll inject `@pragma('wasm:entry-point')` annotations before running
TFA and then lower those nodes after TFA.
This also means we avoid the ugly CFE nodes lowering followed by
lowering of the lowering (for load ids). Instead there's one place where
we lower those two nodes and we choose either to lower to "load id"
methods or the normal methods.
This is part of moving constants to deferred modules.
Issue https://github.com/dart-lang/sdk/issues/61727
Change-Id: Icebaf5a9495e00a8f85ecbf161b6ef891ea179ea
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/457700
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This transforms functions like
async foo() => const ...;
to
foo() => Future.value(const ...);
The transformation is done when the async function body is a `const`
expression or a basic literal (string, int, double, bool).
These expressions don't have side effects and they cannot throw, so it's
safe to convert them to `Future.value`s.
This makes the generated code in the ACX demo 2.5% smaller: (`-O4` with
symbol names removed)
- Before: 9,040,020 bytes
- After: 8,805,471 bytes
- Diff: -234,549 bytes, -2.59%
With this we also remove the same special case in the backend to avoid
generating a state machine for these functions, as the special case
handled before the backend now and backend never sees this kind of
functions.
(Technically with inlining or other backend optimizations it could still
see these cases, but the pattern it matches is too strict, and currently
the special case in the backend doesn't do anything on the ACX demo.)
Note: I tried implementing the same in dart2js's await lowering pass in
https://dart-review.googlesource.com/c/sdk/+/422061 and reusing that
pass in https://dart-review.googlesource.com/c/sdk/+/420140.
However while that transformed simple programs as expected, in ACX demo
it still introduced a lot of `Future.sync` calls and made the overall
binary larger. I think we never want to introduce `Future.sync` calls
(at least until we improve code size for closures, see relevant issue
https://github.com/dart-lang/sdk/issues/60458), so for now we don't
reuse dart2js's pass.
Issue: https://github.com/dart-lang/sdk/issues/60433
Change-Id: I206ac8c6081201041f67e7fc91776077e52180a0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/422120
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
Transform factory calls to default map and set classes to the
constructor calls to the classes to improve kernel.
Also remove some redundant null checks in VM's transformer.
`source_map_simple_optimized_test.dart` is updated: with improved kernel
wasm-opt now eliminates the `testMain` function, so the stack trace
doesn't mention it.
Fixes https://github.com/dart-lang/sdk/issues/60343.
Tested: minor refactoring in VM doesn't need testing. Wasm tested with
existing tests.
Change-Id: Ie448d1374ff0e1b278859f22bc250899e0e4cfd0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/416640
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
Each annotation corresponds to an enum value in the compiler that then dictates the generated code.
This is only done for static call and member intrinsics and not instance call intrinsics. This is because the target member of an instance intrinsic maybe be an interface rather than the annotated implementation of a method.
Change-Id: Iff8fe09b5078d81940cb1813fb65de50473519b1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/402960
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Update `popWasmArray` desugaring to only clear the popped slot when the
element type is nullable.
Use `push/popWasmArray` in `_ChunkedJsonParserState.states` stack to
avoid indirection.
Change-Id: I641b4a78b85640b3676ef935bfd98b8cd5f7789d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/394483
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
This is the final CL for deferred loading. It wires up the library-module analysis logic to the compiler. With all the Translator module predicates implemented, code should now be generated in separate modules (assuming the flag is enabled).
This also handles the module naming scheme. For an invocation of dart2wasm like `dart2wasm main.dart out.wasm` this will produce files like `out.mjs, out.wasm, out_module1.wasm, out_module2.wasm, ...`. `out.wasm` is the main module that gets loaded on initialization. When the flag is disabled this will always be the only output.
If the flag is disabled then the `_importMapping` in `deferred.dart` will be empty and we will default to the same behavior as today which will be to just return an empty `Future`. When enabled, `loadLibrary` will fetch and instantiate the new module(s) before proceeding.
Change-Id: I0dd136c0af61b916be2a24b3d79052ff1b786b52
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/380440
Reviewed-by: Martin Kustermann <kustermann@google.com>
Also removed a bunch of `CheckNotNullable`s that shouldn't be necessary any more. Any remaining non-sound-null-safety code runs today, and no more should be written. (And if it is, it'll mostly just err somewhere else, with a worse error message.)
Tested: New test added. Removed older tests checking for unsound null-safety.
Change-Id: I28626909cd8c1f91db6c61fc2b93042ed1b085dd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/380780
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Lasse Nielsen <lrn@google.com>
Up to Patchset 4 reverts commit 36fb02deca
Remaining Patchsets implement specialized support in is/as check
implementation to handle cases where only a null check is required. The
most common case in iterators:
class <...>Iterator<T> {
T? _current;
T get current => _current as T;
}
This ensures we're never emitting the general subtype checking code as
this only requres checking whether the object is non-`null` or whether
the destination type is declared nullable.
The asymmetry between `is` and `as` checks comes due to the fact that
the `as` checks have to (for the slow case) materialize a type object
for a nice error message.
Issue https://github.com/dart-lang/sdk/issues/55516
Change-Id: Ie4a845816ec4eda37a5a2e78cac0aeda0e411abd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381482
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
Improves bytes/second in an internal JSON decoding benchmark from
227,791,937 to 246,298,043 (+8%).
The container stack (`_JsonListener.stack`) could hold the pair `(array,
array length)`, however since records are also heap allocated, and size
of the record would be the same as `GrowableList`, I've reused the
`GrowableList` type for the stack elements.
To avoid duplicating the code for growing the Wasm arrays in class
fields, a new intrinsic `pushWasmArray` implemented as a macro. It's
implemented as a kernel transform and it copies the arguments as
expressions in the transformed code to grow the Wasm array when it's
full.
To change as little is possible in one CL (to be able to measure
impact), growth strategy for the arrays are kept the same.
Change-Id: I2e6ba7704a83e6e6d8ada5d9015e208069737170
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/380705
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Avoid falling back to variable type if the variable is `final` and has a
more precise inferred type.
Use unboxing information on methods to make unboxed return types
when TFA concludes it's int/double.
This will partially fix a performance regression in SplayHarder
benchmark where a parameter of type `num` was unboxed to `double` but
the local variable was kept as `num` and therefore always caused a box
allocation. After this change the box allocation is moved to the place
where we call `double.toString()`.
TEST=Updated expectation files.
Change-Id: I0252cf86ada9a8affbb46a31e913504930057650
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/365560
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
With nested `async*` functions, the state of whether we're in an
`async*` function should be restored as the previous state after leaving
the nested function, instead of as `false`.
Fixes#55397.
Change-Id: I5f2a964847ae34e98584f3adad6df7857b81e474
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/361600
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
The web platforms used to invent a spurious stack trace when reading
`Error.stackTrace` before the object was thrown.
They now return `null` instead, if there is no underlying JS error object,
matching specified behavior.
Fixed bugs in async error throwing in dart2wasm:
* `throw` in an async function did not set the stack trace on an error.
Now calls `Error._throw` instead of just a direct Wasm "throw".
* `async*` functions did not capture the stack trace of a throw
that ended the function body, which means it called
`StreamController.addError` with only one argument.
That then resused the stack trace from an `Error` throw instead
of the correct stack trace.
Added tests.
Change-Id: I1d9fa8d9e18076a7fe28254b60b950866cd550a7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/354021
Reviewed-by: Stephen Adams <sra@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Lasse Nielsen <lrn@google.com>
Previously we would encode the type of the value returned in `async`
functions as the field `futureValueType` on `FunctionNode`. For all
other kinds of functions, such as `sync`, `sync*`, and `async*`, that
field would be null. This CL renames `futureValueType` into
`emittedVAlueType`, and for functions of kinds `async`, `sync*`, and
`async*` that is expected to be the type of values emitted via
`return` or `yield` statements. For `sync` functions that field is
supposed to contain `null`.
In response to https://github.com/dart-lang/sdk/issues/54159
TEST=existing
Change-Id: I1efdbcc4e75d150f5618c7ca50cfe49a0e54fce6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/341662
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
The dart2wasm compiler treats wasm arrays of objects/ints/floats pretty
much the same, there's no reason to have complicated class hierarchy and
different kinds of wasm array classes.
Also: We rely on all operations on wasm arrays (and other built-in
types) to be handled on the call site. Wasm arrays are not dart objects,
don't support virtual dispatch. So we make operations operating on the
wasm types extensions.
This also makes now loads and stores into the wasm arrays simple `[]` and
`[]=` operations. We still have special extensions for reading/writing
to integer/double arrays that not only read/write but also
sign-extend/zero-extend and operate on Dart's `int` / `double`.
The compiler will allow `WasmArray<X>(length)` for types `X` that have
default-value in wasm arrays (nullable / integer / double types) and
have another `WasmArray<X>.filled(length, X)` for non-nullable reference
types.
Overall this reduces LOCs and simplifies things
Change-Id: I885bed3dfd1c602dc7b0747c69927d464376383d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340881
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Because of the special language rules (int +/-/* int = int),
static type for binary int operations can be more precise than
inferred result type (in case of dart2wasm, int binary operations
are declared as external methods returning num).
So, for dart2wasm it is useful to narrow result of a call by its
static type, if it is different from return type of the call target.
Also, this change fixes an incorrect static type which is
created during dart2wasm async* transformation.
TEST=pkg/vm/testcases/transformations/type_flow/transformer/int_operations_dart2wasm.dart
Fixes https://github.com/dart-lang/sdk/issues/53921
Change-Id: Id6a5a2cffac47918c4e92f996267bf7fae713416
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333580
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
FunctionTearOff node represents a tear-off of the 'call' method of
a Function, so it is basically a no-op:
FunctionTearOff(receiver) == receiver
So we can remove this node early, during lowering transformation on
kernel AST and clean up handling of FunctionTearOff nodes from the VM
and dart2wasm compilation pipelines.
TEST=ci
Change-Id: Ia1500a066a0261076162e018ff0ab502258f606f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/325924
Reviewed-by: Ömer Ağacan <omersa@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This avoids the overhead of Dart lists in subtype checks. It also
alleviates a potential source of infinite recursion by avoiding some
list operations with implicit type checks inside the type check code
(though there are still more of these).
With this change, we no longer have the const object cycle between
the empty list of `_Type` objects and the interface type object for
`_Type`. In combination with the the `struct.new` optimization, this
enables type argument fields to become non-nullable and immutable.
Change-Id: Ib46ea70a078a0c580713090163fecd63fe363bd9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/322900
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Jess Lally <jessicalally@google.com>
This is mainly used in [1] to allow using unboxed int lists when a
factory type argument is `int`, which then allows inlining unboxed int
list `[]` and `[]=` and storing and loading `int` values unboxed.
This implementation is mostly a copy of VM's transformer with the same
name. However we can't reuse VM's pass as we do different
transformations in [1].
[1]: https://dart-review.googlesource.com/c/sdk/+/318680
Change-Id: I16c06fc2b2edb1a5498807fc5c0fee839c003965
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/318921
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Joshua Litt <joshualitt@google.com>
The desugared code uses `Completer<bool>` values to suspend the `async*`
function, but we can't use a type test and to check if a value is the
`Completer<bool>` value for the suspension or a user-emitted value as
the `async*` function can also yield `Completer<bool>` values. Update
the test from `value is Completer<bool>` to `!isEven`.
Change-Id: I74f54b838e6a2aab942154ec7f3e667e291523e0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/304880
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
Currently the `InstanceGet` node result type for for
`Completer<bool>.future` is `Future<bool> Function()`, but it should be
`Future<bool>`.
This causes problems in CL 301020 where we generate temporaries for
nested `await` expressions and use the expression type for the types of
those temporaries. Incorrect expression type in `completer.future`
causes a temporary with incorrect type to be generated.
Change-Id: Ib8193c66afee9454a275c00fb958c11fd35cd3eb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/301382
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
This improves the precision of the Wasm types for Dart function types
in instance method signatures.
It could in principle also improve the precision of the receiver
parameter from the LUB of the representation types to the LUB of the
actual structs for the classes implementing the member. However,
if at a call site the receiver parameter type is more precise than the
representation type of the receiver, the call site will need to cast
the receiver to the more precise type. This gives rise to more casts
in practice than the ones saved inside the methods by the more precise
receiver parameter type. For this reason, the receiver parameter type
is kept at the LUB of the representation types of the classes
implementing the member.
This change is also a stepping stone towards not having `ClassInfo`
for the special Wasm types.
CoreLibraryReviewExempt: Only affects Wasm-specific libraries.
Change-Id: I81ca5aa1107f1c04ed7729a758e983698492a106
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/288400
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
This is an implementation of `sync*` via two main mechanisms:
- The closure context infrastructure is used for preserving local
state. All local variables in `sync*` functions are implicitly
captured in the contexts even if they are not captured by a lambda.
- Suspension and resumption of the body is implemented via a state
machine as a switch in a loop. This allows for an arbitrary control
flow graph that can be resumed at any point. A subclass of the code
generator generates control constructs containing any `yield` or
`yield*` statements as jumps around this CFG while delegating the
rest of the code generation to the normal member code generator.
This version does not support `switch` or `try` inside a `sync*`
function. Support for these statements will be added later.
Change-Id: Iec8236f64500d823f574aa628ddb0d22fe4ac2d0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/280166
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>