Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(250)

Side by Side Diff: src/code-stub-assembler.cc

Issue 2227703003: Reland "[KeyedLoadIC] Support Smi "handlers" for element loads" (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: add DCHECK Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/field-index.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/field-index.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698