2887fe0b2c
This change updates `FlowModel.promotionInfo`, the primary data
structure used by flow analysis to track program state, so that
instead of being a `Map<int, PromotionModel<Type>>`, it is represented
by a new data structure called a `FlowLink`, an immutable data
structure describing program state in a way that's particularly
optimized for flow analysis's usage patterns.
Like a map, a `FlowLink` data structure represents a collection of
key/value pairs (where the keys are integers), however instead of
storing the keys and values in a hashtable, each `FlowLink` object
contains a single key/value pair and a pointer to a previous
`FlowLink` object. The value associated with a given key can be looked
up by starting with the current `FlowLink` and walking backwards
through the linked list of `previous` pointers until a matching key is
found. (An empty map is represented by `null`). This makes it an
`O(1)` operation to update the promotion state associated with a
single promotion key (an operation that flow analysis performs
frequently), since all that is required is a single allocation.
If the `previous` pointers are regarded as parent pointers, all the
`FlowLink` objects produced by a given run of flow analysis form a
tree that mirrors the dominator tree of the code being analyzed.
To optimize reads of `FlowLink` data structures, there is a
`FlowLinkReader` class that keeps track of a lookup table reflecting
the implicit map represented by a given `FlowLink` object; this table
can be updated to reflect a different `FlowLink` object in `O(n)`
time, where `n` is the number of edges between the two `FlowLink`
objects in the tree. Since flow analysis is based on a depth-first
traversal of the syntax tree of the code being analyzed, it has a high
degree of tree locality in the `FlowLink` objects it needs to be able
to read, so these `O(n)` updates do not consume much CPU.
The `FlowLinkReader` class is also able to compute a difference
between the program states represented by two `FlowLink` objects, in
`O(n)` time, where `n` is the number of edges between the two
`FlowLink` objects in the tree. This is used by flow analysis to
compute the program state after a control flow join, so that it does
not need to spend any time examining promotion keys that are unchanged
since the corresponding control flow split.
For more information about the `FlowLink` data structure and how it
works, see the comments in `flow_link.dart`.
This change improves the performance of CFE compilation fairly
substantially:
instructions:u: -0.8167% +/- 0.0007% (-158214865.67 +/- 130252.25)
branches:u: -0.4694% +/- 0.0009% (-18575169.00 +/- 37220.97)
branch-misses:u: -1.0009% +/- 0.7189% (-575742.67 +/- 413521.70)
Change-Id: Ia87458ee599977e6efdc9f0e7aa283a41f84f616
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/326900
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Morgan :) <davidmorgan@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
FE/analyzer shared code
This package contains logic that is shared between the front_end and analyzer packages. It is intended solely to facilitate development of the Dart SDK, and is not intended for use by end users. In particular, this package has no public API, so no guarantee is made of compatibility between one version of the package and the next.
End users should consider using the analyzer package to analyze Dart source code.