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 |