Commit Graph

43 Commits

Author SHA1 Message Date
Martin Kustermann 96d8359e32 [dart2wasm] Cleanup closure related things
Move the creation of

* name of a lambda to `translator.functions.getLambdaFunctionName`
* type of a lambda to `translator.functions.getLambdaFunctionType`

Removes dependency on `w.FunctionBuilder` in the lambda code generators
- as they don't need access to the wasm function. This may allow
inlining closure calls in the future.

Avoid creating `w.FunctionBuilder` eagerly when analyzing closures and
instead create it only when there's a call to it (or the closure object
gets instantiated).

Use `CallTarget` abstraction when invoking lambdas.

Avoid carrying around
`(lambda, enclosingMember, enclosingMemberClosures)` throughout
the codebase and instead store this information on `Lambda`.

=> All these changes make the codebase more uniform between
   lambdas and normal functions and also is net code removal.

Change-Id: Ib69566ea9580827be0ed52c0c179884e84599d88
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/501983
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
2026-05-11 01:48:14 -07:00
Martin Kustermann a3deacfd58 [dart2wasm] Remove unused annotations and field
Change-Id: I83a9bd6a8aedb5312381b975c49e287ee76bc11b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/501141
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2026-05-07 03:46:02 -07:00
Martin Kustermann 4ee6a66270 [dart2wasm] Format pkg/dart2wasm after language version was increased
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>
2026-03-26 04:32:19 -07:00
Nate Biggs a484bb3973 [dart2wasm] Use constants to represent dummy values.
Today "dummy values" are generated per-module to stand in for things
like default parameter sentinels (where a given selector has multiple
default values for an optional parameter).

However, these values can end up crossing between modules. The logic is
set up to use ref_eq to check if an argument is one of these dummy
values. However, if one of these dummy values crosses between modules,
the passed value vs the ref_eq checked value will be different. Since
each module has its own canonical dummy value per type.

This new layout simplifies our handling of these dummy values by
treating them as Constants so that our normal module canonicalization
logic applies to them. We already have plenty of logic to canonicalize
constants across modules. This avoids the need for custom handling of
these dummy value globals.

Change-Id: Ia9c79923c788d7712b16705193ffbf3142141b5d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/480320
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2026-02-19 12:48:49 -08:00
Ömer Ağacan 02a3163219 [dart2wasm] Catch JS exceptions with the right tag, improve toString and stack traces
Example:

    import 'dart:js_interop';

    @JS()
    external void eval(String code);

    @JS()
    external void throwFunction();

    void main() {
      eval('''
        self.throwFunction = function() {
          throw new Error('Hi from JS');
        }
      ''');
      try {
        throwFunction();
      } catch (e, st) {
        print(e);
        print(st);
      }
    }

Output before: ("..." parts are code locations, omitted)

    JavaScriptError
        at module0.main ...
        at module0._invokeMain ...
        at InstantiatedApp.invokeMain ...
        at main ...
        at async action ...
        at async eventLoop ...

Output after:

    Error: Hi from JS
        at self.throwFunction ...
        at _277 ...
        at module0.main ...
        at module0._invokeMain ...
        at InstantiatedApp.invokeMain ...
        at main ...
        at async action ...
        at async eventLoop ...

Fixes #62218.

Issue: https://github.com/dart-lang/sdk/issues/62218
Change-Id: Ia9347e938af209b8b87752479d35b6236f721acf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/469062
Reviewed-by: Martin Kustermann <kustermann@google.com>
2026-01-02 02:27:58 -08:00
Martin Kustermann e502e9049c [dart2wasm] Make <xxx>.enclosingModule an ir.Module.
We have a relatively clean separation between the data structures
representing a wasm module (e.g. `Module`) and the classes used to
build such a module (e.g. `ModuleBuilder`)

Though with deferred loading changes the core IR data structures started
to get a `ModuleBuilder get enclosingModule` getter.

This CL makes the IR classes self-contained again.

=> The `enclosingModule` getter will now return a `Module` instead of a
   `ModuleBuilder`

=> The `*Builder` classes that need a `ModuleBuilder` can store that
   themselves but only pass up `Module` to IR classes.

