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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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: #56502Fixes: #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>
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>
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>
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>
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>
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>
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>
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>
`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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>