@@ -22,130 +22,6 @@ namespace internal { |
22 | 22 | template <class T> |
23 | 23 | using TVariable = compiler::TypedCodeAssemblerVariable<T>; |
24 | 24 |
|
25 | | -class BaseCollectionsAssembler : public CodeStubAssembler { |
26 | | - public: |
27 | | - explicit BaseCollectionsAssembler(compiler::CodeAssemblerState* state) |
28 | | - : CodeStubAssembler(state) {} |
29 | | - |
30 | | - virtual ~BaseCollectionsAssembler() = default; |
31 | | - |
32 | | - protected: |
33 | | - enum Variant { kMap, kSet, kWeakMap, kWeakSet }; |
34 | | - |
35 | | - // Adds an entry to a collection. For Maps, properly handles extracting the |
36 | | - // key and value from the entry (see LoadKeyValue()). |
37 | | - void AddConstructorEntry(Variant variant, TNode<Context> context, |
38 | | - TNode<Object> collection, TNode<Object> add_function, |
39 | | - TNode<Object> key_value, |
40 | | - Label* if_may_have_side_effects = nullptr, |
41 | | - Label* if_exception = nullptr, |
42 | | - TVariable<Object>* var_exception = nullptr); |
43 | | - |
44 | | - // Adds constructor entries to a collection. Choosing a fast path when |
45 | | - // possible. |
46 | | - void AddConstructorEntries(Variant variant, TNode<Context> context, |
47 | | - TNode<Context> native_context, |
48 | | - TNode<HeapObject> collection, |
49 | | - TNode<Object> initial_entries); |
50 | | - |
51 | | - // Fast path for adding constructor entries. Assumes the entries are a fast |
52 | | - // JS array (see CodeStubAssembler::BranchIfFastJSArray()). |
53 | | - void AddConstructorEntriesFromFastJSArray(Variant variant, |
54 | | - TNode<Context> context, |
55 | | - TNode<Context> native_context, |
56 | | - TNode<Object> collection, |
57 | | - TNode<JSArray> fast_jsarray, |
58 | | - Label* if_may_have_side_effects); |
59 | | - |
60 | | - // Adds constructor entries to a collection using the iterator protocol. |
61 | | - void AddConstructorEntriesFromIterable(Variant variant, |
62 | | - TNode<Context> context, |
63 | | - TNode<Context> native_context, |
64 | | - TNode<Object> collection, |
65 | | - TNode<Object> iterable); |
66 | | - |
67 | | - // Constructs a collection instance. Choosing a fast path when possible. |
68 | | - TNode<JSObject> AllocateJSCollection(TNode<Context> context, |
69 | | - TNode<JSFunction> constructor, |
70 | | - TNode<JSReceiver> new_target); |
71 | | - |
72 | | - // Fast path for constructing a collection instance if the constructor |
73 | | - // function has not been modified. |
74 | | - TNode<JSObject> AllocateJSCollectionFast(TNode<JSFunction> constructor); |
75 | | - |
76 | | - // Fallback for constructing a collection instance if the constructor function |
77 | | - // has been modified. |
78 | | - TNode<JSObject> AllocateJSCollectionSlow(TNode<Context> context, |
79 | | - TNode<JSFunction> constructor, |
80 | | - TNode<JSReceiver> new_target); |
81 | | - |
82 | | - // Allocates the backing store for a collection. |
83 | | - virtual TNode<HeapObject> AllocateTable( |
84 | | - Variant variant, TNode<IntPtrT> at_least_space_for) = 0; |
85 | | - |
86 | | - // Main entry point for a collection constructor builtin. |
87 | | - void GenerateConstructor(Variant variant, |
88 | | - Handle<String> constructor_function_name, |
89 | | - TNode<Object> new_target, TNode<IntPtrT> argc, |
90 | | - TNode<Context> context); |
91 | | - |
92 | | - // Retrieves the collection function that adds an entry. `set` for Maps and |
93 | | - // `add` for Sets. |
94 | | - TNode<Object> GetAddFunction(Variant variant, TNode<Context> context, |
95 | | - TNode<Object> collection); |
96 | | - |
97 | | - // Retrieves the collection constructor function. |
98 | | - TNode<JSFunction> GetConstructor(Variant variant, |
99 | | - TNode<Context> native_context); |
100 | | - |
101 | | - // Retrieves the initial collection function that adds an entry. Should only |
102 | | - // be called when it is certain that a collection prototype's map hasn't been |
103 | | - // changed. |
104 | | - TNode<JSFunction> GetInitialAddFunction(Variant variant, |
105 | | - TNode<Context> native_context); |
106 | | - |
107 | | - // Checks whether {collection}'s initial add/set function has been modified |
108 | | - // (depending on {variant}, loaded from {native_context}). |
109 | | - void GotoIfInitialAddFunctionModified(Variant variant, |
110 | | - TNode<NativeContext> native_context, |
111 | | - TNode<HeapObject> collection, |
112 | | - Label* if_modified); |
113 | | - |
114 | | - // Gets root index for the name of the add/set function. |
115 | | - RootIndex GetAddFunctionNameIndex(Variant variant); |
116 | | - |
117 | | - // Retrieves the offset to access the backing table from the collection. |
118 | | - int GetTableOffset(Variant variant); |
119 | | - |
120 | | - // Estimates the number of entries the collection will have after adding the |
121 | | - // entries passed in the constructor. AllocateTable() can use this to avoid |
122 | | - // the time of growing/rehashing when adding the constructor entries. |
123 | | - TNode<IntPtrT> EstimatedInitialSize(TNode<Object> initial_entries, |
124 | | - TNode<BoolT> is_fast_jsarray); |
125 | | - |
126 | | - void GotoIfCannotBeWeakKey(const TNode<Object> obj, |
127 | | - Label* if_cannot_be_weak_key); |
128 | | - |
129 | | - // Determines whether the collection's prototype has been modified. |
130 | | - TNode<BoolT> HasInitialCollectionPrototype(Variant variant, |
131 | | - TNode<Context> native_context, |
132 | | - TNode<Object> collection); |
133 | | - |
134 | | - // Gets the initial prototype map for given collection {variant}. |
135 | | - TNode<Map> GetInitialCollectionPrototype(Variant variant, |
136 | | - TNode<Context> native_context); |
137 | | - |
138 | | - // Loads an element from a fixed array. If the element is the hole, returns |
139 | | - // `undefined`. |
140 | | - TNode<Object> LoadAndNormalizeFixedArrayElement(TNode<FixedArray> elements, |
141 | | - TNode<IntPtrT> index); |
142 | | - |
143 | | - // Loads an element from a fixed double array. If the element is the hole, |
144 | | - // returns `undefined`. |
145 | | - TNode<Object> LoadAndNormalizeFixedDoubleArrayElement( |
146 | | - TNode<HeapObject> elements, TNode<IntPtrT> index); |
147 | | -}; |
148 | | - |
149 | 25 | void BaseCollectionsAssembler::AddConstructorEntry( |
150 | 26 | Variant variant, TNode<Context> context, TNode<Object> collection, |
151 | 27 | TNode<Object> add_function, TNode<Object> key_value, |
@@ -525,12 +401,23 @@ TNode<IntPtrT> BaseCollectionsAssembler::EstimatedInitialSize( |
525 | 401 |
|
526 | 402 | void BaseCollectionsAssembler::GotoIfCannotBeWeakKey( |
527 | 403 | const TNode<Object> obj, Label* if_cannot_be_weak_key) { |
| 404 | + Label check_symbol_key(this); |
| 405 | + Label end(this); |
528 | 406 | GotoIf(TaggedIsSmi(obj), if_cannot_be_weak_key); |
529 | 407 | TNode<Uint16T> instance_type = LoadMapInstanceType(LoadMap(CAST(obj))); |
530 | | - GotoIfNot(IsJSReceiverInstanceType(instance_type), if_cannot_be_weak_key); |
| 408 | + GotoIfNot(IsJSReceiverInstanceType(instance_type), &check_symbol_key); |
531 | 409 | // TODO(v8:12547) Shared structs should only be able to point to shared values |
532 | 410 | // in weak collections. For now, disallow them as weak collection keys. |
533 | 411 | GotoIf(IsJSSharedStructInstanceType(instance_type), if_cannot_be_weak_key); |
| 412 | + Goto(&end); |
| 413 | + Bind(&check_symbol_key); |
| 414 | + GotoIfNot(HasHarmonySymbolAsWeakmapKeyFlag(), if_cannot_be_weak_key); |
| 415 | + GotoIfNot(IsSymbolInstanceType(instance_type), if_cannot_be_weak_key); |
| 416 | + TNode<Uint32T> flags = LoadSymbolFlags(CAST(obj)); |
| 417 | + GotoIf(Word32And(flags, Symbol::IsInPublicSymbolTableBit::kMask), |
| 418 | + if_cannot_be_weak_key); |
| 419 | + Goto(&end); |
| 420 | + Bind(&end); |
534 | 421 | } |
535 | 422 |
|
536 | 423 | TNode<Map> BaseCollectionsAssembler::GetInitialCollectionPrototype( |
@@ -2427,67 +2314,6 @@ TF_BUILTIN(FindOrderedHashMapEntry, CollectionsBuiltinsAssembler) { |
2427 | 2314 | Return(SmiConstant(-1)); |
2428 | 2315 | } |
2429 | 2316 |
|
2430 | | -class WeakCollectionsBuiltinsAssembler : public BaseCollectionsAssembler { |
2431 | | - public: |
2432 | | - explicit WeakCollectionsBuiltinsAssembler(compiler::CodeAssemblerState* state) |
2433 | | - : BaseCollectionsAssembler(state) {} |
2434 | | - |
2435 | | - protected: |
2436 | | - void AddEntry(TNode<EphemeronHashTable> table, TNode<IntPtrT> key_index, |
2437 | | - TNode<Object> key, TNode<Object> value, |
2438 | | - TNode<IntPtrT> number_of_elements); |
2439 | | - |
2440 | | - TNode<HeapObject> AllocateTable(Variant variant, |
2441 | | - TNode<IntPtrT> at_least_space_for) override; |
2442 | | - |
2443 | | - // Generates and sets the identity for a JSRececiver. |
2444 | | - TNode<Smi> CreateIdentityHash(TNode<Object> receiver); |
2445 | | - TNode<IntPtrT> EntryMask(TNode<IntPtrT> capacity); |
2446 | | - |
2447 | | - // Builds code that finds the EphemeronHashTable entry for a {key} using the |
2448 | | - // comparison code generated by {key_compare}. The key index is returned if |
2449 | | - // the {key} is found. |
2450 | | - using KeyComparator = |
2451 | | - std::function<void(TNode<Object> entry_key, Label* if_same)>; |
2452 | | - TNode<IntPtrT> FindKeyIndex(TNode<HeapObject> table, TNode<IntPtrT> key_hash, |
2453 | | - TNode<IntPtrT> entry_mask, |
2454 | | - const KeyComparator& key_compare); |
2455 | | - |
2456 | | - // Builds code that finds an EphemeronHashTable entry available for a new |
2457 | | - // entry. |
2458 | | - TNode<IntPtrT> FindKeyIndexForInsertion(TNode<HeapObject> table, |
2459 | | - TNode<IntPtrT> key_hash, |
2460 | | - TNode<IntPtrT> entry_mask); |
2461 | | - |
2462 | | - // Builds code that finds the EphemeronHashTable entry with key that matches |
2463 | | - // {key} and returns the entry's key index. If {key} cannot be found, jumps to |
2464 | | - // {if_not_found}. |
2465 | | - TNode<IntPtrT> FindKeyIndexForKey(TNode<HeapObject> table, TNode<Object> key, |
2466 | | - TNode<IntPtrT> hash, |
2467 | | - TNode<IntPtrT> entry_mask, |
2468 | | - Label* if_not_found); |
2469 | | - |
2470 | | - TNode<Word32T> InsufficientCapacityToAdd(TNode<IntPtrT> capacity, |
2471 | | - TNode<IntPtrT> number_of_elements, |
2472 | | - TNode<IntPtrT> number_of_deleted); |
2473 | | - TNode<IntPtrT> KeyIndexFromEntry(TNode<IntPtrT> entry); |
2474 | | - |
2475 | | - TNode<IntPtrT> LoadNumberOfElements(TNode<EphemeronHashTable> table, |
2476 | | - int offset); |
2477 | | - TNode<IntPtrT> LoadNumberOfDeleted(TNode<EphemeronHashTable> table, |
2478 | | - int offset = 0); |
2479 | | - TNode<EphemeronHashTable> LoadTable(TNode<JSWeakCollection> collection); |
2480 | | - TNode<IntPtrT> LoadTableCapacity(TNode<EphemeronHashTable> table); |
2481 | | - |
2482 | | - void RemoveEntry(TNode<EphemeronHashTable> table, TNode<IntPtrT> key_index, |
2483 | | - TNode<IntPtrT> number_of_elements); |
2484 | | - TNode<BoolT> ShouldRehash(TNode<IntPtrT> number_of_elements, |
2485 | | - TNode<IntPtrT> number_of_deleted); |
2486 | | - TNode<Word32T> ShouldShrink(TNode<IntPtrT> capacity, |
2487 | | - TNode<IntPtrT> number_of_elements); |
2488 | | - TNode<IntPtrT> ValueIndexFromKeyIndex(TNode<IntPtrT> key_index); |
2489 | | -}; |
2490 | | - |
2491 | 2317 | void WeakCollectionsBuiltinsAssembler::AddEntry( |
2492 | 2318 | TNode<EphemeronHashTable> table, TNode<IntPtrT> key_index, |
2493 | 2319 | TNode<Object> key, TNode<Object> value, TNode<IntPtrT> number_of_elements) { |
@@ -2503,6 +2329,25 @@ void WeakCollectionsBuiltinsAssembler::AddEntry( |
2503 | 2329 | SmiFromIntPtr(number_of_elements)); |
2504 | 2330 | } |
2505 | 2331 |
|
| 2332 | +TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::GetHash( |
| 2333 | + const TNode<HeapObject> key, Label* if_no_hash) { |
| 2334 | + TVARIABLE(IntPtrT, var_hash); |
| 2335 | + Label if_symbol(this); |
| 2336 | + Label return_result(this); |
| 2337 | + GotoIfNot(IsJSReceiver(key), &if_symbol); |
| 2338 | + var_hash = LoadJSReceiverIdentityHash(CAST(key), if_no_hash); |
| 2339 | + Goto(&return_result); |
| 2340 | + Bind(&if_symbol); |
| 2341 | + CSA_DCHECK(this, IsSymbol(key)); |
| 2342 | + CSA_DCHECK(this, Word32BinaryNot( |
| 2343 | + Word32And(LoadSymbolFlags(CAST(key)), |
| 2344 | + Symbol::IsInPublicSymbolTableBit::kMask))); |
| 2345 | + var_hash = ChangeInt32ToIntPtr(LoadNameHash(CAST(key), nullptr)); |
| 2346 | + Goto(&return_result); |
| 2347 | + Bind(&return_result); |
| 2348 | + return var_hash.value(); |
| 2349 | +} |
| 2350 | + |
2506 | 2351 | TNode<HeapObject> WeakCollectionsBuiltinsAssembler::AllocateTable( |
2507 | 2352 | Variant variant, TNode<IntPtrT> at_least_space_for) { |
2508 | 2353 | // See HashTable::New(). |
@@ -2732,8 +2577,7 @@ TF_BUILTIN(WeakMapLookupHashIndex, WeakCollectionsBuiltinsAssembler) { |
2732 | 2577 |
|
2733 | 2578 | GotoIfCannotBeWeakKey(key, &if_cannot_be_weak_key); |
2734 | 2579 |
|
2735 | | - TNode<IntPtrT> hash = |
2736 | | - LoadJSReceiverIdentityHash(CAST(key), &if_cannot_be_weak_key); |
| 2580 | + TNode<IntPtrT> hash = GetHash(CAST(key), &if_cannot_be_weak_key); |
2737 | 2581 | TNode<IntPtrT> capacity = LoadTableCapacity(table); |
2738 | 2582 | TNode<IntPtrT> key_index = FindKeyIndexForKey( |
2739 | 2583 | table, key, hash, EntryMask(capacity), &if_cannot_be_weak_key); |
@@ -2798,8 +2642,7 @@ TF_BUILTIN(WeakCollectionDelete, WeakCollectionsBuiltinsAssembler) { |
2798 | 2642 |
|
2799 | 2643 | GotoIfCannotBeWeakKey(key, &if_cannot_be_weak_key); |
2800 | 2644 |
|
2801 | | - TNode<IntPtrT> hash = |
2802 | | - LoadJSReceiverIdentityHash(CAST(key), &if_cannot_be_weak_key); |
| 2645 | + TNode<IntPtrT> hash = GetHash(CAST(key), &if_cannot_be_weak_key); |
2803 | 2646 | TNode<EphemeronHashTable> table = LoadTable(collection); |
2804 | 2647 | TNode<IntPtrT> capacity = LoadTableCapacity(table); |
2805 | 2648 | TNode<IntPtrT> key_index = FindKeyIndexForKey( |
@@ -2823,18 +2666,18 @@ TF_BUILTIN(WeakCollectionDelete, WeakCollectionsBuiltinsAssembler) { |
2823 | 2666 | TF_BUILTIN(WeakCollectionSet, WeakCollectionsBuiltinsAssembler) { |
2824 | 2667 | auto context = Parameter<Context>(Descriptor::kContext); |
2825 | 2668 | auto collection = Parameter<JSWeakCollection>(Descriptor::kCollection); |
2826 | | - auto key = Parameter<JSReceiver>(Descriptor::kKey); |
| 2669 | + auto key = Parameter<HeapObject>(Descriptor::kKey); |
2827 | 2670 | auto value = Parameter<Object>(Descriptor::kValue); |
2828 | 2671 |
|
2829 | | - CSA_DCHECK(this, IsJSReceiver(key)); |
| 2672 | + CSA_DCHECK(this, Word32Or(IsJSReceiver(key), IsSymbol(key))); |
2830 | 2673 |
|
2831 | 2674 | Label call_runtime(this), if_no_hash(this), if_not_found(this); |
2832 | 2675 |
|
2833 | 2676 | TNode<EphemeronHashTable> table = LoadTable(collection); |
2834 | 2677 | TNode<IntPtrT> capacity = LoadTableCapacity(table); |
2835 | 2678 | TNode<IntPtrT> entry_mask = EntryMask(capacity); |
2836 | 2679 |
|
2837 | | - TVARIABLE(IntPtrT, var_hash, LoadJSReceiverIdentityHash(key, &if_no_hash)); |
| 2680 | + TVARIABLE(IntPtrT, var_hash, GetHash(key, &if_no_hash)); |
2838 | 2681 | TNode<IntPtrT> key_index = FindKeyIndexForKey(table, key, var_hash.value(), |
2839 | 2682 | entry_mask, &if_not_found); |
2840 | 2683 |
|
@@ -2843,6 +2686,7 @@ TF_BUILTIN(WeakCollectionSet, WeakCollectionsBuiltinsAssembler) { |
2843 | 2686 |
|
2844 | 2687 | BIND(&if_no_hash); |
2845 | 2688 | { |
| 2689 | + CSA_DCHECK(this, IsJSReceiver(key)); |
2846 | 2690 | var_hash = SmiUntag(CreateIdentityHash(key)); |
2847 | 2691 | Goto(&if_not_found); |
2848 | 2692 | } |
|