Since the IR data structures are cyclic (the `Module` has various parts
that refer back to it via `enclosingModule`), we allow the `Module`
object to be constructed in an uninitialized state and initialize it
after building the module is done.

Issue https://github.com/dart-lang/sdk/issues/60928

Change-Id: I5fddd6ca43b662a6e6c328230e91b1bc75332deb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/451720
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2025-09-26 04:11:19 -07:00
Martin Kustermann 2fc0c8bf08 [dart2wasm] Some refactorings of the compiler
a) Usage of `ClassInfo.*`

We have an abstraction layer that translates dart types
to wasm types - which is the `Translator` object (it
has e.g. `Translator.translateType`).

=> We remove direct use of `ClassInfo.*` in most places
=> Instead of exposing `ClassInfo` for specific types
   (e.g. top type), we expose the wasm representation type

b) Type of `ClassInfo.repr`

Currently `ClassInfo.repr` is itself a `ClassInfo`, which is
rather confusing. We use `ClassInfo.repr` to determine how to
translate `InterfaceType`s of that class to the wasm type system.

=> We make `Class.repr` be an actual wasm representation type
   (we make it a `w.RefType`)

c) We create a macro assembler `loadClassId` method so we have
   one place where we load the class id and we verify in
   assertions that the receiver type is `ref #Top`.

Change-Id: Ie24008a98131dae34948406a1f5aec881499c1f0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/431080
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
2025-05-28 01:12:19 -07:00
Ömer Ağacan 82282b6287 [dart2wasm] Generate local names in the names section
Local names for function value parameters and for "precise this", return
values are generated, state indices in `async` and `sync*` functions are
generated.

We can generate names for more locals as needed.

Change-Id: Ie919f030f0bfae8adbca90408509dd04a7414278
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/419200
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2025-04-02 01:52:18 -07:00
Ömer Ağacan dad797e04a [dart2wasm] Remove unused default states in br_tables in state machines
When generating the `br_table` for the state machines in `sync*` and
`async` functions, we currently generate a default state (required by
`br_table`) with an `unreachable` instruction.

Instead, remove the default state and make the last state in the
function the default state.

This saves a few instructions per `sync*` and `async` functions.

Issue: https://github.com/dart-lang/sdk/issues/60433
Change-Id: Ie89c3581304a97082628b150cc5604f9e4c2849e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/419540
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2025-04-01 05:01:13 -07:00
Nate Biggs a4a4ca8a41 [dart2wasm] Dynamic modules
Missing from this implementation:
- Closure/dynamic calls with differing signatures
- Overrides with extra optional parameters
- Records with same shape defined in different dynamic modules
- Avoiding running TFA on dynamic module.
- Recompilation of only updateable functions from main module.
- Persist wasm def types from main module.

Testing is currently done locally via the dynamic_modules package test suite:
dart pkg/dynamic_modules/test/runner/main.dart --runtime=dart2wasm

Immediately after this lands we can introduce a new step to one of the wasm test matrix configurations that runs the above test suite (the VM has a similar configuration).

Change-Id: I3386d84be11b773842d45f4268a62a54c47e352b
Tested: Tested via new tests in dynamic_modules package. Tests run locally but will add to existing config.
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/397721
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-02-11 13:59:46 -08:00
Nate Biggs 7bea7d185d [dart2wasm] Add indirection for struct initialization.
For dynamic modules we will "adjust" the class ID at runtime to ensure each module gets independent class ID spaces.

This initial change simply provides the point where we will eventually add that logic.

Change-Id: Iad9c38d9e3e842be2e77c48b1755ebe57d02d023
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/400923
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2024-12-18 08:19:42 -08:00
Nate Biggs 946f3287b4 [dart2wasm] Clean up some dead or unnecessary code.
Change-Id: I01001194f67a908d710622c9b13678d94ce75b0b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/400922
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2024-12-17 08:49:05 -08:00
Nate Biggs b79a06d99b [dart2wasm] Add last few fixes to translator to allow module test mode.
- Declare dummy value globals as needed per module. We cannot share these across modules as they can be used in a const context which limits  how we can reference them. The other option is to declare the dummy values for all heap types in the main module. However, declaring as needed per-module is more in line with our approach elsewhere and will work better for dynamic modules.

