This adds a `--verify-type-checks` option to dart2wasm to instrument
the code such that whenever we are able to generate specialized code
for a type check, we generate both the specialized code and also call
the general fallback path, then compare the results.
This can be used to expose bugs in the type check specializations, or
in the reference implementation, as it may be.
Change-Id: I081540a8eedc7d029b332919283810220b21b3ea
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/336023
Reviewed-by: Ömer Ağacan <omersa@google.com>
Refactor libraries so that JSCM will only use `JSStringImpl` class for
strings.
The goal is to disentangle the native string classes and `JSStringImpl`
and start testing `JSStringImpl` in isolation.
Changes:
- `dart:_string` is no longer available in JSCM.
- Make `int.toString` external to allow patching it differently in JSCM
and normal modes.
`toString` implementations are in `boxed_int_to_string.dart` patch
files.
- `int.parse` now uses JS `parseInt`. However `parseInt` is not
compatible with Dart's `int.parse` so this will cause some more test
failures in JSCM for now.
- Any dependencies to `dart:_string` from JSCM `dart:convert` are
removed. The library implementation now uses JS `TextDecoder` for
UTF-8 decoding.
Note: `TextDecoder` is not available on d8, so text decoding tests
will fail on d8.
JSON encoding and decoding in `dart:convert` will be updated in a
follow-up CL.
- Compiler (translator, constant generator, code generator etc.) is
updated to allocate the `JSStringImpl`s in JSCM.
Initially this will make some JSCM test fail as `int` parsing is not
quite right, those will be fixed in follow-up CLs.
Co-authored-by: Joshua Litt <joshualitt@google.com>
Change-Id: I366e06f44cdc369d28fe47b24015234260304399
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/332680
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
This is a reland of commit 2cbb5eabca
This removes the optimization that would reuse the Wasm struct of the
superclass if no new fields were added in a class. Such reuse
interferes with debugging.
Binaryen performs a similar optimization in its TypeMerging pass. It
seems to be doing a better job with the more precise type information
provided after this change. Benchmarks show a positive trend.
The change uncovered a number of latent bugs in the compiler, which
are also fixed in this CL:
- References to `StackTrace` objects must be typed with the
representation type of `StackTrace`, rather than its struct type.
- The dynamic call vtable entry and dynamic invocation forwarder
functions must use `_ListBase` rather than `_List` for their
parameters, since we sometimes pass growable lists to these
functions.
- Most covariant parameters must use the top type, since any object
can be passed into such parameters via class type parameter
covariance or tear-offs.
The change makes us fail a number of tests with very deep class
hierarchies due to the Wasm subtyping depth limit of 63. The
optimization did not absolve us from this limitation. It just made us
only count classes with newly added fields.
The limitation is not expected to cause any problems for real code.
The maximum subclassing depth that occurs in the Flute benchmark is
11. FWIW, Java has a limit of 60.
The limitation is mentioned along with other limitations in
https://github.com/dart-lang/sdk/issues/53703
Change-Id: I9f541049d2020934e98b2042a7d9852305f17ec1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/330341
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
This reverts commit 2cbb5eabca.
Reason for revert: https://github.com/flutter/flutter/issues/136363
Original change's description:
> [dart2wasm] Use a separate Wasm struct for every Dart class
>
> This removes the optimization that would reuse the Wasm struct of the
> superclass if no new fields were added in a class. Such reuse
> interferes with debugging.
>
> Binaryen performs a similar optimization in its TypeMerging pass. It
> seems to be doing a better job with the more precise type information
> provided after this change. Benchmarks show a positive trend.
>
> The change uncovered a number of latent bugs in the compiler, which
> are also fixed in this CL:
> - References to `StackTrace` objects must be typed with the
> representation type of `StackTrace`, rather than its struct type.
> - The dynamic call vtable entry and dynamic invocation forwarder
> functions must use `_ListBase` rather than `_List` for their
> parameters, since we sometimes pass growable lists to these
> functions.
> - Most covariant parameters must use the top type, since any object
> can be passed into such parameters via class type parameter
> covariance or tear-offs.
>
> The change makes us fail a number of tests with very deep class
> hierarchies due to the Wasm subtyping depth limit of 63. The
> optimization did not absolve us from this limitation. It just made us
> only count classes with newly added fields.
>
> The limitation is not expected to cause any problems for real code.
> The maximum subclassing depth that occurs in the Flute benchmark is
> 11. FWIW, Java has a limit of 60.
>
> The limitation is mentioned along with other limitations in
> https://github.com/dart-lang/sdk/issues/53703
>
> Change-Id: Ifaa23d8278989e2549c41696d8913e55ed1e80aa
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/324460
> Commit-Queue: Aske Simon Christensen <askesc@google.com>
> Reviewed-by: Ömer Ağacan <omersa@google.com>
Change-Id: I1b16936a045f6297f340b5d72344f702446bf955
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/330044
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Auto-Submit: Jackson Gardner <jacksongardner@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
This removes the optimization that would reuse the Wasm struct of the
superclass if no new fields were added in a class. Such reuse
interferes with debugging.
Binaryen performs a similar optimization in its TypeMerging pass. It
seems to be doing a better job with the more precise type information
provided after this change. Benchmarks show a positive trend.
The change uncovered a number of latent bugs in the compiler, which
are also fixed in this CL:
- References to `StackTrace` objects must be typed with the
representation type of `StackTrace`, rather than its struct type.
- The dynamic call vtable entry and dynamic invocation forwarder
functions must use `_ListBase` rather than `_List` for their
parameters, since we sometimes pass growable lists to these
functions.
- Most covariant parameters must use the top type, since any object
can be passed into such parameters via class type parameter
covariance or tear-offs.
The change makes us fail a number of tests with very deep class
hierarchies due to the Wasm subtyping depth limit of 63. The
optimization did not absolve us from this limitation. It just made us
only count classes with newly added fields.
The limitation is not expected to cause any problems for real code.
The maximum subclassing depth that occurs in the Flute benchmark is
11. FWIW, Java has a limit of 60.
The limitation is mentioned along with other limitations in
https://github.com/dart-lang/sdk/issues/53703
Change-Id: Ifaa23d8278989e2549c41696d8913e55ed1e80aa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/324460
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
This reverts commit 67f0d4daf0, and further optimises constructor contexts by preventing empty contexts.
Reason for revert: Includes fix for Flutter engine unit test failures.
Fixes https://github.com/dart-lang/sdk/issues/53506
Original change's description:
[dart2wasm] Replace `struct.new_default` with `struct.new` for object allocation.
When using the `struct.new_default` instruction for object allocation,
fields are always nullable and mutable. By using the `struct.new`
instruction instead, class fields can now have the same mutability and
nullability in Wasm as declared in Dart. In addition, the class ID and
type parameters (which are also stored in an object's struct), can now
be immutable and nonnullable as well.
To do this, object construction is now split into three functions:
(1) Initializer: evaluates initializers for instance fields and
constructor initializers (this constructor before super constructor).
(2) Constructor body: executes the constructor body (super constructor
before this constructor), with `this` pointed to the constructed object.
(3) Constructor allocator: which calls (1), allocates the object using
`struct.new`, then calls (2).
Because fields now have the correct mutability and nullability in Wasm,
this removes unnecessary null checks for nonnullable fields, and may
allow for better optimisations by Binaryen.
Fixes https://github.com/dart-lang/sdk/issues/51492
Change-Id: I13499bdc412f474bc76473115b6e63d6954f4d23
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/326080
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Jess Lally <jessicalally@google.com>
Reviewed-by: Aske Simon Christensen <askesc@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 splits visitors for Initializer, Expression, Statement, Member,
and MemberReference into pure interfaces and mixins with the base
implementation. This is a step towards avoid having an accidental
default implementation where a static error would have been preferable.
TEST=existing
Change-Id: I4aa243ce3b3436e05d6164c934df3c44119cd1fa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/325521
Reviewed-by: Ömer Ağacan <omersa@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
This reverts commit 5a4b252252.
Reason for revert: Causing Flutter engine unit test failures, see https://github.com/dart-lang/sdk/issues/53506
Original change's description:
> [dart2wasm] Replace `struct.new_default` with `struct.new` for object
> allocation.
>
> When using the `struct.new_default` instruction for object allocation,
> fields are always nullable and mutable. By using the `struct.new`
> instruction instead, class fields can now have the same mutability and
> nullability in Wasm as declared in Dart. In addition, the class ID and
> type parameters (which are also stored in an object's struct), can now
> be immutable and nonnullable as well.
>
> To do this, object construction is now split into three functions:
> (1) Initializer: evaluates initializers for instance fields and
> constructor initializers (this constructor before super constructor).
> (2) Constructor body: executes the constructor body (super constructor
> before this constructor), with `this` pointed to the constructed object.
> (3) Constructor allocator: which calls (1), allocates the object using
> `struct.new`, then calls (2).
>
> Because fields now have the correct mutability and nullability in Wasm,
> this removes unnecessary null checks for nonnullable fields, and may
> allow for better optimisations by Binaryen.
>
> Fixes https://github.com/dart-lang/sdk/issues/51492
>
> Change-Id: Ib26046686f772a70509a870301217e9b1c91b77e
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315820
> Commit-Queue: Jess Lally <jessicalally@google.com>
> Reviewed-by: Aske Simon Christensen <askesc@google.com>
Change-Id: I034d3acf3715abadc6811a7393ba780bee974329
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/325445
Commit-Queue: Martin Kustermann <kustermann@google.com>
Commit-Queue: Jackson Gardner <jacksongardner@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This adds a typed `TypeParameter.declaration` property to be used
instead of the `parent` property. The `declaration` property holds the
declaration (Class, Method, Extension, etc.) that introduced the
type parameter. `GenericFunction` is the subset of `GenericDeclaration`
that is defined through a `FunctionNode`.
TEST=existing
Change-Id: Ie89e7f5fa12a7966507a250cacc098eb0ce6b30b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/323160
Reviewed-by: Mayank Patke <fishythefish@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
allocation.
When using the `struct.new_default` instruction for object allocation,
fields are always nullable and mutable. By using the `struct.new`
instruction instead, class fields can now have the same mutability and
nullability in Wasm as declared in Dart. In addition, the class ID and
type parameters (which are also stored in an object's struct), can now
be immutable and nonnullable as well.
To do this, object construction is now split into three functions:
(1) Initializer: evaluates initializers for instance fields and
constructor initializers (this constructor before super constructor).
(2) Constructor body: executes the constructor body (super constructor
before this constructor), with `this` pointed to the constructed object.
(3) Constructor allocator: which calls (1), allocates the object using
`struct.new`, then calls (2).
Because fields now have the correct mutability and nullability in Wasm,
this removes unnecessary null checks for nonnullable fields, and may
allow for better optimisations by Binaryen.
Fixes https://github.com/dart-lang/sdk/issues/51492
Change-Id: Ib26046686f772a70509a870301217e9b1c91b77e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315820
Commit-Queue: Jess Lally <jessicalally@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
When `getFunction` is called, the function will be added to the worklist if it has not been previously generated. However, if there is a later call to the code generator `call` helper method, this may decide to inline the function, meaning that the function will be generated twice. By calling `getFunctionType` instead, functions will be generated once by the `call` helper method.
Change-Id: I39a48dca37428b0723d897437fb4687748ad72f6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/324282
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Jess Lally <jessicalally@google.com>
Removes the assumption from the code generator `call` helper method
that the called function has zero or one return value. This enables
the helper to be used for functions with multiple return values (e.g.
constructor initializer functions), allowing such functions to be
inlined.
Many places that explicitly called a function behind a reference using
`b.call(translator.functions.getFunction(reference))` are now using
the `call` helper like `call(reference)` such that those calls can be
inlined.
Also fixes a bug in the inlining heuristic that would allow inlining
of `async` functions, which would break.
Change-Id: I180d45de8ad36ef8ef1d27a71fc8ec473a25db8b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/324023
Reviewed-by: Jess Lally <jessicalally@google.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
The `collectContexts(member)` already visits initializer lists when
visiting constructors, so no need to call it separately for
initializers.
Change-Id: Ida51a0e8c4003f19cd7b533a2847946926237bc0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/317101
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
This CL mostly just moves code around. There are three broad changes in this CL:
1) Reify the builder / built pattern that exists implicitly in the existing code. Builders now live in `src/builder`, while the built ir lives in `src/ir`.
2) Reify the module subsections.
3) `pkg/dart2wasm` has been updated to use the new API.
There is only one minor logic change in the entire CL, we now defer serialization of a module until the bytes are actually required, as opposed to serializing eagerly.
This change is designed to make the wasm_builder more robust. By clearly delineating which parts of the AST are mutable and which parts are immutable, then it should make it easier for users of the wasm_builder to avoid undefined behavior, i.e. holding on to something that can change.
Change-Id: I676107b867aa74fabf413108673e170126bdb5c1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/316280
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Joshua Litt <joshualitt@google.com>
Currently setting exception variables in `catch` blocks assumes that the
variables are not captured and always creates a new local for the
variable.
This CL adds a new function for initializing a variables. The
implementation is similar to `VariableDeclration` visitor and handles
captured (updated or not updated) and non-captured variables. This
function is then used in `catch` blocks to initialize exception and
stack trace variables.
New passing tests:
- co19/LibTest/async/Zone/handleUncaughtError_A01_t04
- lib/async/future_test
Fixes#52556.
Change-Id: I428d8f30ab1509b5b4439f8136190134741dd4ba
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/307042
Reviewed-by: Joshua Litt <joshualitt@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
This CL re-implements the async function compilation without using JSPI
or any other platform features.
This implementation is faster than the JSPI-based one in all benchmarks,
in some cases up to 200x (benchmark results at the end). So we remove
the JSPI-based implementation as there's no point in maintaining a much
slower implementation and supporting two implementations at the same
time (which is tricky because these implementations need different
libraries, all scripts need to support two modes etc.) that also
requires experimental platform features.
# Main changes
- A new pass `AwaitTransformer` transforms `await` expressions to
top-level statements in form `var <fresh variable> = await <simple
expr>`, where `<simple expr>` is an expression without `await`.
After this pass all `await` expressions have the simple continuation
of "assign the value of the awaited future to this variable and
continue with the next statement". This simplifies `await`
compilation.
- A new code generator `AsyncCodeGenerator` (inherits from
`CodeGenerator`) compiles `async` functions. The `_YieldFinder` class
is copied from `sync*` code generator but modified to handle `async`
expressions.
- Mentions to the V8 flag `--experimental-wasm-stack-switching` is
removed from all scripts and documents.
# Future work
- Control flow handling in `AsyncCodeGenerator` needs to be implemented
in a similar way in `SyncStarCodeGenerator`. Doing this without
duplicating a lot of code will require some refactoring.
# New passing tests
- co19/Language/Statements/Yield_and_Yield_Each/Yield/execution_async_A05_t01
- co19/Language/Statements/For/Asynchronous_For_in/execution_A02_t02
- language/regress/regress23996_test
- language/sync_star/dcall_type_test
# Benchmarks
Current implementation:
```
AsyncLiveVars.LiveObj1(RunTime): 1586000.0 us.
AsyncLiveVars.LiveObj2(RunTime): 2114000.0 us.
AsyncLiveVars.LiveObj4(RunTime): 1972500.0 us.
AsyncLiveVars.LiveObj8(RunTime): 2212000.0 us.
AsyncLiveVars.LiveObj16(RunTime): 2238000.0 us.
AsyncLiveVars.LiveInt1(RunTime): 2362000.0 us.
AsyncLiveVars.LiveInt4(RunTime): 2470000.0 us.
AsyncLiveVars.LiveObj2Int2(RunTime): 2575000.0 us.
AsyncLiveVars.LiveObj4Int4(RunTime): 2820000.0 us.
Calls.AwaitAsyncCall(RunTimeRaw): 35676.15658362989 ns.
Calls.AwaitAsyncCallClosureTargetPolymorphic(RunTimeRaw): 38934.108527131786 ns.
Calls.AwaitAsyncCallInstanceTargetPolymorphic(RunTimeRaw): 42617.02127659575 ns.
Calls.AwaitFutureCall(RunTimeRaw): 2832.058906825262 ns.
Calls.AwaitFutureCallClosureTargetPolymorphic(RunTimeRaw): 3665.8125915080527 ns.
Calls.AwaitFutureCallInstanceTargetPolymorphic(RunTimeRaw): 4420.449537241076 ns.
Calls.AwaitFutureOrCall(RunTimeRaw): 3692.7621861152143 ns.
Calls.AwaitFutureOrCallClosureTargetPolymorphic(RunTimeRaw): 4625.346901017576 ns.
Calls.AwaitFutureOrCallInstanceTargetPolymorphic(RunTimeRaw): 4514.6726862302485 ns.
Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits(RunTimeRaw): 345172.4137931034 ns.
Calls.AwaitForAsyncStarStreamPolymorphic(RunTimeRaw): 697000.0 ns.
Calls.AwaitForAsyncStarStreamPolymorphicManyYields(RunTimeRaw): 704666.6666666666 ns.
Calls.AwaitForManualStreamPolymorphic(RunTimeRaw): 11010.989010989011 ns.
Calls.SyncCall(RunTimeRaw): 0.40275240996973316 ns.
Calls.SyncCallClosureTarget(RunTimeRaw): 0.3989591156672242 ns.
Calls.SyncCallInstanceTargetPolymorphic(RunTimeRaw): 3.2632549336335526 ns.
Calls.IterableSyncStarIterablePolymorphic(RunTimeRaw): 353.3980582524272 ns.
Calls.IterableManualIterablePolymorphic(RunTimeRaw): 332.1161825726141 ns.
Calls.IterableManualIterablePolymorphicManyYields(RunTimeRaw): 354.28067078552516 ns.
```
New implementation:
```
AsyncLiveVars.LiveObj1(RunTime): 11327.683615819209 us.
AsyncLiveVars.LiveObj2(RunTime): 10923.91304347826 us.
AsyncLiveVars.LiveObj4(RunTime): 10956.284153005465 us.
AsyncLiveVars.LiveObj8(RunTime): 11286.516853932584 us.
AsyncLiveVars.LiveObj16(RunTime): 11445.714285714286 us.
AsyncLiveVars.LiveInt1(RunTime): 11016.483516483517 us.
AsyncLiveVars.LiveInt4(RunTime): 11327.683615819209 us.
AsyncLiveVars.LiveObj2Int2(RunTime): 10918.478260869566 us.
AsyncLiveVars.LiveObj4Int4(RunTime): 10737.967914438503 us.
Calls.AwaitAsyncCall(RunTimeRaw): 1082.2510822510822 ns.
Calls.AwaitAsyncCallClosureTargetPolymorphic(RunTimeRaw): 1056.4124234100993 ns.
Calls.AwaitAsyncCallInstanceTargetPolymorphic(RunTimeRaw): 1134.1726210729273 ns.
Calls.AwaitFutureCall(RunTimeRaw): 865.6509695290858 ns.
Calls.AwaitFutureCallClosureTargetPolymorphic(RunTimeRaw): 841.3967185527977 ns.
Calls.AwaitFutureCallInstanceTargetPolymorphic(RunTimeRaw): 839.066957543212 ns.
Calls.AwaitFutureOrCall(RunTimeRaw): 397.9941096871766 ns.
Calls.AwaitFutureOrCallClosureTargetPolymorphic(RunTimeRaw): 406.17384240454913 ns.
Calls.AwaitFutureOrCallInstanceTargetPolymorphic(RunTimeRaw): 393.7472929873607 ns.
Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits(RunTimeRaw): 1095.0503723171266 ns.
Calls.AwaitForAsyncStarStreamPolymorphic(RunTimeRaw): 6643.426294820717 ns.
Calls.AwaitForAsyncStarStreamPolymorphicManyYields(RunTimeRaw): 7178.750897343863 ns.
Calls.AwaitForManualStreamPolymorphic(RunTimeRaw): 1456.23998835008 ns.
Calls.SyncCall(RunTimeRaw): 0.3919935321067202 ns.
Calls.SyncCallClosureTarget(RunTimeRaw): 0.3906669661780074 ns.
Calls.SyncCallInstanceTargetPolymorphic(RunTimeRaw): 3.1676143112814583 ns.
Calls.IterableSyncStarIterablePolymorphic(RunTimeRaw): 104.4932079414838 ns.
Calls.IterableManualIterablePolymorphic(RunTimeRaw): 104.57516339869281 ns.
Calls.IterableManualIterablePolymorphicManyYields(RunTimeRaw): 116.92487576731949 ns.
```
TEST=ci
CoreLibraryReviewExempt: Added entry-point pragmas.
Change-Id: I02fbd08141f51c00fb37b6fa0304dc25d6afdb71
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/301020
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: William Hesse <whesse@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Joshua Litt <joshualitt@google.com>
The map `breakFinalizers` need to have insertion-ordered iteration
otherwise creation of Wasm blocks when compiling try-finally blocks
won't work. Update the map type from `Map` to `LinkedHashMap` to make
this clear.
This doesn't change the concrete map type used as non-constant map
literals are already compiled to `LinkedHashMap`s, just makes the type
more precise for clarity.
Change-Id: Idebffe2f0f75232f5ef41729538ad3d2508c74c1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/294760
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
Currently when `switch` expression is nullable (so the values are boxed)
we currently use `ref.eq` to compare the values.
This doesn't work as expected when one of the values is a constant and
the other one is a runtime-allocated value. Example:
void test(bool? x) {
switch (x) {
case false:
print('no');
case true:
print('yes');
case null:
print('maybe');
}
}
bool runtimeTrue = int.parse('1') == 1;
void main() {
test(runtimeTrue);
}
Here the return value of `runtimeTrue` is boxed in the call site of
`test`. In the body of `test` we use globals for constants `true` and
`false`, which are never equal to runtime-allocated values.
We now use `identical` in these cases, which handles `bool`, `String`,
and `num` values as expected and compares the rest using `ref.eq`.
New passing test: co19/LanguageFeatures/Patterns/exhaustiveness_A01_t10
Fixes#52075
Change-Id: Ibbeda7525fd40cfec5ee477493d0d96ac6e139b2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/295941
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
With https://dart-review.googlesource.com/c/sdk/+/289224 the front-end
can now generate switch-case expressions where type of the `switch`
expression is different than the types of expressions in `case`s.
To handle this case we have two options:
1. Compare type of `switch` and `case`s and compile the code to just
evaluate the switch expressions and the default case.
2. Use reference equality
This CL implements (2) as it's simpler and no correct code will have a
switch-case with differently typed switch and case expressions.
Fixes#51793,
Fixes tests:
- co19/Language/Statements/Switch/execution_t01
- co19/Language/Statements/Switch/type_t01
- co19/Language/Statements/Switch/type_t02
Change-Id: I7eece161249498cf19c9f5245b3898c15a721b60
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/290063
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
This avoids virtual calls for `runtimeType` (unless the user overrides
it) and `_runtimeType` (since the internal categorization is now done
using the table instead), which saves a huge amount of space in the
global dispatch table.
It also fixes record runtime types, which now use the masqueraded
types for its fields, rather than the (possibly user-overridden)
`runtimeType`.
A masquerade case was missing for `Type`, which has been added.
Fixes https://github.com/dart-lang/sdk/issues/51134
Tested: ci + new test for overridden runtimeType
Change-Id: I1909c665ae78eb07b9c0eb22b6e8836e27495d70
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/285684
Reviewed-by: Ömer Ağacan <omersa@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
The block starts and ends for the entry points to the finally block
instances corresponding to break paths were emitted in the same order,
causing the jump targets to be reversed.
Change-Id: Ifc8a6b6320ba7341140606c98333f5825d2228ac
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/283042
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
This generates a class for every record shape in the program. Record
shape classes with the same number of fields share the same Wasm struct.
(Shape is number of positional fields + set of names of the named
fields)
Summary of the changes:
- A new kernel pass runs right before TFA and generates record shape
classes for every record literal and type in the program, one class
per shape.
A class for a record shape has the name `Record_N_a_b_...` where `N`
is the number of positional fields, and `a_b_...` is the `_` separated
names of the named fields.
For example, class for a record `(1, a: 'hi', false)` is:
```
@pragma('wasm:entry-point')
class Record_2_a {
@pragma('wasm:entry-point')
final Object? $1;
@pragma('wasm:entry-point')
final Object? $2;
@pragma('wasm:entry-point')
final Object? a;
@pragma('wasm:entry-point')
Record_2_a(this.$1, this.$2, this.a);
@pragma('wasm:entry-point')
_Type get _runtimeType =>
// Uses of `runtimeType` below will be fixed with #51134
_RecordType(
const ["a"],
[$1.runtimeType, $2.runtimeType, a.runtimeType]);
@pragma('wasm:entry-point')
Type get runtimeType => _runtimeType;
@pragma('wasm:entry-point')
String toString() => "(" + $1 + ", " + $2 + ", " + "a: " + a + ")";
@pragma('wasm:entry-point')
bool operator ==(Object other) {
if (other is! Record_2_a) return false;
if ($1 != other.$1) return false;
if ($2 != other.$2) return false;
if (a != other.a) return false;
return true;
}
@pragma('wasm:entry-point')
int hashCode => Object.hash(shapeID, $1, $2, a);
}
```
`shapeID` in `hashCode` is unique to the class. It's not stored in the
structs, only used in `hashCode` code.
Field gets in members (`this.$1` etc.) are compiled to `struct.get`s
as they're single target.
`toString` currently does not use a buffer. This will be fixed in a
separate CL.
`entry-point` pragmas needed because there are no references from the
program to these classes, but we want to consider them as potential
targets.
- When generating class infos, we have a special case for records to use
the same struct for records with the same number of fields.
- Code generator for record expressions get the record shape from the
record type, and uses the struct type for the record.
- `ProcedureAttributesMetadata` uses in dispatch table needs a special
case for records. This is becuase as far as TFA concerned there's no
connection from the program to the record shape class fields, so the
it considers record shape class fields as not dynamically called.
Fixes#50014.
Change-Id: Ie8338a0917d51984a9e32e755ccdaa2783a8e2ba
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/280461
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Joshua Litt <joshualitt@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>
This implements this part of the language spec (section 17.10):
> If v is an instance of class Error or a subclass thereof, and it is
> the first time that Error object is thrown, the stack trace t is
> stored on v so that it will be returned by the stackTrace getter
> inherited from Error.
New passing tests:
- co19/Language/Expressions/Throw/stack_trace_t01
- co19/LibTest/core/Error/stackTrace_A01_t01
- co19/LibTest/core/IndexError/stackTrace_A01_t01
- corelib/error_stack_trace_test/none
- corelib/error_stack_trace_test/nullThrown
- language/stack_trace/error_runtime_test
Fixes#50608
Change-Id: I1d7df2337cce1be3ecbab0180def5769b8fe3e68
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279966
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
Since Dart `void` can actually carry values, functions with `void`
return type are translated into Wasm functions returning the Dart
object top type instead of an empty output type list.
Only constructors, setters and imports/exports with void return type
are now given empty output type lists in their Wasm signatures. A new
low-level `WasmVoid` type is added to the internal Wasm types for
specifying explicitly that a Wasm function should have an empty list
of outputs.
Fixes https://github.com/dart-lang/sdk/issues/50458
CoreLibraryReviewExempt: Only changes Wasm-specific libraries.
Change-Id: I9562248f94e75a60142fd1af0136183aa288b98b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279971
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
By using the unboxed type for `preciseThisLocal`, methods that access
the receiver multiple times will only unbox it once.
Change-Id: I6cad58c38975154f2216e50acc6938583f1f577a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279099
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Also renamed the `_Function` class to `_Closure` and fixed the name of
closure structs so they aren't all called `#ClosureBase`.
Change-Id: I6b55cb9827fdffac751dfc3043f3a36e7a18f225
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279091
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
This changes a number of things in dart2wasm's internal inliner:
- Fixed a few places that access the outputs of the current function
to take inlining into account.
- Don't inline functions that contain local functions or function
literals, since the mechanism does not support this situation.
- Don't inline a function if it's already on the stack of functions
being generated.
- When a function is inlined, don't put it on the worklist, so we
don't generate bodies for functions that are inlined at all calls.
- Recognize `@pragma("wasm:prefer-inline")` and inline functions
marked with this annotation.
- Enabled inlining by default.
- Set the default inlining limit to 0, so small functions are not
heuristically inlined by default.
Later changes will add annotations to selectively inline functions
that particularly benefit from it.
Change-Id: If8829833da5f8b8e4ce0655154fdc430db8928cc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/278909
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Joshua Litt <joshualitt@google.com>