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

Side by Side Diff: src/ic/keyed-store-generic.cc

Issue 2504403005: [stubs] KeyedStoreGeneric: inline dictionary property stores (Closed)
Patch Set: ready for review Created 4 years, 1 month 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
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/ic/keyed-store-generic.h" 5 #include "src/ic/keyed-store-generic.h"
6 6
7 #include "src/code-factory.h"
7 #include "src/code-stub-assembler.h" 8 #include "src/code-stub-assembler.h"
8 #include "src/contexts.h" 9 #include "src/contexts.h"
9 #include "src/ic/accessor-assembler-impl.h" 10 #include "src/ic/accessor-assembler-impl.h"
10 #include "src/interface-descriptors.h" 11 #include "src/interface-descriptors.h"
11 #include "src/isolate.h" 12 #include "src/isolate.h"
12 13
13 namespace v8 { 14 namespace v8 {
14 namespace internal { 15 namespace internal {
15 16
16 using compiler::Node; 17 using compiler::Node;
(...skipping 10 matching lines...) Expand all
27 kDontChangeLength, 28 kDontChangeLength,
28 kIncrementLengthByOne, 29 kIncrementLengthByOne,
29 kBumpLengthWithGap 30 kBumpLengthWithGap
30 }; 31 };
31 32
32 void EmitGenericElementStore(Node* receiver, Node* receiver_map, 33 void EmitGenericElementStore(Node* receiver, Node* receiver_map,
33 Node* instance_type, Node* intptr_index, 34 Node* instance_type, Node* intptr_index,
34 Node* value, Node* context, Label* slow); 35 Node* value, Node* context, Label* slow);
35 36
36 void EmitGenericPropertyStore(Node* receiver, Node* receiver_map, 37 void EmitGenericPropertyStore(Node* receiver, Node* receiver_map,
37 const StoreICParameters* p, Label* slow); 38 const StoreICParameters* p, Label* slow,
39 LanguageMode language_mode);
38 40
39 void BranchIfPrototypesHaveNonFastElements(Node* receiver_map, 41 void BranchIfPrototypesHaveNonFastElements(Node* receiver_map,
40 Label* non_fast_elements, 42 Label* non_fast_elements,
41 Label* only_fast_elements); 43 Label* only_fast_elements);
42 44
43 void TryRewriteElements(Node* receiver, Node* receiver_map, Node* elements, 45 void TryRewriteElements(Node* receiver, Node* receiver_map, Node* elements,
44 Node* native_context, ElementsKind from_kind, 46 Node* native_context, ElementsKind from_kind,
45 ElementsKind to_kind, Label* bailout); 47 ElementsKind to_kind, Label* bailout);
46 48
47 void StoreElementWithCapacity(Node* receiver, Node* receiver_map, 49 void StoreElementWithCapacity(Node* receiver, Node* receiver_map,
48 Node* elements, Node* elements_kind, 50 Node* elements, Node* elements_kind,
49 Node* intptr_index, Node* value, Node* context, 51 Node* intptr_index, Node* value, Node* context,
50 Label* slow, UpdateLength update_length); 52 Label* slow, UpdateLength update_length);
51 53
52 void MaybeUpdateLengthAndReturn(Node* receiver, Node* index, Node* value, 54 void MaybeUpdateLengthAndReturn(Node* receiver, Node* index, Node* value,
53 UpdateLength update_length); 55 UpdateLength update_length);
54 56
55 void TryChangeToHoleyMapHelper(Node* receiver, Node* receiver_map, 57 void TryChangeToHoleyMapHelper(Node* receiver, Node* receiver_map,
56 Node* native_context, ElementsKind packed_kind, 58 Node* native_context, ElementsKind packed_kind,
57 ElementsKind holey_kind, Label* done, 59 ElementsKind holey_kind, Label* done,
58 Label* map_mismatch, Label* bailout); 60 Label* map_mismatch, Label* bailout);
59 void TryChangeToHoleyMap(Node* receiver, Node* receiver_map, 61 void TryChangeToHoleyMap(Node* receiver, Node* receiver_map,
60 Node* current_elements_kind, Node* context, 62 Node* current_elements_kind, Node* context,
61 ElementsKind packed_kind, Label* bailout); 63 ElementsKind packed_kind, Label* bailout);
62 void TryChangeToHoleyMapMulti(Node* receiver, Node* receiver_map, 64 void TryChangeToHoleyMapMulti(Node* receiver, Node* receiver_map,
63 Node* current_elements_kind, Node* context, 65 Node* current_elements_kind, Node* context,
64 ElementsKind packed_kind, 66 ElementsKind packed_kind,
65 ElementsKind packed_kind_2, Label* bailout); 67 ElementsKind packed_kind_2, Label* bailout);
68
69 void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
70 void LookupPropertyOnPrototypeChain(Node* receiver_map, Node* name,
71 Label* accessor,
72 Variable* var_accessor_pair,
73 Variable* var_accessor_holder,
74 Label* readonly, Label* bailout);
66 }; 75 };
67 76
68 void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state, 77 void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state,
69 LanguageMode language_mode) { 78 LanguageMode language_mode) {
70 KeyedStoreGenericAssembler assembler(state); 79 KeyedStoreGenericAssembler assembler(state);
71 assembler.KeyedStoreGeneric(language_mode); 80 assembler.KeyedStoreGeneric(language_mode);
72 } 81 }
73 82
74 void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements( 83 void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
75 Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) { 84 Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) {
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after
471 } 480 }
472 481
473 Bind(&if_typed_array); 482 Bind(&if_typed_array);
474 { 483 {
475 Comment("Typed array"); 484 Comment("Typed array");
476 // TODO(jkummerow): Support typed arrays. 485 // TODO(jkummerow): Support typed arrays.
477 Goto(slow); 486 Goto(slow);
478 } 487 }
479 } 488 }
480 489
490 void KeyedStoreGenericAssembler::JumpIfDataProperty(Node* details,
491 Label* writable,
492 Label* readonly) {
493 GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
Igor Sheludko 2016/11/22 12:05:08 Please add a comment that accessor properties neve
Jakob Kummerow 2016/11/22 13:47:57 Done.
494 readonly);
495 Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
496 GotoIf(Word32Equal(kind, Int32Constant(kData)), writable);
497 // Fall through if it's an accessor property.
498 }
499
500 void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
501 Node* receiver_map, Node* name, Label* accessor,
502 Variable* var_accessor_pair, Variable* var_accessor_holder, Label* readonly,
503 Label* bailout) {
504 Label ok_to_write(this);
505 Variable var_holder(this, MachineRepresentation::kTagged);
506 var_holder.Bind(LoadMapPrototype(receiver_map));
507 Variable var_holder_map(this, MachineRepresentation::kTagged);
508 var_holder_map.Bind(LoadMap(var_holder.value()));
509
510 Variable* merged_variables[] = {&var_holder, &var_holder_map};
511 Label loop(this, arraysize(merged_variables), merged_variables);
512 Goto(&loop);
513 Bind(&loop);
514 {
515 Node* holder = var_holder.value();
516 Node* holder_map = var_holder_map.value();
517 Node* instance_type = LoadMapInstanceType(holder_map);
518 Label next_proto(this);
519 {
520 Label found(this), found_fast(this), found_dict(this), found_global(this);
521 Variable var_meta_storage(this, MachineRepresentation::kTagged);
522 Variable var_entry(this, MachineType::PointerRepresentation());
523 TryLookupProperty(holder, holder_map, instance_type, name, &found_fast,
524 &found_dict, &found_global, &var_meta_storage,
525 &var_entry, &next_proto, bailout);
526 Bind(&found_fast);
527 {
528 Node* descriptors = var_meta_storage.value();
529 Node* name_index = var_entry.value();
530 const int kNameToDetailsOffset = (DescriptorArray::kDescriptorDetails -
531 DescriptorArray::kDescriptorKey) *
532 kPointerSize;
533 Node* details = LoadAndUntagToWord32FixedArrayElement(
534 descriptors, name_index, kNameToDetailsOffset);
535 JumpIfDataProperty(details, &ok_to_write, readonly);
536
537 // Accessor case.
538 Variable var_details(this, MachineRepresentation::kWord32);
539 LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index,
540 &var_details, var_accessor_pair);
541 var_accessor_holder->Bind(holder);
542 Goto(accessor);
543 }
544
545 Bind(&found_dict);
546 {
547 Node* dictionary = var_meta_storage.value();
548 Node* entry = var_entry.value();
549 const int kNameToDetailsOffset = (NameDictionary::kEntryDetailsIndex -
550 NameDictionary::kEntryKeyIndex) *
551 kPointerSize;
552 Node* details = LoadAndUntagToWord32FixedArrayElement(
553 dictionary, entry, kNameToDetailsOffset);
554 JumpIfDataProperty(details, &ok_to_write, readonly);
555
556 // Accessor case.
557 const int kNameToValueOffset = (NameDictionary::kEntryValueIndex -
558 NameDictionary::kEntryKeyIndex) *
559 kPointerSize;
560 var_accessor_pair->Bind(
561 LoadFixedArrayElement(dictionary, entry, kNameToValueOffset));
562 var_accessor_holder->Bind(holder);
563 Goto(accessor);
564 }
565
566 Bind(&found_global);
567 {
568 Node* dictionary = var_meta_storage.value();
569 Node* entry = var_entry.value();
570 const int kNameToValueOffset = (GlobalDictionary::kEntryValueIndex -
Igor Sheludko 2016/11/22 12:05:08 Idea for next CL: add helper functions for accessi
Jakob Kummerow 2016/11/22 13:47:57 Acknowledged. Good idea. An alternative I've consi
571 GlobalDictionary::kEntryKeyIndex) *
572 kPointerSize;
573
574 Node* property_cell =
575 LoadFixedArrayElement(dictionary, entry, kNameToValueOffset);
576
577 Node* value =
578 LoadObjectField(property_cell, PropertyCell::kValueOffset);
579 GotoIf(WordEqual(value, TheHoleConstant()), &next_proto);
580 Node* details = LoadAndUntagToWord32ObjectField(
581 property_cell, PropertyCell::kDetailsOffset);
582 JumpIfDataProperty(details, &ok_to_write, readonly);
583
584 // Accessor case.
585 var_accessor_pair->Bind(value);
586 var_accessor_holder->Bind(holder);
587 Goto(accessor);
588 }
589 }
590
591 Bind(&next_proto);
592 // Bailout if it can be an integer indexed exotic case.
593 GotoIf(Word32Equal(instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
594 bailout);
595 Node* proto = LoadMapPrototype(holder_map);
596 GotoIf(WordEqual(proto, NullConstant()), &ok_to_write);
597 var_holder.Bind(proto);
598 var_holder_map.Bind(LoadMap(proto));
599 Goto(&loop);
600 }
601 Bind(&ok_to_write);
602 }
603
481 void KeyedStoreGenericAssembler::EmitGenericPropertyStore( 604 void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
482 Node* receiver, Node* receiver_map, const StoreICParameters* p, 605 Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow,
483 Label* slow) { 606 LanguageMode language_mode) {
484 Comment("stub cache probe"); 607 Variable var_accessor_pair(this, MachineRepresentation::kTagged);
485 // TODO(jkummerow): Don't rely on the stub cache as much. 608 Variable var_accessor_holder(this, MachineRepresentation::kTagged);
486 // - existing properties can be overwritten inline (unless readonly). 609 Label stub_cache(this), fast_properties(this), dictionary_properties(this),
487 // - for dictionary mode receivers, we can even add properties inline 610 accessor(this), readonly(this);
488 // (unless the prototype chain prevents it). 611 Node* properties = LoadProperties(receiver);
489 Variable var_handler(this, MachineRepresentation::kTagged); 612 Node* properties_map = LoadMap(properties);
490 Label found_handler(this, &var_handler), stub_cache_miss(this); 613 Branch(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)),
491 TryProbeStubCache(isolate()->store_stub_cache(), receiver, p->name, 614 &dictionary_properties, &fast_properties);
492 &found_handler, &var_handler, &stub_cache_miss); 615
493 Bind(&found_handler); 616 Bind(&fast_properties);
494 { 617 {
495 Comment("KeyedStoreGeneric found handler"); 618 // TODO(jkummerow): Does it make sense to support some cases here inline?
496 HandleStoreICHandlerCase(p, var_handler.value(), slow); 619 // Maybe overwrite existing writable properties?
497 } 620 // Maybe support map transitions?
498 Bind(&stub_cache_miss); 621 Goto(&stub_cache);
499 { 622 }
500 Comment("KeyedStoreGeneric_miss"); 623
501 TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot, 624 Bind(&dictionary_properties);
502 p->vector, p->receiver, p->name); 625 {
503 } 626 Comment("dictionary property store");
504 } 627 // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
505 628 // seeing global objects here (which would need special handling).
629
630 Variable var_name_index(this, MachineType::PointerRepresentation());
631 Label dictionary_found(this, &var_name_index), not_found(this);
632 NameDictionaryLookup<NameDictionary>(properties, p->name, &dictionary_found,
633 &var_name_index, &not_found);
634 Bind(&dictionary_found);
635 {
636 Label overwrite(this);
637 const int kNameToDetailsOffset = (NameDictionary::kEntryDetailsIndex -
638 NameDictionary::kEntryKeyIndex) *
639 kPointerSize;
640 Node* details = LoadAndUntagToWord32FixedArrayElement(
641 properties, var_name_index.value(), kNameToDetailsOffset);
642 JumpIfDataProperty(details, &overwrite, &readonly);
643
644 // Accessor case.
645 const int kNameToValueOffset =
646 (NameDictionary::kEntryValueIndex - NameDictionary::kEntryKeyIndex) *
647 kPointerSize;
648 var_accessor_pair.Bind(LoadFixedArrayElement(
649 properties, var_name_index.value(), kNameToValueOffset));
650 var_accessor_holder.Bind(receiver);
651 Goto(&accessor);
652
653 Bind(&overwrite);
654 {
655 StoreFixedArrayElement(properties, var_name_index.value(), p->value,
656 kNameToValueOffset, UPDATE_WRITE_BARRIER,
657 INTPTR_PARAMETERS);
658 Return(p->value);
659 }
660 }
661
662 Bind(&not_found);
663 {
664 LookupPropertyOnPrototypeChain(receiver_map, p->name, &accessor,
665 &var_accessor_pair, &var_accessor_holder,
666 &readonly, slow);
667 Add<NameDictionary>(properties, p->name, p->value, slow);
668 Return(p->value);
669 }
670 }
671
672 Bind(&accessor);
673 {
674 Label not_callable(this);
675 Node* accessor_pair = var_accessor_pair.value();
676 GotoIf(Word32Equal(LoadInstanceType(accessor_pair),
Igor Sheludko 2016/11/22 12:05:08 You can compare maps instead of instance types.
Jakob Kummerow 2016/11/22 13:47:57 Done. (I wonder which is faster...)
Igor Sheludko 2016/11/22 14:07:31 I heard rumors that CSA can replace LoadRoot() wit
677 Int32Constant(ACCESSOR_INFO_TYPE)),
678 slow);
679 CSA_ASSERT(this, HasInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE));
680 Node* setter = LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
681 Node* setter_map = LoadMap(setter);
682 // FunctionTemplateInfo setters are not supported yet.
683 GotoIf(Word32Equal(LoadMapInstanceType(setter_map),
Igor Sheludko 2016/11/22 12:05:08 Same here.
Jakob Kummerow 2016/11/22 13:47:57 Done.
684 Int32Constant(FUNCTION_TEMPLATE_INFO_TYPE)),
685 slow);
686 GotoUnless(IsCallableMap(setter_map), &not_callable);
687
688 Callable callable = CodeFactory::Call(isolate());
689 CallJS(callable, p->context, setter, receiver, p->value);
690 Return(p->value);
691
692 Bind(&not_callable);
693 {
694 if (language_mode == STRICT) {
695 Node* message =
696 SmiConstant(Smi::FromInt(MessageTemplate::kNoSetterInCallback));
697 TailCallRuntime(Runtime::kThrowTypeError, p->context, message, p->name,
698 var_accessor_holder.value());
699 } else {
700 DCHECK(language_mode == SLOPPY);
Igor Sheludko 2016/11/22 12:05:08 DCHECK_EQ
Jakob Kummerow 2016/11/22 13:47:57 Done.
701 Return(p->value);
702 }
703 }
704 }
705
706 Bind(&readonly);
707 {
708 if (language_mode == STRICT) {
709 Node* message =
710 SmiConstant(Smi::FromInt(MessageTemplate::kStrictReadOnlyProperty));
711 Node* type = Typeof(p->receiver, p->context);
712 TailCallRuntime(Runtime::kThrowTypeError, p->context, message, p->name,
713 type, p->receiver);
714 } else {
715 DCHECK(language_mode == SLOPPY);
Igor Sheludko 2016/11/22 12:05:08 DCHECK_EQ
Jakob Kummerow 2016/11/22 13:47:57 Done.
716 Return(p->value);
717 }
718 }
719
720 Bind(&stub_cache);
721 {
722 Comment("stub cache probe");
723 Variable var_handler(this, MachineRepresentation::kTagged);
724 Label found_handler(this, &var_handler), stub_cache_miss(this);
725 TryProbeStubCache(isolate()->store_stub_cache(), receiver, p->name,
726 &found_handler, &var_handler, &stub_cache_miss);
727 Bind(&found_handler);
728 {
729 Comment("KeyedStoreGeneric found handler");
730 HandleStoreICHandlerCase(p, var_handler.value(), slow);
731 }
732 Bind(&stub_cache_miss);
733 {
734 Comment("KeyedStoreGeneric_miss");
735 TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value,
736 p->slot, p->vector, p->receiver, p->name);
737 }
738 }
739 }
740
506 void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) { 741 void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) {
507 typedef StoreWithVectorDescriptor Descriptor; 742 typedef StoreWithVectorDescriptor Descriptor;
508 743
509 Node* receiver = Parameter(Descriptor::kReceiver); 744 Node* receiver = Parameter(Descriptor::kReceiver);
510 Node* name = Parameter(Descriptor::kName); 745 Node* name = Parameter(Descriptor::kName);
511 Node* value = Parameter(Descriptor::kValue); 746 Node* value = Parameter(Descriptor::kValue);
512 Node* slot = Parameter(Descriptor::kSlot); 747 Node* slot = Parameter(Descriptor::kSlot);
513 Node* vector = Parameter(Descriptor::kVector); 748 Node* vector = Parameter(Descriptor::kVector);
514 Node* context = Parameter(Descriptor::kContext); 749 Node* context = Parameter(Descriptor::kContext);
515 750
(...skipping 16 matching lines...) Expand all
532 Comment("integer index"); 767 Comment("integer index");
533 EmitGenericElementStore(receiver, receiver_map, instance_type, 768 EmitGenericElementStore(receiver, receiver_map, instance_type,
534 var_index.value(), value, context, &slow); 769 var_index.value(), value, context, &slow);
535 } 770 }
536 771
537 Bind(&if_unique_name); 772 Bind(&if_unique_name);
538 { 773 {
539 Comment("key is unique name"); 774 Comment("key is unique name");
540 KeyedStoreGenericAssembler::StoreICParameters p(context, receiver, name, 775 KeyedStoreGenericAssembler::StoreICParameters p(context, receiver, name,
541 value, slot, vector); 776 value, slot, vector);
542 EmitGenericPropertyStore(receiver, receiver_map, &p, &slow); 777 EmitGenericPropertyStore(receiver, receiver_map, &p, &slow, language_mode);
543 } 778 }
544 779
545 Bind(&slow); 780 Bind(&slow);
546 { 781 {
547 Comment("KeyedStoreGeneric_slow"); 782 Comment("KeyedStoreGeneric_slow");
548 TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value, 783 TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value,
549 SmiConstant(language_mode)); 784 SmiConstant(language_mode));
550 } 785 }
551 } 786 }
552 787
553 } // namespace internal 788 } // namespace internal
554 } // namespace v8 789 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698