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