[builtins] FastCreateDataProperty avoids runtime calls

If we make use of this in the generic Array.prototype.filter case
we get a performance boost of over 60%.

Bug: v8:8213, chromium:920187
Change-Id: Ia116a852f355a9f037850aee86db7284f0023929
Reviewed-on: https://chromium-review.googlesource.com/c/1484297
Reviewed-by: Daniel Clifford <danno@chromium.org>
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59979}
This commit is contained in:
Mike Stanton 2019-03-01 14:26:17 +01:00 committed by Commit Bot
parent a66712deba
commit 7d971fb022
8 changed files with 66 additions and 12 deletions

View File

@ -46,7 +46,7 @@ namespace array_filter {
// the output array. After incrementing k and to, we can glide into the loop
// continuation builtin.
if (ToBoolean(result)) {
CreateDataProperty(outputArray, numberTo, valueK);
FastCreateDataProperty(outputArray, numberTo, valueK);
numberTo = numberTo + 1;
}
@ -83,7 +83,7 @@ namespace array_filter {
// iii. If selected is true, then...
if (ToBoolean(result)) {
// 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue).
CreateDataProperty(array, to, kValue);
FastCreateDataProperty(array, to, kValue);
// 2. Increase to by 1.
to = to + 1;
}
@ -123,7 +123,7 @@ namespace array_filter {
fastOutputW.Push(value) otherwise SlowStore;
}
label SlowStore {
CreateDataProperty(fastOutputW.stable, to, value);
FastCreateDataProperty(fastOutputW.stable, to, value);
}
to = to + 1;
}

View File

@ -44,7 +44,7 @@ namespace array_map {
// continuation builtin.
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
CreateDataProperty(outputArray, numberK, result);
FastCreateDataProperty(outputArray, numberK, result);
// 7d. Increase k by 1.
numberK = numberK + 1;
@ -78,7 +78,7 @@ namespace array_map {
Call(context, callbackfn, thisArg, kValue, k, o);
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
CreateDataProperty(array, k, mappedValue);
FastCreateDataProperty(array, k, mappedValue);
}
// 7d. Increase k by 1. (done by the loop).

View File

@ -39,7 +39,7 @@ namespace array_of {
// b. Let Pk be ! ToString(k).
// c. Perform ? CreateDataPropertyOrThrow(A, Pk, kValue).
CreateDataProperty(a, k, kValue);
FastCreateDataProperty(a, k, kValue);
// d. Increase k by 1.
k++;

View File

@ -193,7 +193,7 @@ namespace array_slice {
const kValue: Object = GetProperty(o, pK);
// ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(n), kValue).
CreateDataProperty(a, n, kValue);
FastCreateDataProperty(a, n, kValue);
}
// d. Increase k by 1.

View File

@ -197,7 +197,7 @@ namespace array_splice {
const fromValue: Object = GetProperty(o, from);
// ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(k), fromValue).
CreateDataProperty(a, k, fromValue);
FastCreateDataProperty(a, k, fromValue);
}
// d. Increment k by 1.

View File

@ -675,8 +675,6 @@ extern builtin ToString(Context, Object): String;
extern transitioning runtime NormalizeElements(Context, JSObject);
extern transitioning runtime TransitionElementsKindWithKind(
Context, JSObject, Smi);
extern transitioning runtime CreateDataProperty(implicit context: Context)(
JSReceiver, Object, Object);
extern macro LoadBufferObject(RawPtr, constexpr int32): Object;
extern macro LoadBufferPointer(RawPtr, constexpr int32): RawPtr;
@ -1861,3 +1859,51 @@ macro BranchIfFastJSArrayForCopy(o: Object, context: Context): never
macro IsFastJSArrayWithNoCustomIteration(context: Context, o: Object): bool {
return Is<FastJSArrayWithNoCustomIteration>(o);
}
extern transitioning runtime
CreateDataProperty(implicit context: Context)(JSReceiver, Object, Object);
transitioning builtin FastCreateDataProperty(implicit context: Context)(
receiver: JSReceiver, key: Object, value: Object): Object {
try {
let array = Cast<FastJSArray>(receiver) otherwise Slow;
const index: Smi = Cast<Smi>(key) otherwise goto Slow;
if (index < 0 || index > array.length) goto Slow;
array::EnsureWriteableFastElements(array);
const isAppend = index == array.length;
const kind = array.map.elements_kind;
// We may have to transition a.
// For now, if transition is required, jump away to slow.
if (IsFastSmiElementsKind(kind)) {
const smiValue = Cast<Smi>(value) otherwise Slow;
if (isAppend) {
BuildAppendJSArray(HOLEY_SMI_ELEMENTS, array, value) otherwise Slow;
} else {
const elements = Cast<FixedArray>(array.elements) otherwise unreachable;
elements[index] = smiValue;
}
} else if (IsDoubleElementsKind(kind)) {
const numberValue = Cast<Number>(value) otherwise Slow;
if (isAppend) {
BuildAppendJSArray(HOLEY_DOUBLE_ELEMENTS, array, value)
otherwise Slow;
} else {
const doubleElements = Cast<FixedDoubleArray>(array.elements)
otherwise unreachable;
doubleElements[index] = numberValue;
}
} else {
assert(IsFastSmiOrTaggedElementsKind(kind));
if (isAppend) {
BuildAppendJSArray(HOLEY_ELEMENTS, array, value) otherwise Slow;
} else {
const elements = Cast<FixedArray>(array.elements) otherwise unreachable;
elements[index] = value;
}
}
}
label Slow {
CreateDataProperty(receiver, key, value);
}
return Undefined;
}

View File

@ -22,7 +22,7 @@ namespace object {
// Symbol.toPrimitive, toString, and valueOf, which could
// invalidate assumptions about the iterable.
if (Is<JSReceiver>(pair.key)) goto IfSlow;
CreateDataProperty(result, pair.key, pair.value);
FastCreateDataProperty(result, pair.key, pair.value);
}
return result;
}
@ -55,7 +55,7 @@ namespace object {
iterator::IteratorValue(step, fastIteratorResultMap);
const pair: KeyValuePair =
collections::LoadKeyValuePair(iteratorValue);
CreateDataProperty(result, pair.key, pair.value);
FastCreateDataProperty(result, pair.key, pair.value);
}
return result;
} catch (e) deferred {

View File

@ -980,6 +980,14 @@ static bool TransitivelyCalledBuiltinHasNoSideEffect(Builtins::Name caller,
default:
return false;
}
case Builtins::kFastCreateDataProperty:
switch (caller) {
case Builtins::kArrayPrototypeSlice:
case Builtins::kArrayFilter:
return true;
default:
return false;
}
case Builtins::kSetProperty:
switch (caller) {
case Builtins::kArrayPrototypeSlice: