Commit Graph

135 Commits

Author SHA1 Message Date
Ömer Ağacan 0246c485e0 [dart2wasm] Check types of JS references when boxing JSValues as non-interop types
To make sure Dart values with typed data types like `Uint8List`, `List`,
`String` etc. hold the right type of JS values, check types of JS
references in boxing functions that return Dart typed data types.

To reflect what the functions actually do, and for consistency with
other functions, boxing factory names are changed from `fromJSArray` to
`fromRef`.

New boxing functions `fromRefUnchecked` added for the call sites that
already know the reference type to be the right type, for example in
`dartifyRaw`.

These unchecked functions will also be used in CL 424021 where we
replace some `dartifyRaw` calls with more precise "dartify" functions
that only converts when the type is right. (`dartifyRaw` always boxes
the argument regardless of the type)

Issue: https://github.com/dart-lang/sdk/issues/60357
Change-Id: Icdfb49b9b235d35af2af0c4be51b295ee68d99fc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/429362
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2025-05-20 09:38:12 -07:00
Martin Kustermann 7882084ab5 [dart2wasm] Correctly deal with abstract members in selector building
When we create a `Selector` we compute various information
based on all members belonging to that selector. Before this
CL this was split up: Some things like `ParameterInfo` was
calculated&updated while discovering members, others was
calculated after all members were discovered.

We now make all fields whose value depends on knowing all
members `late final` and initialize those fields after
having found all members of a selector.

When we compute the `ParameterInfo` of the selector we take
special care:

If there's non-abstract implementations and the selector is
not overridable by dynamic modules then we create the
`ParameterInfo` by looking only at the non-abstract members

=> This increases precision as we ignore the types and
   default values of optional parameters for abstract members

If there's no implementations of the selector it may still be
referred to by instance invocation AST nodes (which are
unreachable). The current code generator still needs a
`Selector.signature` in order to evaluate arguments for such
nodes.

=> We calculate `ParameterInfo` based on the abstract member
   and use `defaultSentinel` for optional parameters.

If a selector can have implementations in dynamic modules
then we cannot determine whether all implementations have
the same default value of optional parameters.

=> We calculate `ParameterInfo` using `defaultSentinel`
   value for all optional parameters. Ensuring the caller
   doesn't pass them but the callee will default to it's
   default value if it wasn't passed by caller.

See added test case for when we (before this CL) may
use unreachable members in the param info / signature
calculation and how that could lead to a compiler bug
(before this CL) due to a missing
 `VariableDeclaration.initializer`

TEST=web/wasm/unreachable_selector_implementation_test

Change-Id: I3628177f8e93c5d24ff0eb0ff8fee6121a4a08d1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/428541
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2025-05-19 06:46:18 -07:00
Robert Nystrom ba40d9bece Format tests/web/ using the 3.8 formatting style.
Change-Id: I73edeeaf4934899b71d6335dcb4b4b54dce46bae
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/426340
Auto-Submit: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-05-02 20:17:11 -07:00
Ömer Ağacan 6952a80978 [dart2wasm] JS interop: pass small ints as i31ref
In V8, the only way to pass a Wasm integer or float to JS without
allocation is by passing it as a 31-bit integer.

This can be done by:

1. Passing as `i32`. If the integer fits into 31 bits it's passed
   without allocation.

2. Passing as externalized `i31ref`.

(1) requires importing the JS function with different signatures: for
each `int` argument we would need a signature with the `i32` as the Wasm
argument type, and another with `externref` (or `f64` if we want to pass
large integers as `f64`).

This is not feasible as with a JS function with N `int` arguments we
would need `2^N` imports. So we implement (2): we import each interop
function with one signature, passing `externref` as the argument, as
before. When the number fits into 31 bits we convert it to an `i31ref`
and externalize it. Otherwise we convert the number to `externref` as
before, by calling the JS function `(o) => o` imported with type `[f64]
-> [externref]`.

New benchmark checks `int` passing for small (31 bit) and large (larger
than 31 bit) integers. Results before:

    WasmJSInterop.call.void.1ArgsSmi(RunTimeRaw): 0.020 ns.
    WasmJSInterop.call.void.1ArgsInt(RunTimeRaw): 0.018 ns.

After:

    WasmJSInterop.call.void.1ArgsSmi(RunTimeRaw): 0.014 ns.
    WasmJSInterop.call.void.1ArgsInt(RunTimeRaw): 0.018 ns.

Issue: https://github.com/dart-lang/sdk/issues/60357
Change-Id: I749001e0e7e9784114415439298c2f3e0fb974b3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/419880
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2025-04-11 04:14:04 -07:00
Ömer Ağacan 27d2904b0a [dart2wasm] Compare named argument names by equality instead of identity
This fixes #60059 when `--minify` is not used.

With minification we expect that runtime and const symbols won't be
equal or identical, even when the symbol names are the same.

