blob: bb65639165ad23324f5cee1668d689c72eb860c8 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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/factory.h"
9#include "src/isolate.h"
10#include "src/objects.h"
11
12namespace v8 {
13namespace internal {
14
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015class LookupIterator final BASE_EMBEDDED {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016 public:
17 enum Configuration {
18 // Configuration bits.
Ben Murdochc5610432016-08-08 18:44:38 +010019 kInterceptor = 1 << 0,
20 kPrototypeChain = 1 << 1,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021
22 // Convience combinations of bits.
23 OWN_SKIP_INTERCEPTOR = 0,
24 OWN = kInterceptor,
Ben Murdochc5610432016-08-08 18:44:38 +010025 PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
26 PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000027 DEFAULT = PROTOTYPE_CHAIN
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028 };
29
30 enum State {
31 ACCESS_CHECK,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000032 INTEGER_INDEXED_EXOTIC,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033 INTERCEPTOR,
34 JSPROXY,
35 NOT_FOUND,
36 ACCESSOR,
37 DATA,
38 TRANSITION,
39 // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
40 // PROPERTY lookup.
41 BEFORE_PROPERTY = INTERCEPTOR
42 };
43
44 LookupIterator(Handle<Object> receiver, Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045 Configuration configuration = DEFAULT)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046 : configuration_(ComputeConfiguration(configuration, name)),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000047 interceptor_state_(InterceptorState::kUninitialized),
48 property_details_(PropertyDetails::Empty()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049 isolate_(name->GetIsolate()),
Ben Murdoch097c5b22016-05-18 11:27:45 +010050 name_(isolate_->factory()->InternalizeName(name)),
Ben Murdochda12d292016-06-02 14:46:10 +010051 receiver_(receiver),
52 initial_holder_(GetRoot(isolate_, receiver)),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000053 // kMaxUInt32 isn't a valid index.
54 index_(kMaxUInt32),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000055 number_(DescriptorArray::kNotFound) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000056#ifdef DEBUG
57 uint32_t index; // Assert that the name is not an array index.
58 DCHECK(!name->AsArrayIndex(&index));
59#endif // DEBUG
Ben Murdochda12d292016-06-02 14:46:10 +010060 Start<false>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000061 }
62
63 LookupIterator(Handle<Object> receiver, Handle<Name> name,
64 Handle<JSReceiver> holder,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 Configuration configuration = DEFAULT)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000066 : configuration_(ComputeConfiguration(configuration, name)),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067 interceptor_state_(InterceptorState::kUninitialized),
68 property_details_(PropertyDetails::Empty()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000069 isolate_(name->GetIsolate()),
Ben Murdoch097c5b22016-05-18 11:27:45 +010070 name_(isolate_->factory()->InternalizeName(name)),
Ben Murdochda12d292016-06-02 14:46:10 +010071 receiver_(receiver),
72 initial_holder_(holder),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000073 // kMaxUInt32 isn't a valid index.
74 index_(kMaxUInt32),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 number_(DescriptorArray::kNotFound) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000076#ifdef DEBUG
77 uint32_t index; // Assert that the name is not an array index.
78 DCHECK(!name->AsArrayIndex(&index));
79#endif // DEBUG
Ben Murdochda12d292016-06-02 14:46:10 +010080 Start<false>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081 }
82
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083 LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
84 Configuration configuration = DEFAULT)
85 : configuration_(configuration),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086 interceptor_state_(InterceptorState::kUninitialized),
87 property_details_(PropertyDetails::Empty()),
88 isolate_(isolate),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089 receiver_(receiver),
Ben Murdochda12d292016-06-02 14:46:10 +010090 initial_holder_(GetRoot(isolate, receiver, index)),
91 index_(index),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 number_(DescriptorArray::kNotFound) {
93 // kMaxUInt32 isn't a valid index.
94 DCHECK_NE(kMaxUInt32, index_);
Ben Murdochda12d292016-06-02 14:46:10 +010095 Start<true>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096 }
97
98 LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
99 Handle<JSReceiver> holder,
100 Configuration configuration = DEFAULT)
101 : configuration_(configuration),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000102 interceptor_state_(InterceptorState::kUninitialized),
103 property_details_(PropertyDetails::Empty()),
104 isolate_(isolate),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105 receiver_(receiver),
Ben Murdochda12d292016-06-02 14:46:10 +0100106 initial_holder_(holder),
107 index_(index),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 number_(DescriptorArray::kNotFound) {
109 // kMaxUInt32 isn't a valid index.
110 DCHECK_NE(kMaxUInt32, index_);
Ben Murdochda12d292016-06-02 14:46:10 +0100111 Start<true>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 }
113
114 static LookupIterator PropertyOrElement(
115 Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
116 Configuration configuration = DEFAULT) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000117 uint32_t index;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100118 if (name->AsArrayIndex(&index)) {
119 LookupIterator it =
120 LookupIterator(isolate, receiver, index, configuration);
121 it.name_ = name;
122 return it;
123 }
124 return LookupIterator(receiver, name, configuration);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 }
126
127 static LookupIterator PropertyOrElement(
128 Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
129 Handle<JSReceiver> holder, Configuration configuration = DEFAULT) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000130 uint32_t index;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100131 if (name->AsArrayIndex(&index)) {
132 LookupIterator it =
133 LookupIterator(isolate, receiver, index, holder, configuration);
134 it.name_ = name;
135 return it;
136 }
137 return LookupIterator(receiver, name, holder, configuration);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138 }
139
140 static LookupIterator PropertyOrElement(
141 Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
142 bool* success, Configuration configuration = DEFAULT);
143
Ben Murdochda12d292016-06-02 14:46:10 +0100144 void Restart() {
145 InterceptorState state = InterceptorState::kUninitialized;
146 IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
147 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000149 Isolate* isolate() const { return isolate_; }
150 State state() const { return state_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151
152 Handle<Name> name() const {
153 DCHECK(!IsElement());
154 return name_;
155 }
156 Handle<Name> GetName() {
157 if (name_.is_null()) {
158 DCHECK(IsElement());
159 name_ = factory()->Uint32ToString(index_);
160 }
161 return name_;
162 }
163 uint32_t index() const { return index_; }
164
165 bool IsElement() const { return index_ != kMaxUInt32; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000166
167 bool IsFound() const { return state_ != NOT_FOUND; }
168 void Next();
169 void NotFound() {
170 has_property_ = false;
171 state_ = NOT_FOUND;
172 }
173
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000174 Heap* heap() const { return isolate_->heap(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000175 Factory* factory() const { return isolate_->factory(); }
176 Handle<Object> GetReceiver() const { return receiver_; }
Ben Murdochda12d292016-06-02 14:46:10 +0100177
178 Handle<JSObject> GetStoreTarget() const {
179 if (receiver_->IsJSGlobalProxy()) {
180 Map* map = JSGlobalProxy::cast(*receiver_)->map();
181 if (map->has_hidden_prototype()) {
182 return handle(JSGlobalObject::cast(map->prototype()), isolate_);
183 }
184 }
185 return Handle<JSObject>::cast(receiver_);
186 }
187
Ben Murdoch097c5b22016-05-18 11:27:45 +0100188 bool is_dictionary_holder() const { return !holder_->HasFastProperties(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189 Handle<Map> transition_map() const {
190 DCHECK_EQ(TRANSITION, state_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000191 return Handle<Map>::cast(transition_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192 }
193 template <class T>
194 Handle<T> GetHolder() const {
195 DCHECK(IsFound());
196 return Handle<T>::cast(holder_);
197 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000198
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000199 bool HolderIsReceiverOrHiddenPrototype() const;
200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 bool check_prototype_chain() const {
202 return (configuration_ & kPrototypeChain) != 0;
203 }
204
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000205 /* ACCESS_CHECK */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000206 bool HasAccess() const;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000207
208 /* PROPERTY */
Ben Murdoch097c5b22016-05-18 11:27:45 +0100209 bool ExtendingNonExtensible(Handle<JSObject> receiver) {
210 DCHECK(receiver.is_identical_to(GetStoreTarget()));
211 return !receiver->map()->is_extensible() &&
212 (IsElement() || !name_->IsPrivate());
213 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 void PrepareForDataProperty(Handle<Object> value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100215 void PrepareTransitionToDataProperty(Handle<JSObject> receiver,
216 Handle<Object> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217 PropertyAttributes attributes,
218 Object::StoreFromKeyed store_mode);
219 bool IsCacheableTransition() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100220 DCHECK_EQ(TRANSITION, state_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 return transition_->IsPropertyCell() ||
222 (!transition_map()->is_dictionary_map() &&
223 transition_map()->GetBackPointer()->IsMap());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000224 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100225 void ApplyTransitionToDataProperty(Handle<JSObject> receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000226 void ReconfigureDataProperty(Handle<Object> value,
227 PropertyAttributes attributes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228 void Delete();
Ben Murdochc5610432016-08-08 18:44:38 +0100229 void TransitionToAccessorProperty(Handle<Object> getter,
230 Handle<Object> setter,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231 PropertyAttributes attributes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 void TransitionToAccessorPair(Handle<Object> pair,
233 PropertyAttributes attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234 PropertyDetails property_details() const {
235 DCHECK(has_property_);
236 return property_details_;
237 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100238 PropertyAttributes property_attributes() const {
239 return property_details().attributes();
240 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241 bool IsConfigurable() const { return property_details().IsConfigurable(); }
242 bool IsReadOnly() const { return property_details().IsReadOnly(); }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100243 bool IsEnumerable() const { return property_details().IsEnumerable(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 Representation representation() const {
245 return property_details().representation();
246 }
247 FieldIndex GetFieldIndex() const;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100248 Handle<FieldType> GetFieldType() const;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249 int GetAccessorIndex() const;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000250 int GetConstantIndex() const;
251 Handle<PropertyCell> GetPropertyCell() const;
252 Handle<Object> GetAccessors() const;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253 inline Handle<InterceptorInfo> GetInterceptor() const {
254 DCHECK_EQ(INTERCEPTOR, state_);
Ben Murdochda12d292016-06-02 14:46:10 +0100255 InterceptorInfo* result =
256 IsElement() ? GetInterceptor<true>(JSObject::cast(*holder_))
257 : GetInterceptor<false>(JSObject::cast(*holder_));
258 return handle(result, isolate_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000260 Handle<Object> GetDataValue() const;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261 void WriteDataValue(Handle<Object> value);
Ben Murdochda12d292016-06-02 14:46:10 +0100262 inline void UpdateProtector() {
Ben Murdochc5610432016-08-08 18:44:38 +0100263 if (IsElement()) return;
264 if (*name_ == heap()->is_concat_spreadable_symbol() ||
265 (FLAG_harmony_species && (*name_ == heap()->constructor_string() ||
266 *name_ == heap()->species_symbol())) ||
267 (FLAG_harmony_instanceof &&
268 (*name_ == heap()->has_instance_symbol()))) {
Ben Murdochda12d292016-06-02 14:46:10 +0100269 InternalUpdateProtector();
270 }
271 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000272
273 private:
Ben Murdochda12d292016-06-02 14:46:10 +0100274 void InternalUpdateProtector();
275
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276 enum class InterceptorState {
277 kUninitialized,
278 kSkipNonMasking,
279 kProcessNonMasking
280 };
281
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282 Handle<Map> GetReceiverMap() const;
283
284 MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
Ben Murdochda12d292016-06-02 14:46:10 +0100285
286 template <bool is_element>
287 void Start();
288 template <bool is_element>
289 void NextInternal(Map* map, JSReceiver* holder);
290 template <bool is_element>
291 inline State LookupInHolder(Map* map, JSReceiver* holder) {
292 return map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE
293 ? LookupInSpecialHolder<is_element>(map, holder)
294 : LookupInRegularHolder<is_element>(map, holder);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295 }
Ben Murdochda12d292016-06-02 14:46:10 +0100296 template <bool is_element>
297 State LookupInRegularHolder(Map* map, JSReceiver* holder);
298 template <bool is_element>
299 State LookupInSpecialHolder(Map* map, JSReceiver* holder);
300 template <bool is_element>
301 void RestartLookupForNonMaskingInterceptors() {
302 RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
303 }
304 template <bool is_element>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000305 void RestartInternal(InterceptorState interceptor_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 Handle<Object> FetchValue() const;
Ben Murdochda12d292016-06-02 14:46:10 +0100307 template <bool is_element>
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000308 void ReloadPropertyInformation();
Ben Murdochda12d292016-06-02 14:46:10 +0100309
310 template <bool is_element>
311 bool SkipInterceptor(JSObject* holder);
312 template <bool is_element>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000313 inline InterceptorInfo* GetInterceptor(JSObject* holder) const {
Ben Murdochda12d292016-06-02 14:46:10 +0100314 return is_element ? holder->GetIndexedInterceptor()
315 : holder->GetNamedInterceptor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000317
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000318 bool check_interceptor() const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 return (configuration_ & kInterceptor) != 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320 }
321 int descriptor_number() const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100322 DCHECK(!IsElement());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000323 DCHECK(has_property_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100324 DCHECK(holder_->HasFastProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325 return number_;
326 }
327 int dictionary_entry() const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100328 DCHECK(!IsElement());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000329 DCHECK(has_property_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100330 DCHECK(!holder_->HasFastProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000331 return number_;
332 }
333
334 static Configuration ComputeConfiguration(
335 Configuration configuration, Handle<Name> name) {
Ben Murdochc5610432016-08-08 18:44:38 +0100336 return name->IsPrivate() ? OWN_SKIP_INTERCEPTOR : configuration;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337 }
338
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000339 static Handle<JSReceiver> GetRootForNonJSReceiver(
340 Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32);
341 inline static Handle<JSReceiver> GetRoot(Isolate* isolate,
342 Handle<Object> receiver,
343 uint32_t index = kMaxUInt32) {
344 if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
345 return GetRootForNonJSReceiver(isolate, receiver, index);
346 }
347
Ben Murdoch097c5b22016-05-18 11:27:45 +0100348 State NotFound(JSReceiver* const holder) const;
349
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000350 // If configuration_ becomes mutable, update
351 // HolderIsReceiverOrHiddenPrototype.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000352 const Configuration configuration_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000353 State state_;
354 bool has_property_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000355 InterceptorState interceptor_state_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000356 PropertyDetails property_details_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000357 Isolate* const isolate_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000358 Handle<Name> name_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000359 Handle<Object> transition_;
360 const Handle<Object> receiver_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000361 Handle<JSReceiver> holder_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 const Handle<JSReceiver> initial_holder_;
Ben Murdochda12d292016-06-02 14:46:10 +0100363 const uint32_t index_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000364 uint32_t number_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000365};
366
367
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368} // namespace internal
369} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000370
371#endif // V8_LOOKUP_H_