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 12015 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 12026 | 12026 |
| 12027 void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) { | 12027 void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) { |
| 12028 DCHECK(call->arguments()->length() == 1); | 12028 DCHECK(call->arguments()->length() == 1); |
| 12029 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 12029 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12030 HValue* value = Pop(); | 12030 HValue* value = Pop(); |
| 12031 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt); | 12031 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt); |
| 12032 return ast_context()->ReturnInstruction(result, call->id()); | 12032 return ast_context()->ReturnInstruction(result, call->id()); |
| 12033 } | 12033 } |
| 12034 | 12034 |
| 12035 | 12035 |
| 12036 HValue* HOptimizedGraphBuilder::BuildOrderedHashTableHashToBucket( | 12036 void HOptimizedGraphBuilder::GenerateFixedArrayGet(CallRuntime* call) { |
| 12037 HValue* hash, HValue* num_buckets) { | 12037 DCHECK(call->arguments()->length() == 2); |
| 12038 HValue* mask = AddUncasted<HSub>(num_buckets, graph()->GetConstant1()); | 12038 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12039 mask->ChangeRepresentation(Representation::Integer32()); | 12039 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 12040 mask->ClearFlag(HValue::kCanOverflow); | 12040 HValue* index = Pop(); |
| 12041 return AddUncasted<HBitwise>(Token::BIT_AND, hash, mask); | 12041 HValue* object = Pop(); |
| 12042 HInstruction* result = New<HLoadKeyed>(object, index, nullptr, FAST_ELEMENTS); | |
|
Toon Verwaest
2015/03/30 12:55:42
Seems like it would be more honest to FAST_HOLEY_E
adamk
2015/03/30 18:44:54
Done.
arv (Not doing code reviews)
2015/03/30 18:55:22
Would that impact the performance?
adamk
2015/03/30 22:31:50
I don't believe so, but if it does, that's because
| |
| 12043 return ast_context()->ReturnInstruction(result, call->id()); | |
| 12042 } | 12044 } |
| 12043 | 12045 |
| 12044 | 12046 |
| 12045 template <typename CollectionType> | 12047 void HOptimizedGraphBuilder::GenerateFixedArraySet(CallRuntime* call) { |
| 12046 HValue* HOptimizedGraphBuilder::BuildOrderedHashTableHashToEntry( | |
| 12047 HValue* table, HValue* hash, HValue* num_buckets) { | |
| 12048 HValue* bucket = BuildOrderedHashTableHashToBucket(hash, num_buckets); | |
| 12049 HValue* entry_index = AddUncasted<HAdd>( | |
| 12050 bucket, Add<HConstant>(CollectionType::kHashTableStartIndex)); | |
| 12051 entry_index->ClearFlag(HValue::kCanOverflow); | |
| 12052 HValue* entry = Add<HLoadKeyed>(table, entry_index, nullptr, FAST_ELEMENTS); | |
| 12053 entry->set_type(HType::Smi()); | |
| 12054 return entry; | |
| 12055 } | |
| 12056 | |
| 12057 | |
| 12058 template <typename CollectionType> | |
| 12059 HValue* HOptimizedGraphBuilder::BuildOrderedHashTableEntryToIndex( | |
| 12060 HValue* entry, HValue* num_buckets) { | |
| 12061 HValue* index = | |
| 12062 AddUncasted<HMul>(entry, Add<HConstant>(CollectionType::kEntrySize)); | |
| 12063 index->ClearFlag(HValue::kCanOverflow); | |
| 12064 index = AddUncasted<HAdd>(index, num_buckets); | |
| 12065 index->ClearFlag(HValue::kCanOverflow); | |
| 12066 index = AddUncasted<HAdd>( | |
| 12067 index, Add<HConstant>(CollectionType::kHashTableStartIndex)); | |
| 12068 index->ClearFlag(HValue::kCanOverflow); | |
| 12069 return index; | |
| 12070 } | |
| 12071 | |
| 12072 | |
| 12073 template <typename CollectionType> | |
| 12074 HValue* HOptimizedGraphBuilder::BuildOrderedHashTableFindEntry(HValue* table, | |
| 12075 HValue* key, | |
| 12076 HValue* hash) { | |
| 12077 HValue* num_buckets = Add<HLoadNamedField>( | |
| 12078 table, nullptr, | |
| 12079 HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>()); | |
| 12080 | |
| 12081 HValue* entry = BuildOrderedHashTableHashToEntry<CollectionType>(table, hash, | |
| 12082 num_buckets); | |
| 12083 | |
| 12084 Push(entry); | |
| 12085 | |
| 12086 LoopBuilder loop(this); | |
| 12087 loop.BeginBody(1); | |
| 12088 | |
| 12089 entry = Pop(); | |
| 12090 | |
| 12091 { | |
| 12092 IfBuilder if_not_found(this); | |
| 12093 if_not_found.If<HCompareNumericAndBranch>( | |
| 12094 entry, Add<HConstant>(CollectionType::kNotFound), Token::EQ); | |
| 12095 if_not_found.Then(); | |
| 12096 Push(entry); | |
| 12097 loop.Break(); | |
| 12098 } | |
| 12099 | |
| 12100 HValue* key_index = | |
| 12101 BuildOrderedHashTableEntryToIndex<CollectionType>(entry, num_buckets); | |
| 12102 HValue* candidate_key = | |
| 12103 Add<HLoadKeyed>(table, key_index, nullptr, FAST_ELEMENTS); | |
| 12104 | |
| 12105 { | |
| 12106 IfBuilder if_keys_equal(this); | |
| 12107 if_keys_equal.If<HIsStringAndBranch>(candidate_key); | |
| 12108 if_keys_equal.AndIf<HStringCompareAndBranch>(candidate_key, key, | |
| 12109 Token::EQ_STRICT); | |
| 12110 if_keys_equal.Then(); | |
| 12111 Push(key_index); | |
| 12112 loop.Break(); | |
| 12113 } | |
| 12114 | |
| 12115 // BuildChainAt | |
| 12116 HValue* chain_index = AddUncasted<HAdd>( | |
| 12117 key_index, Add<HConstant>(CollectionType::kChainOffset)); | |
| 12118 chain_index->ClearFlag(HValue::kCanOverflow); | |
| 12119 entry = Add<HLoadKeyed>(table, chain_index, nullptr, FAST_ELEMENTS); | |
| 12120 entry->set_type(HType::Smi()); | |
| 12121 Push(entry); | |
| 12122 | |
| 12123 loop.EndBody(); | |
| 12124 | |
| 12125 return Pop(); | |
| 12126 } | |
| 12127 | |
| 12128 | |
| 12129 void HOptimizedGraphBuilder::GenerateMapGet(CallRuntime* call) { | |
| 12130 DCHECK(call->arguments()->length() == 2); | |
| 12131 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | |
| 12132 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | |
| 12133 HValue* key = Pop(); | |
| 12134 HValue* receiver = Pop(); | |
| 12135 | |
| 12136 NoObservableSideEffectsScope no_effects(this); | |
| 12137 | |
| 12138 HIfContinuation continuation; | |
| 12139 HValue* hash = | |
| 12140 BuildStringHashLoadIfIsStringAndHashComputed(key, &continuation); | |
| 12141 { | |
| 12142 IfBuilder string_checker(this, &continuation); | |
| 12143 string_checker.Then(); | |
| 12144 { | |
| 12145 HValue* table = Add<HLoadNamedField>( | |
| 12146 receiver, nullptr, HObjectAccess::ForJSCollectionTable()); | |
| 12147 HValue* key_index = | |
| 12148 BuildOrderedHashTableFindEntry<OrderedHashMap>(table, key, hash); | |
| 12149 IfBuilder if_found(this); | |
| 12150 if_found.If<HCompareNumericAndBranch>( | |
| 12151 key_index, Add<HConstant>(OrderedHashMap::kNotFound), Token::NE); | |
| 12152 if_found.Then(); | |
| 12153 { | |
| 12154 HValue* value_index = AddUncasted<HAdd>( | |
| 12155 key_index, Add<HConstant>(OrderedHashMap::kValueOffset)); | |
| 12156 value_index->ClearFlag(HValue::kCanOverflow); | |
| 12157 Push(Add<HLoadKeyed>(table, value_index, nullptr, FAST_ELEMENTS)); | |
| 12158 } | |
| 12159 if_found.Else(); | |
| 12160 Push(graph()->GetConstantUndefined()); | |
| 12161 if_found.End(); | |
| 12162 } | |
| 12163 string_checker.Else(); | |
| 12164 { | |
| 12165 Add<HPushArguments>(receiver, key); | |
| 12166 Push(Add<HCallRuntime>(call->name(), | |
| 12167 Runtime::FunctionForId(Runtime::kMapGet), 2)); | |
| 12168 } | |
| 12169 } | |
| 12170 | |
| 12171 return ast_context()->ReturnValue(Pop()); | |
| 12172 } | |
| 12173 | |
| 12174 | |
| 12175 HValue* HOptimizedGraphBuilder::BuildStringHashLoadIfIsStringAndHashComputed( | |
| 12176 HValue* object, HIfContinuation* continuation) { | |
| 12177 IfBuilder string_checker(this); | |
| 12178 string_checker.If<HIsStringAndBranch>(object); | |
| 12179 string_checker.And(); | |
| 12180 HValue* hash = Add<HLoadNamedField>(object, nullptr, | |
| 12181 HObjectAccess::ForStringHashField()); | |
| 12182 HValue* hash_not_computed_mask = Add<HConstant>(String::kHashNotComputedMask); | |
| 12183 HValue* hash_computed_test = | |
| 12184 AddUncasted<HBitwise>(Token::BIT_AND, hash, hash_not_computed_mask); | |
| 12185 string_checker.If<HCompareNumericAndBranch>( | |
| 12186 hash_computed_test, graph()->GetConstant0(), Token::EQ); | |
| 12187 string_checker.Then(); | |
| 12188 HValue* shifted_hash = | |
| 12189 AddUncasted<HShr>(hash, Add<HConstant>(String::kHashShift)); | |
| 12190 string_checker.CaptureContinuation(continuation); | |
| 12191 return shifted_hash; | |
| 12192 } | |
| 12193 | |
| 12194 | |
| 12195 template <typename CollectionType> | |
| 12196 void HOptimizedGraphBuilder::BuildJSCollectionHas( | |
| 12197 CallRuntime* call, const Runtime::Function* c_function) { | |
| 12198 DCHECK(call->arguments()->length() == 2); | |
| 12199 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | |
| 12200 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | |
| 12201 HValue* key = Pop(); | |
| 12202 HValue* receiver = Pop(); | |
| 12203 | |
| 12204 NoObservableSideEffectsScope no_effects(this); | |
| 12205 | |
| 12206 HIfContinuation continuation; | |
| 12207 HValue* hash = | |
| 12208 BuildStringHashLoadIfIsStringAndHashComputed(key, &continuation); | |
| 12209 { | |
| 12210 IfBuilder string_checker(this, &continuation); | |
| 12211 string_checker.Then(); | |
| 12212 { | |
| 12213 HValue* table = Add<HLoadNamedField>( | |
| 12214 receiver, nullptr, HObjectAccess::ForJSCollectionTable()); | |
| 12215 HValue* key_index = | |
| 12216 BuildOrderedHashTableFindEntry<CollectionType>(table, key, hash); | |
| 12217 { | |
| 12218 IfBuilder if_found(this); | |
| 12219 if_found.If<HCompareNumericAndBranch>( | |
| 12220 key_index, Add<HConstant>(CollectionType::kNotFound), Token::NE); | |
| 12221 if_found.Then(); | |
| 12222 Push(graph()->GetConstantTrue()); | |
| 12223 if_found.Else(); | |
| 12224 Push(graph()->GetConstantFalse()); | |
| 12225 } | |
| 12226 } | |
| 12227 string_checker.Else(); | |
| 12228 { | |
| 12229 Add<HPushArguments>(receiver, key); | |
| 12230 Push(Add<HCallRuntime>(call->name(), c_function, 2)); | |
| 12231 } | |
| 12232 } | |
| 12233 | |
| 12234 return ast_context()->ReturnValue(Pop()); | |
| 12235 } | |
| 12236 | |
| 12237 | |
| 12238 void HOptimizedGraphBuilder::GenerateMapHas(CallRuntime* call) { | |
| 12239 BuildJSCollectionHas<OrderedHashMap>( | |
| 12240 call, Runtime::FunctionForId(Runtime::kMapHas)); | |
| 12241 } | |
| 12242 | |
| 12243 | |
| 12244 void HOptimizedGraphBuilder::GenerateSetHas(CallRuntime* call) { | |
| 12245 BuildJSCollectionHas<OrderedHashSet>( | |
| 12246 call, Runtime::FunctionForId(Runtime::kSetHas)); | |
| 12247 } | |
| 12248 | |
| 12249 | |
| 12250 template <typename CollectionType> | |
| 12251 HValue* HOptimizedGraphBuilder::BuildOrderedHashTableAddEntry( | |
| 12252 HValue* table, HValue* key, HValue* hash, | |
| 12253 HIfContinuation* join_continuation) { | |
| 12254 HValue* num_buckets = Add<HLoadNamedField>( | |
| 12255 table, nullptr, | |
| 12256 HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>()); | |
| 12257 HValue* capacity = AddUncasted<HMul>( | |
| 12258 num_buckets, Add<HConstant>(CollectionType::kLoadFactor)); | |
| 12259 capacity->ClearFlag(HValue::kCanOverflow); | |
| 12260 HValue* num_elements = Add<HLoadNamedField>( | |
| 12261 table, nullptr, | |
| 12262 HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>()); | |
| 12263 HValue* num_deleted = Add<HLoadNamedField>( | |
| 12264 table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements< | |
| 12265 CollectionType>()); | |
| 12266 HValue* used = AddUncasted<HAdd>(num_elements, num_deleted); | |
| 12267 used->ClearFlag(HValue::kCanOverflow); | |
| 12268 IfBuilder if_space_available(this); | |
| 12269 if_space_available.If<HCompareNumericAndBranch>(capacity, used, Token::GT); | |
| 12270 if_space_available.Then(); | |
| 12271 HValue* bucket = BuildOrderedHashTableHashToBucket(hash, num_buckets); | |
| 12272 HValue* entry = used; | |
| 12273 HValue* key_index = | |
| 12274 BuildOrderedHashTableEntryToIndex<CollectionType>(entry, num_buckets); | |
| 12275 | |
| 12276 HValue* bucket_index = AddUncasted<HAdd>( | |
| 12277 bucket, Add<HConstant>(CollectionType::kHashTableStartIndex)); | |
| 12278 bucket_index->ClearFlag(HValue::kCanOverflow); | |
| 12279 HValue* chain_entry = | |
| 12280 Add<HLoadKeyed>(table, bucket_index, nullptr, FAST_ELEMENTS); | |
| 12281 chain_entry->set_type(HType::Smi()); | |
| 12282 | |
| 12283 HValue* chain_index = AddUncasted<HAdd>( | |
| 12284 key_index, Add<HConstant>(CollectionType::kChainOffset)); | |
| 12285 chain_index->ClearFlag(HValue::kCanOverflow); | |
| 12286 | |
| 12287 Add<HStoreKeyed>(table, bucket_index, entry, FAST_ELEMENTS); | |
| 12288 Add<HStoreKeyed>(table, chain_index, chain_entry, FAST_ELEMENTS); | |
| 12289 Add<HStoreKeyed>(table, key_index, key, FAST_ELEMENTS); | |
| 12290 | |
| 12291 HValue* new_num_elements = | |
| 12292 AddUncasted<HAdd>(num_elements, graph()->GetConstant1()); | |
| 12293 new_num_elements->ClearFlag(HValue::kCanOverflow); | |
| 12294 Add<HStoreNamedField>( | |
| 12295 table, | |
| 12296 HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>(), | |
| 12297 new_num_elements); | |
| 12298 if_space_available.JoinContinuation(join_continuation); | |
| 12299 return key_index; | |
| 12300 } | |
| 12301 | |
| 12302 | |
| 12303 void HOptimizedGraphBuilder::GenerateMapSet(CallRuntime* call) { | |
| 12304 DCHECK(call->arguments()->length() == 3); | 12048 DCHECK(call->arguments()->length() == 3); |
| 12305 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 12049 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12306 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 12050 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 12307 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); | 12051 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); |
| 12308 HValue* value = Pop(); | 12052 HValue* value = Pop(); |
| 12309 HValue* key = Pop(); | 12053 HValue* index = Pop(); |
| 12310 HValue* receiver = Pop(); | 12054 HValue* object = Pop(); |
| 12311 | |
| 12312 NoObservableSideEffectsScope no_effects(this); | 12055 NoObservableSideEffectsScope no_effects(this); |
| 12313 | 12056 Add<HStoreKeyed>(object, index, value, FAST_ELEMENTS); |
|
Toon Verwaest
2015/03/30 12:55:42
FAST_HOLEY_ELEMENTS?
adamk
2015/03/30 18:44:54
Done.
| |
| 12314 HIfContinuation return_or_call_runtime_continuation( | 12057 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 12315 graph()->CreateBasicBlock(), graph()->CreateBasicBlock()); | |
| 12316 HIfContinuation got_string_hash; | |
| 12317 HValue* hash = | |
| 12318 BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash); | |
| 12319 IfBuilder string_checker(this, &got_string_hash); | |
| 12320 string_checker.Then(); | |
| 12321 { | |
| 12322 HValue* table = Add<HLoadNamedField>(receiver, nullptr, | |
| 12323 HObjectAccess::ForJSCollectionTable()); | |
| 12324 HValue* key_index = | |
| 12325 BuildOrderedHashTableFindEntry<OrderedHashMap>(table, key, hash); | |
| 12326 { | |
| 12327 IfBuilder if_found(this); | |
| 12328 if_found.If<HCompareNumericAndBranch>( | |
| 12329 key_index, Add<HConstant>(OrderedHashMap::kNotFound), Token::NE); | |
| 12330 if_found.Then(); | |
| 12331 { | |
| 12332 HValue* value_index = AddUncasted<HAdd>( | |
| 12333 key_index, Add<HConstant>(OrderedHashMap::kValueOffset)); | |
| 12334 value_index->ClearFlag(HValue::kCanOverflow); | |
| 12335 Add<HStoreKeyed>(table, value_index, value, FAST_ELEMENTS); | |
| 12336 } | |
| 12337 if_found.Else(); | |
| 12338 { | |
| 12339 HIfContinuation did_add(graph()->CreateBasicBlock(), | |
| 12340 graph()->CreateBasicBlock()); | |
| 12341 HValue* key_index = BuildOrderedHashTableAddEntry<OrderedHashMap>( | |
| 12342 table, key, hash, &did_add); | |
| 12343 IfBuilder if_did_add(this, &did_add); | |
| 12344 if_did_add.Then(); | |
| 12345 { | |
| 12346 HValue* value_index = AddUncasted<HAdd>( | |
| 12347 key_index, Add<HConstant>(OrderedHashMap::kValueOffset)); | |
| 12348 value_index->ClearFlag(HValue::kCanOverflow); | |
| 12349 Add<HStoreKeyed>(table, value_index, value, FAST_ELEMENTS); | |
| 12350 } | |
| 12351 if_did_add.JoinContinuation(&return_or_call_runtime_continuation); | |
| 12352 } | |
| 12353 } | |
| 12354 } | |
| 12355 string_checker.JoinContinuation(&return_or_call_runtime_continuation); | |
| 12356 | |
| 12357 { | |
| 12358 IfBuilder return_or_call_runtime(this, | |
| 12359 &return_or_call_runtime_continuation); | |
| 12360 return_or_call_runtime.Then(); | |
| 12361 Push(receiver); | |
| 12362 return_or_call_runtime.Else(); | |
| 12363 Add<HPushArguments>(receiver, key, value); | |
| 12364 Push(Add<HCallRuntime>(call->name(), | |
| 12365 Runtime::FunctionForId(Runtime::kMapSet), 3)); | |
| 12366 } | |
| 12367 | |
| 12368 return ast_context()->ReturnValue(Pop()); | |
| 12369 } | 12058 } |
| 12370 | 12059 |
| 12371 | 12060 |
| 12372 void HOptimizedGraphBuilder::GenerateSetAdd(CallRuntime* call) { | 12061 void HOptimizedGraphBuilder::GenerateTheHole(CallRuntime* call) { |
| 12373 DCHECK(call->arguments()->length() == 2); | 12062 DCHECK(call->arguments()->length() == 0); |
| 12374 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 12063 return ast_context()->ReturnValue(graph()->GetConstantHole()); |
| 12375 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | |
| 12376 HValue* key = Pop(); | |
| 12377 HValue* receiver = Pop(); | |
| 12378 | |
| 12379 NoObservableSideEffectsScope no_effects(this); | |
| 12380 | |
| 12381 HIfContinuation return_or_call_runtime_continuation( | |
| 12382 graph()->CreateBasicBlock(), graph()->CreateBasicBlock()); | |
| 12383 HIfContinuation got_string_hash; | |
| 12384 HValue* hash = | |
| 12385 BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash); | |
| 12386 IfBuilder string_checker(this, &got_string_hash); | |
| 12387 string_checker.Then(); | |
| 12388 { | |
| 12389 HValue* table = Add<HLoadNamedField>(receiver, nullptr, | |
| 12390 HObjectAccess::ForJSCollectionTable()); | |
| 12391 HValue* key_index = | |
| 12392 BuildOrderedHashTableFindEntry<OrderedHashSet>(table, key, hash); | |
| 12393 { | |
| 12394 IfBuilder if_not_found(this); | |
| 12395 if_not_found.If<HCompareNumericAndBranch>( | |
| 12396 key_index, Add<HConstant>(OrderedHashSet::kNotFound), Token::EQ); | |
| 12397 if_not_found.Then(); | |
| 12398 BuildOrderedHashTableAddEntry<OrderedHashSet>( | |
| 12399 table, key, hash, &return_or_call_runtime_continuation); | |
| 12400 } | |
| 12401 } | |
| 12402 string_checker.JoinContinuation(&return_or_call_runtime_continuation); | |
| 12403 | |
| 12404 { | |
| 12405 IfBuilder return_or_call_runtime(this, | |
| 12406 &return_or_call_runtime_continuation); | |
| 12407 return_or_call_runtime.Then(); | |
| 12408 Push(receiver); | |
| 12409 return_or_call_runtime.Else(); | |
| 12410 Add<HPushArguments>(receiver, key); | |
| 12411 Push(Add<HCallRuntime>(call->name(), | |
| 12412 Runtime::FunctionForId(Runtime::kSetAdd), 2)); | |
| 12413 } | |
| 12414 | |
| 12415 return ast_context()->ReturnValue(Pop()); | |
| 12416 } | 12064 } |
| 12417 | 12065 |
| 12418 | 12066 |
| 12419 template <typename CollectionType> | 12067 void HOptimizedGraphBuilder::GenerateJSCollectionGetTable(CallRuntime* call) { |
| 12420 void HOptimizedGraphBuilder::BuildJSCollectionDelete( | |
| 12421 CallRuntime* call, const Runtime::Function* c_function) { | |
| 12422 DCHECK(call->arguments()->length() == 2); | |
| 12423 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | |
| 12424 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | |
| 12425 HValue* key = Pop(); | |
| 12426 HValue* receiver = Pop(); | |
| 12427 | |
| 12428 NoObservableSideEffectsScope no_effects(this); | |
| 12429 | |
| 12430 HIfContinuation return_or_call_runtime_continuation( | |
| 12431 graph()->CreateBasicBlock(), graph()->CreateBasicBlock()); | |
| 12432 HIfContinuation got_string_hash; | |
| 12433 HValue* hash = | |
| 12434 BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash); | |
| 12435 IfBuilder string_checker(this, &got_string_hash); | |
| 12436 string_checker.Then(); | |
| 12437 { | |
| 12438 HValue* table = Add<HLoadNamedField>(receiver, nullptr, | |
| 12439 HObjectAccess::ForJSCollectionTable()); | |
| 12440 HValue* key_index = | |
| 12441 BuildOrderedHashTableFindEntry<CollectionType>(table, key, hash); | |
| 12442 { | |
| 12443 IfBuilder if_found(this); | |
| 12444 if_found.If<HCompareNumericAndBranch>( | |
| 12445 key_index, Add<HConstant>(CollectionType::kNotFound), Token::NE); | |
| 12446 if_found.Then(); | |
| 12447 { | |
| 12448 // If we're removing an element, we might need to shrink. | |
| 12449 // If we do need to shrink, we'll be bailing out to the runtime. | |
| 12450 HValue* num_elements = Add<HLoadNamedField>( | |
| 12451 table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfElements< | |
| 12452 CollectionType>()); | |
| 12453 num_elements = AddUncasted<HSub>(num_elements, graph()->GetConstant1()); | |
| 12454 num_elements->ClearFlag(HValue::kCanOverflow); | |
| 12455 | |
| 12456 HValue* num_buckets = Add<HLoadNamedField>( | |
| 12457 table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfBuckets< | |
| 12458 CollectionType>()); | |
| 12459 // threshold is capacity >> 2; we simplify this to num_buckets >> 1 | |
| 12460 // since kLoadFactor is 2. | |
| 12461 STATIC_ASSERT(CollectionType::kLoadFactor == 2); | |
| 12462 HValue* threshold = | |
| 12463 AddUncasted<HShr>(num_buckets, graph()->GetConstant1()); | |
| 12464 | |
| 12465 IfBuilder if_need_not_shrink(this); | |
| 12466 if_need_not_shrink.If<HCompareNumericAndBranch>(num_elements, threshold, | |
| 12467 Token::GTE); | |
| 12468 if_need_not_shrink.Then(); | |
| 12469 { | |
| 12470 Add<HStoreKeyed>(table, key_index, graph()->GetConstantHole(), | |
| 12471 FAST_ELEMENTS); | |
| 12472 | |
| 12473 // For maps, also need to clear the value. | |
| 12474 if (CollectionType::kChainOffset > 1) { | |
| 12475 HValue* value_index = | |
| 12476 AddUncasted<HAdd>(key_index, graph()->GetConstant1()); | |
| 12477 value_index->ClearFlag(HValue::kCanOverflow); | |
| 12478 Add<HStoreKeyed>(table, value_index, graph()->GetConstantHole(), | |
| 12479 FAST_ELEMENTS); | |
| 12480 } | |
| 12481 STATIC_ASSERT(CollectionType::kChainOffset <= 2); | |
| 12482 | |
| 12483 HValue* num_deleted = Add<HLoadNamedField>( | |
| 12484 table, nullptr, | |
| 12485 HObjectAccess::ForOrderedHashTableNumberOfDeletedElements< | |
| 12486 CollectionType>()); | |
| 12487 num_deleted = AddUncasted<HAdd>(num_deleted, graph()->GetConstant1()); | |
| 12488 num_deleted->ClearFlag(HValue::kCanOverflow); | |
| 12489 Add<HStoreNamedField>( | |
| 12490 table, HObjectAccess::ForOrderedHashTableNumberOfElements< | |
| 12491 CollectionType>(), | |
| 12492 num_elements); | |
| 12493 Add<HStoreNamedField>( | |
| 12494 table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements< | |
| 12495 CollectionType>(), | |
| 12496 num_deleted); | |
| 12497 Push(graph()->GetConstantTrue()); | |
| 12498 } | |
| 12499 if_need_not_shrink.JoinContinuation( | |
| 12500 &return_or_call_runtime_continuation); | |
| 12501 } | |
| 12502 if_found.Else(); | |
| 12503 { | |
| 12504 // Not found, so we're done. | |
| 12505 Push(graph()->GetConstantFalse()); | |
| 12506 } | |
| 12507 } | |
| 12508 } | |
| 12509 string_checker.JoinContinuation(&return_or_call_runtime_continuation); | |
| 12510 | |
| 12511 { | |
| 12512 IfBuilder return_or_call_runtime(this, | |
| 12513 &return_or_call_runtime_continuation); | |
| 12514 return_or_call_runtime.Then(); | |
| 12515 return_or_call_runtime.Else(); | |
| 12516 Add<HPushArguments>(receiver, key); | |
| 12517 Push(Add<HCallRuntime>(call->name(), c_function, 2)); | |
| 12518 } | |
| 12519 | |
| 12520 return ast_context()->ReturnValue(Pop()); | |
| 12521 } | |
| 12522 | |
| 12523 | |
| 12524 void HOptimizedGraphBuilder::GenerateMapDelete(CallRuntime* call) { | |
| 12525 BuildJSCollectionDelete<OrderedHashMap>( | |
| 12526 call, Runtime::FunctionForId(Runtime::kMapDelete)); | |
| 12527 } | |
| 12528 | |
| 12529 | |
| 12530 void HOptimizedGraphBuilder::GenerateSetDelete(CallRuntime* call) { | |
| 12531 BuildJSCollectionDelete<OrderedHashSet>( | |
| 12532 call, Runtime::FunctionForId(Runtime::kSetDelete)); | |
| 12533 } | |
| 12534 | |
| 12535 | |
| 12536 void HOptimizedGraphBuilder::GenerateSetGetSize(CallRuntime* call) { | |
| 12537 DCHECK(call->arguments()->length() == 1); | 12068 DCHECK(call->arguments()->length() == 1); |
| 12538 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 12069 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12539 HValue* receiver = Pop(); | 12070 HValue* receiver = Pop(); |
| 12540 HValue* table = Add<HLoadNamedField>(receiver, nullptr, | |
| 12541 HObjectAccess::ForJSCollectionTable()); | |
| 12542 HInstruction* result = New<HLoadNamedField>( | 12071 HInstruction* result = New<HLoadNamedField>( |
| 12543 table, nullptr, | 12072 receiver, nullptr, HObjectAccess::ForJSCollectionTable()); |
| 12544 HObjectAccess::ForOrderedHashTableNumberOfElements<OrderedHashSet>()); | |
| 12545 return ast_context()->ReturnInstruction(result, call->id()); | 12073 return ast_context()->ReturnInstruction(result, call->id()); |
| 12546 } | 12074 } |
| 12547 | 12075 |
| 12548 | 12076 |
| 12549 void HOptimizedGraphBuilder::GenerateMapGetSize(CallRuntime* call) { | 12077 void HOptimizedGraphBuilder::GenerateStringGetRawHashField(CallRuntime* call) { |
| 12550 DCHECK(call->arguments()->length() == 1); | 12078 DCHECK(call->arguments()->length() == 1); |
| 12551 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 12079 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 12552 HValue* receiver = Pop(); | 12080 HValue* object = Pop(); |
| 12553 HValue* table = Add<HLoadNamedField>(receiver, nullptr, | |
| 12554 HObjectAccess::ForJSCollectionTable()); | |
| 12555 HInstruction* result = New<HLoadNamedField>( | 12081 HInstruction* result = New<HLoadNamedField>( |
| 12556 table, nullptr, | 12082 object, nullptr, HObjectAccess::ForStringHashField()); |
| 12557 HObjectAccess::ForOrderedHashTableNumberOfElements<OrderedHashMap>()); | |
| 12558 return ast_context()->ReturnInstruction(result, call->id()); | 12083 return ast_context()->ReturnInstruction(result, call->id()); |
| 12559 } | 12084 } |
| 12560 | 12085 |
| 12561 | 12086 |
| 12562 template <typename CollectionType> | 12087 template <typename CollectionType> |
| 12563 HValue* HOptimizedGraphBuilder::BuildAllocateOrderedHashTable() { | 12088 HValue* HOptimizedGraphBuilder::BuildAllocateOrderedHashTable() { |
| 12564 static const int kCapacity = CollectionType::kMinCapacity; | 12089 static const int kCapacity = CollectionType::kMinCapacity; |
| 12565 static const int kBucketCount = kCapacity / CollectionType::kLoadFactor; | 12090 static const int kBucketCount = kCapacity / CollectionType::kLoadFactor; |
| 12566 static const int kFixedArrayLength = CollectionType::kHashTableStartIndex + | 12091 static const int kFixedArrayLength = CollectionType::kHashTableStartIndex + |
| 12567 kBucketCount + | 12092 kBucketCount + |
| (...skipping 822 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 13390 if (ShouldProduceTraceOutput()) { | 12915 if (ShouldProduceTraceOutput()) { |
| 13391 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 12916 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 13392 } | 12917 } |
| 13393 | 12918 |
| 13394 #ifdef DEBUG | 12919 #ifdef DEBUG |
| 13395 graph_->Verify(false); // No full verify. | 12920 graph_->Verify(false); // No full verify. |
| 13396 #endif | 12921 #endif |
| 13397 } | 12922 } |
| 13398 | 12923 |
| 13399 } } // namespace v8::internal | 12924 } } // namespace v8::internal |
| OLD | NEW |