[array] Prepare Array.p.shift for removal of the JavaScript fall-back
This CL changes the ArrayPrototypeShift builtin to a CSA macro which is used in a newly created Torque builtin. This is in preparation for removing the JavaScript fall-back, which will be replaced by a baseline Torque implementation. R=cbruni@chromium.org, jgruber@chromium.org Bug: v8:7624 Change-Id: I9b7898beea2802cc02d394e040a1e500387cf108 Reviewed-on: https://chromium-review.googlesource.com/1169172 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Simon Zünd <szuend@google.com> Cr-Commit-Position: refs/heads/master@{#55036}
This commit is contained in:
parent
1536ef9052
commit
f4ca3fc56e
1
BUILD.gn
1
BUILD.gn
@ -872,6 +872,7 @@ torque_files = [
|
||||
"src/builtins/array.tq",
|
||||
"src/builtins/array-copywithin.tq",
|
||||
"src/builtins/array-foreach.tq",
|
||||
"src/builtins/array-shift.tq",
|
||||
"src/builtins/typed-array.tq",
|
||||
"src/builtins/data-view.tq",
|
||||
"test/torque/test-torque.tq",
|
||||
|
25
src/builtins/array-shift.tq
Normal file
25
src/builtins/array-shift.tq
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
module array {
|
||||
extern macro GenerateFastArrayShift(Context, Object): Object labels Slow;
|
||||
extern builtin ArrayShift(Context, JSFunction, Object, int32): void;
|
||||
|
||||
// https://tc39.github.io/ecma262/#sec-array.prototype.shift
|
||||
javascript builtin ArrayPrototypeShift(
|
||||
context: Context, receiver: Object, ...arguments): Object {
|
||||
try {
|
||||
return GenerateFastArrayShift(context, receiver) otherwise Slow;
|
||||
}
|
||||
label Slow {
|
||||
// TODO(szuend): Move checks if FastElementsAccessor::shift can be used
|
||||
// from the C++ builtin here.
|
||||
tail ArrayShift(
|
||||
context, LoadTargetFromFrame(), Undefined,
|
||||
convert<int32>(arguments.length));
|
||||
}
|
||||
|
||||
// TODO(szuend): Implement baseline Array.p.shift that replaces JS fallback.
|
||||
}
|
||||
}
|
@ -738,6 +738,7 @@ extern macro IsFixedArray(HeapObject): bool;
|
||||
extern macro IsExtensibleMap(Map): bool;
|
||||
extern macro IsCustomElementsReceiverInstanceType(int32): bool;
|
||||
extern macro Typeof(Object): Object;
|
||||
extern macro LoadTargetFromFrame(): JSFunction;
|
||||
|
||||
// Return true iff number is NaN.
|
||||
macro NumberIsNaN(number: Number): bool {
|
||||
|
@ -18,6 +18,8 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
using Node = compiler::Node;
|
||||
template <class T>
|
||||
using TNode = compiler::TNode<T>;
|
||||
|
||||
ArrayBuiltinsAssembler::ArrayBuiltinsAssembler(
|
||||
compiler::CodeAssemblerState* state)
|
||||
@ -1503,17 +1505,9 @@ TF_BUILTIN(ArrayPrototypeSlice, ArrayPrototypeSliceCodeStubAssembler) {
|
||||
args.PopAndReturn(a);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayPrototypeShift, CodeStubAssembler) {
|
||||
TNode<Int32T> argc =
|
||||
UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
|
||||
|
||||
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
|
||||
TNode<Object> receiver = args.GetReceiver();
|
||||
|
||||
Label runtime(this, Label::kDeferred);
|
||||
Label fast(this);
|
||||
TNode<Object> ArrayBuiltinsAssembler::GenerateFastArrayShift(
|
||||
TNode<Context> context, TNode<Object> receiver, Label* slow) {
|
||||
Label fast(this), done(this);
|
||||
|
||||
// Only shift in this stub if
|
||||
// 1) the array has fast elements
|
||||
@ -1523,10 +1517,11 @@ TF_BUILTIN(ArrayPrototypeShift, CodeStubAssembler) {
|
||||
// 5) we aren't supposed to left-trim the backing store.
|
||||
|
||||
// 1) Check that the array has fast elements.
|
||||
BranchIfFastJSArray(receiver, context, &fast, &runtime);
|
||||
BranchIfFastJSArray(receiver, context, &fast, slow);
|
||||
|
||||
BIND(&fast);
|
||||
{
|
||||
TVARIABLE(Object, result, UndefinedConstant());
|
||||
TNode<JSArray> array_receiver = CAST(receiver);
|
||||
CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array_receiver)));
|
||||
Node* length =
|
||||
@ -1536,13 +1531,13 @@ TF_BUILTIN(ArrayPrototypeShift, CodeStubAssembler) {
|
||||
GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined);
|
||||
|
||||
// 2) Ensure that the length is writable.
|
||||
EnsureArrayLengthWritable(LoadMap(array_receiver), &runtime);
|
||||
EnsureArrayLengthWritable(LoadMap(array_receiver), slow);
|
||||
|
||||
// 3) Check that the elements backing store isn't copy-on-write.
|
||||
Node* elements = LoadElements(array_receiver);
|
||||
GotoIf(WordEqual(LoadMap(elements),
|
||||
LoadRoot(Heap::kFixedCOWArrayMapRootIndex)),
|
||||
&runtime);
|
||||
slow);
|
||||
|
||||
Node* new_length = IntPtrSub(length, IntPtrConstant(1));
|
||||
|
||||
@ -1553,13 +1548,13 @@ TF_BUILTIN(ArrayPrototypeShift, CodeStubAssembler) {
|
||||
IntPtrAdd(IntPtrAdd(new_length, new_length),
|
||||
IntPtrConstant(JSObject::kMinAddedElementsCapacity)),
|
||||
capacity),
|
||||
&runtime);
|
||||
slow);
|
||||
|
||||
// 5) Check that we're not supposed to left-trim the backing store, as
|
||||
// implemented in elements.cc:FastElementsAccessor::MoveElements.
|
||||
GotoIf(IntPtrGreaterThan(new_length,
|
||||
IntPtrConstant(JSArray::kMaxCopyElements)),
|
||||
&runtime);
|
||||
slow);
|
||||
|
||||
StoreObjectFieldNoWriteBarrier(array_receiver, JSArray::kLengthOffset,
|
||||
SmiTag(new_length));
|
||||
@ -1577,12 +1572,10 @@ TF_BUILTIN(ArrayPrototypeShift, CodeStubAssembler) {
|
||||
Int32LessThanOrEqual(elements_kind,
|
||||
Int32Constant(HOLEY_DOUBLE_ELEMENTS)));
|
||||
|
||||
VARIABLE(result, MachineRepresentation::kTagged, UndefinedConstant());
|
||||
|
||||
Label move_elements(this);
|
||||
result.Bind(AllocateHeapNumberWithValue(LoadFixedDoubleArrayElement(
|
||||
result = AllocateHeapNumberWithValue(LoadFixedDoubleArrayElement(
|
||||
elements, IntPtrConstant(0), MachineType::Float64(), 0,
|
||||
INTPTR_PARAMETERS, &move_elements)));
|
||||
INTPTR_PARAMETERS, &move_elements));
|
||||
Goto(&move_elements);
|
||||
BIND(&move_elements);
|
||||
|
||||
@ -1612,13 +1605,14 @@ TF_BUILTIN(ArrayPrototypeShift, CodeStubAssembler) {
|
||||
IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
|
||||
double_hole);
|
||||
}
|
||||
args.PopAndReturn(result.value());
|
||||
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&fast_elements_tagged);
|
||||
{
|
||||
TNode<FixedArray> elements_fixed_array = CAST(elements);
|
||||
Node* value = LoadFixedArrayElement(elements_fixed_array, 0);
|
||||
TNode<Object> value = LoadFixedArrayElement(elements_fixed_array, 0);
|
||||
BuildFastLoop(
|
||||
IntPtrConstant(0), new_length,
|
||||
[&](Node* index) {
|
||||
@ -1631,13 +1625,15 @@ TF_BUILTIN(ArrayPrototypeShift, CodeStubAssembler) {
|
||||
StoreFixedArrayElement(elements_fixed_array, new_length,
|
||||
TheHoleConstant());
|
||||
GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
|
||||
args.PopAndReturn(value);
|
||||
|
||||
result = value;
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&fast_elements_smi);
|
||||
{
|
||||
TNode<FixedArray> elements_fixed_array = CAST(elements);
|
||||
Node* value = LoadFixedArrayElement(elements_fixed_array, 0);
|
||||
TNode<Object> value = LoadFixedArrayElement(elements_fixed_array, 0);
|
||||
BuildFastLoop(
|
||||
IntPtrConstant(0), new_length,
|
||||
[&](Node* index) {
|
||||
@ -1651,21 +1647,19 @@ TF_BUILTIN(ArrayPrototypeShift, CodeStubAssembler) {
|
||||
StoreFixedArrayElement(elements_fixed_array, new_length,
|
||||
TheHoleConstant());
|
||||
GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
|
||||
args.PopAndReturn(value);
|
||||
|
||||
result = value;
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&return_undefined);
|
||||
{ args.PopAndReturn(UndefinedConstant()); }
|
||||
}
|
||||
{
|
||||
result = UndefinedConstant();
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&runtime);
|
||||
{
|
||||
// We are not using Parameter(Descriptor::kJSTarget) and loading the value
|
||||
// from the current frame here in order to reduce register pressure on the
|
||||
// fast path.
|
||||
TNode<JSFunction> target = LoadTargetFromFrame();
|
||||
TailCallBuiltin(Builtins::kArrayShift, context, target, UndefinedConstant(),
|
||||
argc);
|
||||
BIND(&done);
|
||||
return result.value();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,6 +145,9 @@ class ArrayBuiltinsAssembler : public BaseBuiltinsFromDSLAssembler {
|
||||
void GenerateInternalArrayNoArgumentConstructor(ElementsKind kind);
|
||||
void GenerateInternalArraySingleArgumentConstructor(ElementsKind kind);
|
||||
|
||||
TNode<Object> GenerateFastArrayShift(TNode<Context> context,
|
||||
TNode<Object> receiver, Label* slow);
|
||||
|
||||
private:
|
||||
static ElementsKind ElementsKindForInstanceType(InstanceType type);
|
||||
|
||||
|
@ -312,7 +312,6 @@ namespace internal {
|
||||
TFJ(ArrayPrototypePush, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-array.prototype.shift */ \
|
||||
CPP(ArrayShift) \
|
||||
TFJ(ArrayPrototypeShift, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-array.prototype.slice */ \
|
||||
TFJ(ArrayPrototypeSlice, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-array.prototype.splice */ \
|
||||
|
Loading…
Reference in New Issue
Block a user