Change-Id: Ib2cd0a9300610ff8aa86d904902815d4fe9042d7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/385401
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-09-23 18:56:24 +00:00
Ömer Sinan Ağacan 6d1f17133a [dart2wasm] Rename some code generator methods
Per suggestions in https://dart-review.googlesource.com/c/sdk/+/370500,
rename:

- CodeGenerator.wrap -> translateExpression
- CodeGenerator.visitStatement -> translateStatement

Motivations:

- visitStatement is confusingly named: it's not a part of the visitor
  interface.

- wrap doesn't always wrap, it also downcasts and unwraps.

- These methods are the entry points for compiling expressions and
  statements, so it makes sense for them to be named consistently.

  Alternative namings could be: compileExpression/Statement,
  generateExpression/Statement.

Change-Id: I4e4ef53a7d9a04e3686b0ed3a80f4b7f0a26ee5f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/374080
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2024-09-17 12:02:59 +00:00
Nate Biggs 56536825ed [dart2wasm] Add deferred loading support to dart2wasm (10/X).
Remove all references to a global `ModuleBuilder` (code like `ModuleBuilder get m => ...`). References to module builders should be more specific now, whether that be to the `mainModule` on Translator or some other module.

Technically this could remain and always refer to the mainModule but making the name more specific makes it clear there is no single ModuleBuilder anymore and code that needs to access a ModuleBuilder will need to consider which one it needs.

Change-Id: I140c4e80a131a1786fa66c93be07a622dd0756c3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381443
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-09-04 21:58:12 +00:00
Nate Biggs c5bd4d05db [dart2wasm] Add deferred loading support to dart2wasm (6/X).
Wasm globals serve a few purposes in the compiler such as storing static fields and closure vtables. Sometimes the access of these globals will be from a different module than the ones they're defined in. We need some indirection to be able to access them in these cross-module situations.

This change adds getter and setter functions that can be called via the StaticTable when a global needs to be accessed from a different module.

We use References to track the owning module for each global to determine if we can access it directly or not.

Change-Id: I93191c83dee1b7a47171c5808e64b071479cdeea
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381324
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-09-04 21:58:12 +00:00
Nate Biggs 3b4ab02425 [dart2wasm] Add deferred loading support to dart2wasm (3/X).
Adds some simple module predicates and helpers. Uses them to add support for multimodule exception tags. If we have multiple modules we need to share the same exception tag between them so that error handling works. We do this by defining and exporting the tag in the main module and importing it into subsequent modules.

Change-Id: Id458453033db4c11914943231104d2d004abf719
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381321
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-09-04 21:58:12 +00:00
Nate Biggs 5ca6b36bf1 [dart2wasm] Add deferred loading support to dart2wasm (0/X).
Remove code similar to `m.types` from the compiler. With upcoming changes there will not be a global `ModuleBuilder` to get the `TypesBuilder` from. There will be multiple modules being built at once.

Change-Id: I42c6616f2babb28e14ad418ffd9e8e9b3f3e946e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381342
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-09-04 21:58:12 +00:00
Martin Kustermann 85ae8e03eb [dart2wasm] Make compiler use a compilation queue of compilation tasks
This creates a centralized loop that iterates over wasm functions to be
compiled. That centralized loop can then e.g. act on `--print-wasm`,
etc.

Migrate synthetic wasm functions to also use this compilation queue.

(We also remove the --export-all flag which is unused and untested)

Change-Id: I7a9384716c69ea2dd80424ff3dd7f736ac943f14
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/378703
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2024-08-06 12:02:29 +00:00
Martin Kustermann 786742f34c [dart2wasm] Refactor code generation into class hierarchy.
A `CodeGenerator` can generate code not only for a member but also for
e.g. sub-parts of a member (e.g. lambdas, state machine functions, etc).

=> Remove `CodeGenerator.reference`.
=> Have a `CodeGenerator.enclosingMember`.

A `CodeGenerator` has functionality that isn't relevenat for some
subclasses, e.g. `StateMachineCodeGenerator`.

