[dart2js] lazyFinal can use a variable for the result.

Returning the value is faster than reading the holder slot on V8.
Some benchmarks which read a lazy final in a tight loop are up to
40% faster.
JSC and SM unchanged.

Change-Id: I72afa456160469e4ccfe6ab80f8a53694133d794
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/220132
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
This commit is contained in:
Stephen Adams 2021-11-15 22:25:31 +00:00 committed by commit-bot@chromium.org
parent 7bc9ca5ee9
commit 405734f18b

View file

@ -189,11 +189,12 @@ function lazy(holder, name, getterName, initializer) {
};
}
// Creates a lazy final field that uses non-nullable initialization semantics.
// Creates a lazy final static field that uses non-nullable initialization
// semantics.
//
// A lazy field has a storage entry, [name], which holds the value, and a
// getter ([getterName]) to access the field. If the field wasn't set before
// the first access, it is initialized with the [initializer].
// A lazy final field has a storage entry, [name], which holds the value, and a
// getter ([getterName]) to access the field. The field is initialized on first
// access with the [initializer].
function lazyFinal(holder, name, getterName, initializer) {
var uninitializedSentinel = holder;
holder[name] = uninitializedSentinel;
@ -201,12 +202,21 @@ function lazyFinal(holder, name, getterName, initializer) {
if (holder[name] === uninitializedSentinel) {
var value = initializer();
if (holder[name] !== uninitializedSentinel) {
// Since there is no setter, the only way to get here is via bounded
// recursion, where `initializer` calls the lazy final getter.
#throwLateFieldADI(name);
}
holder[name] = value;
}
holder[getterName] = function() { return this[name]; };
return holder[name];
// TODO(sra): Does the value need to be stored in the holder at all?
// Potentially a call to the getter could be replaced with an access to
// holder slot if dominated by a previous call to the getter. Does the
// optimizer do this? If so, within a single function, the dominance
// relations should allow a local copy via GVN, so it is not that valuable
// an optimization for a `final` static variable.
var finalValue = holder[name];
holder[getterName] = function() { return finalValue; };
return finalValue;
};
}