Commit Graph

347 Commits

Author SHA1 Message Date
Martin Kustermann d38e30d65a [dart2wasm] Fix bug in JS typed data .sublist() implementations
Issue https://github.com/flutter/flutter/issues/179853

Change-Id: I97ce8d7177dfdd612714fafbc2a6b13555d9bba1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/468300
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2025-12-15 06:46:18 -08:00
Nate Biggs 43f234799e [dart2wasm] Fix JS callback wrappers invoked in deferred modules.
The generated callback wrappers were referring to exported functions via
'dartInstance.exports' which is always the main module. But in order to
avoid bloating the main module we put some of these JS exports into
submodules.

So the wrapper must be fetched from the correct module that defines the
wrapped function. In order to facilitate this we give each module a
self-reference that it can then pass up to the JS wrapper as an
externref.

Change-Id: Id2514de2c13d38a0cee1f6c935e45a9ef826f805
Fixes: https://github.com/dart-lang/sdk/issues/62094
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/464820
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-12-01 12:12:48 -08:00
Martin Kustermann c942b23b07 [dart2wasm] Fix access of constants under deferred load guard
When accessing a constant under a load guard we can push the constant to
the deferred module (as we only access it under the guard that the
module has been loaded). The access has to therefore also use the
constant initializer function from the deferred module.

We also remove `--extra-compiler-option` prefix for
`--enable-deferred-loading` as the prefix isn't recognized by
dartdev.

Change-Id: I58489303dc10bb265ef730c05a4fc78a8f598edb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/464980
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2025-11-28 03:23:01 -08:00
Martin Kustermann ba35b8c59c [dart2wasm] Fix pkg/dart2wasm/tool/compile_benchmark script
The script was incorrectly handling source maps when deferred
loading is enabled and we emit & optimize multiple wasm modules
(the source maps very completely bogus)

Change-Id: Ib65b72a4d2a3c8958bbe80e94c76145b6e1a0e5b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/464480
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
2025-11-26 01:49:53 -08:00
Martin Kustermann 407afe84ca [dart2wasm] Remove dynamic closure call vtable entry in most cases
This reduces acx main: module -0.35%,  global section: -2.3%

Previous change in [0] made dynamic call sites have per-caller-shape
dynamic forwarders.

In this change we utilize this: Since we know the dynamic caller shape
we can make the dynamic forwarder call via a closure representation that
matches this caller shape (modulo the type arguments - as a dynamic call
without type arguments may get default type arguments of unknown count).

=> This means we no longer have to pass types, positionals and named
   arguments as wasm arrays to dynamic call forwarder. Instead we can
   pass the arguments unpacked to the vtable.

Additionally we change `Function.apply`: If we know there's no
`Function.apply` usage with named arguments, we can enumerate all
possible closure representations and call the corresponding vtable
entry. We use 2 `br_table` instructions for this:

  * branch on number of type parameters
  * branch on number of positional parameters

Together these two changes means that neither dynamic forwarders nor
`Function.apply` will use the dynamic call entry.

=> We remove the dynamic call entry from the vtable construction

The only exception to the above are:

* If dynamic submodules is enabled we don't compute closed world
  information about closures and always call via dynamic call entry

* If `Function.apply` is used with named arguments then call via dynamic
  call entry (and make vtables have it).

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


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

Change-Id: I26e6a2a48ee37616061d701dc4d4327c2e109e82
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/462060
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2025-11-26 01:02:31 -08:00
Tess Strickland 06795bb3a5 [pkg/smith] Convert NamedEnums to enhanced Enums.
This allows Enums created elsewhere to be used for enumOption
declarations.

Also change the analysis options for pkg/test_runner so that
exhaustive case errors are no longer ignored.

TEST=ci

