Commit 5b427ad2 authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

[builtins] Add a fast-path for Apply with double elements.

Double element types were much slower than Smi/Object previously.
We can box each double in a HeapNumber and push them into a new
FixedArray to save going into the runtime.

Bug: v8:4826, chromium:704966
Change-Id: I7f15d0d636a52760daefed722265c696c1ebb13e
Reviewed-on: https://chromium-review.googlesource.com/531004
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45897}
parent b0c70d55
...@@ -103,7 +103,7 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike( ...@@ -103,7 +103,7 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
Node* target, Node* new_target, Node* arguments_list, Node* context) { Node* target, Node* new_target, Node* arguments_list, Node* context) {
Variable var_elements(this, MachineRepresentation::kTagged); Variable var_elements(this, MachineRepresentation::kTagged);
Variable var_length(this, MachineRepresentation::kWord32); Variable var_length(this, MachineRepresentation::kWord32);
Label if_done(this), if_arguments(this), if_array(this), Label if_done(this), if_arguments(this), if_array(this), if_double(this),
if_holey_array(this, Label::kDeferred), if_holey_array(this, Label::kDeferred),
if_runtime(this, Label::kDeferred); if_runtime(this, Label::kDeferred);
...@@ -119,6 +119,7 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike( ...@@ -119,6 +119,7 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX); LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX);
GotoIf(WordEqual(arguments_list_map, strict_arguments_map), &if_arguments); GotoIf(WordEqual(arguments_list_map, strict_arguments_map), &if_arguments);
Node* kind = LoadMapElementsKind(arguments_list_map);
// Check if {arguments_list} is a fast JSArray. // Check if {arguments_list} is a fast JSArray.
Branch(IsJSArrayMap(arguments_list_map), &if_array, &if_runtime); Branch(IsJSArrayMap(arguments_list_map), &if_array, &if_runtime);
...@@ -131,17 +132,22 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike( ...@@ -131,17 +132,22 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
JSArray::kLengthOffset)); JSArray::kLengthOffset));
// Holey arrays and double backing stores need special treatment. // Holey arrays and double backing stores need special treatment.
Node* kind = LoadMapElementsKind(arguments_list_map);
STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(FAST_ELEMENTS == 2); STATIC_ASSERT(FAST_ELEMENTS == 2);
STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
GotoIf(Word32Equal(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), STATIC_ASSERT(FAST_DOUBLE_ELEMENTS == 4);
&if_holey_array); STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
GotoIf(Word32Equal(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), STATIC_ASSERT(LAST_FAST_ELEMENTS_KIND == FAST_HOLEY_DOUBLE_ELEMENTS);
&if_holey_array);
Branch(Uint32LessThanOrEqual(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), GotoIf(Int32GreaterThan(kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
&if_done, &if_runtime); &if_runtime);
GotoIf(Word32And(kind, Int32Constant(1)), &if_holey_array);
GotoIf(Word32Equal(kind, Int32Constant(FAST_DOUBLE_ELEMENTS)), &if_double);
CSA_ASSERT(this,
Word32Or(Word32Equal(kind, Int32Constant(FAST_ELEMENTS)),
Word32Equal(kind, Int32Constant(FAST_SMI_ELEMENTS))));
Goto(&if_done);
} }
BIND(&if_holey_array); BIND(&if_holey_array);
...@@ -155,10 +161,46 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike( ...@@ -155,10 +161,46 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
&if_runtime); &if_runtime);
Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex); Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex);
DCHECK(isolate()->heap()->array_protector()->IsPropertyCell()); DCHECK(isolate()->heap()->array_protector()->IsPropertyCell());
Branch( GotoIfNot(
WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset), WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
SmiConstant(Smi::FromInt(Isolate::kProtectorValid))), SmiConstant(Smi::FromInt(Isolate::kProtectorValid))),
&if_done, &if_runtime); &if_runtime);
Branch(Word32Equal(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)),
&if_double, &if_done);
}
BIND(&if_double);
{
// For JSArrays of doubles, we need to box the elements as they will be
// pushed onto the stack.
Label if_holey_double(this), if_packed_double(this);
Node* elements = var_elements.value();
Node* length = ChangeInt32ToIntPtr(var_length.value());
const ElementsKind new_kind = FAST_ELEMENTS;
// Allocate a new FixedArray of Objects.
Node* new_elements = AllocateFixedArray(FAST_ELEMENTS, length);
Branch(Word32Equal(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)),
&if_holey_double, &if_packed_double);
BIND(&if_holey_double);
{
// Fill the FixedArray with pointers to HeapObjects.
CopyFixedArrayElements(FAST_HOLEY_DOUBLE_ELEMENTS, elements, new_kind,
new_elements, length, length);
var_elements.Bind(new_elements);
Goto(&if_done);
}
BIND(&if_packed_double);
{
CopyFixedArrayElements(FAST_DOUBLE_ELEMENTS, elements, new_kind,
new_elements, length, length);
var_elements.Bind(new_elements);
Goto(&if_done);
}
} }
BIND(&if_arguments); BIND(&if_arguments);
......
...@@ -141,6 +141,28 @@ for (var j = 1; j < 0x400000; j <<= 1) { ...@@ -141,6 +141,28 @@ for (var j = 1; j < 0x400000; j <<= 1) {
} }
} }
// Check packed double arrays
var arr = [0.0];
for (var i = 1; i < 4; i++) {
arr.push(i * 0.1);
}
assertEquals(0.0, Math.min.apply(Math, arr));
assertEquals(0.30000000000000004, Math.max.apply(Math, arr));
// Check holey double arrays
var arr = Array(4);
for (var i = 0; i < 4; i++) {
arr[i] = i * 0.1;
}
assertEquals(0.0, Math.min.apply(Math, arr));
assertEquals(0.30000000000000004, Math.max.apply(Math, arr));
// Check that holes are set properly
arr[5] = 0.5;
assertEquals(NaN, Math.min.apply(Math, arr));
assertEquals(NaN, Math.max.apply(Math, arr));
var primes = new Array(0); var primes = new Array(0);
function isPrime(possible_prime) { function isPrime(possible_prime) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment