Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/hydrogen.cc

Issue 947683002: Reimplement Maps and Sets in JS (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Disable one more test Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698