Issue: https://github.com/dart-lang/sdk/issues/60059
Change-Id: Id6560558e2bd00cd9bef1f0026e2bd92a74d82fc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/414783
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2025-03-25 08:05:54 -07:00
Ömer Ağacan cf9f45f1d4 [dart2wasm] Copy VM's map and set factory transformers
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>
2025-03-19 08:10:16 -07:00
Martin Kustermann f1d81e337c [dart2wasm] Ensure tests/web/wasm/issue_56234_test runs in unoptimized mode
This test is a regression test for a dart2wasm compiler crash. It tests
that the compiler doesn't crash anymore but the error happens at
runtime.

The particular error that will happen at runtime is that `unreachable`
will be hit (in the place where a unboxed double is attempted to be cast
to an unboxed integer).

Since we run binaryen with `--traps-never-happen` it may optimize this
`unreachable` away and make the test accidentally pass.

So we force this to be run in `-O0` mode, which means we don't run
binaryen on it.

Change-Id: I6460982d4b32d773ee763e9687c8fec0bffa00f0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/415881
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2025-03-18 03:22:49 -07:00
Martin Kustermann 20fc102287 [dart2wasm] Switch to only using JS strings
Currently we have 3 different string types (JS Strings, OneByteString
and TwoByteString)s. There's some advantages to this, mainly that
if strings are used purely inside Dart we have more control over
optimizing them. But it does come with some issues

* Operations on mixture of strings are slow
* We get JS strings from outside (in DevTools e.g. websocket messages)
* Any kind of DOM interaction requires copying strings
* Regular expression matches can result in O(N*N) instead of O(N)
* Encoding of string literals/constants is terrible, high size overhead
* ...

Now that there's a standardized way to access JS strings (via
the `js-string` builtin spec) and this standard is finalized and
enabled in Chrome & Firefox it makes sense for us to switch to it.

It reduces app size:

* Smaller size: hello world -25%, flute -5.5%
* Faster startup

The performance changes are nuanced, some workloads will improve
significantly, some workloads will regress.

Improvements will come especially in cases where
strings are concatenated (due to JS not actually allocating new
strings in this case). That impacts e.g. string interpolations,
string buffer, json-to-string encoding, ...

Regressions will come especially for cases where we have to
construct strings from bytes (e.g. in utf8 decoder, utf8+json
decoder) - mainly due to having to go through an intermediary
`WasmArray<WasmI16>` to allocate strings. Also in cases where we
access individual char codes from the strings.

There's some follow-up improvements we can do, but it's better to
not iterate on this CL even longer but get it landed.

This CL will make the benchmarking system use
`--require-js-string-builtin` as well as most of test CI
(in `pkg/dart2wasm/tool/compile_benchmark`)

Though we run some configurations via overriding with
`--no-require-js-string-builtin`
(in `tools/bots/test_matrix.json`)

Issue https://github.com/flutter/flutter/issues/159400#issuecomment-2538593980
Issue https://github.com/dart-lang/sdk/issues/59699

TEST=ci

Change-Id: I238ac65efe092de569da870f23134f889ac929f9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/392903
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2025-02-27 00:33:34 -08:00
Nate Biggs 05d293aac2 Move web regression tests into langauge suite.
Change-Id: Id1b61a345be94965f2ca8da228d694a1e13d2f92
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/406381
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Nate Bosch <nbosch@google.com>
2025-01-29 12:00:13 -08:00
Nate Biggs b969f32a76 [dart2wasm] Store exception/stacktrace for nested catch blocks.
The async state machine uses a single state in the heap to store the current exception and stacktrace when within a catch block in case they need to be rethrown. When catch blocks are nested this state can be overwritten.

With this new change, before entering a new catch we store the current value of the exception/stacktrace in a local that we can restore after exiting the associated catch blocks. A wasm catch can represent multiple Dart catch blocks so we only need to store the state per wasm catch.

Fixes: https://github.com/dart-lang/sdk/issues/59981
Change-Id: I738084fdecdf5aceac65c5d3698e40b791175171
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/405920
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-01-27 07:58:31 -08:00
Ömer Sinan Ağacan 78ce85a7fe [dart2wasm,tfa] Don't infer class of string values in comparisons
In dart2wasm, when a comparison like `x == "hello"` is true, we can't
assume that the class of `x` is the same as the class of `"hello"`:

- If `x` is received from JS, it will be `JSStringImpl`.
- If it's a substring of a `TwoByteString`, it will be `TwoByteString`.
- Otherwise it will be `OneByteString`.

Update `Target` with the new method

```
bool get canInferStringClassAfterEqualityComparison => true;
```

to allow TFA to *not* infer classes of string values after comparisons.

Override the method to return `false` in dart2wasm's `Target`
implementation.

Fixes #59901.
Tested: web/wasm/issue_59901_test
Change-Id: I1a6c8deaf27c54240dd4e821dbd8160914502ad7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/404562
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2025-01-16 03:24:39 -08:00
Nate Biggs d80fab4a8a [dart2wasm] Fix dynamic switch casts.
If the switch's expression has type 'dynamic' and all the case expressions have the same type, we compare them using '=='. This requires a cast to ensure all the types match for the dispatch to the '==' function. However, we don't check that the type of the switch expression matches the type of the case expressions. So the cast fails if they don't match.

