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

Side by Side Diff: src/lookup.cc

Issue 1751043002: Speed up the LookupIterator (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix proxy + private symbols Created 4 years, 9 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/lookup.h ('k') | src/objects.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 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 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/lookup.h" 5 #include "src/lookup.h"
6 6
7 #include "src/bootstrapper.h" 7 #include "src/bootstrapper.h"
8 #include "src/deoptimizer.h" 8 #include "src/deoptimizer.h"
9 #include "src/elements.h" 9 #include "src/elements.h"
10 #include "src/field-type.h" 10 #include "src/field-type.h"
(...skipping 27 matching lines...) Expand all
38 LookupIterator it(isolate, receiver, index, configuration); 38 LookupIterator it(isolate, receiver, index, configuration);
39 // Here we try to avoid having to rebuild the string later 39 // Here we try to avoid having to rebuild the string later
40 // by storing it on the indexed LookupIterator. 40 // by storing it on the indexed LookupIterator.
41 it.name_ = name; 41 it.name_ = name;
42 return it; 42 return it;
43 } 43 }
44 44
45 return LookupIterator(receiver, name, configuration); 45 return LookupIterator(receiver, name, configuration);
46 } 46 }
47 47
48 void LookupIterator::Start() {
49 DisallowHeapAllocation no_gc;
50
51 has_property_ = false;
52 state_ = NOT_FOUND;
53 number_ = DescriptorArray::kNotFound;
54 holder_ = initial_holder_;
55
56 JSReceiver* holder = *holder_;
57 Map* map = holder->map();
58
59 state_ = LookupInHolder(map, holder);
60 if (IsFound()) return;
61
62 NextInternal(map, holder);
63 }
48 64
49 void LookupIterator::Next() { 65 void LookupIterator::Next() {
50 DCHECK_NE(JSPROXY, state_); 66 DCHECK_NE(JSPROXY, state_);
51 DCHECK_NE(TRANSITION, state_); 67 DCHECK_NE(TRANSITION, state_);
52 DisallowHeapAllocation no_gc; 68 DisallowHeapAllocation no_gc;
53 has_property_ = false; 69 has_property_ = false;
54 70
55 JSReceiver* holder = *holder_; 71 JSReceiver* holder = *holder_;
56 Map* map = holder->map(); 72 Map* map = holder->map();
57 73
58 // Perform lookup on current holder. 74 if (map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
59 state_ = LookupInHolder(map, holder); 75 state_ = LookupInSpecialHolder(map, holder);
60 if (IsFound()) return; 76 if (IsFound()) return;
77 }
61 78
62 // Continue lookup if lookup on current holder failed. 79 NextInternal(map, holder);
80 }
81
82 void LookupIterator::NextInternal(Map* map, JSReceiver* holder) {
63 do { 83 do {
64 JSReceiver* maybe_holder = NextHolder(map); 84 JSReceiver* maybe_holder = NextHolder(map);
65 if (maybe_holder == nullptr) { 85 if (maybe_holder == nullptr) {
66 if (interceptor_state_ == InterceptorState::kSkipNonMasking) { 86 if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
67 RestartLookupForNonMaskingInterceptors(); 87 RestartLookupForNonMaskingInterceptors();
68 return; 88 return;
69 } 89 }
70 break; 90 if (holder != *holder_) holder_ = handle(holder, isolate_);
91 return;
71 } 92 }
72 holder = maybe_holder; 93 holder = maybe_holder;
73 map = holder->map(); 94 map = holder->map();
74 state_ = LookupInHolder(map, holder); 95 state_ = LookupInHolder(map, holder);
75 } while (!IsFound()); 96 } while (!IsFound());
76 97
77 if (holder != *holder_) holder_ = handle(holder, isolate_); 98 holder_ = handle(holder, isolate_);
99 }
100
101 void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
102 interceptor_state_ = interceptor_state;
103 property_details_ = PropertyDetails::Empty();
104 Start();
78 } 105 }
79 106
80 107
81 void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
82 state_ = NOT_FOUND;
83 interceptor_state_ = interceptor_state;
84 property_details_ = PropertyDetails::Empty();
85 holder_ = initial_holder_;
86 number_ = DescriptorArray::kNotFound;
87 Next();
88 }
89
90
91 // static 108 // static
92 Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver( 109 Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
93 Isolate* isolate, Handle<Object> receiver, uint32_t index) { 110 Isolate* isolate, Handle<Object> receiver, uint32_t index) {
94 // Strings are the only objects with properties (only elements) directly on 111 // Strings are the only objects with properties (only elements) directly on
95 // the wrapper. Hence we can skip generating the wrapper for all other cases. 112 // the wrapper. Hence we can skip generating the wrapper for all other cases.
96 if (index != kMaxUInt32 && receiver->IsString() && 113 if (index != kMaxUInt32 && receiver->IsString() &&
97 index < static_cast<uint32_t>(String::cast(*receiver)->length())) { 114 index < static_cast<uint32_t>(String::cast(*receiver)->length())) {
98 // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native 115 // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
99 // context, ensuring that we don't leak it into JS? 116 // context, ensuring that we don't leak it into JS?
100 Handle<JSFunction> constructor = isolate->string_function(); 117 Handle<JSFunction> constructor = isolate->string_function();
101 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); 118 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
102 Handle<JSValue>::cast(result)->set_value(*receiver); 119 Handle<JSValue>::cast(result)->set_value(*receiver);
103 return result; 120 return result;
104 } 121 }
105 auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate); 122 auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate);
106 if (root->IsNull()) { 123 if (root->IsNull()) {
107 unsigned int magic = 0xbbbbbbbb; 124 unsigned int magic = 0xbbbbbbbb;
108 isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic); 125 isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic);
109 } 126 }
110 return Handle<JSReceiver>::cast(root); 127 return Handle<JSReceiver>::cast(root);
111 } 128 }
112 129
113 130
114 Handle<Map> LookupIterator::GetReceiverMap() const { 131 Handle<Map> LookupIterator::GetReceiverMap() const {
115 if (receiver_->IsNumber()) return factory()->heap_number_map(); 132 if (receiver_->IsNumber()) return factory()->heap_number_map();
116 return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_); 133 return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_);
117 } 134 }
118 135
119
120 Handle<JSObject> LookupIterator::GetStoreTarget() const {
121 if (receiver_->IsJSGlobalProxy()) {
122 Object* prototype = JSGlobalProxy::cast(*receiver_)->map()->prototype();
123 if (!prototype->IsNull()) {
124 return handle(JSGlobalObject::cast(prototype), isolate_);
125 }
126 }
127 return Handle<JSObject>::cast(receiver_);
128 }
129
130
131 bool LookupIterator::HasAccess() const { 136 bool LookupIterator::HasAccess() const {
132 DCHECK_EQ(ACCESS_CHECK, state_); 137 DCHECK_EQ(ACCESS_CHECK, state_);
133 return isolate_->MayAccess(handle(isolate_->context()), 138 return isolate_->MayAccess(handle(isolate_->context()),
134 GetHolder<JSObject>()); 139 GetHolder<JSObject>());
135 } 140 }
136 141
137 142
138 void LookupIterator::ReloadPropertyInformation() { 143 void LookupIterator::ReloadPropertyInformation() {
139 state_ = BEFORE_PROPERTY; 144 state_ = BEFORE_PROPERTY;
140 interceptor_state_ = InterceptorState::kUninitialized; 145 interceptor_state_ = InterceptorState::kUninitialized;
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after
598 // Fall through. 603 // Fall through.
599 case InterceptorState::kSkipNonMasking: 604 case InterceptorState::kSkipNonMasking:
600 return true; 605 return true;
601 case InterceptorState::kProcessNonMasking: 606 case InterceptorState::kProcessNonMasking:
602 return false; 607 return false;
603 } 608 }
604 } 609 }
605 return interceptor_state_ == InterceptorState::kProcessNonMasking; 610 return interceptor_state_ == InterceptorState::kProcessNonMasking;
606 } 611 }
607 612
608
609 JSReceiver* LookupIterator::NextHolder(Map* map) { 613 JSReceiver* LookupIterator::NextHolder(Map* map) {
610 DisallowHeapAllocation no_gc; 614 DisallowHeapAllocation no_gc;
611 if (!map->prototype()->IsJSReceiver()) return NULL; 615 if (map->prototype() == heap()->null_value()) return NULL;
612 616
613 DCHECK(!map->IsJSGlobalProxyMap() || map->has_hidden_prototype()); 617 DCHECK(!map->IsJSGlobalProxyMap() || map->has_hidden_prototype());
614 618
615 if (!check_prototype_chain() && 619 if (!check_prototype_chain() &&
616 !(check_hidden() && map->has_hidden_prototype()) && 620 !(check_hidden() && map->has_hidden_prototype()) &&
617 // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even 621 // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even
618 // when not checking other hidden prototypes. 622 // when not checking other hidden prototypes.
619 !map->IsJSGlobalProxyMap()) { 623 !map->IsJSGlobalProxyMap()) {
620 return NULL; 624 return NULL;
621 } 625 }
622 626
623 return JSReceiver::cast(map->prototype()); 627 return JSReceiver::cast(map->prototype());
624 } 628 }
625 629
626 LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const { 630 LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const {
627 DCHECK(!IsElement()); 631 DCHECK(!IsElement());
628 if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND; 632 if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND;
629 633
630 Handle<String> name_string = Handle<String>::cast(name_); 634 Handle<String> name_string = Handle<String>::cast(name_);
631 if (name_string->length() == 0) return NOT_FOUND; 635 if (name_string->length() == 0) return NOT_FOUND;
632 636
633 return IsSpecialIndex(isolate_->unicode_cache(), *name_string) 637 return IsSpecialIndex(isolate_->unicode_cache(), *name_string)
634 ? INTEGER_INDEXED_EXOTIC 638 ? INTEGER_INDEXED_EXOTIC
635 : NOT_FOUND; 639 : NOT_FOUND;
636 } 640 }
637 641
638 LookupIterator::State LookupIterator::LookupInHolder(Map* const map, 642 LookupIterator::State LookupIterator::LookupInSpecialHolder(
639 JSReceiver* const holder) { 643 Map* const map, JSReceiver* const holder) {
640 STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY); 644 STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
641 DisallowHeapAllocation no_gc;
642 if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
643 return LookupNonMaskingInterceptorInHolder(map, holder);
644 }
645 switch (state_) { 645 switch (state_) {
646 case NOT_FOUND: 646 case NOT_FOUND:
647 if (map->IsJSProxyMap()) { 647 if (map->IsJSProxyMap()) {
648 if (IsElement() || !name_->IsPrivate()) return JSPROXY; 648 if (IsElement() || !name_->IsPrivate()) return JSPROXY;
649 } 649 }
650 if (map->is_access_check_needed()) { 650 if (map->is_access_check_needed()) {
651 if (IsElement() || !name_->IsPrivate()) return ACCESS_CHECK; 651 if (IsElement() || !name_->IsPrivate()) return ACCESS_CHECK;
652 } 652 }
653 // Fall through. 653 // Fall through.
654 case ACCESS_CHECK: 654 case ACCESS_CHECK:
655 if (check_interceptor() && HasInterceptor(map) && 655 if (check_interceptor() && HasInterceptor(map) &&
656 !SkipInterceptor(JSObject::cast(holder))) { 656 !SkipInterceptor(JSObject::cast(holder))) {
657 if (IsElement() || !name_->IsPrivate()) return INTERCEPTOR; 657 if (IsElement() || !name_->IsPrivate()) return INTERCEPTOR;
658 } 658 }
659 // Fall through. 659 // Fall through.
660 case INTERCEPTOR: 660 case INTERCEPTOR:
661 if (IsElement()) { 661 if (!IsElement() && map->IsJSGlobalObjectMap()) {
662 JSObject* js_object = JSObject::cast(holder);
663 ElementsAccessor* accessor = js_object->GetElementsAccessor();
664 FixedArrayBase* backing_store = js_object->elements();
665 number_ = accessor->GetEntryForIndex(js_object, backing_store, index_);
666 if (number_ == kMaxUInt32) {
667 return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
668 }
669 property_details_ = accessor->GetDetails(js_object, number_);
670 } else if (!map->is_dictionary_map()) {
671 DescriptorArray* descriptors = map->instance_descriptors();
672 int number = descriptors->SearchWithCache(isolate_, *name_, map);
673 if (number == DescriptorArray::kNotFound) return NotFound(holder);
674 number_ = static_cast<uint32_t>(number);
675 property_details_ = descriptors->GetDetails(number_);
676 } else if (map->IsJSGlobalObjectMap()) {
677 GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary(); 662 GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary();
678 int number = dict->FindEntry(name_); 663 int number = dict->FindEntry(name_);
679 if (number == GlobalDictionary::kNotFound) return NOT_FOUND; 664 if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
680 number_ = static_cast<uint32_t>(number); 665 number_ = static_cast<uint32_t>(number);
681 DCHECK(dict->ValueAt(number_)->IsPropertyCell()); 666 DCHECK(dict->ValueAt(number_)->IsPropertyCell());
682 PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_)); 667 PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_));
683 if (cell->value()->IsTheHole()) return NOT_FOUND; 668 if (cell->value()->IsTheHole()) return NOT_FOUND;
684 property_details_ = cell->property_details(); 669 property_details_ = cell->property_details();
685 } else { 670 has_property_ = true;
686 NameDictionary* dict = holder->property_dictionary(); 671 switch (property_details_.kind()) {
687 int number = dict->FindEntry(name_); 672 case v8::internal::kData:
688 if (number == NameDictionary::kNotFound) return NotFound(holder); 673 return DATA;
689 number_ = static_cast<uint32_t>(number); 674 case v8::internal::kAccessor:
690 property_details_ = dict->DetailsAt(number_); 675 return ACCESSOR;
676 }
691 } 677 }
692 has_property_ = true; 678 return LookupInRegularHolder(map, holder);
693 switch (property_details_.kind()) {
694 case v8::internal::kData:
695 return DATA;
696 case v8::internal::kAccessor:
697 return ACCESSOR;
698 }
699 case ACCESSOR: 679 case ACCESSOR:
700 case DATA: 680 case DATA:
701 return NOT_FOUND; 681 return NOT_FOUND;
702 case INTEGER_INDEXED_EXOTIC: 682 case INTEGER_INDEXED_EXOTIC:
703 case JSPROXY: 683 case JSPROXY:
704 case TRANSITION: 684 case TRANSITION:
705 UNREACHABLE(); 685 UNREACHABLE();
706 } 686 }
707 UNREACHABLE(); 687 UNREACHABLE();
708 return state_; 688 return NOT_FOUND;
709 } 689 }
710 690
691 LookupIterator::State LookupIterator::LookupInRegularHolder(
692 Map* const map, JSReceiver* const holder) {
693 DisallowHeapAllocation no_gc;
694 if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
695 return NOT_FOUND;
696 }
711 697
712 LookupIterator::State LookupIterator::LookupNonMaskingInterceptorInHolder( 698 if (IsElement()) {
713 Map* const map, JSReceiver* const holder) { 699 JSObject* js_object = JSObject::cast(holder);
714 switch (state_) { 700 ElementsAccessor* accessor = js_object->GetElementsAccessor();
715 case NOT_FOUND: 701 FixedArrayBase* backing_store = js_object->elements();
716 if (check_interceptor() && HasInterceptor(map) && 702 number_ = accessor->GetEntryForIndex(js_object, backing_store, index_);
717 !SkipInterceptor(JSObject::cast(holder))) { 703 if (number_ == kMaxUInt32) {
718 return INTERCEPTOR; 704 return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
719 } 705 }
720 // Fall through. 706 property_details_ = accessor->GetDetails(js_object, number_);
721 default: 707 } else if (!map->is_dictionary_map()) {
722 return NOT_FOUND; 708 DescriptorArray* descriptors = map->instance_descriptors();
709 int number = descriptors->SearchWithCache(isolate_, *name_, map);
710 if (number == DescriptorArray::kNotFound) return NotFound(holder);
711 number_ = static_cast<uint32_t>(number);
712 property_details_ = descriptors->GetDetails(number_);
713 } else {
714 NameDictionary* dict = holder->property_dictionary();
715 int number = dict->FindEntry(name_);
716 if (number == NameDictionary::kNotFound) return NotFound(holder);
717 number_ = static_cast<uint32_t>(number);
718 property_details_ = dict->DetailsAt(number_);
723 } 719 }
720 has_property_ = true;
721 switch (property_details_.kind()) {
722 case v8::internal::kData:
723 return DATA;
724 case v8::internal::kAccessor:
725 return ACCESSOR;
726 }
727
724 UNREACHABLE(); 728 UNREACHABLE();
725 return state_; 729 return state_;
726 } 730 }
727 731
728 } // namespace internal 732 } // namespace internal
729 } // namespace v8 733 } // namespace v8
OLDNEW
« no previous file with comments | « src/lookup.h ('k') | src/objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698