=> Make a class per kind of function we generate code for.
=> Pull functionality only related for a specific kind of function into
   the subclass.
=> Make those subclasses have the actual member (e.g. Constructor) they
   generate code for.

Seperate creation of `CodeGenerator` from deciding whether to inline the
code or not.

=> Make `CodeGenerator.generate()` take `paramLocals` & `returnLabel`

Have a base `CodeGenerator` base class and a `AstCodeGenerator` subclass
that contains most AST related code generation.

=> This is preparation for having non-AST `CodeGenerator`s

Change-Id: I42224eefa85fca6350272b0d8c821bad939637fb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/378660
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2024-08-02 10:26:57 +00:00
Martin Kustermann e245b63858 [dart2wasm] Ensure a [CodeGenerator] is used to generate code for one function only
Refactors the async/async*/sync* generation to use a seperate
[CodeGenerator] for outer & inner functions.

This removes a hack where the [CodeGenerator]'s current function,
current instruction builder are modified while generating code.

=> This allows making the two fields on [CodeGenerator] final

This decoupling of generating outer and inner functions may be taken
further in the future to e.g. enable inlining the outer function.

Change-Id: I4fb61bfe2cb5c7045fc8edadebede027c40e9b8e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/378422
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2024-08-01 12:18:00 +00:00
Martin Kustermann 15818c52d8 [dart2wasm] Decouple various code from the current function that is being compiled
There's various components in the code generation that should not depend
on the current function. This is especially relevant when inlining, as
we want to emit wasm for the inlined body in the context of an unrelated
caller function. The codegen for the inlined body should therefore not
be aware or require knowing anything about the function it's being
inlined into.

Also results in net removal of code.

Change-Id: I808b6f10fa3f262ec7e0b5a4b2b6e42d60ff6582
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/378144
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
2024-08-01 08:59:39 +00:00
Ömer Sinan Ağacan fab56db71b [dart2wasm] Move common code generation routines to state_machine, fix sync*
This is the last part of the series of patches to implement missing
sync* features and fix bugs.

Move common code generation functions between async and sync* code
generators to the state_machine library, with the name
`StateMachineCodeGenerator`.

This class allows overriding parts that differ between the async and
sync* code generators.

Fixes tests:

- co19/Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_sync_t05
- language/sync_star/generator3_test/test1
- language/sync_star/generator3_test/test2
- language/sync_star/sync_star_exception_iterator_test
- language/sync_star/sync_star_exception_nested_test
- language/sync_star/sync_star_exception_test
- language/sync_star/sync_star_exception_current_test

Fixes #51343.
Fixes #51342.

Change-Id: Ife6eab43b2721b003ebf9bc0f03796748fd5df46
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/367041
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-05-21 14:53:58 +00:00
Ömer Sinan Ağacan 3863e78e80 [dart2wasm] Move yield finder to a shared library
- Generalize `YieldFinder` to consider both `await` and `yield` as a
  suspension point.

- Move it to `state_machine.dart`, reuse it in async and sync* code
  generators.

This is a change from
https://dart-review.googlesource.com/c/sdk/+/366663, moved to a spearate
CL to make revieweing easier.

The end goal is to share code generation for async and sync* code
generators.

Change-Id: I4c75c746f85b2fedf7c1117a20fcd32152573c6d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/367021
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2024-05-21 09:09:40 +00:00
Martin Kustermann 8ccb41284a [dart2wasm] Move type parameter bounds checks & parameter type check logic together with logic setting up variables
Change-Id: I47b8c1122f796b574281cfbd6f6f1049bdd0212b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/365221
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
2024-05-02 12:44:30 +00:00
Martin Kustermann 350954ae9d [dart2wasm] Fix this restoration code in sync* handling.
Noticed that the same bug that was fixed in [0] also exists in other
places.

=> Remove duplicated code & share in macro assembler.
=> Make use of this in async & sync* generator.

[0] https://dart-review.googlesource.com/c/sdk/+/364321

