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_H_
6#define V8_LOOKUP_H_
7
8#include "src/globals.h"
9#include "src/heap/factory.h"
10#include "src/isolate.h"
11#include "src/objects.h"
12#include "src/objects/descriptor-array.h"
13#include "src/objects/js-objects.h"
14#include "src/objects/map.h"
15
16namespace v8 {
17namespace internal {
18
19class V8_EXPORT_PRIVATE LookupIterator final {
20 public:
21 enum Configuration {
22 // Configuration bits.
23 kInterceptor = 1 << 0,
24 kPrototypeChain = 1 << 1,
25
26 // Convenience combinations of bits.
27 OWN_SKIP_INTERCEPTOR = 0,
28 OWN = kInterceptor,
29 PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
30 PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor,
31 DEFAULT = PROTOTYPE_CHAIN
32 };
33
34 enum State {
35 ACCESS_CHECK,
36 INTEGER_INDEXED_EXOTIC,
37 INTERCEPTOR,
38 JSPROXY,
39 NOT_FOUND,
40 ACCESSOR,
41 DATA,
42 TRANSITION,
43 // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
44 // PROPERTY lookup.
45 BEFORE_PROPERTY = INTERCEPTOR
46 };
47
48 inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
49 Handle<Name> name,
50 Configuration configuration = DEFAULT);
51
52 inline LookupIterator(Handle<Object> receiver, Handle<Name> name,
53 Handle<JSReceiver> holder,
54 Configuration configuration = DEFAULT);
55
56 inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
57 Handle<Name> name, Handle<JSReceiver> holder,
58 Configuration configuration = DEFAULT);
59
60 inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
61 uint32_t index, Configuration configuration = DEFAULT);
62
63 LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
64 Handle<JSReceiver> holder,
65 Configuration configuration = DEFAULT)
66 : configuration_(configuration),
67 interceptor_state_(InterceptorState::kUninitialized),
68 property_details_(PropertyDetails::Empty()),
69 isolate_(isolate),
70 receiver_(receiver),
71 initial_holder_(holder),
72 index_(index),
73 number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
74 // kMaxUInt32 isn't a valid index.
75 DCHECK_NE(kMaxUInt32, index_);
76 Start<true>();
77 }
78
79 static inline LookupIterator PropertyOrElement(
80 Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
81 Configuration configuration = DEFAULT);
82
83 static inline LookupIterator PropertyOrElement(
84 Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
85 Handle<JSReceiver> holder, Configuration configuration = DEFAULT);
86
87 static LookupIterator PropertyOrElement(
88 Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
89 bool* success, Handle<JSReceiver> holder,
90 Configuration configuration = DEFAULT);
91
92 static LookupIterator PropertyOrElement(
93 Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
94 bool* success, Configuration configuration = DEFAULT);
95
96 static LookupIterator ForTransitionHandler(
97 Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
98 Handle<Object> value, MaybeHandle<Map> maybe_transition_map);
99
100 void Restart() {
101 InterceptorState state = InterceptorState::kUninitialized;
102 IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
103 }
104
105 Isolate* isolate() const { return isolate_; }
106 State state() const { return state_; }
107
108 Handle<Name> name() const {
109 DCHECK(!IsElement());
110 return name_;
111 }
112 inline Handle<Name> GetName();
113 uint32_t index() const { return index_; }
114
115 bool IsElement() const { return index_ != kMaxUInt32; }
116
117 bool IsFound() const { return state_ != NOT_FOUND; }
118 void Next();
119 void NotFound() {
120 has_property_ = false;
121 state_ = NOT_FOUND;
122 }
123
124 Heap* heap() const { return isolate_->heap(); }
125 Factory* factory() const { return isolate_->factory(); }
126 Handle<Object> GetReceiver() const { return receiver_; }
127
128 template <class T>
129 inline Handle<T> GetStoreTarget() const;
130 inline bool is_dictionary_holder() const;
131 inline Handle<Map> transition_map() const;
132 inline Handle<PropertyCell> transition_cell() const;
133 template <class T>
134 inline Handle<T> GetHolder() const;
135
136 bool HolderIsReceiver() const;
137 bool HolderIsReceiverOrHiddenPrototype() const;
138
139 bool check_prototype_chain() const {
140 return (configuration_ & kPrototypeChain) != 0;
141 }
142
143 /* ACCESS_CHECK */
144 bool HasAccess() const;
145
146 /* PROPERTY */
147 inline bool ExtendingNonExtensible(Handle<JSReceiver> receiver);
148 void PrepareForDataProperty(Handle<Object> value);
149 void PrepareTransitionToDataProperty(Handle<JSReceiver> receiver,
150 Handle<Object> value,
151 PropertyAttributes attributes,
152 StoreOrigin store_origin);
153 inline bool IsCacheableTransition();
154 void ApplyTransitionToDataProperty(Handle<JSReceiver> receiver);
155 void ReconfigureDataProperty(Handle<Object> value,
156 PropertyAttributes attributes);
157 void Delete();
158 void TransitionToAccessorProperty(Handle<Object> getter,
159 Handle<Object> setter,
160 PropertyAttributes attributes);
161 void TransitionToAccessorPair(Handle<Object> pair,
162 PropertyAttributes attributes);
163 PropertyDetails property_details() const {
164 DCHECK(has_property_);
165 return property_details_;
166 }
167 PropertyAttributes property_attributes() const {
168 return property_details().attributes();
169 }
170 bool IsConfigurable() const { return property_details().IsConfigurable(); }
171 bool IsReadOnly() const { return property_details().IsReadOnly(); }
172 bool IsEnumerable() const { return property_details().IsEnumerable(); }
173 Representation representation() const {
174 return property_details().representation();
175 }
176 PropertyLocation location() const { return property_details().location(); }
177 PropertyConstness constness() const { return property_details().constness(); }
178 Handle<Map> GetFieldOwnerMap() const;
179 FieldIndex GetFieldIndex() const;
180 Handle<FieldType> GetFieldType() const;
181 int GetFieldDescriptorIndex() const;
182 int GetAccessorIndex() const;
183 int GetConstantIndex() const;
184 Handle<PropertyCell> GetPropertyCell() const;
185 Handle<Object> GetAccessors() const;
186 inline Handle<InterceptorInfo> GetInterceptor() const;
187 Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const;
188 Handle<Object> GetDataValue() const;
189 void WriteDataValue(Handle<Object> value, bool initializing_store);
190 inline void UpdateProtector();
191
192 // Lookup a 'cached' private property for an accessor.
193 // If not found returns false and leaves the LookupIterator unmodified.
194 bool TryLookupCachedProperty();
195 bool LookupCachedProperty();
196
197 private:
198 // For |ForTransitionHandler|.
199 LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
200 Handle<Map> transition_map, PropertyDetails details,
201 bool has_property);
202
203 void InternalUpdateProtector();
204
205 enum class InterceptorState {
206 kUninitialized,
207 kSkipNonMasking,
208 kProcessNonMasking
209 };
210
211 Handle<Map> GetReceiverMap() const;
212
213 V8_WARN_UNUSED_RESULT inline JSReceiver NextHolder(Map map);
214
215 template <bool is_element>
216 V8_EXPORT_PRIVATE void Start();
217 template <bool is_element>
218 void NextInternal(Map map, JSReceiver holder);
219 template <bool is_element>
220 inline State LookupInHolder(Map map, JSReceiver holder) {
221 return map->IsSpecialReceiverMap()
222 ? LookupInSpecialHolder<is_element>(map, holder)
223 : LookupInRegularHolder<is_element>(map, holder);
224 }
225 template <bool is_element>
226 State LookupInRegularHolder(Map map, JSReceiver holder);
227 template <bool is_element>
228 State LookupInSpecialHolder(Map map, JSReceiver holder);
229 template <bool is_element>
230 void RestartLookupForNonMaskingInterceptors() {
231 RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
232 }
233 template <bool is_element>
234 void RestartInternal(InterceptorState interceptor_state);
235 Handle<Object> FetchValue() const;
236 bool IsConstFieldValueEqualTo(Object value) const;
237 template <bool is_element>
238 void ReloadPropertyInformation();
239
240 template <bool is_element>
241 bool SkipInterceptor(JSObject holder);
242 template <bool is_element>
243 static inline InterceptorInfo GetInterceptor(JSObject holder);
244
245 bool check_interceptor() const {
246 return (configuration_ & kInterceptor) != 0;
247 }
248 inline int descriptor_number() const;
249 inline int dictionary_entry() const;
250
251 static inline Configuration ComputeConfiguration(
252 Configuration configuration, Handle<Name> name);
253
254 static Handle<JSReceiver> GetRootForNonJSReceiver(
255 Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32);
256 static inline Handle<JSReceiver> GetRoot(Isolate* isolate,
257 Handle<Object> receiver,
258 uint32_t index = kMaxUInt32);
259
260 State NotFound(JSReceiver const holder) const;
261
262 // If configuration_ becomes mutable, update
263 // HolderIsReceiverOrHiddenPrototype.
264 const Configuration configuration_;
265 State state_;
266 bool has_property_;
267 InterceptorState interceptor_state_;
268 PropertyDetails property_details_;
269 Isolate* const isolate_;
270 Handle<Name> name_;
271 Handle<Object> transition_;
272 const Handle<Object> receiver_;
273 Handle<JSReceiver> holder_;
274 const Handle<JSReceiver> initial_holder_;
275 const uint32_t index_;
276 uint32_t number_;
277};
278
279
280} // namespace internal
281} // namespace v8
282
283#endif // V8_LOOKUP_H_
284