Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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, ¬_found); | |
| 481 | |
| 482 BIND(&entry_found); | |
| 483 Return(LoadFixedArrayElement( | |
| 484 table, entry_start_position, | |
| 485 (OrderedHashMap::kHashTableStartIndex + OrderedHashMap::kValueOffset) * | |
| 486 kPointerSize)); | |
| 487 | |
| 488 BIND(¬_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, ¬_found); | |
| 509 | |
| 510 BIND(&entry_found); | |
| 511 Return(TrueConstant()); | |
| 512 | |
| 513 BIND(¬_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 |
| OLD | NEW |