This adds a guard to ensure the types match before running through the case expressions. If the guard fails, we either jump to the default case or if there isn't one, we skip the switch entirely.

Fixes: https://github.com/dart-lang/sdk/issues/59782
Change-Id: I12e81f98d1c2046ee47e8ca4371642fd40620636
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/402460
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2025-01-07 11:44:30 -08:00
Nate Biggs fb5fbf1dec [dart2wasm] Fix null checks being added on non-nullable value types.
Bug: https://github.com/dart-lang/sdk/issues/59840
Change-Id: Ifaac6430eabfee21e4971b3dd864e22f65c80adf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/402980
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-01-06 10:32:33 -08:00
Nate Biggs d82e84ca2f [dart2wasm] Fix tearoff codegen on boxed types.
The struct type for closures requires the context value be a struct. If the tearoff is on an unboxed value, it first has to be boxed before being used to create the closure struct.

The new test currently fails at runtime (or via assertions at compile time) with this error:
"BoxedInt.abs tear-off" failed: struct.new[2] expected type (ref struct), found local.get of type i64

Change-Id: Ie861bc12a34b21f8b3415edadf55ce3d59f97580
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/402560
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-01-06 10:23:43 -08:00
Nate Biggs 3b056e1d50 [dart2wasm] Fix deferred loading tests on optimized configs.
Add -O0 to failing tests so that binaryen is not run on them in any configuration.

Also skip 'multi_module_stress_test' on d8/jsshell/jsc as these runtimes fail when trying to create a DataView of the necessary files:
https://github.com/dart-lang/sdk/blob/main/sdk/lib/_internal/wasm/lib/js_typed_array.dart#L2460

Bug: https://github.com/dart-lang/sdk/issues/59736
Change-Id: Iccc96fde01776f0179c888ac6bbe13a81d0ee847
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/401380
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-12-18 01:14:17 -08:00
Martin Kustermann 9b11bf4da9 [dart2wasm] Take advantage of fast js-string builtins
Some wasm engines have started to optimize the `js-string` builtin
proposal (e.g. V8) and those that haven't yet are probaly going to
do soon.

So we can start taking advantage of it in dart2wasm.

=> We make use of them in the JS<->Dart string copy code.

=> This will also provide a better baseline when evaluating whether
   switching to JS stringes entirely makes sense.

A somewhat unrelated (but necessary for this CL) change is to tighten
the types we use in `@pragma('wasm:import')` and
`@pragma('wasm:export')` in some cases:

We should only use 'pure' wasm types (i.e. not wasm struct / function
types we define for dart classes & functions) and mostly non-composed
types in import/exports as the `--closed-world` optimizations from
binaryen rely on that (and error otherwise).

Overall this leads to significant improvements in Dart<->JS
string copies.

The `WasmDataTransfer.*{From,To}BrowserString` benchmarks
improve something between 50-100%.

Change-Id: I2048113c462ecb2047402c0616d2b3b1f45773f5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/400641
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
2024-12-16 00:55:26 -08:00
Robert Nystrom d7ed15658a Opt multitests out of formatting in web/.
The new formatter supports opting a region of code out from being
formatted. I'm applying this marker to all of the multitests since
those tests are often very sensitive to formatting and easily broken.
This way, anyone touching a multitest (including me when I reformat
the tests) doesn't have to remember to not run the formatter on it.

Change-Id: I3d6346d31581772dc8e1701594bf9d919f28db7d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/396104
Commit-Queue: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Srujan Gaddam <srujzs@google.com>
Auto-Submit: Bob Nystrom <rnystrom@google.com>
2024-11-19 00:59:10 +00:00
Martin Kustermann a96ad1b176 [dart2wasm] Add ImmutableWasmArray to dart:_wasm
Dart does not incorporate immutability into it's type system.
Though the WasmGC type system does have such a concept:

  * mutable wasm arrays: they are invariant in the element type
  * immutable wasm arrays: they are covariant in the element type

Currently we use the mutable wasm array types for e.g.

  const foo = const WasmArray<WasmI32>.literal([0]);

