Intern the following fields:
* Category names
* Event labels
* Debug annotation keys and values
This significantly reduces the size of the timeline
(e.g. a timeline containing 60k slices goes from 15Mb
to 5Mb timeline)
This relands commit f2614d24f8
with a fix for Android build.
TEST=ci and manually
Cq-Include-Trybots: luci.dart.try:vm-ffi-android-release-arm64c-try
Change-Id: I88d4c5e1142ff66b270a22b82bacd1e9313fa953
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/418220
Reviewed-by: Derek Xu <derekx@google.com>
Intern the following fields:
* Category names
* Event labels
* Debug annotation keys and values
This significantly reduces the size of the timeline
(e.g. a timeline containing 60k slices goes from 15Mb
to 5Mb timeline)
TEST=ci and manually
Change-Id: I59e850279b6714b8b75c5b8e79e6a8b0a981a261
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417202
Reviewed-by: Derek Xu <derekx@google.com>
We use message passing as comunication mechanism between isolates.
The transitive closure of an object to be sent is currently serialized
into a snapshot form and deserialized on the receiver side. Furthermore
the receiver side will re-hash any linked hashmaps in that graph.
If isolate gropus are enabled we have all isolates in a group work on
the same heap. That removes the need to use an intermediate
serialization format. It also removes the need for an O(n) step on the
receiver side.
This CL implements a fast transitive object copy implementation and
makes use of it a message that is to be passed to another isolate stays
within the same isolate group.
In the common case the object graph will fit into new space. So the
copy algorithm will try to take advantage of it by having a fast path
and a fallback path. Both of them effectively copy the graph in BFS
order.
The algorithm works effectively like a scavenge operation, but instead
of first copying the from-object to the to-space and then re-writing the
object in to-space to forward the pointers (which requires us writing to
the to-space memory twice), we only reserve space for to-objects and
then initialize the to-objects to it's final contents, including
forwarded pointers (i.e. write the to-space object only once).
Compared with a scavenge operation (which stores forwarding pointers in
the objects themselves), we use a [WeakTable] to store them. This is the
only remaining expensive part of the algorithm and could be further
optimized. To avoid relying on iterating the to-space, we'll remember
[from, to] addresses.
=> All of this works inside a [NoSafepointOperationScope] and avoids
usages of handles as well as write barriers.
While doing the transitive object copy, we'll share any object we can
safely share (canonical objects, strings, sendports, ...) instead of
copying it.
If the fast path fails (due to allocation failure or hitting) we'll
handlify any raw pointers and continue almost the same algorithm in a
safe way, where GC is possible at every object allocation site and
normal barriers are used for any stores of object pointers.
The copy algorithm uses templates to share the copy logic between the
fast and slow case (same copy routines can work on raw pointers as well
as handles).
There's a few special things to take into consideration:
* If we copy a view on external typed data we need to know the
external typed data address to compute the inner pointer of the
view, so we'll eagerly initialize external typed data.
* All external typed data needs to get a finalizer attached
(irrespective if the object copy suceeds or not) to ensure the
`malloc()`ed data is freed again.
* Transferables will only be transferred on successful transitive
copies. Also they need to attach finalizers to objects (which
requires all objects be in handles).
* We copy linked hashmaps as they are - instead of compressing the
data by removing deleted entries. We may need to re-hash those
hashmaps on the receiver side (similar to the snapshot-based copy
approach) since new object graph will have no identity hash codes
assigned to them. Though if the hashmaps only has sharable objects
as keys (very common, e.g. json) there is no need for re-hashing.
It changes the SendPort.* benchmarks as follows:
```
Benchmark | default | IG | IG + FOC
----------------------------------------------------------------------------------------------------------------------------
SendPort.Send.Nop(RunTimeRaw): | 0.25 us (1 x) | 0.26 us (0.96 x) | 0.25 us (1.00 x)
SendPort.Send.Json.400B(RunTimeRaw): | 4.15 us (1 x) | 1.45 us (2.86 x) | 1.05 us (3.95 x)
SendPort.Send.Json.5KB(RunTimeRaw): | 82.16 us (1 x) | 27.17 us (3.02 x) | 18.32 us (4.48 x)
SendPort.Send.Json.50KB(RunTimeRaw): | 784.70 us (1 x) | 242.10 us (3.24 x) | 165.50 us (4.74 x)
SendPort.Send.Json.500KB(RunTimeRaw): | 8510.4 us (1 x) | 3083.80 us (2.76 x) | 2311.29 us (3.68 x)
SendPort.Send.Json.5MB(RunTimeRaw): | 122381.33 us (1 x) | 62959.40 us (1.94 x) | 55492.10 us (2.21 x)
SendPort.Send.BinaryTree.2(RunTimeRaw): | 1.91 us (1 x) | 0.92 us (2.08 x) | 0.72 us (2.65 x)
SendPort.Send.BinaryTree.4(RunTimeRaw): | 6.32 us (1 x) | 2.70 us (2.34 x) | 2.10 us (3.01 x)
SendPort.Send.BinaryTree.6(RunTimeRaw): | 25.24 us (1 x) | 10.47 us (2.41 x) | 8.61 us (2.93 x)
SendPort.Send.BinaryTree.8(RunTimeRaw): | 104.08 us (1 x) | 41.08 us (2.53 x) | 33.51 us (3.11 x)
SendPort.Send.BinaryTree.10(RunTimeRaw): | 373.39 us (1 x) | 174.11 us (2.14 x) | 134.75 us (2.77 x)
SendPort.Send.BinaryTree.12(RunTimeRaw): | 1588.64 us (1 x) | 893.18 us (1.78 x) | 532.05 us (2.99 x)
SendPort.Send.BinaryTree.14(RunTimeRaw): | 6849.55 us (1 x) | 3705.19 us (1.85 x) | 2507.90 us (2.73 x)
SendPort.Receive.Nop(RunTimeRaw): | 0.67 us (1 x) | 0.69 us (0.97 x) | 0.68 us (0.99 x)
SendPort.Receive.Json.400B(RunTimeRaw): | 4.37 us (1 x) | 0.78 us (5.60 x) | 0.77 us (5.68 x)
SendPort.Receive.Json.5KB(RunTimeRaw): | 45.67 us (1 x) | 0.90 us (50.74 x) | 0.87 us (52.49 x)
SendPort.Receive.Json.50KB(RunTimeRaw): | 498.81 us (1 x) | 1.24 us (402.27 x) | 1.06 us (470.58 x)
SendPort.Receive.Json.500KB(RunTimeRaw): | 5366.02 us (1 x) | 4.22 us (1271.57 x) | 4.65 us (1153.98 x)
SendPort.Receive.Json.5MB(RunTimeRaw): | 101050.88 us (1 x) | 20.81 us (4855.88 x) | 21.0 us (4811.95 x)
SendPort.Receive.BinaryTree.2(RunTimeRaw): | 3.91 us (1 x) | 0.76 us (5.14 x) | 0.74 us (5.28 x)
SendPort.Receive.BinaryTree.4(RunTimeRaw): | 9.90 us (1 x) | 0.79 us (12.53 x) | 0.76 us (13.03 x)
SendPort.Receive.BinaryTree.6(RunTimeRaw): | 33.09 us (1 x) | 0.87 us (38.03 x) | 0.84 us (39.39 x)
SendPort.Receive.BinaryTree.8(RunTimeRaw): | 126.77 us (1 x) | 0.92 us (137.79 x) | 0.88 us (144.06 x)
SendPort.Receive.BinaryTree.10(RunTimeRaw): | 533.09 us (1 x) | 0.94 us (567.12 x) | 0.92 us (579.45 x)
SendPort.Receive.BinaryTree.12(RunTimeRaw): | 2223.23 us (1 x) | 3.03 us (733.74 x) | 3.04 us (731.33 x)
SendPort.Receive.BinaryTree.14(RunTimeRaw): | 8945.66 us (1 x) | 4.03 us (2219.77 x) | 4.30 us (2080.39 x)
```
Issue https://github.com/dart-lang/sdk/issues/36097
TEST=vm/dart{,_2}/isolates/fast_object_copy{,2}_test
Change-Id: I835c59dab573d365b8a4b9d7c5359a6ea8d8b0a7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/203776
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
With this change, allocation instructions can now be direct inputs to
other allocation instructions, so the redundancy eliminator is extended
to handle this possibility.
Methods for working with instruction input-related slots are added to
subclasses of AllocationInstr, so that the redundancy eliminator can be
written more generically in places, instead of needing to add cases for
new allocation instructions and/or instruction inputs.
Code size different in Flutter gallery (release-sizeopt):
* ARM7: Total -0.30%, instructions -0.41%
* ARM8: Total -0.31%, instructions -0.47%
TEST=Current test suite.
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-simarm64c-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64c-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-linux-debug-ia32-try,vm-kernel-linux-debug-x64-try,vm-kernel-linux-product-x64-try,vm-kernel-linux-release-simarm64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-x64-try,vm-kernel-linux-debug-x64c-try
Change-Id: Idc1aa2a1cb8c0c62f0bcb64aee89a7525dd3d1e1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/198406
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
This is a Dart-tailored implementation of the "row-displacement
dispatch table" technique for closed-world instance calls:
All interface targets in the program are grouped into selectors such
that all targets that could potentially be called from the same call
site have the same selector (currently just grouped by name).
Each selector is assigned a selector offset such that offset + classid
is unique for all selector/classid combinations where the class
implements the selector.
At every instance call site that has an interface target (i.e. where
the static type of the receiver is not dynamic), the selector offset +
receiver classid is computed and used as index into a global table of
entry points.
If the receiver can be null (as determined by the front-end TFA and the
VM type propagation), a null check is inserted before the call.
An arguments descriptor is provided (only) for selectors that need it
(those which have type parameters or optional/named parameters).
The dispatch table calls don't need the monomorphic entry code, so for
functions that are only called via dispatch table calls (i.e. never
called dynamically), the monomorphic entry code is left out.
Some future improvements to the table dispatch implementation are
mentioned in https://github.com/dart-lang/sdk/issues/40188
The table dispatch flag is disabled by default in this commit. A
separate commit enables the flag.
Change-Id: Ic2911742b4a2c9a8d3bc7df60605454cbe4c0714
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/126648
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
When logical expression is evaluated in the control context (e.g. if (cond) { ... })
avoid materializing a boolean value and then dispatching on it. Instead connect
true and false successors directly to then and else branches.
This CL also improves IL generated when logical expression is evaluated for value
(e.g. x = (cond)): we similarly avoid materializing intermediate results and also
avoid comparisons that are not needed, e.g. when evaluating x = A && B we construct
graph x = A ? B : false, instead of x = A ? (B == true ? true : false) : false style
of graph.
Change-Id: I204d414cc6751949641b6c46423a6319f6e2d89b
Reviewed-on: https://dart-review.googlesource.com/67562
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This fixes an issue when a program got loaded via dill, a function
with a try-catch got optimized and the exception/stacktrace variables
got captured.
Change-Id: Icb8ea5f3557080f8274f7db2af09e33154820e5b
Reviewed-on: https://dart-review.googlesource.com/55721
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
This reverts commit 23b4a505ec.
Reason for revert: The language_2/custom_await_stack_trace_test started failing.
Original change's description:
> Reland "[VM] Use IR for code in [CatchEntryInstr]s to populate captured exception/stacktrace variables"
>
> This fixes an issue when a program got loaded via dill, a function
> with a try-catch got optimized and the exception/stacktrace variables
> got captured.
>
> Change-Id: Icb626965019b248afe3b72a6679c5049ea7b7b00
> Reviewed-on: https://dart-review.googlesource.com/55681
> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
> Commit-Queue: Martin Kustermann <kustermann@google.com>
TBR=vegorov@google.com,kustermann@google.com
Change-Id: Ic825c1e3ed14c731da1d43aa6f27d37ed5d36b4c
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/55720
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This fixes an issue when a program got loaded via dill, a function
with a try-catch got optimized and the exception/stacktrace variables
got captured.
Change-Id: Icb626965019b248afe3b72a6679c5049ea7b7b00
Reviewed-on: https://dart-review.googlesource.com/55681
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This reverts commit 12759870a4.
Reason for revert: Broke many bots.
Original change's description:
> [VM] Use IR for code in [CatchEntryInstr]s to populate captured exception/stacktrace variables
>
> This fixes an issue when a program got loaded via dill, a function
> with a try-catch got optimized and the exception/stacktrace variables
> got captured.
>
> Change-Id: Ia6b62f2a0986c78b90afe7fae25025ca4e5b09db
> Reviewed-on: https://dart-review.googlesource.com/35182
> Commit-Queue: Martin Kustermann <kustermann@google.com>
> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
TBR=vegorov@google.com,kustermann@google.com
Change-Id: I2ec7b4bea401e6d5665f6e789eb8e241b99db7b3
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/36200
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This fixes an issue when a program got loaded via dill, a function
with a try-catch got optimized and the exception/stacktrace variables
got captured.
Change-Id: Ia6b62f2a0986c78b90afe7fae25025ca4e5b09db
Reviewed-on: https://dart-review.googlesource.com/35182
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>