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 |
3 | // found in the LICENSE file. |
4 | |
5 | #ifndef V8_LOOKUP_INL_H_ |
6 | #define V8_LOOKUP_INL_H_ |
7 | |
8 | #include "src/lookup.h" |
9 | |
10 | #include "src/handles-inl.h" |
11 | #include "src/heap/factory-inl.h" |
12 | #include "src/objects-inl.h" |
13 | #include "src/objects/api-callbacks.h" |
14 | #include "src/objects/name-inl.h" |
15 | #include "src/objects/map-inl.h" |
16 | |
17 | namespace v8 { |
18 | namespace internal { |
19 | |
20 | LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, |
21 | Handle<Name> name, Configuration configuration) |
22 | : LookupIterator(isolate, receiver, name, GetRoot(isolate, receiver), |
23 | configuration) {} |
24 | |
25 | LookupIterator::LookupIterator(Handle<Object> receiver, Handle<Name> name, |
26 | Handle<JSReceiver> holder, |
27 | Configuration configuration) |
28 | : LookupIterator(holder->GetIsolate(), receiver, name, holder, |
29 | configuration) {} |
30 | |
31 | LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, |
32 | Handle<Name> name, Handle<JSReceiver> holder, |
33 | Configuration configuration) |
34 | : configuration_(ComputeConfiguration(configuration, name)), |
35 | interceptor_state_(InterceptorState::kUninitialized), |
36 | property_details_(PropertyDetails::Empty()), |
37 | isolate_(isolate), |
38 | name_(isolate_->factory()->InternalizeName(name)), |
39 | receiver_(receiver), |
40 | initial_holder_(holder), |
41 | // kMaxUInt32 isn't a valid index. |
42 | index_(kMaxUInt32), |
43 | number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) { |
44 | #ifdef DEBUG |
45 | uint32_t index; // Assert that the name is not an array index. |
46 | DCHECK(!name->AsArrayIndex(&index)); |
47 | #endif // DEBUG |
48 | Start<false>(); |
49 | } |
50 | |
51 | LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, |
52 | uint32_t index, Configuration configuration) |
53 | : LookupIterator(isolate, receiver, index, |
54 | GetRoot(isolate, receiver, index), configuration) {} |
55 | |
56 | LookupIterator LookupIterator::PropertyOrElement( |
57 | Isolate* isolate, Handle<Object> receiver, Handle<Name> name, |
58 | Handle<JSReceiver> holder, Configuration configuration) { |
59 | uint32_t index; |
60 | if (name->AsArrayIndex(&index)) { |
61 | LookupIterator it = |
62 | LookupIterator(isolate, receiver, index, holder, configuration); |
63 | it.name_ = name; |
64 | return it; |
65 | } |
66 | return LookupIterator(receiver, name, holder, configuration); |
67 | } |
68 | |
69 | LookupIterator LookupIterator::PropertyOrElement( |
70 | Isolate* isolate, Handle<Object> receiver, Handle<Name> name, |
71 | Configuration configuration) { |
72 | uint32_t index; |
73 | if (name->AsArrayIndex(&index)) { |
74 | LookupIterator it = LookupIterator(isolate, receiver, index, configuration); |
75 | it.name_ = name; |
76 | return it; |
77 | } |
78 | return LookupIterator(isolate, receiver, name, configuration); |
79 | } |
80 | |
81 | Handle<Name> LookupIterator::GetName() { |
82 | if (name_.is_null()) { |
83 | DCHECK(IsElement()); |
84 | name_ = factory()->Uint32ToString(index_); |
85 | } |
86 | return name_; |
87 | } |
88 | |
89 | bool LookupIterator::is_dictionary_holder() const { |
90 | return !holder_->HasFastProperties(); |
91 | } |
92 | |
93 | Handle<Map> LookupIterator::transition_map() const { |
94 | DCHECK_EQ(TRANSITION, state_); |
95 | return Handle<Map>::cast(transition_); |
96 | } |
97 | |
98 | Handle<PropertyCell> LookupIterator::transition_cell() const { |
99 | DCHECK_EQ(TRANSITION, state_); |
100 | return Handle<PropertyCell>::cast(transition_); |
101 | } |
102 | |
103 | template <class T> |
104 | Handle<T> LookupIterator::GetHolder() const { |
105 | DCHECK(IsFound()); |
106 | return Handle<T>::cast(holder_); |
107 | } |
108 | |
109 | bool LookupIterator::ExtendingNonExtensible(Handle<JSReceiver> receiver) { |
110 | DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>())); |
111 | return !receiver->map()->is_extensible() && |
112 | (IsElement() || !name_->IsPrivate()); |
113 | } |
114 | |
115 | bool LookupIterator::IsCacheableTransition() { |
116 | DCHECK_EQ(TRANSITION, state_); |
117 | return transition_->IsPropertyCell() || |
118 | (transition_map()->is_dictionary_map() && |
119 | !GetStoreTarget<JSReceiver>()->HasFastProperties()) || |
120 | transition_map()->GetBackPointer()->IsMap(); |
121 | } |
122 | |
123 | void LookupIterator::UpdateProtector() { |
124 | if (IsElement()) return; |
125 | // This list must be kept in sync with |
126 | // CodeStubAssembler::CheckForAssociatedProtector! |
127 | ReadOnlyRoots roots(heap()); |
128 | if (*name_ == roots.is_concat_spreadable_symbol() || |
129 | *name_ == roots.constructor_string() || *name_ == roots.next_string() || |
130 | *name_ == roots.species_symbol() || *name_ == roots.iterator_symbol() || |
131 | *name_ == roots.resolve_string() || *name_ == roots.then_string()) { |
132 | InternalUpdateProtector(); |
133 | } |
134 | } |
135 | |
136 | int LookupIterator::descriptor_number() const { |
137 | DCHECK(!IsElement()); |
138 | DCHECK(has_property_); |
139 | DCHECK(holder_->HasFastProperties()); |
140 | return number_; |
141 | } |
142 | |
143 | int LookupIterator::dictionary_entry() const { |
144 | DCHECK(!IsElement()); |
145 | DCHECK(has_property_); |
146 | DCHECK(!holder_->HasFastProperties()); |
147 | return number_; |
148 | } |
149 | |
150 | LookupIterator::Configuration LookupIterator::ComputeConfiguration( |
151 | Configuration configuration, Handle<Name> name) { |
152 | return name->IsPrivate() ? OWN_SKIP_INTERCEPTOR : configuration; |
153 | } |
154 | |
155 | Handle<JSReceiver> LookupIterator::GetRoot(Isolate* isolate, |
156 | Handle<Object> receiver, |
157 | uint32_t index) { |
158 | if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver); |
159 | return GetRootForNonJSReceiver(isolate, receiver, index); |
160 | } |
161 | |
162 | template <class T> |
163 | Handle<T> LookupIterator::GetStoreTarget() const { |
164 | DCHECK(receiver_->IsJSReceiver()); |
165 | if (receiver_->IsJSGlobalProxy()) { |
166 | Map map = JSGlobalProxy::cast(*receiver_)->map(); |
167 | if (map->has_hidden_prototype()) { |
168 | return handle(JSGlobalObject::cast(map->prototype()), isolate_); |
169 | } |
170 | } |
171 | return Handle<T>::cast(receiver_); |
172 | } |
173 | |
174 | template <bool is_element> |
175 | InterceptorInfo LookupIterator::GetInterceptor(JSObject holder) { |
176 | return is_element ? holder->GetIndexedInterceptor() |
177 | : holder->GetNamedInterceptor(); |
178 | } |
179 | |
180 | inline Handle<InterceptorInfo> LookupIterator::GetInterceptor() const { |
181 | DCHECK_EQ(INTERCEPTOR, state_); |
182 | InterceptorInfo result = |
183 | IsElement() ? GetInterceptor<true>(JSObject::cast(*holder_)) |
184 | : GetInterceptor<false>(JSObject::cast(*holder_)); |
185 | return handle(result, isolate_); |
186 | } |
187 | |
188 | } // namespace internal |
189 | } // namespace v8 |
190 | |
191 | #endif // V8_LOOKUP_INL_H_ |
192 | |