Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/hydrogen.h" | 5 #include "src/hydrogen.h" |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 | 8 |
| 9 #include "src/v8.h" | 9 #include "src/v8.h" |
| 10 | 10 |
| (...skipping 1607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1618 HValue* shifted_hash = AddUncasted<HShr>( | 1618 HValue* shifted_hash = AddUncasted<HShr>( |
| 1619 string_hash, Add<HConstant>(String::kHashShift)); | 1619 string_hash, Add<HConstant>(String::kHashShift)); |
| 1620 HValue* xor_result = AddUncasted<HBitwise>(Token::BIT_XOR, shifted_map, | 1620 HValue* xor_result = AddUncasted<HBitwise>(Token::BIT_XOR, shifted_map, |
| 1621 shifted_hash); | 1621 shifted_hash); |
| 1622 int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); | 1622 int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); |
| 1623 return AddUncasted<HBitwise>(Token::BIT_AND, xor_result, | 1623 return AddUncasted<HBitwise>(Token::BIT_AND, xor_result, |
| 1624 Add<HConstant>(mask)); | 1624 Add<HConstant>(mask)); |
| 1625 } | 1625 } |
| 1626 | 1626 |
| 1627 | 1627 |
| 1628 HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) { | 1628 HValue* HGraphBuilder::BuildComputeIntegerHash(HValue* value, |
|
Sven Panne
2015/02/23 09:26:53
I think this can be expressed purely in JavaScript
adamk
2015/03/16 17:35:06
Done.
| |
| 1629 int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed()); | 1629 uint32_t seed_value) { |
| 1630 HValue* seed = Add<HConstant>(seed_value); | 1630 HValue* seed = Add<HConstant>(static_cast<int32_t>(seed_value)); |
| 1631 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, index, seed); | 1631 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, value, seed); |
| 1632 | 1632 |
| 1633 // hash = ~hash + (hash << 15); | 1633 // hash = ~hash + (hash << 15); |
| 1634 HValue* shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(15)); | 1634 HValue* shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(15)); |
| 1635 HValue* not_hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, | 1635 HValue* not_hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, |
| 1636 graph()->GetConstantMinus1()); | 1636 graph()->GetConstantMinus1()); |
| 1637 hash = AddUncasted<HAdd>(shifted_hash, not_hash); | 1637 hash = AddUncasted<HAdd>(shifted_hash, not_hash); |
| 1638 | 1638 |
| 1639 // hash = hash ^ (hash >> 12); | 1639 // hash = hash ^ (hash >> 12); |
| 1640 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(12)); | 1640 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(12)); |
| 1641 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); | 1641 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); |
| (...skipping 10427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 12069 | 12069 |
| 12070 void HOptimizedGraphBuilder::GenerateMathSqrtRT(CallRuntime* call) { | 12070 void HOptimizedGraphBuilder::GenerateMathSqrtRT(CallRuntime* call) { |
| 12071 DCHECK(call->arguments()->length() == 1); | 12071 DCHECK(call->arguments()->length() == 1); |
| 12072 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 12072 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12073 HValue* value = Pop(); | 12073 HValue* value = Pop(); |
| 12074 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt); | 12074 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt); |
| 12075 return ast_context()->ReturnInstruction(result, call->id()); | 12075 return ast_context()->ReturnInstruction(result, call->id()); |
| 12076 } | 12076 } |
| 12077 | 12077 |
| 12078 | 12078 |
| 12079 HValue* HOptimizedGraphBuilder::BuildOrderedHashTableHashToBucket( | 12079 void HOptimizedGraphBuilder::GenerateFixedArrayGet(CallRuntime* call) { |
| 12080 HValue* hash, HValue* num_buckets) { | 12080 DCHECK(call->arguments()->length() == 2); |
| 12081 HValue* mask = AddUncasted<HSub>(num_buckets, graph()->GetConstant1()); | 12081 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12082 mask->ChangeRepresentation(Representation::Integer32()); | 12082 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 12083 mask->ClearFlag(HValue::kCanOverflow); | 12083 HValue* index = Pop(); |
| 12084 return AddUncasted<HBitwise>(Token::BIT_AND, hash, mask); | 12084 HValue* object = Pop(); |
| 12085 HInstruction* result = New<HLoadKeyed>(object, index, nullptr, FAST_ELEMENTS); | |
| 12086 return ast_context()->ReturnInstruction(result, call->id()); | |
| 12085 } | 12087 } |
| 12086 | 12088 |
| 12087 | 12089 |
| 12088 template <typename CollectionType> | 12090 void HOptimizedGraphBuilder::GenerateFixedArraySet(CallRuntime* call) { |
| 12089 HValue* HOptimizedGraphBuilder::BuildOrderedHashTableHashToEntry( | 12091 DCHECK(call->arguments()->length() == 3); |
| 12090 HValue* table, HValue* hash, HValue* num_buckets) { | 12092 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12091 HValue* bucket = BuildOrderedHashTableHashToBucket(hash, num_buckets); | 12093 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 12092 HValue* entry_index = AddUncasted<HAdd>( | 12094 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); |
| 12093 bucket, Add<HConstant>(CollectionType::kHashTableStartIndex)); | 12095 HValue* value = Pop(); |
| 12094 entry_index->ClearFlag(HValue::kCanOverflow); | 12096 HValue* index = Pop(); |
| 12095 HValue* entry = Add<HLoadKeyed>(table, entry_index, nullptr, FAST_ELEMENTS); | 12097 HValue* object = Pop(); |
| 12096 entry->set_type(HType::Smi()); | 12098 NoObservableSideEffectsScope no_effects(this); |
| 12097 return entry; | 12099 Add<HStoreKeyed>(object, index, value, FAST_ELEMENTS); |
| 12100 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); | |
| 12098 } | 12101 } |
| 12099 | 12102 |
| 12100 | 12103 |
| 12101 template <typename CollectionType> | 12104 void HOptimizedGraphBuilder::GenerateFixedArraySetTheHole(CallRuntime* call) { |
|
Sven Panne
2015/02/23 09:26:53
Hmmm, perhaps a %_Hole() intrinsic is nicer, you c
adamk
2015/02/23 18:43:34
Yeah, I should have left a TODO on this.
| |
| 12102 HValue* HOptimizedGraphBuilder::BuildOrderedHashTableEntryToIndex( | 12105 DCHECK(call->arguments()->length() == 3); |
|
arv (Not doing code reviews)
2015/02/21 16:20:16
2
| |
| 12103 HValue* entry, HValue* num_buckets) { | 12106 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12104 HValue* index = | 12107 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 12105 AddUncasted<HMul>(entry, Add<HConstant>(CollectionType::kEntrySize)); | 12108 HValue* index = Pop(); |
| 12106 index->ClearFlag(HValue::kCanOverflow); | 12109 HValue* object = Pop(); |
| 12107 index = AddUncasted<HAdd>(index, num_buckets); | 12110 NoObservableSideEffectsScope no_effects(this); |
| 12108 index->ClearFlag(HValue::kCanOverflow); | 12111 Add<HStoreKeyed>(object, index, graph()->GetConstantHole(), FAST_ELEMENTS); |
| 12109 index = AddUncasted<HAdd>( | 12112 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 12110 index, Add<HConstant>(CollectionType::kHashTableStartIndex)); | |
| 12111 index->ClearFlag(HValue::kCanOverflow); | |
| 12112 return index; | |
| 12113 } | 12113 } |
| 12114 | 12114 |
| 12115 | 12115 |
| 12116 template <typename CollectionType> | |
| 12117 HValue* HOptimizedGraphBuilder::BuildOrderedHashTableFindEntry(HValue* table, | |
| 12118 HValue* key, | |
| 12119 HValue* hash) { | |
| 12120 HValue* num_buckets = Add<HLoadNamedField>( | |
| 12121 table, nullptr, | |
| 12122 HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>()); | |
| 12123 | 12116 |
| 12124 HValue* entry = BuildOrderedHashTableHashToEntry<CollectionType>(table, hash, | 12117 void HOptimizedGraphBuilder::GenerateJSCollectionGetTable(CallRuntime* call) { |
|
Sven Panne
2015/02/23 09:26:53
We can leave it as it is for now, but I think that
adamk
2015/02/23 18:43:34
So this is an interesting one. The Hydrogen versio
adamk
2015/03/16 17:35:06
As discussed offline, it seems like this will stay
| |
| 12125 num_buckets); | 12118 DCHECK(call->arguments()->length() == 1); |
| 12126 | 12119 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12127 Push(entry); | 12120 HValue* receiver = Pop(); |
| 12128 | 12121 HInstruction* result = New<HLoadNamedField>( |
| 12129 LoopBuilder loop(this); | 12122 receiver, nullptr, HObjectAccess::ForJSCollectionTable()); |
| 12130 loop.BeginBody(1); | 12123 return ast_context()->ReturnInstruction(result, call->id()); |
| 12131 | |
| 12132 entry = Pop(); | |
| 12133 | |
| 12134 { | |
| 12135 IfBuilder if_not_found(this); | |
| 12136 if_not_found.If<HCompareNumericAndBranch>( | |
| 12137 entry, Add<HConstant>(CollectionType::kNotFound), Token::EQ); | |
| 12138 if_not_found.Then(); | |
| 12139 Push(entry); | |
| 12140 loop.Break(); | |
| 12141 } | |
| 12142 | |
| 12143 HValue* key_index = | |
| 12144 BuildOrderedHashTableEntryToIndex<CollectionType>(entry, num_buckets); | |
| 12145 HValue* candidate_key = | |
| 12146 Add<HLoadKeyed>(table, key_index, nullptr, FAST_ELEMENTS); | |
| 12147 | |
| 12148 { | |
| 12149 IfBuilder if_keys_equal(this); | |
| 12150 if_keys_equal.If<HIsStringAndBranch>(candidate_key); | |
| 12151 if_keys_equal.AndIf<HStringCompareAndBranch>(candidate_key, key, | |
| 12152 Token::EQ_STRICT); | |
| 12153 if_keys_equal.Then(); | |
| 12154 Push(key_index); | |
| 12155 loop.Break(); | |
| 12156 } | |
| 12157 | |
| 12158 // BuildChainAt | |
| 12159 HValue* chain_index = AddUncasted<HAdd>( | |
| 12160 key_index, Add<HConstant>(CollectionType::kChainOffset)); | |
| 12161 chain_index->ClearFlag(HValue::kCanOverflow); | |
| 12162 entry = Add<HLoadKeyed>(table, chain_index, nullptr, FAST_ELEMENTS); | |
| 12163 entry->set_type(HType::Smi()); | |
| 12164 Push(entry); | |
| 12165 | |
| 12166 loop.EndBody(); | |
| 12167 | |
| 12168 return Pop(); | |
| 12169 } | 12124 } |
| 12170 | 12125 |
| 12171 | 12126 |
| 12172 void HOptimizedGraphBuilder::GenerateMapGet(CallRuntime* call) { | 12127 void HOptimizedGraphBuilder::GenerateSmiHash(CallRuntime* call) { |
| 12173 DCHECK(call->arguments()->length() == 2); | 12128 DCHECK(call->arguments()->length() == 1); |
| 12174 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 12129 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12175 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 12130 HValue* value = Pop(); |
| 12176 HValue* key = Pop(); | |
| 12177 HValue* receiver = Pop(); | |
| 12178 | 12131 |
| 12179 NoObservableSideEffectsScope no_effects(this); | 12132 NoObservableSideEffectsScope no_effects(this); |
| 12180 | 12133 HValue* hash = BuildComputeIntegerHash(value, kZeroHashSeed); |
| 12181 HIfContinuation continuation; | 12134 return ast_context()->ReturnValue(hash); |
| 12182 HValue* hash = | |
| 12183 BuildStringHashLoadIfIsStringAndHashComputed(key, &continuation); | |
| 12184 { | |
| 12185 IfBuilder string_checker(this, &continuation); | |
| 12186 string_checker.Then(); | |
| 12187 { | |
| 12188 HValue* table = Add<HLoadNamedField>( | |
| 12189 receiver, nullptr, HObjectAccess::ForJSCollectionTable()); | |
| 12190 HValue* key_index = | |
| 12191 BuildOrderedHashTableFindEntry<OrderedHashMap>(table, key, hash); | |
| 12192 IfBuilder if_found(this); | |
| 12193 if_found.If<HCompareNumericAndBranch>( | |
| 12194 key_index, Add<HConstant>(OrderedHashMap::kNotFound), Token::NE); | |
| 12195 if_found.Then(); | |
| 12196 { | |
| 12197 HValue* value_index = AddUncasted<HAdd>( | |
| 12198 key_index, Add<HConstant>(OrderedHashMap::kValueOffset)); | |
| 12199 value_index->ClearFlag(HValue::kCanOverflow); | |
| 12200 Push(Add<HLoadKeyed>(table, value_index, nullptr, FAST_ELEMENTS)); | |
| 12201 } | |
| 12202 if_found.Else(); | |
| 12203 Push(graph()->GetConstantUndefined()); | |
| 12204 if_found.End(); | |
| 12205 } | |
| 12206 string_checker.Else(); | |
| 12207 { | |
| 12208 Add<HPushArguments>(receiver, key); | |
| 12209 Push(Add<HCallRuntime>(call->name(), | |
| 12210 Runtime::FunctionForId(Runtime::kMapGet), 2)); | |
| 12211 } | |
| 12212 } | |
| 12213 | |
| 12214 return ast_context()->ReturnValue(Pop()); | |
| 12215 } | 12135 } |
| 12216 | 12136 |
| 12217 | 12137 |
| 12218 HValue* HOptimizedGraphBuilder::BuildStringHashLoadIfIsStringAndHashComputed( | 12138 void HOptimizedGraphBuilder::GenerateStringHash(CallRuntime* call) { |
| 12219 HValue* object, HIfContinuation* continuation) { | 12139 DCHECK(call->arguments()->length() == 1); |
| 12220 IfBuilder string_checker(this); | 12140 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12221 string_checker.If<HIsStringAndBranch>(object); | 12141 HValue* object = Pop(); |
| 12222 string_checker.And(); | 12142 |
| 12143 NoObservableSideEffectsScope no_effects(this); | |
| 12223 HValue* hash = Add<HLoadNamedField>(object, nullptr, | 12144 HValue* hash = Add<HLoadNamedField>(object, nullptr, |
| 12224 HObjectAccess::ForStringHashField()); | 12145 HObjectAccess::ForStringHashField()); |
| 12225 HValue* hash_not_computed_mask = Add<HConstant>(String::kHashNotComputedMask); | 12146 HValue* hash_not_computed_mask = Add<HConstant>(String::kHashNotComputedMask); |
| 12226 HValue* hash_computed_test = | 12147 HValue* hash_computed_test = |
| 12227 AddUncasted<HBitwise>(Token::BIT_AND, hash, hash_not_computed_mask); | 12148 AddUncasted<HBitwise>(Token::BIT_AND, hash, hash_not_computed_mask); |
| 12228 string_checker.If<HCompareNumericAndBranch>( | |
| 12229 hash_computed_test, graph()->GetConstant0(), Token::EQ); | |
| 12230 string_checker.Then(); | |
| 12231 HValue* shifted_hash = | |
| 12232 AddUncasted<HShr>(hash, Add<HConstant>(String::kHashShift)); | |
| 12233 string_checker.CaptureContinuation(continuation); | |
| 12234 return shifted_hash; | |
| 12235 } | |
| 12236 | 12149 |
| 12237 | |
| 12238 template <typename CollectionType> | |
| 12239 void HOptimizedGraphBuilder::BuildJSCollectionHas( | |
| 12240 CallRuntime* call, const Runtime::Function* c_function) { | |
| 12241 DCHECK(call->arguments()->length() == 2); | |
| 12242 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | |
| 12243 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | |
| 12244 HValue* key = Pop(); | |
| 12245 HValue* receiver = Pop(); | |
| 12246 | |
| 12247 NoObservableSideEffectsScope no_effects(this); | |
| 12248 | |
| 12249 HIfContinuation continuation; | |
| 12250 HValue* hash = | |
| 12251 BuildStringHashLoadIfIsStringAndHashComputed(key, &continuation); | |
| 12252 { | 12150 { |
| 12253 IfBuilder string_checker(this, &continuation); | 12151 IfBuilder string_checker(this); |
|
Sven Panne
2015/02/23 09:26:53
As a general rule of thumb, we should not have any
adamk
2015/02/23 18:43:34
Thanks, this is good feedback. "No non-trivial con
adamk
2015/02/23 19:49:06
One more issue here: the hash field in Strings use
adamk
2015/03/16 17:35:06
Turns out this works fine if it just gets returned
| |
| 12152 string_checker.If<HCompareNumericAndBranch>( | |
| 12153 hash_computed_test, graph()->GetConstant0(), Token::EQ); | |
| 12254 string_checker.Then(); | 12154 string_checker.Then(); |
| 12255 { | 12155 { |
| 12256 HValue* table = Add<HLoadNamedField>( | 12156 HValue* shifted_hash = |
| 12257 receiver, nullptr, HObjectAccess::ForJSCollectionTable()); | 12157 AddUncasted<HShr>(hash, Add<HConstant>(String::kHashShift)); |
| 12258 HValue* key_index = | 12158 Push(shifted_hash); |
| 12259 BuildOrderedHashTableFindEntry<CollectionType>(table, key, hash); | |
| 12260 { | |
| 12261 IfBuilder if_found(this); | |
| 12262 if_found.If<HCompareNumericAndBranch>( | |
| 12263 key_index, Add<HConstant>(CollectionType::kNotFound), Token::NE); | |
| 12264 if_found.Then(); | |
| 12265 Push(graph()->GetConstantTrue()); | |
| 12266 if_found.Else(); | |
| 12267 Push(graph()->GetConstantFalse()); | |
| 12268 } | |
| 12269 } | 12159 } |
| 12270 string_checker.Else(); | 12160 string_checker.Else(); |
| 12271 { | 12161 { |
| 12272 Add<HPushArguments>(receiver, key); | 12162 Add<HPushArguments>(object); |
| 12273 Push(Add<HCallRuntime>(call->name(), c_function, 2)); | 12163 Push(Add<HCallRuntime>(call->name(), |
| 12164 Runtime::FunctionForId(Runtime::kStringHash), 1)); | |
| 12274 } | 12165 } |
| 12275 } | 12166 } |
| 12276 | |
| 12277 return ast_context()->ReturnValue(Pop()); | 12167 return ast_context()->ReturnValue(Pop()); |
| 12278 } | 12168 } |
| 12279 | 12169 |
| 12280 | 12170 |
| 12281 void HOptimizedGraphBuilder::GenerateMapHas(CallRuntime* call) { | |
| 12282 BuildJSCollectionHas<OrderedHashMap>( | |
| 12283 call, Runtime::FunctionForId(Runtime::kMapHas)); | |
| 12284 } | |
| 12285 | |
| 12286 | |
| 12287 void HOptimizedGraphBuilder::GenerateSetHas(CallRuntime* call) { | |
| 12288 BuildJSCollectionHas<OrderedHashSet>( | |
| 12289 call, Runtime::FunctionForId(Runtime::kSetHas)); | |
| 12290 } | |
| 12291 | |
| 12292 | |
| 12293 template <typename CollectionType> | |
| 12294 HValue* HOptimizedGraphBuilder::BuildOrderedHashTableAddEntry( | |
| 12295 HValue* table, HValue* key, HValue* hash, | |
| 12296 HIfContinuation* join_continuation) { | |
| 12297 HValue* num_buckets = Add<HLoadNamedField>( | |
| 12298 table, nullptr, | |
| 12299 HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>()); | |
| 12300 HValue* capacity = AddUncasted<HMul>( | |
| 12301 num_buckets, Add<HConstant>(CollectionType::kLoadFactor)); | |
| 12302 capacity->ClearFlag(HValue::kCanOverflow); | |
| 12303 HValue* num_elements = Add<HLoadNamedField>( | |
| 12304 table, nullptr, | |
| 12305 HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>()); | |
| 12306 HValue* num_deleted = Add<HLoadNamedField>( | |
| 12307 table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements< | |
| 12308 CollectionType>()); | |
| 12309 HValue* used = AddUncasted<HAdd>(num_elements, num_deleted); | |
| 12310 used->ClearFlag(HValue::kCanOverflow); | |
| 12311 IfBuilder if_space_available(this); | |
| 12312 if_space_available.If<HCompareNumericAndBranch>(capacity, used, Token::GT); | |
| 12313 if_space_available.Then(); | |
| 12314 HValue* bucket = BuildOrderedHashTableHashToBucket(hash, num_buckets); | |
| 12315 HValue* entry = used; | |
| 12316 HValue* key_index = | |
| 12317 BuildOrderedHashTableEntryToIndex<CollectionType>(entry, num_buckets); | |
| 12318 | |
| 12319 HValue* bucket_index = AddUncasted<HAdd>( | |
| 12320 bucket, Add<HConstant>(CollectionType::kHashTableStartIndex)); | |
| 12321 bucket_index->ClearFlag(HValue::kCanOverflow); | |
| 12322 HValue* chain_entry = | |
| 12323 Add<HLoadKeyed>(table, bucket_index, nullptr, FAST_ELEMENTS); | |
| 12324 chain_entry->set_type(HType::Smi()); | |
| 12325 | |
| 12326 HValue* chain_index = AddUncasted<HAdd>( | |
| 12327 key_index, Add<HConstant>(CollectionType::kChainOffset)); | |
| 12328 chain_index->ClearFlag(HValue::kCanOverflow); | |
| 12329 | |
| 12330 Add<HStoreKeyed>(table, bucket_index, entry, FAST_ELEMENTS); | |
| 12331 Add<HStoreKeyed>(table, chain_index, chain_entry, FAST_ELEMENTS); | |
| 12332 Add<HStoreKeyed>(table, key_index, key, FAST_ELEMENTS); | |
| 12333 | |
| 12334 HValue* new_num_elements = | |
| 12335 AddUncasted<HAdd>(num_elements, graph()->GetConstant1()); | |
| 12336 new_num_elements->ClearFlag(HValue::kCanOverflow); | |
| 12337 Add<HStoreNamedField>( | |
| 12338 table, | |
| 12339 HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>(), | |
| 12340 new_num_elements); | |
| 12341 if_space_available.JoinContinuation(join_continuation); | |
| 12342 return key_index; | |
| 12343 } | |
| 12344 | |
| 12345 | |
| 12346 void HOptimizedGraphBuilder::GenerateMapSet(CallRuntime* call) { | |
| 12347 DCHECK(call->arguments()->length() == 3); | |
| 12348 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | |
| 12349 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | |
| 12350 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); | |
| 12351 HValue* value = Pop(); | |
| 12352 HValue* key = Pop(); | |
| 12353 HValue* receiver = Pop(); | |
| 12354 | |
| 12355 NoObservableSideEffectsScope no_effects(this); | |
| 12356 | |
| 12357 HIfContinuation return_or_call_runtime_continuation( | |
| 12358 graph()->CreateBasicBlock(), graph()->CreateBasicBlock()); | |
| 12359 HIfContinuation got_string_hash; | |
| 12360 HValue* hash = | |
| 12361 BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash); | |
| 12362 IfBuilder string_checker(this, &got_string_hash); | |
| 12363 string_checker.Then(); | |
| 12364 { | |
| 12365 HValue* table = Add<HLoadNamedField>(receiver, nullptr, | |
| 12366 HObjectAccess::ForJSCollectionTable()); | |
| 12367 HValue* key_index = | |
| 12368 BuildOrderedHashTableFindEntry<OrderedHashMap>(table, key, hash); | |
| 12369 { | |
| 12370 IfBuilder if_found(this); | |
| 12371 if_found.If<HCompareNumericAndBranch>( | |
| 12372 key_index, Add<HConstant>(OrderedHashMap::kNotFound), Token::NE); | |
| 12373 if_found.Then(); | |
| 12374 { | |
| 12375 HValue* value_index = AddUncasted<HAdd>( | |
| 12376 key_index, Add<HConstant>(OrderedHashMap::kValueOffset)); | |
| 12377 value_index->ClearFlag(HValue::kCanOverflow); | |
| 12378 Add<HStoreKeyed>(table, value_index, value, FAST_ELEMENTS); | |
| 12379 } | |
| 12380 if_found.Else(); | |
| 12381 { | |
| 12382 HIfContinuation did_add(graph()->CreateBasicBlock(), | |
| 12383 graph()->CreateBasicBlock()); | |
| 12384 HValue* key_index = BuildOrderedHashTableAddEntry<OrderedHashMap>( | |
| 12385 table, key, hash, &did_add); | |
| 12386 IfBuilder if_did_add(this, &did_add); | |
| 12387 if_did_add.Then(); | |
| 12388 { | |
| 12389 HValue* value_index = AddUncasted<HAdd>( | |
| 12390 key_index, Add<HConstant>(OrderedHashMap::kValueOffset)); | |
| 12391 value_index->ClearFlag(HValue::kCanOverflow); | |
| 12392 Add<HStoreKeyed>(table, value_index, value, FAST_ELEMENTS); | |
| 12393 } | |
| 12394 if_did_add.JoinContinuation(&return_or_call_runtime_continuation); | |
| 12395 } | |
| 12396 } | |
| 12397 } | |
| 12398 string_checker.JoinContinuation(&return_or_call_runtime_continuation); | |
| 12399 | |
| 12400 { | |
| 12401 IfBuilder return_or_call_runtime(this, | |
| 12402 &return_or_call_runtime_continuation); | |
| 12403 return_or_call_runtime.Then(); | |
| 12404 Push(receiver); | |
| 12405 return_or_call_runtime.Else(); | |
| 12406 Add<HPushArguments>(receiver, key, value); | |
| 12407 Push(Add<HCallRuntime>(call->name(), | |
| 12408 Runtime::FunctionForId(Runtime::kMapSet), 3)); | |
| 12409 } | |
| 12410 | |
| 12411 return ast_context()->ReturnValue(Pop()); | |
| 12412 } | |
| 12413 | |
| 12414 | |
| 12415 void HOptimizedGraphBuilder::GenerateSetAdd(CallRuntime* call) { | |
| 12416 DCHECK(call->arguments()->length() == 2); | |
| 12417 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | |
| 12418 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | |
| 12419 HValue* key = Pop(); | |
| 12420 HValue* receiver = Pop(); | |
| 12421 | |
| 12422 NoObservableSideEffectsScope no_effects(this); | |
| 12423 | |
| 12424 HIfContinuation return_or_call_runtime_continuation( | |
| 12425 graph()->CreateBasicBlock(), graph()->CreateBasicBlock()); | |
| 12426 HIfContinuation got_string_hash; | |
| 12427 HValue* hash = | |
| 12428 BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash); | |
| 12429 IfBuilder string_checker(this, &got_string_hash); | |
| 12430 string_checker.Then(); | |
| 12431 { | |
| 12432 HValue* table = Add<HLoadNamedField>(receiver, nullptr, | |
| 12433 HObjectAccess::ForJSCollectionTable()); | |
| 12434 HValue* key_index = | |
| 12435 BuildOrderedHashTableFindEntry<OrderedHashSet>(table, key, hash); | |
| 12436 { | |
| 12437 IfBuilder if_not_found(this); | |
| 12438 if_not_found.If<HCompareNumericAndBranch>( | |
| 12439 key_index, Add<HConstant>(OrderedHashSet::kNotFound), Token::EQ); | |
| 12440 if_not_found.Then(); | |
| 12441 BuildOrderedHashTableAddEntry<OrderedHashSet>( | |
| 12442 table, key, hash, &return_or_call_runtime_continuation); | |
| 12443 } | |
| 12444 } | |
| 12445 string_checker.JoinContinuation(&return_or_call_runtime_continuation); | |
| 12446 | |
| 12447 { | |
| 12448 IfBuilder return_or_call_runtime(this, | |
| 12449 &return_or_call_runtime_continuation); | |
| 12450 return_or_call_runtime.Then(); | |
| 12451 Push(receiver); | |
| 12452 return_or_call_runtime.Else(); | |
| 12453 Add<HPushArguments>(receiver, key); | |
| 12454 Push(Add<HCallRuntime>(call->name(), | |
| 12455 Runtime::FunctionForId(Runtime::kSetAdd), 2)); | |
| 12456 } | |
| 12457 | |
| 12458 return ast_context()->ReturnValue(Pop()); | |
| 12459 } | |
| 12460 | |
| 12461 | |
| 12462 template <typename CollectionType> | |
| 12463 void HOptimizedGraphBuilder::BuildJSCollectionDelete( | |
| 12464 CallRuntime* call, const Runtime::Function* c_function) { | |
| 12465 DCHECK(call->arguments()->length() == 2); | |
| 12466 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | |
| 12467 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | |
| 12468 HValue* key = Pop(); | |
| 12469 HValue* receiver = Pop(); | |
| 12470 | |
| 12471 NoObservableSideEffectsScope no_effects(this); | |
| 12472 | |
| 12473 HIfContinuation return_or_call_runtime_continuation( | |
| 12474 graph()->CreateBasicBlock(), graph()->CreateBasicBlock()); | |
| 12475 HIfContinuation got_string_hash; | |
| 12476 HValue* hash = | |
| 12477 BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash); | |
| 12478 IfBuilder string_checker(this, &got_string_hash); | |
| 12479 string_checker.Then(); | |
| 12480 { | |
| 12481 HValue* table = Add<HLoadNamedField>(receiver, nullptr, | |
| 12482 HObjectAccess::ForJSCollectionTable()); | |
| 12483 HValue* key_index = | |
| 12484 BuildOrderedHashTableFindEntry<CollectionType>(table, key, hash); | |
| 12485 { | |
| 12486 IfBuilder if_found(this); | |
| 12487 if_found.If<HCompareNumericAndBranch>( | |
| 12488 key_index, Add<HConstant>(CollectionType::kNotFound), Token::NE); | |
| 12489 if_found.Then(); | |
| 12490 { | |
| 12491 // If we're removing an element, we might need to shrink. | |
| 12492 // If we do need to shrink, we'll be bailing out to the runtime. | |
| 12493 HValue* num_elements = Add<HLoadNamedField>( | |
| 12494 table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfElements< | |
| 12495 CollectionType>()); | |
| 12496 num_elements = AddUncasted<HSub>(num_elements, graph()->GetConstant1()); | |
| 12497 num_elements->ClearFlag(HValue::kCanOverflow); | |
| 12498 | |
| 12499 HValue* num_buckets = Add<HLoadNamedField>( | |
| 12500 table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfBuckets< | |
| 12501 CollectionType>()); | |
| 12502 // threshold is capacity >> 2; we simplify this to num_buckets >> 1 | |
| 12503 // since kLoadFactor is 2. | |
| 12504 STATIC_ASSERT(CollectionType::kLoadFactor == 2); | |
| 12505 HValue* threshold = | |
| 12506 AddUncasted<HShr>(num_buckets, graph()->GetConstant1()); | |
| 12507 | |
| 12508 IfBuilder if_need_not_shrink(this); | |
| 12509 if_need_not_shrink.If<HCompareNumericAndBranch>(num_elements, threshold, | |
| 12510 Token::GTE); | |
| 12511 if_need_not_shrink.Then(); | |
| 12512 { | |
| 12513 Add<HStoreKeyed>(table, key_index, graph()->GetConstantHole(), | |
| 12514 FAST_ELEMENTS); | |
| 12515 | |
| 12516 // For maps, also need to clear the value. | |
| 12517 if (CollectionType::kChainOffset > 1) { | |
| 12518 HValue* value_index = | |
| 12519 AddUncasted<HAdd>(key_index, graph()->GetConstant1()); | |
| 12520 value_index->ClearFlag(HValue::kCanOverflow); | |
| 12521 Add<HStoreKeyed>(table, value_index, graph()->GetConstantHole(), | |
| 12522 FAST_ELEMENTS); | |
| 12523 } | |
| 12524 STATIC_ASSERT(CollectionType::kChainOffset <= 2); | |
| 12525 | |
| 12526 HValue* num_deleted = Add<HLoadNamedField>( | |
| 12527 table, nullptr, | |
| 12528 HObjectAccess::ForOrderedHashTableNumberOfDeletedElements< | |
| 12529 CollectionType>()); | |
| 12530 num_deleted = AddUncasted<HAdd>(num_deleted, graph()->GetConstant1()); | |
| 12531 num_deleted->ClearFlag(HValue::kCanOverflow); | |
| 12532 Add<HStoreNamedField>( | |
| 12533 table, HObjectAccess::ForOrderedHashTableNumberOfElements< | |
| 12534 CollectionType>(), | |
| 12535 num_elements); | |
| 12536 Add<HStoreNamedField>( | |
| 12537 table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements< | |
| 12538 CollectionType>(), | |
| 12539 num_deleted); | |
| 12540 Push(graph()->GetConstantTrue()); | |
| 12541 } | |
| 12542 if_need_not_shrink.JoinContinuation( | |
| 12543 &return_or_call_runtime_continuation); | |
| 12544 } | |
| 12545 if_found.Else(); | |
| 12546 { | |
| 12547 // Not found, so we're done. | |
| 12548 Push(graph()->GetConstantFalse()); | |
| 12549 } | |
| 12550 } | |
| 12551 } | |
| 12552 string_checker.JoinContinuation(&return_or_call_runtime_continuation); | |
| 12553 | |
| 12554 { | |
| 12555 IfBuilder return_or_call_runtime(this, | |
| 12556 &return_or_call_runtime_continuation); | |
| 12557 return_or_call_runtime.Then(); | |
| 12558 return_or_call_runtime.Else(); | |
| 12559 Add<HPushArguments>(receiver, key); | |
| 12560 Push(Add<HCallRuntime>(call->name(), c_function, 2)); | |
| 12561 } | |
| 12562 | |
| 12563 return ast_context()->ReturnValue(Pop()); | |
| 12564 } | |
| 12565 | |
| 12566 | |
| 12567 void HOptimizedGraphBuilder::GenerateMapDelete(CallRuntime* call) { | |
| 12568 BuildJSCollectionDelete<OrderedHashMap>( | |
| 12569 call, Runtime::FunctionForId(Runtime::kMapDelete)); | |
| 12570 } | |
| 12571 | |
| 12572 | |
| 12573 void HOptimizedGraphBuilder::GenerateSetDelete(CallRuntime* call) { | |
| 12574 BuildJSCollectionDelete<OrderedHashSet>( | |
| 12575 call, Runtime::FunctionForId(Runtime::kSetDelete)); | |
| 12576 } | |
| 12577 | |
| 12578 | |
| 12579 void HOptimizedGraphBuilder::GenerateSetGetSize(CallRuntime* call) { | |
| 12580 DCHECK(call->arguments()->length() == 1); | |
| 12581 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | |
| 12582 HValue* receiver = Pop(); | |
| 12583 HValue* table = Add<HLoadNamedField>(receiver, nullptr, | |
| 12584 HObjectAccess::ForJSCollectionTable()); | |
| 12585 HInstruction* result = New<HLoadNamedField>( | |
| 12586 table, nullptr, | |
| 12587 HObjectAccess::ForOrderedHashTableNumberOfElements<OrderedHashSet>()); | |
| 12588 return ast_context()->ReturnInstruction(result, call->id()); | |
| 12589 } | |
| 12590 | |
| 12591 | |
| 12592 void HOptimizedGraphBuilder::GenerateMapGetSize(CallRuntime* call) { | |
| 12593 DCHECK(call->arguments()->length() == 1); | |
| 12594 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | |
| 12595 HValue* receiver = Pop(); | |
| 12596 HValue* table = Add<HLoadNamedField>(receiver, nullptr, | |
| 12597 HObjectAccess::ForJSCollectionTable()); | |
| 12598 HInstruction* result = New<HLoadNamedField>( | |
| 12599 table, nullptr, | |
| 12600 HObjectAccess::ForOrderedHashTableNumberOfElements<OrderedHashMap>()); | |
| 12601 return ast_context()->ReturnInstruction(result, call->id()); | |
| 12602 } | |
| 12603 | |
| 12604 | |
| 12605 template <typename CollectionType> | 12171 template <typename CollectionType> |
| 12606 HValue* HOptimizedGraphBuilder::BuildAllocateOrderedHashTable() { | 12172 HValue* HOptimizedGraphBuilder::BuildAllocateOrderedHashTable() { |
| 12607 static const int kCapacity = CollectionType::kMinCapacity; | 12173 static const int kCapacity = CollectionType::kMinCapacity; |
| 12608 static const int kBucketCount = kCapacity / CollectionType::kLoadFactor; | 12174 static const int kBucketCount = kCapacity / CollectionType::kLoadFactor; |
| 12609 static const int kFixedArrayLength = CollectionType::kHashTableStartIndex + | 12175 static const int kFixedArrayLength = CollectionType::kHashTableStartIndex + |
| 12610 kBucketCount + | 12176 kBucketCount + |
| 12611 (kCapacity * CollectionType::kEntrySize); | 12177 (kCapacity * CollectionType::kEntrySize); |
| 12612 static const int kSizeInBytes = | 12178 static const int kSizeInBytes = |
| 12613 FixedArray::kHeaderSize + (kFixedArrayLength * kPointerSize); | 12179 FixedArray::kHeaderSize + (kFixedArrayLength * kPointerSize); |
| 12614 | 12180 |
| (...skipping 824 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 13439 if (ShouldProduceTraceOutput()) { | 13005 if (ShouldProduceTraceOutput()) { |
| 13440 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 13006 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 13441 } | 13007 } |
| 13442 | 13008 |
| 13443 #ifdef DEBUG | 13009 #ifdef DEBUG |
| 13444 graph_->Verify(false); // No full verify. | 13010 graph_->Verify(false); // No full verify. |
| 13445 #endif | 13011 #endif |
| 13446 } | 13012 } |
| 13447 | 13013 |
| 13448 } } // namespace v8::internal | 13014 } } // namespace v8::internal |
| OLD | NEW |