which will be compiled to

  (type $Array<WasmI32> () (array (field (mut i32))))
  (global $globalFoo
         (ref $Array<WasmI32>)
         (i32.const 0)
         (array.new_fixed $Array<WasmI32> 1
  )

=> Notice the **mut** in `array (field (mut i32))`

This CL introduces a `ImmutableWasmArray` which is analogous to
`WasmArray`. The array supports only reading methods since the
contents of the array cannot be modified.

Future CLs will make use of this new array type in various places.

=> This will allow binaryen to optimize things better as it knows the
array contents cannot change.
=> So loads from a (final) global with immutable contents can be
folded away at compile time if the index is known at compile-time.

NOTE: The `WasmArray`& `ImmutableArray` classes are not related to
each other. The reason is that in WasmGC a mutable array isn't a
subtype of a immutable array.

Change-Id: I3a764b5aaa3ac47827332f3064035133ab01f1b2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/392900
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2024-10-31 19:04:27 +00:00
Ömer Sinan Ağacan 9046485cda [dart2wasm] Add function names to source maps
Annotate code with the enclosing Dart function names.

Fixes #56718.

Change-Id: I1d53fc3752580514aa92b3d62ec717c93ad58d66
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/386780
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2024-10-18 07:43:41 +00:00
Martin Kustermann 0dd5d3e24f [dart2wasm] Roll binaryen to newer version
Change-Id: I5176e71d0680d66db6f81b5d7003129afd70fb4a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/389962
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2024-10-15 11:30:25 +00:00
Lasse R.H. Nielsen f8086c81ae Collect all test-related files in package:expect.
Collects files from `package:async_helper` and `tests/language`
that are generally useful, so that all test-related helpers are
in `package:expect`.

Moves the two libraries from `package:async_helper` into `package:expect`,
and the `tests/language/static_type_helper.dart` file too.

Deprecates `async_minitest.dart`, to follow `minitest.dart`,
expecting the Flutter use of it to have been fixed to not break
on deprecation (I believe Flutter no longer breaks builds on deprecations at all).

Patch 1 is the actual change.
Patch 2+4+8 is changing all existing references to the files.
Patch 6 ignores deprecation in files still using `async_minitest.dart`.

3+5+7+9 are updating this text to make the numbers match.
Then it's just test-expectations and small tweaks from there.

Change-Id: I1b665135b5fef9b9a0c3b340ffe9daf874d0174c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/373120
Reviewed-by: Nate Bosch <nbosch@google.com>
Reviewed-by: Devon Carew <devoncarew@google.com>
Commit-Queue: Lasse Nielsen <lrn@google.com>
2024-10-11 16:53:52 +00:00
Nate Biggs 963c28a114 [dart2wasm] Allow tests to override jscm mode.
This allows tests that would fail in JS compatibility mode (e.g. tests that do a lot of string manipulation) to disable the mode for their own execution.

Also ensure dart2wasm-*-jscm-* builds do a "create_sdk" so that the dart2js platform dill is available for the test.

The alternative I considered was skipping the test but "--js-compatibility" is a dart2wasm-specific flag and the test infra is unaware of it so we can't skip the test via a status file.

Bug: https://github.com/dart-lang/sdk/issues/56858
Change-Id: I60179eaab2e4522acf1fe0b47c7c02ccb1ca957b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/388644
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2024-10-08 13:16:19 +00:00
Nate Biggs 7ba8957b12 [dart2wasm] Add FluteComplex multi-module stress test.
Change-Id: I2b13649d67d5b68211b6c15c745fd194773b9e7f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/386380
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2024-09-24 15:53:30 +00:00
Ömer Sinan Ağacan f80214eb86 [dart2wasm] Fix Uri.base in d8
Currently when the .wasm file path passed to run_wasm.js is a relative
path, `Uri.base` becomes something like `file://test.wasm`, which is not
a valid file URI, so it causes crashes in `Uri.toFilePath`.

When the file path is relative add a omit `file://` prefix.

`Uri.base` values before and after:

- Before, relative .wasm path: `file://test.wasm` (invalid)
- Before, absolute .wasm path: `file:///home/user/test.wasm`

- After, relative .wasm path: `test.wasm` (fixed)
- After, absolute .wasm path: `file:///home/user/test.wasm` (same as before)

Change-Id: I0d1c43716e07a9ee926e7feeeab514c2c66bac16
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/385700
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2024-09-24 10:21:52 +00:00
Nate Biggs 25706745bc [dart2wasm] Fix handling of user-defined _typeArguments members.
The dart2wasm transformer injects a `_typeArguments` into each class.
https://github.com/dart-lang/sdk/blob/main/pkg/dart2wasm/lib/transformers.dart#L201

This is a synthetic private member that gets handled specially. However, users can have their own private members with the same name so we have to ensure the intrinsic handler is only operating on synthesized members by looking at the library attached to the private name.

Bug: https://github.com/flutter/flutter/issues/154383
Change-Id: I04062bec1f2bcf9ce6420e749c417a65f676505d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/386040
Auto-Submit: Nate Biggs <natebiggs@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-09-23 21:15:06 +00:00
Nate Biggs 1d392255ef [dart2wasm] Add wasm module test mode.
Adds a mode that puts every library (outside of the SDK) into its own wasm module. Each module is then loaded before the program executes.

This allows us to get better coverage on multi-module logic.

I chose to augment the SDK `_invokeMain` entry point because it allows us to push the user-defined main into a second module ensuring we always have at least 2 modules. The SDK alone is then the main module and all user-code is in deferred modules.

The next step is to make a test configuration for this and decide what frequency to execute it with.

Change-Id: I01bf3a5fee4604a890ef376ebd35113281a36a5c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384404
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-09-23 18:56:24 +00:00
Nate Biggs 92727ab977 [dart2wasm] Check laziness of sub-constants for records.
All other constant types include similar logic.

This caused a failure when testing deferred loading logic. Laziness of static tear offs are module sensitive. A record containing a constant static tear off needs to match the inner laziness. Though there are other ways to get lazy subconstants that would also cause this to fail (e.g. very large strings).

Change-Id: Ia55b4f24a15e57b9721383726e7afb5f39557d5d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384980
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-09-12 17:59:36 +00:00
Nate Biggs b8ff81ea0d [dart2wasm] Fix while scoping in async generator.
The new test was resulting in an uninitialized late read of localContext here:
https://github.com/dart-lang/sdk/blob/main/pkg/dart2wasm/lib/code_generator.dart#L830

The `++i` results in a let expression declaring a new variable within the condition of the while loop.

The code linked above tries to look up the variable within the current context. The `ContextCollector` defines the while scope as including the while's condition:
https://github.com/dart-lang/sdk/blob/main/pkg/dart2wasm/lib/closures.dart#L1486

However, the AstCodeGenerator doesn't register the while's scope until after processing the condition:
https://github.com/dart-lang/sdk/blob/main/pkg/dart2wasm/lib/code_generator.dart#L1248

So when processing the condition, the loopkup happens on the scope above the while even though the variable is captured on the while's scope.

A synthetic let statement is the only way to get a variable declaration within a while's condition. And it wouldn't otherwise be captured (a closure can't reference it) but async function bodies mark all variables as captured.

Change-Id: I5f8fdd69d4875c099a21505cd588b08cacdd86c1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384863
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-09-12 17:59:36 +00:00
Ömer Sinan Ağacan c8a7922160 Reland "Reapply "[dart2wasm] Allocate boxed bools once" and "[dart2wasm] Box Pointer values obtained from FFI calls""
This is a reland of commit fca5417d49

- Patchset 1 is the reland.
- Patchset 2 adds a regression test and fixes the bug.

Also tested engine chrome-dart2wasm-html-engine,chrome-dart2wasm-html-html,chrome-dart2wasm-html-ui,chrome-dart2wasm-canvaskit-canvaskit,chrome-dart2wasm-canvaskit-ui,chrome-dart2wasm-skwasm-ui tests manually.

Original change's description:
> Reapply "[dart2wasm] Allocate boxed bools once" and "[dart2wasm] Box `Pointer` values obtained from FFI calls"
>
> This reverts commit a4e9775a99.
>
> - Patchset 1 reverts the revert.
>
> - Patchset 2 adds regression tests. These tests fail.
>
> - Patchset 3 and the rest fixes the bug in `_loadPointer` and
>   `_storePointer` intrinsics. Also adds some inline annotations to
>   reduce the noise in unoptimized builds.
>
> Tested: updated test web/wasm/ffi/ffi_native_test
> Change-Id: I748a8aa8ff7cc663b1980d2bfab0d0da9f369e3b
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384760
> Reviewed-by: Martin Kustermann <kustermann@google.com>
> Commit-Queue: Ömer Ağacan <omersa@google.com>

Tested: web/wasm/ffi/ffi_native_test updated. Manual run of engine chrome-dart2wasm-html-engine,chrome-dart2wasm-html-html,chrome-dart2wasm-html-ui,chrome-dart2wasm-canvaskit-canvaskit,chrome-dart2wasm-canvaskit-ui,chrome-dart2wasm-skwasm-ui tests.
Change-Id: Ifcd5156b8a03228119b2146edcfc56db8ac6273b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384843
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2024-09-12 09:55:11 +00:00
Nate Biggs 91f099aa59 [dart2wasm] Fix switch statements containing jumps but no awaits.
This would throw when compiling before because there was no label target recorded for the target case statement.

Change-Id: Id00af345cf2a167a079f6ef8c077fa97cffdb3f3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384587
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2024-09-11 18:42:23 +00:00
Ömer Ağacan d146083865 Revert "Reapply "[dart2wasm] Allocate boxed bools once" and "[dart2wasm] Box Pointer values obtained from FFI calls""
This reverts commit fca5417d49.

Reason for revert: https://ci.chromium.org/ui/p/flutter/builders/try/Linux%20Engine%20Drone/2677631/overview

Original change's description:
> Reapply "[dart2wasm] Allocate boxed bools once" and "[dart2wasm] Box `Pointer` values obtained from FFI calls"
>
> This reverts commit a4e9775a99.
>
> - Patchset 1 reverts the revert.
>
> - Patchset 2 adds regression tests. These tests fail.
>
> - Patchset 3 and the rest fixes the bug in `_loadPointer` and
>   `_storePointer` intrinsics. Also adds some inline annotations to
>   reduce the noise in unoptimized builds.
>
> Tested: updated test web/wasm/ffi/ffi_native_test
> Change-Id: I748a8aa8ff7cc663b1980d2bfab0d0da9f369e3b
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384760
> Reviewed-by: Martin Kustermann <kustermann@google.com>
> Commit-Queue: Ömer Ağacan <omersa@google.com>

Change-Id: I2cb55b6d2fdf429c5a0634329079e9df7e9e5871
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384841
Reviewed-by: Martin Kustermann <kustermann@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2024-09-11 17:06:58 +00:00
Ömer Sinan Ağacan fca5417d49 Reapply "[dart2wasm] Allocate boxed bools once" and "[dart2wasm] Box Pointer values obtained from FFI calls"
This reverts commit a4e9775a99.

- Patchset 1 reverts the revert.

- Patchset 2 adds regression tests. These tests fail.

- Patchset 3 and the rest fixes the bug in `_loadPointer` and
  `_storePointer` intrinsics. Also adds some inline annotations to
  reduce the noise in unoptimized builds.

Tested: updated test web/wasm/ffi/ffi_native_test
Change-Id: I748a8aa8ff7cc663b1980d2bfab0d0da9f369e3b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384760
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2024-09-11 11:09:39 +00:00
Ömer Sinan Ağacan 0e58775986 [dart2wasm] Small improvements in FFI native tests:
- Document which target needs to be built for the test
  `web/wasm/ffi/ffi_native`.

- Add tests that passes and expects `double` and `float`s.
  (The `sqrt` native function was previous unused)

- Define inputs in `wasm_module` gn template so that the
  `ffi_native_test_wasm_module` target will rebuild the Wasm file when
  `tests/web/wasm/ffi/ffi_native_test_module.c` changes.

Change-Id: Iff642ff2cdee48a617e8f2cf4cca4053122a7e05
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384263
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2024-09-10 09:51:41 +00:00
Martin Kustermann 7ebc3f7f31 [dart2wasm] Fix bug in --omit-implicit-checks
When `-O3` / `-O4` / `--omit-implicit-checks` are turned on then the
runtime type of tear off functions with covariant parameters was
incorrect.

=> The runtime type of any kind of function or object should always be
the same, irrespective of whether we're dropping some implicit or
explicit `as` checks - as the runtime type can also be observed via e.g.
`is` checks.

The issue was originally introduced in [0].

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

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

Change-Id: I5c64134e4735d73cf228e12b8eb3bd4767616e11
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384285
Reviewed-by: Ömer Ağacan <omersa@google.com>
2024-09-10 07:55:25 +00:00
Jason Simmons a4e9775a99 Revert "[dart2wasm] Allocate boxed bools once" and "[dart2wasm] Box Pointer values obtained from FFI calls"
This reverts commit d7a283de26 and commit d7a39788d4

The "[dart2wasm] Box `Pointer` values obtained from FFI calls" change causes a Flutter Web test to hang (https://github.com/flutter/engine/blob/main/lib/web_ui/test/fallbacks/fallbacks_test.dart)

Change-Id: Ia44bcf68cd6edc72697a0c2b05e05b4f8e1408fd
TEST=reproduced the hang locally and confirmed that it does not happen with this revert
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384321
Reviewed-by: Siva Annamalai <asiva@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Jason Simmons <jsimmons@google.com>
2024-09-09 20:10:06 +00:00
Ömer Sinan Ağacan d7a39788d4 [dart2wasm] Box Pointer values obtained from FFI calls
Currently `Pointer` argument and return types of `FfiNative` functions
are translated to Wasm as `i32`.

This causes problems when we need to box those `i32` values as we don't
track which Dart types Wasm types come from when converting a Dart type
like `Pointer` to a Wasm type like `i32`.

Currently this works somewhat accidentally. All `i32`s are boxed as
`BoxedBool`, including `i32`s that represent `Pointer`s.

This breaks when we need to get the type parameter of a `Pointer` (e.g.
in a `is` or `as` check), but more importantly it means that we can't
cache boxed `true` and `false` values and return those cached values
when converting an `i32` to a boxed type as we don't know whether the
`i32` represents a bool or pointer.

Ideally we would have some kind of intermediate layer between
`wasm_builder` and dart2wasm that allows types like "a Wasm i32
representing an unboxed T" (for some T).

Alternatively we could attach extra information to `ValueType`s, for
example using expandos or maybe by adding a `dynamic` field to the base
class.

However it's unclear whether it's worth doing a major refactoring, when
a simpler alternative exist: we box `Pointer` values obtained from an
import in the Dart wrapper for the imported function.

VM already boxes `Pointer`s, so the performance should be acceptable.

This CL implements this simpler alternative of boxing `Pointer` values.

Tested: web/wasm/ffi/ffi_native_test updated.
Change-Id: I02e5c07fdb021a7b51ed5db2a44123b1608c9aad
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/383325
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2024-09-05 11:24:10 +00:00
Martin Kustermann d769a9105b [dart2wasm] Adjustments to inliner
* Inline small `get iterator` & `get current` iterator methods
* Inline bodies that are small compared to arguments
* Make AST node counter more precise
* Manually mark ListIterator methods as prefer inline

CoreLibraryReviewExempt: Only adds annotation to existing functions
Change-Id: Ib6379e73713cd47a88e5cc67cecd4b5c8344adcb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/382882
Reviewed-by: Slava Egorov <vegorov@google.com>
2024-08-30 13:14:56 +00:00
Martin Kustermann 810301045d [dart2wasm] Make JS<....>Array.setRange(..., ...TypedListList()) faster
The fused utf8+json decoder ensures the bytes that it operates on are
U8List:

  void parseChunk(List<int> value, int start, int end) {
    if (value is U8List) {
      chunk = value;
    } else {
      final bytes = U8List(end - start);
      bytes.setRange(0, bytes.length, value, start);
      ...
    }
    ...
  }

This speeds up the `bytes.setRange()` call by using an optimized loop
that copies memory from JS arrays to wasm arrays.

=> This speeds up WasmDataTransfer.FromBrowserBytes.* by 10x
=> This speeds up Json*JS.*.FromBytes benchmarks by up to 3x

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

Change-Id: I99fd1db280f503e91972c53537d7cd1fd4fd49ff
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/382002
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2024-08-26 08:58:11 +00:00
Daco Harkes 3d44d5598f [dart2wasm][ffi] Don't crash compiler on Native.addressOf
`Native.addressOf` is not implemented in dart2wasm (yet).

However, crashing the compiler means we cannot use packages which use
`Native.addressOf` even if these are not invoked.

This CL changes these expressions to a `throw` at runtime. This enables
using the subset of packages that use `@Native`s.

Implementation note: The existing FfiNative transformer doesn't
recurse into visitors. And it extends the transformer for the VM which
doesn't recurse. So I don't want to change it to recurse over the
whole AST. Instead, this introduces a new transformer that traverses
the whole AST.

TEST=tests/web/wasm/ffi/ffi_native_test.dart
TEST=existing tests with rolling `package:ffi` in via DEPS.

Closes: https://github.com/dart-lang/sdk/issues/56461
Change-Id: If8fab07a852939a4b519ae7cc47b4071adda8a3a
Cq-Include-Trybots: luci.dart.try:dart2wasm-linux-jscm-chrome-try,dart2wasm-linux-firefox-try,dart2wasm-linux-d8-try,dart2wasm-linux-chrome-try,dart2wasm-asserts-linux-chrome-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/380260
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
2024-08-26 08:10:23 +00:00
Martin Kustermann f7fc4d0374 [dart2wasm] Fix partial instantiation constants
Partial instantiation constants are closures. Those closures have
vtables with all entries needed for the closure representation
corresponding to the instantiated closure.

The entries of those vtables have to either call the corresponding
method of the generic closure, or are unreachable dummy entries.

Dummy entries can be required due to clustering callees/callers together
where a particular target doesn't support the name combination.

The case that was incorrect is if the particular name combination did
not get clustered with anything for the generic closure representation.

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

TEST=web/wasm/regress_56372_test

Change-Id: Ifbf624e10dd1162f4d5660b43914e5b34ba82294
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/380100
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
2024-08-12 14:05:04 +00:00
Ömer Sinan Ağacan 1b1740e941 [dart2wasm] Pass source maps to wasm-opt when optimizing
To be able to know when we are generating a source map, make `dart
compile wasm` aware of the `--no-source-maps` flag.

The "name" segments of source mappings are also made `null` with this
patch. Browsers don't use that segment and binaryen doesn't support it.

Change-Id: I7b52c8fb7cef92ed60547e97ad137e0cd3967f26
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/378421
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-08-09 14:23:29 +00:00
Martin Kustermann 2cf3222e4f [dart2wasm] Fix bug in seter type checker argument checking implementation
The CL in [0] introduced a regression: By not performing the type
checking code in -O4 mode it didn't have the side-effect of the type
checking code anymore (setting the `argLocal`) which caused the setter
to store `null` instead of the actual value.

Patchset 1: Fix
Patchset 2: Make type checking code not have side-effects

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

Fixes https://github.com/flutter/flutter/issues/152029

TEST=web/wasm/flutter_regress_152029_test

Change-Id: Ia678d922ba766aa885224e069f5f4e04a4bf457a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/378800
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2024-08-03 07:53:40 +00:00
Ömer Sinan Ağacan 25169313d9 [dart2wasm] Avoid compiler crash when casting unboxed types
When omitting checks, casts between unboxed types currently cause a
compile-time crash when generating the conversion.

This compile-time crash is useful to catch compiler errors, but when the
checks are omitted it can be triggered on invalid casts, such as when
casting a `double` to `int`.

So when omitting checks, generate an `unreachable` (consistent with
other type cast failure when omitting checks) instead of crashing.

An alterantive implementation (see patchset 1) would be checking for
cast failures when compiling `as` expressions with omitted checks.
However it makes the code slightly more complicated, and more
importantly `unreachable` gets a wrong source span as it's generated
after the `wrap` to compile expression.

Fixes #56234.

Change-Id: Ia93a850d028a69320ff671efd8344843fa7c4388
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/375640
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-07-15 11:27:32 +00:00
Ömer Sinan Ağacan 10742d9a12 [dart2wasm] Generate source maps
This implements generating source maps for the generated Wasm files.

Copying dart2js's command line interface, a source map file with the
name `<program name>.wasm.map` is generated unless `--no-source-maps` is
passed.

When a source map is generated, the generated .wasm file gets a new
section `sourceMappingURL` with the contents `<program name>.wasm.map`.

This section seems to be undocumented, but Chrome and binaryen recognize
it as the URI to the source map file. Chrome is then loads it
automatically in the DevTools.

## Implementation

- `wasm_builder` package is updated with the new `source_map` library,
  which describes the source mapping entries.

- `wasm_builder`'s `InstructionsBuilder` is updated with the new public
  members:

  - `startSourceMapping`: starts mapping the instructions generated to
    the given source code.

  - `stopSourceMapping`: stops mapping the instructions generated to a
    source code. These instructions won't have a mapping in the source
    map.

- `CodeGenerator` sets the source file URI and location in the file
  when:

  - Starting compiling a new member
  - Compiling an expression and statement

Change-Id: Ic8f723f7a154402c0d34710689db57d640b83b86
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370500
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2024-07-04 09:25:39 +00:00
Martin Kustermann 689852e3f0 [dart2wasm] Fix new web/wasm/allow_import_export_pragmas_test test: Add --extra-compiler-option= before the flag name
This wasn't caught by default CI builders, because
default configurations use `pkg/dart2wasm/tool/compile_benchmark`
which passes all unknown flags to the compiler (for convenience
of local development) but `dart compile wasm` doesn't

Change-Id: I6a92d3f04848e027c92b1feee3d54e7efba9fd27
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/371661
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
2024-06-14 10:18:23 +00:00
Martin Kustermann 6f21d19b02 [dart2wasm] Add flag to allow experimental wasm interop.
Adds a flag users can use via

    dart compile wasm \
        --extra-compiler-option=--enable-experimental-wasm-interop

which allows code to import `dart:_wasm` and use import/export
pragmas.

Similar to how we have a way to import `dart:ffi`

    dart compile wasm \
        --extra-compiler-option=--enable-experimental-ffi

TEST=web/wasm/allow_import_export_pragmas_test (positive test)
TEST=web/wasm/reject_import_export_pragmas_test (negative test)

Change-Id: Ibdbbac6c3aa049b2759e96b7b749dd30ecc6aaed
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370063
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Jackson Gardner <jacksongardner@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2024-06-14 07:01:58 +00:00
Ömer Sinan Ağacan 4796b25a30 Reland "[dart2wasm] Check import/export pragmas in user code"
This is a reland of commit 35bc17a0fa

Changes from the original CL is that we now allow packages in
`allowedInteropLibrariesInDart2WasmPackages`.

Original change's description:
> [dart2wasm] Check import/export pragmas in user code
>
> Change-Id: I926d108a4571d685c67d3a174a8e506910cce8f7
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/369020
> Commit-Queue: Ömer Ağacan <omersa@google.com>
> Reviewed-by: Martin Kustermann <kustermann@google.com>

Change-Id: I69f61ecf246dfdbfcab372c6c2adb2a64f2d0b36
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370900
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2024-06-11 13:12:27 +00:00
Martin Kustermann 847c35612a [dart2wasm] Make dart compile wasm compiled apps disable dart.library.ffi
This is a follow-up to [0]. That CL changed dart2wasm's modular
transformer to issue an error if `dart:ffi` is imported.

Users of packages that have specialized code for the VM (which supports
FFI) use conditional imports based on `dart.library.ffi`. We don't want
the VM-specific code to be used for web in dart2wasm (as dart2wasm
doesn't support the entirety of `dart:ffi`).

As a result we're going to make `dart.library.ffi` be false in
coditional imports (as well as in
`const bool.fromEnvironment('dart.library.ffi')`).

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

Issue https://github.com/dart-lang/sdk/issues/55948
Issue https://github.com/flutter/flutter/issues/149984

Change-Id: I70a775278ab701d1fd2596521e378cb6364edac2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370580
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
2024-06-11 09:28:40 +00:00
Jackson Gardner 9fa160b706 Revert "[dart2wasm] Check import/export pragmas in user code"
This reverts commit 35bc17a0fa.

Reason for revert: Breaking flutter web engine unit tests: https://github.com/flutter/flutter/issues/149600

Original change's description:
> [dart2wasm] Check import/export pragmas in user code
>
> Change-Id: I926d108a4571d685c67d3a174a8e506910cce8f7
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/369020
> Commit-Queue: Ömer Ağacan <omersa@google.com>
> Reviewed-by: Martin Kustermann <kustermann@google.com>

Change-Id: Iba57910e7492abb7371172ecdb4fc2cc18fed66e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/369500
Reviewed-by: Siva Annamalai <asiva@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Jackson Gardner <jacksongardner@google.com>
2024-06-03 17:28:36 +00:00
Ömer Sinan Ağacan 35bc17a0fa [dart2wasm] Check import/export pragmas in user code
Change-Id: I926d108a4571d685c67d3a174a8e506910cce8f7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/369020
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-05-31 09:22:28 +00:00