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 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, 29 PROTOTYPE_CHAIN = kHidden | 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 : configuration_(ComputeConfiguration(configuration, name)), 50 state_(NOT_FOUND), 51 exotic_index_state_(ExoticIndexState::kUninitialized), 52 interceptor_state_(InterceptorState::kUninitialized), 53 property_details_(PropertyDetails::Empty()), 54 isolate_(name->GetIsolate()), 55 name_(Name::Flatten(name)), 56 // kMaxUInt32 isn't a valid index. 57 index_(kMaxUInt32), 58 receiver_(receiver), 59 holder_(GetRoot(isolate_, receiver)), 60 holder_map_(holder_->map(), isolate_), 61 initial_holder_(holder_), 62 number_(DescriptorArray::kNotFound) { 63 #ifdef DEBUG 64 uint32_t index; // Assert that the name is not an array index. 65 DCHECK(!name->AsArrayIndex(&index)); 66 #endif // DEBUG 67 Next(); 68 } 69 70 LookupIterator(Handle<Object> receiver, Handle<Name> name, 71 Handle<JSReceiver> holder, 72 Configuration configuration = DEFAULT) 73 : configuration_(ComputeConfiguration(configuration, name)), 74 state_(NOT_FOUND), 75 exotic_index_state_(ExoticIndexState::kUninitialized), 76 interceptor_state_(InterceptorState::kUninitialized), 77 property_details_(PropertyDetails::Empty()), 78 isolate_(name->GetIsolate()), 79 name_(Name::Flatten(name)), 80 // kMaxUInt32 isn't a valid index. 81 index_(kMaxUInt32), 82 receiver_(receiver), 83 holder_(holder), 84 holder_map_(holder_->map(), isolate_), 85 initial_holder_(holder_), 86 number_(DescriptorArray::kNotFound) { 87 #ifdef DEBUG 88 uint32_t index; // Assert that the name is not an array index. 89 DCHECK(!name->AsArrayIndex(&index)); 90 #endif // DEBUG 91 Next(); 92 } 93 94 LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index, 95 Configuration configuration = DEFAULT) 96 : configuration_(configuration), 97 state_(NOT_FOUND), 98 exotic_index_state_(ExoticIndexState::kUninitialized), 99 interceptor_state_(InterceptorState::kUninitialized), 100 property_details_(PropertyDetails::Empty()), 101 isolate_(isolate), 102 name_(), 103 index_(index), 104 receiver_(receiver), 105 holder_(GetRoot(isolate, receiver, index)), 106 holder_map_(holder_->map(), isolate_), 107 initial_holder_(holder_), 108 number_(DescriptorArray::kNotFound) { 109 // kMaxUInt32 isn't a valid index. 110 DCHECK_NE(kMaxUInt32, index_); 111 Next(); 112 } 113 114 LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index, 115 Handle<JSReceiver> holder, 116 Configuration configuration = DEFAULT) 117 : configuration_(configuration), 118 state_(NOT_FOUND), 119 exotic_index_state_(ExoticIndexState::kUninitialized), 120 interceptor_state_(InterceptorState::kUninitialized), 121 property_details_(PropertyDetails::Empty()), 122 isolate_(isolate), 123 name_(), 124 index_(index), 125 receiver_(receiver), 126 holder_(holder), 127 holder_map_(holder_->map(), isolate_), 128 initial_holder_(holder_), 129 number_(DescriptorArray::kNotFound) { 130 // kMaxUInt32 isn't a valid index. 131 DCHECK_NE(kMaxUInt32, index_); 132 Next(); 133 } 134 135 static LookupIterator PropertyOrElement( 136 Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 137 Configuration configuration = DEFAULT) { 138 name = Name::Flatten(name); 139 uint32_t index; 140 LookupIterator it = 141 name->AsArrayIndex(&index) 142 ? LookupIterator(isolate, receiver, index, configuration) 143 : LookupIterator(receiver, name, configuration); 144 it.name_ = name; 145 return it; 146 } 147 148 static LookupIterator PropertyOrElement( 149 Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 150 Handle<JSReceiver> holder, Configuration configuration = DEFAULT) { 151 name = Name::Flatten(name); 152 uint32_t index; 153 LookupIterator it = 154 name->AsArrayIndex(&index) 155 ? LookupIterator(isolate, receiver, index, holder, configuration) 156 : LookupIterator(receiver, name, holder, configuration); 157 it.name_ = name; 158 return it; 159 } 160 161 static LookupIterator PropertyOrElement( 162 Isolate* isolate, Handle<Object> receiver, Handle<Object> key, 163 bool* success, Configuration configuration = DEFAULT); 164 165 void Restart() { RestartInternal(InterceptorState::kUninitialized); } 166 167 Isolate* isolate() const { return isolate_; } 168 State state() const { return state_; } 169 170 Handle<Name> name() const { 171 DCHECK(!IsElement()); 172 return name_; 173 } 174 Handle<Name> GetName() { 175 if (name_.is_null()) { 176 DCHECK(IsElement()); 177 name_ = factory()->Uint32ToString(index_); 178 } 179 return name_; 180 } 181 uint32_t index() const { return index_; } 182 183 bool IsElement() const { return index_ != kMaxUInt32; } 184 185 bool IsFound() const { return state_ != NOT_FOUND; } 186 void Next(); 187 void NotFound() { 188 has_property_ = false; 189 state_ = NOT_FOUND; 190 } 191 192 Heap* heap() const { return isolate_->heap(); } 193 Factory* factory() const { return isolate_->factory(); } 194 Handle<Object> GetReceiver() const { return receiver_; } 195 Handle<JSObject> GetStoreTarget() const; 196 bool is_dictionary_holder() const { return holder_map_->is_dictionary_map(); } 197 Handle<Map> transition_map() const { 198 DCHECK_EQ(TRANSITION, state_); 199 return Handle<Map>::cast(transition_); 200 } 201 template <class T> 202 Handle<T> GetHolder() const { 203 DCHECK(IsFound()); 204 return Handle<T>::cast(holder_); 205 } 206 207 bool HolderIsReceiverOrHiddenPrototype() const; 208 209 bool check_prototype_chain() const { 210 return (configuration_ & kPrototypeChain) != 0; 211 } 212 213 /* ACCESS_CHECK */ 214 bool HasAccess() const; 215 216 /* PROPERTY */ 217 void PrepareForDataProperty(Handle<Object> value); 218 void PrepareTransitionToDataProperty(Handle<Object> value, 219 PropertyAttributes attributes, 220 Object::StoreFromKeyed store_mode); 221 bool IsCacheableTransition() { 222 if (state_ != TRANSITION) return false; 223 return transition_->IsPropertyCell() || 224 (!transition_map()->is_dictionary_map() && 225 transition_map()->GetBackPointer()->IsMap()); 226 } 227 void ApplyTransitionToDataProperty(); 228 void ReconfigureDataProperty(Handle<Object> value, 229 PropertyAttributes attributes); 230 void Delete(); 231 void TransitionToAccessorProperty(AccessorComponent component, 232 Handle<Object> accessor, 233 PropertyAttributes attributes); 234 void TransitionToAccessorPair(Handle<Object> pair, 235 PropertyAttributes attributes); 236 PropertyDetails property_details() const { 237 DCHECK(has_property_); 238 return property_details_; 239 } 240 bool IsConfigurable() const { return property_details().IsConfigurable(); } 241 bool IsReadOnly() const { return property_details().IsReadOnly(); } 242 Representation representation() const { 243 return property_details().representation(); 244 } 245 FieldIndex GetFieldIndex() const; 246 Handle<HeapType> GetFieldType() const; 247 int GetAccessorIndex() const; 248 int GetConstantIndex() const; 249 Handle<PropertyCell> GetPropertyCell() const; 250 Handle<Object> GetAccessors() const; 251 inline Handle<InterceptorInfo> GetInterceptor() const { 252 DCHECK_EQ(INTERCEPTOR, state_); 253 return handle(GetInterceptor(JSObject::cast(*holder_)), isolate_); 254 } 255 Handle<Object> GetDataValue() const; 256 void WriteDataValue(Handle<Object> value); 257 void InternalizeName(); 258 void ReloadHolderMap(); 259 260 private: 261 enum class InterceptorState { 262 kUninitialized, 263 kSkipNonMasking, 264 kProcessNonMasking 265 }; 266 267 Handle<Map> GetReceiverMap() const; 268 269 MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map); 270 inline State LookupInHolder(Map* map, JSReceiver* holder); 271 void RestartLookupForNonMaskingInterceptors() { 272 RestartInternal(InterceptorState::kProcessNonMasking); 273 } 274 void RestartInternal(InterceptorState interceptor_state); 275 State LookupNonMaskingInterceptorInHolder(Map* map, JSReceiver* holder); 276 Handle<Object> FetchValue() const; 277 void ReloadPropertyInformation(); 278 inline bool SkipInterceptor(JSObject* holder); 279 bool HasInterceptor(Map* map) const; 280 bool InternalHolderIsReceiverOrHiddenPrototype() const; 281 inline InterceptorInfo* GetInterceptor(JSObject* holder) const { 282 if (IsElement()) return holder->GetIndexedInterceptor(); 283 return holder->GetNamedInterceptor(); 284 } 285 286 bool check_hidden() const { return (configuration_ & kHidden) != 0; } 287 bool check_interceptor() const { 288 return (configuration_ & kInterceptor) != 0; 289 } 290 int descriptor_number() const { 291 DCHECK(has_property_); 292 DCHECK(!holder_map_->is_dictionary_map()); 293 return number_; 294 } 295 int dictionary_entry() const { 296 DCHECK(has_property_); 297 DCHECK(holder_map_->is_dictionary_map()); 298 return number_; 299 } 300 301 static Configuration ComputeConfiguration( 302 Configuration configuration, Handle<Name> name) { 303 if (name->IsPrivate()) { 304 return static_cast<Configuration>(configuration & 305 HIDDEN_SKIP_INTERCEPTOR); 306 } else { 307 return configuration; 308 } 309 } 310 311 static Handle<JSReceiver> GetRootForNonJSReceiver( 312 Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32); 313 inline static Handle<JSReceiver> GetRoot(Isolate* isolate, 314 Handle<Object> receiver, 315 uint32_t index = kMaxUInt32) { 316 if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver); 317 return GetRootForNonJSReceiver(isolate, receiver, index); 318 } 319 320 enum class ExoticIndexState { kUninitialized, kNotExotic, kExotic }; 321 inline bool IsIntegerIndexedExotic(JSReceiver* holder); 322 323 // If configuration_ becomes mutable, update 324 // HolderIsReceiverOrHiddenPrototype. 325 const Configuration configuration_; 326 State state_; 327 bool has_property_; 328 ExoticIndexState exotic_index_state_; 329 InterceptorState interceptor_state_; 330 PropertyDetails property_details_; 331 Isolate* const isolate_; 332 Handle<Name> name_; 333 uint32_t index_; 334 Handle<Object> transition_; 335 const Handle<Object> receiver_; 336 Handle<JSReceiver> holder_; 337 Handle<Map> holder_map_; 338 const Handle<JSReceiver> initial_holder_; 339 uint32_t number_; 340 }; 341 342 343 } // namespace internal 344 } // namespace v8 345 346 #endif // V8_LOOKUP_H_ 347