diff options
author | Michaël Zasso <targos@protonmail.com> | 2018-01-24 20:16:06 +0100 |
---|---|---|
committer | Myles Borins <mylesborins@google.com> | 2018-01-24 15:02:20 -0800 |
commit | 4c4af643e5042d615a60c6bbc05aee9d81b903e5 (patch) | |
tree | 3fb0a97988fe4439ae3ae06f26915d1dcf8cab92 /deps/v8/src/builtins/builtins-array-gen.cc | |
parent | fa9f31a4fda5a3782c652e56e394465805ebb50f (diff) | |
download | node-new-4c4af643e5042d615a60c6bbc05aee9d81b903e5.tar.gz |
deps: update V8 to 6.4.388.40
PR-URL: https://github.com/nodejs/node/pull/17489
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Diffstat (limited to 'deps/v8/src/builtins/builtins-array-gen.cc')
-rw-r--r-- | deps/v8/src/builtins/builtins-array-gen.cc | 678 |
1 files changed, 603 insertions, 75 deletions
diff --git a/deps/v8/src/builtins/builtins-array-gen.cc b/deps/v8/src/builtins/builtins-array-gen.cc index 46d20e57eb..5fec0abfa5 100644 --- a/deps/v8/src/builtins/builtins-array-gen.cc +++ b/deps/v8/src/builtins/builtins-array-gen.cc @@ -31,6 +31,32 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> PostLoopAction; + void FindResultGenerator() { a_.Bind(UndefinedConstant()); } + + Node* FindProcessor(Node* k_value, Node* k) { + Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), + this_arg(), k_value, k, o()); + Label false_continue(this), return_true(this); + BranchIfToBooleanIsTrue(value, &return_true, &false_continue); + BIND(&return_true); + ReturnFromBuiltin(k_value); + BIND(&false_continue); + return a(); + } + + void FindIndexResultGenerator() { a_.Bind(SmiConstant(-1)); } + + Node* FindIndexProcessor(Node* k_value, Node* k) { + Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), + this_arg(), k_value, k, o()); + Label false_continue(this), return_true(this); + BranchIfToBooleanIsTrue(value, &return_true, &false_continue); + BIND(&return_true); + ReturnFromBuiltin(k); + BIND(&false_continue); + return a(); + } + void ForEachResultGenerator() { a_.Bind(UndefinedConstant()); } Node* ForEachProcessor(Node* k_value, Node* k) { @@ -92,8 +118,9 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { void FilterResultGenerator() { // 7. Let A be ArraySpeciesCreate(O, 0). - Node* len = SmiConstant(0); - ArraySpeciesCreate(len); + // This version of ArraySpeciesCreate will create with the correct + // ElementsKind in the fast case. + ArraySpeciesCreate(); } Node* FilterProcessor(Node* k_value, Node* k) { @@ -305,7 +332,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { BIND(&slow); CallRuntime(Runtime::kSetProperty, context(), a(), k, mapped_value, - SmiConstant(STRICT)); + SmiConstant(LanguageMode::kStrict)); Goto(&done); BIND(&detached); @@ -362,10 +389,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { // TODO(danno): Seriously? Do we really need to throw the exact error // message on null and undefined so that the webkit tests pass? Label throw_null_undefined_exception(this, Label::kDeferred); - GotoIf(WordEqual(receiver(), NullConstant()), - &throw_null_undefined_exception); - GotoIf(WordEqual(receiver(), UndefinedConstant()), - &throw_null_undefined_exception); + GotoIf(IsNullOrUndefined(receiver()), &throw_null_undefined_exception); // By the book: taken directly from the ECMAScript 2015 specification @@ -534,11 +558,11 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { { if (direction == ForEachDirection::kForward) { // 8. Repeat, while k < len - GotoIfNumberGreaterThanOrEqual(k(), len_, &after_loop); + GotoIfNumericGreaterThanOrEqual(k(), len_, &after_loop); } else { // OR // 10. Repeat, while k >= 0 - GotoIfNumberGreaterThanOrEqual(SmiConstant(-1), k(), &after_loop); + GotoIfNumericGreaterThanOrEqual(SmiConstant(-1), k(), &after_loop); } Label done_element(this, &to_); @@ -743,13 +767,61 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { } // Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate). - void ArraySpeciesCreate(Node* len) { + // This version is specialized to create a zero length array + // of the elements kind of the input array. + void ArraySpeciesCreate() { + Label runtime(this, Label::kDeferred), done(this); + + TNode<Smi> len = SmiConstant(0); + TNode<Map> original_map = LoadMap(o()); + GotoIfNot( + InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE), + &runtime); + + GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map), + &runtime); + + Node* species_protector = SpeciesProtectorConstant(); + Node* value = + LoadObjectField(species_protector, PropertyCell::kValueOffset); + TNode<Smi> const protector_invalid = + SmiConstant(Isolate::kProtectorInvalid); + GotoIf(WordEqual(value, protector_invalid), &runtime); + + // Respect the ElementsKind of the input array. + TNode<Int32T> elements_kind = LoadMapElementsKind(original_map); + GotoIfNot(IsFastElementsKind(elements_kind), &runtime); + TNode<Context> native_context = CAST(LoadNativeContext(context())); + TNode<Map> array_map = + CAST(LoadJSArrayElementsMap(elements_kind, native_context)); + TNode<JSArray> array = + CAST(AllocateJSArray(GetInitialFastElementsKind(), array_map, len, len, + nullptr, CodeStubAssembler::SMI_PARAMETERS)); + a_.Bind(array); + + Goto(&done); + + BIND(&runtime); + { + // 5. Let A be ? ArraySpeciesCreate(O, len). + Node* constructor = + CallRuntime(Runtime::kArraySpeciesConstructor, context(), o()); + a_.Bind(ConstructJS(CodeFactory::Construct(isolate()), context(), + constructor, len)); + Goto(&fully_spec_compliant_); + } + + BIND(&done); + } + + // Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate). + void ArraySpeciesCreate(SloppyTNode<Smi> len) { Label runtime(this, Label::kDeferred), done(this); Node* const original_map = LoadMap(o()); - GotoIf(Word32NotEqual(LoadMapInstanceType(original_map), - Int32Constant(JS_ARRAY_TYPE)), - &runtime); + GotoIfNot( + InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE), + &runtime); GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map), &runtime); @@ -769,8 +841,9 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { // element in the input array (maybe the callback deletes an element). const ElementsKind elements_kind = GetHoleyElementsKind(GetInitialFastElementsKind()); - Node* const native_context = LoadNativeContext(context()); - Node* array_map = LoadJSArrayElementsMap(elements_kind, native_context); + TNode<Context> native_context = CAST(LoadNativeContext(context())); + TNode<Map> array_map = + CAST(LoadJSArrayElementsMap(elements_kind, native_context)); a_.Bind(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, len, len, nullptr, CodeStubAssembler::SMI_PARAMETERS)); @@ -809,8 +882,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { TF_BUILTIN(FastArrayPop, CodeStubAssembler) { Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); Node* context = Parameter(BuiltinDescriptor::kContext); - CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget), - UndefinedConstant())); + CSA_ASSERT(this, IsUndefined(Parameter(BuiltinDescriptor::kNewTarget))); CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); Node* receiver = args.GetReceiver(); @@ -829,8 +901,7 @@ TF_BUILTIN(FastArrayPop, CodeStubAssembler) { BIND(&fast); { - CSA_ASSERT(this, TaggedIsPositiveSmi( - LoadObjectField(receiver, JSArray::kLengthOffset))); + CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(receiver))); Node* length = LoadAndUntagObjectField(receiver, JSArray::kLengthOffset); Label return_undefined(this), fast_elements(this); GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined); @@ -920,8 +991,7 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) { // arguments are reordered. Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); Node* context = Parameter(BuiltinDescriptor::kContext); - CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget), - UndefinedConstant())); + CSA_ASSERT(this, IsUndefined(Parameter(BuiltinDescriptor::kNewTarget))); CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); Node* receiver = args.GetReceiver(); @@ -954,7 +1024,7 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) { // TODO(danno): Use the KeyedStoreGeneric stub here when possible, // calling into the runtime to do the elements transition is overkill. CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, - SmiConstant(STRICT)); + SmiConstant(LanguageMode::kStrict)); Increment(&arg_index); // The runtime SetProperty call could have converted the array to dictionary // mode, which must be detected to abort the fast-path. @@ -1001,7 +1071,7 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) { // TODO(danno): Use the KeyedStoreGeneric stub here when possible, // calling into the runtime to do the elements transition is overkill. CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, - SmiConstant(STRICT)); + SmiConstant(LanguageMode::kStrict)); Increment(&arg_index); // The runtime SetProperty call could have converted the array to dictionary // mode, which must be detected to abort the fast-path. @@ -1021,7 +1091,7 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) { [this, receiver, context](Node* arg) { Node* length = LoadJSArrayLength(receiver); CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, - SmiConstant(STRICT)); + SmiConstant(LanguageMode::kStrict)); }, arg_index); args.PopAndReturn(LoadJSArrayLength(receiver)); @@ -1036,11 +1106,342 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) { } } +class FastArraySliceCodeStubAssembler : public CodeStubAssembler { + public: + explicit FastArraySliceCodeStubAssembler(compiler::CodeAssemblerState* state) + : CodeStubAssembler(state) {} + + Node* HandleFastSlice(Node* context, Node* array, Node* from, Node* count, + Label* slow) { + VARIABLE(result, MachineRepresentation::kTagged); + Label done(this); + + GotoIf(TaggedIsNotSmi(from), slow); + GotoIf(TaggedIsNotSmi(count), slow); + + Label try_fast_arguments(this), try_simple_slice(this); + + Node* map = LoadMap(array); + GotoIfNot(IsJSArrayMap(map), &try_fast_arguments); + + // Check prototype chain if receiver does not have packed elements + GotoIfNot(IsPrototypeInitialArrayPrototype(context, map), slow); + + GotoIf(IsNoElementsProtectorCellInvalid(), slow); + + GotoIf(IsSpeciesProtectorCellInvalid(), slow); + + // Bailout if receiver has slow elements. + Node* elements_kind = LoadMapElementsKind(map); + GotoIfNot(IsFastElementsKind(elements_kind), &try_simple_slice); + + // Make sure that the length hasn't been changed by side-effect. + Node* array_length = LoadJSArrayLength(array); + GotoIf(TaggedIsNotSmi(array_length), slow); + GotoIf(SmiAbove(SmiAdd(from, count), array_length), slow); + + CSA_ASSERT(this, SmiGreaterThanOrEqual(from, SmiConstant(0))); + + result.Bind(CallStub(CodeFactory::ExtractFastJSArray(isolate()), context, + array, from, count)); + Goto(&done); + + BIND(&try_fast_arguments); + + Node* const native_context = LoadNativeContext(context); + Node* const fast_aliasted_arguments_map = LoadContextElement( + native_context, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX); + GotoIf(WordNotEqual(map, fast_aliasted_arguments_map), &try_simple_slice); + + Node* sloppy_elements = LoadElements(array); + Node* sloppy_elements_length = LoadFixedArrayBaseLength(sloppy_elements); + Node* parameter_map_length = + SmiSub(sloppy_elements_length, + SmiConstant(SloppyArgumentsElements::kParameterMapStart)); + VARIABLE(index_out, MachineType::PointerRepresentation()); + + int max_fast_elements = + (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - JSArray::kSize - + AllocationMemento::kSize) / + kPointerSize; + GotoIf(SmiAboveOrEqual(count, SmiConstant(max_fast_elements)), + &try_simple_slice); + + GotoIf(SmiLessThan(from, SmiConstant(0)), slow); + + Node* end = SmiAdd(from, count); + + Node* unmapped_elements = LoadFixedArrayElement( + sloppy_elements, SloppyArgumentsElements::kArgumentsIndex); + Node* unmapped_elements_length = + LoadFixedArrayBaseLength(unmapped_elements); + + GotoIf(SmiAbove(end, unmapped_elements_length), slow); + + Node* array_map = LoadJSArrayElementsMap(HOLEY_ELEMENTS, native_context); + result.Bind(AllocateJSArray(HOLEY_ELEMENTS, array_map, count, count, + nullptr, SMI_PARAMETERS)); + + index_out.Bind(IntPtrConstant(0)); + Node* result_elements = LoadElements(result.value()); + Node* from_mapped = SmiMin(parameter_map_length, from); + Node* to = SmiMin(parameter_map_length, end); + Node* arguments_context = LoadFixedArrayElement( + sloppy_elements, SloppyArgumentsElements::kContextIndex); + VariableList var_list({&index_out}, zone()); + BuildFastLoop( + var_list, from_mapped, to, + [this, result_elements, arguments_context, sloppy_elements, + unmapped_elements, &index_out](Node* current) { + Node* context_index = LoadFixedArrayElement( + sloppy_elements, current, + kPointerSize * SloppyArgumentsElements::kParameterMapStart, + SMI_PARAMETERS); + Label is_the_hole(this), done(this); + GotoIf(IsTheHole(context_index), &is_the_hole); + Node* mapped_argument = + LoadContextElement(arguments_context, SmiUntag(context_index)); + StoreFixedArrayElement(result_elements, index_out.value(), + mapped_argument, SKIP_WRITE_BARRIER); + Goto(&done); + BIND(&is_the_hole); + Node* argument = LoadFixedArrayElement(unmapped_elements, current, 0, + SMI_PARAMETERS); + StoreFixedArrayElement(result_elements, index_out.value(), argument, + SKIP_WRITE_BARRIER); + Goto(&done); + BIND(&done); + index_out.Bind(IntPtrAdd(index_out.value(), IntPtrConstant(1))); + }, + 1, SMI_PARAMETERS, IndexAdvanceMode::kPost); + + Node* unmapped_from = SmiMin(SmiMax(parameter_map_length, from), end); + + BuildFastLoop( + var_list, unmapped_from, end, + [this, unmapped_elements, result_elements, &index_out](Node* current) { + Node* argument = LoadFixedArrayElement(unmapped_elements, current, 0, + SMI_PARAMETERS); + StoreFixedArrayElement(result_elements, index_out.value(), argument, + SKIP_WRITE_BARRIER); + index_out.Bind(IntPtrAdd(index_out.value(), IntPtrConstant(1))); + }, + 1, SMI_PARAMETERS, IndexAdvanceMode::kPost); + + Goto(&done); + + BIND(&try_simple_slice); + Node* simple_result = CallRuntime(Runtime::kTrySliceSimpleNonFastElements, + context, array, from, count); + GotoIfNumber(simple_result, slow); + result.Bind(simple_result); + + Goto(&done); + + BIND(&done); + return result.value(); + } + + void CopyOneElement(Node* context, Node* o, Node* a, Node* p_k, Variable& n) { + // b. Let kPresent be HasProperty(O, Pk). + // c. ReturnIfAbrupt(kPresent). + Node* k_present = HasProperty(o, p_k, context, kHasProperty); + + // d. If kPresent is true, then + Label done_element(this); + GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); + + // i. Let kValue be Get(O, Pk). + // ii. ReturnIfAbrupt(kValue). + Node* k_value = GetProperty(context, o, p_k); + + // iii. Let status be CreateDataPropertyOrThrow(A, ToString(n), kValue). + // iv. ReturnIfAbrupt(status). + CallRuntime(Runtime::kCreateDataProperty, context, a, n.value(), k_value); + + Goto(&done_element); + BIND(&done_element); + } +}; + +TF_BUILTIN(FastArraySlice, FastArraySliceCodeStubAssembler) { + Node* const argc = + ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount)); + Node* const context = Parameter(BuiltinDescriptor::kContext); + Label slow(this, Label::kDeferred), fast_elements_kind(this); + + CodeStubArguments args(this, argc); + Node* receiver = args.GetReceiver(); + + VARIABLE(o, MachineRepresentation::kTagged); + VARIABLE(len, MachineRepresentation::kTagged); + Label length_done(this), generic_length(this), check_arguments_length(this), + load_arguments_length(this); + + GotoIf(TaggedIsSmi(receiver), &generic_length); + GotoIfNot(IsJSArray(receiver), &check_arguments_length); + + o.Bind(receiver); + len.Bind(LoadJSArrayLength(receiver)); + + // Check for the array clone case. There can be no arguments to slice, the + // array prototype chain must be intact and have no elements, the array has to + // have fast elements. + GotoIf(WordNotEqual(argc, IntPtrConstant(0)), &length_done); + + Label clone(this); + BranchIfFastJSArrayForCopy(receiver, context, &clone, &length_done); + BIND(&clone); + + args.PopAndReturn( + CallStub(CodeFactory::CloneFastJSArray(isolate()), context, receiver)); + + BIND(&check_arguments_length); + + Node* map = LoadMap(receiver); + Node* native_context = LoadNativeContext(context); + GotoIfContextElementEqual(map, native_context, + Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX, + &load_arguments_length); + GotoIfContextElementEqual(map, native_context, + Context::SLOW_ALIASED_ARGUMENTS_MAP_INDEX, + &load_arguments_length); + GotoIfContextElementEqual(map, native_context, + Context::STRICT_ARGUMENTS_MAP_INDEX, + &load_arguments_length); + GotoIfContextElementEqual(map, native_context, + Context::SLOPPY_ARGUMENTS_MAP_INDEX, + &load_arguments_length); + + Goto(&generic_length); + + BIND(&load_arguments_length); + Node* arguments_length = + LoadObjectField(receiver, JSArgumentsObject::kLengthOffset); + GotoIf(TaggedIsNotSmi(arguments_length), &generic_length); + o.Bind(receiver); + len.Bind(arguments_length); + Goto(&length_done); + + BIND(&generic_length); + // 1. Let O be ToObject(this value). + // 2. ReturnIfAbrupt(O). + o.Bind(CallBuiltin(Builtins::kToObject, context, receiver)); + + // 3. Let len be ToLength(Get(O, "length")). + // 4. ReturnIfAbrupt(len). + len.Bind(ToLength_Inline( + context, + GetProperty(context, o.value(), isolate()->factory()->length_string()))); + Goto(&length_done); + + BIND(&length_done); + + // 5. Let relativeStart be ToInteger(start). + // 6. ReturnIfAbrupt(relativeStart). + Node* arg0 = args.GetOptionalArgumentValue(0, SmiConstant(0)); + Node* relative_start = ToInteger(context, arg0); + + // 7. If relativeStart < 0, let k be max((len + relativeStart),0); + // else let k be min(relativeStart, len.value()). + VARIABLE(k, MachineRepresentation::kTagged); + Label relative_start_positive(this), relative_start_done(this); + GotoIfNumericGreaterThanOrEqual(relative_start, SmiConstant(0), + &relative_start_positive); + k.Bind(NumberMax(NumberAdd(len.value(), relative_start), NumberConstant(0))); + Goto(&relative_start_done); + BIND(&relative_start_positive); + k.Bind(NumberMin(relative_start, len.value())); + Goto(&relative_start_done); + BIND(&relative_start_done); + + // 8. If end is undefined, let relativeEnd be len; + // else let relativeEnd be ToInteger(end). + // 9. ReturnIfAbrupt(relativeEnd). + Node* end = args.GetOptionalArgumentValue(1, UndefinedConstant()); + Label end_undefined(this), end_done(this); + VARIABLE(relative_end, MachineRepresentation::kTagged); + GotoIf(WordEqual(end, UndefinedConstant()), &end_undefined); + relative_end.Bind(ToInteger(context, end)); + Goto(&end_done); + BIND(&end_undefined); + relative_end.Bind(len.value()); + Goto(&end_done); + BIND(&end_done); + + // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); + // else let final be min(relativeEnd, len). + VARIABLE(final, MachineRepresentation::kTagged); + Label relative_end_positive(this), relative_end_done(this); + GotoIfNumericGreaterThanOrEqual(relative_end.value(), NumberConstant(0), + &relative_end_positive); + final.Bind(NumberMax(NumberAdd(len.value(), relative_end.value()), + NumberConstant(0))); + Goto(&relative_end_done); + BIND(&relative_end_positive); + final.Bind(NumberMin(relative_end.value(), len.value())); + Goto(&relative_end_done); + BIND(&relative_end_done); + + // 11. Let count be max(final – k, 0). + Node* count = + NumberMax(NumberSub(final.value(), k.value()), NumberConstant(0)); + + // Handle FAST_ELEMENTS + Label non_fast(this); + Node* fast_result = + HandleFastSlice(context, o.value(), k.value(), count, &non_fast); + args.PopAndReturn(fast_result); + + // 12. Let A be ArraySpeciesCreate(O, count). + // 13. ReturnIfAbrupt(A). + BIND(&non_fast); + + Node* constructor = + CallRuntime(Runtime::kArraySpeciesConstructor, context, o.value()); + Node* a = ConstructJS(CodeFactory::Construct(isolate()), context, constructor, + count); + + // 14. Let n be 0. + VARIABLE(n, MachineRepresentation::kTagged); + n.Bind(SmiConstant(0)); + + Label loop(this, {&k, &n}); + Label after_loop(this); + Goto(&loop); + BIND(&loop); + { + // 15. Repeat, while k < final + GotoIfNumericGreaterThanOrEqual(k.value(), final.value(), &after_loop); + + Node* p_k = k.value(); // ToString(context, k.value()) is no-op + + CopyOneElement(context, o.value(), a, p_k, n); + + // e. Increase k by 1. + k.Bind(NumberInc(k.value())); + + // f. Increase n by 1. + n.Bind(NumberInc(n.value())); + + Goto(&loop); + } + + BIND(&after_loop); + + // 16. Let setStatus be Set(A, "length", n, true). + // 17. ReturnIfAbrupt(setStatus). + CallRuntime(Runtime::kSetProperty, context, a, + HeapConstant(isolate()->factory()->length_string()), n.value(), + SmiConstant(static_cast<int>(LanguageMode::kStrict))); + + args.PopAndReturn(a); +} + TF_BUILTIN(FastArrayShift, CodeStubAssembler) { Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); Node* context = Parameter(BuiltinDescriptor::kContext); - CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget), - UndefinedConstant())); + CSA_ASSERT(this, IsUndefined(Parameter(BuiltinDescriptor::kNewTarget))); CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); Node* receiver = args.GetReceiver(); @@ -1060,8 +1461,7 @@ TF_BUILTIN(FastArrayShift, CodeStubAssembler) { BIND(&fast); { - CSA_ASSERT(this, TaggedIsPositiveSmi( - LoadObjectField(receiver, JSArray::kLengthOffset))); + CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(receiver))); Node* length = LoadAndUntagObjectField(receiver, JSArray::kLengthOffset); Label return_undefined(this), fast_elements_tagged(this), fast_elements_smi(this); @@ -1167,17 +1567,16 @@ TF_BUILTIN(FastArrayShift, CodeStubAssembler) { BIND(&fast_elements_smi); { Node* value = LoadFixedArrayElement(elements, 0); - int32_t header_size = FixedDoubleArray::kHeaderSize - kHeapObjectTag; - Node* memmove = - ExternalConstant(ExternalReference::libc_memmove_function(isolate())); - Node* start = IntPtrAdd( - BitcastTaggedToWord(elements), - ElementOffsetFromIndex(IntPtrConstant(0), HOLEY_SMI_ELEMENTS, - INTPTR_PARAMETERS, header_size)); - CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(), - MachineType::Pointer(), MachineType::UintPtr(), memmove, - start, IntPtrAdd(start, IntPtrConstant(kPointerSize)), - IntPtrMul(new_length, IntPtrConstant(kPointerSize))); + BuildFastLoop(IntPtrConstant(0), new_length, + [&](Node* index) { + StoreFixedArrayElement( + elements, index, + LoadFixedArrayElement( + elements, IntPtrAdd(index, IntPtrConstant(1))), + SKIP_WRITE_BARRIER); + }, + 1, ParameterMode::INTPTR_PARAMETERS, + IndexAdvanceMode::kPost); StoreFixedArrayElement(elements, new_length, TheHoleConstant()); GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined); args.PopAndReturn(value); @@ -1196,6 +1595,72 @@ TF_BUILTIN(FastArrayShift, CodeStubAssembler) { } } +TF_BUILTIN(ExtractFastJSArray, ArrayBuiltinCodeStubAssembler) { + ParameterMode mode = OptimalParameterMode(); + Node* context = Parameter(Descriptor::kContext); + Node* array = Parameter(Descriptor::kSource); + Node* begin = TaggedToParameter(Parameter(Descriptor::kBegin), mode); + Node* count = TaggedToParameter(Parameter(Descriptor::kCount), mode); + + CSA_ASSERT(this, IsJSArray(array)); + CSA_ASSERT(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid())); + + Return(ExtractFastJSArray(context, array, begin, count, mode)); +} + +TF_BUILTIN(CloneFastJSArray, ArrayBuiltinCodeStubAssembler) { + Node* context = Parameter(Descriptor::kContext); + Node* array = Parameter(Descriptor::kSource); + + CSA_ASSERT(this, IsJSArray(array)); + CSA_ASSERT(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid())); + + ParameterMode mode = OptimalParameterMode(); + Return(CloneFastJSArray(context, array, mode)); +} + +// ES #sec-get-%typedarray%.prototype.find +TF_BUILTIN(TypedArrayPrototypeFind, ArrayBuiltinCodeStubAssembler) { + Node* argc = + ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount)); + CodeStubArguments args(this, argc); + Node* context = Parameter(BuiltinDescriptor::kContext); + Node* new_target = Parameter(BuiltinDescriptor::kNewTarget); + Node* receiver = args.GetReceiver(); + Node* callbackfn = args.GetOptionalArgumentValue(0); + Node* this_arg = args.GetOptionalArgumentValue(1); + + InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, + new_target, argc); + + GenerateIteratingTypedArrayBuiltinBody( + "%TypedArray%.prototype.find", + &ArrayBuiltinCodeStubAssembler::FindResultGenerator, + &ArrayBuiltinCodeStubAssembler::FindProcessor, + &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); +} + +// ES #sec-get-%typedarray%.prototype.findIndex +TF_BUILTIN(TypedArrayPrototypeFindIndex, ArrayBuiltinCodeStubAssembler) { + Node* argc = + ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount)); + CodeStubArguments args(this, argc); + Node* context = Parameter(BuiltinDescriptor::kContext); + Node* new_target = Parameter(BuiltinDescriptor::kNewTarget); + Node* receiver = args.GetReceiver(); + Node* callbackfn = args.GetOptionalArgumentValue(0); + Node* this_arg = args.GetOptionalArgumentValue(1); + + InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, + new_target, argc); + + GenerateIteratingTypedArrayBuiltinBody( + "%TypedArray%.prototype.findIndex", + &ArrayBuiltinCodeStubAssembler::FindIndexResultGenerator, + &ArrayBuiltinCodeStubAssembler::FindIndexProcessor, + &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); +} + TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinCodeStubAssembler) { Node* context = Parameter(Descriptor::kContext); Node* receiver = Parameter(Descriptor::kReceiver); @@ -1558,6 +2023,66 @@ TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinCodeStubAssembler) { &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); } +TF_BUILTIN(ArrayFilterLoopEagerDeoptContinuation, + ArrayBuiltinCodeStubAssembler) { + Node* context = Parameter(Descriptor::kContext); + Node* receiver = Parameter(Descriptor::kReceiver); + Node* callbackfn = Parameter(Descriptor::kCallbackFn); + Node* this_arg = Parameter(Descriptor::kThisArg); + Node* array = Parameter(Descriptor::kArray); + Node* initial_k = Parameter(Descriptor::kInitialK); + Node* len = Parameter(Descriptor::kLength); + Node* to = Parameter(Descriptor::kTo); + + Callable stub( + Builtins::CallableFor(isolate(), Builtins::kArrayFilterLoopContinuation)); + Return(CallStub(stub, context, receiver, callbackfn, this_arg, array, + receiver, initial_k, len, to)); +} + +TF_BUILTIN(ArrayFilterLoopLazyDeoptContinuation, + ArrayBuiltinCodeStubAssembler) { + Node* context = Parameter(Descriptor::kContext); + Node* receiver = Parameter(Descriptor::kReceiver); + Node* callbackfn = Parameter(Descriptor::kCallbackFn); + Node* this_arg = Parameter(Descriptor::kThisArg); + Node* array = Parameter(Descriptor::kArray); + Node* initial_k = Parameter(Descriptor::kInitialK); + Node* len = Parameter(Descriptor::kLength); + Node* value_k = Parameter(Descriptor::kValueK); + Node* result = Parameter(Descriptor::kResult); + + VARIABLE(to, MachineRepresentation::kTagged, Parameter(Descriptor::kTo)); + + // This custom lazy deopt point is right after the callback. filter() needs + // to pick up at the next step, which is setting the callback result in + // the output array. After incrementing k and to, we can glide into the loop + // continuation builtin. + + Label true_continue(this, &to), false_continue(this); + + // iii. If selected is true, then... + BranchIfToBooleanIsTrue(result, &true_continue, &false_continue); + BIND(&true_continue); + { + // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue). + CallRuntime(Runtime::kCreateDataProperty, context, array, to.value(), + value_k); + // 2. Increase to by 1. + to.Bind(NumberInc(to.value())); + Goto(&false_continue); + } + BIND(&false_continue); + + // Increment k. + initial_k = NumberInc(initial_k); + + Callable stub( + Builtins::CallableFor(isolate(), Builtins::kArrayFilterLoopContinuation)); + Return(CallStub(stub, context, receiver, callbackfn, this_arg, array, + receiver, initial_k, len, to.value())); +} + TF_BUILTIN(ArrayFilter, ArrayBuiltinCodeStubAssembler) { Node* argc = ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount)); @@ -1689,18 +2214,17 @@ TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { GotoIf(TaggedIsSmi(object), &return_false); TNode<Word32T> instance_type = LoadInstanceType(CAST(object)); - GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), - &return_true); + GotoIf(InstanceTypeEqual(instance_type, JS_ARRAY_TYPE), &return_true); // TODO(verwaest): Handle proxies in-place. - Branch(Word32Equal(instance_type, Int32Constant(JS_PROXY_TYPE)), - &call_runtime, &return_false); + Branch(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), &call_runtime, + &return_false); BIND(&return_true); - Return(BooleanConstant(true)); + Return(TrueConstant()); BIND(&return_false); - Return(BooleanConstant(false)); + Return(FalseConstant()); BIND(&call_runtime); Return(CallRuntime(Runtime::kArrayIsArray, context, object)); @@ -1898,32 +2422,32 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant) { BIND(&string_loop); { - CSA_ASSERT(this, IsString(search_element)); + TNode<String> search_element_string = CAST(search_element); Label continue_loop(this), next_iteration(this, &index_var), slow_compare(this), runtime(this, Label::kDeferred); - Node* search_length = LoadStringLength(search_element); + TNode<IntPtrT> search_length = + LoadStringLengthAsWord(search_element_string); Goto(&next_iteration); BIND(&next_iteration); GotoIfNot(UintPtrLessThan(index_var.value(), array_length), &return_not_found); Node* element_k = LoadFixedArrayElement(elements, index_var.value()); GotoIf(TaggedIsSmi(element_k), &continue_loop); - GotoIf(WordEqual(search_element, element_k), &return_found); + GotoIf(WordEqual(search_element_string, element_k), &return_found); Node* element_k_type = LoadInstanceType(element_k); GotoIfNot(IsStringInstanceType(element_k_type), &continue_loop); - Branch(WordEqual(search_length, LoadStringLength(element_k)), + Branch(WordEqual(search_length, LoadStringLengthAsWord(element_k)), &slow_compare, &continue_loop); BIND(&slow_compare); StringBuiltinsAssembler string_asm(state()); - string_asm.StringEqual_Core(context, search_element, search_type, - search_length, element_k, element_k_type, + string_asm.StringEqual_Core(context, search_element_string, search_type, + element_k, element_k_type, search_length, &return_found, &continue_loop, &runtime); BIND(&runtime); TNode<Object> result = CallRuntime(Runtime::kStringEqual, context, - search_element, element_k); - Branch(WordEqual(BooleanConstant(true), result), &return_found, - &continue_loop); + search_element_string, element_k); + Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop); BIND(&continue_loop); Increment(&index_var); @@ -1934,10 +2458,16 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant) { { GotoIfNot(UintPtrLessThan(index_var.value(), array_length), &return_not_found); + Node* element_k = LoadFixedArrayElement(elements, index_var.value()); - TNode<Object> result = CallRuntime(Runtime::kBigIntEqual, context, + Label continue_loop(this); + GotoIf(TaggedIsSmi(element_k), &continue_loop); + GotoIfNot(IsBigInt(element_k), &continue_loop); + TNode<Object> result = CallRuntime(Runtime::kBigIntEqualToBigInt, context, search_element, element_k); - GotoIf(WordEqual(result, TrueConstant()), &return_found); + Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop); + + BIND(&continue_loop); Increment(&index_var); Goto(&bigint_loop); } @@ -2178,11 +2708,7 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) { // (22.1.5.3), throw a TypeError exception GotoIf(TaggedIsSmi(iterator), &throw_bad_receiver); TNode<Int32T> instance_type = LoadInstanceType(iterator); - GotoIf( - Uint32LessThan( - Int32Constant(LAST_ARRAY_ITERATOR_TYPE - FIRST_ARRAY_ITERATOR_TYPE), - Int32Sub(instance_type, Int32Constant(FIRST_ARRAY_ITERATOR_TYPE))), - &throw_bad_receiver); + GotoIf(IsArrayIteratorInstanceType(instance_type), &throw_bad_receiver); // Let a be O.[[IteratedObject]]. Node* array = @@ -2201,10 +2727,10 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) { BIND(&if_isfastarray); { - CSA_ASSERT(this, Word32Equal(LoadMapInstanceType(array_map), - Int32Constant(JS_ARRAY_TYPE))); + CSA_ASSERT( + this, InstanceTypeEqual(LoadMapInstanceType(array_map), JS_ARRAY_TYPE)); - Node* length = LoadObjectField(array, JSArray::kLengthOffset); + Node* length = LoadJSArrayLength(array); CSA_ASSERT(this, TaggedIsSmi(length)); CSA_ASSERT(this, TaggedIsSmi(index)); @@ -2262,8 +2788,9 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) { BIND(&holey_object_values); { - // Check the array_protector cell, and take the slow path if it's invalid. - GotoIf(IsArrayProtectorCellInvalid(), &generic_values); + // Check the no_elements_protector cell, and take the slow path if it's + // invalid. + GotoIf(IsNoElementsProtectorCellInvalid(), &generic_values); var_value.Bind(UndefinedConstant()); Node* value = LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS); @@ -2274,8 +2801,9 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) { BIND(&holey_double_values); { - // Check the array_protector cell, and take the slow path if it's invalid. - GotoIf(IsArrayProtectorCellInvalid(), &generic_values); + // Check the no_elements_protector cell, and take the slow path if it's + // invalid. + GotoIf(IsNoElementsProtectorCellInvalid(), &generic_values); var_value.Bind(UndefinedConstant()); Node* value = LoadFixedDoubleArrayElement( @@ -2291,11 +2819,11 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) { Label if_istypedarray(this), if_isgeneric(this); // If a is undefined, return CreateIterResultObject(undefined, true) - GotoIf(WordEqual(array, UndefinedConstant()), &allocate_iterator_result); + GotoIf(IsUndefined(array), &allocate_iterator_result); Node* array_type = LoadInstanceType(array); - Branch(Word32Equal(array_type, Int32Constant(JS_TYPED_ARRAY_TYPE)), - &if_istypedarray, &if_isgeneric); + Branch(InstanceTypeEqual(array_type, JS_TYPED_ARRAY_TYPE), &if_istypedarray, + &if_isgeneric); BIND(&if_isgeneric); { @@ -2305,12 +2833,12 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) { { VARIABLE(var_length, MachineRepresentation::kTagged); Label if_isarray(this), if_isnotarray(this), done(this); - Branch(Word32Equal(array_type, Int32Constant(JS_ARRAY_TYPE)), - &if_isarray, &if_isnotarray); + Branch(InstanceTypeEqual(array_type, JS_ARRAY_TYPE), &if_isarray, + &if_isnotarray); BIND(&if_isarray); { - var_length.Bind(LoadObjectField(array, JSArray::kLengthOffset)); + var_length.Bind(LoadJSArrayLength(array)); // Invalidate protector cell if needed Branch(WordNotEqual(orig_map, UndefinedConstant()), &if_wasfastarray, @@ -2349,7 +2877,7 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) { length = var_length.value(); } - GotoIfNumberGreaterThanOrEqual(index, length, &set_done); + GotoIfNumericGreaterThanOrEqual(index, length, &set_done); StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset, NumberInc(index)); |