5 #include "src/builtins/builtins-collections-gen.h" 7 #include "src/builtins/builtins-constructor-gen.h" 8 #include "src/builtins/builtins-iterator-gen.h" 9 #include "src/builtins/builtins-utils-gen.h" 10 #include "src/code-stub-assembler.h" 11 #include "src/heap/factory-inl.h" 12 #include "src/objects/hash-table-inl.h" 13 #include "src/objects/js-collection.h" 14 #include "torque-generated/builtins-base-from-dsl-gen.h" 15 #include "torque-generated/builtins-collections-from-dsl-gen.h" 21 using TVariable = compiler::TypedCodeAssemblerVariable<T>;
32 enum Variant { kMap, kSet, kWeakMap, kWeakSet };
39 Label* if_may_have_side_effects =
nullptr,
40 Label* if_exception =
nullptr,
45 void AddConstructorEntries(Variant variant,
TNode<Context> context,
52 void AddConstructorEntriesFromFastJSArray(Variant variant,
57 Label* if_may_have_side_effects);
60 void AddConstructorEntriesFromIterable(Variant variant,
86 void GenerateConstructor(Variant variant,
108 void GotoIfInitialAddFunctionModified(Variant variant,
114 RootIndex GetAddFunctionNameIndex(Variant variant);
117 int GetTableOffset(Variant variant);
125 void GotoIfNotJSReceiver(
Node*
const obj,
Label* if_not_receiver);
128 TNode<BoolT> HasInitialCollectionPrototype(Variant variant,
133 TNode<Map> GetInitialCollectionPrototype(Variant variant,
147 void BaseCollectionsAssembler::AddConstructorEntry(
150 Label* if_may_have_side_effects,
Label* if_exception,
154 CSA_ASSERT(
this, Word32BinaryNot(IsTheHole(key_value)));
155 if (variant == kMap || variant == kWeakMap) {
156 BaseBuiltinsFromDSLAssembler::KeyValuePair pair =
157 if_may_have_side_effects !=
nullptr 158 ? LoadKeyValuePairNoSideEffects(context, key_value,
159 if_may_have_side_effects)
160 : LoadKeyValuePair(context, key_value);
161 Node* key_n = pair.key;
162 Node* value_n = pair.value;
163 CallJS(CodeFactory::Call(isolate()), context, add_function, collection,
166 DCHECK(variant == kSet || variant == kWeakSet);
167 CallJS(CodeFactory::Call(isolate()), context, add_function, collection,
172 void BaseCollectionsAssembler::AddConstructorEntries(
173 Variant variant, TNode<Context> context, TNode<Context> native_context,
174 TNode<Object> collection, TNode<Object> initial_entries) {
175 TVARIABLE(BoolT, use_fast_loop,
176 IsFastJSArrayWithNoCustomIteration(context, initial_entries));
177 TNode<IntPtrT> at_least_space_for =
178 EstimatedInitialSize(initial_entries, use_fast_loop.value());
179 Label allocate_table(
this, &use_fast_loop), exit(
this), fast_loop(
this),
180 slow_loop(
this, Label::kDeferred);
181 Goto(&allocate_table);
182 BIND(&allocate_table);
184 TNode<Object> table = AllocateTable(variant, context, at_least_space_for);
185 StoreObjectField(collection, GetTableOffset(variant), table);
186 GotoIf(IsNullOrUndefined(initial_entries), &exit);
187 GotoIfInitialAddFunctionModified(variant, native_context, collection,
189 Branch(use_fast_loop.value(), &fast_loop, &slow_loop);
193 TNode<JSArray> initial_entries_jsarray =
194 UncheckedCast<JSArray>(initial_entries);
196 CSA_ASSERT(
this, IsFastJSArrayWithNoCustomIteration(
197 context, initial_entries_jsarray));
198 TNode<Map> original_initial_entries_map = LoadMap(initial_entries_jsarray);
201 Label if_may_have_side_effects(
this, Label::kDeferred);
202 AddConstructorEntriesFromFastJSArray(variant, context, native_context,
203 collection, initial_entries_jsarray,
204 &if_may_have_side_effects);
207 if (variant == kMap || variant == kWeakMap) {
208 BIND(&if_may_have_side_effects);
212 Label if_not_modified(
this), if_modified(
this);
213 GotoIfInitialAddFunctionModified(variant, native_context, collection,
215 Goto(&if_not_modified);
218 BIND(&if_not_modified);
220 CSA_ASSERT(
this, WordEqual(original_initial_entries_map,
221 LoadMap(initial_entries_jsarray)));
223 use_fast_loop = Int32FalseConstant();
224 Goto(&allocate_table);
229 AddConstructorEntriesFromIterable(variant, context, native_context,
230 collection, initial_entries);
236 void BaseCollectionsAssembler::AddConstructorEntriesFromFastJSArray(
237 Variant variant, TNode<Context> context, TNode<Context> native_context,
238 TNode<Object> collection, TNode<JSArray> fast_jsarray,
239 Label* if_may_have_side_effects) {
240 TNode<FixedArrayBase> elements = LoadElements(fast_jsarray);
241 TNode<Int32T> elements_kind = LoadElementsKind(fast_jsarray);
242 TNode<JSFunction> add_func = GetInitialAddFunction(variant, native_context);
245 WordEqual(GetAddFunction(variant, native_context, collection), add_func));
246 CSA_ASSERT(
this, IsFastJSArrayWithNoCustomIteration(context, fast_jsarray));
247 TNode<IntPtrT> length = SmiUntag(LoadFastJSArrayLength(fast_jsarray));
248 CSA_ASSERT(
this, IntPtrGreaterThanOrEqual(length, IntPtrConstant(0)));
250 this, HasInitialCollectionPrototype(variant, native_context, collection));
253 TNode<Map> original_collection_map = LoadMap(CAST(collection));
254 TNode<Map> original_fast_js_array_map = LoadMap(fast_jsarray);
256 Label exit(
this), if_doubles(
this), if_smiorobjects(
this);
257 GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &exit);
258 Branch(IsFastSmiOrTaggedElementsKind(elements_kind), &if_smiorobjects,
260 BIND(&if_smiorobjects);
262 auto set_entry = [&](Node* index) {
263 TNode<Object> element = LoadAndNormalizeFixedArrayElement(
264 CAST(elements), UncheckedCast<IntPtrT>(index));
265 AddConstructorEntry(variant, context, collection, add_func, element,
266 if_may_have_side_effects);
273 BuildFastLoop(IntPtrConstant(0), length, set_entry, 1,
274 ParameterMode::INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
281 if (variant == kMap || variant == kWeakMap) {
282 CSA_ASSERT(
this, IntPtrGreaterThan(length, IntPtrConstant(0)));
283 TNode<Object> element =
284 LoadAndNormalizeFixedDoubleArrayElement(elements, IntPtrConstant(0));
285 ThrowTypeError(context, MessageTemplate::kIteratorValueNotAnObject,
288 DCHECK(variant == kSet || variant == kWeakSet);
289 auto set_entry = [&](Node* index) {
290 TNode<Object> entry = LoadAndNormalizeFixedDoubleArrayElement(
291 elements, UncheckedCast<IntPtrT>(index));
292 AddConstructorEntry(variant, context, collection, add_func, entry);
294 BuildFastLoop(IntPtrConstant(0), length, set_entry, 1,
295 ParameterMode::INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
302 WordEqual(original_collection_map, LoadMap(CAST(collection))));
304 WordEqual(original_fast_js_array_map, LoadMap(fast_jsarray)));
308 void BaseCollectionsAssembler::AddConstructorEntriesFromIterable(
309 Variant variant, TNode<Context> context, TNode<Context> native_context,
310 TNode<Object> collection, TNode<Object> iterable) {
311 Label exit(
this), loop(
this), if_exception(
this, Label::kDeferred);
312 CSA_ASSERT(
this, Word32BinaryNot(IsNullOrUndefined(iterable)));
314 TNode<Object> add_func = GetAddFunction(variant, context, collection);
315 IteratorBuiltinsAssembler iterator_assembler(this->state());
316 IteratorBuiltinsAssembler::IteratorRecord iterator =
317 iterator_assembler.GetIterator(context, iterable);
319 CSA_ASSERT(
this, Word32BinaryNot(IsUndefined(iterator.object)));
321 TNode<Object> fast_iterator_result_map =
322 LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
323 TVARIABLE(Object, var_exception);
328 TNode<Object> next = iterator_assembler.IteratorStep(
329 context, iterator, &exit, fast_iterator_result_map);
330 TNode<Object> next_value = CAST(iterator_assembler.IteratorValue(
331 context, next, fast_iterator_result_map));
332 AddConstructorEntry(variant, context, collection, add_func, next_value,
333 nullptr, &if_exception, &var_exception);
338 iterator_assembler.IteratorCloseOnException(context, iterator,
339 var_exception.value());
344 RootIndex BaseCollectionsAssembler::GetAddFunctionNameIndex(Variant variant) {
348 return RootIndex::kset_string;
351 return RootIndex::kadd_string;
356 void BaseCollectionsAssembler::GotoIfInitialAddFunctionModified(
357 Variant variant, TNode<Context> native_context, TNode<Object> collection,
358 Label* if_modified) {
359 STATIC_ASSERT(JSCollection::kAddFunctionDescriptorIndex ==
360 JSWeakCollection::kAddFunctionDescriptorIndex);
361 GotoIfInitialPrototypePropertyModified(
362 LoadMap(CAST(collection)),
363 GetInitialCollectionPrototype(variant, native_context),
364 JSCollection::kAddFunctionDescriptorIndex,
365 GetAddFunctionNameIndex(variant), if_modified);
368 TNode<Object> BaseCollectionsAssembler::AllocateJSCollection(
369 TNode<Context> context, TNode<JSFunction> constructor,
370 TNode<Object> new_target) {
371 TNode<BoolT> is_target_unmodified = WordEqual(constructor, new_target);
373 return Select<Object>(is_target_unmodified,
374 [=] {
return AllocateJSCollectionFast(constructor); },
376 return AllocateJSCollectionSlow(context, constructor,
381 TNode<Object> BaseCollectionsAssembler::AllocateJSCollectionFast(
382 TNode<HeapObject> constructor) {
383 CSA_ASSERT(
this, IsConstructorMap(LoadMap(constructor)));
384 TNode<Object> initial_map =
385 LoadObjectField(constructor, JSFunction::kPrototypeOrInitialMapOffset);
386 return CAST(AllocateJSObjectFromMap(initial_map));
389 TNode<Object> BaseCollectionsAssembler::AllocateJSCollectionSlow(
390 TNode<Context> context, TNode<JSFunction> constructor,
391 TNode<Object> new_target) {
392 ConstructorBuiltinsAssembler constructor_assembler(this->state());
393 return CAST(constructor_assembler.EmitFastNewObject(context, constructor,
397 void BaseCollectionsAssembler::GenerateConstructor(
398 Variant variant, Handle<String> constructor_function_name,
399 TNode<Object> new_target, TNode<IntPtrT> argc, TNode<Context> context) {
400 const int kIterableArg = 0;
401 CodeStubArguments args(
this, argc);
402 TNode<Object> iterable = args.GetOptionalArgumentValue(kIterableArg);
404 Label if_undefined(
this, Label::kDeferred);
405 GotoIf(IsUndefined(new_target), &if_undefined);
407 TNode<Context> native_context = LoadNativeContext(context);
408 TNode<Object> collection = AllocateJSCollection(
409 context, GetConstructor(variant, native_context), new_target);
411 AddConstructorEntries(variant, context, native_context, collection, iterable);
415 ThrowTypeError(context, MessageTemplate::kConstructorNotFunction,
416 HeapConstant(constructor_function_name));
419 TNode<Object> BaseCollectionsAssembler::GetAddFunction(
420 Variant variant, TNode<Context> context, TNode<Object> collection) {
421 Handle<String> add_func_name = (variant == kMap || variant == kWeakMap)
422 ? isolate()->factory()->set_string()
423 : isolate()->factory()->add_string();
424 TNode<Object> add_func = GetProperty(context, collection, add_func_name);
426 Label exit(
this), if_notcallable(
this, Label::kDeferred);
427 GotoIf(TaggedIsSmi(add_func), &if_notcallable);
428 GotoIfNot(IsCallable(CAST(add_func)), &if_notcallable);
431 BIND(&if_notcallable);
432 ThrowTypeError(context, MessageTemplate::kPropertyNotFunction, add_func,
433 HeapConstant(add_func_name), collection);
439 TNode<JSFunction> BaseCollectionsAssembler::GetConstructor(
440 Variant variant, TNode<Context> native_context) {
444 index = Context::JS_MAP_FUN_INDEX;
447 index = Context::JS_SET_FUN_INDEX;
450 index = Context::JS_WEAK_MAP_FUN_INDEX;
453 index = Context::JS_WEAK_SET_FUN_INDEX;
456 return CAST(LoadContextElement(native_context, index));
459 TNode<JSFunction> BaseCollectionsAssembler::GetInitialAddFunction(
460 Variant variant, TNode<Context> native_context) {
464 index = Context::MAP_SET_INDEX;
467 index = Context::SET_ADD_INDEX;
470 index = Context::WEAKMAP_SET_INDEX;
473 index = Context::WEAKSET_ADD_INDEX;
476 return CAST(LoadContextElement(native_context, index));
479 int BaseCollectionsAssembler::GetTableOffset(Variant variant) {
482 return JSMap::kTableOffset;
484 return JSSet::kTableOffset;
486 return JSWeakMap::kTableOffset;
488 return JSWeakSet::kTableOffset;
493 TNode<IntPtrT> BaseCollectionsAssembler::EstimatedInitialSize(
494 TNode<Object> initial_entries, TNode<BoolT> is_fast_jsarray) {
495 return Select<IntPtrT>(
497 [=] {
return SmiUntag(LoadFastJSArrayLength(CAST(initial_entries))); },
498 [=] {
return IntPtrConstant(0); });
501 void BaseCollectionsAssembler::GotoIfNotJSReceiver(Node*
const obj,
502 Label* if_not_receiver) {
503 GotoIf(TaggedIsSmi(obj), if_not_receiver);
504 GotoIfNot(IsJSReceiver(obj), if_not_receiver);
507 TNode<Map> BaseCollectionsAssembler::GetInitialCollectionPrototype(
508 Variant variant, TNode<Context> native_context) {
509 int initial_prototype_index;
512 initial_prototype_index = Context::INITIAL_MAP_PROTOTYPE_MAP_INDEX;
515 initial_prototype_index = Context::INITIAL_SET_PROTOTYPE_MAP_INDEX;
518 initial_prototype_index = Context::INITIAL_WEAKMAP_PROTOTYPE_MAP_INDEX;
521 initial_prototype_index = Context::INITIAL_WEAKSET_PROTOTYPE_MAP_INDEX;
524 return CAST(LoadContextElement(native_context, initial_prototype_index));
527 TNode<BoolT> BaseCollectionsAssembler::HasInitialCollectionPrototype(
528 Variant variant, TNode<Context> native_context, TNode<Object> collection) {
529 TNode<Map> collection_proto_map =
530 LoadMap(LoadMapPrototype(LoadMap(CAST(collection))));
532 return WordEqual(collection_proto_map,
533 GetInitialCollectionPrototype(variant, native_context));
536 TNode<Object> BaseCollectionsAssembler::LoadAndNormalizeFixedArrayElement(
537 TNode<FixedArray> elements, TNode<IntPtrT> index) {
538 TNode<Object> element = LoadFixedArrayElement(elements, index);
539 return Select<Object>(IsTheHole(element), [=] {
return UndefinedConstant(); },
540 [=] {
return element; });
543 TNode<Object> BaseCollectionsAssembler::LoadAndNormalizeFixedDoubleArrayElement(
544 TNode<HeapObject> elements, TNode<IntPtrT> index) {
545 TVARIABLE(Object, entry);
546 Label if_hole(
this, Label::kDeferred), next(
this);
547 TNode<Float64T> element =
548 LoadFixedDoubleArrayElement(CAST(elements), index, MachineType::Float64(),
549 0, INTPTR_PARAMETERS, &if_hole);
551 entry = AllocateHeapNumberWithValue(element);
556 entry = UndefinedConstant();
560 return entry.value();
571 void BranchIfIterableWithOriginalKeyOrValueMapIterator(
TNode<Object> iterable,
579 void BranchIfIterableWithOriginalValueSetIterator(
TNode<Object> iterable,
585 template <
typename IteratorType>
586 Node* AllocateJSCollectionIterator(
Node* context,
int map_index,
591 Node* CallGetHashRaw(
Node*
const key);
592 Node* CallGetOrCreateHashRaw(
Node*
const key);
596 typedef std::function<void(Node* const table, Node* const index)>
598 template <
typename TableType>
601 UpdateInTransition
const& update_in_transition);
602 template <
typename IteratorType,
typename TableType>
605 template <
typename TableType>
612 template <
typename CollectionType>
613 void FindOrderedHashTableEntryForSmiKey(
Node* table,
Node* key_tagged,
616 void SameValueZeroSmi(
Node* key_smi,
Node* candidate_key,
Label* if_same,
622 void SameValueZeroHeapNumber(
Node* key_string,
Node* candidate_key,
624 template <
typename CollectionType>
625 void FindOrderedHashTableEntryForHeapNumberKey(
Node* context,
Node* table,
626 Node* key_heap_number,
634 void SameValueZeroBigInt(
Node* key,
Node* candidate_key,
Label* if_same,
636 template <
typename CollectionType>
637 void FindOrderedHashTableEntryForBigIntKey(
Node* context,
Node* table,
645 template <
typename CollectionType>
646 void FindOrderedHashTableEntryForStringKey(
Node* context,
Node* table,
650 Node* ComputeStringHash(
Node* context,
Node* string_key);
651 void SameValueZeroString(
Node* context,
Node* key_string,
Node* candidate_key,
659 template <
typename CollectionType>
660 void FindOrderedHashTableEntryForOtherKey(
Node* context,
Node* table,
665 template <
typename CollectionType>
666 void TryLookupOrderedHashTableIndex(
Node*
const table,
Node*
const key,
668 Label* if_entry_found,
669 Label* if_not_found);
671 Node* NormalizeNumberKey(
Node* key);
675 Node*
const number_of_buckets,
676 Node*
const occupancy);
679 Node*
const number_of_buckets,
680 Node*
const occupancy);
699 void BranchIfMapIteratorProtectorValid(
Label* if_true,
Label* if_false);
700 void BranchIfSetIteratorProtectorValid(
Label* if_true,
Label* if_false);
703 template <
typename IteratorType>
704 Node* CollectionsBuiltinsAssembler::AllocateJSCollectionIterator(
705 Node* context,
int map_index,
Node* collection) {
706 Node*
const table = LoadObjectField(collection, JSCollection::kTableOffset);
707 Node*
const native_context = LoadNativeContext(context);
708 Node*
const iterator_map = LoadContextElement(native_context, map_index);
709 Node*
const iterator = AllocateInNewSpace(IteratorType::kSize);
710 StoreMapNoWriteBarrier(iterator, iterator_map);
711 StoreObjectFieldRoot(iterator, IteratorType::kPropertiesOrHashOffset,
712 RootIndex::kEmptyFixedArray);
713 StoreObjectFieldRoot(iterator, IteratorType::kElementsOffset,
714 RootIndex::kEmptyFixedArray);
715 StoreObjectFieldNoWriteBarrier(iterator, IteratorType::kTableOffset, table);
716 StoreObjectFieldNoWriteBarrier(iterator, IteratorType::kIndexOffset,
721 TNode<Object> CollectionsBuiltinsAssembler::AllocateTable(
722 Variant variant, TNode<Context> context,
723 TNode<IntPtrT> at_least_space_for) {
724 return CAST((variant == kMap || variant == kWeakMap)
725 ? AllocateOrderedHashTable<OrderedHashMap>()
726 : AllocateOrderedHashTable<OrderedHashSet>());
729 TF_BUILTIN(MapConstructor, CollectionsBuiltinsAssembler) {
730 TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
731 TNode<IntPtrT> argc =
732 ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
733 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
735 GenerateConstructor(kMap, isolate()->factory()->Map_string(), new_target,
739 TF_BUILTIN(SetConstructor, CollectionsBuiltinsAssembler) {
740 TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
741 TNode<IntPtrT> argc =
742 ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
743 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
745 GenerateConstructor(kSet, isolate()->factory()->Set_string(), new_target,
749 Node* CollectionsBuiltinsAssembler::CallGetOrCreateHashRaw(Node*
const key) {
750 Node*
const function_addr =
751 ExternalConstant(ExternalReference::get_or_create_hash_raw());
752 Node*
const isolate_ptr =
753 ExternalConstant(ExternalReference::isolate_address(isolate()));
755 MachineType type_ptr = MachineType::Pointer();
756 MachineType type_tagged = MachineType::AnyTagged();
758 Node*
const result = CallCFunction2(type_tagged, type_ptr, type_tagged,
759 function_addr, isolate_ptr, key);
764 Node* CollectionsBuiltinsAssembler::CallGetHashRaw(Node*
const key) {
765 Node*
const function_addr =
766 ExternalConstant(ExternalReference::orderedhashmap_gethash_raw());
767 Node*
const isolate_ptr =
768 ExternalConstant(ExternalReference::isolate_address(isolate()));
770 MachineType type_ptr = MachineType::Pointer();
771 MachineType type_tagged = MachineType::AnyTagged();
773 Node*
const result = CallCFunction2(type_tagged, type_ptr, type_tagged,
774 function_addr, isolate_ptr, key);
775 return SmiUntag(result);
778 Node* CollectionsBuiltinsAssembler::GetHash(Node*
const key) {
779 VARIABLE(var_hash, MachineType::PointerRepresentation());
780 Label if_receiver(
this), if_other(
this), done(
this);
781 Branch(IsJSReceiver(key), &if_receiver, &if_other);
785 var_hash.Bind(LoadJSReceiverIdentityHash(key));
791 var_hash.Bind(CallGetHashRaw(key));
796 return var_hash.value();
799 void CollectionsBuiltinsAssembler::SameValueZeroSmi(Node* key_smi,
802 Label* if_not_same) {
804 GotoIf(WordEqual(candidate_key, key_smi), if_same);
808 GotoIf(TaggedIsSmi(candidate_key), if_not_same);
812 GotoIfNot(IsHeapNumber(candidate_key), if_not_same);
814 Node*
const candidate_key_number = LoadHeapNumberValue(candidate_key);
815 Node*
const key_number = SmiToFloat64(key_smi);
817 GotoIf(Float64Equal(candidate_key_number, key_number), if_same);
822 void CollectionsBuiltinsAssembler::BranchIfMapIteratorProtectorValid(
823 Label* if_true, Label* if_false) {
824 Node* protector_cell = LoadRoot(RootIndex::kMapIteratorProtector);
825 DCHECK(isolate()->heap()->map_iterator_protector()->IsPropertyCell());
826 Branch(WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
827 SmiConstant(Isolate::kProtectorValid)),
831 void CollectionsBuiltinsAssembler::
832 BranchIfIterableWithOriginalKeyOrValueMapIterator(TNode<Object> iterator,
833 TNode<Context> context,
836 Label if_key_or_value_iterator(
this), extra_checks(
this);
839 GotoIf(TaggedIsSmi(iterator), if_false);
840 TNode<Map> iter_map = LoadMap(CAST(iterator));
841 Node*
const instance_type = LoadMapInstanceType(iter_map);
842 GotoIf(InstanceTypeEqual(instance_type, JS_MAP_KEY_ITERATOR_TYPE),
843 &if_key_or_value_iterator);
844 Branch(InstanceTypeEqual(instance_type, JS_MAP_VALUE_ITERATOR_TYPE),
845 &if_key_or_value_iterator, if_false);
847 BIND(&if_key_or_value_iterator);
850 LoadObjectField(CAST(iterator), JSMapIterator::kIndexOffset);
851 GotoIfNot(WordEqual(index, SmiConstant(0)), if_false);
852 BranchIfMapIteratorProtectorValid(&extra_checks, if_false);
856 Node*
const native_context = LoadNativeContext(context);
857 Node*
const initial_map_iter_proto = LoadContextElement(
858 native_context, Context::INITIAL_MAP_ITERATOR_PROTOTYPE_INDEX);
859 Node*
const map_iter_proto = LoadMapPrototype(iter_map);
860 GotoIfNot(WordEqual(map_iter_proto, initial_map_iter_proto), if_false);
864 Node*
const initial_iter_proto = LoadContextElement(
865 native_context, Context::INITIAL_ITERATOR_PROTOTYPE_INDEX);
866 Node*
const iter_proto = LoadMapPrototype(LoadMap(map_iter_proto));
867 Branch(WordEqual(iter_proto, initial_iter_proto), if_true, if_false);
870 void BranchIfIterableWithOriginalKeyOrValueMapIterator(
871 compiler::CodeAssemblerState* state, TNode<Object> iterable,
872 TNode<Context> context, compiler::CodeAssemblerLabel* if_true,
873 compiler::CodeAssemblerLabel* if_false) {
874 CollectionsBuiltinsAssembler assembler(state);
875 assembler.BranchIfIterableWithOriginalKeyOrValueMapIterator(
876 iterable, context, if_true, if_false);
879 void CollectionsBuiltinsAssembler::BranchIfSetIteratorProtectorValid(
880 Label* if_true, Label* if_false) {
881 Node*
const protector_cell = LoadRoot(RootIndex::kSetIteratorProtector);
882 DCHECK(isolate()->heap()->set_iterator_protector()->IsPropertyCell());
883 Branch(WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
884 SmiConstant(Isolate::kProtectorValid)),
888 void CollectionsBuiltinsAssembler::BranchIfIterableWithOriginalValueSetIterator(
889 TNode<Object> iterable, TNode<Context> context, Label* if_true,
891 Label if_set(
this), if_value_iterator(
this), check_protector(
this);
892 TVARIABLE(BoolT, var_result);
894 GotoIf(TaggedIsSmi(iterable), if_false);
895 TNode<Map> iterable_map = LoadMap(CAST(iterable));
896 Node*
const instance_type = LoadMapInstanceType(iterable_map);
898 GotoIf(InstanceTypeEqual(instance_type, JS_SET_TYPE), &if_set);
899 Branch(InstanceTypeEqual(instance_type, JS_SET_VALUE_ITERATOR_TYPE),
900 &if_value_iterator, if_false);
904 Node*
const initial_set_proto = LoadContextElement(
905 LoadNativeContext(context), Context::INITIAL_SET_PROTOTYPE_INDEX);
906 Node*
const set_proto = LoadMapPrototype(iterable_map);
907 GotoIfNot(WordEqual(set_proto, initial_set_proto), if_false);
908 Goto(&check_protector);
910 BIND(&if_value_iterator);
913 LoadObjectField(CAST(iterable), JSSetIterator::kIndexOffset);
914 GotoIfNot(WordEqual(index, SmiConstant(0)), if_false);
917 Node*
const native_context = LoadNativeContext(context);
918 Node*
const initial_set_iter_proto = LoadContextElement(
919 native_context, Context::INITIAL_SET_ITERATOR_PROTOTYPE_INDEX);
920 Node*
const set_iter_proto = LoadMapPrototype(iterable_map);
921 GotoIfNot(WordEqual(set_iter_proto, initial_set_iter_proto), if_false);
925 Node*
const initial_iter_proto = LoadContextElement(
926 native_context, Context::INITIAL_ITERATOR_PROTOTYPE_INDEX);
927 Node*
const iter_proto = LoadMapPrototype(LoadMap(set_iter_proto));
928 GotoIfNot(WordEqual(iter_proto, initial_iter_proto), if_false);
929 Goto(&check_protector);
931 BIND(&check_protector);
932 BranchIfSetIteratorProtectorValid(if_true, if_false);
935 void BranchIfIterableWithOriginalValueSetIterator(
936 compiler::CodeAssemblerState* state, TNode<Object> iterable,
937 TNode<Context> context, compiler::CodeAssemblerLabel* if_true,
938 compiler::CodeAssemblerLabel* if_false) {
939 CollectionsBuiltinsAssembler assembler(state);
940 assembler.BranchIfIterableWithOriginalValueSetIterator(iterable, context,
944 TNode<JSArray> CollectionsBuiltinsAssembler::MapIteratorToList(
945 TNode<Context> context, TNode<JSMapIterator> iterator) {
947 TNode<OrderedHashMap> table;
948 TNode<IntPtrT> index;
949 std::tie(table, index) =
950 TransitionAndUpdate<JSMapIterator, OrderedHashMap>(iterator);
951 CSA_ASSERT(
this, IntPtrEqual(index, IntPtrConstant(0)));
953 TNode<IntPtrT> size =
954 LoadAndUntagObjectField(table, OrderedHashMap::kNumberOfElementsOffset);
956 const ElementsKind kind = PACKED_ELEMENTS;
957 TNode<Map> array_map =
958 LoadJSArrayElementsMap(kind, LoadNativeContext(context));
959 TNode<JSArray> array =
960 AllocateJSArray(kind, array_map, size, SmiTag(size),
nullptr,
961 INTPTR_PARAMETERS, kAllowLargeObjectAllocation);
962 TNode<FixedArray> elements = CAST(LoadElements(array));
964 const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag;
965 TNode<IntPtrT> first_to_element_offset =
966 ElementOffsetFromIndex(IntPtrConstant(0), kind, INTPTR_PARAMETERS, 0);
968 var_offset, MachineType::PointerRepresentation(),
969 IntPtrAdd(first_to_element_offset, IntPtrConstant(first_element_offset)));
970 TVARIABLE(IntPtrT, var_index, index);
971 VariableList vars({&var_index, &var_offset}, zone());
972 Label done(
this, {&var_index}), loop(
this, vars), continue_loop(
this, vars),
973 write_key(
this, vars), write_value(
this, vars);
980 TNode<Object> entry_key;
981 TNode<IntPtrT> entry_start_position;
982 TNode<IntPtrT> cur_index;
983 std::tie(entry_key, entry_start_position, cur_index) =
984 NextSkipHoles<OrderedHashMap>(table, var_index.value(), &done);
988 InstanceTypeEqual(LoadInstanceType(iterator), JS_MAP_KEY_ITERATOR_TYPE),
989 &write_key, &write_value);
993 Store(elements, var_offset.value(), entry_key);
994 Goto(&continue_loop);
999 CSA_ASSERT(
this, InstanceTypeEqual(LoadInstanceType(iterator),
1000 JS_MAP_VALUE_ITERATOR_TYPE));
1001 TNode<Object> entry_value =
1002 LoadFixedArrayElement(table, entry_start_position,
1003 (OrderedHashMap::kHashTableStartIndex +
1004 OrderedHashMap::kValueOffset) *
1007 Store(elements, var_offset.value(), entry_value);
1008 Goto(&continue_loop);
1011 BIND(&continue_loop);
1014 var_index = cur_index;
1016 IntPtrAdd(var_offset.value(), IntPtrConstant(kPointerSize)));
1023 StoreObjectFieldRoot(iterator, JSMapIterator::kTableOffset,
1024 RootIndex::kEmptyOrderedHashMap);
1025 StoreObjectFieldNoWriteBarrier(iterator, JSMapIterator::kIndexOffset,
1026 SmiTag(var_index.value()));
1027 return UncheckedCast<JSArray>(array);
1030 TF_BUILTIN(MapIteratorToList, CollectionsBuiltinsAssembler) {
1031 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1032 TNode<JSMapIterator> iterator = CAST(Parameter(Descriptor::kSource));
1033 Return(MapIteratorToList(context, iterator));
1036 TNode<JSArray> CollectionsBuiltinsAssembler::SetOrSetIteratorToList(
1037 TNode<Context> context, TNode<Object> iterable) {
1038 TVARIABLE(OrderedHashSet, var_table);
1039 Label if_set(
this), if_iterator(
this), copy(
this);
1041 Node*
const instance_type = LoadInstanceType(CAST(iterable));
1042 Branch(InstanceTypeEqual(instance_type, JS_SET_TYPE), &if_set, &if_iterator);
1047 var_table = CAST(LoadObjectField(CAST(iterable), JSSet::kTableOffset));
1055 TNode<OrderedHashSet> iter_table;
1056 TNode<IntPtrT> iter_index;
1057 std::tie(iter_table, iter_index) =
1058 TransitionAndUpdate<JSSetIterator, OrderedHashSet>(CAST(iterable));
1059 CSA_ASSERT(
this, IntPtrEqual(iter_index, IntPtrConstant(0)));
1060 var_table = iter_table;
1065 TNode<OrderedHashSet> table = var_table.value();
1066 TNode<IntPtrT> size =
1067 LoadAndUntagObjectField(table, OrderedHashMap::kNumberOfElementsOffset);
1069 const ElementsKind kind = PACKED_ELEMENTS;
1070 TNode<Map> array_map =
1071 LoadJSArrayElementsMap(kind, LoadNativeContext(context));
1072 TNode<JSArray> array =
1073 AllocateJSArray(kind, array_map, size, SmiTag(size),
nullptr,
1074 INTPTR_PARAMETERS, kAllowLargeObjectAllocation);
1075 TNode<FixedArray> elements = CAST(LoadElements(array));
1077 const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag;
1078 TNode<IntPtrT> first_to_element_offset =
1079 ElementOffsetFromIndex(IntPtrConstant(0), kind, INTPTR_PARAMETERS, 0);
1081 var_offset, MachineType::PointerRepresentation(),
1082 IntPtrAdd(first_to_element_offset, IntPtrConstant(first_element_offset)));
1083 TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
1084 Label done(
this), finalize(
this, {&var_index}),
1085 loop(
this, {&var_index, &var_offset});
1092 TNode<Object> entry_key;
1093 TNode<IntPtrT> entry_start_position;
1094 TNode<IntPtrT> cur_index;
1095 std::tie(entry_key, entry_start_position, cur_index) =
1096 NextSkipHoles<OrderedHashSet>(table, var_index.value(), &finalize);
1098 Store(elements, var_offset.value(), entry_key);
1100 var_index = cur_index;
1102 IntPtrAdd(var_offset.value(), IntPtrConstant(kPointerSize)));
1107 GotoIf(InstanceTypeEqual(instance_type, JS_SET_TYPE), &done);
1109 StoreObjectFieldRoot(iterable, JSSetIterator::kTableOffset,
1110 RootIndex::kEmptyOrderedHashSet);
1111 StoreObjectFieldNoWriteBarrier(iterable, JSSetIterator::kIndexOffset,
1112 SmiTag(var_index.value()));
1116 return UncheckedCast<JSArray>(array);
1119 TF_BUILTIN(SetOrSetIteratorToList, CollectionsBuiltinsAssembler) {
1120 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1121 TNode<Object>
object = CAST(Parameter(Descriptor::kSource));
1122 Return(SetOrSetIteratorToList(context,
object));
1125 template <
typename CollectionType>
1126 void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForSmiKey(
1127 Node* table, Node* smi_key, Variable* result, Label* entry_found,
1129 Node*
const key_untagged = SmiUntag(smi_key);
1130 Node*
const hash = ChangeInt32ToIntPtr(ComputeUnseededHash(key_untagged));
1131 CSA_ASSERT(
this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
1133 FindOrderedHashTableEntry<CollectionType>(
1135 [&](Node* other_key, Label* if_same, Label* if_not_same) {
1136 SameValueZeroSmi(smi_key, other_key, if_same, if_not_same);
1138 result, entry_found, not_found);
1141 template <
typename CollectionType>
1142 void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForStringKey(
1143 Node* context, Node* table, Node* key_tagged, Variable* result,
1144 Label* entry_found, Label* not_found) {
1145 Node*
const hash = ComputeStringHash(context, key_tagged);
1146 CSA_ASSERT(
this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
1148 FindOrderedHashTableEntry<CollectionType>(
1150 [&](Node* other_key, Label* if_same, Label* if_not_same) {
1151 SameValueZeroString(context, key_tagged, other_key, if_same,
1154 result, entry_found, not_found);
1157 template <
typename CollectionType>
1158 void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForHeapNumberKey(
1159 Node* context, Node* table, Node* key_heap_number, Variable* result,
1160 Label* entry_found, Label* not_found) {
1161 Node* hash = CallGetHashRaw(key_heap_number);
1162 CSA_ASSERT(
this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
1164 Node*
const key_float = LoadHeapNumberValue(key_heap_number);
1165 FindOrderedHashTableEntry<CollectionType>(
1167 [&](Node* other_key, Label* if_same, Label* if_not_same) {
1168 SameValueZeroHeapNumber(key_float, other_key, if_same, if_not_same);
1170 result, entry_found, not_found);
1173 template <
typename CollectionType>
1174 void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForBigIntKey(
1175 Node* context, Node* table, Node* key, Variable* result, Label* entry_found,
1177 Node* hash = CallGetHashRaw(key);
1178 CSA_ASSERT(
this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
1180 FindOrderedHashTableEntry<CollectionType>(
1182 [&](Node* other_key, Label* if_same, Label* if_not_same) {
1183 SameValueZeroBigInt(key, other_key, if_same, if_not_same);
1185 result, entry_found, not_found);
1188 template <
typename CollectionType>
1189 void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForOtherKey(
1190 Node* context, Node* table, Node* key, Variable* result, Label* entry_found,
1192 Node* hash = GetHash(key);
1193 CSA_ASSERT(
this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
1195 FindOrderedHashTableEntry<CollectionType>(
1197 [&](Node* other_key, Label* if_same, Label* if_not_same) {
1198 Branch(WordEqual(key, other_key), if_same, if_not_same);
1200 result, entry_found, not_found);
1203 Node* CollectionsBuiltinsAssembler::ComputeStringHash(Node* context,
1205 VARIABLE(var_result, MachineType::PointerRepresentation());
1207 Label hash_not_computed(
this), done(
this, &var_result);
1209 ChangeInt32ToIntPtr(LoadNameHash(string_key, &hash_not_computed));
1210 var_result.Bind(hash);
1213 BIND(&hash_not_computed);
1214 var_result.Bind(CallGetHashRaw(string_key));
1218 return var_result.value();
1221 void CollectionsBuiltinsAssembler::SameValueZeroString(Node* context,
1223 Node* candidate_key,
1225 Label* if_not_same) {
1227 GotoIf(TaggedIsSmi(candidate_key), if_not_same);
1228 GotoIfNot(IsString(candidate_key), if_not_same);
1230 Branch(WordEqual(CallBuiltin(Builtins::kStringEqual, context, key_string,
1233 if_same, if_not_same);
1236 void CollectionsBuiltinsAssembler::SameValueZeroBigInt(Node* key,
1237 Node* candidate_key,
1239 Label* if_not_same) {
1240 CSA_ASSERT(
this, IsBigInt(key));
1241 GotoIf(TaggedIsSmi(candidate_key), if_not_same);
1242 GotoIfNot(IsBigInt(candidate_key), if_not_same);
1244 Branch(WordEqual(CallRuntime(Runtime::kBigIntEqualToBigInt,
1245 NoContextConstant(), key, candidate_key),
1247 if_same, if_not_same);
1250 void CollectionsBuiltinsAssembler::SameValueZeroHeapNumber(Node* key_float,
1251 Node* candidate_key,
1253 Label* if_not_same) {
1254 Label if_smi(
this), if_keyisnan(
this);
1256 GotoIf(TaggedIsSmi(candidate_key), &if_smi);
1257 GotoIfNot(IsHeapNumber(candidate_key), if_not_same);
1261 Node*
const candidate_float = LoadHeapNumberValue(candidate_key);
1262 GotoIf(Float64Equal(key_float, candidate_float), if_same);
1266 BranchIfFloat64IsNaN(key_float, &if_keyisnan, if_not_same);
1271 Branch(Float64Equal(candidate_float, candidate_float), if_not_same,
1278 Node*
const candidate_float = SmiToFloat64(candidate_key);
1279 Branch(Float64Equal(key_float, candidate_float), if_same, if_not_same);
1283 TF_BUILTIN(OrderedHashTableHealIndex, CollectionsBuiltinsAssembler) {
1284 TNode<HeapObject> table = CAST(Parameter(Descriptor::kTable));
1285 TNode<Smi> index = CAST(Parameter(Descriptor::kIndex));
1286 Label return_index(
this), return_zero(
this);
1289 GotoIfNot(SmiLessThan(SmiConstant(0), index), &return_zero);
1292 STATIC_ASSERT(OrderedHashMap::kNumberOfDeletedElementsOffset ==
1293 OrderedHashSet::kNumberOfDeletedElementsOffset);
1294 Node* number_of_deleted_elements = LoadAndUntagObjectField(
1295 table, OrderedHashMap::kNumberOfDeletedElementsOffset);
1296 STATIC_ASSERT(OrderedHashMap::kClearedTableSentinel ==
1297 OrderedHashSet::kClearedTableSentinel);
1298 GotoIf(WordEqual(number_of_deleted_elements,
1299 IntPtrConstant(OrderedHashMap::kClearedTableSentinel)),
1302 VARIABLE(var_i, MachineType::PointerRepresentation(), IntPtrConstant(0));
1303 VARIABLE(var_index, MachineRepresentation::kTagged, index);
1304 Label loop(
this, {&var_i, &var_index});
1308 Node*
i = var_i.value();
1309 GotoIfNot(IntPtrLessThan(
i, number_of_deleted_elements), &return_index);
1310 STATIC_ASSERT(OrderedHashMap::kRemovedHolesIndex ==
1311 OrderedHashSet::kRemovedHolesIndex);
1312 TNode<Smi> removed_index = CAST(LoadFixedArrayElement(
1313 CAST(table),
i, OrderedHashMap::kRemovedHolesIndex * kPointerSize));
1314 GotoIf(SmiGreaterThanOrEqual(removed_index, index), &return_index);
1315 Decrement(&var_index, 1, SMI_PARAMETERS);
1320 BIND(&return_index);
1321 Return(var_index.value());
1324 Return(SmiConstant(0));
1327 template <
typename TableType>
1328 std::pair<TNode<TableType>, TNode<IntPtrT>>
1329 CollectionsBuiltinsAssembler::Transition(
1330 TNode<TableType>
const table, TNode<IntPtrT>
const index,
1331 UpdateInTransition
const& update_in_transition) {
1332 TVARIABLE(IntPtrT, var_index, index);
1333 TVARIABLE(TableType, var_table, table);
1334 Label if_done(
this), if_transition(
this, Label::kDeferred);
1336 LoadObjectField(var_table.value(), TableType::kNextTableOffset)),
1337 &if_done, &if_transition);
1339 BIND(&if_transition);
1341 Label loop(
this, {&var_table, &var_index}), done_loop(
this);
1345 TNode<TableType> table = var_table.value();
1346 TNode<IntPtrT> index = var_index.value();
1348 TNode<Object> next_table =
1349 LoadObjectField(table, TableType::kNextTableOffset);
1350 GotoIf(TaggedIsSmi(next_table), &done_loop);
1352 var_table = CAST(next_table);
1353 var_index = SmiUntag(
1354 CAST(CallBuiltin(Builtins::kOrderedHashTableHealIndex,
1355 NoContextConstant(), table, SmiTag(index))));
1361 update_in_transition(var_table.value(), var_index.value());
1366 return {var_table.value(), var_index.value()};
1369 template <
typename IteratorType,
typename TableType>
1370 std::pair<TNode<TableType>, TNode<IntPtrT>>
1371 CollectionsBuiltinsAssembler::TransitionAndUpdate(
1372 TNode<IteratorType>
const iterator) {
1373 return Transition<TableType>(
1374 CAST(LoadObjectField(iterator, IteratorType::kTableOffset)),
1375 LoadAndUntagObjectField(iterator, IteratorType::kIndexOffset),
1376 [
this, iterator](Node*
const table, Node*
const index) {
1378 StoreObjectField(iterator, IteratorType::kTableOffset, table);
1379 StoreObjectFieldNoWriteBarrier(iterator, IteratorType::kIndexOffset,
1384 template <
typename TableType>
1385 std::tuple<TNode<Object>, TNode<IntPtrT>, TNode<IntPtrT>>
1386 CollectionsBuiltinsAssembler::NextSkipHoles(TNode<TableType> table,
1387 TNode<IntPtrT> index,
1390 TNode<IntPtrT> number_of_buckets =
1391 LoadAndUntagObjectField(table, TableType::kNumberOfBucketsOffset);
1392 TNode<IntPtrT> number_of_elements =
1393 LoadAndUntagObjectField(table, TableType::kNumberOfElementsOffset);
1394 TNode<IntPtrT> number_of_deleted_elements =
1395 LoadAndUntagObjectField(table, TableType::kNumberOfDeletedElementsOffset);
1396 TNode<IntPtrT> used_capacity =
1397 IntPtrAdd(number_of_elements, number_of_deleted_elements);
1399 TNode<Object> entry_key;
1400 TNode<IntPtrT> entry_start_position;
1401 TVARIABLE(IntPtrT, var_index, index);
1402 Label loop(
this, &var_index), done_loop(
this);
1406 GotoIfNot(IntPtrLessThan(var_index.value(), used_capacity), if_end);
1407 entry_start_position = IntPtrAdd(
1408 IntPtrMul(var_index.value(), IntPtrConstant(TableType::kEntrySize)),
1411 LoadFixedArrayElement(table, entry_start_position,
1412 TableType::kHashTableStartIndex * kPointerSize);
1413 Increment(&var_index);
1414 Branch(IsTheHole(entry_key), &loop, &done_loop);
1418 return std::tuple<TNode<Object>, TNode<IntPtrT>, TNode<IntPtrT>>{
1419 entry_key, entry_start_position, var_index.value()};
1422 TF_BUILTIN(MapPrototypeGet, CollectionsBuiltinsAssembler) {
1423 Node*
const receiver = Parameter(Descriptor::kReceiver);
1424 Node*
const key = Parameter(Descriptor::kKey);
1425 Node*
const context = Parameter(Descriptor::kContext);
1427 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
"Map.prototype.get");
1429 Node*
const table = LoadObjectField(receiver, JSMap::kTableOffset);
1430 TNode<Smi> index = CAST(
1431 CallBuiltin(Builtins::kFindOrderedHashMapEntry, context, table, key));
1433 Label if_found(
this), if_not_found(
this);
1434 Branch(SmiGreaterThanOrEqual(index, SmiConstant(0)), &if_found,
1438 Return(LoadFixedArrayElement(
1439 CAST(table), SmiUntag(index),
1440 (OrderedHashMap::kHashTableStartIndex + OrderedHashMap::kValueOffset) *
1443 BIND(&if_not_found);
1444 Return(UndefinedConstant());
1447 TF_BUILTIN(MapPrototypeHas, CollectionsBuiltinsAssembler) {
1448 Node*
const receiver = Parameter(Descriptor::kReceiver);
1449 Node*
const key = Parameter(Descriptor::kKey);
1450 Node*
const context = Parameter(Descriptor::kContext);
1452 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
"Map.prototype.has");
1454 Node*
const table = LoadObjectField(receiver, JSMap::kTableOffset);
1455 TNode<Smi> index = CAST(
1456 CallBuiltin(Builtins::kFindOrderedHashMapEntry, context, table, key));
1458 Label if_found(
this), if_not_found(
this);
1459 Branch(SmiGreaterThanOrEqual(index, SmiConstant(0)), &if_found,
1463 Return(TrueConstant());
1465 BIND(&if_not_found);
1466 Return(FalseConstant());
1469 Node* CollectionsBuiltinsAssembler::NormalizeNumberKey(Node*
const key) {
1470 VARIABLE(result, MachineRepresentation::kTagged, key);
1473 GotoIf(TaggedIsSmi(key), &done);
1474 GotoIfNot(IsHeapNumber(key), &done);
1475 Node*
const number = LoadHeapNumberValue(key);
1476 GotoIfNot(Float64Equal(number, Float64Constant(0.0)), &done);
1479 result.Bind(SmiConstant(0));
1483 return result.value();
1486 TF_BUILTIN(MapPrototypeSet, CollectionsBuiltinsAssembler) {
1487 Node*
const receiver = Parameter(Descriptor::kReceiver);
1488 Node* key = Parameter(Descriptor::kKey);
1489 Node*
const value = Parameter(Descriptor::kValue);
1490 Node*
const context = Parameter(Descriptor::kContext);
1492 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
"Map.prototype.set");
1494 key = NormalizeNumberKey(key);
1496 TNode<OrderedHashMap>
const table =
1497 CAST(LoadObjectField(receiver, JSMap::kTableOffset));
1499 VARIABLE(entry_start_position_or_hash, MachineType::PointerRepresentation(),
1501 Label entry_found(
this), not_found(
this);
1503 TryLookupOrderedHashTableIndex<OrderedHashMap>(table, key, context,
1504 &entry_start_position_or_hash,
1505 &entry_found, ¬_found);
1509 StoreFixedArrayElement(table, entry_start_position_or_hash.value(), value,
1510 UPDATE_WRITE_BARRIER,
1511 kPointerSize * (OrderedHashMap::kHashTableStartIndex +
1512 OrderedHashMap::kValueOffset));
1515 Label no_hash(
this), add_entry(
this), store_new_entry(
this);
1519 GotoIf(IntPtrGreaterThan(entry_start_position_or_hash.value(),
1524 entry_start_position_or_hash.Bind(SmiUntag(CallGetOrCreateHashRaw(key)));
1529 VARIABLE(number_of_buckets, MachineType::PointerRepresentation());
1530 VARIABLE(occupancy, MachineType::PointerRepresentation());
1531 TVARIABLE(OrderedHashMap, table_var, table);
1534 number_of_buckets.Bind(SmiUntag(CAST(
1535 LoadFixedArrayElement(table, OrderedHashMap::kNumberOfBucketsIndex))));
1537 STATIC_ASSERT(OrderedHashMap::kLoadFactor == 2);
1538 Node*
const capacity = WordShl(number_of_buckets.value(), 1);
1539 Node*
const number_of_elements = SmiUntag(
1540 CAST(LoadObjectField(table, OrderedHashMap::kNumberOfElementsOffset)));
1541 Node*
const number_of_deleted = SmiUntag(CAST(LoadObjectField(
1542 table, OrderedHashMap::kNumberOfDeletedElementsOffset)));
1543 occupancy.Bind(IntPtrAdd(number_of_elements, number_of_deleted));
1544 GotoIf(IntPtrLessThan(occupancy.value(), capacity), &store_new_entry);
1548 CallRuntime(Runtime::kMapGrow, context, receiver);
1549 table_var = CAST(LoadObjectField(receiver, JSMap::kTableOffset));
1550 number_of_buckets.Bind(SmiUntag(CAST(LoadFixedArrayElement(
1551 table_var.value(), OrderedHashMap::kNumberOfBucketsIndex))));
1552 Node*
const new_number_of_elements = SmiUntag(CAST(LoadObjectField(
1553 table_var.value(), OrderedHashMap::kNumberOfElementsOffset)));
1554 Node*
const new_number_of_deleted = SmiUntag(CAST(LoadObjectField(
1555 table_var.value(), OrderedHashMap::kNumberOfDeletedElementsOffset)));
1556 occupancy.Bind(IntPtrAdd(new_number_of_elements, new_number_of_deleted));
1557 Goto(&store_new_entry);
1559 BIND(&store_new_entry);
1561 StoreOrderedHashMapNewEntry(table_var.value(), key, value,
1562 entry_start_position_or_hash.value(),
1563 number_of_buckets.value(), occupancy.value());
1567 void CollectionsBuiltinsAssembler::StoreOrderedHashMapNewEntry(
1568 TNode<OrderedHashMap>
const table, Node*
const key, Node*
const value,
1569 Node*
const hash, Node*
const number_of_buckets, Node*
const occupancy) {
1570 Node*
const bucket =
1571 WordAnd(hash, IntPtrSub(number_of_buckets, IntPtrConstant(1)));
1572 Node*
const bucket_entry = LoadFixedArrayElement(
1573 table, bucket, OrderedHashMap::kHashTableStartIndex * kPointerSize);
1576 Node*
const entry_start = IntPtrAdd(
1577 IntPtrMul(occupancy, IntPtrConstant(OrderedHashMap::kEntrySize)),
1579 StoreFixedArrayElement(table, entry_start, key, UPDATE_WRITE_BARRIER,
1580 kPointerSize * OrderedHashMap::kHashTableStartIndex);
1581 StoreFixedArrayElement(table, entry_start, value, UPDATE_WRITE_BARRIER,
1582 kPointerSize * (OrderedHashMap::kHashTableStartIndex +
1583 OrderedHashMap::kValueOffset));
1584 StoreFixedArrayElement(table, entry_start, bucket_entry, SKIP_WRITE_BARRIER,
1585 kPointerSize * (OrderedHashMap::kHashTableStartIndex +
1586 OrderedHashMap::kChainOffset));
1589 StoreFixedArrayElement(table, bucket, SmiTag(occupancy), SKIP_WRITE_BARRIER,
1590 OrderedHashMap::kHashTableStartIndex * kPointerSize);
1593 TNode<Smi>
const number_of_elements =
1594 CAST(LoadObjectField(table, OrderedHashMap::kNumberOfElementsOffset));
1595 StoreObjectFieldNoWriteBarrier(table, OrderedHashMap::kNumberOfElementsOffset,
1596 SmiAdd(number_of_elements, SmiConstant(1)));
1599 TF_BUILTIN(MapPrototypeDelete, CollectionsBuiltinsAssembler) {
1600 Node*
const receiver = Parameter(Descriptor::kReceiver);
1601 Node* key = Parameter(Descriptor::kKey);
1602 Node*
const context = Parameter(Descriptor::kContext);
1604 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
1605 "Map.prototype.delete");
1607 TNode<OrderedHashMap>
const table =
1608 CAST(LoadObjectField(receiver, JSMap::kTableOffset));
1610 VARIABLE(entry_start_position_or_hash, MachineType::PointerRepresentation(),
1612 Label entry_found(
this), not_found(
this);
1614 TryLookupOrderedHashTableIndex<OrderedHashMap>(table, key, context,
1615 &entry_start_position_or_hash,
1616 &entry_found, ¬_found);
1619 Return(FalseConstant());
1623 StoreFixedArrayElement(table, entry_start_position_or_hash.value(),
1624 TheHoleConstant(), UPDATE_WRITE_BARRIER,
1625 kPointerSize * OrderedHashMap::kHashTableStartIndex);
1626 StoreFixedArrayElement(table, entry_start_position_or_hash.value(),
1627 TheHoleConstant(), UPDATE_WRITE_BARRIER,
1628 kPointerSize * (OrderedHashMap::kHashTableStartIndex +
1629 OrderedHashMap::kValueOffset));
1632 TNode<Smi>
const number_of_elements = SmiSub(
1633 CAST(LoadObjectField(table, OrderedHashMap::kNumberOfElementsOffset)),
1635 StoreObjectFieldNoWriteBarrier(table, OrderedHashMap::kNumberOfElementsOffset,
1636 number_of_elements);
1637 TNode<Smi>
const number_of_deleted =
1638 SmiAdd(CAST(LoadObjectField(
1639 table, OrderedHashMap::kNumberOfDeletedElementsOffset)),
1641 StoreObjectFieldNoWriteBarrier(
1642 table, OrderedHashMap::kNumberOfDeletedElementsOffset, number_of_deleted);
1644 TNode<Smi>
const number_of_buckets =
1645 CAST(LoadFixedArrayElement(table, OrderedHashMap::kNumberOfBucketsIndex));
1649 GotoIf(SmiLessThan(SmiAdd(number_of_elements, number_of_elements),
1652 Return(TrueConstant());
1655 CallRuntime(Runtime::kMapShrink, context, receiver);
1656 Return(TrueConstant());
1659 TF_BUILTIN(SetPrototypeAdd, CollectionsBuiltinsAssembler) {
1660 Node*
const receiver = Parameter(Descriptor::kReceiver);
1661 Node* key = Parameter(Descriptor::kKey);
1662 Node*
const context = Parameter(Descriptor::kContext);
1664 ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE,
"Set.prototype.add");
1666 key = NormalizeNumberKey(key);
1668 TNode<OrderedHashSet>
const table =
1669 CAST(LoadObjectField(receiver, JSMap::kTableOffset));
1671 VARIABLE(entry_start_position_or_hash, MachineType::PointerRepresentation(),
1673 Label entry_found(
this), not_found(
this);
1675 TryLookupOrderedHashTableIndex<OrderedHashSet>(table, key, context,
1676 &entry_start_position_or_hash,
1677 &entry_found, ¬_found);
1683 Label no_hash(
this), add_entry(
this), store_new_entry(
this);
1687 GotoIf(IntPtrGreaterThan(entry_start_position_or_hash.value(),
1692 entry_start_position_or_hash.Bind(SmiUntag(CallGetOrCreateHashRaw(key)));
1697 VARIABLE(number_of_buckets, MachineType::PointerRepresentation());
1698 VARIABLE(occupancy, MachineType::PointerRepresentation());
1699 TVARIABLE(OrderedHashSet, table_var, table);
1702 number_of_buckets.Bind(SmiUntag(CAST(
1703 LoadFixedArrayElement(table, OrderedHashSet::kNumberOfBucketsIndex))));
1705 STATIC_ASSERT(OrderedHashSet::kLoadFactor == 2);
1706 Node*
const capacity = WordShl(number_of_buckets.value(), 1);
1707 Node*
const number_of_elements = SmiUntag(
1708 CAST(LoadObjectField(table, OrderedHashSet::kNumberOfElementsOffset)));
1709 Node*
const number_of_deleted = SmiUntag(CAST(LoadObjectField(
1710 table, OrderedHashSet::kNumberOfDeletedElementsOffset)));
1711 occupancy.Bind(IntPtrAdd(number_of_elements, number_of_deleted));
1712 GotoIf(IntPtrLessThan(occupancy.value(), capacity), &store_new_entry);
1716 CallRuntime(Runtime::kSetGrow, context, receiver);
1717 table_var = CAST(LoadObjectField(receiver, JSMap::kTableOffset));
1718 number_of_buckets.Bind(SmiUntag(CAST(LoadFixedArrayElement(
1719 table_var.value(), OrderedHashSet::kNumberOfBucketsIndex))));
1720 Node*
const new_number_of_elements = SmiUntag(CAST(LoadObjectField(
1721 table_var.value(), OrderedHashSet::kNumberOfElementsOffset)));
1722 Node*
const new_number_of_deleted = SmiUntag(CAST(LoadObjectField(
1723 table_var.value(), OrderedHashSet::kNumberOfDeletedElementsOffset)));
1724 occupancy.Bind(IntPtrAdd(new_number_of_elements, new_number_of_deleted));
1725 Goto(&store_new_entry);
1727 BIND(&store_new_entry);
1729 StoreOrderedHashSetNewEntry(table_var.value(), key,
1730 entry_start_position_or_hash.value(),
1731 number_of_buckets.value(), occupancy.value());
1735 void CollectionsBuiltinsAssembler::StoreOrderedHashSetNewEntry(
1736 TNode<OrderedHashSet>
const table, Node*
const key, Node*
const hash,
1737 Node*
const number_of_buckets, Node*
const occupancy) {
1738 Node*
const bucket =
1739 WordAnd(hash, IntPtrSub(number_of_buckets, IntPtrConstant(1)));
1740 Node*
const bucket_entry = LoadFixedArrayElement(
1741 table, bucket, OrderedHashSet::kHashTableStartIndex * kPointerSize);
1744 Node*
const entry_start = IntPtrAdd(
1745 IntPtrMul(occupancy, IntPtrConstant(OrderedHashSet::kEntrySize)),
1747 StoreFixedArrayElement(table, entry_start, key, UPDATE_WRITE_BARRIER,
1748 kPointerSize * OrderedHashSet::kHashTableStartIndex);
1749 StoreFixedArrayElement(table, entry_start, bucket_entry, SKIP_WRITE_BARRIER,
1750 kPointerSize * (OrderedHashSet::kHashTableStartIndex +
1751 OrderedHashSet::kChainOffset));
1754 StoreFixedArrayElement(table, bucket, SmiTag(occupancy), SKIP_WRITE_BARRIER,
1755 OrderedHashSet::kHashTableStartIndex * kPointerSize);
1758 TNode<Smi>
const number_of_elements =
1759 CAST(LoadObjectField(table, OrderedHashSet::kNumberOfElementsOffset));
1760 StoreObjectFieldNoWriteBarrier(table, OrderedHashSet::kNumberOfElementsOffset,
1761 SmiAdd(number_of_elements, SmiConstant(1)));
1764 TF_BUILTIN(SetPrototypeDelete, CollectionsBuiltinsAssembler) {
1765 Node*
const receiver = Parameter(Descriptor::kReceiver);
1766 Node* key = Parameter(Descriptor::kKey);
1767 Node*
const context = Parameter(Descriptor::kContext);
1769 ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE,
1770 "Set.prototype.delete");
1772 TNode<OrderedHashSet>
const table =
1773 CAST(LoadObjectField(receiver, JSMap::kTableOffset));
1775 VARIABLE(entry_start_position_or_hash, MachineType::PointerRepresentation(),
1777 Label entry_found(
this), not_found(
this);
1779 TryLookupOrderedHashTableIndex<OrderedHashSet>(table, key, context,
1780 &entry_start_position_or_hash,
1781 &entry_found, ¬_found);
1784 Return(FalseConstant());
1788 StoreFixedArrayElement(table, entry_start_position_or_hash.value(),
1789 TheHoleConstant(), UPDATE_WRITE_BARRIER,
1790 kPointerSize * OrderedHashSet::kHashTableStartIndex);
1793 TNode<Smi>
const number_of_elements = SmiSub(
1794 CAST(LoadObjectField(table, OrderedHashSet::kNumberOfElementsOffset)),
1796 StoreObjectFieldNoWriteBarrier(table, OrderedHashSet::kNumberOfElementsOffset,
1797 number_of_elements);
1798 TNode<Smi>
const number_of_deleted =
1799 SmiAdd(CAST(LoadObjectField(
1800 table, OrderedHashSet::kNumberOfDeletedElementsOffset)),
1802 StoreObjectFieldNoWriteBarrier(
1803 table, OrderedHashSet::kNumberOfDeletedElementsOffset, number_of_deleted);
1805 TNode<Smi>
const number_of_buckets =
1806 CAST(LoadFixedArrayElement(table, OrderedHashSet::kNumberOfBucketsIndex));
1810 GotoIf(SmiLessThan(SmiAdd(number_of_elements, number_of_elements),
1813 Return(TrueConstant());
1816 CallRuntime(Runtime::kSetShrink, context, receiver);
1817 Return(TrueConstant());
1820 TF_BUILTIN(MapPrototypeEntries, CollectionsBuiltinsAssembler) {
1821 Node*
const receiver = Parameter(Descriptor::kReceiver);
1822 Node*
const context = Parameter(Descriptor::kContext);
1823 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
1824 "Map.prototype.entries");
1825 Return(AllocateJSCollectionIterator<JSMapIterator>(
1826 context, Context::MAP_KEY_VALUE_ITERATOR_MAP_INDEX, receiver));
1829 TF_BUILTIN(MapPrototypeGetSize, CollectionsBuiltinsAssembler) {
1830 Node*
const receiver = Parameter(Descriptor::kReceiver);
1831 Node*
const context = Parameter(Descriptor::kContext);
1832 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
1833 "get Map.prototype.size");
1834 Node*
const table = LoadObjectField(receiver, JSMap::kTableOffset);
1835 Return(LoadObjectField(table, OrderedHashMap::kNumberOfElementsOffset));
1838 TF_BUILTIN(MapPrototypeForEach, CollectionsBuiltinsAssembler) {
1839 const char*
const kMethodName =
"Map.prototype.forEach";
1840 Node*
const argc = Parameter(Descriptor::kJSActualArgumentsCount);
1841 Node*
const context = Parameter(Descriptor::kContext);
1842 CodeStubArguments args(
this, ChangeInt32ToIntPtr(argc));
1843 Node*
const receiver = args.GetReceiver();
1844 Node*
const callback = args.GetOptionalArgumentValue(0);
1845 Node*
const this_arg = args.GetOptionalArgumentValue(1);
1847 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, kMethodName);
1850 Label callback_not_callable(
this, Label::kDeferred);
1851 GotoIf(TaggedIsSmi(callback), &callback_not_callable);
1852 GotoIfNot(IsCallable(callback), &callback_not_callable);
1854 TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
1855 TVARIABLE(OrderedHashMap, var_table,
1856 CAST(LoadObjectField(receiver, JSMap::kTableOffset)));
1857 Label loop(
this, {&var_index, &var_table}), done_loop(
this);
1863 TNode<IntPtrT> index = var_index.value();
1864 TNode<OrderedHashMap> table = var_table.value();
1865 std::tie(table, index) =
1866 Transition<OrderedHashMap>(table, index, [](Node*, Node*) {});
1869 TNode<Object> entry_key;
1870 TNode<IntPtrT> entry_start_position;
1871 std::tie(entry_key, entry_start_position, index) =
1872 NextSkipHoles<OrderedHashMap>(table, index, &done_loop);
1875 Node* entry_value = LoadFixedArrayElement(
1876 table, entry_start_position,
1877 (OrderedHashMap::kHashTableStartIndex + OrderedHashMap::kValueOffset) *
1882 CallJS(CodeFactory::Call(isolate()), context, callback, this_arg,
1883 entry_value, entry_key, receiver);
1892 args.PopAndReturn(UndefinedConstant());
1894 BIND(&callback_not_callable);
1896 CallRuntime(Runtime::kThrowCalledNonCallable, context, callback);
1901 TF_BUILTIN(MapPrototypeKeys, CollectionsBuiltinsAssembler) {
1902 Node*
const receiver = Parameter(Descriptor::kReceiver);
1903 Node*
const context = Parameter(Descriptor::kContext);
1904 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
"Map.prototype.keys");
1905 Return(AllocateJSCollectionIterator<JSMapIterator>(
1906 context, Context::MAP_KEY_ITERATOR_MAP_INDEX, receiver));
1909 TF_BUILTIN(MapPrototypeValues, CollectionsBuiltinsAssembler) {
1910 Node*
const receiver = Parameter(Descriptor::kReceiver);
1911 Node*
const context = Parameter(Descriptor::kContext);
1912 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
1913 "Map.prototype.values");
1914 Return(AllocateJSCollectionIterator<JSMapIterator>(
1915 context, Context::MAP_VALUE_ITERATOR_MAP_INDEX, receiver));
1918 TF_BUILTIN(MapIteratorPrototypeNext, CollectionsBuiltinsAssembler) {
1919 const char*
const kMethodName =
"Map Iterator.prototype.next";
1920 Node*
const receiver = Parameter(Descriptor::kReceiver);
1921 Node*
const context = Parameter(Descriptor::kContext);
1924 Label if_receiver_valid(
this), if_receiver_invalid(
this, Label::kDeferred);
1925 GotoIf(TaggedIsSmi(receiver), &if_receiver_invalid);
1926 Node*
const receiver_instance_type = LoadInstanceType(receiver);
1928 InstanceTypeEqual(receiver_instance_type, JS_MAP_KEY_VALUE_ITERATOR_TYPE),
1929 &if_receiver_valid);
1930 GotoIf(InstanceTypeEqual(receiver_instance_type, JS_MAP_KEY_ITERATOR_TYPE),
1931 &if_receiver_valid);
1932 Branch(InstanceTypeEqual(receiver_instance_type, JS_MAP_VALUE_ITERATOR_TYPE),
1933 &if_receiver_valid, &if_receiver_invalid);
1934 BIND(&if_receiver_invalid);
1935 ThrowTypeError(context, MessageTemplate::kIncompatibleMethodReceiver,
1936 StringConstant(kMethodName), receiver);
1937 BIND(&if_receiver_valid);
1940 VARIABLE(var_done, MachineRepresentation::kTagged, TrueConstant());
1941 VARIABLE(var_value, MachineRepresentation::kTagged, UndefinedConstant());
1942 Label return_value(
this, {&var_done, &var_value}), return_entry(
this),
1943 return_end(
this, Label::kDeferred);
1946 TNode<OrderedHashMap> table;
1947 TNode<IntPtrT> index;
1948 std::tie(table, index) =
1949 TransitionAndUpdate<JSMapIterator, OrderedHashMap>(CAST(receiver));
1952 TNode<Object> entry_key;
1953 TNode<IntPtrT> entry_start_position;
1954 std::tie(entry_key, entry_start_position, index) =
1955 NextSkipHoles<OrderedHashMap>(table, index, &return_end);
1956 StoreObjectFieldNoWriteBarrier(receiver, JSMapIterator::kIndexOffset,
1958 var_value.Bind(entry_key);
1959 var_done.Bind(FalseConstant());
1962 GotoIf(InstanceTypeEqual(receiver_instance_type, JS_MAP_KEY_ITERATOR_TYPE),
1964 var_value.Bind(LoadFixedArrayElement(
1965 table, entry_start_position,
1966 (OrderedHashMap::kHashTableStartIndex + OrderedHashMap::kValueOffset) *
1968 Branch(InstanceTypeEqual(receiver_instance_type, JS_MAP_VALUE_ITERATOR_TYPE),
1969 &return_value, &return_entry);
1971 BIND(&return_entry);
1974 AllocateJSIteratorResultForEntry(context, entry_key, var_value.value());
1978 BIND(&return_value);
1981 AllocateJSIteratorResult(context, var_value.value(), var_done.value());
1987 StoreObjectFieldRoot(receiver, JSMapIterator::kTableOffset,
1988 RootIndex::kEmptyOrderedHashMap);
1989 Goto(&return_value);
1993 TF_BUILTIN(SetPrototypeHas, CollectionsBuiltinsAssembler) {
1994 Node*
const receiver = Parameter(Descriptor::kReceiver);
1995 Node*
const key = Parameter(Descriptor::kKey);
1996 Node*
const context = Parameter(Descriptor::kContext);
1998 ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE,
"Set.prototype.has");
2000 Node*
const table = LoadObjectField(receiver, JSMap::kTableOffset);
2002 VARIABLE(entry_start_position, MachineType::PointerRepresentation(),
2004 VARIABLE(result, MachineRepresentation::kTaggedSigned, IntPtrConstant(0));
2005 Label if_key_smi(
this), if_key_string(
this), if_key_heap_number(
this),
2006 if_key_bigint(
this), entry_found(
this), not_found(
this), done(
this);
2008 GotoIf(TaggedIsSmi(key), &if_key_smi);
2010 Node* key_map = LoadMap(key);
2011 Node* key_instance_type = LoadMapInstanceType(key_map);
2013 GotoIf(IsStringInstanceType(key_instance_type), &if_key_string);
2014 GotoIf(IsHeapNumberMap(key_map), &if_key_heap_number);
2015 GotoIf(IsBigIntInstanceType(key_instance_type), &if_key_bigint);
2017 FindOrderedHashTableEntryForOtherKey<OrderedHashSet>(
2018 context, table, key, &entry_start_position, &entry_found, ¬_found);
2022 FindOrderedHashTableEntryForSmiKey<OrderedHashSet>(
2023 table, key, &entry_start_position, &entry_found, ¬_found);
2026 BIND(&if_key_string);
2028 FindOrderedHashTableEntryForStringKey<OrderedHashSet>(
2029 context, table, key, &entry_start_position, &entry_found, ¬_found);
2032 BIND(&if_key_heap_number);
2034 FindOrderedHashTableEntryForHeapNumberKey<OrderedHashSet>(
2035 context, table, key, &entry_start_position, &entry_found, ¬_found);
2038 BIND(&if_key_bigint);
2040 FindOrderedHashTableEntryForBigIntKey<OrderedHashSet>(
2041 context, table, key, &entry_start_position, &entry_found, ¬_found);
2045 Return(TrueConstant());
2048 Return(FalseConstant());
2051 TF_BUILTIN(SetPrototypeEntries, CollectionsBuiltinsAssembler) {
2052 Node*
const receiver = Parameter(Descriptor::kReceiver);
2053 Node*
const context = Parameter(Descriptor::kContext);
2054 ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE,
2055 "Set.prototype.entries");
2056 Return(AllocateJSCollectionIterator<JSSetIterator>(
2057 context, Context::SET_KEY_VALUE_ITERATOR_MAP_INDEX, receiver));
2060 TF_BUILTIN(SetPrototypeGetSize, CollectionsBuiltinsAssembler) {
2061 Node*
const receiver = Parameter(Descriptor::kReceiver);
2062 Node*
const context = Parameter(Descriptor::kContext);
2063 ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE,
2064 "get Set.prototype.size");
2065 Node*
const table = LoadObjectField(receiver, JSSet::kTableOffset);
2066 Return(LoadObjectField(table, OrderedHashSet::kNumberOfElementsOffset));
2069 TF_BUILTIN(SetPrototypeForEach, CollectionsBuiltinsAssembler) {
2070 const char*
const kMethodName =
"Set.prototype.forEach";
2071 Node*
const argc = Parameter(Descriptor::kJSActualArgumentsCount);
2072 Node*
const context = Parameter(Descriptor::kContext);
2073 CodeStubArguments args(
this, ChangeInt32ToIntPtr(argc));
2074 Node*
const receiver = args.GetReceiver();
2075 Node*
const callback = args.GetOptionalArgumentValue(0);
2076 Node*
const this_arg = args.GetOptionalArgumentValue(1);
2078 ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE, kMethodName);
2081 Label callback_not_callable(
this, Label::kDeferred);
2082 GotoIf(TaggedIsSmi(callback), &callback_not_callable);
2083 GotoIfNot(IsCallable(callback), &callback_not_callable);
2085 TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
2086 TVARIABLE(OrderedHashSet, var_table,
2087 CAST(LoadObjectField(receiver, JSSet::kTableOffset)));
2088 Label loop(
this, {&var_index, &var_table}), done_loop(
this);
2094 TNode<IntPtrT> index = var_index.value();
2095 TNode<OrderedHashSet> table = var_table.value();
2096 std::tie(table, index) =
2097 Transition<OrderedHashSet>(table, index, [](Node*, Node*) {});
2101 Node* entry_start_position;
2102 std::tie(entry_key, entry_start_position, index) =
2103 NextSkipHoles<OrderedHashSet>(table, index, &done_loop);
2106 CallJS(CodeFactory::Call(isolate()), context, callback, this_arg, entry_key,
2107 entry_key, receiver);
2116 args.PopAndReturn(UndefinedConstant());
2118 BIND(&callback_not_callable);
2120 CallRuntime(Runtime::kThrowCalledNonCallable, context, callback);
2125 TF_BUILTIN(SetPrototypeValues, CollectionsBuiltinsAssembler) {
2126 Node*
const receiver = Parameter(Descriptor::kReceiver);
2127 Node*
const context = Parameter(Descriptor::kContext);
2128 ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE,
2129 "Set.prototype.values");
2130 Return(AllocateJSCollectionIterator<JSSetIterator>(
2131 context, Context::SET_VALUE_ITERATOR_MAP_INDEX, receiver));
2134 TF_BUILTIN(SetIteratorPrototypeNext, CollectionsBuiltinsAssembler) {
2135 const char*
const kMethodName =
"Set Iterator.prototype.next";
2136 Node*
const receiver = Parameter(Descriptor::kReceiver);
2137 Node*
const context = Parameter(Descriptor::kContext);
2140 Label if_receiver_valid(
this), if_receiver_invalid(
this, Label::kDeferred);
2141 GotoIf(TaggedIsSmi(receiver), &if_receiver_invalid);
2142 Node*
const receiver_instance_type = LoadInstanceType(receiver);
2143 GotoIf(InstanceTypeEqual(receiver_instance_type, JS_SET_VALUE_ITERATOR_TYPE),
2144 &if_receiver_valid);
2146 InstanceTypeEqual(receiver_instance_type, JS_SET_KEY_VALUE_ITERATOR_TYPE),
2147 &if_receiver_valid, &if_receiver_invalid);
2148 BIND(&if_receiver_invalid);
2149 ThrowTypeError(context, MessageTemplate::kIncompatibleMethodReceiver,
2150 StringConstant(kMethodName), receiver);
2151 BIND(&if_receiver_valid);
2154 VARIABLE(var_done, MachineRepresentation::kTagged, TrueConstant());
2155 VARIABLE(var_value, MachineRepresentation::kTagged, UndefinedConstant());
2156 Label return_value(
this, {&var_done, &var_value}), return_entry(
this),
2157 return_end(
this, Label::kDeferred);
2160 TNode<OrderedHashSet> table;
2161 TNode<IntPtrT> index;
2162 std::tie(table, index) =
2163 TransitionAndUpdate<JSSetIterator, OrderedHashSet>(CAST(receiver));
2167 Node* entry_start_position;
2168 std::tie(entry_key, entry_start_position, index) =
2169 NextSkipHoles<OrderedHashSet>(table, index, &return_end);
2170 StoreObjectFieldNoWriteBarrier(receiver, JSSetIterator::kIndexOffset,
2172 var_value.Bind(entry_key);
2173 var_done.Bind(FalseConstant());
2176 Branch(InstanceTypeEqual(receiver_instance_type, JS_SET_VALUE_ITERATOR_TYPE),
2177 &return_value, &return_entry);
2179 BIND(&return_entry);
2181 Node* result = AllocateJSIteratorResultForEntry(context, var_value.value(),
2186 BIND(&return_value);
2189 AllocateJSIteratorResult(context, var_value.value(), var_done.value());
2195 StoreObjectFieldRoot(receiver, JSSetIterator::kTableOffset,
2196 RootIndex::kEmptyOrderedHashSet);
2197 Goto(&return_value);
2201 template <
typename CollectionType>
2202 void CollectionsBuiltinsAssembler::TryLookupOrderedHashTableIndex(
2203 Node*
const table, Node*
const key, Node*
const context, Variable* result,
2204 Label* if_entry_found, Label* if_not_found) {
2205 Label if_key_smi(
this), if_key_string(
this), if_key_heap_number(
this),
2206 if_key_bigint(
this);
2208 GotoIf(TaggedIsSmi(key), &if_key_smi);
2210 Node* key_map = LoadMap(key);
2211 Node* key_instance_type = LoadMapInstanceType(key_map);
2213 GotoIf(IsStringInstanceType(key_instance_type), &if_key_string);
2214 GotoIf(IsHeapNumberMap(key_map), &if_key_heap_number);
2215 GotoIf(IsBigIntInstanceType(key_instance_type), &if_key_bigint);
2217 FindOrderedHashTableEntryForOtherKey<CollectionType>(
2218 context, table, key, result, if_entry_found, if_not_found);
2222 FindOrderedHashTableEntryForSmiKey<CollectionType>(
2223 table, key, result, if_entry_found, if_not_found);
2226 BIND(&if_key_string);
2228 FindOrderedHashTableEntryForStringKey<CollectionType>(
2229 context, table, key, result, if_entry_found, if_not_found);
2232 BIND(&if_key_heap_number);
2234 FindOrderedHashTableEntryForHeapNumberKey<CollectionType>(
2235 context, table, key, result, if_entry_found, if_not_found);
2238 BIND(&if_key_bigint);
2240 FindOrderedHashTableEntryForBigIntKey<CollectionType>(
2241 context, table, key, result, if_entry_found, if_not_found);
2245 TF_BUILTIN(FindOrderedHashMapEntry, CollectionsBuiltinsAssembler) {
2246 Node*
const table = Parameter(Descriptor::kTable);
2247 Node*
const key = Parameter(Descriptor::kKey);
2248 Node*
const context = Parameter(Descriptor::kContext);
2250 VARIABLE(entry_start_position, MachineType::PointerRepresentation(),
2252 Label entry_found(
this), not_found(
this);
2254 TryLookupOrderedHashTableIndex<OrderedHashMap>(
2255 table, key, context, &entry_start_position, &entry_found, ¬_found);
2258 Return(SmiTag(entry_start_position.value()));
2261 Return(SmiConstant(-1));
2284 typedef std::function<void(TNode<Object> entry_key,
Label* if_same)>
2288 const KeyComparator& key_compare);
2302 Label* if_not_found);
2325 void WeakCollectionsBuiltinsAssembler::AddEntry(
2330 StoreFixedArrayElement(table, key_index, key);
2331 StoreFixedArrayElement(table, value_index, value);
2334 StoreFixedArrayElement(table, EphemeronHashTable::kNumberOfElementsIndex,
2335 SmiFromIntPtr(number_of_elements), SKIP_WRITE_BARRIER);
2338 TNode<Object> WeakCollectionsBuiltinsAssembler::AllocateTable(
2339 Variant variant, TNode<Context> context,
2340 TNode<IntPtrT> at_least_space_for) {
2343 IntPtrLessThanOrEqual(IntPtrConstant(0), at_least_space_for));
2344 TNode<IntPtrT> capacity = HashTableComputeCapacity(at_least_space_for);
2347 TNode<IntPtrT> length = KeyIndexFromEntry(capacity);
2348 TNode<FixedArray> table = CAST(
2349 AllocateFixedArray(HOLEY_ELEMENTS, length, kAllowLargeObjectAllocation));
2351 RootIndex map_root_index = EphemeronHashTableShape::GetMapRootIndex();
2352 StoreMapNoWriteBarrier(table, map_root_index);
2353 StoreFixedArrayElement(table, EphemeronHashTable::kNumberOfElementsIndex,
2354 SmiConstant(0), SKIP_WRITE_BARRIER);
2355 StoreFixedArrayElement(table,
2356 EphemeronHashTable::kNumberOfDeletedElementsIndex,
2357 SmiConstant(0), SKIP_WRITE_BARRIER);
2358 StoreFixedArrayElement(table, EphemeronHashTable::kCapacityIndex,
2359 SmiFromIntPtr(capacity), SKIP_WRITE_BARRIER);
2361 TNode<IntPtrT> start = KeyIndexFromEntry(IntPtrConstant(0));
2362 FillFixedArrayWithValue(HOLEY_ELEMENTS, table, start, length,
2363 RootIndex::kUndefinedValue);
2367 TNode<Smi> WeakCollectionsBuiltinsAssembler::CreateIdentityHash(
2368 TNode<Object> key) {
2369 TNode<ExternalReference> function_addr =
2370 ExternalConstant(ExternalReference::jsreceiver_create_identity_hash());
2371 TNode<ExternalReference> isolate_ptr =
2372 ExternalConstant(ExternalReference::isolate_address(isolate()));
2374 MachineType type_ptr = MachineType::Pointer();
2375 MachineType type_tagged = MachineType::AnyTagged();
2377 return CAST(CallCFunction2(type_tagged, type_ptr, type_tagged, function_addr,
2381 TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::EntryMask(
2382 TNode<IntPtrT> capacity) {
2383 return IntPtrSub(capacity, IntPtrConstant(1));
2386 TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::FindKeyIndex(
2387 TNode<HeapObject> table, TNode<IntPtrT> key_hash, TNode<IntPtrT> entry_mask,
2388 const KeyComparator& key_compare) {
2390 TVARIABLE(IntPtrT, var_entry, WordAnd(key_hash, entry_mask));
2391 TVARIABLE(IntPtrT, var_count, IntPtrConstant(0));
2393 Variable* loop_vars[] = {&var_count, &var_entry};
2394 Label loop(
this, arraysize(loop_vars), loop_vars), if_found(
this);
2397 TNode<IntPtrT> key_index;
2399 key_index = KeyIndexFromEntry(var_entry.value());
2400 TNode<Object> entry_key = LoadFixedArrayElement(CAST(table), key_index);
2402 key_compare(entry_key, &if_found);
2405 Increment(&var_count);
2407 WordAnd(IntPtrAdd(var_entry.value(), var_count.value()), entry_mask);
2415 TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::FindKeyIndexForInsertion(
2416 TNode<HeapObject> table, TNode<IntPtrT> key_hash,
2417 TNode<IntPtrT> entry_mask) {
2419 auto is_not_live = [&](TNode<Object> entry_key, Label* if_found) {
2421 GotoIf(Word32Or(IsTheHole(entry_key), IsUndefined(entry_key)), if_found);
2423 return FindKeyIndex(table, key_hash, entry_mask, is_not_live);
2426 TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::FindKeyIndexForKey(
2427 TNode<HeapObject> table, TNode<Object> key, TNode<IntPtrT> hash,
2428 TNode<IntPtrT> entry_mask, Label* if_not_found) {
2430 auto match_key_or_exit_on_empty = [&](TNode<Object> entry_key,
2432 GotoIf(IsUndefined(entry_key), if_not_found);
2433 GotoIf(WordEqual(entry_key, key), if_same);
2435 return FindKeyIndex(table, hash, entry_mask, match_key_or_exit_on_empty);
2438 TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::KeyIndexFromEntry(
2439 TNode<IntPtrT> entry) {
2443 IntPtrMul(entry, IntPtrConstant(EphemeronHashTable::kEntrySize)),
2444 IntPtrConstant(EphemeronHashTable::kElementsStartIndex +
2445 EphemeronHashTable::kEntryKeyIndex));
2448 TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::LoadNumberOfElements(
2449 TNode<EphemeronHashTable> table,
int offset) {
2450 TNode<IntPtrT> number_of_elements = SmiUntag(CAST(LoadFixedArrayElement(
2451 table, EphemeronHashTable::kNumberOfElementsIndex)));
2452 return IntPtrAdd(number_of_elements, IntPtrConstant(offset));
2455 TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::LoadNumberOfDeleted(
2456 TNode<EphemeronHashTable> table,
int offset) {
2457 TNode<IntPtrT> number_of_deleted = SmiUntag(CAST(LoadFixedArrayElement(
2458 table, EphemeronHashTable::kNumberOfDeletedElementsIndex)));
2459 return IntPtrAdd(number_of_deleted, IntPtrConstant(offset));
2462 TNode<EphemeronHashTable> WeakCollectionsBuiltinsAssembler::LoadTable(
2463 TNode<JSWeakCollection> collection) {
2464 return CAST(LoadObjectField(collection, JSWeakCollection::kTableOffset));
2467 TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::LoadTableCapacity(
2468 TNode<EphemeronHashTable> table) {
2470 CAST(LoadFixedArrayElement(table, EphemeronHashTable::kCapacityIndex)));
2473 TNode<Word32T> WeakCollectionsBuiltinsAssembler::InsufficientCapacityToAdd(
2474 TNode<IntPtrT> capacity, TNode<IntPtrT> number_of_elements,
2475 TNode<IntPtrT> number_of_deleted) {
2480 TNode<IntPtrT> available = IntPtrSub(capacity, number_of_elements);
2481 TNode<IntPtrT> half_available = WordShr(available, 1);
2482 TNode<IntPtrT> needed_available = WordShr(number_of_elements, 1);
2485 IntPtrGreaterThan(number_of_deleted, half_available),
2487 IntPtrGreaterThan(IntPtrAdd(number_of_elements, needed_available),
2491 void WeakCollectionsBuiltinsAssembler::RemoveEntry(
2492 TNode<EphemeronHashTable> table, TNode<IntPtrT> key_index,
2493 TNode<IntPtrT> number_of_elements) {
2495 TNode<IntPtrT> value_index = ValueIndexFromKeyIndex(key_index);
2496 StoreFixedArrayElement(table, key_index, TheHoleConstant());
2497 StoreFixedArrayElement(table, value_index, TheHoleConstant());
2500 TNode<IntPtrT> number_of_deleted = LoadNumberOfDeleted(table, 1);
2501 StoreFixedArrayElement(table, EphemeronHashTable::kNumberOfElementsIndex,
2502 SmiFromIntPtr(number_of_elements), SKIP_WRITE_BARRIER);
2503 StoreFixedArrayElement(table,
2504 EphemeronHashTable::kNumberOfDeletedElementsIndex,
2505 SmiFromIntPtr(number_of_deleted), SKIP_WRITE_BARRIER);
2508 TNode<BoolT> WeakCollectionsBuiltinsAssembler::ShouldRehash(
2509 TNode<IntPtrT> number_of_elements, TNode<IntPtrT> number_of_deleted) {
2511 return IntPtrGreaterThanOrEqual(WordShl(number_of_deleted, 1),
2512 number_of_elements);
2515 TNode<Word32T> WeakCollectionsBuiltinsAssembler::ShouldShrink(
2516 TNode<IntPtrT> capacity, TNode<IntPtrT> number_of_elements) {
2518 TNode<IntPtrT> quarter_capacity = WordShr(capacity, 2);
2522 IntPtrLessThanOrEqual(number_of_elements, quarter_capacity),
2528 IntPtrGreaterThanOrEqual(number_of_elements, IntPtrConstant(16)));
2531 TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::ValueIndexFromKeyIndex(
2532 TNode<IntPtrT> key_index) {
2533 return IntPtrAdd(key_index,
2534 IntPtrConstant(EphemeronHashTableShape::kEntryValueIndex -
2535 EphemeronHashTable::kEntryKeyIndex));
2538 TF_BUILTIN(WeakMapConstructor, WeakCollectionsBuiltinsAssembler) {
2539 TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
2540 TNode<IntPtrT> argc =
2541 ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2542 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2544 GenerateConstructor(kWeakMap, isolate()->factory()->WeakMap_string(),
2545 new_target, argc, context);
2548 TF_BUILTIN(WeakSetConstructor, WeakCollectionsBuiltinsAssembler) {
2549 TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
2550 TNode<IntPtrT> argc =
2551 ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2552 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2554 GenerateConstructor(kWeakSet, isolate()->factory()->WeakSet_string(),
2555 new_target, argc, context);
2558 TF_BUILTIN(WeakMapLookupHashIndex, WeakCollectionsBuiltinsAssembler) {
2559 TNode<EphemeronHashTable> table = CAST(Parameter(Descriptor::kTable));
2560 TNode<Object> key = CAST(Parameter(Descriptor::kKey));
2562 Label if_not_found(
this);
2564 GotoIfNotJSReceiver(key, &if_not_found);
2566 TNode<IntPtrT> hash = LoadJSReceiverIdentityHash(key, &if_not_found);
2567 TNode<IntPtrT> capacity = LoadTableCapacity(table);
2568 TNode<IntPtrT> key_index =
2569 FindKeyIndexForKey(table, key, hash, EntryMask(capacity), &if_not_found);
2570 Return(SmiTag(ValueIndexFromKeyIndex(key_index)));
2572 BIND(&if_not_found);
2573 Return(SmiConstant(-1));
2576 TF_BUILTIN(WeakMapGet, WeakCollectionsBuiltinsAssembler) {
2577 Node*
const receiver = Parameter(Descriptor::kReceiver);
2578 Node*
const key = Parameter(Descriptor::kKey);
2579 Node*
const context = Parameter(Descriptor::kContext);
2581 Label return_undefined(
this);
2583 ThrowIfNotInstanceType(context, receiver, JS_WEAK_MAP_TYPE,
2584 "WeakMap.prototype.get");
2586 TNode<EphemeronHashTable>
const table = LoadTable(CAST(receiver));
2587 TNode<Smi>
const index =
2588 CAST(CallBuiltin(Builtins::kWeakMapLookupHashIndex, context, table, key));
2590 GotoIf(WordEqual(index, SmiConstant(-1)), &return_undefined);
2592 Return(LoadFixedArrayElement(table, SmiUntag(index)));
2594 BIND(&return_undefined);
2595 Return(UndefinedConstant());
2598 TF_BUILTIN(WeakMapHas, WeakCollectionsBuiltinsAssembler) {
2599 Node*
const receiver = Parameter(Descriptor::kReceiver);
2600 Node*
const key = Parameter(Descriptor::kKey);
2601 Node*
const context = Parameter(Descriptor::kContext);
2603 Label return_false(
this);
2605 ThrowIfNotInstanceType(context, receiver, JS_WEAK_MAP_TYPE,
2606 "WeakMap.prototype.has");
2608 TNode<EphemeronHashTable>
const table = LoadTable(CAST(receiver));
2610 CallBuiltin(Builtins::kWeakMapLookupHashIndex, context, table, key);
2612 GotoIf(WordEqual(index, SmiConstant(-1)), &return_false);
2614 Return(TrueConstant());
2616 BIND(&return_false);
2617 Return(FalseConstant());
2622 TF_BUILTIN(WeakCollectionDelete, WeakCollectionsBuiltinsAssembler) {
2623 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2624 TNode<JSWeakCollection> collection = CAST(Parameter(Descriptor::kCollection));
2625 TNode<Object> key = CAST(Parameter(Descriptor::kKey));
2627 Label call_runtime(
this), if_not_found(
this);
2629 GotoIfNotJSReceiver(key, &if_not_found);
2631 TNode<IntPtrT> hash = LoadJSReceiverIdentityHash(key, &if_not_found);
2632 TNode<EphemeronHashTable> table = LoadTable(collection);
2633 TNode<IntPtrT> capacity = LoadTableCapacity(table);
2634 TNode<IntPtrT> key_index =
2635 FindKeyIndexForKey(table, key, hash, EntryMask(capacity), &if_not_found);
2636 TNode<IntPtrT> number_of_elements = LoadNumberOfElements(table, -1);
2637 GotoIf(ShouldShrink(capacity, number_of_elements), &call_runtime);
2639 RemoveEntry(table, key_index, number_of_elements);
2640 Return(TrueConstant());
2642 BIND(&if_not_found);
2643 Return(FalseConstant());
2645 BIND(&call_runtime);
2646 Return(CallRuntime(Runtime::kWeakCollectionDelete, context, collection, key,
2652 TF_BUILTIN(WeakCollectionSet, WeakCollectionsBuiltinsAssembler) {
2653 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2654 TNode<JSWeakCollection> collection = CAST(Parameter(Descriptor::kCollection));
2655 TNode<JSReceiver> key = CAST(Parameter(Descriptor::kKey));
2656 TNode<Object> value = CAST(Parameter(Descriptor::kValue));
2658 CSA_ASSERT(
this, IsJSReceiver(key));
2660 Label call_runtime(
this), if_no_hash(
this), if_not_found(
this);
2662 TNode<EphemeronHashTable> table = LoadTable(collection);
2663 TNode<IntPtrT> capacity = LoadTableCapacity(table);
2664 TNode<IntPtrT> entry_mask = EntryMask(capacity);
2666 TVARIABLE(IntPtrT, var_hash, LoadJSReceiverIdentityHash(key, &if_no_hash));
2667 TNode<IntPtrT> key_index = FindKeyIndexForKey(table, key, var_hash.value(),
2668 entry_mask, &if_not_found);
2670 StoreFixedArrayElement(table, ValueIndexFromKeyIndex(key_index), value);
2675 var_hash = SmiUntag(CreateIdentityHash(key));
2676 Goto(&if_not_found);
2678 BIND(&if_not_found);
2680 TNode<IntPtrT> number_of_deleted = LoadNumberOfDeleted(table);
2681 TNode<IntPtrT> number_of_elements = LoadNumberOfElements(table, 1);
2684 GotoIf(Word32Or(ShouldRehash(number_of_elements, number_of_deleted),
2685 InsufficientCapacityToAdd(capacity, number_of_elements,
2686 number_of_deleted)),
2689 TNode<IntPtrT> insertion_key_index =
2690 FindKeyIndexForInsertion(table, var_hash.value(), entry_mask);
2691 AddEntry(table, insertion_key_index, key, value, number_of_elements);
2694 BIND(&call_runtime);
2696 CallRuntime(Runtime::kWeakCollectionSet, context, collection, key, value,
2697 SmiTag(var_hash.value()));
2702 TF_BUILTIN(WeakMapPrototypeDelete, CodeStubAssembler) {
2703 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2704 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2705 TNode<Object> key = CAST(Parameter(Descriptor::kKey));
2707 ThrowIfNotInstanceType(context, receiver, JS_WEAK_MAP_TYPE,
2708 "WeakMap.prototype.delete");
2710 Return(CallBuiltin(Builtins::kWeakCollectionDelete, context, receiver, key));
2713 TF_BUILTIN(WeakMapPrototypeSet, WeakCollectionsBuiltinsAssembler) {
2714 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2715 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2716 TNode<Object> key = CAST(Parameter(Descriptor::kKey));
2717 TNode<Object> value = CAST(Parameter(Descriptor::kValue));
2719 ThrowIfNotInstanceType(context, receiver, JS_WEAK_MAP_TYPE,
2720 "WeakMap.prototype.set");
2722 Label throw_invalid_key(
this);
2723 GotoIfNotJSReceiver(key, &throw_invalid_key);
2726 CallBuiltin(Builtins::kWeakCollectionSet, context, receiver, key, value));
2728 BIND(&throw_invalid_key);
2729 ThrowTypeError(context, MessageTemplate::kInvalidWeakMapKey, key);
2732 TF_BUILTIN(WeakSetPrototypeAdd, WeakCollectionsBuiltinsAssembler) {
2733 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2734 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2735 TNode<Object> value = CAST(Parameter(Descriptor::kValue));
2737 ThrowIfNotInstanceType(context, receiver, JS_WEAK_SET_TYPE,
2738 "WeakSet.prototype.add");
2740 Label throw_invalid_value(
this);
2741 GotoIfNotJSReceiver(value, &throw_invalid_value);
2743 Return(CallBuiltin(Builtins::kWeakCollectionSet, context, receiver, value,
2746 BIND(&throw_invalid_value);
2747 ThrowTypeError(context, MessageTemplate::kInvalidWeakSetValue, value);
2750 TF_BUILTIN(WeakSetPrototypeDelete, CodeStubAssembler) {
2751 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2752 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2753 TNode<Object> value = CAST(Parameter(Descriptor::kValue));
2755 ThrowIfNotInstanceType(context, receiver, JS_WEAK_SET_TYPE,
2756 "WeakSet.prototype.delete");
2759 CallBuiltin(Builtins::kWeakCollectionDelete, context, receiver, value));
2762 TF_BUILTIN(WeakSetHas, WeakCollectionsBuiltinsAssembler) {
2763 Node*
const receiver = Parameter(Descriptor::kReceiver);
2764 Node*
const key = Parameter(Descriptor::kKey);
2765 Node*
const context = Parameter(Descriptor::kContext);
2767 Label return_false(
this);
2769 ThrowIfNotInstanceType(context, receiver, JS_WEAK_SET_TYPE,
2770 "WeakSet.prototype.has");
2772 Node*
const table = LoadTable(CAST(receiver));
2774 CallBuiltin(Builtins::kWeakMapLookupHashIndex, context, table, key);
2776 GotoIf(WordEqual(index, SmiConstant(-1)), &return_false);
2778 Return(TrueConstant());
2780 BIND(&return_false);
2781 Return(FalseConstant());