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