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 |