mirror of
https://github.com/dart-lang/sdk
synced 2024-10-07 12:35:04 +00:00
[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:
parent
7bc9ca5ee9
commit
405734f18b
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue