Commit ff4fa92e authored by Mike Stanton's avatar Mike Stanton Committed by Commit Bot

[builtins] Enable Torque Array.prototype.splice

Before, splice was implemented with a C++ fast path and a
comprehensive JavaScript version.

This impl. is entirely in Torque with a fastpath for SMI,
DOUBLE and OBJECT arrays, and a comprehensive slow path.
The same level of "sparse" array support as given by the
array.js implementation is included.

Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: Ibfa3407ed75b9ad15ac54cce446b3952e38f90a9
Reviewed-on: https://chromium-review.googlesource.com/1039190Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54974}
parent da3c2db9
......@@ -872,6 +872,7 @@ torque_files = [
"src/builtins/array.tq",
"src/builtins/array-foreach.tq",
"src/builtins/array-sort.tq",
"src/builtins/array-splice.tq",
"src/builtins/typed-array.tq",
"src/builtins/data-view.tq",
"test/torque/test-torque.tq",
......
......@@ -1738,13 +1738,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
1, false);
SimpleInstallFunction(isolate_, proto, "slice",
Builtins::kArrayPrototypeSlice, 2, false);
if (FLAG_enable_experimental_builtins) {
SimpleInstallFunction(isolate_, proto, "splice",
Builtins::kArraySpliceTorque, 2, false);
} else {
SimpleInstallFunction(isolate_, proto, "splice", Builtins::kArraySplice,
2, false);
}
SimpleInstallFunction(isolate_, proto, "splice", Builtins::kArraySplice, 2,
false);
SimpleInstallFunction(isolate_, proto, "includes", Builtins::kArrayIncludes,
1, false);
SimpleInstallFunction(isolate_, proto, "indexOf", Builtins::kArrayIndexOf,
......
......@@ -61,6 +61,10 @@ module array {
let callbackfn: Callable = cast<Callable>(callback) otherwise Unexpected;
let k: Smi = cast<Smi>(initialK) otherwise Unexpected;
let number_length: Number = cast<Number>(length) otherwise Unexpected;
// The unsafe cast is safe because all continuation points in forEach are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
let jsreceiver: JSReceiver = unsafe_cast<JSReceiver>(object);
return ArrayForEachTorqueContinuation(
context, receiver, number_length, callbackfn, thisArg, k);
......
This diff is collapsed.
This diff is collapsed.
......@@ -106,6 +106,10 @@ type FixedUint8ClampedArray extends FixedTypedArray;
type FixedBigUint64Array extends FixedTypedArray;
type FixedBigInt64Array extends FixedTypedArray;
const kFixedArrays: constexpr ExtractFixedArrayFlags generates
'ExtractFixedArrayFlag::kFixedArrays';
const kFixedDoubleArrays: constexpr ExtractFixedArrayFlags generates
'ExtractFixedArrayFlag::kFixedDoubleArrays';
const kAllFixedArrays: constexpr ExtractFixedArrayFlags generates
'ExtractFixedArrayFlag::kAllFixedArrays';
......@@ -164,6 +168,7 @@ extern macro Is64(): constexpr bool;
extern macro Print(constexpr string);
extern macro Print(constexpr string, Object);
extern macro Comment(constexpr string);
extern macro Print(Object);
extern macro DebugBreak();
extern macro ToInteger_Inline(Context, Object): Number;
......@@ -188,7 +193,8 @@ extern macro ThrowTypeError(Context, constexpr MessageTemplate): never;
extern macro ThrowTypeError(Context, constexpr MessageTemplate, Object): never;
extern macro ThrowTypeError(
Context, constexpr MessageTemplate, Object, Object, Object): never;
extern macro ArraySpeciesCreate(Context, Object, Number): Object;
extern macro ArraySpeciesCreate(Context, Object, Number): JSReceiver;
extern macro InternalArrayCreate(Context, Number): JSArray;
extern macro EnsureArrayPushable(Map): ElementsKind labels Bailout;
extern builtin ToObject(Context, Object): JSReceiver;
......@@ -197,7 +203,9 @@ extern macro IsTheHole(Object): bool;
extern macro IsString(HeapObject): bool;
extern builtin ToString(Context, Object): String;
extern runtime CreateDataProperty(Context, Object, Object, Object);
extern runtime NormalizeElements(Context, JSObject);
extern runtime TransitionElementsKindWithKind(Context, JSObject, Smi);
extern runtime CreateDataProperty(Context, JSReceiver, Object, Object);
extern runtime SetProperty(Context, Object, Object, Object, LanguageMode);
extern runtime DeleteProperty(Context, Object, Object, LanguageMode);
......@@ -226,6 +234,10 @@ extern operator '>=' macro SmiGreaterThanOrEqual(Smi, Smi): bool;
extern operator '==' macro ElementsKindEqual(
constexpr ElementsKind, constexpr ElementsKind): constexpr bool;
extern operator '==' macro ElementsKindEqual(ElementsKind, ElementsKind): bool;
operator '!=' macro ElementsKindNotEqual(
k1: ElementsKind, k2: ElementsKind): bool {
return !ElementsKindEqual(k1, k2);
}
extern macro IsFastElementsKind(constexpr ElementsKind): constexpr bool;
extern macro IsDoubleElementsKind(constexpr ElementsKind): constexpr bool;
......@@ -244,11 +256,14 @@ extern operator '>=' macro UintPtrGreaterThanOrEqual(uintptr, uintptr): bool;
extern operator '==' macro Float64Equal(float64, float64): bool;
extern operator '!=' macro Float64NotEqual(float64, float64): bool;
extern operator
'==' macro BranchIfNumberEqual(Number, Number): never labels Taken, NotTaken;
extern operator
'<' macro BranchIfNumberLessThan(Number, Number): never labels Taken, NotTaken;
extern operator
'<=' macro BranchIfNumberLessThanOrEqual(Number, Number): never labels Taken,
NotTaken;
extern operator
'>' macro BranchIfNumberGreaterThan(Number, Number): never labels Taken,
NotTaken;
......@@ -315,8 +330,8 @@ extern operator '.length' macro GetArgumentsLength(constexpr Arguments): intptr;
extern operator
'[]' macro GetArgumentValue(constexpr Arguments, intptr): Object;
extern operator 'is<Smi>' macro TaggedIsSmi(Object): bool;
extern operator 'isnt<Smi>' macro TaggedIsNotSmi(Object): bool;
extern macro TaggedIsSmi(Object): bool;
extern macro TaggedIsNotSmi(Object): bool;
extern macro TaggedIsPositiveSmi(Object): bool;
extern macro HeapObjectToJSDataView(HeapObject): JSDataView labels CastError;
......@@ -462,6 +477,13 @@ from_constexpr<Object>(s: constexpr string): Object {
macro convert<A : type>(i: constexpr int31): A {
return i;
}
extern macro ConvertElementsKindToInt(ElementsKind): int32;
macro convert<A : type>(elements_kind: ElementsKind): A;
convert<int32>(elements_kind: ElementsKind): int32 {
return ConvertElementsKindToInt(elements_kind);
}
macro convert<A : type>(i: int32): A;
convert<Number>(i: int32): Number {
return ChangeInt32ToTagged(i);
......@@ -548,6 +570,9 @@ unsafe_cast<HeapNumber>(n: Number): HeapNumber {
return UnsafeCastNumberToHeapNumber(n);
}
macro unsafe_cast<A : type>(o: Object): A;
unsafe_cast<Object>(o: Object): Object {
return o;
}
unsafe_cast<FixedArray>(o: Object): FixedArray {
return UnsafeCastObjectToFixedArray(o);
}
......@@ -634,6 +659,10 @@ extern operator
FixedArray, constexpr int31, Object): void;
extern operator
'[]=' macro StoreFixedArrayElementSmi(FixedArray, Smi, Object): void;
operator '[]=' macro StoreFixedDoubleArrayNumber(
a: FixedDoubleArray, index: Smi, value: Number): void {
a[index] = convert<float64>(value);
}
extern operator '.instance_type' macro LoadMapInstanceType(Map): int32;
......@@ -659,6 +688,28 @@ extern macro IsFastSmiOrTaggedElementsKind(ElementsKind): bool;
extern macro IsFastSmiElementsKind(ElementsKind): bool;
extern macro IsHoleyFastElementsKind(ElementsKind): bool;
macro AllowDoubleElements(kind: ElementsKind): ElementsKind {
if (kind == PACKED_SMI_ELEMENTS) {
return PACKED_DOUBLE_ELEMENTS;
} else if (kind == HOLEY_SMI_ELEMENTS) {
return HOLEY_DOUBLE_ELEMENTS;
}
return kind;
}
macro AllowNonNumberElements(kind: ElementsKind): ElementsKind {
if (kind == PACKED_SMI_ELEMENTS) {
return PACKED_ELEMENTS;
} else if (kind == HOLEY_SMI_ELEMENTS) {
return HOLEY_ELEMENTS;
} else if (kind == PACKED_DOUBLE_ELEMENTS) {
return PACKED_ELEMENTS;
} else if (kind == HOLEY_DOUBLE_ELEMENTS) {
return HOLEY_ELEMENTS;
}
return kind;
}
extern macro AllocateFixedArray(constexpr ElementsKind, intptr): FixedArray;
extern macro CopyFixedArrayElements(
......@@ -673,8 +724,13 @@ extern macro AllocateJSArray(constexpr ElementsKind, Map, Smi, Smi): JSArray;
extern macro IsElementsKindGreaterThan(
ElementsKind, constexpr ElementsKind): bool;
extern operator
'[]=' macro StoreFixedDoubleArrayElementSmi(
FixedDoubleArray, Smi, float64): void;
extern macro LoadDoubleWithHoleCheck(FixedDoubleArray, Smi): float64
labels IfHole;
extern macro StoreFixedDoubleArrayHoleSmi(FixedDoubleArray, Smi): void;
extern macro Call(Context, Callable, Object): Object;
extern macro Call(Context, Callable, Object, Object): Object;
......@@ -685,8 +741,9 @@ extern macro Call(
extern macro Call(
Context, Callable, Object, Object, Object, Object, Object, Object): Object;
extern macro ExtractFixedArray(FixedArray, Smi, Smi, Smi): FixedArray;
extern macro ExtractFixedArray(
FixedArray, Smi, Smi, Smi, constexpr ExtractFixedArrayFlags): FixedArray;
FixedDoubleArray, Smi, Smi, Smi): FixedDoubleArray;
extern builtin ExtractFastJSArray(Context, JSArray, Smi, Smi): JSArray;
......@@ -721,11 +778,17 @@ labels IfHole {
}
}
extern macro TransitionElementsKind(
JSObject, Map, ElementsKind, ElementsKind): void labels Bailout;
extern macro IsCallable(HeapObject): bool;
extern macro IsJSArray(HeapObject): bool;
extern macro IsJSReceiver(HeapObject): bool;
extern macro IsFixedArray(HeapObject): bool;
extern macro TaggedIsCallable(Object): bool;
extern macro IsDetachedBuffer(JSArrayBuffer): bool;
extern macro IsHeapNumber(HeapObject): bool;
extern macro IsNumber(Object): bool;
extern macro IsExtensibleMap(Map): bool;
extern macro IsCustomElementsReceiverInstanceType(int32): bool;
extern macro Typeof(Object): Object;
......
......@@ -23,34 +23,6 @@ namespace internal {
namespace {
inline bool ClampedToInteger(Isolate* isolate, Object* object, int* out) {
// This is an extended version of ECMA-262 7.1.11 handling signed values
// Try to convert object to a number and clamp values to [kMinInt, kMaxInt]
if (object->IsSmi()) {
*out = Smi::ToInt(object);
return true;
} else if (object->IsHeapNumber()) {
double value = HeapNumber::cast(object)->value();
if (std::isnan(value)) {
*out = 0;
} else if (value > kMaxInt) {
*out = kMaxInt;
} else if (value < kMinInt) {
*out = kMinInt;
} else {
*out = static_cast<int>(value);
}
return true;
} else if (object->IsNullOrUndefined(isolate)) {
*out = 0;
return true;
} else if (object->IsBoolean()) {
*out = object->IsTrue(isolate);
return true;
}
return false;
}
inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
JSArray* receiver) {
return JSObject::PrototypeHasNoElements(isolate, receiver);
......@@ -530,67 +502,6 @@ BUILTIN(ArrayUnshift) {
return Smi::FromInt(new_length);
}
BUILTIN(ArraySplice) {
HandleScope scope(isolate);
Handle<Object> receiver = args.receiver();
if (V8_UNLIKELY(
!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3,
args.length() - 3) ||
// If this is a subclass of Array, then call out to JS.
!Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) ||
// If anything with @@species has been messed with, call out to JS.
!isolate->IsArraySpeciesLookupChainIntact())) {
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
}
Handle<JSArray> array = Handle<JSArray>::cast(receiver);
int argument_count = args.length() - 1;
int relative_start = 0;
if (argument_count > 0) {
DisallowHeapAllocation no_gc;
if (!ClampedToInteger(isolate, args[1], &relative_start)) {
AllowHeapAllocation allow_allocation;
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
}
}
int len = Smi::ToInt(array->length());
// clip relative start to [0, len]
int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
: Min(relative_start, len);
int actual_delete_count;
if (argument_count == 1) {
// SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
// given as a request to delete all the elements from the start.
// And it differs from the case of undefined delete count.
// This does not follow ECMA-262, but we do the same for compatibility.
DCHECK_GE(len - actual_start, 0);
actual_delete_count = len - actual_start;
} else {
int delete_count = 0;
DisallowHeapAllocation no_gc;
if (argument_count > 1) {
if (!ClampedToInteger(isolate, args[2], &delete_count)) {
AllowHeapAllocation allow_allocation;
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
}
}
actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
}
int add_count = (argument_count > 1) ? (argument_count - 2) : 0;
int new_length = len - actual_delete_count + add_count;
if (new_length != len && JSArray::HasReadOnlyLength(array)) {
AllowHeapAllocation allow_allocation;
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
}
ElementsAccessor* accessor = array->GetElementsAccessor();
Handle<JSArray> result_array = accessor->Splice(
array, actual_start, actual_delete_count, &args, add_count);
return *result_array;
}
// Array Concat -------------------------------------------------------------
namespace {
......
......@@ -315,8 +315,6 @@ namespace internal {
TFJ(ArrayPrototypeShift, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-array.prototype.slice */ \
TFJ(ArrayPrototypeSlice, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-array.prototype.splice */ \
CPP(ArraySplice) \
/* ES6 #sec-array.prototype.unshift */ \
CPP(ArrayUnshift) \
/* Support for Array.from and other array-copying idioms */ \
......
......@@ -329,7 +329,6 @@ bool Builtins::IsIsolateIndependent(int index) {
// than 128KB, and this triggers generation of MIPS specific trampolines.
// Trampoline code is not PIC and therefore the builtin is not isolate
// independent.
case kArraySpliceTorque:
case kKeyedLoadIC_Megamorphic:
case kKeyedStoreIC_Megamorphic:
case kObjectAssign:
......
......@@ -90,8 +90,8 @@ TNode<FixedArray> GrowableFixedArray::ResizeFixedArray(
CodeStubAssembler::ExtractFixedArrayFlags flags;
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kFixedArrays;
TNode<FixedArray> to_array = ExtractFixedArray(
from_array, nullptr, element_count, new_capacity, flags);
TNode<FixedArray> to_array = CAST(ExtractFixedArray(
from_array, nullptr, element_count, new_capacity, flags));
return to_array;
}
......
......@@ -3858,7 +3858,7 @@ TNode<FixedArray> CodeStubAssembler::AllocateFixedArray(
return UncheckedCast<FixedArray>(array);
}
TNode<FixedArray> CodeStubAssembler::ExtractFixedArray(
TNode<FixedArrayBase> CodeStubAssembler::ExtractFixedArray(
Node* fixed_array, Node* first, Node* count, Node* capacity,
ExtractFixedArrayFlags extract_flags, ParameterMode parameter_mode) {
VARIABLE(var_result, MachineRepresentation::kTagged);
......@@ -4084,6 +4084,33 @@ void CodeStubAssembler::FillFixedArrayWithValue(
mode);
}
void CodeStubAssembler::StoreFixedDoubleArrayHole(
TNode<FixedDoubleArray> array, Node* index, ParameterMode parameter_mode) {
CSA_SLOW_ASSERT(this, MatchesParameterMode(index, parameter_mode));
Node* offset =
ElementOffsetFromIndex(index, PACKED_DOUBLE_ELEMENTS, parameter_mode,
FixedArray::kHeaderSize - kHeapObjectTag);
CSA_ASSERT(this, IsOffsetInBounds(
offset, LoadAndUntagFixedArrayBaseLength(array),
FixedDoubleArray::kHeaderSize, PACKED_DOUBLE_ELEMENTS));
Node* double_hole =
Is64() ? ReinterpretCast<UintPtrT>(Int64Constant(kHoleNanInt64))
: ReinterpretCast<UintPtrT>(Int32Constant(kHoleNanLower32));
// TODO(danno): When we have a Float32/Float64 wrapper class that
// preserves double bits during manipulation, remove this code/change
// this to an indexed Float64 store.
if (Is64()) {
StoreNoWriteBarrier(MachineRepresentation::kWord64, array, offset,
double_hole);
} else {
StoreNoWriteBarrier(MachineRepresentation::kWord32, array, offset,
double_hole);
StoreNoWriteBarrier(MachineRepresentation::kWord32, array,
IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
double_hole);
}
}
void CodeStubAssembler::CopyFixedArrayElements(
ElementsKind from_kind, Node* from_array, ElementsKind to_kind,
Node* to_array, Node* first_element, Node* element_count, Node* capacity,
......@@ -9817,6 +9844,9 @@ void CodeStubAssembler::BranchIfNumberRelationalComparison(
// Both {left} and {right} are Smi, so just perform a fast Smi comparison.
switch (op) {
case Operation::kEqual:
BranchIfSmiEqual(smi_left, smi_right, if_true, if_false);
break;
case Operation::kLessThan:
BranchIfSmiLessThan(smi_left, smi_right, if_true, if_false);
break;
......@@ -9863,6 +9893,10 @@ void CodeStubAssembler::BranchIfNumberRelationalComparison(
BIND(&do_float_comparison);
{
switch (op) {
case Operation::kEqual:
Branch(Float64Equal(var_left_float.value(), var_right_float.value()),
if_true, if_false);
break;
case Operation::kLessThan:
Branch(Float64LessThan(var_left_float.value(), var_right_float.value()),
if_true, if_false);
......@@ -11771,6 +11805,15 @@ Node* CodeStubAssembler::ArraySpeciesCreate(TNode<Context> context,
len);
}
Node* CodeStubAssembler::InternalArrayCreate(TNode<Context> context,
TNode<Number> len) {
Node* native_context = LoadNativeContext(context);
Node* const constructor = LoadContextElement(
native_context, Context::INTERNAL_ARRAY_FUNCTION_INDEX);
return ConstructJS(CodeFactory::Construct(isolate()), context, constructor,
len);
}
Node* CodeStubAssembler::IsDetachedBuffer(Node* buffer) {
CSA_ASSERT(this, HasInstanceType(buffer, JS_ARRAY_BUFFER_TYPE));
......
......@@ -1179,6 +1179,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* object, Node* index, Node* value,
ParameterMode parameter_mode = INTPTR_PARAMETERS);
Node* StoreFixedDoubleArrayElementSmi(TNode<FixedDoubleArray> object,
TNode<Smi> index,
TNode<Float64T> value) {
return StoreFixedDoubleArrayElement(object, index, value, SMI_PARAMETERS);
}
void StoreFixedDoubleArrayHole(TNode<FixedDoubleArray> array, Node* index,
ParameterMode mode = INTPTR_PARAMETERS);
void StoreFixedDoubleArrayHoleSmi(TNode<FixedDoubleArray> array,
TNode<Smi> index) {
StoreFixedDoubleArrayHole(array, index, SMI_PARAMETERS);
}
Node* StoreFeedbackVectorSlot(
Node* object, Node* index, Node* value,
WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
......@@ -1397,6 +1410,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* ArraySpeciesCreate(TNode<Context> context, TNode<Object> originalArray,
TNode<Number> len);
Node* InternalArrayCreate(TNode<Context> context, TNode<Number> len);
void FillFixedArrayWithValue(ElementsKind kind, Node* array, Node* from_index,
Node* to_index,
......@@ -1466,6 +1480,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
return UncheckedCast<FixedDoubleArray>(base);
}
TNode<Int32T> ConvertElementsKindToInt(TNode<Int32T> elements_kind) {
return UncheckedCast<Int32T>(elements_kind);
}
enum class ExtractFixedArrayFlag {
kFixedArrays = 1,
kFixedDoubleArrays = 2,
......@@ -1499,20 +1517,27 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
// passed as the |source| parameter.
// * |parameter_mode| determines the parameter mode of |first|, |count| and
// |capacity|.
TNode<FixedArray> ExtractFixedArray(
TNode<FixedArrayBase> ExtractFixedArray(
Node* source, Node* first, Node* count = nullptr,
Node* capacity = nullptr,
ExtractFixedArrayFlags extract_flags =
ExtractFixedArrayFlag::kAllFixedArrays,
ParameterMode parameter_mode = INTPTR_PARAMETERS);
TNode<FixedArray> ExtractFixedArray(
TNode<FixedArray> source, TNode<Smi> first, TNode<Smi> count,
TNode<Smi> capacity,
ExtractFixedArrayFlags extract_flags =
ExtractFixedArrayFlag::kAllFixedArrays) {
return ExtractFixedArray(source, first, count, capacity, extract_flags,
SMI_PARAMETERS);
TNode<FixedArray> ExtractFixedArray(TNode<FixedArray> source,
TNode<Smi> first, TNode<Smi> count,
TNode<Smi> capacity) {
return CAST(ExtractFixedArray(source, first, count, capacity,
ExtractFixedArrayFlag::kFixedArrays,
SMI_PARAMETERS));
}
TNode<FixedDoubleArray> ExtractFixedArray(TNode<FixedDoubleArray> source,
TNode<Smi> first, TNode<Smi> count,
TNode<Smi> capacity) {
return CAST(ExtractFixedArray(source, first, count, capacity,
ExtractFixedArrayFlag::kFixedDoubleArrays,
SMI_PARAMETERS));
}
// Copy the entire contents of a FixedArray or FixedDoubleArray to a new
......@@ -2476,6 +2501,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
ElementsKind to_kind, bool is_jsarray,
Label* bailout);
void TransitionElementsKind(TNode<JSReceiver> object, TNode<Map> map,
ElementsKind from_kind, ElementsKind to_kind,
Label* bailout) {
TransitionElementsKind(object, map, from_kind, to_kind, true, bailout);
}
void TrapAllocationMemento(Node* object, Label* memento_found);
TNode<IntPtrT> PageFromAddress(TNode<IntPtrT> address);
......@@ -2567,26 +2598,32 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
void BranchIfNumberRelationalComparison(Operation op, Node* left, Node* right,
Label* if_true, Label* if_false);
void BranchIfNumberLessThan(Node* left, Node* right, Label* if_true,
Label* if_false) {
void BranchIfNumberEqual(TNode<Number> left, TNode<Number> right,
Label* if_true, Label* if_false) {
BranchIfNumberRelationalComparison(Operation::kEqual, left, right, if_true,
if_false);
}
void BranchIfNumberLessThan(TNode<Number> left, TNode<Number> right,
Label* if_true, Label* if_false) {
BranchIfNumberRelationalComparison(Operation::kLessThan, left, right,
if_true, if_false);
}
void BranchIfNumberLessThanOrEqual(Node* left, Node* right, Label* if_true,
Label* if_false) {
void BranchIfNumberLessThanOrEqual(TNode<Number> left, TNode<Number> right,
Label* if_true, Label* if_false) {
BranchIfNumberRelationalComparison(Operation::kLessThanOrEqual, left, right,
if_true, if_false);
}
void BranchIfNumberGreaterThan(Node* left, Node* right, Label* if_true,
Label* if_false) {
void BranchIfNumberGreaterThan(TNode<Number> left, TNode<Number> right,
Label* if_true, Label* if_false) {
BranchIfNumberRelationalComparison(Operation::kGreaterThan, left, right,
if_true, if_false);
}
void BranchIfNumberGreaterThanOrEqual(Node* left, Node* right, Label* if_true,
Label* if_false) {
void BranchIfNumberGreaterThanOrEqual(TNode<Number> left, TNode<Number> right,
Label* if_true, Label* if_false) {
BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual, left,
right, if_true, if_false);
}
......
......@@ -72,7 +72,6 @@ enum ContextLookupFlags {
#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
V(ARRAY_SHIFT_INDEX, JSFunction, array_shift) \
V(ARRAY_SPLICE_INDEX, JSFunction, array_splice) \
V(ARRAY_UNSHIFT_INDEX, JSFunction, array_unshift) \
V(ARRAY_ENTRIES_ITERATOR_INDEX, JSFunction, array_entries_iterator) \
V(ARRAY_FOR_EACH_ITERATOR_INDEX, JSFunction, array_for_each_iterator) \
......
......@@ -870,8 +870,6 @@ DEFINE_BOOL(expose_trigger_failure, false, "expose trigger-failure extension")
DEFINE_INT(stack_trace_limit, 10, "number of stack frames to capture")
DEFINE_BOOL(builtins_in_stack_traces, false,
"show built-in functions in stack traces")
DEFINE_BOOL(enable_experimental_builtins, false,
"enable new csa-based experimental builtins")
DEFINE_BOOL(disallow_code_generation_from_strings, false,
"disallow eval and friends")
DEFINE_BOOL(expose_async_hooks, false, "expose async_hooks object")
......
......@@ -200,35 +200,6 @@ function ConvertToString(use_locale, x, locales, options) {
return TO_STRING(x);
}
// This function implements the optimized splice implementation that can use
// special array operations to handle sparse arrays in a sensible fashion.
function SparseSlice(array, start_i, del_count, len, deleted_elements) {
// Move deleted elements to a new array (the return value from splice).
var indices = %GetArrayKeys(array, start_i + del_count);
if (IS_NUMBER(indices)) {
var limit = indices;
for (var i = start_i; i < limit; ++i) {
var current = array[i];
if (!IS_UNDEFINED(current) || i in array) {
%CreateDataProperty(deleted_elements, i - start_i, current);
}
}
} else {
var length = indices.length;
for (var k = 0; k < length; ++k) {
var key = indices[k];
if (key >= start_i) {
var current = array[key];
if (!IS_UNDEFINED(current) || key in array) {
%CreateDataProperty(deleted_elements, key - start_i, current);
}
}
}
}
}
// This function implements the optimized splice implementation that can use
// special array operations to handle sparse arrays in a sensible fashion.
function SparseMove(array, start_i, del_count, len, num_additional_args) {
......@@ -565,83 +536,6 @@ function ArraySliceFallback(start, end) {
return null;
}
function ComputeSpliceStartIndex(start_i, len) {
if (start_i < 0) {
start_i += len;
return start_i < 0 ? 0 : start_i;
}
return start_i > len ? len : start_i;
}
function ComputeSpliceDeleteCount(delete_count, num_arguments, len, start_i) {
// SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
// given as a request to delete all the elements from the start.
// And it differs from the case of undefined delete count.
// This does not follow ECMA-262, but we do the same for
// compatibility.
var del_count = 0;
if (num_arguments == 1)
return len - start_i;
del_count = TO_INTEGER(delete_count);
if (del_count < 0)
return 0;
if (del_count > len - start_i)
return len - start_i;
return del_count;
}
function ArraySpliceFallback(start, delete_count) {
var num_arguments = arguments.length;
var array = TO_OBJECT(this);
var len = TO_LENGTH(array.length);
var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len);
var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len,
start_i);
var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0;
const new_len = len - del_count + num_elements_to_add;
if (new_len >= 2**53) throw %make_type_error(kInvalidArrayLength);
var deleted_elements = ArraySpeciesCreate(array, del_count);
deleted_elements.length = del_count;
var changed_elements = del_count;
if (num_elements_to_add != del_count) {
// If the slice needs to do a actually move elements after the insertion
// point, then include those in the estimate of changed elements.
changed_elements += len - start_i - del_count;
}
if (UseSparseVariant(array, len, IS_ARRAY(array), changed_elements)) {
%NormalizeElements(array);
if (IS_ARRAY(deleted_elements)) %NormalizeElements(deleted_elements);
SparseSlice(array, start_i, del_count, len, deleted_elements);
SparseMove(array, start_i, del_count, len, num_elements_to_add);
} else {
SimpleSlice(array, start_i, del_count, len, deleted_elements);
SimpleMove(array, start_i, del_count, len, num_elements_to_add);
}
// Insert the arguments into the resulting array in
// place of the deleted elements.
var i = start_i;
var arguments_index = 2;
var arguments_length = arguments.length;
while (arguments_index < arguments_length) {
array[i++] = arguments[arguments_index++];
}
array.length = new_len;
// Return the deleted elements.
return deleted_elements;
}
function InnerArraySort(array, length, comparefn) {
// In-place QuickSort algorithm.
// For short (length <= 10) arrays, insertion sort is used for efficiency.
......@@ -998,7 +892,6 @@ utils.Export(function(to) {
"array_values_iterator", ArrayValues,
// Fallback implementations of Array builtins.
"array_shift", ArrayShiftFallback,
"array_splice", ArraySpliceFallback,
"array_unshift", ArrayUnshiftFallback,
]);
......
......@@ -30,6 +30,16 @@ RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
return *object;
}
RUNTIME_FUNCTION(Runtime_TransitionElementsKindWithKind) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
CONVERT_ARG_HANDLE_CHECKED(Smi, elements_kind_smi, 1);
ElementsKind to_kind = static_cast<ElementsKind>(elements_kind_smi->value());
JSObject::TransitionElementsKind(object, to_kind);
return *object;
}
namespace {
// Find the next free position. undefined and holes are both considered
// free spots. Returns "Nothing" if an exception occurred.
......
......@@ -36,21 +36,22 @@ namespace internal {
// A variable number of arguments is specified by a -1, additional restrictions
// are specified by inline comments
#define FOR_EACH_INTRINSIC_ARRAY(F) \
F(ArrayIncludes_Slow, 3, 1) \
F(ArrayIndexOf, 3, 1) \
F(ArrayIsArray, 1, 1) \
F(ArraySpeciesConstructor, 1, 1) \
F(EstimateNumberOfElements, 1, 1) \
F(GetArrayKeys, 2, 1) \
F(GrowArrayElements, 2, 1) \
F(HasComplexElements, 1, 1) \
F(IsArray, 1, 1) \
F(MoveArrayContents, 2, 1) \
F(NewArray, -1 /* >= 3 */, 1) \
F(NormalizeElements, 1, 1) \
F(PrepareElementsForSort, 2, 1) \
F(TransitionElementsKind, 2, 1) \
#define FOR_EACH_INTRINSIC_ARRAY(F) \
F(ArrayIncludes_Slow, 3, 1) \
F(ArrayIndexOf, 3, 1) \
F(ArrayIsArray, 1, 1) \
F(ArraySpeciesConstructor, 1, 1) \
F(EstimateNumberOfElements, 1, 1) \
F(GetArrayKeys, 2, 1) \
F(GrowArrayElements, 2, 1) \
F(HasComplexElements, 1, 1) \
F(IsArray, 1, 1) \
F(MoveArrayContents, 2, 1) \
F(NewArray, -1 /* >= 3 */, 1) \
F(NormalizeElements, 1, 1) \
F(PrepareElementsForSort, 2, 1) \
F(TransitionElementsKind, 2, 1) \
F(TransitionElementsKindWithKind, 2, 1) \
F(TrySliceSimpleNonFastElements, 3, 1)
#define FOR_EACH_INTRINSIC_ATOMICS(F) \
......
......@@ -474,9 +474,6 @@
# https://bugs.chromium.org/p/v8/issues/detail?id=7993
'intl402/RelativeTimeFormat/prototype/toStringTag/toStringTag': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=7814
'built-ins/Array/prototype/splice/property-traps-order-with-species': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=6705
'built-ins/Object/assign/strings-and-symbol-order': [FAIL],
......@@ -518,8 +515,6 @@
# https://bugs.chromium.org/p/v8/issues/detail?id=6538
'built-ins/Array/prototype/unshift/throws-if-integer-limit-exceeded': [SKIP],
'built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-proxy': [FAIL],
'built-ins/Array/prototype/splice/create-species-length-exceeding-integer-limit': [FAIL],
'built-ins/Array/prototype/splice/throws-if-integer-limit-exceeded': [SKIP],
# https://bugs.chromium.org/p/v8/issues/detail?id=6541
'language/export/escaped-as-export-specifier': [FAIL],
......
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