Commit 642478bb authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[csa] Add Array.prototype.pop fast path

Bug: v8:6364,v8:6344
Change-Id: I13bf1ec89a17c64b38b757694ee8b7df30d4f45f
Reviewed-on: https://chromium-review.googlesource.com/497428
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45133}
parent 9a572e1d
......@@ -730,6 +730,103 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
Label fully_spec_compliant_;
};
TF_BUILTIN(FastArrayPop, CodeStubAssembler) {
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget),
UndefinedConstant()));
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
Node* receiver = args.GetReceiver();
Label runtime(this, Label::kDeferred);
Label fast(this);
// Only pop in this stub if
// 1) the array has fast elements
// 2) the length is writable,
// 3) the elements backing store isn't copy-on-write,
// 4) we aren't supposed to shrink the backing store.
// 1) Check that the array has fast elements.
BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::INBOUNDS_READ,
&fast, &runtime);
BIND(&fast);
{
CSA_ASSERT(this, TaggedIsPositiveSmi(
LoadObjectField(receiver, JSArray::kLengthOffset)));
Node* length = LoadAndUntagObjectField(receiver, JSArray::kLengthOffset);
Label return_undefined(this), fast_elements(this);
GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined);
// 2) Ensure that the lenght is writable.
EnsureArrayLengthWritable(LoadMap(receiver), &runtime);
// 3) Check that the elements backing store isn't copy-on-write.
Node* elements = LoadElements(receiver);
GotoIf(WordEqual(LoadMap(elements),
LoadRoot(Heap::kFixedCOWArrayMapRootIndex)),
&runtime);
Node* new_length = IntPtrSub(length, IntPtrConstant(1));
// 4) Check that we're not supposed to shrink the backing store.
Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
GotoIf(IntPtrLessThan(IntPtrAdd(new_length, new_length), capacity),
&runtime);
StoreObjectFieldNoWriteBarrier(receiver, JSArray::kLengthOffset,
SmiTag(new_length));
Node* elements_kind = LoadMapElementsKind(LoadMap(receiver));
GotoIf(Int32LessThanOrEqual(elements_kind,
Int32Constant(TERMINAL_FAST_ELEMENTS_KIND)),
&fast_elements);
Node* value = LoadFixedDoubleArrayElement(
elements, new_length, MachineType::Float64(), 0, INTPTR_PARAMETERS,
&return_undefined);
int32_t header_size = FixedDoubleArray::kHeaderSize - kHeapObjectTag;
Node* offset = ElementOffsetFromIndex(
new_length, FAST_HOLEY_DOUBLE_ELEMENTS, INTPTR_PARAMETERS, header_size);
if (Is64()) {
Node* double_hole = Int64Constant(kHoleNanInt64);
StoreNoWriteBarrier(MachineRepresentation::kWord64, elements, offset,
double_hole);
} else {
STATIC_ASSERT(kHoleNanLower32 == kHoleNanUpper32);
Node* double_hole = Int32Constant(kHoleNanLower32);
StoreNoWriteBarrier(MachineRepresentation::kWord32, elements, offset,
double_hole);
StoreNoWriteBarrier(MachineRepresentation::kWord32, elements,
IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
double_hole);
}
args.PopAndReturn(AllocateHeapNumberWithValue(value));
Bind(&fast_elements);
{
Node* value = LoadFixedArrayElement(elements, new_length);
StoreFixedArrayElement(elements, new_length, TheHoleConstant());
GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
args.PopAndReturn(value);
}
BIND(&return_undefined);
{ args.PopAndReturn(UndefinedConstant()); }
}
BIND(&runtime);
{
Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
MachineType::TaggedPointer());
TailCallStub(CodeFactory::ArrayPop(isolate()), context, target,
UndefinedConstant(), argc);
}
}
TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
VARIABLE(arg_index, MachineType::PointerRepresentation());
Label default_label(this, &arg_index);
......@@ -744,7 +841,8 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
// arguments are reordered.
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget),
UndefinedConstant()));
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
Node* receiver = args.GetReceiver();
......@@ -854,8 +952,8 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
{
Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
MachineType::TaggedPointer());
TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target,
argc);
TailCallStub(CodeFactory::ArrayPush(isolate()), context, target,
UndefinedConstant(), argc);
}
}
......
......@@ -257,6 +257,7 @@ namespace internal {
TFJ(ArrayIndexOf, 2, kSearchElement, kFromIndex) \
/* ES6 #sec-array.prototype.pop */ \
CPP(ArrayPop) \
TFJ(FastArrayPop, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-array.prototype.push */ \
CPP(ArrayPush) \
TFJ(FastArrayPush, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
......
......@@ -499,6 +499,11 @@ Callable CodeFactory::ArrayConstructor(Isolate* isolate) {
return make_callable(stub);
}
// static
Callable CodeFactory::ArrayPop(Isolate* isolate) {
return Callable(isolate->builtins()->ArrayPop(), BuiltinDescriptor(isolate));
}
// static
Callable CodeFactory::ArrayPush(Isolate* isolate) {
return Callable(isolate->builtins()->ArrayPush(), BuiltinDescriptor(isolate));
......
......@@ -182,6 +182,7 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable InterpreterOnStackReplacement(Isolate* isolate);
static Callable ArrayConstructor(Isolate* isolate);
static Callable ArrayPop(Isolate* isolate);
static Callable ArrayPush(Isolate* isolate);
static Callable FunctionPrototypeBind(Isolate* isolate);
static Callable PromiseHandleReject(Isolate* isolate);
......
......@@ -1544,6 +1544,16 @@ Node* CodeStubAssembler::StoreFixedDoubleArrayElement(
return StoreNoWriteBarrier(rep, object, offset, value);
}
void CodeStubAssembler::EnsureArrayLengthWritable(Node* map, Label* bailout) {
// Check whether the length property is writable. The length property is the
// only default named property on arrays. It's nonconfigurable, hence is
// guaranteed to stay the first property.
Node* descriptors = LoadMapDescriptors(map);
Node* details =
LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0));
GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask), bailout);
}
Node* CodeStubAssembler::EnsureArrayPushable(Node* receiver, Label* bailout) {
// Disallow pushing onto prototypes. It might be the JSArray prototype.
// Disallow pushing onto non-extensible objects.
......@@ -1560,13 +1570,7 @@ Node* CodeStubAssembler::EnsureArrayPushable(Node* receiver, Label* bailout) {
Comment("Disallow pushing onto arrays in dictionary named property mode");
GotoIf(IsDictionaryMap(map), bailout);
// Check whether the length property is writable. The length property is the
// only default named property on arrays. It's nonconfigurable, hence is
// guaranteed to stay the first property.
Node* descriptors = LoadMapDescriptors(map);
Node* details =
LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0));
GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask), bailout);
EnsureArrayLengthWritable(map, bailout);
Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
return kind;
......
......@@ -509,6 +509,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* object, Node* index, Node* value,
ParameterMode parameter_mode = INTPTR_PARAMETERS);
void EnsureArrayLengthWritable(Node* map, Label* bailout);
// EnsureArrayPushable verifies that receiver is:
// 1. Is not a prototype.
// 2. Is not a dictionary.
......
......@@ -52,7 +52,7 @@ RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
Handle<JSObject> holder =
isolate->factory()->NewJSObject(isolate->object_function());
InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
InstallBuiltin(isolate, holder, "pop", Builtins::kFastArrayPop);
InstallBuiltin(isolate, holder, "push", Builtins::kFastArrayPush);
InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
......
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