When deferred loading was enabled the dynamic dispatch class ID table
was incorrectly assigning class IDs to the wrong module. If a contiguous
target segment included classes/targets from different modules, all of
them were getting assigned to the module of the first class/target in
that segment.
This was causing spurious NSM exceptions as the necessary rows in the
table might not be populated for a dynamic call if the module the
segment was assigned to wasn't loaded yet.
To fix this we end the segment if the next target does not belong to the
same module as the active segment.
The new test fails with an NSM exception prior to this fix.
Change-Id: I07bc4fdb5a8bff1bfad5fe17f45c8076a965a775
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/502860
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
It reduces e main module by around -0.3% compressed/uncompressed.
The dynamic calls use 2 tables. One of them stores class ids and one
stores targets. We can compute the table initialization for these two
tables independently.
The targets table may contain different targets but the class ids may
still be consecutive and therefore allow a larger stride which may move
initialization from element section to a loop in the #start function.
Change-Id: Ief5415f035ce1b854aecaa635a5e916938217b8e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/501420
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
This gives in e main module
* 2.7% size reduction uncompressed
* 1.7% size reduction compressed
The element section goes from 300 kb to 175 kb and #init function also
shrinks in size.
We perform two optimizations
* If the dispatch table contains `null` entries, then they are
unreachable. That means if we have long strides of the same target and
possibly gaps in-between, we can use one `table.fill` instruction to
initialize the entire segment. Entries that are supposed to be `null`
are then occupied but unused.
* If the dispatch table entries of the main module contain gaps but are
not `null` but will be filled in later by a deferred module, we can
also use a `table.fill` with large area. The entries that are then
occupied, but should be `null` until deferred module initializes it.
That's not a problem because they will be unused until the deferred
module loads, and when it does it will override those (incorrect)
entries with valid ones.
Change-Id: I356faff4204d04dfe42cbd1282f23090229a8503
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/499560
Reviewed-by: Srujan Gaddam <srujzs@google.com>
This removes 1% uncompressed size from e main module and
may make startup a bit faster.
The element segment of the dynamic dispatch table may have large
strides of identical functions. This happens e.g. when a base
class defines a method and large number of subclasses inherit tha
method.
This CL applies a similar optimization to the dynamic dispatch
table building code as we did in [0] for the normal dispatch
table.
Due to [1] which updated checked-in SDK, new formatter is used
for presubmit checks. Patchset 1-2 is formatting the files, the
actual changes is from Patchset 3+ onwards.
[0] https://dart-review.googlesource.com/c/sdk/+/467843
[1] https://dart-review.googlesource.com/c/sdk/+/484224
Issue https://github.com/dart-lang/sdk/issues/62639
Change-Id: Ia5d63ab31a4167e3ea4c5903ed5db764b6ad3327
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/488720
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This reduces e mail module by -4% in compressed form. It does have
a increase of 2.5% in uncompressed form. This is due to repeated
entries in the element section of the dynamic dispatch table and
will be addressed in future CLs.
Currently if the main module of an app has a dynamic call, it will have
a caller-shape specific dynamic dispatcher that checks (via class ids)
all possible targets in the app and issues calls to them.
That means the code size is O(targets) - even if most targets reside in
deferred modules.
We change this now to use a row displacement table based dispatch,
just as our normal typed dispatch table. Though there's a few
differences
* In a typed call we know the target exists, in a dynamic call we don't
know whether the target exists (it may be a NSM case). To accomodate
for this we make 2 wasm tables of the same layout: First we load a
table of i31refs and check if the value is in agreement with the
receiver class id. If so we have a match and can load the actual
destination from the funcref table.
* In typed calls we use one row in the table for each selector. In the
dynamic invocation case we'll use one row per dynamic selector + call
shape.
* The wasm module that contains the actual instance method will also
hold all it's dynamic forwarder functions (one per dynamic caller
shape). The elements section of that module will cause initialization
of the two slots in the two tables mentioned above.
Issue https://github.com/dart-lang/sdk/issues/62639
Change-Id: I4e631f98fe9c58e2110bac34c3f5ff6d11bef909
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/487660
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>