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/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
10 | 11 |
11 namespace v8 { | 12 namespace v8 { |
12 namespace internal { | 13 namespace internal { |
13 | 14 |
14 using compiler::Node; | 15 using compiler::Node; |
15 | 16 |
16 CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone, | 17 CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone, |
17 const CallInterfaceDescriptor& descriptor, | 18 const CallInterfaceDescriptor& descriptor, |
18 Code::Flags flags, const char* name, | 19 Code::Flags flags, const char* name, |
(...skipping 3402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3421 receiver_map, if_handler, var_handler, &miss); | 3422 receiver_map, if_handler, var_handler, &miss); |
3422 } | 3423 } |
3423 | 3424 |
3424 Bind(&miss); | 3425 Bind(&miss); |
3425 { | 3426 { |
3426 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); | 3427 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); |
3427 Goto(if_miss); | 3428 Goto(if_miss); |
3428 } | 3429 } |
3429 } | 3430 } |
3430 | 3431 |
3431 void CodeStubAssembler::HandleLoadICHandlerCase(const LoadICParameters* p, | 3432 Node* CodeStubAssembler::TryToIntptr(Node* key, Label* miss) { |
3432 Node* handler, Label* miss) { | 3433 Variable var_intptr_key(this, MachineType::PointerRepresentation()); |
| 3434 Label done(this, &var_intptr_key), key_is_smi(this); |
| 3435 GotoIf(WordIsSmi(key), &key_is_smi); |
| 3436 // Try to convert a heap number to a Smi. |
| 3437 GotoUnless(WordEqual(LoadMap(key), HeapNumberMapConstant()), miss); |
| 3438 { |
| 3439 Node* value = LoadHeapNumberValue(key); |
| 3440 Node* int_value = RoundFloat64ToInt32(value); |
| 3441 GotoUnless(Float64Equal(value, ChangeInt32ToFloat64(int_value)), miss); |
| 3442 var_intptr_key.Bind(ChangeInt32ToIntPtr(int_value)); |
| 3443 Goto(&done); |
| 3444 } |
| 3445 |
| 3446 Bind(&key_is_smi); |
| 3447 { |
| 3448 var_intptr_key.Bind(SmiUntag(key)); |
| 3449 Goto(&done); |
| 3450 } |
| 3451 |
| 3452 Bind(&done); |
| 3453 return var_intptr_key.value(); |
| 3454 } |
| 3455 |
| 3456 // |is_jsarray| should be non-zero for JSArrays. |
| 3457 void CodeStubAssembler::EmitBoundsCheck(Node* object, Node* elements, |
| 3458 Node* intptr_key, Node* is_jsarray, |
| 3459 Label* miss) { |
| 3460 Variable var_length(this, MachineRepresentation::kTagged); |
| 3461 Label if_array(this), length_loaded(this, &var_length); |
| 3462 GotoUnless(WordEqual(is_jsarray, IntPtrConstant(0)), &if_array); |
| 3463 { |
| 3464 var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements))); |
| 3465 Goto(&length_loaded); |
| 3466 } |
| 3467 Bind(&if_array); |
| 3468 { |
| 3469 var_length.Bind(SmiUntag(LoadObjectField(object, JSArray::kLengthOffset))); |
| 3470 Goto(&length_loaded); |
| 3471 } |
| 3472 Bind(&length_loaded); |
| 3473 GotoUnless(UintPtrLessThan(intptr_key, var_length.value()), miss); |
| 3474 } |
| 3475 |
| 3476 // |key| should be untagged (int32). |
| 3477 void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements, |
| 3478 Node* elements_kind, Node* key, |
| 3479 Label* if_hole, Label* rebox_double, |
| 3480 Variable* var_double_value, |
| 3481 Label* miss) { |
| 3482 Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this), |
| 3483 if_fast_double(this), if_fast_holey_double(this), |
| 3484 unimplemented_elements_kind(this); |
| 3485 STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); |
| 3486 GotoIf( |
| 3487 IntPtrGreaterThanOrEqual( |
| 3488 elements_kind, IntPtrConstant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)), |
| 3489 &if_typed_array); |
| 3490 |
| 3491 int32_t kinds[] = {// Handled by if_fast_packed. |
| 3492 FAST_SMI_ELEMENTS, FAST_ELEMENTS, |
| 3493 // Handled by if_fast_holey. |
| 3494 FAST_HOLEY_SMI_ELEMENTS, FAST_HOLEY_ELEMENTS, |
| 3495 // Handled by if_fast_double. |
| 3496 FAST_DOUBLE_ELEMENTS, |
| 3497 // Handled by if_fast_holey_double. |
| 3498 FAST_HOLEY_DOUBLE_ELEMENTS}; |
| 3499 Label* labels[] = {// FAST_{SMI,}_ELEMENTS |
| 3500 &if_fast_packed, &if_fast_packed, |
| 3501 // FAST_HOLEY_{SMI,}_ELEMENTS |
| 3502 &if_fast_holey, &if_fast_holey, |
| 3503 // FAST_DOUBLE_ELEMENTS |
| 3504 &if_fast_double, |
| 3505 // FAST_HOLEY_DOUBLE_ELEMENTS |
| 3506 &if_fast_holey_double}; |
| 3507 Switch(elements_kind, &unimplemented_elements_kind, kinds, labels, |
| 3508 arraysize(kinds)); |
| 3509 Bind(&unimplemented_elements_kind); |
| 3510 { |
| 3511 // Crash if we get here. |
| 3512 DebugBreak(); |
| 3513 Goto(miss); |
| 3514 } |
| 3515 |
| 3516 Bind(&if_fast_packed); |
| 3517 { |
| 3518 Comment("fast packed elements"); |
| 3519 // TODO(jkummerow): The Load*Element helpers add movsxlq instructions |
| 3520 // on x64 which we don't need here, because |key| is an IntPtr already. |
| 3521 // Do something about that. |
| 3522 Return(LoadFixedArrayElement(elements, key)); |
| 3523 } |
| 3524 |
| 3525 Bind(&if_fast_holey); |
| 3526 { |
| 3527 Comment("fast holey elements"); |
| 3528 Node* element = LoadFixedArrayElement(elements, key); |
| 3529 GotoIf(WordEqual(element, TheHoleConstant()), if_hole); |
| 3530 Return(element); |
| 3531 } |
| 3532 |
| 3533 Bind(&if_fast_double); |
| 3534 { |
| 3535 Comment("packed double elements"); |
| 3536 var_double_value->Bind( |
| 3537 LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); |
| 3538 Goto(rebox_double); |
| 3539 } |
| 3540 |
| 3541 Bind(&if_fast_holey_double); |
| 3542 { |
| 3543 Comment("holey double elements"); |
| 3544 if (kPointerSize == kDoubleSize) { |
| 3545 Node* raw_element = |
| 3546 LoadFixedDoubleArrayElement(elements, key, MachineType::Uint64()); |
| 3547 Node* the_hole = Int64Constant(kHoleNanInt64); |
| 3548 GotoIf(Word64Equal(raw_element, the_hole), if_hole); |
| 3549 } else { |
| 3550 Node* element_upper = LoadFixedDoubleArrayElement( |
| 3551 elements, key, MachineType::Uint32(), kIeeeDoubleExponentWordOffset); |
| 3552 GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)), |
| 3553 if_hole); |
| 3554 } |
| 3555 var_double_value->Bind( |
| 3556 LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); |
| 3557 Goto(rebox_double); |
| 3558 } |
| 3559 |
| 3560 Bind(&if_typed_array); |
| 3561 { |
| 3562 Comment("typed elements"); |
| 3563 // Check if buffer has been neutered. |
| 3564 Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset); |
| 3565 Node* bitfield = LoadObjectField(buffer, JSArrayBuffer::kBitFieldOffset, |
| 3566 MachineType::Uint32()); |
| 3567 Node* neutered_bit = |
| 3568 Word32And(bitfield, Int32Constant(JSArrayBuffer::WasNeutered::kMask)); |
| 3569 GotoUnless(Word32Equal(neutered_bit, Int32Constant(0)), miss); |
| 3570 // Backing store = external_pointer + base_pointer. |
| 3571 Node* external_pointer = |
| 3572 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, |
| 3573 MachineType::Pointer()); |
| 3574 Node* base_pointer = |
| 3575 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); |
| 3576 Node* backing_store = IntPtrAdd(external_pointer, base_pointer); |
| 3577 |
| 3578 const int kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND - |
| 3579 FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + |
| 3580 1; |
| 3581 Label* elements_kind_labels[kTypedElementsKindCount]; |
| 3582 int32_t elements_kinds[kTypedElementsKindCount]; |
| 3583 for (int i = 0; i < kTypedElementsKindCount; i++) { |
| 3584 elements_kinds[i] = i + FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND; |
| 3585 elements_kind_labels[i] = new Label(this); |
| 3586 } |
| 3587 Switch(elements_kind, miss, elements_kinds, elements_kind_labels, |
| 3588 static_cast<size_t>(kTypedElementsKindCount)); |
| 3589 |
| 3590 for (int i = 0; i < kTypedElementsKindCount; i++) { |
| 3591 ElementsKind kind = static_cast<ElementsKind>(elements_kinds[i]); |
| 3592 Bind(elements_kind_labels[i]); |
| 3593 Comment(ElementsKindToString(kind)); |
| 3594 switch (kind) { |
| 3595 case UINT8_ELEMENTS: |
| 3596 case UINT8_CLAMPED_ELEMENTS: |
| 3597 Return(SmiTag(Load(MachineType::Uint8(), backing_store, key))); |
| 3598 break; |
| 3599 case INT8_ELEMENTS: |
| 3600 Return(SmiTag(Load(MachineType::Int8(), backing_store, key))); |
| 3601 break; |
| 3602 case UINT16_ELEMENTS: { |
| 3603 Node* index = WordShl(key, IntPtrConstant(1)); |
| 3604 Return(SmiTag(Load(MachineType::Uint16(), backing_store, index))); |
| 3605 break; |
| 3606 } |
| 3607 case INT16_ELEMENTS: { |
| 3608 Node* index = WordShl(key, IntPtrConstant(1)); |
| 3609 Return(SmiTag(Load(MachineType::Int16(), backing_store, index))); |
| 3610 break; |
| 3611 } |
| 3612 case UINT32_ELEMENTS: { |
| 3613 Node* index = WordShl(key, IntPtrConstant(2)); |
| 3614 Node* element = Load(MachineType::Uint32(), backing_store, index); |
| 3615 Return(ChangeUint32ToTagged(element)); |
| 3616 break; |
| 3617 } |
| 3618 case INT32_ELEMENTS: { |
| 3619 Node* index = WordShl(key, IntPtrConstant(2)); |
| 3620 Node* element = Load(MachineType::Int32(), backing_store, index); |
| 3621 Return(ChangeInt32ToTagged(element)); |
| 3622 break; |
| 3623 } |
| 3624 case FLOAT32_ELEMENTS: { |
| 3625 Node* index = WordShl(key, IntPtrConstant(2)); |
| 3626 Node* element = Load(MachineType::Float32(), backing_store, index); |
| 3627 var_double_value->Bind(ChangeFloat32ToFloat64(element)); |
| 3628 Goto(rebox_double); |
| 3629 break; |
| 3630 } |
| 3631 case FLOAT64_ELEMENTS: { |
| 3632 Node* index = WordShl(key, IntPtrConstant(3)); |
| 3633 Node* element = Load(MachineType::Float64(), backing_store, index); |
| 3634 var_double_value->Bind(element); |
| 3635 Goto(rebox_double); |
| 3636 break; |
| 3637 } |
| 3638 default: |
| 3639 UNREACHABLE(); |
| 3640 } |
| 3641 // Don't forget to clean up. |
| 3642 delete elements_kind_labels[i]; |
| 3643 } |
| 3644 } |
| 3645 } |
| 3646 |
| 3647 void CodeStubAssembler::HandleLoadICHandlerCase( |
| 3648 const LoadICParameters* p, Node* handler, Label* miss, |
| 3649 ElementSupport support_elements) { |
3433 Comment("have_handler"); | 3650 Comment("have_handler"); |
3434 Label call_handler(this); | 3651 Label call_handler(this); |
3435 GotoUnless(WordIsSmi(handler), &call_handler); | 3652 GotoUnless(WordIsSmi(handler), &call_handler); |
3436 | 3653 |
3437 // |handler| is a Smi. It encodes a field index as obtained by | 3654 // |handler| is a Smi, encoding what to do. See handler-configuration.h |
3438 // FieldIndex.GetLoadByFieldOffset(). | 3655 // for the encoding format. |
3439 // TODO(jkummerow): For KeyedLoadICs, extend this scheme to encode | |
3440 // fast *element* loads. | |
3441 { | 3656 { |
3442 Variable var_double_value(this, MachineRepresentation::kFloat64); | 3657 Variable var_double_value(this, MachineRepresentation::kFloat64); |
3443 Label rebox_double(this, &var_double_value); | 3658 Label rebox_double(this, &var_double_value); |
3444 | 3659 |
3445 Node* handler_word = SmiUntag(handler); | 3660 Node* handler_word = SmiUntag(handler); |
| 3661 if (support_elements == kSupportElements) { |
| 3662 Label property(this); |
| 3663 Node* handler_type = |
| 3664 WordAnd(handler_word, IntPtrConstant(LoadHandlerTypeBit::kMask)); |
| 3665 GotoUnless( |
| 3666 WordEqual(handler_type, IntPtrConstant(kLoadICHandlerForElements)), |
| 3667 &property); |
| 3668 |
| 3669 Comment("element_load"); |
| 3670 Node* key = TryToIntptr(p->name, miss); |
| 3671 Node* elements = LoadElements(p->receiver); |
| 3672 Node* is_jsarray = |
| 3673 WordAnd(handler_word, IntPtrConstant(KeyedLoadIsJsArray::kMask)); |
| 3674 EmitBoundsCheck(p->receiver, elements, key, is_jsarray, miss); |
| 3675 Label if_hole(this); |
| 3676 |
| 3677 Node* elements_kind = BitFieldDecode<KeyedLoadElementsKind>(handler_word); |
| 3678 |
| 3679 EmitElementLoad(p->receiver, elements, elements_kind, key, &if_hole, |
| 3680 &rebox_double, &var_double_value, miss); |
| 3681 |
| 3682 Bind(&if_hole); |
| 3683 { |
| 3684 Comment("convert hole"); |
| 3685 Node* convert_hole = |
| 3686 WordAnd(handler_word, IntPtrConstant(KeyedLoadConvertHole::kMask)); |
| 3687 GotoIf(WordEqual(convert_hole, IntPtrConstant(0)), miss); |
| 3688 Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex); |
| 3689 DCHECK(isolate()->heap()->array_protector()->IsPropertyCell()); |
| 3690 GotoUnless( |
| 3691 WordEqual( |
| 3692 LoadObjectField(protector_cell, PropertyCell::kValueOffset), |
| 3693 SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), |
| 3694 miss); |
| 3695 Return(UndefinedConstant()); |
| 3696 } |
| 3697 |
| 3698 Bind(&property); |
| 3699 Comment("property_load"); |
| 3700 } |
| 3701 |
3446 // |handler_word| is a field index as obtained by | 3702 // |handler_word| is a field index as obtained by |
3447 // FieldIndex.GetLoadByFieldOffset(): | 3703 // FieldIndex.GetLoadByFieldOffset(): |
3448 Label inobject_double(this), out_of_object(this), | 3704 Label inobject_double(this), out_of_object(this), |
3449 out_of_object_double(this); | 3705 out_of_object_double(this); |
3450 Node* inobject_bit = WordAnd( | 3706 Node* inobject_bit = |
3451 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsInobject::kMask)); | 3707 WordAnd(handler_word, IntPtrConstant(FieldOffsetIsInobject::kMask)); |
3452 Node* double_bit = WordAnd( | 3708 Node* double_bit = |
3453 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsDouble::kMask)); | 3709 WordAnd(handler_word, IntPtrConstant(FieldOffsetIsDouble::kMask)); |
3454 Node* offset = WordSar( | 3710 Node* offset = |
3455 handler_word, IntPtrConstant(FieldIndex::FieldOffsetOffset::kShift)); | 3711 WordSar(handler_word, IntPtrConstant(FieldOffsetOffset::kShift)); |
3456 | 3712 |
3457 GotoIf(WordEqual(inobject_bit, IntPtrConstant(0)), &out_of_object); | 3713 GotoIf(WordEqual(inobject_bit, IntPtrConstant(0)), &out_of_object); |
3458 | 3714 |
3459 GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &inobject_double); | 3715 GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &inobject_double); |
3460 Return(LoadObjectField(p->receiver, offset)); | 3716 Return(LoadObjectField(p->receiver, offset)); |
3461 | 3717 |
3462 Bind(&inobject_double); | 3718 Bind(&inobject_double); |
3463 if (FLAG_unbox_double_fields) { | 3719 if (FLAG_unbox_double_fields) { |
3464 var_double_value.Bind( | 3720 var_double_value.Bind( |
3465 LoadObjectField(p->receiver, offset, MachineType::Float64())); | 3721 LoadObjectField(p->receiver, offset, MachineType::Float64())); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3546 try_polymorphic_name(this /*, Label::kDeferred*/), | 3802 try_polymorphic_name(this /*, Label::kDeferred*/), |
3547 miss(this /*, Label::kDeferred*/); | 3803 miss(this /*, Label::kDeferred*/); |
3548 | 3804 |
3549 Node* receiver_map = LoadReceiverMap(p->receiver); | 3805 Node* receiver_map = LoadReceiverMap(p->receiver); |
3550 | 3806 |
3551 // Check monomorphic case. | 3807 // Check monomorphic case. |
3552 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler, | 3808 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler, |
3553 &var_handler, &try_polymorphic); | 3809 &var_handler, &try_polymorphic); |
3554 Bind(&if_handler); | 3810 Bind(&if_handler); |
3555 { | 3811 { |
3556 HandleLoadICHandlerCase(p, var_handler.value(), &miss); | 3812 HandleLoadICHandlerCase(p, var_handler.value(), &miss, kSupportElements); |
3557 } | 3813 } |
3558 | 3814 |
3559 Bind(&try_polymorphic); | 3815 Bind(&try_polymorphic); |
3560 { | 3816 { |
3561 // Check polymorphic case. | 3817 // Check polymorphic case. |
3562 Comment("KeyedLoadIC_try_polymorphic"); | 3818 Comment("KeyedLoadIC_try_polymorphic"); |
3563 GotoUnless( | 3819 GotoUnless( |
3564 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), | 3820 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), |
3565 &try_megamorphic); | 3821 &try_megamorphic); |
3566 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler, | 3822 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler, |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3718 Heap::kTheHoleValueRootIndex); | 3974 Heap::kTheHoleValueRootIndex); |
3719 | 3975 |
3720 // Store the WeakCell in the feedback vector. | 3976 // Store the WeakCell in the feedback vector. |
3721 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, | 3977 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, |
3722 CodeStubAssembler::SMI_PARAMETERS); | 3978 CodeStubAssembler::SMI_PARAMETERS); |
3723 return cell; | 3979 return cell; |
3724 } | 3980 } |
3725 | 3981 |
3726 } // namespace internal | 3982 } // namespace internal |
3727 } // namespace v8 | 3983 } // namespace v8 |
OLD | NEW |