| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/code-stub-assembler.h" | 5 #include "src/code-stub-assembler.h" |
| 6 #include "src/code-factory.h" | 6 #include "src/code-factory.h" |
| 7 #include "src/frames-inl.h" | 7 #include "src/frames-inl.h" |
| 8 #include "src/frames.h" | 8 #include "src/frames.h" |
| 9 #include "src/ic/handler-configuration.h" | 9 #include "src/ic/handler-configuration.h" |
| 10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
| (...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 | 623 |
| 624 // Bitwise comparison succeeded, {lhs} and {rhs} considered equal. | 624 // Bitwise comparison succeeded, {lhs} and {rhs} considered equal. |
| 625 Goto(if_equal); | 625 Goto(if_equal); |
| 626 } | 626 } |
| 627 } | 627 } |
| 628 | 628 |
| 629 Bind(&if_mapnotsame); | 629 Bind(&if_mapnotsame); |
| 630 Goto(if_notequal); | 630 Goto(if_notequal); |
| 631 } | 631 } |
| 632 | 632 |
| 633 void CodeStubAssembler::BranchIfPrototypesHaveNoElements( | |
| 634 Node* receiver_map, Label* definitely_no_elements, | |
| 635 Label* possibly_elements) { | |
| 636 Variable var_map(this, MachineRepresentation::kTagged); | |
| 637 var_map.Bind(receiver_map); | |
| 638 Label loop_body(this, &var_map); | |
| 639 Node* empty_elements = LoadRoot(Heap::kEmptyFixedArrayRootIndex); | |
| 640 Goto(&loop_body); | |
| 641 | |
| 642 Bind(&loop_body); | |
| 643 { | |
| 644 Node* map = var_map.value(); | |
| 645 Node* prototype = LoadMapPrototype(map); | |
| 646 GotoIf(WordEqual(prototype, NullConstant()), definitely_no_elements); | |
| 647 Node* prototype_map = LoadMap(prototype); | |
| 648 // Pessimistically assume elements if a Proxy, Special API Object, | |
| 649 // or JSValue wrapper is found on the prototype chain. After this | |
| 650 // instance type check, it's not necessary to check for interceptors or | |
| 651 // access checks. | |
| 652 GotoIf(Int32LessThanOrEqual(LoadMapInstanceType(prototype_map), | |
| 653 Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)), | |
| 654 possibly_elements); | |
| 655 GotoIf(WordNotEqual(LoadElements(prototype), empty_elements), | |
| 656 possibly_elements); | |
| 657 var_map.Bind(prototype_map); | |
| 658 Goto(&loop_body); | |
| 659 } | |
| 660 } | |
| 661 | |
| 662 void CodeStubAssembler::BranchIfFastJSArray(Node* object, Node* context, | 633 void CodeStubAssembler::BranchIfFastJSArray(Node* object, Node* context, |
| 663 Label* if_true, Label* if_false) { | 634 Label* if_true, Label* if_false) { |
| 664 // Bailout if receiver is a Smi. | 635 Node* int32_zero = Int32Constant(0); |
| 636 Node* int32_one = Int32Constant(1); |
| 637 |
| 638 Node* empty_elements = LoadRoot(Heap::kEmptyFixedArrayRootIndex); |
| 639 |
| 640 Variable last_map(this, MachineRepresentation::kTagged); |
| 641 Label check_prototype(this); |
| 642 |
| 643 // Bailout if Smi |
| 665 GotoIf(WordIsSmi(object), if_false); | 644 GotoIf(WordIsSmi(object), if_false); |
| 666 | 645 |
| 667 Node* map = LoadMap(object); | 646 Node* map = LoadMap(object); |
| 647 last_map.Bind(map); |
| 668 | 648 |
| 669 // Bailout if instance type is not JS_ARRAY_TYPE. | 649 // Bailout if instance type is not JS_ARRAY_TYPE |
| 670 GotoIf(WordNotEqual(LoadMapInstanceType(map), Int32Constant(JS_ARRAY_TYPE)), | 650 GotoIf(WordNotEqual(LoadMapInstanceType(map), Int32Constant(JS_ARRAY_TYPE)), |
| 671 if_false); | 651 if_false); |
| 672 | 652 |
| 673 Node* bit_field2 = LoadMapBitField2(map); | 653 Node* bit_field2 = LoadMapBitField2(map); |
| 674 Node* elements_kind = BitFieldDecode<Map::ElementsKindBits>(bit_field2); | 654 Node* elements_kind = BitFieldDecode<Map::ElementsKindBits>(bit_field2); |
| 675 | 655 |
| 676 // Bailout if receiver has slow elements. | 656 // Bailout if slow receiver elements |
| 677 GotoIf( | 657 GotoIf( |
| 678 Int32GreaterThan(elements_kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)), | 658 Int32GreaterThan(elements_kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)), |
| 679 if_false); | 659 if_false); |
| 680 | 660 |
| 681 // Check prototype chain if receiver does not have packed elements. | |
| 682 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == (FAST_SMI_ELEMENTS | 1)); | 661 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == (FAST_SMI_ELEMENTS | 1)); |
| 683 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == (FAST_ELEMENTS | 1)); | 662 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == (FAST_ELEMENTS | 1)); |
| 684 STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == (FAST_DOUBLE_ELEMENTS | 1)); | 663 STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == (FAST_DOUBLE_ELEMENTS | 1)); |
| 685 Node* holey_elements = Word32And(elements_kind, Int32Constant(1)); | 664 |
| 686 GotoIf(Word32Equal(holey_elements, Int32Constant(0)), if_true); | 665 // Check prototype chain if receiver does not have packed elements |
| 687 BranchIfPrototypesHaveNoElements(map, if_true, if_false); | 666 Node* holey_elements = Word32And(elements_kind, int32_one); |
| 667 Branch(Word32Equal(holey_elements, int32_zero), if_true, &check_prototype); |
| 668 |
| 669 Bind(&check_prototype); |
| 670 { |
| 671 Label loop_body(this, &last_map); |
| 672 Goto(&loop_body); |
| 673 Bind(&loop_body); |
| 674 Node* current_map = last_map.value(); |
| 675 Node* proto = LoadObjectField(current_map, Map::kPrototypeOffset); |
| 676 |
| 677 // End loop |
| 678 GotoIf(WordEqual(proto, NullConstant()), if_true); |
| 679 |
| 680 // ASSERT: proto->IsHeapObject() |
| 681 Node* proto_map = LoadMap(proto); |
| 682 |
| 683 // Bailout if a Proxy, API Object, or JSValue wrapper found in prototype |
| 684 // Because of this bailout, it's not necessary to check for interceptors or |
| 685 // access checks on the prototype chain. |
| 686 GotoIf(Int32LessThanOrEqual(LoadMapInstanceType(proto_map), |
| 687 Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)), |
| 688 if_false); |
| 689 |
| 690 // Bailout if prototype contains non-empty elements |
| 691 GotoUnless(WordEqual(LoadElements(proto), empty_elements), if_false); |
| 692 |
| 693 last_map.Bind(proto_map); |
| 694 Goto(&loop_body); |
| 695 } |
| 688 } | 696 } |
| 689 | 697 |
| 690 Node* CodeStubAssembler::AllocateRawUnaligned(Node* size_in_bytes, | 698 Node* CodeStubAssembler::AllocateRawUnaligned(Node* size_in_bytes, |
| 691 AllocationFlags flags, | 699 AllocationFlags flags, |
| 692 Node* top_address, | 700 Node* top_address, |
| 693 Node* limit_address) { | 701 Node* limit_address) { |
| 694 Node* top = Load(MachineType::Pointer(), top_address); | 702 Node* top = Load(MachineType::Pointer(), top_address); |
| 695 Node* limit = Load(MachineType::Pointer(), limit_address); | 703 Node* limit = Load(MachineType::Pointer(), limit_address); |
| 696 | 704 |
| 697 // If there's not enough space, call the runtime. | 705 // If there's not enough space, call the runtime. |
| (...skipping 2776 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3474 Bind(&key_is_smi); | 3482 Bind(&key_is_smi); |
| 3475 { | 3483 { |
| 3476 var_intptr_key.Bind(SmiUntag(key)); | 3484 var_intptr_key.Bind(SmiUntag(key)); |
| 3477 Goto(&done); | 3485 Goto(&done); |
| 3478 } | 3486 } |
| 3479 | 3487 |
| 3480 Bind(&done); | 3488 Bind(&done); |
| 3481 return var_intptr_key.value(); | 3489 return var_intptr_key.value(); |
| 3482 } | 3490 } |
| 3483 | 3491 |
| 3484 void CodeStubAssembler::EmitFastElementsBoundsCheck(Node* object, | 3492 // |is_jsarray| should be non-zero for JSArrays. |
| 3485 Node* elements, | 3493 void CodeStubAssembler::EmitBoundsCheck(Node* object, Node* elements, |
| 3486 Node* intptr_key, | 3494 Node* intptr_key, Node* is_jsarray, |
| 3487 Node* is_jsarray_condition, | 3495 Label* miss) { |
| 3488 Label* miss) { | |
| 3489 Variable var_length(this, MachineRepresentation::kTagged); | 3496 Variable var_length(this, MachineRepresentation::kTagged); |
| 3490 Label if_array(this), length_loaded(this, &var_length); | 3497 Label if_array(this), length_loaded(this, &var_length); |
| 3491 GotoIf(is_jsarray_condition, &if_array); | 3498 GotoUnless(WordEqual(is_jsarray, IntPtrConstant(0)), &if_array); |
| 3492 { | 3499 { |
| 3493 var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements))); | 3500 var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements))); |
| 3494 Goto(&length_loaded); | 3501 Goto(&length_loaded); |
| 3495 } | 3502 } |
| 3496 Bind(&if_array); | 3503 Bind(&if_array); |
| 3497 { | 3504 { |
| 3498 var_length.Bind(SmiUntag(LoadObjectField(object, JSArray::kLengthOffset))); | 3505 var_length.Bind(SmiUntag(LoadObjectField(object, JSArray::kLengthOffset))); |
| 3499 Goto(&length_loaded); | 3506 Goto(&length_loaded); |
| 3500 } | 3507 } |
| 3501 Bind(&length_loaded); | 3508 Bind(&length_loaded); |
| 3502 GotoUnless(UintPtrLessThan(intptr_key, var_length.value()), miss); | 3509 GotoUnless(UintPtrLessThan(intptr_key, var_length.value()), miss); |
| 3503 } | 3510 } |
| 3504 | 3511 |
| 3505 // |key| should be untagged (int32). | 3512 // |key| should be untagged (int32). |
| 3506 void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements, | 3513 void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements, |
| 3507 Node* elements_kind, Node* key, | 3514 Node* elements_kind, Node* key, |
| 3508 Node* is_jsarray_condition, | |
| 3509 Label* if_hole, Label* rebox_double, | 3515 Label* if_hole, Label* rebox_double, |
| 3510 Variable* var_double_value, | 3516 Variable* var_double_value, |
| 3511 Label* unimplemented_elements_kind, | 3517 Label* miss) { |
| 3512 Label* out_of_bounds, Label* miss) { | |
| 3513 Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this), | 3518 Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this), |
| 3514 if_fast_double(this), if_fast_holey_double(this), if_nonfast(this), | 3519 if_fast_double(this), if_fast_holey_double(this), |
| 3515 if_dictionary(this), unreachable(this); | 3520 unimplemented_elements_kind(this); |
| 3521 STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); |
| 3516 GotoIf( | 3522 GotoIf( |
| 3517 IntPtrGreaterThan(elements_kind, IntPtrConstant(LAST_FAST_ELEMENTS_KIND)), | 3523 IntPtrGreaterThanOrEqual( |
| 3518 &if_nonfast); | 3524 elements_kind, IntPtrConstant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)), |
| 3525 &if_typed_array); |
| 3519 | 3526 |
| 3520 EmitFastElementsBoundsCheck(object, elements, key, is_jsarray_condition, | |
| 3521 out_of_bounds); | |
| 3522 int32_t kinds[] = {// Handled by if_fast_packed. | 3527 int32_t kinds[] = {// Handled by if_fast_packed. |
| 3523 FAST_SMI_ELEMENTS, FAST_ELEMENTS, | 3528 FAST_SMI_ELEMENTS, FAST_ELEMENTS, |
| 3524 // Handled by if_fast_holey. | 3529 // Handled by if_fast_holey. |
| 3525 FAST_HOLEY_SMI_ELEMENTS, FAST_HOLEY_ELEMENTS, | 3530 FAST_HOLEY_SMI_ELEMENTS, FAST_HOLEY_ELEMENTS, |
| 3526 // Handled by if_fast_double. | 3531 // Handled by if_fast_double. |
| 3527 FAST_DOUBLE_ELEMENTS, | 3532 FAST_DOUBLE_ELEMENTS, |
| 3528 // Handled by if_fast_holey_double. | 3533 // Handled by if_fast_holey_double. |
| 3529 FAST_HOLEY_DOUBLE_ELEMENTS}; | 3534 FAST_HOLEY_DOUBLE_ELEMENTS}; |
| 3530 Label* labels[] = {// FAST_{SMI,}_ELEMENTS | 3535 Label* labels[] = {// FAST_{SMI,}_ELEMENTS |
| 3531 &if_fast_packed, &if_fast_packed, | 3536 &if_fast_packed, &if_fast_packed, |
| 3532 // FAST_HOLEY_{SMI,}_ELEMENTS | 3537 // FAST_HOLEY_{SMI,}_ELEMENTS |
| 3533 &if_fast_holey, &if_fast_holey, | 3538 &if_fast_holey, &if_fast_holey, |
| 3534 // FAST_DOUBLE_ELEMENTS | 3539 // FAST_DOUBLE_ELEMENTS |
| 3535 &if_fast_double, | 3540 &if_fast_double, |
| 3536 // FAST_HOLEY_DOUBLE_ELEMENTS | 3541 // FAST_HOLEY_DOUBLE_ELEMENTS |
| 3537 &if_fast_holey_double}; | 3542 &if_fast_holey_double}; |
| 3538 Switch(elements_kind, unimplemented_elements_kind, kinds, labels, | 3543 Switch(elements_kind, &unimplemented_elements_kind, kinds, labels, |
| 3539 arraysize(kinds)); | 3544 arraysize(kinds)); |
| 3545 Bind(&unimplemented_elements_kind); |
| 3546 { |
| 3547 // Crash if we get here. |
| 3548 DebugBreak(); |
| 3549 Goto(miss); |
| 3550 } |
| 3540 | 3551 |
| 3541 Bind(&if_fast_packed); | 3552 Bind(&if_fast_packed); |
| 3542 { | 3553 { |
| 3543 Comment("fast packed elements"); | 3554 Comment("fast packed elements"); |
| 3544 // TODO(jkummerow): The Load*Element helpers add movsxlq instructions | 3555 // TODO(jkummerow): The Load*Element helpers add movsxlq instructions |
| 3545 // on x64 which we don't need here, because |key| is an IntPtr already. | 3556 // on x64 which we don't need here, because |key| is an IntPtr already. |
| 3546 // Do something about that. | 3557 // Do something about that. |
| 3547 Return(LoadFixedArrayElement(elements, key)); | 3558 Return(LoadFixedArrayElement(elements, key)); |
| 3548 } | 3559 } |
| 3549 | 3560 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 3575 Node* element_upper = LoadFixedDoubleArrayElement( | 3586 Node* element_upper = LoadFixedDoubleArrayElement( |
| 3576 elements, key, MachineType::Uint32(), kIeeeDoubleExponentWordOffset); | 3587 elements, key, MachineType::Uint32(), kIeeeDoubleExponentWordOffset); |
| 3577 GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)), | 3588 GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)), |
| 3578 if_hole); | 3589 if_hole); |
| 3579 } | 3590 } |
| 3580 var_double_value->Bind( | 3591 var_double_value->Bind( |
| 3581 LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); | 3592 LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); |
| 3582 Goto(rebox_double); | 3593 Goto(rebox_double); |
| 3583 } | 3594 } |
| 3584 | 3595 |
| 3585 Bind(&if_nonfast); | |
| 3586 { | |
| 3587 STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); | |
| 3588 GotoIf(IntPtrGreaterThanOrEqual( | |
| 3589 elements_kind, | |
| 3590 IntPtrConstant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)), | |
| 3591 &if_typed_array); | |
| 3592 GotoIf(IntPtrEqual(elements_kind, IntPtrConstant(DICTIONARY_ELEMENTS)), | |
| 3593 &if_dictionary); | |
| 3594 Goto(unimplemented_elements_kind); | |
| 3595 } | |
| 3596 | |
| 3597 Bind(&if_dictionary); | |
| 3598 { | |
| 3599 Comment("dictionary elements"); | |
| 3600 Variable var_entry(this, MachineRepresentation::kWord32); | |
| 3601 Label if_found(this); | |
| 3602 NumberDictionaryLookup<SeededNumberDictionary>(elements, key, &if_found, | |
| 3603 &var_entry, if_hole); | |
| 3604 Bind(&if_found); | |
| 3605 // Check that the value is a data property. | |
| 3606 Node* details_index = EntryToIndex<SeededNumberDictionary>( | |
| 3607 var_entry.value(), SeededNumberDictionary::kEntryDetailsIndex); | |
| 3608 Node* details = SmiToWord32(LoadFixedArrayElement(elements, details_index)); | |
| 3609 Node* kind = BitFieldDecode<PropertyDetails::KindField>(details); | |
| 3610 // TODO(jkummerow): Support accessors without missing? | |
| 3611 GotoUnless(Word32Equal(kind, Int32Constant(kData)), miss); | |
| 3612 // Finally, load the value. | |
| 3613 Node* value_index = EntryToIndex<SeededNumberDictionary>( | |
| 3614 var_entry.value(), SeededNumberDictionary::kEntryValueIndex); | |
| 3615 Return(LoadFixedArrayElement(elements, value_index)); | |
| 3616 } | |
| 3617 | |
| 3618 Bind(&if_typed_array); | 3596 Bind(&if_typed_array); |
| 3619 { | 3597 { |
| 3620 Comment("typed elements"); | 3598 Comment("typed elements"); |
| 3621 // Check if buffer has been neutered. | 3599 // Check if buffer has been neutered. |
| 3622 Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset); | 3600 Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset); |
| 3623 Node* bitfield = LoadObjectField(buffer, JSArrayBuffer::kBitFieldOffset, | 3601 Node* bitfield = LoadObjectField(buffer, JSArrayBuffer::kBitFieldOffset, |
| 3624 MachineType::Uint32()); | 3602 MachineType::Uint32()); |
| 3625 Node* neutered_bit = | 3603 Node* neutered_bit = |
| 3626 Word32And(bitfield, Int32Constant(JSArrayBuffer::WasNeutered::kMask)); | 3604 Word32And(bitfield, Int32Constant(JSArrayBuffer::WasNeutered::kMask)); |
| 3627 GotoUnless(Word32Equal(neutered_bit, Int32Constant(0)), miss); | 3605 GotoUnless(Word32Equal(neutered_bit, Int32Constant(0)), miss); |
| 3628 | |
| 3629 // Bounds check. | |
| 3630 Node* length = | |
| 3631 SmiUntag(LoadObjectField(object, JSTypedArray::kLengthOffset)); | |
| 3632 GotoUnless(UintPtrLessThan(key, length), out_of_bounds); | |
| 3633 | |
| 3634 // Backing store = external_pointer + base_pointer. | 3606 // Backing store = external_pointer + base_pointer. |
| 3635 Node* external_pointer = | 3607 Node* external_pointer = |
| 3636 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, | 3608 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, |
| 3637 MachineType::Pointer()); | 3609 MachineType::Pointer()); |
| 3638 Node* base_pointer = | 3610 Node* base_pointer = |
| 3639 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); | 3611 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); |
| 3640 Node* backing_store = IntPtrAdd(external_pointer, base_pointer); | 3612 Node* backing_store = IntPtrAdd(external_pointer, base_pointer); |
| 3641 | 3613 |
| 3642 Label uint8_elements(this), int8_elements(this), uint16_elements(this), | 3614 Label uint8_elements(this), int8_elements(this), uint16_elements(this), |
| 3643 int16_elements(this), uint32_elements(this), int32_elements(this), | 3615 int16_elements(this), uint32_elements(this), int32_elements(this), |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3732 WordAnd(handler_word, IntPtrConstant(LoadHandlerTypeBit::kMask)); | 3704 WordAnd(handler_word, IntPtrConstant(LoadHandlerTypeBit::kMask)); |
| 3733 GotoUnless( | 3705 GotoUnless( |
| 3734 WordEqual(handler_type, IntPtrConstant(kLoadICHandlerForElements)), | 3706 WordEqual(handler_type, IntPtrConstant(kLoadICHandlerForElements)), |
| 3735 &property); | 3707 &property); |
| 3736 | 3708 |
| 3737 Comment("element_load"); | 3709 Comment("element_load"); |
| 3738 Node* key = TryToIntptr(p->name, miss); | 3710 Node* key = TryToIntptr(p->name, miss); |
| 3739 Node* elements = LoadElements(p->receiver); | 3711 Node* elements = LoadElements(p->receiver); |
| 3740 Node* is_jsarray = | 3712 Node* is_jsarray = |
| 3741 WordAnd(handler_word, IntPtrConstant(KeyedLoadIsJsArray::kMask)); | 3713 WordAnd(handler_word, IntPtrConstant(KeyedLoadIsJsArray::kMask)); |
| 3742 Node* is_jsarray_condition = WordNotEqual(is_jsarray, IntPtrConstant(0)); | 3714 EmitBoundsCheck(p->receiver, elements, key, is_jsarray, miss); |
| 3715 Label if_hole(this); |
| 3716 |
| 3743 Node* elements_kind = BitFieldDecode<KeyedLoadElementsKind>(handler_word); | 3717 Node* elements_kind = BitFieldDecode<KeyedLoadElementsKind>(handler_word); |
| 3744 Label if_hole(this), unimplemented_elements_kind(this); | |
| 3745 Label* out_of_bounds = miss; | |
| 3746 EmitElementLoad(p->receiver, elements, elements_kind, key, | |
| 3747 is_jsarray_condition, &if_hole, &rebox_double, | |
| 3748 &var_double_value, &unimplemented_elements_kind, | |
| 3749 out_of_bounds, miss); | |
| 3750 | 3718 |
| 3751 Bind(&unimplemented_elements_kind); | 3719 EmitElementLoad(p->receiver, elements, elements_kind, key, &if_hole, |
| 3752 { | 3720 &rebox_double, &var_double_value, miss); |
| 3753 // Smi handlers should only be installed for supported elements kinds. | |
| 3754 // Crash if we get here. | |
| 3755 DebugBreak(); | |
| 3756 Goto(miss); | |
| 3757 } | |
| 3758 | 3721 |
| 3759 Bind(&if_hole); | 3722 Bind(&if_hole); |
| 3760 { | 3723 { |
| 3761 Comment("convert hole"); | 3724 Comment("convert hole"); |
| 3762 Node* convert_hole = | 3725 Node* convert_hole = |
| 3763 WordAnd(handler_word, IntPtrConstant(KeyedLoadConvertHole::kMask)); | 3726 WordAnd(handler_word, IntPtrConstant(KeyedLoadConvertHole::kMask)); |
| 3764 GotoIf(WordEqual(convert_hole, IntPtrConstant(0)), miss); | 3727 GotoIf(WordEqual(convert_hole, IntPtrConstant(0)), miss); |
| 3765 Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex); | 3728 Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex); |
| 3766 DCHECK(isolate()->heap()->array_protector()->IsPropertyCell()); | 3729 DCHECK(isolate()->heap()->array_protector()->IsPropertyCell()); |
| 3767 GotoUnless( | 3730 GotoUnless( |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3926 &miss, 1); | 3889 &miss, 1); |
| 3927 } | 3890 } |
| 3928 Bind(&miss); | 3891 Bind(&miss); |
| 3929 { | 3892 { |
| 3930 Comment("KeyedLoadIC_miss"); | 3893 Comment("KeyedLoadIC_miss"); |
| 3931 TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver, | 3894 TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver, |
| 3932 p->name, p->slot, p->vector); | 3895 p->name, p->slot, p->vector); |
| 3933 } | 3896 } |
| 3934 } | 3897 } |
| 3935 | 3898 |
| 3936 void CodeStubAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { | |
| 3937 Variable var_index(this, MachineType::PointerRepresentation()); | |
| 3938 Label if_index(this), if_key_is_not_number(this), if_index_name(this), | |
| 3939 if_unique_name(this), if_element_hole(this), if_oob(this), slow(this), | |
| 3940 stub_cache_miss(this), if_property_dictionary(this); | |
| 3941 | |
| 3942 Node* receiver = p->receiver; | |
| 3943 GotoIf(WordIsSmi(receiver), &slow); | |
| 3944 Node* receiver_map = LoadMap(receiver); | |
| 3945 Node* instance_type = LoadMapInstanceType(receiver_map); | |
| 3946 // Receivers requiring non-standard element accesses (interceptors, access | |
| 3947 // checks, strings and string wrappers, proxies) are handled in the runtime. | |
| 3948 GotoIf(Int32LessThanOrEqual(instance_type, | |
| 3949 Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)), | |
| 3950 &slow); | |
| 3951 | |
| 3952 // Check what kind of key we have. | |
| 3953 Node* key = p->name; | |
| 3954 var_index.Bind(TryToIntptr(key, &if_key_is_not_number)); | |
| 3955 Goto(&if_index); | |
| 3956 | |
| 3957 Node* hash = nullptr; | |
| 3958 // TODO(jkummerow): Unify this with CodeStubAssembler::TryToName(). | |
| 3959 Bind(&if_key_is_not_number); | |
| 3960 { | |
| 3961 Node* key_map = LoadMap(key); | |
| 3962 Node* key_instance_type = LoadMapInstanceType(key_map); | |
| 3963 // Jump to the runtime if key is neither String nor Symbol. | |
| 3964 GotoIf(Int32GreaterThan(key_instance_type, | |
| 3965 Int32Constant(LAST_UNIQUE_NAME_TYPE)), | |
| 3966 &slow); | |
| 3967 // Symbols are always unique names. | |
| 3968 GotoIf(Word32Equal(key_instance_type, Int32Constant(LAST_UNIQUE_NAME_TYPE)), | |
| 3969 &if_unique_name); | |
| 3970 // |key| is a String. Check if it has a cached array index. | |
| 3971 hash = LoadNameHashField(key); | |
| 3972 Node* contains_index = | |
| 3973 Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); | |
| 3974 GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_index_name); | |
| 3975 // Otherwise, jump to the runtime if the string is not internalized. | |
| 3976 STATIC_ASSERT(kNotInternalizedTag != 0); | |
| 3977 Node* not_internalized = | |
| 3978 Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask)); | |
| 3979 GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), &slow); | |
| 3980 Goto(&if_unique_name); | |
| 3981 } | |
| 3982 | |
| 3983 Bind(&if_index_name); | |
| 3984 { | |
| 3985 Comment("string key with cached array index"); | |
| 3986 var_index.Bind(BitFieldDecode<String::ArrayIndexValueBits>(hash)); | |
| 3987 Goto(&if_index); | |
| 3988 } | |
| 3989 | |
| 3990 Bind(&if_index); | |
| 3991 { | |
| 3992 Comment("integer index"); | |
| 3993 Node* index = var_index.value(); | |
| 3994 Node* elements = LoadElements(receiver); | |
| 3995 Node* bitfield2 = LoadMapBitField2(receiver_map); | |
| 3996 Node* elements_kind = BitFieldDecode<Map::ElementsKindBits>(bitfield2); | |
| 3997 Node* is_jsarray_condition = | |
| 3998 Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)); | |
| 3999 Variable var_double_value(this, MachineRepresentation::kFloat64); | |
| 4000 Label rebox_double(this, &var_double_value); | |
| 4001 | |
| 4002 // Unimplemented elements kinds fall back to a runtime call. | |
| 4003 Label* unimplemented_elements_kind = &slow; | |
| 4004 IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1); | |
| 4005 EmitElementLoad(receiver, elements, elements_kind, index, | |
| 4006 is_jsarray_condition, &if_element_hole, &rebox_double, | |
| 4007 &var_double_value, unimplemented_elements_kind, &if_oob, | |
| 4008 &slow); | |
| 4009 | |
| 4010 Bind(&rebox_double); | |
| 4011 Return(AllocateHeapNumberWithValue(var_double_value.value())); | |
| 4012 } | |
| 4013 | |
| 4014 Bind(&if_oob); | |
| 4015 { | |
| 4016 Comment("out of bounds"); | |
| 4017 Node* index = var_index.value(); | |
| 4018 // Negative keys can't take the fast OOB path. | |
| 4019 GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), &slow); | |
| 4020 // Positive OOB indices are effectively the same as hole loads. | |
| 4021 Goto(&if_element_hole); | |
| 4022 } | |
| 4023 | |
| 4024 Bind(&if_element_hole); | |
| 4025 { | |
| 4026 Comment("found the hole"); | |
| 4027 Label return_undefined(this); | |
| 4028 BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, &slow); | |
| 4029 | |
| 4030 Bind(&return_undefined); | |
| 4031 Return(UndefinedConstant()); | |
| 4032 } | |
| 4033 | |
| 4034 Node* properties = nullptr; | |
| 4035 Bind(&if_unique_name); | |
| 4036 { | |
| 4037 Comment("key is unique name"); | |
| 4038 // Check if the receiver has fast or slow properties. | |
| 4039 properties = LoadProperties(receiver); | |
| 4040 Node* properties_map = LoadMap(properties); | |
| 4041 GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), | |
| 4042 &if_property_dictionary); | |
| 4043 | |
| 4044 Comment("stub cache probe for fast property load"); | |
| 4045 Variable var_handler(this, MachineRepresentation::kTagged); | |
| 4046 Label found_handler(this, &var_handler), stub_cache_miss(this); | |
| 4047 TryProbeStubCache(isolate()->load_stub_cache(), receiver, key, | |
| 4048 &found_handler, &var_handler, &stub_cache_miss); | |
| 4049 Bind(&found_handler); | |
| 4050 { HandleLoadICHandlerCase(p, var_handler.value(), &slow); } | |
| 4051 | |
| 4052 Bind(&stub_cache_miss); | |
| 4053 { | |
| 4054 Comment("KeyedLoadGeneric_miss"); | |
| 4055 TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver, | |
| 4056 p->name, p->slot, p->vector); | |
| 4057 } | |
| 4058 } | |
| 4059 | |
| 4060 Bind(&if_property_dictionary); | |
| 4061 { | |
| 4062 Comment("dictionary property load"); | |
| 4063 // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out | |
| 4064 // seeing global objects here (which would need special handling). | |
| 4065 | |
| 4066 Variable var_name_index(this, MachineRepresentation::kWord32); | |
| 4067 Label dictionary_found(this, &var_name_index); | |
| 4068 NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found, | |
| 4069 &var_name_index, &slow); | |
| 4070 Bind(&dictionary_found); | |
| 4071 { | |
| 4072 Variable var_details(this, MachineRepresentation::kWord32); | |
| 4073 Variable var_value(this, MachineRepresentation::kTagged); | |
| 4074 LoadPropertyFromNameDictionary(properties, var_name_index.value(), | |
| 4075 &var_details, &var_value); | |
| 4076 Node* kind = | |
| 4077 BitFieldDecode<PropertyDetails::KindField>(var_details.value()); | |
| 4078 // TODO(jkummerow): Support accessors without missing? | |
| 4079 GotoUnless(Word32Equal(kind, Int32Constant(kData)), &slow); | |
| 4080 IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), | |
| 4081 1); | |
| 4082 Return(var_value.value()); | |
| 4083 } | |
| 4084 } | |
| 4085 | |
| 4086 Bind(&slow); | |
| 4087 { | |
| 4088 Comment("KeyedLoadGeneric_slow"); | |
| 4089 IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1); | |
| 4090 // TODO(jkummerow): Should we use the GetProperty TF stub instead? | |
| 4091 TailCallRuntime(Runtime::kKeyedGetProperty, p->context, p->receiver, | |
| 4092 p->name); | |
| 4093 } | |
| 4094 } | |
| 4095 | |
| 4096 void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) { | 3899 void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) { |
| 4097 Label try_handler(this), miss(this); | 3900 Label try_handler(this), miss(this); |
| 4098 Node* weak_cell = | 3901 Node* weak_cell = |
| 4099 LoadFixedArrayElement(p->vector, p->slot, 0, SMI_PARAMETERS); | 3902 LoadFixedArrayElement(p->vector, p->slot, 0, SMI_PARAMETERS); |
| 4100 AssertInstanceType(weak_cell, WEAK_CELL_TYPE); | 3903 AssertInstanceType(weak_cell, WEAK_CELL_TYPE); |
| 4101 | 3904 |
| 4102 // Load value or try handler case if the {weak_cell} is cleared. | 3905 // Load value or try handler case if the {weak_cell} is cleared. |
| 4103 Node* property_cell = LoadWeakCellValue(weak_cell, &try_handler); | 3906 Node* property_cell = LoadWeakCellValue(weak_cell, &try_handler); |
| 4104 AssertInstanceType(property_cell, PROPERTY_CELL_TYPE); | 3907 AssertInstanceType(property_cell, PROPERTY_CELL_TYPE); |
| 4105 | 3908 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4211 Heap::kTheHoleValueRootIndex); | 4014 Heap::kTheHoleValueRootIndex); |
| 4212 | 4015 |
| 4213 // Store the WeakCell in the feedback vector. | 4016 // Store the WeakCell in the feedback vector. |
| 4214 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, | 4017 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, |
| 4215 CodeStubAssembler::SMI_PARAMETERS); | 4018 CodeStubAssembler::SMI_PARAMETERS); |
| 4216 return cell; | 4019 return cell; |
| 4217 } | 4020 } |
| 4218 | 4021 |
| 4219 } // namespace internal | 4022 } // namespace internal |
| 4220 } // namespace v8 | 4023 } // namespace v8 |
| OLD | NEW |