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

Side by Side Diff: src/builtins/builtins-collections-gen.cc

Issue 2958063002: Fast path for Map.prototype.(Get|Has) with Smi key. (Closed)
Patch Set: Tweaks Created 3 years, 5 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 the V8 project authors. All rights reserved. 1 // Copyright 2017 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/builtins/builtins-constructor-gen.h" 5 #include "src/builtins/builtins-constructor-gen.h"
6 #include "src/builtins/builtins-iterator-gen.h" 6 #include "src/builtins/builtins-iterator-gen.h"
7 #include "src/builtins/builtins-utils-gen.h" 7 #include "src/builtins/builtins-utils-gen.h"
8 #include "src/code-stub-assembler.h" 8 #include "src/code-stub-assembler.h"
9 #include "src/objects/hash-table.h" 9 #include "src/objects/hash-table.h"
10 10
(...skipping 10 matching lines...) Expand all
21 protected: 21 protected:
22 Node* AllocateJSMap(Node* js_map_function); 22 Node* AllocateJSMap(Node* js_map_function);
23 23
24 template <typename CollectionType> 24 template <typename CollectionType>
25 Node* AllocateOrderedHashTable(); 25 Node* AllocateOrderedHashTable();
26 Node* AllocateJSCollection(Node* js_map_function); 26 Node* AllocateJSCollection(Node* js_map_function);
27 27
28 Node* CallGetRaw(Node* const table, Node* const key); 28 Node* CallGetRaw(Node* const table, Node* const key);
29 template <typename CollectionType, int entrysize> 29 template <typename CollectionType, int entrysize>
30 Node* CallHasRaw(Node* const table, Node* const key); 30 Node* CallHasRaw(Node* const table, Node* const key);
31
32 // Tries to find OrderedHashMap entry for given Smi key, jumps
33 // to {entry_found} if the key is found, or to {not_found} if the
34 // key was not found. Returns the node with the entry index (relative to
35 // OrderedHashMap::kHashTableStartIndex). The node can only be used in the
36 // {entry_found} branch.
37 Node* FindOrderedHashMapEntryForSmiKey(Node* table, Node* key_tagged,
38 Label* entry_found, Label* not_found);
31 }; 39 };
32 40
33 template <typename CollectionType> 41 template <typename CollectionType>
34 Node* CollectionsBuiltinsAssembler::AllocateOrderedHashTable() { 42 Node* CollectionsBuiltinsAssembler::AllocateOrderedHashTable() {
35 static const int kCapacity = CollectionType::kMinCapacity; 43 static const int kCapacity = CollectionType::kMinCapacity;
36 static const int kBucketCount = kCapacity / CollectionType::kLoadFactor; 44 static const int kBucketCount = kCapacity / CollectionType::kLoadFactor;
37 static const int kDataTableLength = kCapacity * CollectionType::kEntrySize; 45 static const int kDataTableLength = kCapacity * CollectionType::kEntrySize;
38 static const int kFixedArrayLength = 46 static const int kFixedArrayLength =
39 CollectionType::kHashTableStartIndex + kBucketCount + kDataTableLength; 47 CollectionType::kHashTableStartIndex + kBucketCount + kDataTableLength;
40 static const int kDataTableStartIndex = 48 static const int kDataTableStartIndex =
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 MachineType type_tagged = MachineType::AnyTagged(); 373 MachineType type_tagged = MachineType::AnyTagged();
366 374
367 Node* const result = 375 Node* const result =
368 CallCFunction3(type_uint8, type_ptr, type_tagged, type_tagged, 376 CallCFunction3(type_uint8, type_ptr, type_tagged, type_tagged,
369 function_addr, isolate_ptr, table, key); 377 function_addr, isolate_ptr, table, key);
370 378
371 return SelectBooleanConstant( 379 return SelectBooleanConstant(
372 Word32NotEqual(Word32And(result, Int32Constant(0xFF)), Int32Constant(0))); 380 Word32NotEqual(Word32And(result, Int32Constant(0xFF)), Int32Constant(0)));
373 } 381 }
374 382
383 Node* CollectionsBuiltinsAssembler::FindOrderedHashMapEntryForSmiKey(
384 Node* table, Node* key_tagged, Label* entry_found, Label* not_found) {
385 // Compute the hash.
386 Node* const key = SmiUntag(key_tagged);
387 Node* const hash =
388 ChangeInt32ToIntPtr(ComputeIntegerHash(key, Int32Constant(0)));
Camillo Bruni 2017/06/28 11:31:16 uh, I think we should add a cctest to ensure the C
389
390 // Get the index of the bucket.
391 Node* const number_of_buckets = SmiUntag(
392 LoadFixedArrayElement(table, OrderedHashMap::kNumberOfBucketsIndex));
393 Node* const bucket =
394 WordAnd(hash, IntPtrSub(number_of_buckets, IntPtrConstant(1)));
395 Node* const first_entry = SmiUntag(LoadFixedArrayElement(
396 table, bucket, OrderedHashMap::kHashTableStartIndex * kPointerSize));
397
398 Node* entry_start_position;
399 // Walk the bucket chain.
400 {
401 VARIABLE(var_entry, MachineType::PointerRepresentation(), first_entry);
402 Label loop(this, &var_entry), continue_next_entry(this);
403 Goto(&loop);
404 BIND(&loop);
405
406 // If the entry index is the not-found sentinel, we are done.
407 GotoIf(
408 WordEqual(var_entry.value(), IntPtrConstant(OrderedHashMap::kNotFound)),
409 not_found);
410
411 // Make sure the entry index is within range.
412 CSA_ASSERT(
413 this,
414 UintPtrLessThan(
415 var_entry.value(),
416 SmiUntag(SmiAdd(
417 LoadFixedArrayElement(table,
418 OrderedHashMap::kNumberOfElementsIndex),
419 LoadFixedArrayElement(
420 table, OrderedHashMap::kNumberOfDeletedElementsIndex)))));
421
422 // Compute the index of the entry relative to kHashTableStartIndex.
423 entry_start_position =
424 IntPtrAdd(IntPtrMul(var_entry.value(),
425 IntPtrConstant(OrderedHashMap::kEntrySize)),
426 number_of_buckets);
427
428 // Load the key from the entry.
429 Node* const candidate_key = LoadFixedArrayElement(
430 table, entry_start_position,
431 OrderedHashMap::kHashTableStartIndex * kPointerSize);
432
433 // If the key is the same, we are done.
434 GotoIf(WordEqual(candidate_key, key_tagged), entry_found);
435
436 // If the candidate key is smi, then it must be different (because
437 // we already checked for equality above).
438 GotoIf(TaggedIsSmi(candidate_key), &continue_next_entry);
439
440 // If the candidate key is not smi, we still have to check if it is a heap
441 // number with the same value.
442 GotoIfNot(IsHeapNumber(candidate_key), &continue_next_entry);
443
444 Node* const candidate_key_number = LoadHeapNumberValue(candidate_key);
445 Node* const key_number = SmiToFloat64(key_tagged);
446
447 GotoIf(Float64Equal(candidate_key_number, key_number), entry_found);
448
449 Goto(&continue_next_entry);
450
451 BIND(&continue_next_entry);
452 // Load the index of the next entry in the bucket chain.
453 var_entry.Bind(SmiUntag(LoadFixedArrayElement(
454 table, entry_start_position,
455 (OrderedHashMap::kHashTableStartIndex + OrderedHashMap::kChainOffset) *
456 kPointerSize)));
457
458 Goto(&loop);
459 }
460 return entry_start_position;
461 }
462
375 TF_BUILTIN(MapGet, CollectionsBuiltinsAssembler) { 463 TF_BUILTIN(MapGet, CollectionsBuiltinsAssembler) {
376 Node* const receiver = Parameter(Descriptor::kReceiver); 464 Node* const receiver = Parameter(Descriptor::kReceiver);
377 Node* const key = Parameter(Descriptor::kKey); 465 Node* const key_tagged = Parameter(Descriptor::kKey);
378 Node* const context = Parameter(Descriptor::kContext); 466 Node* const context = Parameter(Descriptor::kContext);
379 467
380 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, "Map.prototype.get"); 468 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, "Map.prototype.get");
381 469
382 Node* const table = LoadObjectField(receiver, JSMap::kTableOffset); 470 Node* const table = LoadObjectField(receiver, JSMap::kTableOffset);
383 Return(CallGetRaw(table, key)); 471
472 Label if_key_smi(this);
473 GotoIf(TaggedIsSmi(key_tagged), &if_key_smi);
474
475 Return(CallGetRaw(table, key_tagged));
476
477 BIND(&if_key_smi);
478 Label entry_found(this), not_found(this);
479 Node* entry_start_position = FindOrderedHashMapEntryForSmiKey(
480 table, key_tagged, &entry_found, &not_found);
481
482 BIND(&entry_found);
483 Return(LoadFixedArrayElement(
484 table, entry_start_position,
485 (OrderedHashMap::kHashTableStartIndex + OrderedHashMap::kValueOffset) *
486 kPointerSize));
487
488 BIND(&not_found);
489 Return(UndefinedConstant());
384 } 490 }
385 491
386 TF_BUILTIN(MapHas, CollectionsBuiltinsAssembler) { 492 TF_BUILTIN(MapHas, CollectionsBuiltinsAssembler) {
387 Node* const receiver = Parameter(Descriptor::kReceiver); 493 Node* const receiver = Parameter(Descriptor::kReceiver);
388 Node* const key = Parameter(Descriptor::kKey); 494 Node* const key_tagged = Parameter(Descriptor::kKey);
389 Node* const context = Parameter(Descriptor::kContext); 495 Node* const context = Parameter(Descriptor::kContext);
390 496
391 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, "Map.prototype.has"); 497 ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, "Map.prototype.has");
392 498
393 Node* const table = LoadObjectField(receiver, JSMap::kTableOffset); 499 Node* const table = LoadObjectField(receiver, JSMap::kTableOffset);
394 Return(CallHasRaw<OrderedHashMap, 2>(table, key)); 500
501 Label if_key_smi(this);
502 GotoIf(TaggedIsSmi(key_tagged), &if_key_smi);
503
504 Return(CallHasRaw<OrderedHashMap, 2>(table, key_tagged));
505
506 BIND(&if_key_smi);
507 Label entry_found(this), not_found(this);
508 FindOrderedHashMapEntryForSmiKey(table, key_tagged, &entry_found, &not_found);
509
510 BIND(&entry_found);
511 Return(TrueConstant());
512
513 BIND(&not_found);
514 Return(FalseConstant());
395 } 515 }
Camillo Bruni 2017/06/28 11:31:16 Now that we have the Smi fast-path there is no way
396 516
397 TF_BUILTIN(SetHas, CollectionsBuiltinsAssembler) { 517 TF_BUILTIN(SetHas, CollectionsBuiltinsAssembler) {
398 Node* const receiver = Parameter(Descriptor::kReceiver); 518 Node* const receiver = Parameter(Descriptor::kReceiver);
399 Node* const key = Parameter(Descriptor::kKey); 519 Node* const key = Parameter(Descriptor::kKey);
400 Node* const context = Parameter(Descriptor::kContext); 520 Node* const context = Parameter(Descriptor::kContext);
401 521
402 ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE, "Set.prototype.has"); 522 ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE, "Set.prototype.has");
403 523
404 Node* const table = LoadObjectField(receiver, JSMap::kTableOffset); 524 Node* const table = LoadObjectField(receiver, JSMap::kTableOffset);
405 Return(CallHasRaw<OrderedHashSet, 1>(table, key)); 525 Return(CallHasRaw<OrderedHashSet, 1>(table, key));
406 } 526 }
407 527
408 } // namespace internal 528 } // namespace internal
409 } // namespace v8 529 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698