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 } 239 FieldIndex GetFieldIndex() const; 240 Handle<FieldType> GetFieldType() const; 241 int GetFieldDescriptorIndex() const; 242 int GetAccessorIndex() const; 243 int GetConstantIndex() const; 244 Handle<PropertyCell> GetPropertyCell() const; 245 Handle<Object> GetAccessors() const; GetInterceptor()246 inline Handle<InterceptorInfo> GetInterceptor() const { 247 DCHECK_EQ(INTERCEPTOR, state_); 248 InterceptorInfo* result = 249 IsElement() ? GetInterceptor<true>(JSObject::cast(*holder_)) 250 : GetInterceptor<false>(JSObject::cast(*holder_)); 251 return handle(result, isolate_); 252 } 253 Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const; 254 Handle<Object> GetDataValue() const; 255 void WriteDataValue(Handle<Object> value); UpdateProtector()256 inline void UpdateProtector() { 257 if (IsElement()) return; 258 if (*name_ == heap()->is_concat_spreadable_symbol() || 259 *name_ == heap()->constructor_string() || 260 *name_ == heap()->species_symbol() || 261 *name_ == heap()->has_instance_symbol() || 262 *name_ == heap()->iterator_symbol()) { 263 InternalUpdateProtector(); 264 } 265 } 266 267 // Lookup a 'cached' private property for an accessor. 268 // If not found returns false and leaves the LookupIterator unmodified. 269 bool TryLookupCachedProperty(); 270 bool LookupCachedProperty(); 271 272 private: 273 void InternalUpdateProtector(); 274 275 enum class InterceptorState { 276 kUninitialized, 277 kSkipNonMasking, 278 kProcessNonMasking 279 }; 280 281 Handle<Map> GetReceiverMap() const; 282 283 MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map); 284 285 template <bool is_element> 286 V8_EXPORT_PRIVATE void Start(); 287 template <bool is_element> 288 void NextInternal(Map* map, JSReceiver* holder); 289 template <bool is_element> LookupInHolder(Map * map,JSReceiver * holder)290 inline State LookupInHolder(Map* map, JSReceiver* holder) { 291 return map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE 292 ? LookupInSpecialHolder<is_element>(map, holder) 293 : LookupInRegularHolder<is_element>(map, holder); 294 } 295 template <bool is_element> 296 State LookupInRegularHolder(Map* map, JSReceiver* holder); 297 template <bool is_element> 298 State LookupInSpecialHolder(Map* map, JSReceiver* holder); 299 template <bool is_element> RestartLookupForNonMaskingInterceptors()300 void RestartLookupForNonMaskingInterceptors() { 301 RestartInternal<is_element>(InterceptorState::kProcessNonMasking); 302 } 303 template <bool is_element> 304 void RestartInternal(InterceptorState interceptor_state); 305 Handle<Object> FetchValue() const; 306 template <bool is_element> 307 void ReloadPropertyInformation(); 308 309 template <bool is_element> 310 bool SkipInterceptor(JSObject* holder); 311 template <bool is_element> GetInterceptor(JSObject * holder)312 inline InterceptorInfo* GetInterceptor(JSObject* holder) const { 313 return is_element ? holder->GetIndexedInterceptor() 314 : holder->GetNamedInterceptor(); 315 } 316 check_interceptor()317 bool check_interceptor() const { 318 return (configuration_ & kInterceptor) != 0; 319 } descriptor_number()320 int descriptor_number() const { 321 DCHECK(!IsElement()); 322 DCHECK(has_property_); 323 DCHECK(holder_->HasFastProperties()); 324 return number_; 325 } dictionary_entry()326 int dictionary_entry() const { 327 DCHECK(!IsElement()); 328 DCHECK(has_property_); 329 DCHECK(!holder_->HasFastProperties()); 330 return number_; 331 } 332 ComputeConfiguration(Configuration configuration,Handle<Name> name)333 static Configuration ComputeConfiguration( 334 Configuration configuration, Handle<Name> name) { 335 return name->IsPrivate() ? OWN_SKIP_INTERCEPTOR : configuration; 336 } 337 338 static Handle<JSReceiver> GetRootForNonJSReceiver( 339 Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32); 340 inline static Handle<JSReceiver> GetRoot(Isolate* isolate, 341 Handle<Object> receiver, 342 uint32_t index = kMaxUInt32) { 343 if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver); 344 return GetRootForNonJSReceiver(isolate, receiver, index); 345 } 346 347 State NotFound(JSReceiver* const holder) const; 348 349 // If configuration_ becomes mutable, update 350 // HolderIsReceiverOrHiddenPrototype. 351 const Configuration configuration_; 352 State state_; 353 bool has_property_; 354 InterceptorState interceptor_state_; 355 PropertyDetails property_details_; 356 Isolate* const isolate_; 357 Handle<Name> name_; 358 Handle<Object> transition_; 359 const Handle<Object> receiver_; 360 Handle<JSReceiver> holder_; 361 const Handle<JSReceiver> initial_holder_; 362 const uint32_t index_; 363 uint32_t number_; 364 }; 365 366 367 } // namespace internal 368 } // namespace v8 369 370 #endif // V8_LOOKUP_H_ 371