LCOV - code coverage report
Current view: top level - src/builtins - builtins-collections-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1422 1427 99.6 %
Date: 2019-03-21 Functions: 288 326 88.3 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/builtins/builtins-collections-gen.h"
       6             : 
       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/heap/heap-inl.h"
      13             : #include "src/objects/hash-table-inl.h"
      14             : #include "src/objects/js-collection.h"
      15             : #include "torque-generated/builtins-base-from-dsl-gen.h"
      16             : #include "torque-generated/builtins-collections-from-dsl-gen.h"
      17             : 
      18             : namespace v8 {
      19             : namespace internal {
      20             : 
      21             : using compiler::Node;
      22             : template <class T>
      23             : using TNode = compiler::TNode<T>;
      24             : template <class T>
      25             : using TVariable = compiler::TypedCodeAssemblerVariable<T>;
      26             : 
      27             : class BaseCollectionsAssembler : public CodeStubAssembler,
      28             :                                  public CollectionsBuiltinsFromDSLAssembler {
      29             :  public:
      30        2128 :   explicit BaseCollectionsAssembler(compiler::CodeAssemblerState* state)
      31        2128 :       : CodeStubAssembler(state), CollectionsBuiltinsFromDSLAssembler(state) {}
      32             : 
      33        2128 :   virtual ~BaseCollectionsAssembler() = default;
      34             : 
      35             :  protected:
      36             :   enum Variant { kMap, kSet, kWeakMap, kWeakSet };
      37             : 
      38             :   // Adds an entry to a collection.  For Maps, properly handles extracting the
      39             :   // key and value from the entry (see LoadKeyValue()).
      40             :   void AddConstructorEntry(Variant variant, TNode<Context> context,
      41             :                            TNode<Object> collection, TNode<Object> add_function,
      42             :                            TNode<Object> key_value,
      43             :                            Label* if_may_have_side_effects = nullptr,
      44             :                            Label* if_exception = nullptr,
      45             :                            TVariable<Object>* var_exception = nullptr);
      46             : 
      47             :   // Adds constructor entries to a collection.  Choosing a fast path when
      48             :   // possible.
      49             :   void AddConstructorEntries(Variant variant, TNode<Context> context,
      50             :                              TNode<Context> native_context,
      51             :                              TNode<Object> collection,
      52             :                              TNode<Object> initial_entries);
      53             : 
      54             :   // Fast path for adding constructor entries.  Assumes the entries are a fast
      55             :   // JS array (see CodeStubAssembler::BranchIfFastJSArray()).
      56             :   void AddConstructorEntriesFromFastJSArray(Variant variant,
      57             :                                             TNode<Context> context,
      58             :                                             TNode<Context> native_context,
      59             :                                             TNode<Object> collection,
      60             :                                             TNode<JSArray> fast_jsarray,
      61             :                                             Label* if_may_have_side_effects);
      62             : 
      63             :   // Adds constructor entries to a collection using the iterator protocol.
      64             :   void AddConstructorEntriesFromIterable(Variant variant,
      65             :                                          TNode<Context> context,
      66             :                                          TNode<Context> native_context,
      67             :                                          TNode<Object> collection,
      68             :                                          TNode<Object> iterable);
      69             : 
      70             :   // Constructs a collection instance. Choosing a fast path when possible.
      71             :   TNode<Object> AllocateJSCollection(TNode<Context> context,
      72             :                                      TNode<JSFunction> constructor,
      73             :                                      TNode<Object> new_target);
      74             : 
      75             :   // Fast path for constructing a collection instance if the constructor
      76             :   // function has not been modified.
      77             :   TNode<Object> AllocateJSCollectionFast(TNode<HeapObject> constructor);
      78             : 
      79             :   // Fallback for constructing a collection instance if the constructor function
      80             :   // has been modified.
      81             :   TNode<Object> AllocateJSCollectionSlow(TNode<Context> context,
      82             :                                          TNode<JSFunction> constructor,
      83             :                                          TNode<Object> new_target);
      84             : 
      85             :   // Allocates the backing store for a collection.
      86             :   virtual TNode<Object> AllocateTable(Variant variant, TNode<Context> context,
      87             :                                       TNode<IntPtrT> at_least_space_for) = 0;
      88             : 
      89             :   // Main entry point for a collection constructor builtin.
      90             :   void GenerateConstructor(Variant variant,
      91             :                            Handle<String> constructor_function_name,
      92             :                            TNode<Object> new_target, TNode<IntPtrT> argc,
      93             :                            TNode<Context> context);
      94             : 
      95             :   // Retrieves the collection function that adds an entry. `set` for Maps and
      96             :   // `add` for Sets.
      97             :   TNode<Object> GetAddFunction(Variant variant, TNode<Context> context,
      98             :                                TNode<Object> collection);
      99             : 
     100             :   // Retrieves the collection constructor function.
     101             :   TNode<JSFunction> GetConstructor(Variant variant,
     102             :                                    TNode<Context> native_context);
     103             : 
     104             :   // Retrieves the initial collection function that adds an entry. Should only
     105             :   // be called when it is certain that a collection prototype's map hasn't been
     106             :   // changed.
     107             :   TNode<JSFunction> GetInitialAddFunction(Variant variant,
     108             :                                           TNode<Context> native_context);
     109             : 
     110             :   // Checks whether {collection}'s initial add/set function has been modified
     111             :   // (depending on {variant}, loaded from {native_context}).
     112             :   void GotoIfInitialAddFunctionModified(Variant variant,
     113             :                                         TNode<Context> native_context,
     114             :                                         TNode<Object> collection,
     115             :                                         Label* if_modified);
     116             : 
     117             :   // Gets root index for the name of the add/set function.
     118             :   RootIndex GetAddFunctionNameIndex(Variant variant);
     119             : 
     120             :   // Retrieves the offset to access the backing table from the collection.
     121             :   int GetTableOffset(Variant variant);
     122             : 
     123             :   // Estimates the number of entries the collection will have after adding the
     124             :   // entries passed in the constructor. AllocateTable() can use this to avoid
     125             :   // the time of growing/rehashing when adding the constructor entries.
     126             :   TNode<IntPtrT> EstimatedInitialSize(TNode<Object> initial_entries,
     127             :                                       TNode<BoolT> is_fast_jsarray);
     128             : 
     129             :   void GotoIfNotJSReceiver(Node* const obj, Label* if_not_receiver);
     130             : 
     131             :   // Determines whether the collection's prototype has been modified.
     132             :   TNode<BoolT> HasInitialCollectionPrototype(Variant variant,
     133             :                                              TNode<Context> native_context,
     134             :                                              TNode<Object> collection);
     135             : 
     136             :   // Gets the initial prototype map for given collection {variant}.
     137             :   TNode<Map> GetInitialCollectionPrototype(Variant variant,
     138             :                                            TNode<Context> native_context);
     139             : 
     140             :   // Loads an element from a fixed array.  If the element is the hole, returns
     141             :   // `undefined`.
     142             :   TNode<Object> LoadAndNormalizeFixedArrayElement(TNode<FixedArray> elements,
     143             :                                                   TNode<IntPtrT> index);
     144             : 
     145             :   // Loads an element from a fixed double array.  If the element is the hole,
     146             :   // returns `undefined`.
     147             :   TNode<Object> LoadAndNormalizeFixedDoubleArrayElement(
     148             :       TNode<HeapObject> elements, TNode<IntPtrT> index);
     149             : };
     150             : 
     151         560 : void BaseCollectionsAssembler::AddConstructorEntry(
     152             :     Variant variant, TNode<Context> context, TNode<Object> collection,
     153             :     TNode<Object> add_function, TNode<Object> key_value,
     154             :     Label* if_may_have_side_effects, Label* if_exception,
     155             :     TVariable<Object>* var_exception) {
     156             :   compiler::CodeAssemblerScopedExceptionHandler handler(this, if_exception,
     157        1120 :                                                         var_exception);
     158             :   CSA_ASSERT(this, Word32BinaryNot(IsTheHole(key_value)));
     159         560 :   if (variant == kMap || variant == kWeakMap) {
     160             :     BaseBuiltinsFromDSLAssembler::KeyValuePair pair =
     161             :         if_may_have_side_effects != nullptr
     162             :             ? LoadKeyValuePairNoSideEffects(context, key_value,
     163         112 :                                             if_may_have_side_effects)
     164         336 :             : LoadKeyValuePair(context, key_value);
     165         224 :     Node* key_n = pair.key;
     166         224 :     Node* value_n = pair.value;
     167         448 :     CallJS(CodeFactory::Call(isolate()), context, add_function, collection,
     168         448 :            key_n, value_n);
     169             :   } else {
     170             :     DCHECK(variant == kSet || variant == kWeakSet);
     171         672 :     CallJS(CodeFactory::Call(isolate()), context, add_function, collection,
     172         336 :            key_value);
     173             :   }
     174         560 : }
     175             : 
     176         224 : void BaseCollectionsAssembler::AddConstructorEntries(
     177             :     Variant variant, TNode<Context> context, TNode<Context> native_context,
     178             :     TNode<Object> collection, TNode<Object> initial_entries) {
     179         448 :   TVARIABLE(BoolT, use_fast_loop,
     180             :             IsFastJSArrayWithNoCustomIteration(context, initial_entries));
     181             :   TNode<IntPtrT> at_least_space_for =
     182         224 :       EstimatedInitialSize(initial_entries, use_fast_loop.value());
     183         448 :   Label allocate_table(this, &use_fast_loop), exit(this), fast_loop(this),
     184         448 :       slow_loop(this, Label::kDeferred);
     185         224 :   Goto(&allocate_table);
     186         224 :   BIND(&allocate_table);
     187             :   {
     188         224 :     TNode<Object> table = AllocateTable(variant, context, at_least_space_for);
     189         224 :     StoreObjectField(collection, GetTableOffset(variant), table);
     190         224 :     GotoIf(IsNullOrUndefined(initial_entries), &exit);
     191             :     GotoIfInitialAddFunctionModified(variant, native_context, collection,
     192         224 :                                      &slow_loop);
     193         224 :     Branch(use_fast_loop.value(), &fast_loop, &slow_loop);
     194             :   }
     195         224 :   BIND(&fast_loop);
     196             :   {
     197             :     TNode<JSArray> initial_entries_jsarray =
     198         224 :         UncheckedCast<JSArray>(initial_entries);
     199             : #if DEBUG
     200             :     CSA_ASSERT(this, IsFastJSArrayWithNoCustomIteration(
     201             :                          context, initial_entries_jsarray));
     202             :     TNode<Map> original_initial_entries_map = LoadMap(initial_entries_jsarray);
     203             : #endif
     204             : 
     205         448 :     Label if_may_have_side_effects(this, Label::kDeferred);
     206             :     AddConstructorEntriesFromFastJSArray(variant, context, native_context,
     207             :                                          collection, initial_entries_jsarray,
     208         224 :                                          &if_may_have_side_effects);
     209         224 :     Goto(&exit);
     210             : 
     211         224 :     if (variant == kMap || variant == kWeakMap) {
     212         112 :       BIND(&if_may_have_side_effects);
     213             : #if DEBUG
     214             :       {
     215             :         // Check that add/set function has not been modified.
     216             :         Label if_not_modified(this), if_modified(this);
     217             :         GotoIfInitialAddFunctionModified(variant, native_context, collection,
     218             :                                          &if_modified);
     219             :         Goto(&if_not_modified);
     220             :         BIND(&if_modified);
     221             :         Unreachable();
     222             :         BIND(&if_not_modified);
     223             :       }
     224             :       CSA_ASSERT(this, WordEqual(original_initial_entries_map,
     225             :                                  LoadMap(initial_entries_jsarray)));
     226             : #endif
     227         112 :       use_fast_loop = Int32FalseConstant();
     228         112 :       Goto(&allocate_table);
     229             :     }
     230             :   }
     231         224 :   BIND(&slow_loop);
     232             :   {
     233             :     AddConstructorEntriesFromIterable(variant, context, native_context,
     234         224 :                                       collection, initial_entries);
     235         224 :     Goto(&exit);
     236             :   }
     237         224 :   BIND(&exit);
     238         224 : }
     239             : 
     240         224 : void BaseCollectionsAssembler::AddConstructorEntriesFromFastJSArray(
     241             :     Variant variant, TNode<Context> context, TNode<Context> native_context,
     242             :     TNode<Object> collection, TNode<JSArray> fast_jsarray,
     243             :     Label* if_may_have_side_effects) {
     244         224 :   TNode<FixedArrayBase> elements = LoadElements(fast_jsarray);
     245         224 :   TNode<Int32T> elements_kind = LoadElementsKind(fast_jsarray);
     246         224 :   TNode<JSFunction> add_func = GetInitialAddFunction(variant, native_context);
     247             :   CSA_ASSERT(
     248             :       this,
     249             :       WordEqual(GetAddFunction(variant, native_context, collection), add_func));
     250             :   CSA_ASSERT(this, IsFastJSArrayWithNoCustomIteration(context, fast_jsarray));
     251         224 :   TNode<IntPtrT> length = SmiUntag(LoadFastJSArrayLength(fast_jsarray));
     252             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(length, IntPtrConstant(0)));
     253             :   CSA_ASSERT(
     254             :       this, HasInitialCollectionPrototype(variant, native_context, collection));
     255             : 
     256             : #if DEBUG
     257             :   TNode<Map> original_collection_map = LoadMap(CAST(collection));
     258             :   TNode<Map> original_fast_js_array_map = LoadMap(fast_jsarray);
     259             : #endif
     260         448 :   Label exit(this), if_doubles(this), if_smiorobjects(this);
     261         224 :   GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &exit);
     262         448 :   Branch(IsFastSmiOrTaggedElementsKind(elements_kind), &if_smiorobjects,
     263         224 :          &if_doubles);
     264         224 :   BIND(&if_smiorobjects);
     265             :   {
     266         224 :     auto set_entry = [&](Node* index) {
     267             :       TNode<Object> element = LoadAndNormalizeFixedArrayElement(
     268         448 :           CAST(elements), UncheckedCast<IntPtrT>(index));
     269         448 :       AddConstructorEntry(variant, context, collection, add_func, element,
     270         448 :                           if_may_have_side_effects);
     271         448 :     };
     272             : 
     273             :     // Instead of using the slower iteration protocol to iterate over the
     274             :     // elements, a fast loop is used.  This assumes that adding an element
     275             :     // to the collection does not call user code that could mutate the elements
     276             :     // or collection.
     277         448 :     BuildFastLoop(IntPtrConstant(0), length, set_entry, 1,
     278         224 :                   ParameterMode::INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
     279         224 :     Goto(&exit);
     280             :   }
     281         224 :   BIND(&if_doubles);
     282             :   {
     283             :     // A Map constructor requires entries to be arrays (ex. [key, value]),
     284             :     // so a FixedDoubleArray can never succeed.
     285         224 :     if (variant == kMap || variant == kWeakMap) {
     286             :       CSA_ASSERT(this, IntPtrGreaterThan(length, IntPtrConstant(0)));
     287             :       TNode<Object> element =
     288         112 :           LoadAndNormalizeFixedDoubleArrayElement(elements, IntPtrConstant(0));
     289         112 :       ThrowTypeError(context, MessageTemplate::kIteratorValueNotAnObject,
     290         112 :                      element);
     291             :     } else {
     292             :       DCHECK(variant == kSet || variant == kWeakSet);
     293         112 :       auto set_entry = [&](Node* index) {
     294             :         TNode<Object> entry = LoadAndNormalizeFixedDoubleArrayElement(
     295         224 :             elements, UncheckedCast<IntPtrT>(index));
     296         224 :         AddConstructorEntry(variant, context, collection, add_func, entry);
     297         224 :       };
     298         224 :       BuildFastLoop(IntPtrConstant(0), length, set_entry, 1,
     299         112 :                     ParameterMode::INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
     300         112 :       Goto(&exit);
     301             :     }
     302             :   }
     303         224 :   BIND(&exit);
     304             : #if DEBUG
     305             :   CSA_ASSERT(this,
     306             :              WordEqual(original_collection_map, LoadMap(CAST(collection))));
     307             :   CSA_ASSERT(this,
     308             :              WordEqual(original_fast_js_array_map, LoadMap(fast_jsarray)));
     309             : #endif
     310         224 : }
     311             : 
     312         224 : void BaseCollectionsAssembler::AddConstructorEntriesFromIterable(
     313             :     Variant variant, TNode<Context> context, TNode<Context> native_context,
     314             :     TNode<Object> collection, TNode<Object> iterable) {
     315         448 :   Label exit(this), loop(this), if_exception(this, Label::kDeferred);
     316             :   CSA_ASSERT(this, Word32BinaryNot(IsNullOrUndefined(iterable)));
     317             : 
     318         224 :   TNode<Object> add_func = GetAddFunction(variant, context, collection);
     319         448 :   IteratorBuiltinsAssembler iterator_assembler(this->state());
     320             :   IteratorBuiltinsAssembler::IteratorRecord iterator =
     321         224 :       iterator_assembler.GetIterator(context, iterable);
     322             : 
     323             :   CSA_ASSERT(this, Word32BinaryNot(IsUndefined(iterator.object)));
     324             : 
     325             :   TNode<Object> fast_iterator_result_map =
     326         224 :       LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
     327         448 :   TVARIABLE(Object, var_exception);
     328             : 
     329         224 :   Goto(&loop);
     330         224 :   BIND(&loop);
     331             :   {
     332             :     TNode<Object> next = iterator_assembler.IteratorStep(
     333         224 :         context, iterator, &exit, fast_iterator_result_map);
     334         224 :     TNode<Object> next_value = CAST(iterator_assembler.IteratorValue(
     335             :         context, next, fast_iterator_result_map));
     336             :     AddConstructorEntry(variant, context, collection, add_func, next_value,
     337         224 :                         nullptr, &if_exception, &var_exception);
     338         224 :     Goto(&loop);
     339             :   }
     340         224 :   BIND(&if_exception);
     341             :   {
     342         224 :     iterator_assembler.IteratorCloseOnException(context, iterator,
     343         224 :                                                 var_exception.value());
     344             :   }
     345         224 :   BIND(&exit);
     346         224 : }
     347             : 
     348         224 : RootIndex BaseCollectionsAssembler::GetAddFunctionNameIndex(Variant variant) {
     349         224 :   switch (variant) {
     350             :     case kMap:
     351             :     case kWeakMap:
     352         112 :       return RootIndex::kset_string;
     353             :     case kSet:
     354             :     case kWeakSet:
     355         112 :       return RootIndex::kadd_string;
     356             :   }
     357           0 :   UNREACHABLE();
     358             : }
     359             : 
     360         224 : void BaseCollectionsAssembler::GotoIfInitialAddFunctionModified(
     361             :     Variant variant, TNode<Context> native_context, TNode<Object> collection,
     362             :     Label* if_modified) {
     363             :   STATIC_ASSERT(JSCollection::kAddFunctionDescriptorIndex ==
     364             :                 JSWeakCollection::kAddFunctionDescriptorIndex);
     365         448 :   GotoIfInitialPrototypePropertyModified(
     366         448 :       LoadMap(CAST(collection)),
     367             :       GetInitialCollectionPrototype(variant, native_context),
     368             :       JSCollection::kAddFunctionDescriptorIndex,
     369         224 :       GetAddFunctionNameIndex(variant), if_modified);
     370         224 : }
     371             : 
     372         224 : TNode<Object> BaseCollectionsAssembler::AllocateJSCollection(
     373             :     TNode<Context> context, TNode<JSFunction> constructor,
     374             :     TNode<Object> new_target) {
     375         224 :   TNode<BoolT> is_target_unmodified = WordEqual(constructor, new_target);
     376             : 
     377             :   return Select<Object>(is_target_unmodified,
     378         224 :                         [=] { return AllocateJSCollectionFast(constructor); },
     379         224 :                         [=] {
     380             :                           return AllocateJSCollectionSlow(context, constructor,
     381         224 :                                                           new_target);
     382         448 :                         });
     383             : }
     384             : 
     385         224 : TNode<Object> BaseCollectionsAssembler::AllocateJSCollectionFast(
     386             :     TNode<HeapObject> constructor) {
     387             :   CSA_ASSERT(this, IsConstructorMap(LoadMap(constructor)));
     388             :   TNode<Object> initial_map =
     389         224 :       LoadObjectField(constructor, JSFunction::kPrototypeOrInitialMapOffset);
     390         224 :   return CAST(AllocateJSObjectFromMap(initial_map));
     391             : }
     392             : 
     393         224 : TNode<Object> BaseCollectionsAssembler::AllocateJSCollectionSlow(
     394             :     TNode<Context> context, TNode<JSFunction> constructor,
     395             :     TNode<Object> new_target) {
     396         448 :   ConstructorBuiltinsAssembler constructor_assembler(this->state());
     397         448 :   return CAST(constructor_assembler.EmitFastNewObject(context, constructor,
     398             :                                                       new_target));
     399             : }
     400             : 
     401         224 : void BaseCollectionsAssembler::GenerateConstructor(
     402             :     Variant variant, Handle<String> constructor_function_name,
     403             :     TNode<Object> new_target, TNode<IntPtrT> argc, TNode<Context> context) {
     404         224 :   const int kIterableArg = 0;
     405         224 :   CodeStubArguments args(this, argc);
     406         224 :   TNode<Object> iterable = args.GetOptionalArgumentValue(kIterableArg);
     407             : 
     408         448 :   Label if_undefined(this, Label::kDeferred);
     409         224 :   GotoIf(IsUndefined(new_target), &if_undefined);
     410             : 
     411         224 :   TNode<Context> native_context = LoadNativeContext(context);
     412             :   TNode<Object> collection = AllocateJSCollection(
     413         224 :       context, GetConstructor(variant, native_context), new_target);
     414             : 
     415         224 :   AddConstructorEntries(variant, context, native_context, collection, iterable);
     416         224 :   Return(collection);
     417             : 
     418         224 :   BIND(&if_undefined);
     419         224 :   ThrowTypeError(context, MessageTemplate::kConstructorNotFunction,
     420         448 :                  HeapConstant(constructor_function_name));
     421         224 : }
     422             : 
     423         224 : TNode<Object> BaseCollectionsAssembler::GetAddFunction(
     424             :     Variant variant, TNode<Context> context, TNode<Object> collection) {
     425         168 :   Handle<String> add_func_name = (variant == kMap || variant == kWeakMap)
     426         112 :                                      ? isolate()->factory()->set_string()
     427         336 :                                      : isolate()->factory()->add_string();
     428         224 :   TNode<Object> add_func = GetProperty(context, collection, add_func_name);
     429             : 
     430         448 :   Label exit(this), if_notcallable(this, Label::kDeferred);
     431         224 :   GotoIf(TaggedIsSmi(add_func), &if_notcallable);
     432         224 :   GotoIfNot(IsCallable(CAST(add_func)), &if_notcallable);
     433         224 :   Goto(&exit);
     434             : 
     435         224 :   BIND(&if_notcallable);
     436         448 :   ThrowTypeError(context, MessageTemplate::kPropertyNotFunction, add_func,
     437         448 :                  HeapConstant(add_func_name), collection);
     438             : 
     439         224 :   BIND(&exit);
     440         448 :   return add_func;
     441             : }
     442             : 
     443         224 : TNode<JSFunction> BaseCollectionsAssembler::GetConstructor(
     444             :     Variant variant, TNode<Context> native_context) {
     445             :   int index;
     446         224 :   switch (variant) {
     447             :     case kMap:
     448          56 :       index = Context::JS_MAP_FUN_INDEX;
     449          56 :       break;
     450             :     case kSet:
     451          56 :       index = Context::JS_SET_FUN_INDEX;
     452          56 :       break;
     453             :     case kWeakMap:
     454          56 :       index = Context::JS_WEAK_MAP_FUN_INDEX;
     455          56 :       break;
     456             :     case kWeakSet:
     457          56 :       index = Context::JS_WEAK_SET_FUN_INDEX;
     458          56 :       break;
     459             :   }
     460         224 :   return CAST(LoadContextElement(native_context, index));
     461             : }
     462             : 
     463         224 : TNode<JSFunction> BaseCollectionsAssembler::GetInitialAddFunction(
     464             :     Variant variant, TNode<Context> native_context) {
     465             :   int index;
     466         224 :   switch (variant) {
     467             :     case kMap:
     468          56 :       index = Context::MAP_SET_INDEX;
     469          56 :       break;
     470             :     case kSet:
     471          56 :       index = Context::SET_ADD_INDEX;
     472          56 :       break;
     473             :     case kWeakMap:
     474          56 :       index = Context::WEAKMAP_SET_INDEX;
     475          56 :       break;
     476             :     case kWeakSet:
     477          56 :       index = Context::WEAKSET_ADD_INDEX;
     478          56 :       break;
     479             :   }
     480         224 :   return CAST(LoadContextElement(native_context, index));
     481             : }
     482             : 
     483         224 : int BaseCollectionsAssembler::GetTableOffset(Variant variant) {
     484         224 :   switch (variant) {
     485             :     case kMap:
     486          56 :       return JSMap::kTableOffset;
     487             :     case kSet:
     488          56 :       return JSSet::kTableOffset;
     489             :     case kWeakMap:
     490          56 :       return JSWeakMap::kTableOffset;
     491             :     case kWeakSet:
     492          56 :       return JSWeakSet::kTableOffset;
     493             :   }
     494           0 :   UNREACHABLE();
     495             : }
     496             : 
     497         224 : TNode<IntPtrT> BaseCollectionsAssembler::EstimatedInitialSize(
     498             :     TNode<Object> initial_entries, TNode<BoolT> is_fast_jsarray) {
     499             :   return Select<IntPtrT>(
     500             :       is_fast_jsarray,
     501         224 :       [=] { return SmiUntag(LoadFastJSArrayLength(CAST(initial_entries))); },
     502         448 :       [=] { return IntPtrConstant(0); });
     503             : }
     504             : 
     505         224 : void BaseCollectionsAssembler::GotoIfNotJSReceiver(Node* const obj,
     506             :                                                    Label* if_not_receiver) {
     507         224 :   GotoIf(TaggedIsSmi(obj), if_not_receiver);
     508         224 :   GotoIfNot(IsJSReceiver(obj), if_not_receiver);
     509         224 : }
     510             : 
     511         224 : TNode<Map> BaseCollectionsAssembler::GetInitialCollectionPrototype(
     512             :     Variant variant, TNode<Context> native_context) {
     513             :   int initial_prototype_index;
     514         224 :   switch (variant) {
     515             :     case kMap:
     516          56 :       initial_prototype_index = Context::INITIAL_MAP_PROTOTYPE_MAP_INDEX;
     517          56 :       break;
     518             :     case kSet:
     519          56 :       initial_prototype_index = Context::INITIAL_SET_PROTOTYPE_MAP_INDEX;
     520          56 :       break;
     521             :     case kWeakMap:
     522          56 :       initial_prototype_index = Context::INITIAL_WEAKMAP_PROTOTYPE_MAP_INDEX;
     523          56 :       break;
     524             :     case kWeakSet:
     525          56 :       initial_prototype_index = Context::INITIAL_WEAKSET_PROTOTYPE_MAP_INDEX;
     526          56 :       break;
     527             :   }
     528         224 :   return CAST(LoadContextElement(native_context, initial_prototype_index));
     529             : }
     530             : 
     531           0 : TNode<BoolT> BaseCollectionsAssembler::HasInitialCollectionPrototype(
     532             :     Variant variant, TNode<Context> native_context, TNode<Object> collection) {
     533             :   TNode<Map> collection_proto_map =
     534           0 :       LoadMap(LoadMapPrototype(LoadMap(CAST(collection))));
     535             : 
     536             :   return WordEqual(collection_proto_map,
     537           0 :                    GetInitialCollectionPrototype(variant, native_context));
     538             : }
     539             : 
     540         224 : TNode<Object> BaseCollectionsAssembler::LoadAndNormalizeFixedArrayElement(
     541             :     TNode<FixedArray> elements, TNode<IntPtrT> index) {
     542         224 :   TNode<Object> element = UnsafeLoadFixedArrayElement(elements, index);
     543         672 :   return Select<Object>(IsTheHole(element), [=] { return UndefinedConstant(); },
     544         896 :                         [=] { return element; });
     545             : }
     546             : 
     547         224 : TNode<Object> BaseCollectionsAssembler::LoadAndNormalizeFixedDoubleArrayElement(
     548             :     TNode<HeapObject> elements, TNode<IntPtrT> index) {
     549         448 :   TVARIABLE(Object, entry);
     550         448 :   Label if_hole(this, Label::kDeferred), next(this);
     551             :   TNode<Float64T> element =
     552         448 :       LoadFixedDoubleArrayElement(CAST(elements), index, MachineType::Float64(),
     553         448 :                                   0, INTPTR_PARAMETERS, &if_hole);
     554             :   {  // not hole
     555         224 :     entry = AllocateHeapNumberWithValue(element);
     556         224 :     Goto(&next);
     557             :   }
     558         224 :   BIND(&if_hole);
     559             :   {
     560         224 :     entry = UndefinedConstant();
     561         224 :     Goto(&next);
     562             :   }
     563         224 :   BIND(&next);
     564         448 :   return entry.value();
     565             : }
     566             : 
     567        1568 : class CollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
     568             :  public:
     569        1568 :   explicit CollectionsBuiltinsAssembler(compiler::CodeAssemblerState* state)
     570        1568 :       : BaseCollectionsAssembler(state) {}
     571             : 
     572             :   // Check whether |iterable| is a JS_MAP_KEY_ITERATOR_TYPE or
     573             :   // JS_MAP_VALUE_ITERATOR_TYPE object that is not partially consumed and still
     574             :   // has original iteration behavior.
     575             :   void BranchIfIterableWithOriginalKeyOrValueMapIterator(TNode<Object> iterable,
     576             :                                                          TNode<Context> context,
     577             :                                                          Label* if_true,
     578             :                                                          Label* if_false);
     579             : 
     580             :   // Check whether |iterable| is a JS_SET_TYPE or JS_SET_VALUE_ITERATOR_TYPE
     581             :   // object that still has original iteration behavior. In case of the iterator,
     582             :   // the iterator also must not have been partially consumed.
     583             :   void BranchIfIterableWithOriginalValueSetIterator(TNode<Object> iterable,
     584             :                                                     TNode<Context> context,
     585             :                                                     Label* if_true,
     586             :                                                     Label* if_false);
     587             : 
     588             :  protected:
     589             :   template <typename IteratorType>
     590             :   Node* AllocateJSCollectionIterator(Node* context, int map_index,
     591             :                                      Node* collection);
     592             :   TNode<Object> AllocateTable(Variant variant, TNode<Context> context,
     593             :                               TNode<IntPtrT> at_least_space_for) override;
     594             :   Node* GetHash(Node* const key);
     595             :   Node* CallGetHashRaw(Node* const key);
     596             :   Node* CallGetOrCreateHashRaw(Node* const key);
     597             : 
     598             :   // Transitions the iterator to the non obsolete backing store.
     599             :   // This is a NOP if the [table] is not obsolete.
     600             :   typedef std::function<void(Node* const table, Node* const index)>
     601             :       UpdateInTransition;
     602             :   template <typename TableType>
     603             :   std::pair<TNode<TableType>, TNode<IntPtrT>> Transition(
     604             :       TNode<TableType> const table, TNode<IntPtrT> const index,
     605             :       UpdateInTransition const& update_in_transition);
     606             :   template <typename IteratorType, typename TableType>
     607             :   std::pair<TNode<TableType>, TNode<IntPtrT>> TransitionAndUpdate(
     608             :       TNode<IteratorType> const iterator);
     609             :   template <typename TableType>
     610             :   std::tuple<TNode<Object>, TNode<IntPtrT>, TNode<IntPtrT>> NextSkipHoles(
     611             :       TNode<TableType> table, TNode<IntPtrT> index, Label* if_end);
     612             : 
     613             :   // Specialization for Smi.
     614             :   // The {result} variable will contain the entry index if the key was found,
     615             :   // or the hash code otherwise.
     616             :   template <typename CollectionType>
     617             :   void FindOrderedHashTableEntryForSmiKey(Node* table, Node* key_tagged,
     618             :                                           Variable* result, Label* entry_found,
     619             :                                           Label* not_found);
     620             :   void SameValueZeroSmi(Node* key_smi, Node* candidate_key, Label* if_same,
     621             :                         Label* if_not_same);
     622             : 
     623             :   // Specialization for heap numbers.
     624             :   // The {result} variable will contain the entry index if the key was found,
     625             :   // or the hash code otherwise.
     626             :   void SameValueZeroHeapNumber(Node* key_string, Node* candidate_key,
     627             :                                Label* if_same, Label* if_not_same);
     628             :   template <typename CollectionType>
     629             :   void FindOrderedHashTableEntryForHeapNumberKey(Node* context, Node* table,
     630             :                                                  Node* key_heap_number,
     631             :                                                  Variable* result,
     632             :                                                  Label* entry_found,
     633             :                                                  Label* not_found);
     634             : 
     635             :   // Specialization for bigints.
     636             :   // The {result} variable will contain the entry index if the key was found,
     637             :   // or the hash code otherwise.
     638             :   void SameValueZeroBigInt(Node* key, Node* candidate_key, Label* if_same,
     639             :                            Label* if_not_same);
     640             :   template <typename CollectionType>
     641             :   void FindOrderedHashTableEntryForBigIntKey(Node* context, Node* table,
     642             :                                              Node* key, Variable* result,
     643             :                                              Label* entry_found,
     644             :                                              Label* not_found);
     645             : 
     646             :   // Specialization for string.
     647             :   // The {result} variable will contain the entry index if the key was found,
     648             :   // or the hash code otherwise.
     649             :   template <typename CollectionType>
     650             :   void FindOrderedHashTableEntryForStringKey(Node* context, Node* table,
     651             :                                              Node* key_tagged, Variable* result,
     652             :                                              Label* entry_found,
     653             :                                              Label* not_found);
     654             :   Node* ComputeStringHash(Node* context, Node* string_key);
     655             :   void SameValueZeroString(Node* context, Node* key_string, Node* candidate_key,
     656             :                            Label* if_same, Label* if_not_same);
     657             : 
     658             :   // Specialization for non-strings, non-numbers. For those we only need
     659             :   // reference equality to compare the keys.
     660             :   // The {result} variable will contain the entry index if the key was found,
     661             :   // or the hash code otherwise. If the hash-code has not been computed, it
     662             :   // should be Smi -1.
     663             :   template <typename CollectionType>
     664             :   void FindOrderedHashTableEntryForOtherKey(Node* context, Node* table,
     665             :                                             Node* key, Variable* result,
     666             :                                             Label* entry_found,
     667             :                                             Label* not_found);
     668             : 
     669             :   template <typename CollectionType>
     670             :   void TryLookupOrderedHashTableIndex(Node* const table, Node* const key,
     671             :                                       Node* const context, Variable* result,
     672             :                                       Label* if_entry_found,
     673             :                                       Label* if_not_found);
     674             : 
     675             :   Node* NormalizeNumberKey(Node* key);
     676             :   void StoreOrderedHashMapNewEntry(TNode<OrderedHashMap> const table,
     677             :                                    Node* const key, Node* const value,
     678             :                                    Node* const hash,
     679             :                                    Node* const number_of_buckets,
     680             :                                    Node* const occupancy);
     681             :   void StoreOrderedHashSetNewEntry(TNode<OrderedHashSet> const table,
     682             :                                    Node* const key, Node* const hash,
     683             :                                    Node* const number_of_buckets,
     684             :                                    Node* const occupancy);
     685             : 
     686             :   // Create a JSArray with PACKED_ELEMENTS kind from a Map.prototype.keys() or
     687             :   // Map.prototype.values() iterator. The iterator is assumed to satisfy
     688             :   // IterableWithOriginalKeyOrValueMapIterator. This function will skip the
     689             :   // iterator and iterate directly on the underlying hash table. In the end it
     690             :   // will update the state of the iterator to 'exhausted'.
     691             :   TNode<JSArray> MapIteratorToList(TNode<Context> context,
     692             :                                    TNode<JSMapIterator> iterator);
     693             : 
     694             :   // Create a JSArray with PACKED_ELEMENTS kind from a Set.prototype.keys() or
     695             :   // Set.prototype.values() iterator, or a Set. The |iterable| is assumed to
     696             :   // satisfy IterableWithOriginalValueSetIterator. This function will skip the
     697             :   // iterator and iterate directly on the underlying hash table. In the end, if
     698             :   // |iterable| is an iterator, it will update the state of the iterator to
     699             :   // 'exhausted'.
     700             :   TNode<JSArray> SetOrSetIteratorToList(TNode<Context> context,
     701             :                                         TNode<Object> iterable);
     702             : 
     703             :   void BranchIfMapIteratorProtectorValid(Label* if_true, Label* if_false);
     704             :   void BranchIfSetIteratorProtectorValid(Label* if_true, Label* if_false);
     705             : };
     706             : 
     707             : template <typename IteratorType>
     708         280 : Node* CollectionsBuiltinsAssembler::AllocateJSCollectionIterator(
     709             :     Node* context, int map_index, Node* collection) {
     710         280 :   Node* const table = LoadObjectField(collection, JSCollection::kTableOffset);
     711         280 :   Node* const native_context = LoadNativeContext(context);
     712         280 :   Node* const iterator_map = LoadContextElement(native_context, map_index);
     713         280 :   Node* const iterator = AllocateInNewSpace(IteratorType::kSize);
     714         280 :   StoreMapNoWriteBarrier(iterator, iterator_map);
     715         280 :   StoreObjectFieldRoot(iterator, IteratorType::kPropertiesOrHashOffset,
     716             :                        RootIndex::kEmptyFixedArray);
     717         280 :   StoreObjectFieldRoot(iterator, IteratorType::kElementsOffset,
     718             :                        RootIndex::kEmptyFixedArray);
     719         280 :   StoreObjectFieldNoWriteBarrier(iterator, IteratorType::kTableOffset, table);
     720         280 :   StoreObjectFieldNoWriteBarrier(iterator, IteratorType::kIndexOffset,
     721         280 :                                  SmiConstant(0));
     722         280 :   return iterator;
     723             : }
     724             : 
     725         112 : TNode<Object> CollectionsBuiltinsAssembler::AllocateTable(
     726             :     Variant variant, TNode<Context> context,
     727             :     TNode<IntPtrT> at_least_space_for) {
     728         112 :   return CAST((variant == kMap || variant == kWeakMap)
     729             :                   ? AllocateOrderedHashTable<OrderedHashMap>()
     730             :                   : AllocateOrderedHashTable<OrderedHashSet>());
     731             : }
     732             : 
     733         392 : TF_BUILTIN(MapConstructor, CollectionsBuiltinsAssembler) {
     734          56 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
     735             :   TNode<IntPtrT> argc =
     736          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
     737          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     738             : 
     739          56 :   GenerateConstructor(kMap, isolate()->factory()->Map_string(), new_target,
     740          56 :                       argc, context);
     741          56 : }
     742             : 
     743         392 : TF_BUILTIN(SetConstructor, CollectionsBuiltinsAssembler) {
     744          56 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
     745             :   TNode<IntPtrT> argc =
     746          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
     747          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     748             : 
     749          56 :   GenerateConstructor(kSet, isolate()->factory()->Set_string(), new_target,
     750          56 :                       argc, context);
     751          56 : }
     752             : 
     753         112 : Node* CollectionsBuiltinsAssembler::CallGetOrCreateHashRaw(Node* const key) {
     754             :   Node* const function_addr =
     755         112 :       ExternalConstant(ExternalReference::get_or_create_hash_raw());
     756             :   Node* const isolate_ptr =
     757         112 :       ExternalConstant(ExternalReference::isolate_address(isolate()));
     758             : 
     759         112 :   MachineType type_ptr = MachineType::Pointer();
     760         112 :   MachineType type_tagged = MachineType::AnyTagged();
     761             : 
     762         112 :   Node* const result = CallCFunction2(type_tagged, type_ptr, type_tagged,
     763         112 :                                       function_addr, isolate_ptr, key);
     764             : 
     765         112 :   return result;
     766             : }
     767             : 
     768        1344 : Node* CollectionsBuiltinsAssembler::CallGetHashRaw(Node* const key) {
     769             :   Node* const function_addr =
     770        1344 :       ExternalConstant(ExternalReference::orderedhashmap_gethash_raw());
     771             :   Node* const isolate_ptr =
     772        1344 :       ExternalConstant(ExternalReference::isolate_address(isolate()));
     773             : 
     774        1344 :   MachineType type_ptr = MachineType::Pointer();
     775        1344 :   MachineType type_tagged = MachineType::AnyTagged();
     776             : 
     777        1344 :   Node* const result = CallCFunction2(type_tagged, type_ptr, type_tagged,
     778        1344 :                                       function_addr, isolate_ptr, key);
     779        1344 :   return SmiUntag(result);
     780             : }
     781             : 
     782         336 : Node* CollectionsBuiltinsAssembler::GetHash(Node* const key) {
     783         672 :   VARIABLE(var_hash, MachineType::PointerRepresentation());
     784         672 :   Label if_receiver(this), if_other(this), done(this);
     785         336 :   Branch(IsJSReceiver(key), &if_receiver, &if_other);
     786             : 
     787         336 :   BIND(&if_receiver);
     788             :   {
     789         336 :     var_hash.Bind(LoadJSReceiverIdentityHash(key));
     790         336 :     Goto(&done);
     791             :   }
     792             : 
     793         336 :   BIND(&if_other);
     794             :   {
     795         336 :     var_hash.Bind(CallGetHashRaw(key));
     796         336 :     Goto(&done);
     797             :   }
     798             : 
     799         336 :   BIND(&done);
     800         672 :   return var_hash.value();
     801             : }
     802             : 
     803         336 : void CollectionsBuiltinsAssembler::SameValueZeroSmi(Node* key_smi,
     804             :                                                     Node* candidate_key,
     805             :                                                     Label* if_same,
     806             :                                                     Label* if_not_same) {
     807             :   // If the key is the same, we are done.
     808         336 :   GotoIf(WordEqual(candidate_key, key_smi), if_same);
     809             : 
     810             :   // If the candidate key is smi, then it must be different (because
     811             :   // we already checked for equality above).
     812         336 :   GotoIf(TaggedIsSmi(candidate_key), if_not_same);
     813             : 
     814             :   // If the candidate key is not smi, we still have to check if it is a
     815             :   // heap number with the same value.
     816         336 :   GotoIfNot(IsHeapNumber(candidate_key), if_not_same);
     817             : 
     818         336 :   Node* const candidate_key_number = LoadHeapNumberValue(candidate_key);
     819         336 :   Node* const key_number = SmiToFloat64(key_smi);
     820             : 
     821         336 :   GotoIf(Float64Equal(candidate_key_number, key_number), if_same);
     822             : 
     823         336 :   Goto(if_not_same);
     824         336 : }
     825             : 
     826         112 : void CollectionsBuiltinsAssembler::BranchIfMapIteratorProtectorValid(
     827             :     Label* if_true, Label* if_false) {
     828         112 :   Node* protector_cell = LoadRoot(RootIndex::kMapIteratorProtector);
     829             :   DCHECK(isolate()->heap()->map_iterator_protector()->IsPropertyCell());
     830         224 :   Branch(WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
     831         224 :                    SmiConstant(Isolate::kProtectorValid)),
     832         112 :          if_true, if_false);
     833         112 : }
     834             : 
     835         112 : void CollectionsBuiltinsAssembler::
     836             :     BranchIfIterableWithOriginalKeyOrValueMapIterator(TNode<Object> iterator,
     837             :                                                       TNode<Context> context,
     838             :                                                       Label* if_true,
     839             :                                                       Label* if_false) {
     840         224 :   Label if_key_or_value_iterator(this), extra_checks(this);
     841             : 
     842             :   // Check if iterator is a keys or values JSMapIterator.
     843         112 :   GotoIf(TaggedIsSmi(iterator), if_false);
     844         112 :   TNode<Map> iter_map = LoadMap(CAST(iterator));
     845         112 :   Node* const instance_type = LoadMapInstanceType(iter_map);
     846         224 :   GotoIf(InstanceTypeEqual(instance_type, JS_MAP_KEY_ITERATOR_TYPE),
     847         112 :          &if_key_or_value_iterator);
     848         224 :   Branch(InstanceTypeEqual(instance_type, JS_MAP_VALUE_ITERATOR_TYPE),
     849         112 :          &if_key_or_value_iterator, if_false);
     850             : 
     851         112 :   BIND(&if_key_or_value_iterator);
     852             :   // Check that the iterator is not partially consumed.
     853             :   Node* const index =
     854         112 :       LoadObjectField(CAST(iterator), JSMapIterator::kIndexOffset);
     855         112 :   GotoIfNot(WordEqual(index, SmiConstant(0)), if_false);
     856         112 :   BranchIfMapIteratorProtectorValid(&extra_checks, if_false);
     857             : 
     858         112 :   BIND(&extra_checks);
     859             :   // Check if the iterator object has the original %MapIteratorPrototype%.
     860         112 :   Node* const native_context = LoadNativeContext(context);
     861         224 :   Node* const initial_map_iter_proto = LoadContextElement(
     862         336 :       native_context, Context::INITIAL_MAP_ITERATOR_PROTOTYPE_INDEX);
     863         112 :   Node* const map_iter_proto = LoadMapPrototype(iter_map);
     864         112 :   GotoIfNot(WordEqual(map_iter_proto, initial_map_iter_proto), if_false);
     865             : 
     866             :   // Check if the original MapIterator prototype has the original
     867             :   // %IteratorPrototype%.
     868         224 :   Node* const initial_iter_proto = LoadContextElement(
     869         336 :       native_context, Context::INITIAL_ITERATOR_PROTOTYPE_INDEX);
     870         112 :   Node* const iter_proto = LoadMapPrototype(LoadMap(map_iter_proto));
     871         112 :   Branch(WordEqual(iter_proto, initial_iter_proto), if_true, if_false);
     872         112 : }
     873             : 
     874         112 : void BranchIfIterableWithOriginalKeyOrValueMapIterator(
     875             :     compiler::CodeAssemblerState* state, TNode<Object> iterable,
     876             :     TNode<Context> context, compiler::CodeAssemblerLabel* if_true,
     877             :     compiler::CodeAssemblerLabel* if_false) {
     878         224 :   CollectionsBuiltinsAssembler assembler(state);
     879             :   assembler.BranchIfIterableWithOriginalKeyOrValueMapIterator(
     880         112 :       iterable, context, if_true, if_false);
     881         112 : }
     882             : 
     883         112 : void CollectionsBuiltinsAssembler::BranchIfSetIteratorProtectorValid(
     884             :     Label* if_true, Label* if_false) {
     885         112 :   Node* const protector_cell = LoadRoot(RootIndex::kSetIteratorProtector);
     886             :   DCHECK(isolate()->heap()->set_iterator_protector()->IsPropertyCell());
     887         224 :   Branch(WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
     888         224 :                    SmiConstant(Isolate::kProtectorValid)),
     889         112 :          if_true, if_false);
     890         112 : }
     891             : 
     892         112 : void CollectionsBuiltinsAssembler::BranchIfIterableWithOriginalValueSetIterator(
     893             :     TNode<Object> iterable, TNode<Context> context, Label* if_true,
     894             :     Label* if_false) {
     895         224 :   Label if_set(this), if_value_iterator(this), check_protector(this);
     896         224 :   TVARIABLE(BoolT, var_result);
     897             : 
     898         112 :   GotoIf(TaggedIsSmi(iterable), if_false);
     899         112 :   TNode<Map> iterable_map = LoadMap(CAST(iterable));
     900         112 :   Node* const instance_type = LoadMapInstanceType(iterable_map);
     901             : 
     902         112 :   GotoIf(InstanceTypeEqual(instance_type, JS_SET_TYPE), &if_set);
     903         224 :   Branch(InstanceTypeEqual(instance_type, JS_SET_VALUE_ITERATOR_TYPE),
     904         112 :          &if_value_iterator, if_false);
     905             : 
     906         112 :   BIND(&if_set);
     907             :   // Check if the set object has the original Set prototype.
     908         224 :   Node* const initial_set_proto = LoadContextElement(
     909         336 :       LoadNativeContext(context), Context::INITIAL_SET_PROTOTYPE_INDEX);
     910         112 :   Node* const set_proto = LoadMapPrototype(iterable_map);
     911         112 :   GotoIfNot(WordEqual(set_proto, initial_set_proto), if_false);
     912         112 :   Goto(&check_protector);
     913             : 
     914         112 :   BIND(&if_value_iterator);
     915             :   // Check that the iterator is not partially consumed.
     916             :   Node* const index =
     917         112 :       LoadObjectField(CAST(iterable), JSSetIterator::kIndexOffset);
     918         112 :   GotoIfNot(WordEqual(index, SmiConstant(0)), if_false);
     919             : 
     920             :   // Check if the iterator object has the original SetIterator prototype.
     921         112 :   Node* const native_context = LoadNativeContext(context);
     922         224 :   Node* const initial_set_iter_proto = LoadContextElement(
     923         336 :       native_context, Context::INITIAL_SET_ITERATOR_PROTOTYPE_INDEX);
     924         112 :   Node* const set_iter_proto = LoadMapPrototype(iterable_map);
     925         112 :   GotoIfNot(WordEqual(set_iter_proto, initial_set_iter_proto), if_false);
     926             : 
     927             :   // Check if the original SetIterator prototype has the original
     928             :   // %IteratorPrototype%.
     929         224 :   Node* const initial_iter_proto = LoadContextElement(
     930         336 :       native_context, Context::INITIAL_ITERATOR_PROTOTYPE_INDEX);
     931         112 :   Node* const iter_proto = LoadMapPrototype(LoadMap(set_iter_proto));
     932         112 :   GotoIfNot(WordEqual(iter_proto, initial_iter_proto), if_false);
     933         112 :   Goto(&check_protector);
     934             : 
     935         112 :   BIND(&check_protector);
     936         112 :   BranchIfSetIteratorProtectorValid(if_true, if_false);
     937         112 : }
     938             : 
     939         112 : void BranchIfIterableWithOriginalValueSetIterator(
     940             :     compiler::CodeAssemblerState* state, TNode<Object> iterable,
     941             :     TNode<Context> context, compiler::CodeAssemblerLabel* if_true,
     942             :     compiler::CodeAssemblerLabel* if_false) {
     943         224 :   CollectionsBuiltinsAssembler assembler(state);
     944             :   assembler.BranchIfIterableWithOriginalValueSetIterator(iterable, context,
     945         112 :                                                          if_true, if_false);
     946         112 : }
     947             : 
     948          56 : TNode<JSArray> CollectionsBuiltinsAssembler::MapIteratorToList(
     949             :     TNode<Context> context, TNode<JSMapIterator> iterator) {
     950             :   // Transition the {iterator} table if necessary.
     951          56 :   TNode<OrderedHashMap> table;
     952          56 :   TNode<IntPtrT> index;
     953         112 :   std::tie(table, index) =
     954         168 :       TransitionAndUpdate<JSMapIterator, OrderedHashMap>(iterator);
     955             :   CSA_ASSERT(this, IntPtrEqual(index, IntPtrConstant(0)));
     956             : 
     957             :   TNode<IntPtrT> size =
     958          56 :       LoadAndUntagObjectField(table, OrderedHashMap::NumberOfElementsOffset());
     959             : 
     960          56 :   const ElementsKind kind = PACKED_ELEMENTS;
     961             :   TNode<Map> array_map =
     962          56 :       LoadJSArrayElementsMap(kind, LoadNativeContext(context));
     963             :   TNode<JSArray> array =
     964             :       AllocateJSArray(kind, array_map, size, SmiTag(size), nullptr,
     965          56 :                       INTPTR_PARAMETERS, kAllowLargeObjectAllocation);
     966          56 :   TNode<FixedArray> elements = CAST(LoadElements(array));
     967             : 
     968          56 :   const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag;
     969             :   TNode<IntPtrT> first_to_element_offset =
     970          56 :       ElementOffsetFromIndex(IntPtrConstant(0), kind, INTPTR_PARAMETERS, 0);
     971         112 :   VARIABLE(
     972             :       var_offset, MachineType::PointerRepresentation(),
     973             :       IntPtrAdd(first_to_element_offset, IntPtrConstant(first_element_offset)));
     974         112 :   TVARIABLE(IntPtrT, var_index, index);
     975         112 :   VariableList vars({&var_index, &var_offset}, zone());
     976         112 :   Label done(this, {&var_index}), loop(this, vars), continue_loop(this, vars),
     977         112 :       write_key(this, vars), write_value(this, vars);
     978             : 
     979          56 :   Goto(&loop);
     980             : 
     981          56 :   BIND(&loop);
     982             :   {
     983             :     // Read the next entry from the {table}, skipping holes.
     984          56 :     TNode<Object> entry_key;
     985          56 :     TNode<IntPtrT> entry_start_position;
     986          56 :     TNode<IntPtrT> cur_index;
     987         112 :     std::tie(entry_key, entry_start_position, cur_index) =
     988         168 :         NextSkipHoles<OrderedHashMap>(table, var_index.value(), &done);
     989             : 
     990             :     // Decide to write key or value.
     991         112 :     Branch(
     992         112 :         InstanceTypeEqual(LoadInstanceType(iterator), JS_MAP_KEY_ITERATOR_TYPE),
     993          56 :         &write_key, &write_value);
     994             : 
     995          56 :     BIND(&write_key);
     996             :     {
     997          56 :       Store(elements, var_offset.value(), entry_key);
     998          56 :       Goto(&continue_loop);
     999             :     }
    1000             : 
    1001          56 :     BIND(&write_value);
    1002             :     {
    1003             :       CSA_ASSERT(this, InstanceTypeEqual(LoadInstanceType(iterator),
    1004             :                                          JS_MAP_VALUE_ITERATOR_TYPE));
    1005             :       TNode<Object> entry_value =
    1006             :           UnsafeLoadFixedArrayElement(table, entry_start_position,
    1007          56 :                                       (OrderedHashMap::HashTableStartIndex() +
    1008             :                                        OrderedHashMap::kValueOffset) *
    1009          56 :                                           kTaggedSize);
    1010             : 
    1011          56 :       Store(elements, var_offset.value(), entry_value);
    1012          56 :       Goto(&continue_loop);
    1013             :     }
    1014             : 
    1015          56 :     BIND(&continue_loop);
    1016             :     {
    1017             :       // Increment the array offset and continue the loop to the next entry.
    1018          56 :       var_index = cur_index;
    1019          56 :       var_offset.Bind(
    1020         112 :           IntPtrAdd(var_offset.value(), IntPtrConstant(kTaggedSize)));
    1021          56 :       Goto(&loop);
    1022             :     }
    1023             :   }
    1024             : 
    1025          56 :   BIND(&done);
    1026             :   // Set the {iterator} to exhausted.
    1027          56 :   StoreObjectFieldRoot(iterator, JSMapIterator::kTableOffset,
    1028          56 :                        RootIndex::kEmptyOrderedHashMap);
    1029         112 :   StoreObjectFieldNoWriteBarrier(iterator, JSMapIterator::kIndexOffset,
    1030         168 :                                  SmiTag(var_index.value()));
    1031         112 :   return UncheckedCast<JSArray>(array);
    1032             : }
    1033             : 
    1034         336 : TF_BUILTIN(MapIteratorToList, CollectionsBuiltinsAssembler) {
    1035          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1036          56 :   TNode<JSMapIterator> iterator = CAST(Parameter(Descriptor::kSource));
    1037          56 :   Return(MapIteratorToList(context, iterator));
    1038          56 : }
    1039             : 
    1040          56 : TNode<JSArray> CollectionsBuiltinsAssembler::SetOrSetIteratorToList(
    1041             :     TNode<Context> context, TNode<Object> iterable) {
    1042         112 :   TVARIABLE(OrderedHashSet, var_table);
    1043         112 :   Label if_set(this), if_iterator(this), copy(this);
    1044             : 
    1045          56 :   Node* const instance_type = LoadInstanceType(CAST(iterable));
    1046          56 :   Branch(InstanceTypeEqual(instance_type, JS_SET_TYPE), &if_set, &if_iterator);
    1047             : 
    1048          56 :   BIND(&if_set);
    1049             :   {
    1050             :     // {iterable} is a JSSet.
    1051          56 :     var_table = CAST(LoadObjectField(CAST(iterable), JSSet::kTableOffset));
    1052          56 :     Goto(&copy);
    1053             :   }
    1054             : 
    1055          56 :   BIND(&if_iterator);
    1056             :   {
    1057             :     // {iterable} is a JSSetIterator.
    1058             :     // Transition the {iterable} table if necessary.
    1059          56 :     TNode<OrderedHashSet> iter_table;
    1060          56 :     TNode<IntPtrT> iter_index;
    1061         112 :     std::tie(iter_table, iter_index) =
    1062         168 :         TransitionAndUpdate<JSSetIterator, OrderedHashSet>(CAST(iterable));
    1063             :     CSA_ASSERT(this, IntPtrEqual(iter_index, IntPtrConstant(0)));
    1064          56 :     var_table = iter_table;
    1065          56 :     Goto(&copy);
    1066             :   }
    1067             : 
    1068          56 :   BIND(&copy);
    1069          56 :   TNode<OrderedHashSet> table = var_table.value();
    1070             :   TNode<IntPtrT> size =
    1071          56 :       LoadAndUntagObjectField(table, OrderedHashMap::NumberOfElementsOffset());
    1072             : 
    1073          56 :   const ElementsKind kind = PACKED_ELEMENTS;
    1074             :   TNode<Map> array_map =
    1075          56 :       LoadJSArrayElementsMap(kind, LoadNativeContext(context));
    1076             :   TNode<JSArray> array =
    1077             :       AllocateJSArray(kind, array_map, size, SmiTag(size), nullptr,
    1078          56 :                       INTPTR_PARAMETERS, kAllowLargeObjectAllocation);
    1079          56 :   TNode<FixedArray> elements = CAST(LoadElements(array));
    1080             : 
    1081          56 :   const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag;
    1082             :   TNode<IntPtrT> first_to_element_offset =
    1083          56 :       ElementOffsetFromIndex(IntPtrConstant(0), kind, INTPTR_PARAMETERS, 0);
    1084         112 :   VARIABLE(
    1085             :       var_offset, MachineType::PointerRepresentation(),
    1086             :       IntPtrAdd(first_to_element_offset, IntPtrConstant(first_element_offset)));
    1087         112 :   TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
    1088         112 :   Label done(this), finalize(this, {&var_index}),
    1089         112 :       loop(this, {&var_index, &var_offset});
    1090             : 
    1091          56 :   Goto(&loop);
    1092             : 
    1093          56 :   BIND(&loop);
    1094             :   {
    1095             :     // Read the next entry from the {table}, skipping holes.
    1096          56 :     TNode<Object> entry_key;
    1097          56 :     TNode<IntPtrT> entry_start_position;
    1098          56 :     TNode<IntPtrT> cur_index;
    1099         112 :     std::tie(entry_key, entry_start_position, cur_index) =
    1100         168 :         NextSkipHoles<OrderedHashSet>(table, var_index.value(), &finalize);
    1101             : 
    1102          56 :     Store(elements, var_offset.value(), entry_key);
    1103             : 
    1104          56 :     var_index = cur_index;
    1105          56 :     var_offset.Bind(IntPtrAdd(var_offset.value(), IntPtrConstant(kTaggedSize)));
    1106          56 :     Goto(&loop);
    1107             :   }
    1108             : 
    1109          56 :   BIND(&finalize);
    1110          56 :   GotoIf(InstanceTypeEqual(instance_type, JS_SET_TYPE), &done);
    1111             :   // Set the {iterable} to exhausted if it's an iterator.
    1112          56 :   StoreObjectFieldRoot(iterable, JSSetIterator::kTableOffset,
    1113          56 :                        RootIndex::kEmptyOrderedHashSet);
    1114          56 :   StoreObjectFieldNoWriteBarrier(iterable, JSSetIterator::kIndexOffset,
    1115         112 :                                  SmiTag(var_index.value()));
    1116          56 :   Goto(&done);
    1117             : 
    1118          56 :   BIND(&done);
    1119         112 :   return UncheckedCast<JSArray>(array);
    1120             : }
    1121             : 
    1122         336 : TF_BUILTIN(SetOrSetIteratorToList, CollectionsBuiltinsAssembler) {
    1123          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1124          56 :   TNode<Object> object = CAST(Parameter(Descriptor::kSource));
    1125          56 :   Return(SetOrSetIteratorToList(context, object));
    1126          56 : }
    1127             : 
    1128             : template <typename CollectionType>
    1129         336 : void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForSmiKey(
    1130             :     Node* table, Node* smi_key, Variable* result, Label* entry_found,
    1131             :     Label* not_found) {
    1132         336 :   Node* const key_untagged = SmiUntag(smi_key);
    1133         336 :   Node* const hash = ChangeInt32ToIntPtr(ComputeUnseededHash(key_untagged));
    1134             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
    1135         336 :   result->Bind(hash);
    1136         336 :   FindOrderedHashTableEntry<CollectionType>(
    1137             :       table, hash,
    1138         336 :       [&](Node* other_key, Label* if_same, Label* if_not_same) {
    1139         336 :         SameValueZeroSmi(smi_key, other_key, if_same, if_not_same);
    1140         336 :       },
    1141             :       result, entry_found, not_found);
    1142         336 : }
    1143             : 
    1144             : template <typename CollectionType>
    1145         336 : void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForStringKey(
    1146             :     Node* context, Node* table, Node* key_tagged, Variable* result,
    1147             :     Label* entry_found, Label* not_found) {
    1148         336 :   Node* const hash = ComputeStringHash(context, key_tagged);
    1149             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
    1150         336 :   result->Bind(hash);
    1151         336 :   FindOrderedHashTableEntry<CollectionType>(
    1152             :       table, hash,
    1153         336 :       [&](Node* other_key, Label* if_same, Label* if_not_same) {
    1154         672 :         SameValueZeroString(context, key_tagged, other_key, if_same,
    1155         336 :                             if_not_same);
    1156         336 :       },
    1157             :       result, entry_found, not_found);
    1158         336 : }
    1159             : 
    1160             : template <typename CollectionType>
    1161         336 : void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForHeapNumberKey(
    1162             :     Node* context, Node* table, Node* key_heap_number, Variable* result,
    1163             :     Label* entry_found, Label* not_found) {
    1164         336 :   Node* hash = CallGetHashRaw(key_heap_number);
    1165             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
    1166         336 :   result->Bind(hash);
    1167         336 :   Node* const key_float = LoadHeapNumberValue(key_heap_number);
    1168         336 :   FindOrderedHashTableEntry<CollectionType>(
    1169             :       table, hash,
    1170         336 :       [&](Node* other_key, Label* if_same, Label* if_not_same) {
    1171         336 :         SameValueZeroHeapNumber(key_float, other_key, if_same, if_not_same);
    1172         336 :       },
    1173             :       result, entry_found, not_found);
    1174         336 : }
    1175             : 
    1176             : template <typename CollectionType>
    1177         336 : void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForBigIntKey(
    1178             :     Node* context, Node* table, Node* key, Variable* result, Label* entry_found,
    1179             :     Label* not_found) {
    1180         336 :   Node* hash = CallGetHashRaw(key);
    1181             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
    1182         336 :   result->Bind(hash);
    1183         336 :   FindOrderedHashTableEntry<CollectionType>(
    1184             :       table, hash,
    1185         336 :       [&](Node* other_key, Label* if_same, Label* if_not_same) {
    1186         336 :         SameValueZeroBigInt(key, other_key, if_same, if_not_same);
    1187         336 :       },
    1188             :       result, entry_found, not_found);
    1189         336 : }
    1190             : 
    1191             : template <typename CollectionType>
    1192         336 : void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForOtherKey(
    1193             :     Node* context, Node* table, Node* key, Variable* result, Label* entry_found,
    1194             :     Label* not_found) {
    1195         336 :   Node* hash = GetHash(key);
    1196             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
    1197         336 :   result->Bind(hash);
    1198         336 :   FindOrderedHashTableEntry<CollectionType>(
    1199             :       table, hash,
    1200         336 :       [&](Node* other_key, Label* if_same, Label* if_not_same) {
    1201         336 :         Branch(WordEqual(key, other_key), if_same, if_not_same);
    1202         336 :       },
    1203             :       result, entry_found, not_found);
    1204         336 : }
    1205             : 
    1206         336 : Node* CollectionsBuiltinsAssembler::ComputeStringHash(Node* context,
    1207             :                                                       Node* string_key) {
    1208         672 :   VARIABLE(var_result, MachineType::PointerRepresentation());
    1209             : 
    1210         672 :   Label hash_not_computed(this), done(this, &var_result);
    1211             :   Node* hash =
    1212         336 :       ChangeInt32ToIntPtr(LoadNameHash(string_key, &hash_not_computed));
    1213         336 :   var_result.Bind(hash);
    1214         336 :   Goto(&done);
    1215             : 
    1216         336 :   BIND(&hash_not_computed);
    1217         336 :   var_result.Bind(CallGetHashRaw(string_key));
    1218         336 :   Goto(&done);
    1219             : 
    1220         336 :   BIND(&done);
    1221         672 :   return var_result.value();
    1222             : }
    1223             : 
    1224         336 : void CollectionsBuiltinsAssembler::SameValueZeroString(Node* context,
    1225             :                                                        Node* key_string,
    1226             :                                                        Node* candidate_key,
    1227             :                                                        Label* if_same,
    1228             :                                                        Label* if_not_same) {
    1229             :   // If the candidate is not a string, the keys are not equal.
    1230         336 :   GotoIf(TaggedIsSmi(candidate_key), if_not_same);
    1231         336 :   GotoIfNot(IsString(candidate_key), if_not_same);
    1232             : 
    1233         672 :   Branch(WordEqual(CallBuiltin(Builtins::kStringEqual, context, key_string,
    1234             :                                candidate_key),
    1235         672 :                    TrueConstant()),
    1236         336 :          if_same, if_not_same);
    1237         336 : }
    1238             : 
    1239         336 : void CollectionsBuiltinsAssembler::SameValueZeroBigInt(Node* key,
    1240             :                                                        Node* candidate_key,
    1241             :                                                        Label* if_same,
    1242             :                                                        Label* if_not_same) {
    1243             :   CSA_ASSERT(this, IsBigInt(key));
    1244         336 :   GotoIf(TaggedIsSmi(candidate_key), if_not_same);
    1245         336 :   GotoIfNot(IsBigInt(candidate_key), if_not_same);
    1246             : 
    1247         672 :   Branch(WordEqual(CallRuntime(Runtime::kBigIntEqualToBigInt,
    1248         672 :                                NoContextConstant(), key, candidate_key),
    1249        1008 :                    TrueConstant()),
    1250         336 :          if_same, if_not_same);
    1251         336 : }
    1252             : 
    1253         336 : void CollectionsBuiltinsAssembler::SameValueZeroHeapNumber(Node* key_float,
    1254             :                                                            Node* candidate_key,
    1255             :                                                            Label* if_same,
    1256             :                                                            Label* if_not_same) {
    1257         672 :   Label if_smi(this), if_keyisnan(this);
    1258             : 
    1259         336 :   GotoIf(TaggedIsSmi(candidate_key), &if_smi);
    1260         336 :   GotoIfNot(IsHeapNumber(candidate_key), if_not_same);
    1261             : 
    1262             :   {
    1263             :     // {candidate_key} is a heap number.
    1264         336 :     Node* const candidate_float = LoadHeapNumberValue(candidate_key);
    1265         336 :     GotoIf(Float64Equal(key_float, candidate_float), if_same);
    1266             : 
    1267             :     // SameValueZero needs to treat NaNs as equal. First check if {key_float}
    1268             :     // is NaN.
    1269         336 :     BranchIfFloat64IsNaN(key_float, &if_keyisnan, if_not_same);
    1270             : 
    1271         336 :     BIND(&if_keyisnan);
    1272             :     {
    1273             :       // Return true iff {candidate_key} is NaN.
    1274         672 :       Branch(Float64Equal(candidate_float, candidate_float), if_not_same,
    1275         336 :              if_same);
    1276             :     }
    1277             :   }
    1278             : 
    1279         336 :   BIND(&if_smi);
    1280             :   {
    1281         336 :     Node* const candidate_float = SmiToFloat64(candidate_key);
    1282         336 :     Branch(Float64Equal(key_float, candidate_float), if_same, if_not_same);
    1283             :   }
    1284         336 : }
    1285             : 
    1286         336 : TF_BUILTIN(OrderedHashTableHealIndex, CollectionsBuiltinsAssembler) {
    1287          56 :   TNode<HeapObject> table = CAST(Parameter(Descriptor::kTable));
    1288          56 :   TNode<Smi> index = CAST(Parameter(Descriptor::kIndex));
    1289         112 :   Label return_index(this), return_zero(this);
    1290             : 
    1291             :   // Check if we need to update the {index}.
    1292          56 :   GotoIfNot(SmiLessThan(SmiConstant(0), index), &return_zero);
    1293             : 
    1294             :   // Check if the {table} was cleared.
    1295             :   STATIC_ASSERT(OrderedHashMap::NumberOfDeletedElementsOffset() ==
    1296             :                 OrderedHashSet::NumberOfDeletedElementsOffset());
    1297         112 :   Node* number_of_deleted_elements = LoadAndUntagObjectField(
    1298         168 :       table, OrderedHashMap::NumberOfDeletedElementsOffset());
    1299             :   STATIC_ASSERT(OrderedHashMap::kClearedTableSentinel ==
    1300             :                 OrderedHashSet::kClearedTableSentinel);
    1301         112 :   GotoIf(WordEqual(number_of_deleted_elements,
    1302         112 :                    IntPtrConstant(OrderedHashMap::kClearedTableSentinel)),
    1303          56 :          &return_zero);
    1304             : 
    1305         112 :   VARIABLE(var_i, MachineType::PointerRepresentation(), IntPtrConstant(0));
    1306         112 :   VARIABLE(var_index, MachineRepresentation::kTagged, index);
    1307         112 :   Label loop(this, {&var_i, &var_index});
    1308          56 :   Goto(&loop);
    1309          56 :   BIND(&loop);
    1310             :   {
    1311          56 :     Node* i = var_i.value();
    1312          56 :     GotoIfNot(IntPtrLessThan(i, number_of_deleted_elements), &return_index);
    1313             :     STATIC_ASSERT(OrderedHashMap::RemovedHolesIndex() ==
    1314             :                   OrderedHashSet::RemovedHolesIndex());
    1315          56 :     TNode<Smi> removed_index = CAST(LoadFixedArrayElement(
    1316             :         CAST(table), i, OrderedHashMap::RemovedHolesIndex() * kTaggedSize));
    1317          56 :     GotoIf(SmiGreaterThanOrEqual(removed_index, index), &return_index);
    1318          56 :     Decrement(&var_index, 1, SMI_PARAMETERS);
    1319          56 :     Increment(&var_i);
    1320          56 :     Goto(&loop);
    1321             :   }
    1322             : 
    1323          56 :   BIND(&return_index);
    1324          56 :   Return(var_index.value());
    1325             : 
    1326          56 :   BIND(&return_zero);
    1327          56 :   Return(SmiConstant(0));
    1328          56 : }
    1329             : 
    1330             : template <typename TableType>
    1331             : std::pair<TNode<TableType>, TNode<IntPtrT>>
    1332         336 : CollectionsBuiltinsAssembler::Transition(
    1333             :     TNode<TableType> const table, TNode<IntPtrT> const index,
    1334             :     UpdateInTransition const& update_in_transition) {
    1335         672 :   TVARIABLE(IntPtrT, var_index, index);
    1336         672 :   TVARIABLE(TableType, var_table, table);
    1337         672 :   Label if_done(this), if_transition(this, Label::kDeferred);
    1338         336 :   Branch(TaggedIsSmi(
    1339             :              LoadObjectField(var_table.value(), TableType::NextTableOffset())),
    1340             :          &if_done, &if_transition);
    1341             : 
    1342         336 :   BIND(&if_transition);
    1343             :   {
    1344         672 :     Label loop(this, {&var_table, &var_index}), done_loop(this);
    1345         336 :     Goto(&loop);
    1346         336 :     BIND(&loop);
    1347             :     {
    1348         336 :       TNode<TableType> table = var_table.value();
    1349         336 :       TNode<IntPtrT> index = var_index.value();
    1350             : 
    1351             :       TNode<Object> next_table =
    1352         336 :           LoadObjectField(table, TableType::NextTableOffset());
    1353         336 :       GotoIf(TaggedIsSmi(next_table), &done_loop);
    1354             : 
    1355         336 :       var_table = CAST(next_table);
    1356         672 :       var_index = SmiUntag(
    1357         336 :           CAST(CallBuiltin(Builtins::kOrderedHashTableHealIndex,
    1358             :                            NoContextConstant(), table, SmiTag(index))));
    1359         336 :       Goto(&loop);
    1360             :     }
    1361         336 :     BIND(&done_loop);
    1362             : 
    1363             :     // Update with the new {table} and {index}.
    1364         336 :     update_in_transition(var_table.value(), var_index.value());
    1365         336 :     Goto(&if_done);
    1366             :   }
    1367             : 
    1368         336 :   BIND(&if_done);
    1369         672 :   return {var_table.value(), var_index.value()};
    1370             : }
    1371             : 
    1372             : template <typename IteratorType, typename TableType>
    1373             : std::pair<TNode<TableType>, TNode<IntPtrT>>
    1374         224 : CollectionsBuiltinsAssembler::TransitionAndUpdate(
    1375             :     TNode<IteratorType> const iterator) {
    1376         448 :   return Transition<TableType>(
    1377             :       CAST(LoadObjectField(iterator, IteratorType::kTableOffset)),
    1378             :       LoadAndUntagObjectField(iterator, IteratorType::kIndexOffset),
    1379         896 :       [this, iterator](Node* const table, Node* const index) {
    1380             :         // Update the {iterator} with the new state.
    1381         448 :         StoreObjectField(iterator, IteratorType::kTableOffset, table);
    1382         672 :         StoreObjectFieldNoWriteBarrier(iterator, IteratorType::kIndexOffset,
    1383             :                                        SmiTag(index));
    1384         672 :       });
    1385             : }
    1386             : 
    1387             : template <typename TableType>
    1388             : std::tuple<TNode<Object>, TNode<IntPtrT>, TNode<IntPtrT>>
    1389         336 : CollectionsBuiltinsAssembler::NextSkipHoles(TNode<TableType> table,
    1390             :                                             TNode<IntPtrT> index,
    1391             :                                             Label* if_end) {
    1392             :   // Compute the used capacity for the {table}.
    1393             :   TNode<IntPtrT> number_of_buckets =
    1394         336 :       LoadAndUntagObjectField(table, TableType::NumberOfBucketsOffset());
    1395             :   TNode<IntPtrT> number_of_elements =
    1396         336 :       LoadAndUntagObjectField(table, TableType::NumberOfElementsOffset());
    1397             :   TNode<IntPtrT> number_of_deleted_elements = LoadAndUntagObjectField(
    1398         336 :       table, TableType::NumberOfDeletedElementsOffset());
    1399             :   TNode<IntPtrT> used_capacity =
    1400         336 :       IntPtrAdd(number_of_elements, number_of_deleted_elements);
    1401             : 
    1402         336 :   TNode<Object> entry_key;
    1403         336 :   TNode<IntPtrT> entry_start_position;
    1404         672 :   TVARIABLE(IntPtrT, var_index, index);
    1405         672 :   Label loop(this, &var_index), done_loop(this);
    1406         336 :   Goto(&loop);
    1407         336 :   BIND(&loop);
    1408             :   {
    1409         336 :     GotoIfNot(IntPtrLessThan(var_index.value(), used_capacity), if_end);
    1410         336 :     entry_start_position = IntPtrAdd(
    1411             :         IntPtrMul(var_index.value(), IntPtrConstant(TableType::kEntrySize)),
    1412             :         number_of_buckets);
    1413         336 :     entry_key = UnsafeLoadFixedArrayElement(
    1414             :         table, entry_start_position,
    1415         336 :         TableType::HashTableStartIndex() * kTaggedSize);
    1416         336 :     Increment(&var_index);
    1417         336 :     Branch(IsTheHole(entry_key), &loop, &done_loop);
    1418             :   }
    1419             : 
    1420         336 :   BIND(&done_loop);
    1421             :   return std::tuple<TNode<Object>, TNode<IntPtrT>, TNode<IntPtrT>>{
    1422         672 :       entry_key, entry_start_position, var_index.value()};
    1423             : }
    1424             : 
    1425         392 : TF_BUILTIN(MapPrototypeGet, CollectionsBuiltinsAssembler) {
    1426          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    1427          56 :   Node* const key = Parameter(Descriptor::kKey);
    1428          56 :   Node* const context = Parameter(Descriptor::kContext);
    1429             : 
    1430          56 :   ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, "Map.prototype.get");
    1431             : 
    1432          56 :   Node* const table = LoadObjectField(receiver, JSMap::kTableOffset);
    1433          56 :   TNode<Smi> index = CAST(
    1434             :       CallBuiltin(Builtins::kFindOrderedHashMapEntry, context, table, key));
    1435             : 
    1436         112 :   Label if_found(this), if_not_found(this);
    1437         112 :   Branch(SmiGreaterThanOrEqual(index, SmiConstant(0)), &if_found,
    1438          56 :          &if_not_found);
    1439             : 
    1440          56 :   BIND(&if_found);
    1441         112 :   Return(LoadFixedArrayElement(
    1442         112 :       CAST(table), SmiUntag(index),
    1443          56 :       (OrderedHashMap::HashTableStartIndex() + OrderedHashMap::kValueOffset) *
    1444         224 :           kTaggedSize));
    1445             : 
    1446          56 :   BIND(&if_not_found);
    1447          56 :   Return(UndefinedConstant());
    1448          56 : }
    1449             : 
    1450         392 : TF_BUILTIN(MapPrototypeHas, CollectionsBuiltinsAssembler) {
    1451          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    1452          56 :   Node* const key = Parameter(Descriptor::kKey);
    1453          56 :   Node* const context = Parameter(Descriptor::kContext);
    1454             : 
    1455          56 :   ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, "Map.prototype.has");
    1456             : 
    1457          56 :   Node* const table = LoadObjectField(receiver, JSMap::kTableOffset);
    1458          56 :   TNode<Smi> index = CAST(
    1459             :       CallBuiltin(Builtins::kFindOrderedHashMapEntry, context, table, key));
    1460             : 
    1461         112 :   Label if_found(this), if_not_found(this);
    1462         112 :   Branch(SmiGreaterThanOrEqual(index, SmiConstant(0)), &if_found,
    1463          56 :          &if_not_found);
    1464             : 
    1465          56 :   BIND(&if_found);
    1466          56 :   Return(TrueConstant());
    1467             : 
    1468          56 :   BIND(&if_not_found);
    1469          56 :   Return(FalseConstant());
    1470          56 : }
    1471             : 
    1472         112 : Node* CollectionsBuiltinsAssembler::NormalizeNumberKey(Node* const key) {
    1473         224 :   VARIABLE(result, MachineRepresentation::kTagged, key);
    1474         224 :   Label done(this);
    1475             : 
    1476         112 :   GotoIf(TaggedIsSmi(key), &done);
    1477         112 :   GotoIfNot(IsHeapNumber(key), &done);
    1478         112 :   Node* const number = LoadHeapNumberValue(key);
    1479         112 :   GotoIfNot(Float64Equal(number, Float64Constant(0.0)), &done);
    1480             :   // We know the value is zero, so we take the key to be Smi 0.
    1481             :   // Another option would be to normalize to Smi here.
    1482         112 :   result.Bind(SmiConstant(0));
    1483         112 :   Goto(&done);
    1484             : 
    1485         112 :   BIND(&done);
    1486         224 :   return result.value();
    1487             : }
    1488             : 
    1489         448 : TF_BUILTIN(MapPrototypeSet, CollectionsBuiltinsAssembler) {
    1490          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    1491          56 :   Node* key = Parameter(Descriptor::kKey);
    1492          56 :   Node* const value = Parameter(Descriptor::kValue);
    1493          56 :   Node* const context = Parameter(Descriptor::kContext);
    1494             : 
    1495          56 :   ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, "Map.prototype.set");
    1496             : 
    1497          56 :   key = NormalizeNumberKey(key);
    1498             : 
    1499             :   TNode<OrderedHashMap> const table =
    1500          56 :       CAST(LoadObjectField(receiver, JSMap::kTableOffset));
    1501             : 
    1502         112 :   VARIABLE(entry_start_position_or_hash, MachineType::PointerRepresentation(),
    1503             :            IntPtrConstant(0));
    1504         112 :   Label entry_found(this), not_found(this);
    1505             : 
    1506          56 :   TryLookupOrderedHashTableIndex<OrderedHashMap>(table, key, context,
    1507             :                                                  &entry_start_position_or_hash,
    1508          56 :                                                  &entry_found, &not_found);
    1509             : 
    1510          56 :   BIND(&entry_found);
    1511             :   // If we found the entry, we just store the value there.
    1512         112 :   StoreFixedArrayElement(table, entry_start_position_or_hash.value(), value,
    1513             :                          UPDATE_WRITE_BARRIER,
    1514          56 :                          kTaggedSize * (OrderedHashMap::HashTableStartIndex() +
    1515          56 :                                         OrderedHashMap::kValueOffset));
    1516          56 :   Return(receiver);
    1517             : 
    1518         112 :   Label no_hash(this), add_entry(this), store_new_entry(this);
    1519          56 :   BIND(&not_found);
    1520             :   {
    1521             :     // If we have a hash code, we can start adding the new entry.
    1522         112 :     GotoIf(IntPtrGreaterThan(entry_start_position_or_hash.value(),
    1523         112 :                              IntPtrConstant(0)),
    1524          56 :            &add_entry);
    1525             : 
    1526             :     // Otherwise, go to runtime to compute the hash code.
    1527          56 :     entry_start_position_or_hash.Bind(SmiUntag(CallGetOrCreateHashRaw(key)));
    1528          56 :     Goto(&add_entry);
    1529             :   }
    1530             : 
    1531          56 :   BIND(&add_entry);
    1532         112 :   VARIABLE(number_of_buckets, MachineType::PointerRepresentation());
    1533         112 :   VARIABLE(occupancy, MachineType::PointerRepresentation());
    1534         112 :   TVARIABLE(OrderedHashMap, table_var, table);
    1535             :   {
    1536             :     // Check we have enough space for the entry.
    1537         168 :     number_of_buckets.Bind(SmiUntag(CAST(UnsafeLoadFixedArrayElement(
    1538         112 :         table, OrderedHashMap::NumberOfBucketsIndex()))));
    1539             : 
    1540             :     STATIC_ASSERT(OrderedHashMap::kLoadFactor == 2);
    1541          56 :     Node* const capacity = WordShl(number_of_buckets.value(), 1);
    1542         112 :     Node* const number_of_elements = SmiUntag(
    1543         168 :         CAST(LoadObjectField(table, OrderedHashMap::NumberOfElementsOffset())));
    1544         168 :     Node* const number_of_deleted = SmiUntag(CAST(LoadObjectField(
    1545         112 :         table, OrderedHashMap::NumberOfDeletedElementsOffset())));
    1546          56 :     occupancy.Bind(IntPtrAdd(number_of_elements, number_of_deleted));
    1547          56 :     GotoIf(IntPtrLessThan(occupancy.value(), capacity), &store_new_entry);
    1548             : 
    1549             :     // We do not have enough space, grow the table and reload the relevant
    1550             :     // fields.
    1551          56 :     CallRuntime(Runtime::kMapGrow, context, receiver);
    1552          56 :     table_var = CAST(LoadObjectField(receiver, JSMap::kTableOffset));
    1553         168 :     number_of_buckets.Bind(SmiUntag(CAST(UnsafeLoadFixedArrayElement(
    1554         112 :         table_var.value(), OrderedHashMap::NumberOfBucketsIndex()))));
    1555         168 :     Node* const new_number_of_elements = SmiUntag(CAST(LoadObjectField(
    1556         112 :         table_var.value(), OrderedHashMap::NumberOfElementsOffset())));
    1557         168 :     Node* const new_number_of_deleted = SmiUntag(CAST(LoadObjectField(
    1558         112 :         table_var.value(), OrderedHashMap::NumberOfDeletedElementsOffset())));
    1559          56 :     occupancy.Bind(IntPtrAdd(new_number_of_elements, new_number_of_deleted));
    1560          56 :     Goto(&store_new_entry);
    1561             :   }
    1562          56 :   BIND(&store_new_entry);
    1563             :   // Store the key, value and connect the element to the bucket chain.
    1564          56 :   StoreOrderedHashMapNewEntry(table_var.value(), key, value,
    1565             :                               entry_start_position_or_hash.value(),
    1566          56 :                               number_of_buckets.value(), occupancy.value());
    1567          56 :   Return(receiver);
    1568          56 : }
    1569             : 
    1570          56 : void CollectionsBuiltinsAssembler::StoreOrderedHashMapNewEntry(
    1571             :     TNode<OrderedHashMap> const table, Node* const key, Node* const value,
    1572             :     Node* const hash, Node* const number_of_buckets, Node* const occupancy) {
    1573             :   Node* const bucket =
    1574          56 :       WordAnd(hash, IntPtrSub(number_of_buckets, IntPtrConstant(1)));
    1575         112 :   Node* const bucket_entry = UnsafeLoadFixedArrayElement(
    1576         168 :       table, bucket, OrderedHashMap::HashTableStartIndex() * kTaggedSize);
    1577             : 
    1578             :   // Store the entry elements.
    1579         112 :   Node* const entry_start = IntPtrAdd(
    1580         112 :       IntPtrMul(occupancy, IntPtrConstant(OrderedHashMap::kEntrySize)),
    1581         280 :       number_of_buckets);
    1582         112 :   UnsafeStoreFixedArrayElement(
    1583             :       table, entry_start, key, UPDATE_WRITE_BARRIER,
    1584         112 :       kTaggedSize * OrderedHashMap::HashTableStartIndex());
    1585         112 :   UnsafeStoreFixedArrayElement(
    1586             :       table, entry_start, value, UPDATE_WRITE_BARRIER,
    1587          56 :       kTaggedSize * (OrderedHashMap::HashTableStartIndex() +
    1588          56 :                      OrderedHashMap::kValueOffset));
    1589         112 :   UnsafeStoreFixedArrayElement(
    1590             :       table, entry_start, bucket_entry, SKIP_WRITE_BARRIER,
    1591          56 :       kTaggedSize * (OrderedHashMap::HashTableStartIndex() +
    1592          56 :                      OrderedHashMap::kChainOffset));
    1593             : 
    1594             :   // Update the bucket head.
    1595         168 :   UnsafeStoreFixedArrayElement(
    1596         112 :       table, bucket, SmiTag(occupancy), SKIP_WRITE_BARRIER,
    1597         112 :       OrderedHashMap::HashTableStartIndex() * kTaggedSize);
    1598             : 
    1599             :   // Bump the elements count.
    1600             :   TNode<Smi> const number_of_elements =
    1601          56 :       CAST(LoadObjectField(table, OrderedHashMap::NumberOfElementsOffset()));
    1602         112 :   StoreObjectFieldNoWriteBarrier(table,
    1603             :                                  OrderedHashMap::NumberOfElementsOffset(),
    1604          56 :                                  SmiAdd(number_of_elements, SmiConstant(1)));
    1605          56 : }
    1606             : 
    1607         392 : TF_BUILTIN(MapPrototypeDelete, CollectionsBuiltinsAssembler) {
    1608          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    1609          56 :   Node* key = Parameter(Descriptor::kKey);
    1610          56 :   Node* const context = Parameter(Descriptor::kContext);
    1611             : 
    1612          56 :   ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
    1613          56 :                          "Map.prototype.delete");
    1614             : 
    1615             :   TNode<OrderedHashMap> const table =
    1616          56 :       CAST(LoadObjectField(receiver, JSMap::kTableOffset));
    1617             : 
    1618         112 :   VARIABLE(entry_start_position_or_hash, MachineType::PointerRepresentation(),
    1619             :            IntPtrConstant(0));
    1620         112 :   Label entry_found(this), not_found(this);
    1621             : 
    1622          56 :   TryLookupOrderedHashTableIndex<OrderedHashMap>(table, key, context,
    1623             :                                                  &entry_start_position_or_hash,
    1624          56 :                                                  &entry_found, &not_found);
    1625             : 
    1626          56 :   BIND(&not_found);
    1627          56 :   Return(FalseConstant());
    1628             : 
    1629          56 :   BIND(&entry_found);
    1630             :   // If we found the entry, mark the entry as deleted.
    1631         168 :   StoreFixedArrayElement(table, entry_start_position_or_hash.value(),
    1632         112 :                          TheHoleConstant(), UPDATE_WRITE_BARRIER,
    1633         112 :                          kTaggedSize * OrderedHashMap::HashTableStartIndex());
    1634         168 :   StoreFixedArrayElement(table, entry_start_position_or_hash.value(),
    1635         112 :                          TheHoleConstant(), UPDATE_WRITE_BARRIER,
    1636          56 :                          kTaggedSize * (OrderedHashMap::HashTableStartIndex() +
    1637          56 :                                         OrderedHashMap::kValueOffset));
    1638             : 
    1639             :   // Decrement the number of elements, increment the number of deleted elements.
    1640             :   TNode<Smi> const number_of_elements = SmiSub(
    1641         112 :       CAST(LoadObjectField(table, OrderedHashMap::NumberOfElementsOffset())),
    1642         112 :       SmiConstant(1));
    1643         112 :   StoreObjectFieldNoWriteBarrier(
    1644          56 :       table, OrderedHashMap::NumberOfElementsOffset(), number_of_elements);
    1645             :   TNode<Smi> const number_of_deleted =
    1646         112 :       SmiAdd(CAST(LoadObjectField(
    1647             :                  table, OrderedHashMap::NumberOfDeletedElementsOffset())),
    1648         112 :              SmiConstant(1));
    1649         112 :   StoreObjectFieldNoWriteBarrier(
    1650             :       table, OrderedHashMap::NumberOfDeletedElementsOffset(),
    1651          56 :       number_of_deleted);
    1652             : 
    1653          56 :   TNode<Smi> const number_of_buckets = CAST(
    1654             :       LoadFixedArrayElement(table, OrderedHashMap::NumberOfBucketsIndex()));
    1655             : 
    1656             :   // If there fewer elements than #buckets / 2, shrink the table.
    1657         112 :   Label shrink(this);
    1658         112 :   GotoIf(SmiLessThan(SmiAdd(number_of_elements, number_of_elements),
    1659          56 :                      number_of_buckets),
    1660          56 :          &shrink);
    1661          56 :   Return(TrueConstant());
    1662             : 
    1663          56 :   BIND(&shrink);
    1664          56 :   CallRuntime(Runtime::kMapShrink, context, receiver);
    1665          56 :   Return(TrueConstant());
    1666          56 : }
    1667             : 
    1668         392 : TF_BUILTIN(SetPrototypeAdd, CollectionsBuiltinsAssembler) {
    1669          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    1670          56 :   Node* key = Parameter(Descriptor::kKey);
    1671          56 :   Node* const context = Parameter(Descriptor::kContext);
    1672             : 
    1673          56 :   ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE, "Set.prototype.add");
    1674             : 
    1675          56 :   key = NormalizeNumberKey(key);
    1676             : 
    1677             :   TNode<OrderedHashSet> const table =
    1678          56 :       CAST(LoadObjectField(receiver, JSMap::kTableOffset));
    1679             : 
    1680         112 :   VARIABLE(entry_start_position_or_hash, MachineType::PointerRepresentation(),
    1681             :            IntPtrConstant(0));
    1682         112 :   Label entry_found(this), not_found(this);
    1683             : 
    1684          56 :   TryLookupOrderedHashTableIndex<OrderedHashSet>(table, key, context,
    1685             :                                                  &entry_start_position_or_hash,
    1686          56 :                                                  &entry_found, &not_found);
    1687             : 
    1688          56 :   BIND(&entry_found);
    1689             :   // The entry was found, there is nothing to do.
    1690          56 :   Return(receiver);
    1691             : 
    1692         112 :   Label no_hash(this), add_entry(this), store_new_entry(this);
    1693          56 :   BIND(&not_found);
    1694             :   {
    1695             :     // If we have a hash code, we can start adding the new entry.
    1696         112 :     GotoIf(IntPtrGreaterThan(entry_start_position_or_hash.value(),
    1697         112 :                              IntPtrConstant(0)),
    1698          56 :            &add_entry);
    1699             : 
    1700             :     // Otherwise, go to runtime to compute the hash code.
    1701          56 :     entry_start_position_or_hash.Bind(SmiUntag(CallGetOrCreateHashRaw(key)));
    1702          56 :     Goto(&add_entry);
    1703             :   }
    1704             : 
    1705          56 :   BIND(&add_entry);
    1706         112 :   VARIABLE(number_of_buckets, MachineType::PointerRepresentation());
    1707         112 :   VARIABLE(occupancy, MachineType::PointerRepresentation());
    1708         112 :   TVARIABLE(OrderedHashSet, table_var, table);
    1709             :   {
    1710             :     // Check we have enough space for the entry.
    1711         168 :     number_of_buckets.Bind(SmiUntag(CAST(UnsafeLoadFixedArrayElement(
    1712         112 :         table, OrderedHashSet::NumberOfBucketsIndex()))));
    1713             : 
    1714             :     STATIC_ASSERT(OrderedHashSet::kLoadFactor == 2);
    1715          56 :     Node* const capacity = WordShl(number_of_buckets.value(), 1);
    1716         112 :     Node* const number_of_elements = SmiUntag(
    1717         168 :         CAST(LoadObjectField(table, OrderedHashSet::NumberOfElementsOffset())));
    1718         168 :     Node* const number_of_deleted = SmiUntag(CAST(LoadObjectField(
    1719         112 :         table, OrderedHashSet::NumberOfDeletedElementsOffset())));
    1720          56 :     occupancy.Bind(IntPtrAdd(number_of_elements, number_of_deleted));
    1721          56 :     GotoIf(IntPtrLessThan(occupancy.value(), capacity), &store_new_entry);
    1722             : 
    1723             :     // We do not have enough space, grow the table and reload the relevant
    1724             :     // fields.
    1725          56 :     CallRuntime(Runtime::kSetGrow, context, receiver);
    1726          56 :     table_var = CAST(LoadObjectField(receiver, JSMap::kTableOffset));
    1727         168 :     number_of_buckets.Bind(SmiUntag(CAST(UnsafeLoadFixedArrayElement(
    1728         112 :         table_var.value(), OrderedHashSet::NumberOfBucketsIndex()))));
    1729         168 :     Node* const new_number_of_elements = SmiUntag(CAST(LoadObjectField(
    1730         112 :         table_var.value(), OrderedHashSet::NumberOfElementsOffset())));
    1731         168 :     Node* const new_number_of_deleted = SmiUntag(CAST(LoadObjectField(
    1732         112 :         table_var.value(), OrderedHashSet::NumberOfDeletedElementsOffset())));
    1733          56 :     occupancy.Bind(IntPtrAdd(new_number_of_elements, new_number_of_deleted));
    1734          56 :     Goto(&store_new_entry);
    1735             :   }
    1736          56 :   BIND(&store_new_entry);
    1737             :   // Store the key, value and connect the element to the bucket chain.
    1738          56 :   StoreOrderedHashSetNewEntry(table_var.value(), key,
    1739             :                               entry_start_position_or_hash.value(),
    1740          56 :                               number_of_buckets.value(), occupancy.value());
    1741          56 :   Return(receiver);
    1742          56 : }
    1743             : 
    1744          56 : void CollectionsBuiltinsAssembler::StoreOrderedHashSetNewEntry(
    1745             :     TNode<OrderedHashSet> const table, Node* const key, Node* const hash,
    1746             :     Node* const number_of_buckets, Node* const occupancy) {
    1747             :   Node* const bucket =
    1748          56 :       WordAnd(hash, IntPtrSub(number_of_buckets, IntPtrConstant(1)));
    1749         112 :   Node* const bucket_entry = UnsafeLoadFixedArrayElement(
    1750         168 :       table, bucket, OrderedHashSet::HashTableStartIndex() * kTaggedSize);
    1751             : 
    1752             :   // Store the entry elements.
    1753         112 :   Node* const entry_start = IntPtrAdd(
    1754         112 :       IntPtrMul(occupancy, IntPtrConstant(OrderedHashSet::kEntrySize)),
    1755         280 :       number_of_buckets);
    1756         112 :   UnsafeStoreFixedArrayElement(
    1757             :       table, entry_start, key, UPDATE_WRITE_BARRIER,
    1758         112 :       kTaggedSize * OrderedHashSet::HashTableStartIndex());
    1759         112 :   UnsafeStoreFixedArrayElement(
    1760             :       table, entry_start, bucket_entry, SKIP_WRITE_BARRIER,
    1761          56 :       kTaggedSize * (OrderedHashSet::HashTableStartIndex() +
    1762          56 :                      OrderedHashSet::kChainOffset));
    1763             : 
    1764             :   // Update the bucket head.
    1765         168 :   UnsafeStoreFixedArrayElement(
    1766         112 :       table, bucket, SmiTag(occupancy), SKIP_WRITE_BARRIER,
    1767         112 :       OrderedHashSet::HashTableStartIndex() * kTaggedSize);
    1768             : 
    1769             :   // Bump the elements count.
    1770             :   TNode<Smi> const number_of_elements =
    1771          56 :       CAST(LoadObjectField(table, OrderedHashSet::NumberOfElementsOffset()));
    1772         112 :   StoreObjectFieldNoWriteBarrier(table,
    1773             :                                  OrderedHashSet::NumberOfElementsOffset(),
    1774          56 :                                  SmiAdd(number_of_elements, SmiConstant(1)));
    1775          56 : }
    1776             : 
    1777         392 : TF_BUILTIN(SetPrototypeDelete, CollectionsBuiltinsAssembler) {
    1778          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    1779          56 :   Node* key = Parameter(Descriptor::kKey);
    1780          56 :   Node* const context = Parameter(Descriptor::kContext);
    1781             : 
    1782          56 :   ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE,
    1783          56 :                          "Set.prototype.delete");
    1784             : 
    1785             :   TNode<OrderedHashSet> const table =
    1786          56 :       CAST(LoadObjectField(receiver, JSMap::kTableOffset));
    1787             : 
    1788         112 :   VARIABLE(entry_start_position_or_hash, MachineType::PointerRepresentation(),
    1789             :            IntPtrConstant(0));
    1790         112 :   Label entry_found(this), not_found(this);
    1791             : 
    1792          56 :   TryLookupOrderedHashTableIndex<OrderedHashSet>(table, key, context,
    1793             :                                                  &entry_start_position_or_hash,
    1794          56 :                                                  &entry_found, &not_found);
    1795             : 
    1796          56 :   BIND(&not_found);
    1797          56 :   Return(FalseConstant());
    1798             : 
    1799          56 :   BIND(&entry_found);
    1800             :   // If we found the entry, mark the entry as deleted.
    1801         168 :   StoreFixedArrayElement(table, entry_start_position_or_hash.value(),
    1802         112 :                          TheHoleConstant(), UPDATE_WRITE_BARRIER,
    1803         112 :                          kTaggedSize * OrderedHashSet::HashTableStartIndex());
    1804             : 
    1805             :   // Decrement the number of elements, increment the number of deleted elements.
    1806             :   TNode<Smi> const number_of_elements = SmiSub(
    1807         112 :       CAST(LoadObjectField(table, OrderedHashSet::NumberOfElementsOffset())),
    1808         112 :       SmiConstant(1));
    1809         112 :   StoreObjectFieldNoWriteBarrier(
    1810          56 :       table, OrderedHashSet::NumberOfElementsOffset(), number_of_elements);
    1811             :   TNode<Smi> const number_of_deleted =
    1812         112 :       SmiAdd(CAST(LoadObjectField(
    1813             :                  table, OrderedHashSet::NumberOfDeletedElementsOffset())),
    1814         112 :              SmiConstant(1));
    1815         112 :   StoreObjectFieldNoWriteBarrier(
    1816             :       table, OrderedHashSet::NumberOfDeletedElementsOffset(),
    1817          56 :       number_of_deleted);
    1818             : 
    1819          56 :   TNode<Smi> const number_of_buckets = CAST(
    1820             :       LoadFixedArrayElement(table, OrderedHashSet::NumberOfBucketsIndex()));
    1821             : 
    1822             :   // If there fewer elements than #buckets / 2, shrink the table.
    1823         112 :   Label shrink(this);
    1824         112 :   GotoIf(SmiLessThan(SmiAdd(number_of_elements, number_of_elements),
    1825          56 :                      number_of_buckets),
    1826          56 :          &shrink);
    1827          56 :   Return(TrueConstant());
    1828             : 
    1829          56 :   BIND(&shrink);
    1830          56 :   CallRuntime(Runtime::kSetShrink, context, receiver);
    1831          56 :   Return(TrueConstant());
    1832          56 : }
    1833             : 
    1834         336 : TF_BUILTIN(MapPrototypeEntries, CollectionsBuiltinsAssembler) {
    1835          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    1836          56 :   Node* const context = Parameter(Descriptor::kContext);
    1837          56 :   ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
    1838          56 :                          "Map.prototype.entries");
    1839         112 :   Return(AllocateJSCollectionIterator<JSMapIterator>(
    1840          56 :       context, Context::MAP_KEY_VALUE_ITERATOR_MAP_INDEX, receiver));
    1841          56 : }
    1842             : 
    1843         336 : TF_BUILTIN(MapPrototypeGetSize, CollectionsBuiltinsAssembler) {
    1844          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    1845          56 :   Node* const context = Parameter(Descriptor::kContext);
    1846          56 :   ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
    1847          56 :                          "get Map.prototype.size");
    1848          56 :   Node* const table = LoadObjectField(receiver, JSMap::kTableOffset);
    1849          56 :   Return(LoadObjectField(table, OrderedHashMap::NumberOfElementsOffset()));
    1850          56 : }
    1851             : 
    1852         336 : TF_BUILTIN(MapPrototypeForEach, CollectionsBuiltinsAssembler) {
    1853          56 :   const char* const kMethodName = "Map.prototype.forEach";
    1854          56 :   Node* const argc = Parameter(Descriptor::kJSActualArgumentsCount);
    1855          56 :   Node* const context = Parameter(Descriptor::kContext);
    1856          56 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
    1857          56 :   Node* const receiver = args.GetReceiver();
    1858          56 :   Node* const callback = args.GetOptionalArgumentValue(0);
    1859          56 :   Node* const this_arg = args.GetOptionalArgumentValue(1);
    1860             : 
    1861          56 :   ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, kMethodName);
    1862             : 
    1863             :   // Ensure that {callback} is actually callable.
    1864         112 :   Label callback_not_callable(this, Label::kDeferred);
    1865          56 :   GotoIf(TaggedIsSmi(callback), &callback_not_callable);
    1866          56 :   GotoIfNot(IsCallable(callback), &callback_not_callable);
    1867             : 
    1868         112 :   TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
    1869         112 :   TVARIABLE(OrderedHashMap, var_table,
    1870             :             CAST(LoadObjectField(receiver, JSMap::kTableOffset)));
    1871         112 :   Label loop(this, {&var_index, &var_table}), done_loop(this);
    1872          56 :   Goto(&loop);
    1873          56 :   BIND(&loop);
    1874             :   {
    1875             :     // Transition {table} and {index} if there was any modification to
    1876             :     // the {receiver} while we're iterating.
    1877          56 :     TNode<IntPtrT> index = var_index.value();
    1878          56 :     TNode<OrderedHashMap> table = var_table.value();
    1879         112 :     std::tie(table, index) =
    1880         224 :         Transition<OrderedHashMap>(table, index, [](Node*, Node*) {});
    1881             : 
    1882             :     // Read the next entry from the {table}, skipping holes.
    1883          56 :     TNode<Object> entry_key;
    1884          56 :     TNode<IntPtrT> entry_start_position;
    1885         112 :     std::tie(entry_key, entry_start_position, index) =
    1886         168 :         NextSkipHoles<OrderedHashMap>(table, index, &done_loop);
    1887             : 
    1888             :     // Load the entry value as well.
    1889         112 :     Node* entry_value = LoadFixedArrayElement(
    1890             :         table, entry_start_position,
    1891          56 :         (OrderedHashMap::HashTableStartIndex() + OrderedHashMap::kValueOffset) *
    1892         168 :             kTaggedSize);
    1893             : 
    1894             :     // Invoke the {callback} passing the {entry_key}, {entry_value} and the
    1895             :     // {receiver}.
    1896         112 :     CallJS(CodeFactory::Call(isolate()), context, callback, this_arg,
    1897          56 :            entry_value, entry_key, receiver);
    1898             : 
    1899             :     // Continue with the next entry.
    1900          56 :     var_index = index;
    1901          56 :     var_table = table;
    1902          56 :     Goto(&loop);
    1903             :   }
    1904             : 
    1905          56 :   BIND(&done_loop);
    1906          56 :   args.PopAndReturn(UndefinedConstant());
    1907             : 
    1908          56 :   BIND(&callback_not_callable);
    1909             :   {
    1910          56 :     CallRuntime(Runtime::kThrowCalledNonCallable, context, callback);
    1911          56 :     Unreachable();
    1912             :   }
    1913          56 : }
    1914             : 
    1915         336 : TF_BUILTIN(MapPrototypeKeys, CollectionsBuiltinsAssembler) {
    1916          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    1917          56 :   Node* const context = Parameter(Descriptor::kContext);
    1918          56 :   ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, "Map.prototype.keys");
    1919         112 :   Return(AllocateJSCollectionIterator<JSMapIterator>(
    1920          56 :       context, Context::MAP_KEY_ITERATOR_MAP_INDEX, receiver));
    1921          56 : }
    1922             : 
    1923         336 : TF_BUILTIN(MapPrototypeValues, CollectionsBuiltinsAssembler) {
    1924          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    1925          56 :   Node* const context = Parameter(Descriptor::kContext);
    1926          56 :   ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
    1927          56 :                          "Map.prototype.values");
    1928         112 :   Return(AllocateJSCollectionIterator<JSMapIterator>(
    1929          56 :       context, Context::MAP_VALUE_ITERATOR_MAP_INDEX, receiver));
    1930          56 : }
    1931             : 
    1932         336 : TF_BUILTIN(MapIteratorPrototypeNext, CollectionsBuiltinsAssembler) {
    1933          56 :   const char* const kMethodName = "Map Iterator.prototype.next";
    1934          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    1935          56 :   Node* const context = Parameter(Descriptor::kContext);
    1936             : 
    1937             :   // Ensure that the {receiver} is actually a JSMapIterator.
    1938         112 :   Label if_receiver_valid(this), if_receiver_invalid(this, Label::kDeferred);
    1939          56 :   GotoIf(TaggedIsSmi(receiver), &if_receiver_invalid);
    1940          56 :   Node* const receiver_instance_type = LoadInstanceType(receiver);
    1941         112 :   GotoIf(
    1942         112 :       InstanceTypeEqual(receiver_instance_type, JS_MAP_KEY_VALUE_ITERATOR_TYPE),
    1943          56 :       &if_receiver_valid);
    1944         112 :   GotoIf(InstanceTypeEqual(receiver_instance_type, JS_MAP_KEY_ITERATOR_TYPE),
    1945          56 :          &if_receiver_valid);
    1946         112 :   Branch(InstanceTypeEqual(receiver_instance_type, JS_MAP_VALUE_ITERATOR_TYPE),
    1947          56 :          &if_receiver_valid, &if_receiver_invalid);
    1948          56 :   BIND(&if_receiver_invalid);
    1949          56 :   ThrowTypeError(context, MessageTemplate::kIncompatibleMethodReceiver,
    1950         112 :                  StringConstant(kMethodName), receiver);
    1951          56 :   BIND(&if_receiver_valid);
    1952             : 
    1953             :   // Check if the {receiver} is exhausted.
    1954         112 :   VARIABLE(var_done, MachineRepresentation::kTagged, TrueConstant());
    1955         112 :   VARIABLE(var_value, MachineRepresentation::kTagged, UndefinedConstant());
    1956         112 :   Label return_value(this, {&var_done, &var_value}), return_entry(this),
    1957         112 :       return_end(this, Label::kDeferred);
    1958             : 
    1959             :   // Transition the {receiver} table if necessary.
    1960          56 :   TNode<OrderedHashMap> table;
    1961          56 :   TNode<IntPtrT> index;
    1962         112 :   std::tie(table, index) =
    1963         168 :       TransitionAndUpdate<JSMapIterator, OrderedHashMap>(CAST(receiver));
    1964             : 
    1965             :   // Read the next entry from the {table}, skipping holes.
    1966          56 :   TNode<Object> entry_key;
    1967          56 :   TNode<IntPtrT> entry_start_position;
    1968         112 :   std::tie(entry_key, entry_start_position, index) =
    1969         168 :       NextSkipHoles<OrderedHashMap>(table, index, &return_end);
    1970          56 :   StoreObjectFieldNoWriteBarrier(receiver, JSMapIterator::kIndexOffset,
    1971         112 :                                  SmiTag(index));
    1972          56 :   var_value.Bind(entry_key);
    1973          56 :   var_done.Bind(FalseConstant());
    1974             : 
    1975             :   // Check how to return the {key} (depending on {receiver} type).
    1976         112 :   GotoIf(InstanceTypeEqual(receiver_instance_type, JS_MAP_KEY_ITERATOR_TYPE),
    1977          56 :          &return_value);
    1978         112 :   var_value.Bind(LoadFixedArrayElement(
    1979             :       table, entry_start_position,
    1980          56 :       (OrderedHashMap::HashTableStartIndex() + OrderedHashMap::kValueOffset) *
    1981         168 :           kTaggedSize));
    1982         112 :   Branch(InstanceTypeEqual(receiver_instance_type, JS_MAP_VALUE_ITERATOR_TYPE),
    1983          56 :          &return_value, &return_entry);
    1984             : 
    1985          56 :   BIND(&return_entry);
    1986             :   {
    1987             :     Node* result =
    1988          56 :         AllocateJSIteratorResultForEntry(context, entry_key, var_value.value());
    1989          56 :     Return(result);
    1990             :   }
    1991             : 
    1992          56 :   BIND(&return_value);
    1993             :   {
    1994             :     Node* result =
    1995          56 :         AllocateJSIteratorResult(context, var_value.value(), var_done.value());
    1996          56 :     Return(result);
    1997             :   }
    1998             : 
    1999          56 :   BIND(&return_end);
    2000             :   {
    2001          56 :     StoreObjectFieldRoot(receiver, JSMapIterator::kTableOffset,
    2002          56 :                          RootIndex::kEmptyOrderedHashMap);
    2003          56 :     Goto(&return_value);
    2004             :   }
    2005          56 : }
    2006             : 
    2007         392 : TF_BUILTIN(SetPrototypeHas, CollectionsBuiltinsAssembler) {
    2008          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    2009          56 :   Node* const key = Parameter(Descriptor::kKey);
    2010          56 :   Node* const context = Parameter(Descriptor::kContext);
    2011             : 
    2012          56 :   ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE, "Set.prototype.has");
    2013             : 
    2014          56 :   Node* const table = LoadObjectField(receiver, JSMap::kTableOffset);
    2015             : 
    2016         112 :   VARIABLE(entry_start_position, MachineType::PointerRepresentation(),
    2017             :            IntPtrConstant(0));
    2018         112 :   VARIABLE(result, MachineRepresentation::kTaggedSigned, IntPtrConstant(0));
    2019         112 :   Label if_key_smi(this), if_key_string(this), if_key_heap_number(this),
    2020         112 :       if_key_bigint(this), entry_found(this), not_found(this), done(this);
    2021             : 
    2022          56 :   GotoIf(TaggedIsSmi(key), &if_key_smi);
    2023             : 
    2024          56 :   Node* key_map = LoadMap(key);
    2025          56 :   Node* key_instance_type = LoadMapInstanceType(key_map);
    2026             : 
    2027          56 :   GotoIf(IsStringInstanceType(key_instance_type), &if_key_string);
    2028          56 :   GotoIf(IsHeapNumberMap(key_map), &if_key_heap_number);
    2029          56 :   GotoIf(IsBigIntInstanceType(key_instance_type), &if_key_bigint);
    2030             : 
    2031          56 :   FindOrderedHashTableEntryForOtherKey<OrderedHashSet>(
    2032          56 :       context, table, key, &entry_start_position, &entry_found, &not_found);
    2033             : 
    2034          56 :   BIND(&if_key_smi);
    2035             :   {
    2036          56 :     FindOrderedHashTableEntryForSmiKey<OrderedHashSet>(
    2037          56 :         table, key, &entry_start_position, &entry_found, &not_found);
    2038             :   }
    2039             : 
    2040          56 :   BIND(&if_key_string);
    2041             :   {
    2042          56 :     FindOrderedHashTableEntryForStringKey<OrderedHashSet>(
    2043          56 :         context, table, key, &entry_start_position, &entry_found, &not_found);
    2044             :   }
    2045             : 
    2046          56 :   BIND(&if_key_heap_number);
    2047             :   {
    2048          56 :     FindOrderedHashTableEntryForHeapNumberKey<OrderedHashSet>(
    2049          56 :         context, table, key, &entry_start_position, &entry_found, &not_found);
    2050             :   }
    2051             : 
    2052          56 :   BIND(&if_key_bigint);
    2053             :   {
    2054          56 :     FindOrderedHashTableEntryForBigIntKey<OrderedHashSet>(
    2055          56 :         context, table, key, &entry_start_position, &entry_found, &not_found);
    2056             :   }
    2057             : 
    2058          56 :   BIND(&entry_found);
    2059          56 :   Return(TrueConstant());
    2060             : 
    2061          56 :   BIND(&not_found);
    2062          56 :   Return(FalseConstant());
    2063          56 : }
    2064             : 
    2065         336 : TF_BUILTIN(SetPrototypeEntries, CollectionsBuiltinsAssembler) {
    2066          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    2067          56 :   Node* const context = Parameter(Descriptor::kContext);
    2068          56 :   ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE,
    2069          56 :                          "Set.prototype.entries");
    2070         112 :   Return(AllocateJSCollectionIterator<JSSetIterator>(
    2071          56 :       context, Context::SET_KEY_VALUE_ITERATOR_MAP_INDEX, receiver));
    2072          56 : }
    2073             : 
    2074         336 : TF_BUILTIN(SetPrototypeGetSize, CollectionsBuiltinsAssembler) {
    2075          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    2076          56 :   Node* const context = Parameter(Descriptor::kContext);
    2077          56 :   ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE,
    2078          56 :                          "get Set.prototype.size");
    2079          56 :   Node* const table = LoadObjectField(receiver, JSSet::kTableOffset);
    2080          56 :   Return(LoadObjectField(table, OrderedHashSet::NumberOfElementsOffset()));
    2081          56 : }
    2082             : 
    2083         336 : TF_BUILTIN(SetPrototypeForEach, CollectionsBuiltinsAssembler) {
    2084          56 :   const char* const kMethodName = "Set.prototype.forEach";
    2085          56 :   Node* const argc = Parameter(Descriptor::kJSActualArgumentsCount);
    2086          56 :   Node* const context = Parameter(Descriptor::kContext);
    2087          56 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
    2088          56 :   Node* const receiver = args.GetReceiver();
    2089          56 :   Node* const callback = args.GetOptionalArgumentValue(0);
    2090          56 :   Node* const this_arg = args.GetOptionalArgumentValue(1);
    2091             : 
    2092          56 :   ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE, kMethodName);
    2093             : 
    2094             :   // Ensure that {callback} is actually callable.
    2095         112 :   Label callback_not_callable(this, Label::kDeferred);
    2096          56 :   GotoIf(TaggedIsSmi(callback), &callback_not_callable);
    2097          56 :   GotoIfNot(IsCallable(callback), &callback_not_callable);
    2098             : 
    2099         112 :   TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
    2100         112 :   TVARIABLE(OrderedHashSet, var_table,
    2101             :             CAST(LoadObjectField(receiver, JSSet::kTableOffset)));
    2102         112 :   Label loop(this, {&var_index, &var_table}), done_loop(this);
    2103          56 :   Goto(&loop);
    2104          56 :   BIND(&loop);
    2105             :   {
    2106             :     // Transition {table} and {index} if there was any modification to
    2107             :     // the {receiver} while we're iterating.
    2108          56 :     TNode<IntPtrT> index = var_index.value();
    2109          56 :     TNode<OrderedHashSet> table = var_table.value();
    2110         112 :     std::tie(table, index) =
    2111         224 :         Transition<OrderedHashSet>(table, index, [](Node*, Node*) {});
    2112             : 
    2113             :     // Read the next entry from the {table}, skipping holes.
    2114             :     Node* entry_key;
    2115             :     Node* entry_start_position;
    2116         112 :     std::tie(entry_key, entry_start_position, index) =
    2117         168 :         NextSkipHoles<OrderedHashSet>(table, index, &done_loop);
    2118             : 
    2119             :     // Invoke the {callback} passing the {entry_key} (twice) and the {receiver}.
    2120         112 :     CallJS(CodeFactory::Call(isolate()), context, callback, this_arg, entry_key,
    2121         112 :            entry_key, receiver);
    2122             : 
    2123             :     // Continue with the next entry.
    2124          56 :     var_index = index;
    2125          56 :     var_table = table;
    2126          56 :     Goto(&loop);
    2127             :   }
    2128             : 
    2129          56 :   BIND(&done_loop);
    2130          56 :   args.PopAndReturn(UndefinedConstant());
    2131             : 
    2132          56 :   BIND(&callback_not_callable);
    2133             :   {
    2134          56 :     CallRuntime(Runtime::kThrowCalledNonCallable, context, callback);
    2135          56 :     Unreachable();
    2136             :   }
    2137          56 : }
    2138             : 
    2139         336 : TF_BUILTIN(SetPrototypeValues, CollectionsBuiltinsAssembler) {
    2140          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    2141          56 :   Node* const context = Parameter(Descriptor::kContext);
    2142          56 :   ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE,
    2143          56 :                          "Set.prototype.values");
    2144         112 :   Return(AllocateJSCollectionIterator<JSSetIterator>(
    2145          56 :       context, Context::SET_VALUE_ITERATOR_MAP_INDEX, receiver));
    2146          56 : }
    2147             : 
    2148         336 : TF_BUILTIN(SetIteratorPrototypeNext, CollectionsBuiltinsAssembler) {
    2149          56 :   const char* const kMethodName = "Set Iterator.prototype.next";
    2150          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    2151          56 :   Node* const context = Parameter(Descriptor::kContext);
    2152             : 
    2153             :   // Ensure that the {receiver} is actually a JSSetIterator.
    2154         112 :   Label if_receiver_valid(this), if_receiver_invalid(this, Label::kDeferred);
    2155          56 :   GotoIf(TaggedIsSmi(receiver), &if_receiver_invalid);
    2156          56 :   Node* const receiver_instance_type = LoadInstanceType(receiver);
    2157         112 :   GotoIf(InstanceTypeEqual(receiver_instance_type, JS_SET_VALUE_ITERATOR_TYPE),
    2158          56 :          &if_receiver_valid);
    2159         112 :   Branch(
    2160         112 :       InstanceTypeEqual(receiver_instance_type, JS_SET_KEY_VALUE_ITERATOR_TYPE),
    2161          56 :       &if_receiver_valid, &if_receiver_invalid);
    2162          56 :   BIND(&if_receiver_invalid);
    2163          56 :   ThrowTypeError(context, MessageTemplate::kIncompatibleMethodReceiver,
    2164         112 :                  StringConstant(kMethodName), receiver);
    2165          56 :   BIND(&if_receiver_valid);
    2166             : 
    2167             :   // Check if the {receiver} is exhausted.
    2168         112 :   VARIABLE(var_done, MachineRepresentation::kTagged, TrueConstant());
    2169         112 :   VARIABLE(var_value, MachineRepresentation::kTagged, UndefinedConstant());
    2170         112 :   Label return_value(this, {&var_done, &var_value}), return_entry(this),
    2171         112 :       return_end(this, Label::kDeferred);
    2172             : 
    2173             :   // Transition the {receiver} table if necessary.
    2174          56 :   TNode<OrderedHashSet> table;
    2175          56 :   TNode<IntPtrT> index;
    2176         112 :   std::tie(table, index) =
    2177         168 :       TransitionAndUpdate<JSSetIterator, OrderedHashSet>(CAST(receiver));
    2178             : 
    2179             :   // Read the next entry from the {table}, skipping holes.
    2180             :   Node* entry_key;
    2181             :   Node* entry_start_position;
    2182         112 :   std::tie(entry_key, entry_start_position, index) =
    2183         168 :       NextSkipHoles<OrderedHashSet>(table, index, &return_end);
    2184          56 :   StoreObjectFieldNoWriteBarrier(receiver, JSSetIterator::kIndexOffset,
    2185         112 :                                  SmiTag(index));
    2186          56 :   var_value.Bind(entry_key);
    2187          56 :   var_done.Bind(FalseConstant());
    2188             : 
    2189             :   // Check how to return the {key} (depending on {receiver} type).
    2190         112 :   Branch(InstanceTypeEqual(receiver_instance_type, JS_SET_VALUE_ITERATOR_TYPE),
    2191          56 :          &return_value, &return_entry);
    2192             : 
    2193          56 :   BIND(&return_entry);
    2194             :   {
    2195          56 :     Node* result = AllocateJSIteratorResultForEntry(context, var_value.value(),
    2196          56 :                                                     var_value.value());
    2197          56 :     Return(result);
    2198             :   }
    2199             : 
    2200          56 :   BIND(&return_value);
    2201             :   {
    2202             :     Node* result =
    2203          56 :         AllocateJSIteratorResult(context, var_value.value(), var_done.value());
    2204          56 :     Return(result);
    2205             :   }
    2206             : 
    2207          56 :   BIND(&return_end);
    2208             :   {
    2209          56 :     StoreObjectFieldRoot(receiver, JSSetIterator::kTableOffset,
    2210          56 :                          RootIndex::kEmptyOrderedHashSet);
    2211          56 :     Goto(&return_value);
    2212             :   }
    2213          56 : }
    2214             : 
    2215             : template <typename CollectionType>
    2216         280 : void CollectionsBuiltinsAssembler::TryLookupOrderedHashTableIndex(
    2217             :     Node* const table, Node* const key, Node* const context, Variable* result,
    2218             :     Label* if_entry_found, Label* if_not_found) {
    2219         560 :   Label if_key_smi(this), if_key_string(this), if_key_heap_number(this),
    2220         560 :       if_key_bigint(this);
    2221             : 
    2222         280 :   GotoIf(TaggedIsSmi(key), &if_key_smi);
    2223             : 
    2224         280 :   Node* key_map = LoadMap(key);
    2225         280 :   Node* key_instance_type = LoadMapInstanceType(key_map);
    2226             : 
    2227         280 :   GotoIf(IsStringInstanceType(key_instance_type), &if_key_string);
    2228         280 :   GotoIf(IsHeapNumberMap(key_map), &if_key_heap_number);
    2229         280 :   GotoIf(IsBigIntInstanceType(key_instance_type), &if_key_bigint);
    2230             : 
    2231         280 :   FindOrderedHashTableEntryForOtherKey<CollectionType>(
    2232             :       context, table, key, result, if_entry_found, if_not_found);
    2233             : 
    2234         280 :   BIND(&if_key_smi);
    2235             :   {
    2236         280 :     FindOrderedHashTableEntryForSmiKey<CollectionType>(
    2237             :         table, key, result, if_entry_found, if_not_found);
    2238             :   }
    2239             : 
    2240         280 :   BIND(&if_key_string);
    2241             :   {
    2242         280 :     FindOrderedHashTableEntryForStringKey<CollectionType>(
    2243             :         context, table, key, result, if_entry_found, if_not_found);
    2244             :   }
    2245             : 
    2246         280 :   BIND(&if_key_heap_number);
    2247             :   {
    2248         280 :     FindOrderedHashTableEntryForHeapNumberKey<CollectionType>(
    2249             :         context, table, key, result, if_entry_found, if_not_found);
    2250             :   }
    2251             : 
    2252         280 :   BIND(&if_key_bigint);
    2253             :   {
    2254         280 :     FindOrderedHashTableEntryForBigIntKey<CollectionType>(
    2255             :         context, table, key, result, if_entry_found, if_not_found);
    2256             :   }
    2257         280 : }
    2258             : 
    2259         392 : TF_BUILTIN(FindOrderedHashMapEntry, CollectionsBuiltinsAssembler) {
    2260          56 :   Node* const table = Parameter(Descriptor::kTable);
    2261          56 :   Node* const key = Parameter(Descriptor::kKey);
    2262          56 :   Node* const context = Parameter(Descriptor::kContext);
    2263             : 
    2264         112 :   VARIABLE(entry_start_position, MachineType::PointerRepresentation(),
    2265             :            IntPtrConstant(0));
    2266         112 :   Label entry_found(this), not_found(this);
    2267             : 
    2268          56 :   TryLookupOrderedHashTableIndex<OrderedHashMap>(
    2269          56 :       table, key, context, &entry_start_position, &entry_found, &not_found);
    2270             : 
    2271          56 :   BIND(&entry_found);
    2272          56 :   Return(SmiTag(entry_start_position.value()));
    2273             : 
    2274          56 :   BIND(&not_found);
    2275          56 :   Return(SmiConstant(-1));
    2276          56 : }
    2277             : 
    2278         560 : class WeakCollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
    2279             :  public:
    2280         560 :   explicit WeakCollectionsBuiltinsAssembler(compiler::CodeAssemblerState* state)
    2281         560 :       : BaseCollectionsAssembler(state) {}
    2282             : 
    2283             :  protected:
    2284             :   void AddEntry(TNode<EphemeronHashTable> table, TNode<IntPtrT> key_index,
    2285             :                 TNode<Object> key, TNode<Object> value,
    2286             :                 TNode<IntPtrT> number_of_elements);
    2287             : 
    2288             :   TNode<Object> AllocateTable(Variant variant, TNode<Context> context,
    2289             :                               TNode<IntPtrT> at_least_space_for) override;
    2290             : 
    2291             :   // Generates and sets the identity for a JSRececiver.
    2292             :   TNode<Smi> CreateIdentityHash(TNode<Object> receiver);
    2293             :   TNode<IntPtrT> EntryMask(TNode<IntPtrT> capacity);
    2294             : 
    2295             :   // Builds code that finds the EphemeronHashTable entry for a {key} using the
    2296             :   // comparison code generated by {key_compare}. The key index is returned if
    2297             :   // the {key} is found.
    2298             :   typedef std::function<void(TNode<Object> entry_key, Label* if_same)>
    2299             :       KeyComparator;
    2300             :   TNode<IntPtrT> FindKeyIndex(TNode<HeapObject> table, TNode<IntPtrT> key_hash,
    2301             :                               TNode<IntPtrT> entry_mask,
    2302             :                               const KeyComparator& key_compare);
    2303             : 
    2304             :   // Builds code that finds an EphemeronHashTable entry available for a new
    2305             :   // entry.
    2306             :   TNode<IntPtrT> FindKeyIndexForInsertion(TNode<HeapObject> table,
    2307             :                                           TNode<IntPtrT> key_hash,
    2308             :                                           TNode<IntPtrT> entry_mask);
    2309             : 
    2310             :   // Builds code that finds the EphemeronHashTable entry with key that matches
    2311             :   // {key} and returns the entry's key index. If {key} cannot be found, jumps to
    2312             :   // {if_not_found}.
    2313             :   TNode<IntPtrT> FindKeyIndexForKey(TNode<HeapObject> table, TNode<Object> key,
    2314             :                                     TNode<IntPtrT> hash,
    2315             :                                     TNode<IntPtrT> entry_mask,
    2316             :                                     Label* if_not_found);
    2317             : 
    2318             :   TNode<Word32T> InsufficientCapacityToAdd(TNode<IntPtrT> capacity,
    2319             :                                            TNode<IntPtrT> number_of_elements,
    2320             :                                            TNode<IntPtrT> number_of_deleted);
    2321             :   TNode<IntPtrT> KeyIndexFromEntry(TNode<IntPtrT> entry);
    2322             : 
    2323             :   TNode<IntPtrT> LoadNumberOfElements(TNode<EphemeronHashTable> table,
    2324             :                                       int offset);
    2325             :   TNode<IntPtrT> LoadNumberOfDeleted(TNode<EphemeronHashTable> table,
    2326             :                                      int offset = 0);
    2327             :   TNode<EphemeronHashTable> LoadTable(TNode<JSWeakCollection> collection);
    2328             :   TNode<IntPtrT> LoadTableCapacity(TNode<EphemeronHashTable> table);
    2329             : 
    2330             :   void RemoveEntry(TNode<EphemeronHashTable> table, TNode<IntPtrT> key_index,
    2331             :                    TNode<IntPtrT> number_of_elements);
    2332             :   TNode<BoolT> ShouldRehash(TNode<IntPtrT> number_of_elements,
    2333             :                             TNode<IntPtrT> number_of_deleted);
    2334             :   TNode<Word32T> ShouldShrink(TNode<IntPtrT> capacity,
    2335             :                               TNode<IntPtrT> number_of_elements);
    2336             :   TNode<IntPtrT> ValueIndexFromKeyIndex(TNode<IntPtrT> key_index);
    2337             : };
    2338             : 
    2339          56 : void WeakCollectionsBuiltinsAssembler::AddEntry(
    2340             :     TNode<EphemeronHashTable> table, TNode<IntPtrT> key_index,
    2341             :     TNode<Object> key, TNode<Object> value, TNode<IntPtrT> number_of_elements) {
    2342             :   // See EphemeronHashTable::AddEntry().
    2343          56 :   TNode<IntPtrT> value_index = ValueIndexFromKeyIndex(key_index);
    2344          56 :   UnsafeStoreFixedArrayElement(table, key_index, key);
    2345          56 :   UnsafeStoreFixedArrayElement(table, value_index, value);
    2346             : 
    2347             :   // See HashTableBase::ElementAdded().
    2348         112 :   UnsafeStoreFixedArrayElement(
    2349             :       table, EphemeronHashTable::kNumberOfElementsIndex,
    2350         168 :       SmiFromIntPtr(number_of_elements), SKIP_WRITE_BARRIER);
    2351          56 : }
    2352             : 
    2353         112 : TNode<Object> WeakCollectionsBuiltinsAssembler::AllocateTable(
    2354             :     Variant variant, TNode<Context> context,
    2355             :     TNode<IntPtrT> at_least_space_for) {
    2356             :   // See HashTable::New().
    2357             :   CSA_ASSERT(this,
    2358             :              IntPtrLessThanOrEqual(IntPtrConstant(0), at_least_space_for));
    2359         112 :   TNode<IntPtrT> capacity = HashTableComputeCapacity(at_least_space_for);
    2360             : 
    2361             :   // See HashTable::NewInternal().
    2362         112 :   TNode<IntPtrT> length = KeyIndexFromEntry(capacity);
    2363         112 :   TNode<FixedArray> table = CAST(
    2364             :       AllocateFixedArray(HOLEY_ELEMENTS, length, kAllowLargeObjectAllocation));
    2365             : 
    2366         112 :   RootIndex map_root_index = EphemeronHashTableShape::GetMapRootIndex();
    2367         112 :   StoreMapNoWriteBarrier(table, map_root_index);
    2368         224 :   StoreFixedArrayElement(table, EphemeronHashTable::kNumberOfElementsIndex,
    2369         336 :                          SmiConstant(0), SKIP_WRITE_BARRIER);
    2370         224 :   StoreFixedArrayElement(table,
    2371             :                          EphemeronHashTable::kNumberOfDeletedElementsIndex,
    2372         336 :                          SmiConstant(0), SKIP_WRITE_BARRIER);
    2373         224 :   StoreFixedArrayElement(table, EphemeronHashTable::kCapacityIndex,
    2374         336 :                          SmiFromIntPtr(capacity), SKIP_WRITE_BARRIER);
    2375             : 
    2376         112 :   TNode<IntPtrT> start = KeyIndexFromEntry(IntPtrConstant(0));
    2377         112 :   FillFixedArrayWithValue(HOLEY_ELEMENTS, table, start, length,
    2378         112 :                           RootIndex::kUndefinedValue);
    2379         112 :   return table;
    2380             : }
    2381             : 
    2382          56 : TNode<Smi> WeakCollectionsBuiltinsAssembler::CreateIdentityHash(
    2383             :     TNode<Object> key) {
    2384             :   TNode<ExternalReference> function_addr =
    2385          56 :       ExternalConstant(ExternalReference::jsreceiver_create_identity_hash());
    2386             :   TNode<ExternalReference> isolate_ptr =
    2387          56 :       ExternalConstant(ExternalReference::isolate_address(isolate()));
    2388             : 
    2389          56 :   MachineType type_ptr = MachineType::Pointer();
    2390          56 :   MachineType type_tagged = MachineType::AnyTagged();
    2391             : 
    2392          56 :   return CAST(CallCFunction2(type_tagged, type_ptr, type_tagged, function_addr,
    2393             :                              isolate_ptr, key));
    2394             : }
    2395             : 
    2396         168 : TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::EntryMask(
    2397             :     TNode<IntPtrT> capacity) {
    2398         168 :   return IntPtrSub(capacity, IntPtrConstant(1));
    2399             : }
    2400             : 
    2401         224 : TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::FindKeyIndex(
    2402             :     TNode<HeapObject> table, TNode<IntPtrT> key_hash, TNode<IntPtrT> entry_mask,
    2403             :     const KeyComparator& key_compare) {
    2404             :   // See HashTable::FirstProbe().
    2405         448 :   TVARIABLE(IntPtrT, var_entry, WordAnd(key_hash, entry_mask));
    2406         448 :   TVARIABLE(IntPtrT, var_count, IntPtrConstant(0));
    2407             : 
    2408         224 :   Variable* loop_vars[] = {&var_count, &var_entry};
    2409         448 :   Label loop(this, arraysize(loop_vars), loop_vars), if_found(this);
    2410         224 :   Goto(&loop);
    2411         224 :   BIND(&loop);
    2412         224 :   TNode<IntPtrT> key_index;
    2413             :   {
    2414         224 :     key_index = KeyIndexFromEntry(var_entry.value());
    2415             :     TNode<Object> entry_key =
    2416         224 :         UnsafeLoadFixedArrayElement(CAST(table), key_index);
    2417             : 
    2418         224 :     key_compare(entry_key, &if_found);
    2419             : 
    2420             :     // See HashTable::NextProbe().
    2421         224 :     Increment(&var_count);
    2422         224 :     var_entry =
    2423         224 :         WordAnd(IntPtrAdd(var_entry.value(), var_count.value()), entry_mask);
    2424         224 :     Goto(&loop);
    2425             :   }
    2426             : 
    2427         224 :   BIND(&if_found);
    2428         448 :   return key_index;
    2429             : }
    2430             : 
    2431          56 : TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::FindKeyIndexForInsertion(
    2432             :     TNode<HeapObject> table, TNode<IntPtrT> key_hash,
    2433             :     TNode<IntPtrT> entry_mask) {
    2434             :   // See HashTable::FindInsertionEntry().
    2435          56 :   auto is_not_live = [&](TNode<Object> entry_key, Label* if_found) {
    2436             :     // This is the the negative form BaseShape::IsLive().
    2437          56 :     GotoIf(Word32Or(IsTheHole(entry_key), IsUndefined(entry_key)), if_found);
    2438         112 :   };
    2439          56 :   return FindKeyIndex(table, key_hash, entry_mask, is_not_live);
    2440             : }
    2441             : 
    2442         168 : TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::FindKeyIndexForKey(
    2443             :     TNode<HeapObject> table, TNode<Object> key, TNode<IntPtrT> hash,
    2444             :     TNode<IntPtrT> entry_mask, Label* if_not_found) {
    2445             :   // See HashTable::FindEntry().
    2446             :   auto match_key_or_exit_on_empty = [&](TNode<Object> entry_key,
    2447         168 :                                         Label* if_same) {
    2448         504 :     GotoIf(IsUndefined(entry_key), if_not_found);
    2449         504 :     GotoIf(WordEqual(entry_key, key), if_same);
    2450         336 :   };
    2451         168 :   return FindKeyIndex(table, hash, entry_mask, match_key_or_exit_on_empty);
    2452             : }
    2453             : 
    2454         448 : TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::KeyIndexFromEntry(
    2455             :     TNode<IntPtrT> entry) {
    2456             :   // See HashTable::KeyAt().
    2457             :   // (entry * kEntrySize) + kElementsStartIndex + kEntryKeyIndex
    2458             :   return IntPtrAdd(
    2459             :       IntPtrMul(entry, IntPtrConstant(EphemeronHashTable::kEntrySize)),
    2460             :       IntPtrConstant(EphemeronHashTable::kElementsStartIndex +
    2461         448 :                      EphemeronHashTable::kEntryKeyIndex));
    2462             : }
    2463             : 
    2464         112 : TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::LoadNumberOfElements(
    2465             :     TNode<EphemeronHashTable> table, int offset) {
    2466         224 :   TNode<IntPtrT> number_of_elements = SmiUntag(CAST(UnsafeLoadFixedArrayElement(
    2467         112 :       table, EphemeronHashTable::kNumberOfElementsIndex)));
    2468         112 :   return IntPtrAdd(number_of_elements, IntPtrConstant(offset));
    2469             : }
    2470             : 
    2471         112 : TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::LoadNumberOfDeleted(
    2472             :     TNode<EphemeronHashTable> table, int offset) {
    2473         224 :   TNode<IntPtrT> number_of_deleted = SmiUntag(CAST(UnsafeLoadFixedArrayElement(
    2474         112 :       table, EphemeronHashTable::kNumberOfDeletedElementsIndex)));
    2475         112 :   return IntPtrAdd(number_of_deleted, IntPtrConstant(offset));
    2476             : }
    2477             : 
    2478         280 : TNode<EphemeronHashTable> WeakCollectionsBuiltinsAssembler::LoadTable(
    2479             :     TNode<JSWeakCollection> collection) {
    2480         280 :   return CAST(LoadObjectField(collection, JSWeakCollection::kTableOffset));
    2481             : }
    2482             : 
    2483         168 : TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::LoadTableCapacity(
    2484             :     TNode<EphemeronHashTable> table) {
    2485         336 :   return SmiUntag(CAST(
    2486         336 :       UnsafeLoadFixedArrayElement(table, EphemeronHashTable::kCapacityIndex)));
    2487             : }
    2488             : 
    2489          56 : TNode<Word32T> WeakCollectionsBuiltinsAssembler::InsufficientCapacityToAdd(
    2490             :     TNode<IntPtrT> capacity, TNode<IntPtrT> number_of_elements,
    2491             :     TNode<IntPtrT> number_of_deleted) {
    2492             :   // This is the negative form of HashTable::HasSufficientCapacityToAdd().
    2493             :   // Return true if:
    2494             :   //   - more than 50% of the available space are deleted elements
    2495             :   //   - less than 50% will be available
    2496          56 :   TNode<IntPtrT> available = IntPtrSub(capacity, number_of_elements);
    2497          56 :   TNode<IntPtrT> half_available = WordShr(available, 1);
    2498          56 :   TNode<IntPtrT> needed_available = WordShr(number_of_elements, 1);
    2499             :   return Word32Or(
    2500             :       // deleted > half
    2501         112 :       IntPtrGreaterThan(number_of_deleted, half_available),
    2502             :       // elements + needed available > capacity
    2503         224 :       IntPtrGreaterThan(IntPtrAdd(number_of_elements, needed_available),
    2504         392 :                         capacity));
    2505             : }
    2506             : 
    2507          56 : void WeakCollectionsBuiltinsAssembler::RemoveEntry(
    2508             :     TNode<EphemeronHashTable> table, TNode<IntPtrT> key_index,
    2509             :     TNode<IntPtrT> number_of_elements) {
    2510             :   // See EphemeronHashTable::RemoveEntry().
    2511          56 :   TNode<IntPtrT> value_index = ValueIndexFromKeyIndex(key_index);
    2512          56 :   StoreFixedArrayElement(table, key_index, TheHoleConstant());
    2513          56 :   StoreFixedArrayElement(table, value_index, TheHoleConstant());
    2514             : 
    2515             :   // See HashTableBase::ElementRemoved().
    2516          56 :   TNode<IntPtrT> number_of_deleted = LoadNumberOfDeleted(table, 1);
    2517         112 :   StoreFixedArrayElement(table, EphemeronHashTable::kNumberOfElementsIndex,
    2518         168 :                          SmiFromIntPtr(number_of_elements), SKIP_WRITE_BARRIER);
    2519         112 :   StoreFixedArrayElement(table,
    2520             :                          EphemeronHashTable::kNumberOfDeletedElementsIndex,
    2521         168 :                          SmiFromIntPtr(number_of_deleted), SKIP_WRITE_BARRIER);
    2522          56 : }
    2523             : 
    2524          56 : TNode<BoolT> WeakCollectionsBuiltinsAssembler::ShouldRehash(
    2525             :     TNode<IntPtrT> number_of_elements, TNode<IntPtrT> number_of_deleted) {
    2526             :   // Rehash if more than 33% of the entries are deleted.
    2527         112 :   return IntPtrGreaterThanOrEqual(WordShl(number_of_deleted, 1),
    2528         168 :                                   number_of_elements);
    2529             : }
    2530             : 
    2531          56 : TNode<Word32T> WeakCollectionsBuiltinsAssembler::ShouldShrink(
    2532             :     TNode<IntPtrT> capacity, TNode<IntPtrT> number_of_elements) {
    2533             :   // See HashTable::Shrink().
    2534          56 :   TNode<IntPtrT> quarter_capacity = WordShr(capacity, 2);
    2535             :   return Word32And(
    2536             :       // Shrink to fit the number of elements if only a quarter of the
    2537             :       // capacity is filled with elements.
    2538         112 :       IntPtrLessThanOrEqual(number_of_elements, quarter_capacity),
    2539             : 
    2540             :       // Allocate a new dictionary with room for at least the current
    2541             :       // number of elements. The allocation method will make sure that
    2542             :       // there is extra room in the dictionary for additions. Don't go
    2543             :       // lower than room for 16 elements.
    2544         168 :       IntPtrGreaterThanOrEqual(number_of_elements, IntPtrConstant(16)));
    2545             : }
    2546             : 
    2547         224 : TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::ValueIndexFromKeyIndex(
    2548             :     TNode<IntPtrT> key_index) {
    2549             :   return IntPtrAdd(key_index,
    2550             :                    IntPtrConstant(EphemeronHashTableShape::kEntryValueIndex -
    2551         224 :                                   EphemeronHashTable::kEntryKeyIndex));
    2552             : }
    2553             : 
    2554         392 : TF_BUILTIN(WeakMapConstructor, WeakCollectionsBuiltinsAssembler) {
    2555          56 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
    2556             :   TNode<IntPtrT> argc =
    2557          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    2558          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2559             : 
    2560          56 :   GenerateConstructor(kWeakMap, isolate()->factory()->WeakMap_string(),
    2561          56 :                       new_target, argc, context);
    2562          56 : }
    2563             : 
    2564         392 : TF_BUILTIN(WeakSetConstructor, WeakCollectionsBuiltinsAssembler) {
    2565          56 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
    2566             :   TNode<IntPtrT> argc =
    2567          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    2568          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2569             : 
    2570          56 :   GenerateConstructor(kWeakSet, isolate()->factory()->WeakSet_string(),
    2571          56 :                       new_target, argc, context);
    2572          56 : }
    2573             : 
    2574         336 : TF_BUILTIN(WeakMapLookupHashIndex, WeakCollectionsBuiltinsAssembler) {
    2575          56 :   TNode<EphemeronHashTable> table = CAST(Parameter(Descriptor::kTable));
    2576          56 :   TNode<Object> key = CAST(Parameter(Descriptor::kKey));
    2577             : 
    2578         112 :   Label if_not_found(this);
    2579             : 
    2580          56 :   GotoIfNotJSReceiver(key, &if_not_found);
    2581             : 
    2582          56 :   TNode<IntPtrT> hash = LoadJSReceiverIdentityHash(key, &if_not_found);
    2583          56 :   TNode<IntPtrT> capacity = LoadTableCapacity(table);
    2584             :   TNode<IntPtrT> key_index =
    2585          56 :       FindKeyIndexForKey(table, key, hash, EntryMask(capacity), &if_not_found);
    2586          56 :   Return(SmiTag(ValueIndexFromKeyIndex(key_index)));
    2587             : 
    2588          56 :   BIND(&if_not_found);
    2589          56 :   Return(SmiConstant(-1));
    2590          56 : }
    2591             : 
    2592         392 : TF_BUILTIN(WeakMapGet, WeakCollectionsBuiltinsAssembler) {
    2593          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    2594          56 :   Node* const key = Parameter(Descriptor::kKey);
    2595          56 :   Node* const context = Parameter(Descriptor::kContext);
    2596             : 
    2597         112 :   Label return_undefined(this);
    2598             : 
    2599          56 :   ThrowIfNotInstanceType(context, receiver, JS_WEAK_MAP_TYPE,
    2600          56 :                          "WeakMap.prototype.get");
    2601             : 
    2602          56 :   TNode<EphemeronHashTable> const table = LoadTable(CAST(receiver));
    2603             :   TNode<Smi> const index =
    2604          56 :       CAST(CallBuiltin(Builtins::kWeakMapLookupHashIndex, context, table, key));
    2605             : 
    2606          56 :   GotoIf(WordEqual(index, SmiConstant(-1)), &return_undefined);
    2607             : 
    2608          56 :   Return(LoadFixedArrayElement(table, SmiUntag(index)));
    2609             : 
    2610          56 :   BIND(&return_undefined);
    2611          56 :   Return(UndefinedConstant());
    2612          56 : }
    2613             : 
    2614         392 : TF_BUILTIN(WeakMapPrototypeHas, WeakCollectionsBuiltinsAssembler) {
    2615          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    2616          56 :   Node* const key = Parameter(Descriptor::kKey);
    2617          56 :   Node* const context = Parameter(Descriptor::kContext);
    2618             : 
    2619         112 :   Label return_false(this);
    2620             : 
    2621          56 :   ThrowIfNotInstanceType(context, receiver, JS_WEAK_MAP_TYPE,
    2622          56 :                          "WeakMap.prototype.has");
    2623             : 
    2624          56 :   TNode<EphemeronHashTable> const table = LoadTable(CAST(receiver));
    2625             :   Node* const index =
    2626          56 :       CallBuiltin(Builtins::kWeakMapLookupHashIndex, context, table, key);
    2627             : 
    2628          56 :   GotoIf(WordEqual(index, SmiConstant(-1)), &return_false);
    2629             : 
    2630          56 :   Return(TrueConstant());
    2631             : 
    2632          56 :   BIND(&return_false);
    2633          56 :   Return(FalseConstant());
    2634          56 : }
    2635             : 
    2636             : // Helper that removes the entry with a given key from the backing store
    2637             : // (EphemeronHashTable) of a WeakMap or WeakSet.
    2638         392 : TF_BUILTIN(WeakCollectionDelete, WeakCollectionsBuiltinsAssembler) {
    2639          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2640          56 :   TNode<JSWeakCollection> collection = CAST(Parameter(Descriptor::kCollection));
    2641          56 :   TNode<Object> key = CAST(Parameter(Descriptor::kKey));
    2642             : 
    2643         112 :   Label call_runtime(this), if_not_found(this);
    2644             : 
    2645          56 :   GotoIfNotJSReceiver(key, &if_not_found);
    2646             : 
    2647          56 :   TNode<IntPtrT> hash = LoadJSReceiverIdentityHash(key, &if_not_found);
    2648          56 :   TNode<EphemeronHashTable> table = LoadTable(collection);
    2649          56 :   TNode<IntPtrT> capacity = LoadTableCapacity(table);
    2650             :   TNode<IntPtrT> key_index =
    2651          56 :       FindKeyIndexForKey(table, key, hash, EntryMask(capacity), &if_not_found);
    2652          56 :   TNode<IntPtrT> number_of_elements = LoadNumberOfElements(table, -1);
    2653          56 :   GotoIf(ShouldShrink(capacity, number_of_elements), &call_runtime);
    2654             : 
    2655          56 :   RemoveEntry(table, key_index, number_of_elements);
    2656          56 :   Return(TrueConstant());
    2657             : 
    2658          56 :   BIND(&if_not_found);
    2659          56 :   Return(FalseConstant());
    2660             : 
    2661          56 :   BIND(&call_runtime);
    2662         112 :   Return(CallRuntime(Runtime::kWeakCollectionDelete, context, collection, key,
    2663         168 :                      SmiTag(hash)));
    2664          56 : }
    2665             : 
    2666             : // Helper that sets the key and value to the backing store (EphemeronHashTable)
    2667             : // of a WeakMap or WeakSet.
    2668         448 : TF_BUILTIN(WeakCollectionSet, WeakCollectionsBuiltinsAssembler) {
    2669          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2670          56 :   TNode<JSWeakCollection> collection = CAST(Parameter(Descriptor::kCollection));
    2671          56 :   TNode<JSReceiver> key = CAST(Parameter(Descriptor::kKey));
    2672          56 :   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
    2673             : 
    2674             :   CSA_ASSERT(this, IsJSReceiver(key));
    2675             : 
    2676         112 :   Label call_runtime(this), if_no_hash(this), if_not_found(this);
    2677             : 
    2678          56 :   TNode<EphemeronHashTable> table = LoadTable(collection);
    2679          56 :   TNode<IntPtrT> capacity = LoadTableCapacity(table);
    2680          56 :   TNode<IntPtrT> entry_mask = EntryMask(capacity);
    2681             : 
    2682         112 :   TVARIABLE(IntPtrT, var_hash, LoadJSReceiverIdentityHash(key, &if_no_hash));
    2683             :   TNode<IntPtrT> key_index = FindKeyIndexForKey(table, key, var_hash.value(),
    2684          56 :                                                 entry_mask, &if_not_found);
    2685             : 
    2686          56 :   StoreFixedArrayElement(table, ValueIndexFromKeyIndex(key_index), value);
    2687          56 :   Return(collection);
    2688             : 
    2689          56 :   BIND(&if_no_hash);
    2690             :   {
    2691          56 :     var_hash = SmiUntag(CreateIdentityHash(key));
    2692          56 :     Goto(&if_not_found);
    2693             :   }
    2694          56 :   BIND(&if_not_found);
    2695             :   {
    2696          56 :     TNode<IntPtrT> number_of_deleted = LoadNumberOfDeleted(table);
    2697          56 :     TNode<IntPtrT> number_of_elements = LoadNumberOfElements(table, 1);
    2698             : 
    2699             :     // TODO(pwong): Port HashTable's Rehash() and EnsureCapacity() to CSA.
    2700         224 :     GotoIf(Word32Or(ShouldRehash(number_of_elements, number_of_deleted),
    2701         112 :                     InsufficientCapacityToAdd(capacity, number_of_elements,
    2702         280 :                                               number_of_deleted)),
    2703          56 :            &call_runtime);
    2704             : 
    2705             :     TNode<IntPtrT> insertion_key_index =
    2706          56 :         FindKeyIndexForInsertion(table, var_hash.value(), entry_mask);
    2707          56 :     AddEntry(table, insertion_key_index, key, value, number_of_elements);
    2708          56 :     Return(collection);
    2709             :   }
    2710          56 :   BIND(&call_runtime);
    2711             :   {
    2712             :     CallRuntime(Runtime::kWeakCollectionSet, context, collection, key, value,
    2713          56 :                 SmiTag(var_hash.value()));
    2714          56 :     Return(collection);
    2715             :   }
    2716          56 : }
    2717             : 
    2718         392 : TF_BUILTIN(WeakMapPrototypeDelete, CodeStubAssembler) {
    2719          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2720          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    2721          56 :   TNode<Object> key = CAST(Parameter(Descriptor::kKey));
    2722             : 
    2723          56 :   ThrowIfNotInstanceType(context, receiver, JS_WEAK_MAP_TYPE,
    2724          56 :                          "WeakMap.prototype.delete");
    2725             : 
    2726          56 :   Return(CallBuiltin(Builtins::kWeakCollectionDelete, context, receiver, key));
    2727          56 : }
    2728             : 
    2729         448 : TF_BUILTIN(WeakMapPrototypeSet, WeakCollectionsBuiltinsAssembler) {
    2730          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2731          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    2732          56 :   TNode<Object> key = CAST(Parameter(Descriptor::kKey));
    2733          56 :   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
    2734             : 
    2735          56 :   ThrowIfNotInstanceType(context, receiver, JS_WEAK_MAP_TYPE,
    2736          56 :                          "WeakMap.prototype.set");
    2737             : 
    2738         112 :   Label throw_invalid_key(this);
    2739          56 :   GotoIfNotJSReceiver(key, &throw_invalid_key);
    2740             : 
    2741         112 :   Return(
    2742         168 :       CallBuiltin(Builtins::kWeakCollectionSet, context, receiver, key, value));
    2743             : 
    2744          56 :   BIND(&throw_invalid_key);
    2745          56 :   ThrowTypeError(context, MessageTemplate::kInvalidWeakMapKey, key);
    2746          56 : }
    2747             : 
    2748         392 : TF_BUILTIN(WeakSetPrototypeAdd, WeakCollectionsBuiltinsAssembler) {
    2749          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2750          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    2751          56 :   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
    2752             : 
    2753          56 :   ThrowIfNotInstanceType(context, receiver, JS_WEAK_SET_TYPE,
    2754          56 :                          "WeakSet.prototype.add");
    2755             : 
    2756         112 :   Label throw_invalid_value(this);
    2757          56 :   GotoIfNotJSReceiver(value, &throw_invalid_value);
    2758             : 
    2759         112 :   Return(CallBuiltin(Builtins::kWeakCollectionSet, context, receiver, value,
    2760         168 :                      TrueConstant()));
    2761             : 
    2762          56 :   BIND(&throw_invalid_value);
    2763          56 :   ThrowTypeError(context, MessageTemplate::kInvalidWeakSetValue, value);
    2764          56 : }
    2765             : 
    2766         392 : TF_BUILTIN(WeakSetPrototypeDelete, CodeStubAssembler) {
    2767          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2768          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    2769          56 :   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
    2770             : 
    2771          56 :   ThrowIfNotInstanceType(context, receiver, JS_WEAK_SET_TYPE,
    2772          56 :                          "WeakSet.prototype.delete");
    2773             : 
    2774         112 :   Return(
    2775         168 :       CallBuiltin(Builtins::kWeakCollectionDelete, context, receiver, value));
    2776          56 : }
    2777             : 
    2778         392 : TF_BUILTIN(WeakSetPrototypeHas, WeakCollectionsBuiltinsAssembler) {
    2779          56 :   Node* const receiver = Parameter(Descriptor::kReceiver);
    2780          56 :   Node* const key = Parameter(Descriptor::kKey);
    2781          56 :   Node* const context = Parameter(Descriptor::kContext);
    2782             : 
    2783         112 :   Label return_false(this);
    2784             : 
    2785          56 :   ThrowIfNotInstanceType(context, receiver, JS_WEAK_SET_TYPE,
    2786          56 :                          "WeakSet.prototype.has");
    2787             : 
    2788          56 :   Node* const table = LoadTable(CAST(receiver));
    2789             :   Node* const index =
    2790          56 :       CallBuiltin(Builtins::kWeakMapLookupHashIndex, context, table, key);
    2791             : 
    2792          56 :   GotoIf(WordEqual(index, SmiConstant(-1)), &return_false);
    2793             : 
    2794          56 :   Return(TrueConstant());
    2795             : 
    2796          56 :   BIND(&return_false);
    2797          56 :   Return(FalseConstant());
    2798          56 : }
    2799             : 
    2800             : }  // namespace internal
    2801       87414 : }  // namespace v8

Generated by: LCOV version 1.10