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

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

Issue 2180273002: [KeyedLoadIC] Support Smi "handlers" for element loads (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@keyed-load-ic-fieldindex
Patch Set: rebased 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 3399 matching lines...) Expand 10 before | Expand all | Expand 10 after
3418 receiver_map, if_handler, var_handler, &miss); 3419 receiver_map, if_handler, var_handler, &miss);
3419 } 3420 }
3420 3421
3421 Bind(&miss); 3422 Bind(&miss);
3422 { 3423 {
3423 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); 3424 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
3424 Goto(if_miss); 3425 Goto(if_miss);
3425 } 3426 }
3426 } 3427 }
3427 3428
3428 void CodeStubAssembler::HandleLoadICHandlerCase(const LoadICParameters* p, 3429 // |is_jsarray| should be non-zero for JSArrays.
3429 Node* handler, Label* miss) { 3430 void CodeStubAssembler::EmitBoundsCheck(Node* object, Node* elements,
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) {
3430 Comment("have_handler"); 3623 Comment("have_handler");
3431 Label call_handler(this); 3624 Label call_handler(this);
3432 GotoUnless(WordIsSmi(handler), &call_handler); 3625 GotoUnless(WordIsSmi(handler), &call_handler);
3433 3626
3434 // |handler| is a Smi. It encodes a field index as obtained by 3627 // |handler| is a Smi, encoding what to do. See handler-configuration.h
3435 // FieldIndex.GetLoadByFieldOffset(). 3628 // for the encoding format.
3436 // TODO(jkummerow): For KeyedLoadICs, extend this scheme to encode
3437 // fast *element* loads.
3438 { 3629 {
3439 Variable var_double_value(this, MachineRepresentation::kFloat64); 3630 Variable var_double_value(this, MachineRepresentation::kFloat64);
3440 Label rebox_double(this, &var_double_value); 3631 Label rebox_double(this, &var_double_value);
3441 3632
3442 Node* handler_word = SmiUntag(handler); 3633 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
3443 // |handler_word| is a field index as obtained by 3674 // |handler_word| is a field index as obtained by
3444 // FieldIndex.GetLoadByFieldOffset(): 3675 // FieldIndex.GetLoadByFieldOffset():
3445 Label inobject_double(this), out_of_object(this), 3676 Label inobject_double(this), out_of_object(this),
3446 out_of_object_double(this); 3677 out_of_object_double(this);
3447 Node* inobject_bit = WordAnd( 3678 Node* inobject_bit =
3448 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsInobject::kMask)); 3679 WordAnd(handler_word, IntPtrConstant(FieldOffsetIsInobject::kMask));
3449 Node* double_bit = WordAnd( 3680 Node* double_bit =
3450 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsDouble::kMask)); 3681 WordAnd(handler_word, IntPtrConstant(FieldOffsetIsDouble::kMask));
3451 Node* offset = WordSar( 3682 Node* offset =
3452 handler_word, IntPtrConstant(FieldIndex::FieldOffsetOffset::kShift)); 3683 WordSar(handler_word, IntPtrConstant(FieldOffsetOffset::kShift));
3453 3684
3454 GotoIf(WordEqual(inobject_bit, IntPtrConstant(0)), &out_of_object); 3685 GotoIf(WordEqual(inobject_bit, IntPtrConstant(0)), &out_of_object);
3455 3686
3456 GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &inobject_double); 3687 GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &inobject_double);
3457 Return(LoadObjectField(p->receiver, offset)); 3688 Return(LoadObjectField(p->receiver, offset));
3458 3689
3459 Bind(&inobject_double); 3690 Bind(&inobject_double);
3460 if (FLAG_unbox_double_fields) { 3691 if (FLAG_unbox_double_fields) {
3461 var_double_value.Bind( 3692 var_double_value.Bind(
3462 LoadObjectField(p->receiver, offset, MachineType::Float64())); 3693 LoadObjectField(p->receiver, offset, MachineType::Float64()));
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
3543 try_polymorphic_name(this /*, Label::kDeferred*/), 3774 try_polymorphic_name(this /*, Label::kDeferred*/),
3544 miss(this /*, Label::kDeferred*/); 3775 miss(this /*, Label::kDeferred*/);
3545 3776
3546 Node* receiver_map = LoadReceiverMap(p->receiver); 3777 Node* receiver_map = LoadReceiverMap(p->receiver);
3547 3778
3548 // Check monomorphic case. 3779 // Check monomorphic case.
3549 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler, 3780 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler,
3550 &var_handler, &try_polymorphic); 3781 &var_handler, &try_polymorphic);
3551 Bind(&if_handler); 3782 Bind(&if_handler);
3552 { 3783 {
3553 HandleLoadICHandlerCase(p, var_handler.value(), &miss); 3784 HandleLoadICHandlerCase(p, var_handler.value(), &miss, kSupportElements);
3554 } 3785 }
3555 3786
3556 Bind(&try_polymorphic); 3787 Bind(&try_polymorphic);
3557 { 3788 {
3558 // Check polymorphic case. 3789 // Check polymorphic case.
3559 Comment("KeyedLoadIC_try_polymorphic"); 3790 Comment("KeyedLoadIC_try_polymorphic");
3560 GotoUnless( 3791 GotoUnless(
3561 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), 3792 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
3562 &try_megamorphic); 3793 &try_megamorphic);
3563 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler, 3794 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler,
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
3715 Heap::kTheHoleValueRootIndex); 3946 Heap::kTheHoleValueRootIndex);
3716 3947
3717 // Store the WeakCell in the feedback vector. 3948 // Store the WeakCell in the feedback vector.
3718 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, 3949 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER,
3719 CodeStubAssembler::SMI_PARAMETERS); 3950 CodeStubAssembler::SMI_PARAMETERS);
3720 return cell; 3951 return cell;
3721 } 3952 }
3722 3953
3723 } // namespace internal 3954 } // namespace internal
3724 } // namespace v8 3955 } // 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