OLD | NEW |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |