// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_BUILTINS_BUILTINS_COLLECTIONS_GEN_H_ #define V8_BUILTINS_BUILTINS_COLLECTIONS_GEN_H_ #include "src/codegen/code-stub-assembler.h" namespace v8 { namespace internal { void BranchIfIterableWithOriginalKeyOrValueMapIterator( compiler::CodeAssemblerState* state, TNode iterable, TNode context, compiler::CodeAssemblerLabel* if_true, compiler::CodeAssemblerLabel* if_false); void BranchIfIterableWithOriginalValueSetIterator( compiler::CodeAssemblerState* state, TNode iterable, TNode context, compiler::CodeAssemblerLabel* if_true, compiler::CodeAssemblerLabel* if_false); class BaseCollectionsAssembler : public CodeStubAssembler { public: explicit BaseCollectionsAssembler(compiler::CodeAssemblerState* state) : CodeStubAssembler(state) {} virtual ~BaseCollectionsAssembler() = default; void GotoIfCannotBeHeldWeakly(const TNode obj, Label* if_cannot_be_held_weakly); protected: enum Variant { kMap, kSet, kWeakMap, kWeakSet }; // Adds an entry to a collection. For Maps, properly handles extracting the // key and value from the entry (see LoadKeyValue()). void AddConstructorEntry(Variant variant, TNode context, TNode collection, TNode add_function, TNode key_value, Label* if_may_have_side_effects = nullptr, Label* if_exception = nullptr, TVariable* var_exception = nullptr); // Adds constructor entries to a collection. Choosing a fast path when // possible. void AddConstructorEntries(Variant variant, TNode context, TNode native_context, TNode collection, TNode initial_entries); // Fast path for adding constructor entries. Assumes the entries are a fast // JS array (see CodeStubAssembler::BranchIfFastJSArray()). void AddConstructorEntriesFromFastJSArray(Variant variant, TNode context, TNode native_context, TNode collection, TNode fast_jsarray, Label* if_may_have_side_effects); // Adds constructor entries to a collection using the iterator protocol. void AddConstructorEntriesFromIterable(Variant variant, TNode context, TNode native_context, TNode collection, TNode iterable); // Constructs a collection instance. Choosing a fast path when possible. TNode AllocateJSCollection(TNode context, TNode constructor, TNode new_target); // Fast path for constructing a collection instance if the constructor // function has not been modified. TNode AllocateJSCollectionFast(TNode constructor); // Fallback for constructing a collection instance if the constructor function // has been modified. TNode AllocateJSCollectionSlow(TNode context, TNode constructor, TNode new_target); // Allocates the backing store for a collection. virtual TNode AllocateTable( Variant variant, TNode at_least_space_for) = 0; // Main entry point for a collection constructor builtin. void GenerateConstructor(Variant variant, Handle constructor_function_name, TNode new_target, TNode argc, TNode context); // Retrieves the collection function that adds an entry. `set` for Maps and // `add` for Sets. TNode GetAddFunction(Variant variant, TNode context, TNode collection); // Retrieves the collection constructor function. TNode GetConstructor(Variant variant, TNode native_context); // Retrieves the initial collection function that adds an entry. Should only // be called when it is certain that a collection prototype's map hasn't been // changed. TNode GetInitialAddFunction(Variant variant, TNode native_context); // Checks whether {collection}'s initial add/set function has been modified // (depending on {variant}, loaded from {native_context}). void GotoIfInitialAddFunctionModified(Variant variant, TNode native_context, TNode collection, Label* if_modified); // Gets root index for the name of the add/set function. RootIndex GetAddFunctionNameIndex(Variant variant); // Retrieves the offset to access the backing table from the collection. int GetTableOffset(Variant variant); // Estimates the number of entries the collection will have after adding the // entries passed in the constructor. AllocateTable() can use this to avoid // the time of growing/rehashing when adding the constructor entries. TNode EstimatedInitialSize(TNode initial_entries, TNode is_fast_jsarray); // Determines whether the collection's prototype has been modified. TNode HasInitialCollectionPrototype(Variant variant, TNode native_context, TNode collection); // Gets the initial prototype map for given collection {variant}. TNode GetInitialCollectionPrototype(Variant variant, TNode native_context); // Loads an element from a fixed array. If the element is the hole, returns // `undefined`. TNode LoadAndNormalizeFixedArrayElement(TNode elements, TNode index); // Loads an element from a fixed double array. If the element is the hole, // returns `undefined`. TNode LoadAndNormalizeFixedDoubleArrayElement( TNode elements, TNode index); }; class WeakCollectionsBuiltinsAssembler : public BaseCollectionsAssembler { public: explicit WeakCollectionsBuiltinsAssembler(compiler::CodeAssemblerState* state) : BaseCollectionsAssembler(state) {} protected: void AddEntry(TNode table, TNode key_index, TNode key, TNode value, TNode number_of_elements); TNode AllocateTable(Variant variant, TNode at_least_space_for) override; TNode GetHash(const TNode key, Label* if_no_hash); // Generates and sets the identity for a JSRececiver. TNode CreateIdentityHash(TNode receiver); TNode EntryMask(TNode capacity); // Builds code that finds the EphemeronHashTable entry for a {key} using the // comparison code generated by {key_compare}. The key index is returned if // the {key} is found. using KeyComparator = std::function entry_key, Label* if_same)>; TNode FindKeyIndex(TNode table, TNode key_hash, TNode entry_mask, const KeyComparator& key_compare); // Builds code that finds an EphemeronHashTable entry available for a new // entry. TNode FindKeyIndexForInsertion(TNode table, TNode key_hash, TNode entry_mask); // Builds code that finds the EphemeronHashTable entry with key that matches // {key} and returns the entry's key index. If {key} cannot be found, jumps to // {if_not_found}. TNode FindKeyIndexForKey(TNode table, TNode key, TNode hash, TNode entry_mask, Label* if_not_found); TNode InsufficientCapacityToAdd(TNode capacity, TNode number_of_elements, TNode number_of_deleted); TNode KeyIndexFromEntry(TNode entry); TNode LoadNumberOfElements(TNode table, int offset); TNode LoadNumberOfDeleted(TNode table, int offset = 0); TNode LoadTable(TNode collection); TNode LoadTableCapacity(TNode table); void RemoveEntry(TNode table, TNode key_index, TNode number_of_elements); TNode ShouldRehash(TNode number_of_elements, TNode number_of_deleted); TNode ShouldShrink(TNode capacity, TNode number_of_elements); TNode ValueIndexFromKeyIndex(TNode key_index); }; } // namespace internal } // namespace v8 #endif // V8_BUILTINS_BUILTINS_COLLECTIONS_GEN_H_