[kernel] Call Reference.node less; make it inlinable

This CL splits up `Reference.node` in to the most-often fast-case and the
has-to-load case, making the procedure smaller which makes the VM inline
it. This was "verified" by looking at the VMs optimized flow graph for
`Reference.asClass`.

This CL furthermore reduces the number of "calls" to `Reference.node`
by almost half (a reduction of over 3 mio calls when compiling
`compile.dart`) by "caching" the `.node` call in the `as*` methods.

Change-Id: I7b5497397a11f05fdeaf05d6cc420072d98dc030
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/298101
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
This commit is contained in:
Jens Johansen 2023-04-25 10:21:46 +00:00 committed by Commit Queue
parent e5c2dd28c7
commit dc77baa5a8

View file

@ -438,26 +438,29 @@ class Reference {
NamedNode? _node; NamedNode? _node;
NamedNode? get node { NamedNode? get node {
if (_node == null) { return _node ?? _tryLoadNode();
// Either this is an unbound reference or it belongs to a lazy-loaded }
// (and not yet loaded) class. If it belongs to a lazy-loaded class,
// load the class.
CanonicalName? canonicalNameParent = canonicalName?.parent; /// If the node belongs to a lazy-loaded class load the class.
while (canonicalNameParent != null) { ///
if (canonicalNameParent.name.startsWith("@")) { /// Should only be called if [_node] is null, meaning that either this
break; /// is an unbound reference or it belongs to a lazy-loaded
} /// (and not yet loaded) class. If it belongs to a lazy-loaded class this call
canonicalNameParent = canonicalNameParent.parent; /// will load the class and set [_node].
NamedNode? _tryLoadNode() {
CanonicalName? canonicalNameParent = canonicalName?.parent;
while (canonicalNameParent != null) {
if (canonicalNameParent.name.startsWith("@")) {
break;
} }
if (canonicalNameParent != null) { canonicalNameParent = canonicalNameParent.parent;
NamedNode? parentNamedNode = }
canonicalNameParent.parent?.reference._node; if (canonicalNameParent != null) {
if (parentNamedNode is Class) { NamedNode? parentNamedNode = canonicalNameParent.parent?.reference._node;
Class parentClass = parentNamedNode; if (parentNamedNode is Class) {
if (parentClass.lazyBuilder != null) { Class parentClass = parentNamedNode;
parentClass.ensureLoaded(); if (parentClass.lazyBuilder != null) {
} parentClass.ensureLoaded();
} }
} }
} }
@ -499,6 +502,7 @@ class Reference {
} }
Library get asLibrary { Library get asLibrary {
NamedNode? node = this.node;
if (node == null) { if (node == null) {
throw '$this is not bound to an AST node. A library was expected'; throw '$this is not bound to an AST node. A library was expected';
} }
@ -506,6 +510,7 @@ class Reference {
} }
Class get asClass { Class get asClass {
NamedNode? node = this.node;
if (node == null) { if (node == null) {
throw '$this is not bound to an AST node. A class was expected'; throw '$this is not bound to an AST node. A class was expected';
} }
@ -513,6 +518,7 @@ class Reference {
} }
Member get asMember { Member get asMember {
NamedNode? node = this.node;
if (node == null) { if (node == null) {
throw '$this is not bound to an AST node. A member was expected'; throw '$this is not bound to an AST node. A member was expected';
} }
@ -520,6 +526,7 @@ class Reference {
} }
Field get asField { Field get asField {
NamedNode? node = this.node;
if (node == null) { if (node == null) {
throw '$this is not bound to an AST node. A field was expected'; throw '$this is not bound to an AST node. A field was expected';
} }
@ -527,6 +534,7 @@ class Reference {
} }
Constructor get asConstructor { Constructor get asConstructor {
NamedNode? node = this.node;
if (node == null) { if (node == null) {
throw '$this is not bound to an AST node. A constructor was expected'; throw '$this is not bound to an AST node. A constructor was expected';
} }
@ -534,6 +542,7 @@ class Reference {
} }
Procedure get asProcedure { Procedure get asProcedure {
NamedNode? node = this.node;
if (node == null) { if (node == null) {
throw '$this is not bound to an AST node. A procedure was expected'; throw '$this is not bound to an AST node. A procedure was expected';
} }
@ -541,6 +550,7 @@ class Reference {
} }
Typedef get asTypedef { Typedef get asTypedef {
NamedNode? node = this.node;
if (node == null) { if (node == null) {
throw '$this is not bound to an AST node. A typedef was expected'; throw '$this is not bound to an AST node. A typedef was expected';
} }
@ -548,6 +558,7 @@ class Reference {
} }
Extension get asExtension { Extension get asExtension {
NamedNode? node = this.node;
if (node == null) { if (node == null) {
throw '$this is not bound to an AST node. An extension was expected'; throw '$this is not bound to an AST node. An extension was expected';
} }
@ -555,6 +566,7 @@ class Reference {
} }
InlineClass get asInlineClass { InlineClass get asInlineClass {
NamedNode? node = this.node;
if (node == null) { if (node == null) {
throw '$this is not bound to an AST node. An inline class was expected'; throw '$this is not bound to an AST node. An inline class was expected';
} }