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