Change-Id: Id424ab5e8ed8ab70d19977d10cf80fb8b44b3872
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/364441
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
2024-04-25 10:38:35 +00:00
Kevin Moore 24ee108404 [dart2wasm] code cleanup
Upgrade to latest recommended lints (excluding a few)
Moved to switch expressions
Added a couple of lints about directives

Change-Id: Ibe84f97e84fb50132e61ac38903090447b058d84
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/355547
Commit-Queue: Kevin Moore <kevmoo@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-03-05 16:57:47 +00:00
Martin Kustermann 5c06035575 [dart2wasm] Improve dispatch table call
The compiler would perform O(n) operation (where `n` is number of
classes that implement a selector) every time a GDT call is made.

Change-Id: I428a69faa0f5d83e11b3948fd7e009f49c1acba1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/348400
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2024-01-25 22:16:41 +00:00
Ömer Sinan Ağacan 4d3895a7b3 [dart2wasm] Fix sync* iterable element types
Fixes tests:

- co19/Language/Functions/element_type_A01_t03
- co19/Language/Functions/element_type_A01_t04
- co19/Language/Functions/element_type_A01_t06

Fixes #54413.

Same change for `async*` functions was made in
https://dart-review.googlesource.com/c/sdk/+/342561.

Change-Id: Ib9e23b3fff9e2f1b952b5ba114ec70d5a8aea372
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/343141
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2023-12-22 20:02:46 +00:00
Aske Simon Christensen dd602467dd Reland "[dart2wasm] Use a separate Wasm struct for every Dart class"
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>
2023-10-19 09:45:04 +00:00
Jackson Gardner 665aaefd8c Revert "[dart2wasm] Use a separate Wasm struct for every Dart class"
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>
2023-10-11 16:55:16 +00:00
Aske Simon Christensen 2cbb5eabca [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>
2023-10-10 14:35:53 +00:00
Jess Lally 3c4d4ad450 Reland "[dart2wasm] Replace struct.new_default with struct.new for object allocation."
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>
2023-09-26 10:07:42 +00:00
Johnni Winther 8d7198661e [cfe] Make more visitor pure interfaces
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>
2023-09-14 08:16:49 +00:00
Jackson Gardner 67f0d4daf0 Revert "[dart2wasm] Replace struct.new_default with struct.new for object"
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>
2023-09-12 20:16:56 +00:00
Jess Lally 5a4b252252 [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>
2023-09-07 09:52:57 +00:00
Jess Lally 700c7e3b3f [dart2wasm] Remove Closures dependency on CodeGenerator
Change-Id: Ie18bdc704ca8a3459bde1bd27e8ed7866239b737
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/318942
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Jess Lally <jessicalally@google.com>
2023-08-08 14:54:43 +00:00
Joshua Litt 96d6c2e0d3 [wasm_builder] Refactor to a builder / built pattern.
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>
2023-07-31 15:27:58 +00:00
Ömer Sinan Ağacan c74387a3a2 [dart2wasm] New async implementation
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>
2023-05-22 08:32:12 +00:00
Aske Simon Christensen 4733f9b754 [dart2wasm] Fix accesses to type arguments in sync* functions
Fixes the `Iteration` benchmark.

Change-Id: I947c413524a3d55d19f56d0bfbb45dc5125e972a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287467
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
2023-03-08 17:02:22 +00:00
Ömer Sinan Ağacan 0ad9f2ec66 [dart2wasm] Move covariance checks from async inner to wrapper functions
New passing test: language/async/covariant_type_test

Fixes #51601

Change-Id: Id5e807b463db67d0e44842e375d35604e35398cd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286462
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
2023-03-08 11:22:51 +00:00
Ömer Sinan Ağacan 004b400dfb [dart2wasm] Implement type parameter bound checks
New passing tests:

- language/generic_methods/bounds_test/02
- language/covariant/subtyping_test
- language/covariant/type_parameter_test
- language/records/simple/type_checks_test

Fixes #51358

Change-Id: I6854f71cbfc47106f685a00c36a64330cc0a57f3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/282660
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
2023-02-21 18:56:16 +00:00
Aske Simon Christensen 321f2e9b65 [dart2wasm] Implement sync*
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>
2023-02-09 11:07:01 +00:00