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