[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>
Dart is:
Approachable: Develop with a strongly typed programming language that is consistent, concise, and offers modern language features like null safety and patterns.
Portable: Compile to ARM, x64, or RISC-V machine code for mobile, desktop, and backend. Compile to JavaScript or WebAssembly for the web.
Productive: Make changes iteratively: use hot reload to see the result instantly in your running app. Diagnose app issues using DevTools.
Dart's flexible compiler technology lets you run Dart code in different ways, depending on your target platform and goals:
Dart Native: For programs targeting devices (mobile, desktop, server, and more), Dart Native includes both a Dart VM with JIT (just-in-time) compilation and an AOT (ahead-of-time) compiler for producing machine code.
Dart Web: For programs targeting the web, Dart Web includes both a development time compiler (dartdevc) and a production time compiler (dart2js).
Dart is free and open source.
See LICENSE and PATENT_GRANT.
Visit dart.dev to learn more about the language, tools, and to find codelabs.
Browse pub.dev for more packages and libraries contributed by the community and the Dart team.
Our API reference documentation is published at api.dart.dev, based on the stable release. (We also publish docs from our beta and dev channels, as well as from the primary development branch).
If you want to build Dart yourself, here is a guide to getting the source, preparing your machine to build the SDK, and building.
There are more documents in our repo at docs.
The easiest way to contribute to Dart is to file issues.
You can also contribute patches, as described in Contributing.
Future plans for Dart are included in the combined Dart and Flutter roadmap on the Flutter wiki.