Change-Id: Ib1cf1c015f4a6df9ce018117edfd9b626e91c5f6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/438725
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
2025-11-20 03:19:03 -08:00
Martin Kustermann a1cca73a28 [dart2wasm] Fix exponential compile time in dynamic closure calls
In the loop that has 2 recursive calls: with a name and without a name
we should stop early if we already know that this is unreachable (e.g.
all name combinations require a name or don't have a name).

This should make us now have O(#name-combinations) recursive calls,
emitting unreachables as soon as there's a set of names that aren't
feasible in any name combination.

Change-Id: I4c91a5fa91709398aa80ffd8dc278e30638acb0c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/462400
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2025-11-17 05:26:21 -08:00
Nate Biggs e2cfee0f65 [dart2wasm] Improve module import naming conventions.
- Use the empty string for the string import object since these are the most numerous import objects.
- Use ascii index encoding for module names (when minified). This mostly improve the size of submodules, the main module only has 1 copy of this name.
- Use same ascii encoding instead of base64 encoding for export names. These all show up in the main bundle once and we save a 1-3 bytes per name.

Change-Id: I84bdab3ff5e17c8f2db456cf348e1abf1784e30a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/461280
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-11-13 12:31:51 -08:00
Martin Kustermann 59c8081950 [dart2wasm] Use shared closure argument dispatchers for dynamic call entries
This removes 4591 functions from ACX gallery main module
which translates to -43 KB / -1.6% (-3.5% code section)

We have already today a callsite guarantee that the closure call
(type, positional, named) arguments are valid arguments to the
target closure (they also have the right type).

That means the `closure.vtable.dynamicCall` entry's only purpose
is to unpack the (type, positional, named) argument arrays and call
the target.

Instead of calling the target directly (as we did so far) we now
unpack argument arrays and call the right vtable entry. This logic
can be shared amongst all closures of the same representation and
therefore leads to big reduction in wasm functions.

=> We do that in this CL.

There's two exceptions to this:

* In dynamic module scenario we don't have closed-world knowledge
  of closure definitions & closure call site. There's no specific
  vtable entries for positional+name combinations we could forward
  to.

* In closed world scenario where there's a usage of `Function.apply`
  with named arguments: We don't generate vtable entries for all
  possible name combinations a closure can be called with.

So we change the closure layouter algorithm to find out if there's
a usage of `Function.apply` with named arguments.

A few tangential changes:

* Fix a bug revealed by this change: The static tearoff
  instantiation constant's dynamic call entry must pass the generic
  closure object when calling the generic closure.
  => The shared dynamic call entry dispatchers will now verify
     (in assertion) mode the assumptions, which revealed this issue

* The closure layouter algorithm will now consider `obj.foo(a: ...)`
  as a potential dynamic call site (due to call-via-field) and
  therefore record the name combinations used there
  => Tested via `web/wasm/closures/dynamic_call_via_field_test`

We test the optimization by checking in 3 tests that show what
ends up in the vtables:

* `pkg/dart2wasm/test/ir_tests/dyn_closure.dart`
  => uses dynamic calls
  => dynamic call entries are "closure arguments dispatcher"

* `pkg/dart2wasm/test/ir_tests/dyn_closure_function_apply.dart`
  => uses Function.apply without names
  => dynamic call entries are "closure arguments dispatcher"

* `pkg/dart2wasm/test/ir_tests/dyn_closure_function_apply_named.dart`
  => uses Function.apply with named arguments
  => dynamic call entries are closure specific

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

Change-Id: I099984b542b05920b02596410a1bf6a08d2a0302
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/460080
Reviewed-by: Ömer Ağacan <omersa@google.com>
2025-11-07 11:17:57 -08:00
Nate Biggs 0507f059ee [dart2js] Fix error when comparing constants referenced across deferred import boundaries.
Constant folding was considering strings (or other primitives) unequal if one of them was a DeferredGlobalConstantValue and the other was not. This was producing incorrect results in the cases where the underlying constants were in fact equal.

For the purposes of constant folding equality checks, we should just ignore the deferred boundary and compare the constants themselves.

Fixes: https://github.com/dart-lang/sdk/issues/61833
Change-Id: Ibbd950ae910ee2377353f5fae8d9bea5c64d9d84
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/460020
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
2025-11-06 20:49:28 -08:00
Stephen Adams 456efb510d Make wasm/uri_base_test run on browsers
Change-Id: I6bc542bc6b2f68e7043d4c840da26dda30faad2d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/456141
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
2025-10-23 11:21:40 -07:00
Mayank Patke a63045d197 [dart2wasm] Remove dart:js_util from supported libraries
Since that stops `dart:_js_annotations` from building on dart2wasm,
let's stop supporting that, too.

This causes `package:js` to no longer work on dart2wasm, but none of the
allowlisted packages use it any longer, so we can simply migrate tests
off of it.

Fixes: #56502
Fixes: #61550
Change-Id: I6a6a696438255ebf25a5a17131cdbd327ba81581
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/453645
Commit-Queue: Mayank Patke <fishythefish@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Nate Biggs <natebiggs@google.com>
2025-10-15 15:38:35 -07:00
Nate Biggs 10be4da5dc [dart2wasm] Run wasm-opt local optimizations on deferred loading modules.
Output for ACX gallery (monolith):
```
acx_gallery.Time.Total(CompileTime): 216.80 s
acx_gallery.Time.Dart2Wasm(CompileTime): 88.37 s
acx_gallery.Time.Wasm2WasmOpt(CompileTime): 128.43 s
acx_gallery.Size.mjs(CodeSize): 421228 bytes
acx_gallery.Size.mjs.gz(CodeSize): 29255 bytes
acx_gallery.Size.wasm(CodeSize): 38083554 bytes
acx_gallery.Size.wasm.gz(CodeSize): 9040482 bytes
acx_gallery.Size.wasm.opt(CodeSize): 13147207 bytes
acx_gallery.Size.wasm.opt.gz(CodeSize): 3288834 bytes
acx_gallery.MemoryUse.Max(MemoryUse): 2398687232 bytes
acx_gallery.MemoryUse.Dart2Wasm(MemoryUse): 2359529472 bytes
acx_gallery.MemoryUse.Wasm2WasmOpt(MemoryUse): 2398687232 bytes
```

Output for ACX gallery (monolith -O0):
```
acx_gallery.Time.Dart2Wasm(CompileTime): 87.49 s
acx_gallery.Size.mjs(CodeSize): 421228 bytes
acx_gallery.Size.mjs.gz(CodeSize): 29255 bytes
acx_gallery.Size.wasm(CodeSize): 38466066 bytes
acx_gallery.Size.wasm.gz(CodeSize): 8509479 bytes
acx_gallery.MemoryUse.Dart2Wasm(MemoryUse): 2261155840 bytes
```

Output for ACX gallery (deferred):
```
acx_gallery.Time.Total(CompileTime): 138.03 s
acx_gallery.Time.Dart2Wasm(CompileTime): 92.67 s
acx_gallery.Time.Wasm2WasmOpt(CompileTime): 45.36 s
acx_gallery.Size.mjs(CodeSize): 422584 bytes
acx_gallery.Size.mjs.gz(CodeSize): 29610 bytes
acx_gallery.Size.wasm(CodeSize): 50639314 bytes
acx_gallery.Size.wasm.gz(CodeSize): 13063929 bytes
acx_gallery.Size.wasm.opt(CodeSize): 20308884 bytes
acx_gallery.Size.wasm.opt.gz(CodeSize): 5569508 bytes
acx_gallery.MemoryUse.Max(MemoryUse): 2165276672 bytes
acx_gallery.MemoryUse.Dart2Wasm(MemoryUse): 2165276672 bytes
acx_gallery.MemoryUse.Wasm2WasmOpt(MemoryUse): 454402048 bytes
```

Change-Id: Ia6627b94ff80019b3c180850a3940d7e714c068b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/453240
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-10-06 10:28:40 -07:00
Mayank Patke 20056805f7 [dart2wasm] Clean up dart2wasm tests using js_util
Bug: #61550
Change-Id: I6a6a696405a6a8df62c3088fb3f7bdba2e27b783
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/450967
Reviewed-by: Srujan Gaddam <srujzs@google.com>
2025-09-25 14:22:43 -07:00
Mayank Patke f626a3ce71 [dart2wasm] Remove tests/web/wasm/js_util_test
Bug: #61550
Change-Id: I6a6a6964cb56a64028e6fedd5f986ef0efecf52a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/450961
Auto-Submit: Mayank Patke <fishythefish@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
2025-09-25 14:22:43 -07:00
Srujan Gaddam b01bf92f9a [dart2wasm] Typed array wrappers should unwrap instead of reinstantiate
Fixes https://github.com/dart-lang/sdk/issues/61543

toJS and jsify conversions instantiate a new typed array using
the same underlying buffer instead of returning the original
typed array. To fix this, the typed array wrappers now capture
the original array ref (if any) and return it in toJSArrayExternRef
if it exists and the caller didn't ask for a subrange.

Note that _ref in the wrappers refer to a DataView, and not
the array ref. Some methods are renamed to reduce that confusion.

Change-Id: Ia9befd114a77489aedbb3644c9604aef4b3af7c1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/450966
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Srujan Gaddam <srujzs@google.com>
2025-09-25 09:24:31 -07:00
Martin Kustermann 520607a6a7 [dart2wasm] Ensure we never emit string import names that are longer than 100_000 bytes
D8 currently allows longer import names bot JSShell and JSC do
issue a validation error if the name is larger than 100_000.

This fixes e.g. StarryStrings benchmarks on JSC/JSShell

TEST=tests/web/wasm/long_string_import_test.dart

Change-Id: I93df5d0e3014f6157750511fe486677e9b9413d7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/450922
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2025-09-23 04:02:01 -07:00
Nicholas Shahan 3f2801d63f [ddc] Avoid revisiting sub-expressions on chained invocations
Similar to https://dart-review.googlesource.com/c/sdk/+/445540 this
avoids compilation timeouts by avoiding recompiling the receiver in long
chains of invocations.

Guards all of the soundness checking behind a single generation check.
This was already true for nested calls but not for chains of invocations.

This also resolves a correctness issue where sub expressions of the
receiver in chained calls would be evaluated multiple times at runtime.

Change-Id: Iaf192a639e90d77995da55c7fa9c248e7bb93491
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/450183
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Nicholas Shahan <nshahan@google.com>
2025-09-22 14:25:22 -07:00
Nate Biggs e6f188b3fa [ddc] Avoid revisiting subexpressions during hot reload invocation rewriting.
In extreme cases with deeply nested invocations in closures, this can lead to an exponential recursive call pattern.

For example: https://github.com/spebbe/dartz/blob/8bf79e746d11e6a66c868027e5e1a25fdd270f45/lib/src/either.dart#L108

Moves all nested checks onto a single branch so that there is a single branch with no checks when the generation is the same, and another branch with all the necessary checks when the generation is different.

Bug: https://github.com/flutter/flutter/issues/173700
Change-Id: I3167a96e3ead67fd1d5c763ef2a7309d82c1a7c6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/445540
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Nicholas Shahan <nshahan@google.com>
2025-08-22 20:48:35 -07:00
Srujan Gaddam 6f85292b08 [dart2wasm] Support NullRejectionException.isUndefined
Previously, the implementation worked around boxing limitations
by always setting this field to false. However, because we
control both the callback and the JS code that calls the rejection
function, we can pass more information to the callback to let it
know whether the error was undefined.

Change-Id: Ic19f24ec20d321859eb8184d5c87744f7679cf0c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/439141
Commit-Queue: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
2025-07-08 09:47:12 -07:00
Nate Biggs 886624cbf9 [dart2js] Add helper to detect csp in web tests and use it to set expectations for some tests.
Fixes these: https://dart-ci.firebaseapp.com/#showLatestFailures=true&configurations=dart2js-minified-csp-linux-chrome

Change-Id: I2939e3ce1fdee45d570d038f2f4382747cd617dc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/436140
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
2025-06-24 12:06:22 -07:00
Martin Kustermann 76548a7ab9 [tests] Rewrite various tests to not depend on <obj>.runtimeType.toString()
In dart2wasm applications are by default deployed in `-O2` mode which
implies `--minify`.

Given this is the default configuration for customers, we want good
testing of this configuration and not large numbers of approved failures.

=> Rewrite various tests to not depend on `<obj>.runtimeType.toString()`

Change-Id: I1108b28c63b8bec6ad94df0d7b878b3339776df9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/436281
Reviewed-by: Lasse Nielsen <lrn@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2025-06-24 01:16:24 -07:00
Nate Biggs d3539374ff Cleanup extra --strong flags being passed in test/web.
Change-Id: Ia00ced1c31ccd49dc883d4dfdc4fe644d8a5e363
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/435600
Reviewed-by: Mayank Patke <fishythefish@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-06-20 20:11:25 -07:00
Nate Biggs 124b98b461 [dart2js] Move tests from tests/web that are failing on DDC configurations into dart2js specific folder.
Also update dart2jsOptions on some tests that are failing on production/O0 configurations.

Change-Id: Ie0a8fa56dc391c98186f1573a76cff7ef6afde8d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/433563
Reviewed-by: Mayank Patke <fishythefish@google.com>
2025-06-20 20:11:25 -07:00
Stephen Adams 3f5314fb2f Reapply "[dart2js,rti] Add direct methods for as JSObject"
This reverts commit 43b5c1432e.

This time, fall back on code that works for mocks and fakes.

Issue: #60746

Change-Id: Iecb822486729f8b10377c94bf87d06406bb0f5bc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/434920
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
2025-06-18 19:21:22 -07:00
Lasse R.H. Nielsen 007033109d Only mark tests non-text if they actually depend on line ending.
Some test files were included, where only their data actually
depended on line endings.

Some tests didn't actually depend on line ending at all.
(They may date back to a time where multiline strings didn't
normalize their newlines.)

Fix some syntax tests that had been formatted, and exempt
all files depending on line endings from formatting.

Change-Id: I6c003e9c4f03d3b2af102bfca59d4a7bc8e6d63f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/434380
Reviewed-by: Devon Carew <devoncarew@google.com>
Commit-Queue: Lasse Nielsen <lrn@google.com>
2025-06-13 16:16:13 -07:00
Ryan Macnak 56636971dc [test_runner] Remove nnbd mode options.
In particular, this means the VM tests stop getting invoked with the now-invalid --sound-null-safety flag.

Change-Id: Ia8f5a59e0bf1fd7094508fdc4bb146ebf3034148
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/431360
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Kallen Tu <kallentu@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
2025-06-02 10:59:31 -07:00
Stephen Adams d49cd3c552 [dart2js] Track, rather than compute, isCallOnInterceptor
By tracking `isCallOnInterceptor`, we avoid the need for class context
information in the `sourceElement` to compute the value. `sourceElement`
is now purely advisory to the choice of local names in codegen, and
can't be the wrong kind of element as in issue #60793.

Bug: #60793
Change-Id: I8bb68b6bf864a3a6f9f2beb40f68a6254431d49a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/432003
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
2025-05-30 11:38:22 -07:00
Nate Biggs e688981385 [ddc] Fix capture issue with temp names within async scopes.
`needsCapture` will ensure that any variables used within an async scope get included in the 'asyncScope' object that's created for that scope.

The variables used to lower Dart late variables in particular get emitted separately. But they can still be used across async scopes so they need the special capture logic as well.

Bug: https://github.com/dart-lang/sdk/issues/60748
Change-Id: I2486fce41f88f186fd799029c2cc59635f7ad8f5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/429780
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-05-21 17:49:22 -07:00
Ö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
Srujan Gaddam 2547ccd4d4 Add compiler-specific expectations for object_members_test
This test was intended to capture the existing state of
object members for JS interop and dart:html objects. At some
point, it started failing in ddc, so we add the correct
compiler-specific expectations instead to get it to pass.

Change-Id: I130efc9927a5cb74dafa1b5beb856c7a6ee5a9aa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425882
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Commit-Queue: Srujan Gaddam <srujzs@google.com>
2025-05-01 15:05:01 -07:00
Srujan Gaddam bf16ef7b48 Move browser tests under 'dart2js && d8' to just 'd8'
html_mocks_with_static_interop_test is currently failing in
the DDC d8 bot. Both this test and object_members_test should be
filtered out in this bot instead of just for dart2js. The latter
is currently failing in the DDC d8 bot as well.

Change-Id: I540056d070fa826b0d4b8e61a6f095c5a9568256
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425881
Auto-Submit: Srujan Gaddam <srujzs@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
2025-05-01 14:00:23 -07:00
Stephen Adams 20e8977df2 [rti/js_interop] Redo: Accelerate is JSObject
Change-Id: I9a252319a1c7b426a54d52660c9d8adc5e72cd2b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425334
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
2025-04-30 16:17:31 -07:00
Stephen Adams c9b0f56c19 [dart2js] Update @Native test.
Bug: #60538
Change-Id: If3347236e21cb1faf55252bc09778a8789b89b16
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/422364
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
2025-04-14 17:24:26 -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
Mayank Patke 3a3dfcbb7d [dart2js] Remove references to new-rti/old-rti.
The "new" rti library has been standard for years now and no one should
be passing `--experiment-new-rti` or `--use-old-rti`. We can now clean
up any references to different versions of rtis.

Change-Id: I4421b8943fe5034ed4d259477e8112b25ba0c763
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/416326
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Mayank Patke <fishythefish@google.com>
2025-03-19 11:54:57 -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
Mayank Patke 13b5b8ab37 [dart2js, ddc] Remove support for SNS checks.
Bug: #60327
Change-Id: I38f04fea4e51dcd0fd43dc93ecc7007a0a816f29
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/416120
Reviewed-by: Nate Biggs <natebiggs@google.com>
Reviewed-by: Nicholas Shahan <nshahan@google.com>
2025-03-18 19:09:54 -07:00
Ömer Ağacan f4b41f0902 [dart2wasm] Fix handling of --define/-D
When parsing `--define` or `-D` arguments don't split the the value by
commas.

This is consistent with how dart2js handles `-D`, but inconsistent with
how VM handles it.

Example:

    void main() {
      print(const String.fromEnvironment("FOO"));
    }

When compiled with `dart compile js -DFOO="a, b"` and run, dart2js
prints

    a, b

VM prints (when compiled to exe)

    a

Between these two, I think dart2js' behavior is more common, so we
follow dart2js.

Also update compile_benchmark to avoid splitting a single argument "a b"
into "a" and "b" when parsing the arguments and then splicing them back
before calling `dart2wasm`.

Also update the test runner and ddc batch mode argument parser to handle
splitting quoted arguments in `// dart2jsOption = ...` and the same
options for ddc and dart2wasm, by moving dart2js's `splitLine` to a new
library and reusing it in the test runner and ddc.

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

See also https://github.com/dart-lang/sdk/issues/60341 for relevant
future work.

Change-Id: Idbdf69072fa212c8e4a390990577eb5a57b49e8a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/415280
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
2025-03-18 04:11:41 -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
Mayank Patke 3df2adc587 [dart2js] Add failing tests for #49599, #55058, #60115.
Bug: #49599
Bug: #55058
Bug: #60115
Change-Id: I5e7022179a0d64b92304aec31a5732bb4b00db16
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/258960
Reviewed-by: Stephen Adams <sra@google.com>
2025-02-18 16:50:18 -08:00
Nate Biggs 5855d91ba8 [ddc] Correctly extend type parameters for factory constructors.
RtiTypeEnvironment currently does not support being extended. However it's used for factory constructors which themselves can have generic functions defined in their bodies. This means we have to allow the ability to extend RtiTypeEnvironments as well.

Bug: https://github.com/flutter/flutter/issues/160338
Change-Id: I9b4e79b44f503a4a987e0c38da86fdce81361e4c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/406344
Reviewed-by: Mark Zhou <markzipan@google.com>
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-01-30 08:07:30 -08:00
Nate Biggs 44dfe081b2 [ddc] Add a covariant parameter check for optional nonnullable parameters with null initializer on lowered constructor tearoffs.
Change-Id: I77379ee43173ddbbdee25083bd641968eeeb787f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/406500
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
2025-01-29 23:07:26 -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