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/factory.h" 9 #include "src/globals.h" 10 #include "src/isolate.h" 11 #include "src/objects.h" 12 13 namespace v8 { 14 namespace internal { 15 16 class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED { 17 public: 18 enum Configuration { 19 // Configuration bits. 20 kInterceptor = 1 << 0, 21 kPrototypeChain = 1 << 1, 22 23 // Convience combinations of bits. 24 OWN_SKIP_INTERCEPTOR = 0, 25 OWN = kInterceptor, 26 PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain, 27 PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor, 28 DEFAULT = PROTOTYPE_CHAIN 29 }; 30 31 enum State { 32 ACCESS_CHECK, 33 INTEGER_INDEXED_EXOTIC, 34 INTERCEPTOR, 35 JSPROXY, 36 NOT_FOUND, 37 ACCESSOR, 38 DATA, 39 TRANSITION, 40 // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a 41 // PROPERTY lookup. 42 BEFORE_PROPERTY = INTERCEPTOR 43 }; 44 45 LookupIterator(Handle<Object> receiver, Handle<Name> name, 46 Configuration configuration = DEFAULT) 47 : LookupIterator(name->GetIsolate(), receiver, name, configuration) {} 48 49 LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 50 Configuration configuration = DEFAULT) LookupIterator(isolate,receiver,name,GetRoot (isolate,receiver),configuration)51 : LookupIterator(isolate, receiver, name, GetRoot(isolate, receiver), 52 configuration) {} 53 54 LookupIterator(Handle<Object> receiver, Handle<Name> name, 55 Handle<JSReceiver> holder, 56 Configuration configuration = DEFAULT) 57 : LookupIterator(name->GetIsolate(), receiver, name, holder, 58 configuration) {} 59 60 LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 61 Handle<JSReceiver> holder, 62 Configuration configuration = DEFAULT) configuration_(ComputeConfiguration (configuration,name))63 : configuration_(ComputeConfiguration(configuration, name)), 64 interceptor_state_(InterceptorState::kUninitialized), 65 property_details_(PropertyDetails::Empty()), 66 isolate_(isolate), 67 name_(isolate_->factory()->InternalizeName(name)), 68 receiver_(receiver), 69 initial_holder_(holder), 70 // kMaxUInt32 isn't a valid index. 71 index_(kMaxUInt32), 72 number_(DescriptorArray::kNotFound) { 73 #ifdef DEBUG 74 uint32_t index; // Assert that the name is not an array index. 75 DCHECK(!name->AsArrayIndex(&index)); 76 #endif // DEBUG 77 Start<false>(); 78 } 79 80 LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index, 81 Configuration configuration = DEFAULT) LookupIterator(isolate,receiver,index,GetRoot (isolate,receiver,index),configuration)82 : LookupIterator(isolate, receiver, index, 83 GetRoot(isolate, receiver, index), configuration) {} 84 85 LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index, 86 Handle<JSReceiver> holder, 87 Configuration configuration = DEFAULT) configuration_(configuration)88 : configuration_(configuration), 89 interceptor_state_(InterceptorState::kUninitialized), 90 property_details_(PropertyDetails::Empty()), 91 isolate_(isolate), 92 receiver_(receiver), 93 initial_holder_(holder), 94 index_(index), 95 number_(DescriptorArray::kNotFound) { 96 // kMaxUInt32 isn't a valid index. 97 DCHECK_NE(kMaxUInt32, index_); 98 Start<true>(); 99 } 100 101 static LookupIterator PropertyOrElement( 102 Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 103 Configuration configuration = DEFAULT) { 104 uint32_t index; 105 if (name->AsArrayIndex(&index)) { 106 LookupIterator it = 107 LookupIterator(isolate, receiver, index, configuration); 108 it.name_ = name; 109 return it; 110 } 111 return LookupIterator(receiver, name, configuration); 112 } 113 114 static LookupIterator PropertyOrElement( 115 Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 116 Handle<JSReceiver> holder, Configuration configuration = DEFAULT) { 117 uint32_t index; 118 if (name->AsArrayIndex(&index)) { 119 LookupIterator it = 120 LookupIterator(isolate, receiver, index, holder, configuration); 121 it.name_ = name; 122 return it; 123 } 124 return LookupIterator(receiver, name, holder, configuration); 125 } 126 127 static LookupIterator PropertyOrElement( 128 Isolate* isolate, Handle<Object> receiver, Handle<Object> key, 129 bool* success, Configuration configuration = DEFAULT); 130 Restart()131 void Restart() { 132 InterceptorState state = InterceptorState::kUninitialized; 133 IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state); 134 } 135 isolate()136 Isolate* isolate() const { return isolate_; } state()137 State state() const { return state_; } 138 name()139 Handle<Name> name() const { 140 DCHECK(!IsElement()); 141 return name_; 142 } GetName()143 Handle<Name> GetName() { 144 if (name_.is_null()) { 145 DCHECK(IsElement()); 146 name_ = factory()->Uint32ToString(index_); 147 } 148 return name_; 149 } index()150 uint32_t index() const { return index_; } 151 IsElement()152 bool IsElement() const { return index_ != kMaxUInt32; } 153 IsFound()154 bool IsFound() const { return state_ != NOT_FOUND; } 155 void Next(); NotFound()156 void NotFound() { 157 has_property_ = false; 158 state_ = NOT_FOUND; 159 } 160 heap()161 Heap* heap() const { return isolate_->heap(); } factory()162 Factory* factory() const { return isolate_->factory(); } GetReceiver()163 Handle<Object> GetReceiver() const { return receiver_; } 164 GetStoreTarget()165 Handle<JSObject> GetStoreTarget() const { 166 DCHECK(receiver_->IsJSObject()); 167 if (receiver_->IsJSGlobalProxy()) { 168 Map* map = JSGlobalProxy::cast(*receiver_)->map(); 169 if (map->has_hidden_prototype()) { 170 return handle(JSGlobalObject::cast(map->prototype()), isolate_); 171 } 172 } 173 return Handle<JSObject>::cast(receiver_); 174 } 175 is_dictionary_holder()176 bool is_dictionary_holder() const { return !holder_->HasFastProperties(); } transition_map()177 Handle<Map> transition_map() const { 178 DCHECK_EQ(TRANSITION, state_); 179 return Handle<Map>::cast(transition_); 180 } transition_cell()181 Handle<PropertyCell> transition_cell() const { 182 DCHECK_EQ(TRANSITION, state_); 183 return Handle<PropertyCell>::cast(transition_); 184 } 185 template <class T> GetHolder()186 Handle<T> GetHolder() const { 187 DCHECK(IsFound()); 188 return Handle<T>::cast(holder_); 189 } 190 191 bool HolderIsReceiverOrHiddenPrototype() const; 192 check_prototype_chain()193 bool check_prototype_chain() const { 194 return (configuration_ & kPrototypeChain) != 0; 195 } 196 197 /* ACCESS_CHECK */ 198 bool HasAccess() const; 199 200 /* PROPERTY */ ExtendingNonExtensible(Handle<JSObject> receiver)201 bool ExtendingNonExtensible(Handle<JSObject> receiver) { 202 DCHECK(receiver.is_identical_to(GetStoreTarget())); 203 return !receiver->map()->is_extensible() && 204 (IsElement() || !name_->IsPrivate()); 205 } 206 void PrepareForDataProperty(Handle<Object> value); 207 void PrepareTransitionToDataProperty(Handle<JSObject> receiver, 208 Handle<Object> value, 209 PropertyAttributes attributes, 210 Object::StoreFromKeyed store_mode); IsCacheableTransition()211 bool IsCacheableTransition() { 212 DCHECK_EQ(TRANSITION, state_); 213 return transition_->IsPropertyCell() || 214 (!transition_map()->is_dictionary_map() && 215 transition_map()->GetBackPointer()->IsMap()); 216 } 217 void ApplyTransitionToDataProperty(Handle<JSObject> receiver); 218 void ReconfigureDataProperty(Handle<Object> value, 219 PropertyAttributes attributes); 220 void Delete(); 221 void TransitionToAccessorProperty(Handle<Object> getter, 222 Handle<Object> setter, 223 PropertyAttributes attributes); 224 void TransitionToAccessorPair(Handle<Object> pair, 225 PropertyAttributes attributes); property_details()226 PropertyDetails property_details() const { 227 DCHECK(has_property_); 228 return property_details_; 229 } property_attributes()230 PropertyAttributes property_attributes() const { 231 return property_details().attributes(); 232 } IsConfigurable()233 bool IsConfigurable() const { return property_details().IsConfigurable(); } IsReadOnly()234 bool IsReadOnly() const { return property_details().IsReadOnly(); } IsEnumerable()235 bool IsEnumerable() const { return property_details().IsEnumerable(); } representation()236 Representation representation() const { 237 return property_details().representation(); 238 } location()239 PropertyLocation location() const { return property_details().location(); } constness()240 PropertyConstness constness() const { return property_details().constness(); } 241 Handle<Map> GetFieldOwnerMap() const; 242 FieldIndex GetFieldIndex() const; 243 Handle<FieldType> GetFieldType() const; 244 int GetFieldDescriptorIndex() const; 245 int GetAccessorIndex() const; 246 int GetConstantIndex() const; 247 Handle<PropertyCell> GetPropertyCell() const; 248 Handle<Object> GetAccessors() const; GetInterceptor()249 inline Handle<InterceptorInfo> GetInterceptor() const { 250 DCHECK_EQ(INTERCEPTOR, state_); 251 InterceptorInfo* result = 252 IsElement() ? GetInterceptor<true>(JSObject::cast(*holder_)) 253 : GetInterceptor<false>(JSObject::cast(*holder_)); 254 return handle(result, isolate_); 255 } 256 Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const; 257 Handle<Object> GetDataValue() const; 258 void WriteDataValue(Handle<Object> value, bool initializing_store); UpdateProtector()259 inline void UpdateProtector() { 260 if (IsElement()) return; 261 if (*name_ == heap()->is_concat_spreadable_symbol() || 262 *name_ == heap()->constructor_string() || 263 *name_ == heap()->species_symbol() || 264 *name_ == heap()->has_instance_symbol() || 265 *name_ == heap()->iterator_symbol()) { 266 InternalUpdateProtector(); 267 } 268 } 269 270 // Lookup a 'cached' private property for an accessor. 271 // If not found returns false and leaves the LookupIterator unmodified. 272 bool TryLookupCachedProperty(); 273 bool LookupCachedProperty(); 274 275 private: 276 void InternalUpdateProtector(); 277 278 enum class InterceptorState { 279 kUninitialized, 280 kSkipNonMasking, 281 kProcessNonMasking 282 }; 283 284 Handle<Map> GetReceiverMap() const; 285 286 MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map); 287 288 template <bool is_element> 289 V8_EXPORT_PRIVATE void Start(); 290 template <bool is_element> 291 void NextInternal(Map* map, JSReceiver* holder); 292 template <bool is_element> LookupInHolder(Map * map,JSReceiver * holder)293 inline State LookupInHolder(Map* map, JSReceiver* holder) { 294 return map->IsSpecialReceiverMap() 295 ? LookupInSpecialHolder<is_element>(map, holder) 296 : LookupInRegularHolder<is_element>(map, holder); 297 } 298 template <bool is_element> 299 State LookupInRegularHolder(Map* map, JSReceiver* holder); 300 template <bool is_element> 301 State LookupInSpecialHolder(Map* map, JSReceiver* holder); 302 template <bool is_element> RestartLookupForNonMaskingInterceptors()303 void RestartLookupForNonMaskingInterceptors() { 304 RestartInternal<is_element>(InterceptorState::kProcessNonMasking); 305 } 306 template <bool is_element> 307 void RestartInternal(InterceptorState interceptor_state); 308 Handle<Object> FetchValue() const; 309 bool IsConstFieldValueEqualTo(Object* value) const; 310 template <bool is_element> 311 void ReloadPropertyInformation(); 312 313 template <bool is_element> 314 bool SkipInterceptor(JSObject* holder); 315 template <bool is_element> GetInterceptor(JSObject * holder)316 inline InterceptorInfo* GetInterceptor(JSObject* holder) const { 317 return is_element ? holder->GetIndexedInterceptor() 318 : holder->GetNamedInterceptor(); 319 } 320 check_interceptor()321 bool check_interceptor() const { 322 return (configuration_ & kInterceptor) != 0; 323 } descriptor_number()324 int descriptor_number() const { 325 DCHECK(!IsElement()); 326 DCHECK(has_property_); 327 DCHECK(holder_->HasFastProperties()); 328 return number_; 329 } dictionary_entry()330 int dictionary_entry() const { 331 DCHECK(!IsElement()); 332 DCHECK(has_property_); 333 DCHECK(!holder_->HasFastProperties()); 334 return number_; 335 } 336 ComputeConfiguration(Configuration configuration,Handle<Name> name)337 static Configuration ComputeConfiguration( 338 Configuration configuration, Handle<Name> name) { 339 return name->IsPrivate() ? OWN_SKIP_INTERCEPTOR : configuration; 340 } 341 342 static Handle<JSReceiver> GetRootForNonJSReceiver( 343 Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32); 344 inline static Handle<JSReceiver> GetRoot(Isolate* isolate, 345 Handle<Object> receiver, 346 uint32_t index = kMaxUInt32) { 347 if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver); 348 return GetRootForNonJSReceiver(isolate, receiver, index); 349 } 350 351 State NotFound(JSReceiver* const holder) const; 352 353 // If configuration_ becomes mutable, update 354 // HolderIsReceiverOrHiddenPrototype. 355 const Configuration configuration_; 356 State state_; 357 bool has_property_; 358 InterceptorState interceptor_state_; 359 PropertyDetails property_details_; 360 Isolate* const isolate_; 361 Handle<Name> name_; 362 Handle<Object> transition_; 363 const Handle<Object> receiver_; 364 Handle<JSReceiver> holder_; 365 const Handle<JSReceiver> initial_holder_; 366 const uint32_t index_; 367 uint32_t number_; 368 }; 369 370 371 } // namespace internal 372 } // namespace v8 373 374 #endif // V8_LOOKUP_H_ 375