The type category table is a O(number-of-classes) sized byte array that
maps from class-id to either a type category (function, record, ...) or
a masqueraded class-id.
* for flute this table takes up around 1 KB.
* this prevents from making concrete class-ids come before all abstract
class ids
After recent changes the core RTT implementation no longer involves
masqueraded types (i.e. `<obj> is/as <type>` and `<type> <: <type>`
queries don't trigger masquerading functionality)
This CL removes the type category table, the special casing in the
class-id assignment and the compiler support for building the table.
Instead we move the logic to pure dart code, which can use normal `is`
checks to perform its function.
We add one optimization: The compiler will provide the class-id from
which one only non-masqueraded classes come. This makes the masquerading
function have a fast path.
* We use `Wasm{TypedData,String}Base` marker interfaces i
`dart:_internal` to check for wasm-backed implementations
* We use `-Ddart.wasm.js_compatibility` to provide JSCM mode
We add a test that actually exercises the 2 modes.
Change-Id: I051c35b17878950402a1336df871a686b649f732
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/349641
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
* avoid allocating _RecordType objects for `<obj> is/as <record-type>`
=> Introduce `Record._checkRecordType()`
=> Use `Record._recordRuntimeType` (which is now not masquerading) for
other purposes (e.g. verification)
* avoid using masqueraded types for `<obj> is/as <record-type>`
=> Introduce `Record._masqueradedRecordRuntimeType`
Although we introduce 2 extra methods on `Record` that are overriden,
it's O(record-shapes-in-program) and therefore not a big overhead.
=> This will enforce the invariant that the actual type check
implementation (i.e. for `<obj> is/as <type>` or
for `<type> <: <type>`) *never* calls back into
masquerading functionality
=> This in return means we can make the masquerading functionality
using `<obj> is <type>` checks.
Change-Id: I3e3a0411022042a8e735aaeed396cc8f90d8c9c5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/349800
Reviewed-by: Slava Egorov <vegorov@google.com>
This adds the dart:_macros library to the SDK and adds support for accessing dart:_macros from package:macros. The library is not used yet.
This change is needed as a prestep to adding the package:macros and using it in the CFE and analyzer, and needs to be rolled in as the checked in sdk before package:macros can be supported.
TEST=ci
Change-Id: Ife3ffd48527e3a196048d2ddf7387b8b7818f3a3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/348680
Reviewed-by: Jake Macdonald <jakemac@google.com>
Reviewed-by: William Hesse <whesse@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Improves code size of flute complex in
* -O3 mode by 3.2% (~ 40 kb)
* -O4 mode by 1.4% (~ 17 kb)
There's a number of other improvements in this area, that we may do in
follow up CLs.
Change-Id: I77246686970a4b89286dd9f2061dad1d44252532
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/349501
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
The CL removes a hack that assigned fixed class ids due to the need of
special treatment for masquerading types.
=> Instead of hard coding the type category values, we discover feasible
slots automatically, so we can remove the hack
=> Makes our cid numbering of concrete classes pure DFS pre-order
=> Ensures all concrete subclasses of a class have continious class ids
We also replace an assembly stub that deals with masquerading with one
written in Dart, adding the necessary primitives (e.g.
getting category type table & kinds).
We also align how to get the function type of a closure, namely
add `_Closure._getClosureRuntimeType()` analogous to the method on
`_Record._getRecordRuntimeType()`
Change-Id: I5169fc4953e8e99c4f84a1bbe8e535c08fb47cc5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/348840
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
The most important thing with dispatch table layout is to order classes
in depth-first pre-order numbers and make it only include concrete
classes.
* We only dispatch on concrete classes.
* Any selector of a base class is inherited by its subclasses
* Using DFS makes selector rows have few but wide filled blocks.
This CL orders class ids in a pure DFS pre-order numbering:
* DFS pre-order traversal for concrete classes
* DFS pre-order traversal for abstract classes
=> Increases dispatch table packing from 49% to 99%
=> Reduces GDT from 31k entries to 15k entries on Flute
=> Reduces Flute by around 2.1% code size.
It also prepares for implementing faster type checks by doing class-id
range checks.
Change-Id: I96744b114e8815904f7405dca1432cdca3c7fe30
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/348561
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
The compiler would perform O(n) operation (where `n` is number of
classes that implement a selector) every time a GDT call is made.
Change-Id: I428a69faa0f5d83e11b3948fd7e009f49c1acba1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/348400
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
Records should be marked allocated when records get created
(e.g. record literals / constants) not when fields of records get
accessed.
Change-Id: I7b7fc5cfd71da1f501551efe948ae3a44a128b6e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/348381
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
Closes https://github.com/dart-lang/sdk/issues/54138
Adds a helper to do better type-checks so that users don't
accidentally using is checks or have to manually do the right
typeof or instanceof checks. In order to do this, there is
some refactoring to make ExportCreator a SharedInteropTransformer
(as it's shared across all backends) so that we can reuse an
existing visitor. In the same class, we remove unnecessary setting
of parent pointers. We should clean up the fileOffsets as well,
but dart2js verifies that those are set, so we keep them as is
for now. Also adds some static errors for edge cases.
CoreLibraryReviewExempt: Helper for web-specific library.
Change-Id: I34d818ada1349b69afd15d170d3fafa0460f65fa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/347225
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Srujan Gaddam <srujzs@google.com>
This aligns the behavior of --omit-implicit-type-checks with dart2js
Change-Id: I453652339f23b89873d070422cf61eca77a2b68d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/348164
Reviewed-by: Slava Egorov <vegorov@google.com>
This reduces time for `dart compile wasm` on a hello world in
* `--no-optimize` mode from 8.2 to 1.8 seconds (0.6 sec via [0])
* `--optimize` mode from 9.2 to 3 seconds (1.6 sec via [0])
[0] pkg/dart2wasm/tool/compile_benchmark
Issue https://github.com/dart-lang/sdk/issues/54675
Change-Id: I47093e747f343b542bc7faa34e102c62657c7b81
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/347902
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
The `minified:...` encoding of class names mirrors the one used by
dart2js. So the added test will work in both modes.
This reduces optimized dart2wasm output
* hello world by 20%
* flute complex by 8.5%
Change-Id: I080de40919ee3f25f0f0d8c9b82aa662f7e734aa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/347741
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
JSC only supports `print()` but not `console.log()`.
=> The changes to `printToConsole()` are therefore extended
to check for `console.log()` as well as `print()`.
=> This is extending it to a broader subset of dart2js's print
Change-Id: I7efa697477aa60e473d01716b104fc1526035c67
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/347283
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
Previously `VariableDeclaration.initializer` was sometimes not null even
when a function parameter is required.
[1] fixes this, which breaks dart2wasm. This CL prepares `initializer`
usage in prep for [1].
[1]: https://dart-review.googlesource.com/c/sdk/+/345240/1
Change-Id: Ie16156d01eb3659719f004996adce7acc3511b12
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/345300
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Similar to 4d3895a and 72fd1e0, use `FunctionNode.emittedValueType` to
get the yielded element type.
Change-Id: Ib7b3d37e8c84c1b40c38fc8b4143fd0e2b77a463
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/344704
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
With 3c4d4ad we use non-nullable Wasm field types for non-nullable Dart
fields, so the `ref.as_non_null`s for getting async completer from a
async suspend state can be dropped.
Change-Id: I7857d9996f3415c42b83e4b8961f629e0dd070a7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/345180
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
Auto-Submit: Ömer Ağacan <omersa@google.com>
This avoids allocating lists in dynamic calls for type
arguments.
So far the closure shape checking functionality also
- as a side-effect of shape checking - added default type arguments
to a growable list. We now cleanly separate the logic to use
default type arguments vs shape checking.
=> Doing so allows removing the remaining usages of [List] in the RTT.
=> Probably also results in smaller & faster dynamic calls.
The list allocation is now pushed to the slow path where we
create [Invocation] object that is then used for NoSuchMethod
handling.
Change-Id: I4823cda0aa9b5f1f137813bc5848c365665da5fd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/344822
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This avoids allocating lists in dynamic calls for positional/named
arguments.
=> Doing so allows removing more usages of [List] in the RTT.
=> Also results in up to 50% faster dynamic calls.
=> Probably also results in smaller code.
The list allocation is now pushed to the slow path where we
create [Invocation] object that is then used for NoSuchMethod
handling.
Change-Id: If578fb044a6cf7f31bd409c177b361181ba68a01
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/344821
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
When a const list access does not have a const argument, fall back to
normal compilation. TFA optimizes const list accesses to direct calls to
`_ListBase.[]`, so the code generated by the intrinsic handler is not
any better, and the generated code in the intrinsic handler does not do
bounds check.
Fixes test standalone/array_bounds_check_generalization_test.
Change-Id: I6455826815c22a731bb830aec08b8bdd701e0d52
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/344820
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
- Drop the last '.' in constructor names.
- Add 'new' prefix in factory names.
We still keep the "initializer" and "constructor body" parts in
constructors as we they're useful when debugging dart2wasm, and the
stack trace tests don't care about extra information in stack frames.
Fixes test language/stack_trace/demangle_ctors_test.
Change-Id: Ib23339f3a0b2ac0c16e2f2a35b3b19939d0dadb9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/342620
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
https://github.com/dart-lang/sdk/issues/54004
In order to reach parity with js_util, we expose operators
through an extension and do some partial renames in order
to make the member names sound better e.g. `equals` instead
of `equal`. We also expose the following from js_util:
- NullRejectionException
We don't expose `isJavaScriptArray` and `isJavaScriptSimpleObject`
as they can expressed through other forms of interop. There
was an esoteric bug where we needed these members for Firefox
in pkg:test, but the package no longer uses these members, so to
avoid increasing the API space too much, we do not export them.
For the same reason, we also don't expose `objectGetPrototypeOf`,
`objectPrototype`, `objectKeys`.
We don't expose `allowInteropCaptureThis` as it will take some
work to handle this in dart2wasm. That work is tracked in
https://github.com/dart-lang/sdk/issues/54381.
Lastly, `instanceof` and `instanceOfString` is moved to be on
`JSAny?`, as this operator is useful to avoid needing to
downcast to `JSObject` e.g. `any.instanceOfString('Window')`
instead of `any.typeofEquals('object') &&
(any as JSObject).instanceOfString('Window')`.
Extensions are reorganized and renamed to handle these changes.
CoreLibraryReviewExempt: Backend-specific library.
Change-Id: Ib1a7fabc3fa985ef6638620becccd27eeca68c25
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/341140
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Fixes tests:
- co19/Language/Functions/element_type_A01_t03
- co19/Language/Functions/element_type_A01_t04
- co19/Language/Functions/element_type_A01_t06
Fixes#54413.
Same change for `async*` functions was made in
https://dart-review.googlesource.com/c/sdk/+/342561.
Change-Id: Ib9e23b3fff9e2f1b952b5ba114ec70d5a8aea372
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/343141
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
When compiling a `while` in an `async` function, we need to allocate the
context for the `while` *before* compiling the `while` condition,
because any variables introduced in `while` condition will be stored in
the `while` context, rather than the parent context.
Instead of fixing where we allocate `while` context, we could update
`CaptureFinder` to add variables in the condition to the parent context,
and update `for` code generator, as it currently allocates `for` context
before the conditions.
I don't know if that has any advantages, for now it should be OK to
update `while` code generator.
`for` code generator allocates the context before the conditions and
does not have this issue.
Fixes#54406.
Change-Id: I3c6bb7558a352d78c8f8a46a56d9bd3af68841a5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/342760
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
Previously we would encode the type of the value returned in `async`
functions as the field `futureValueType` on `FunctionNode`. For all
other kinds of functions, such as `sync`, `sync*`, and `async*`, that
field would be null. This CL renames `futureValueType` into
`emittedVAlueType`, and for functions of kinds `async`, `sync*`, and
`async*` that is expected to be the type of values emitted via
`return` or `yield` statements. For `sync` functions that field is
supposed to contain `null`.
In response to https://github.com/dart-lang/sdk/issues/54159
TEST=existing
Change-Id: I1efdbcc4e75d150f5618c7ca50cfe49a0e54fce6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/341662
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
This fixes web/wasm/wasm_types_test in jscm mode.
TEST=web/wasm/wasm_types_test
Change-Id: I4757707d245d7419dac28ec957d7d76b32e9e4d6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/341500
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
The dart2wasm compiler treats wasm arrays of objects/ints/floats pretty
much the same, there's no reason to have complicated class hierarchy and
different kinds of wasm array classes.
Also: We rely on all operations on wasm arrays (and other built-in
types) to be handled on the call site. Wasm arrays are not dart objects,
don't support virtual dispatch. So we make operations operating on the
wasm types extensions.
This also makes now loads and stores into the wasm arrays simple `[]` and
`[]=` operations. We still have special extensions for reading/writing
to integer/double arrays that not only read/write but also
sign-extend/zero-extend and operate on Dart's `int` / `double`.
The compiler will allow `WasmArray<X>(length)` for types `X` that have
default-value in wasm arrays (nullable / integer / double types) and
have another `WasmArray<X>.filled(length, X)` for non-nullable reference
types.
Overall this reduces LOCs and simplifies things
Change-Id: I885bed3dfd1c602dc7b0747c69927d464376383d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340881
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Closes https://github.com/dart-lang/sdk/issues/54192
Callbacks were being casted to their static type before being
called. With generic callbacks, we do not know their exact type
at compile time, therefore cannot make that cast. Similarly, a
null check was being done if the static type of the parameter
was potentially non-nullable, whereas it should be done if it's
*not* potentially nullable.
Change-Id: I3d30e901f1ff2ae4c17887564f15368244baeb24
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340390
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Refactor `JSStringImpl` to use the js-string-builtins API[1].
When the module `WebAssembly.String` is not available we define a
"polyfill" with the previous imports, so this change is backwards
compatible.
Also updates some of the methods to use avoid multiple `this.length`
calls (which do an FFI call), and use unchecked getters when possible.
A new library `dart:_error_utils` is introduced for faster range and
index checks when the length (or max value) is known to be positive
(e.g. when it's the length of a string).
For now only `JSStringImpl` and `operator []` and `operator []=` of
`JSArrayImpl` are updated to use the new range and index checks. Rest of
the libraries will be updated separately.
[1]: https://github.com/WebAssembly/js-string-builtins
CoreLibraryReviewExempt: dart2wasm specific library change.
Change-Id: I9436def0cfe59c631f6f4e15ea06cc18a47a738e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/335043
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
Marked as experimental, and only shown when verbose flag is passed:
```
$ dart help compile -v
Compile Dart to various formats.
Usage: dart [vm-options] compile <subcommand> [arguments]
-h, --help Print this usage information.
Available subcommands:
aot-snapshot Compile Dart to an AOT snapshot.
exe Compile Dart to a self-contained executable.
jit-snapshot Compile Dart to a JIT snapshot.
js Compile Dart to JavaScript.
kernel Compile Dart to a kernel snapshot.
wasm Compile Dart to a WebAssembly/WasmGC module (EXPERIMENTAL).
```
Change-Id: I6a0e65d4fbdd7b2782406b8b9969e14036bf0711
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/304860
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Michael Thomsen <mit@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
In a forwarder for a method, check class IDs of all classes inheriting
the member and run the shape check once.
For example, in a this class hierarchy:
class A {
void printName() { print("A"); }
}
class B extends A {
void printName() { print("B"); }
}
class C extends A {}
When generating method forwarder for `printName`, we currently generate
a shape check for all classes.
This this CL we now generate two shape checks: one for A and C (which
share the same `printName`), one for B.
Secondly, when class IDs of a target contains a range of consecutive
class IDs, we now generate a range check, instead of a sequence of
checks for every class ID in the range.
Fixes#53880.
Change-Id: Ie7360075c7930262e9e18c7cd125b83fd32b4bfa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/339301
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This adds the `Native.addressOf` function, which takes a constant tear-
off of a method annotated with `@Native` as a parameter and returns a
pointer to the underlying C function.
The CFE will resolve these calls in two steps: First, the existing
transformer for `@Native` methods adds a pragma describing the fully-
resolved native annotation (with the asset id inferred from the library
if not given explicitly). Then, the FFI use sites transformer rewrites
calls to `Native.addressOf` by searching for this pragma on the passed
function and passing the `Native` constants to `Native._addressOf`. The
latter method is implemented in the VM, which can re-use existing parts
already used for `@Native` calls.
An alternative implementation strategy would have been to forward
`addressOf` calls to `Native.ffi_resolver_function` directly without
any special consideration in the VM. However, the chosen approach makes
it easier to support static linking in the future, as this requires
unresolved symbols in the generated assembly.
Closes https://github.com/dart-lang/sdk/issues/50552
TEST=pkg/vm/testcases/transformations/ffi/ffinative.dart
TEST=tests/ffi/native_assets/asset_*_test.dart
TEST=tests/ffi/vmspecific_static_checks_ffinative_test.dart
TEST=pkg/analyzer/test/src/diagnostics/ffi_native_test.dart
Cq-Include-Trybots: luci.dart.try:vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-kernel-precomp-linux-release-x64-try
CoreLibraryReviewExempt: VM & dart2wasm only feature
Change-Id: Ic8e3a390146dffd44c95578f975a4472db79a0ee
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333920
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
dart2wasm lowering of async* methods includes call to Stream.where
which takes a closure. The return type of that closure was incorrectly
set to Object?, while it should be bool.
This incorrect static type becomes a problem with more precise
handling of closures in TFA.
Issue: https://github.com/dart-lang/sdk/issues/39692
Change-Id: I35a8a6b198413d564e091a935a8beaff15d6d541
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/339200
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
- Move `TextDecoder` code to decode JS `Uint8Array`s as UTF-8 to its own
module `dart:_js_string_convert`.
- Use the module in default mode (non-JSCM) `dart:convert` when decoding
JS `Uint8Array`s.
Change-Id: I6921b2a99c37ec8920ab79482228ede777bf2b4e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/338520
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This was only ever used to handle modular compiles and is no longer
needed now that we erase in DDC instead.
Change-Id: I44577464c29526d4b4fabb7c65c9f5f693edb02a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/335407
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Srujan Gaddam <srujzs@google.com>