Index: src/builtins/builtins-collections-gen.cc |
diff --git a/src/builtins/builtins-collections-gen.cc b/src/builtins/builtins-collections-gen.cc |
index aa916d4f0647a9b2dc13b7548236a00d0138fd9a..d1e725398c3a044d4be065c9a62447a8613a9a05 100644 |
--- a/src/builtins/builtins-collections-gen.cc |
+++ b/src/builtins/builtins-collections-gen.cc |
@@ -29,13 +29,34 @@ class CollectionsBuiltinsAssembler : public CodeStubAssembler { |
template <typename CollectionType, int entrysize> |
Node* CallHasRaw(Node* const table, Node* const key); |
- // Tries to find OrderedHashMap entry for given Smi key, jumps |
- // to {entry_found} if the key is found, or to {not_found} if the |
- // key was not found. Returns the node with the entry index (relative to |
- // OrderedHashMap::kHashTableStartIndex). The node can only be used in the |
- // {entry_found} branch. |
- Node* FindOrderedHashMapEntryForSmiKey(Node* table, Node* key_tagged, |
- Label* entry_found, Label* not_found); |
+ // Builds code that finds OrderedHashMap entry for given key with hash code |
+ // {hash} with using the comparison code generated by {key_compare}. The code |
+ // jumps to {entry_found} if the key is found, or to {not_found} if the key |
+ // was not found. In the {entry_found} branch, the variable |
+ // entry_start_position will be bound to the index of the entry (relative to |
+ // OrderedHashMap::kHashTableStartIndex). |
+ void FindOrderedHashMapEntry( |
+ Node* table, Node* key_tagged, Node* hash, |
+ std::function<void(Node* other, Label* if_same, Label* if_not_same)> |
+ key_compare, |
+ Variable* entry_start_position, Label* entry_found, Label* not_found); |
+ |
+ // Specialization for Smi. |
+ void FindOrderedHashMapEntryForSmiKey(Node* table, Node* key_tagged, |
+ Variable* entry_start_position, |
+ Label* entry_found, Label* not_found); |
+ void SameValueZeroSmi(Node* key_smi, Node* candidate_key, Label* if_same, |
+ Label* if_not_same); |
+ |
+ // Specialization for String. |
+ void FindOrderedHashMapEntryForStringKey(Node* context, Node* table, |
+ Node* key_tagged, |
+ Variable* entry_start_position, |
+ Label* entry_found, |
+ Label* not_found); |
+ Node* ComputeIntegerHashForString(Node* context, Node* string_key); |
+ void SameValueZeroString(Node* context, Node* key_string, Node* candidate_key, |
+ Label* if_same, Label* if_not_same); |
}; |
template <typename CollectionType> |
@@ -380,13 +401,95 @@ Node* CollectionsBuiltinsAssembler::CallHasRaw(Node* const table, |
Word32NotEqual(Word32And(result, Int32Constant(0xFF)), Int32Constant(0))); |
} |
-Node* CollectionsBuiltinsAssembler::FindOrderedHashMapEntryForSmiKey( |
- Node* table, Node* key_tagged, Label* entry_found, Label* not_found) { |
- // Compute the hash. |
- Node* const key = SmiUntag(key_tagged); |
+void CollectionsBuiltinsAssembler::SameValueZeroSmi(Node* key_smi, |
+ Node* candidate_key, |
+ Label* if_same, |
+ Label* if_not_same) { |
+ // If the key is the same, we are done. |
+ GotoIf(WordEqual(candidate_key, key_smi), if_same); |
+ |
+ // If the candidate key is smi, then it must be different (because |
+ // we already checked for equality above). |
+ GotoIf(TaggedIsSmi(candidate_key), if_not_same); |
+ |
+ // If the candidate key is not smi, we still have to check if it is a |
+ // heap number with the same value. |
+ GotoIfNot(IsHeapNumber(candidate_key), if_not_same); |
+ |
+ Node* const candidate_key_number = LoadHeapNumberValue(candidate_key); |
+ Node* const key_number = SmiToFloat64(key_smi); |
+ |
+ GotoIf(Float64Equal(candidate_key_number, key_number), if_same); |
+ |
+ Goto(if_not_same); |
+} |
+ |
+void CollectionsBuiltinsAssembler::FindOrderedHashMapEntryForSmiKey( |
+ Node* table, Node* smi_key, Variable* entry_start_position, |
+ Label* entry_found, Label* not_found) { |
+ Node* const key = SmiUntag(smi_key); |
Node* const hash = |
ChangeInt32ToIntPtr(ComputeIntegerHash(key, Int32Constant(0))); |
+ FindOrderedHashMapEntry( |
+ table, smi_key, hash, |
+ [&](Node* other_key, Label* if_same, Label* if_not_same) { |
+ SameValueZeroSmi(smi_key, other_key, if_same, if_not_same); |
+ }, |
+ entry_start_position, entry_found, not_found); |
+} |
+ |
+void CollectionsBuiltinsAssembler::FindOrderedHashMapEntryForStringKey( |
+ Node* context, Node* table, Node* key_tagged, |
+ Variable* entry_start_position, Label* entry_found, Label* not_found) { |
+ Node* const hash = ComputeIntegerHashForString(context, key_tagged); |
+ FindOrderedHashMapEntry( |
+ table, key_tagged, hash, |
+ [&](Node* other_key, Label* if_same, Label* if_not_same) { |
+ SameValueZeroString(context, key_tagged, other_key, if_same, |
+ if_not_same); |
+ }, |
+ entry_start_position, entry_found, not_found); |
+} |
+ |
+Node* CollectionsBuiltinsAssembler::ComputeIntegerHashForString( |
+ Node* context, Node* string_key) { |
+ VARIABLE(var_result, MachineType::PointerRepresentation()); |
+ |
+ Label hash_not_computed(this), done(this, &var_result); |
+ Node* hash = |
+ ChangeInt32ToIntPtr(LoadNameHash(string_key, &hash_not_computed)); |
+ var_result.Bind(hash); |
+ Goto(&done); |
+ |
+ BIND(&hash_not_computed); |
+ Node* tagged_hash = CallRuntime(Runtime::kGenericHash, context, string_key); |
+ CSA_ASSERT(this, TaggedIsSmi(tagged_hash)); |
+ var_result.Bind(SmiUntag(tagged_hash)); |
+ Goto(&done); |
+ BIND(&done); |
+ return var_result.value(); |
+} |
+ |
+void CollectionsBuiltinsAssembler::SameValueZeroString(Node* context, |
+ Node* key_string, |
+ Node* candidate_key, |
+ Label* if_same, |
+ Label* if_not_same) { |
+ // If the candidate is not a string, the keys are not equal. |
+ GotoIf(TaggedIsSmi(candidate_key), if_not_same); |
+ GotoIfNot(IsString(candidate_key), if_not_same); |
+ |
+ Branch(WordEqual(CallBuiltin(Builtins::kStringEqual, context, key_string, |
+ candidate_key), |
+ TrueConstant()), |
+ if_same, if_not_same); |
+} |
+ |
+void CollectionsBuiltinsAssembler::FindOrderedHashMapEntry( |
+ Node* table, Node* key_tagged, Node* hash, |
+ std::function<void(Node*, Label*, Label*)> key_compare, |
+ Variable* entry_start_position, Label* entry_found, Label* not_found) { |
// Get the index of the bucket. |
Node* const number_of_buckets = SmiUntag( |
LoadFixedArrayElement(table, OrderedHashMap::kNumberOfBucketsIndex)); |
@@ -395,11 +498,11 @@ Node* CollectionsBuiltinsAssembler::FindOrderedHashMapEntryForSmiKey( |
Node* const first_entry = SmiUntag(LoadFixedArrayElement( |
table, bucket, OrderedHashMap::kHashTableStartIndex * kPointerSize)); |
- Node* entry_start_position; |
// Walk the bucket chain. |
{ |
VARIABLE(var_entry, MachineType::PointerRepresentation(), first_entry); |
- Label loop(this, &var_entry), continue_next_entry(this); |
+ Label loop(this, {&var_entry, entry_start_position}), |
+ continue_next_entry(this); |
Goto(&loop); |
BIND(&loop); |
@@ -420,44 +523,28 @@ Node* CollectionsBuiltinsAssembler::FindOrderedHashMapEntryForSmiKey( |
table, OrderedHashMap::kNumberOfDeletedElementsIndex))))); |
// Compute the index of the entry relative to kHashTableStartIndex. |
- entry_start_position = |
+ Node* entry_start = |
IntPtrAdd(IntPtrMul(var_entry.value(), |
IntPtrConstant(OrderedHashMap::kEntrySize)), |
number_of_buckets); |
+ entry_start_position->Bind(entry_start); |
// Load the key from the entry. |
Node* const candidate_key = LoadFixedArrayElement( |
- table, entry_start_position, |
+ table, entry_start, |
OrderedHashMap::kHashTableStartIndex * kPointerSize); |
- // If the key is the same, we are done. |
- GotoIf(WordEqual(candidate_key, key_tagged), entry_found); |
- |
- // If the candidate key is smi, then it must be different (because |
- // we already checked for equality above). |
- GotoIf(TaggedIsSmi(candidate_key), &continue_next_entry); |
- |
- // If the candidate key is not smi, we still have to check if it is a heap |
- // number with the same value. |
- GotoIfNot(IsHeapNumber(candidate_key), &continue_next_entry); |
- |
- Node* const candidate_key_number = LoadHeapNumberValue(candidate_key); |
- Node* const key_number = SmiToFloat64(key_tagged); |
- |
- GotoIf(Float64Equal(candidate_key_number, key_number), entry_found); |
- |
- Goto(&continue_next_entry); |
+ key_compare(candidate_key, entry_found, &continue_next_entry); |
BIND(&continue_next_entry); |
// Load the index of the next entry in the bucket chain. |
var_entry.Bind(SmiUntag(LoadFixedArrayElement( |
- table, entry_start_position, |
+ table, entry_start, |
(OrderedHashMap::kHashTableStartIndex + OrderedHashMap::kChainOffset) * |
kPointerSize))); |
Goto(&loop); |
} |
- return entry_start_position; |
} |
TF_BUILTIN(MapGet, CollectionsBuiltinsAssembler) { |
@@ -469,19 +556,27 @@ TF_BUILTIN(MapGet, CollectionsBuiltinsAssembler) { |
Node* const table = LoadObjectField(receiver, JSMap::kTableOffset); |
- Label if_key_smi(this); |
+ VARIABLE(entry_start_position, MachineType::PointerRepresentation(), |
+ IntPtrConstant(0)); |
+ Label if_key_smi(this), if_key_string(this); |
GotoIf(TaggedIsSmi(key_tagged), &if_key_smi); |
+ GotoIf(IsString(key_tagged), &if_key_string); |
Return(CallGetRaw(table, key_tagged)); |
BIND(&if_key_smi); |
- Label entry_found(this), not_found(this); |
- Node* entry_start_position = FindOrderedHashMapEntryForSmiKey( |
- table, key_tagged, &entry_found, ¬_found); |
+ Label entry_found(this, &entry_start_position), not_found(this); |
+ FindOrderedHashMapEntryForSmiKey(table, key_tagged, &entry_start_position, |
+ &entry_found, ¬_found); |
+ |
+ BIND(&if_key_string); |
+ FindOrderedHashMapEntryForStringKey(context, table, key_tagged, |
+ &entry_start_position, &entry_found, |
+ ¬_found); |
BIND(&entry_found); |
Return(LoadFixedArrayElement( |
- table, entry_start_position, |
+ table, entry_start_position.value(), |
(OrderedHashMap::kHashTableStartIndex + OrderedHashMap::kValueOffset) * |
kPointerSize)); |
@@ -498,14 +593,23 @@ TF_BUILTIN(MapHas, CollectionsBuiltinsAssembler) { |
Node* const table = LoadObjectField(receiver, JSMap::kTableOffset); |
- Label if_key_smi(this); |
+ VARIABLE(entry_start_position, MachineType::PointerRepresentation(), |
+ IntPtrConstant(0)); |
+ Label if_key_smi(this), if_key_string(this); |
GotoIf(TaggedIsSmi(key_tagged), &if_key_smi); |
+ GotoIf(IsString(key_tagged), &if_key_string); |
Return(CallHasRaw<OrderedHashMap, 2>(table, key_tagged)); |
BIND(&if_key_smi); |
Label entry_found(this), not_found(this); |
- FindOrderedHashMapEntryForSmiKey(table, key_tagged, &entry_found, ¬_found); |
+ FindOrderedHashMapEntryForSmiKey(table, key_tagged, &entry_start_position, |
+ &entry_found, ¬_found); |
+ |
+ BIND(&if_key_string); |
+ FindOrderedHashMapEntryForStringKey(context, table, key_tagged, |
+ &entry_start_position, &entry_found, |
+ ¬_found); |
BIND(&entry_found); |
Return(TrueConstant()); |