blob: 8005f32eb957667b3ff05ddf95795d5ef0fe4bd1 [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.
19 kHidden = 1 << 0,
20 kInterceptor = 1 << 1,
21 kPrototypeChain = 1 << 2,
22
23 // Convience combinations of bits.
24 OWN_SKIP_INTERCEPTOR = 0,
25 OWN = kInterceptor,
26 HIDDEN_SKIP_INTERCEPTOR = kHidden,
27 HIDDEN = kHidden | kInterceptor,
28 PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kHidden | kPrototypeChain,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000029 PROTOTYPE_CHAIN = kHidden | kPrototypeChain | kInterceptor,
30 DEFAULT = PROTOTYPE_CHAIN
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031 };
32
33 enum State {
34 ACCESS_CHECK,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035 INTEGER_INDEXED_EXOTIC,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036 INTERCEPTOR,
37 JSPROXY,
38 NOT_FOUND,
39 ACCESSOR,
40 DATA,
41 TRANSITION,
42 // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
43 // PROPERTY lookup.
44 BEFORE_PROPERTY = INTERCEPTOR
45 };
46
47 LookupIterator(Handle<Object> receiver, Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000048 Configuration configuration = DEFAULT)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049 : configuration_(ComputeConfiguration(configuration, name)),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000050 interceptor_state_(InterceptorState::kUninitialized),
51 property_details_(PropertyDetails::Empty()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000052 isolate_(name->GetIsolate()),
Ben Murdoch097c5b22016-05-18 11:27:45 +010053 name_(isolate_->factory()->InternalizeName(name)),
Ben Murdochda12d292016-06-02 14:46:10 +010054 receiver_(receiver),
55 initial_holder_(GetRoot(isolate_, receiver)),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000056 // kMaxUInt32 isn't a valid index.
57 index_(kMaxUInt32),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000058 number_(DescriptorArray::kNotFound) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059#ifdef DEBUG
60 uint32_t index; // Assert that the name is not an array index.
61 DCHECK(!name->AsArrayIndex(&index));
62#endif // DEBUG
Ben Murdochda12d292016-06-02 14:46:10 +010063 Start<false>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000064 }
65
66 LookupIterator(Handle<Object> receiver, Handle<Name> name,
67 Handle<JSReceiver> holder,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000068 Configuration configuration = DEFAULT)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000069 : configuration_(ComputeConfiguration(configuration, name)),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070 interceptor_state_(InterceptorState::kUninitialized),
71 property_details_(PropertyDetails::Empty()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000072 isolate_(name->GetIsolate()),
Ben Murdoch097c5b22016-05-18 11:27:45 +010073 name_(isolate_->factory()->InternalizeName(name)),
Ben Murdochda12d292016-06-02 14:46:10 +010074 receiver_(receiver),
75 initial_holder_(holder),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000076 // kMaxUInt32 isn't a valid index.
77 index_(kMaxUInt32),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000078 number_(DescriptorArray::kNotFound) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079#ifdef DEBUG
80 uint32_t index; // Assert that the name is not an array index.
81 DCHECK(!name->AsArrayIndex(&index));
82#endif // DEBUG
Ben Murdochda12d292016-06-02 14:46:10 +010083 Start<false>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084 }
85
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086 LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
87 Configuration configuration = DEFAULT)
88 : configuration_(configuration),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089 interceptor_state_(InterceptorState::kUninitialized),
90 property_details_(PropertyDetails::Empty()),
91 isolate_(isolate),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 receiver_(receiver),
Ben Murdochda12d292016-06-02 14:46:10 +010093 initial_holder_(GetRoot(isolate, receiver, index)),
94 index_(index),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000095 number_(DescriptorArray::kNotFound) {
96 // kMaxUInt32 isn't a valid index.
97 DCHECK_NE(kMaxUInt32, index_);
Ben Murdochda12d292016-06-02 14:46:10 +010098 Start<true>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 }
100
101 LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
102 Handle<JSReceiver> holder,
103 Configuration configuration = DEFAULT)
104 : configuration_(configuration),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105 interceptor_state_(InterceptorState::kUninitialized),
106 property_details_(PropertyDetails::Empty()),
107 isolate_(isolate),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 receiver_(receiver),
Ben Murdochda12d292016-06-02 14:46:10 +0100109 initial_holder_(holder),
110 index_(index),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 number_(DescriptorArray::kNotFound) {
112 // kMaxUInt32 isn't a valid index.
113 DCHECK_NE(kMaxUInt32, index_);
Ben Murdochda12d292016-06-02 14:46:10 +0100114 Start<true>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115 }
116
117 static LookupIterator PropertyOrElement(
118 Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
119 Configuration configuration = DEFAULT) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000120 uint32_t index;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100121 if (name->AsArrayIndex(&index)) {
122 LookupIterator it =
123 LookupIterator(isolate, receiver, index, configuration);
124 it.name_ = name;
125 return it;
126 }
127 return LookupIterator(receiver, name, configuration);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000128 }
129
130 static LookupIterator PropertyOrElement(
131 Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
132 Handle<JSReceiver> holder, Configuration configuration = DEFAULT) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133 uint32_t index;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100134 if (name->AsArrayIndex(&index)) {
135 LookupIterator it =
136 LookupIterator(isolate, receiver, index, holder, configuration);
137 it.name_ = name;
138 return it;
139 }
140 return LookupIterator(receiver, name, holder, configuration);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000141 }
142
143 static LookupIterator PropertyOrElement(
144 Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
145 bool* success, Configuration configuration = DEFAULT);
146
Ben Murdochda12d292016-06-02 14:46:10 +0100147 void Restart() {
148 InterceptorState state = InterceptorState::kUninitialized;
149 IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
150 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152 Isolate* isolate() const { return isolate_; }
153 State state() const { return state_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000154
155 Handle<Name> name() const {
156 DCHECK(!IsElement());
157 return name_;
158 }
159 Handle<Name> GetName() {
160 if (name_.is_null()) {
161 DCHECK(IsElement());
162 name_ = factory()->Uint32ToString(index_);
163 }
164 return name_;
165 }
166 uint32_t index() const { return index_; }
167
168 bool IsElement() const { return index_ != kMaxUInt32; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000169
170 bool IsFound() const { return state_ != NOT_FOUND; }
171 void Next();
172 void NotFound() {
173 has_property_ = false;
174 state_ = NOT_FOUND;
175 }
176
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000177 Heap* heap() const { return isolate_->heap(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000178 Factory* factory() const { return isolate_->factory(); }
179 Handle<Object> GetReceiver() const { return receiver_; }
Ben Murdochda12d292016-06-02 14:46:10 +0100180
181 Handle<JSObject> GetStoreTarget() const {
182 if (receiver_->IsJSGlobalProxy()) {
183 Map* map = JSGlobalProxy::cast(*receiver_)->map();
184 if (map->has_hidden_prototype()) {
185 return handle(JSGlobalObject::cast(map->prototype()), isolate_);
186 }
187 }
188 return Handle<JSObject>::cast(receiver_);
189 }
190
Ben Murdoch097c5b22016-05-18 11:27:45 +0100191 bool is_dictionary_holder() const { return !holder_->HasFastProperties(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192 Handle<Map> transition_map() const {
193 DCHECK_EQ(TRANSITION, state_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000194 return Handle<Map>::cast(transition_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000195 }
196 template <class T>
197 Handle<T> GetHolder() const {
198 DCHECK(IsFound());
199 return Handle<T>::cast(holder_);
200 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000202 bool HolderIsReceiverOrHiddenPrototype() const;
203
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000204 bool check_prototype_chain() const {
205 return (configuration_ & kPrototypeChain) != 0;
206 }
207
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208 /* ACCESS_CHECK */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209 bool HasAccess() const;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000210
211 /* PROPERTY */
Ben Murdoch097c5b22016-05-18 11:27:45 +0100212 bool ExtendingNonExtensible(Handle<JSObject> receiver) {
213 DCHECK(receiver.is_identical_to(GetStoreTarget()));
214 return !receiver->map()->is_extensible() &&
215 (IsElement() || !name_->IsPrivate());
216 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217 void PrepareForDataProperty(Handle<Object> value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100218 void PrepareTransitionToDataProperty(Handle<JSObject> receiver,
219 Handle<Object> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 PropertyAttributes attributes,
221 Object::StoreFromKeyed store_mode);
222 bool IsCacheableTransition() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100223 DCHECK_EQ(TRANSITION, state_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 return transition_->IsPropertyCell() ||
225 (!transition_map()->is_dictionary_map() &&
226 transition_map()->GetBackPointer()->IsMap());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100228 void ApplyTransitionToDataProperty(Handle<JSObject> receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000229 void ReconfigureDataProperty(Handle<Object> value,
230 PropertyAttributes attributes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231 void Delete();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 void TransitionToAccessorProperty(AccessorComponent component,
233 Handle<Object> accessor,
234 PropertyAttributes attributes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000235 void TransitionToAccessorPair(Handle<Object> pair,
236 PropertyAttributes attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000237 PropertyDetails property_details() const {
238 DCHECK(has_property_);
239 return property_details_;
240 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100241 PropertyAttributes property_attributes() const {
242 return property_details().attributes();
243 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 bool IsConfigurable() const { return property_details().IsConfigurable(); }
245 bool IsReadOnly() const { return property_details().IsReadOnly(); }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100246 bool IsEnumerable() const { return property_details().IsEnumerable(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247 Representation representation() const {
248 return property_details().representation();
249 }
250 FieldIndex GetFieldIndex() const;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100251 Handle<FieldType> GetFieldType() const;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000252 int GetAccessorIndex() const;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000253 int GetConstantIndex() const;
254 Handle<PropertyCell> GetPropertyCell() const;
255 Handle<Object> GetAccessors() const;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256 inline Handle<InterceptorInfo> GetInterceptor() const {
257 DCHECK_EQ(INTERCEPTOR, state_);
Ben Murdochda12d292016-06-02 14:46:10 +0100258 InterceptorInfo* result =
259 IsElement() ? GetInterceptor<true>(JSObject::cast(*holder_))
260 : GetInterceptor<false>(JSObject::cast(*holder_));
261 return handle(result, isolate_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000262 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263 Handle<Object> GetDataValue() const;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264 void WriteDataValue(Handle<Object> value);
Ben Murdochda12d292016-06-02 14:46:10 +0100265 inline void UpdateProtector() {
266 if (FLAG_harmony_species && !IsElement() &&
267 (*name_ == heap()->constructor_string() ||
268 *name_ == heap()->species_symbol())) {
269 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
318 bool check_hidden() const { return (configuration_ & kHidden) != 0; }
319 bool check_interceptor() const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000320 return (configuration_ & kInterceptor) != 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000321 }
322 int descriptor_number() const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100323 DCHECK(!IsElement());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000324 DCHECK(has_property_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100325 DCHECK(holder_->HasFastProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000326 return number_;
327 }
328 int dictionary_entry() const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100329 DCHECK(!IsElement());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000330 DCHECK(has_property_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100331 DCHECK(!holder_->HasFastProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332 return number_;
333 }
334
335 static Configuration ComputeConfiguration(
336 Configuration configuration, Handle<Name> name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000337 if (name->IsPrivate()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400338 return static_cast<Configuration>(configuration &
339 HIDDEN_SKIP_INTERCEPTOR);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000340 } else {
341 return configuration;
342 }
343 }
344
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345 static Handle<JSReceiver> GetRootForNonJSReceiver(
346 Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32);
347 inline static Handle<JSReceiver> GetRoot(Isolate* isolate,
348 Handle<Object> receiver,
349 uint32_t index = kMaxUInt32) {
350 if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
351 return GetRootForNonJSReceiver(isolate, receiver, index);
352 }
353
Ben Murdoch097c5b22016-05-18 11:27:45 +0100354 State NotFound(JSReceiver* const holder) const;
355
356 bool HolderIsInContextIndex(uint32_t index) const;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000357
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000358 // If configuration_ becomes mutable, update
359 // HolderIsReceiverOrHiddenPrototype.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000360 const Configuration configuration_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000361 State state_;
362 bool has_property_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000363 InterceptorState interceptor_state_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000364 PropertyDetails property_details_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000365 Isolate* const isolate_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000366 Handle<Name> name_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000367 Handle<Object> transition_;
368 const Handle<Object> receiver_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000369 Handle<JSReceiver> holder_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000370 const Handle<JSReceiver> initial_holder_;
Ben Murdochda12d292016-06-02 14:46:10 +0100371 const uint32_t index_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000372 uint32_t number_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000373};
374
375
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000376} // namespace internal
377} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000378
379#endif // V8_LOOKUP_H_