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(Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 48 Configuration configuration = DEFAULT) LookupIterator(isolate,receiver,name,GetRoot (isolate,receiver),configuration)49 : LookupIterator(isolate, receiver, name, GetRoot(isolate, receiver), 50 configuration) {} 51 52 inline LookupIterator(Handle<Object> receiver, Handle<Name> name, 53 Handle<JSReceiver> holder, 54 Configuration configuration = DEFAULT); 55 56 inline LookupIterator(Isolate* isolate, Handle<Object> receiver, 57 Handle<Name> name, Handle<JSReceiver> holder, 58 Configuration configuration = DEFAULT); 59 60 LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index, 61 Configuration configuration = DEFAULT) LookupIterator(isolate,receiver,index,GetRoot (isolate,receiver,index),configuration)62 : LookupIterator(isolate, receiver, index, 63 GetRoot(isolate, receiver, index), configuration) {} 64 65 LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index, 66 Handle<JSReceiver> holder, 67 Configuration configuration = DEFAULT) configuration_(configuration)68 : configuration_(configuration), 69 interceptor_state_(InterceptorState::kUninitialized), 70 property_details_(PropertyDetails::Empty()), 71 isolate_(isolate), 72 receiver_(receiver), 73 initial_holder_(holder), 74 index_(index), 75 number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) { 76 // kMaxUInt32 isn't a valid index. 77 DCHECK_NE(kMaxUInt32, index_); 78 Start<true>(); 79 } 80 81 static inline LookupIterator PropertyOrElement( 82 Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 83 Configuration configuration = DEFAULT); 84 85 static inline LookupIterator PropertyOrElement( 86 Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 87 Handle<JSReceiver> holder, Configuration configuration = DEFAULT); 88 89 static LookupIterator PropertyOrElement( 90 Isolate* isolate, Handle<Object> receiver, Handle<Object> key, 91 bool* success, Handle<JSReceiver> holder, 92 Configuration configuration = DEFAULT); 93 94 static LookupIterator PropertyOrElement( 95 Isolate* isolate, Handle<Object> receiver, Handle<Object> key, 96 bool* success, Configuration configuration = DEFAULT); 97 98 static LookupIterator ForTransitionHandler( 99 Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 100 Handle<Object> value, MaybeHandle<Map> maybe_transition_map); 101 Restart()102 void Restart() { 103 InterceptorState state = InterceptorState::kUninitialized; 104 IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state); 105 } 106 isolate()107 Isolate* isolate() const { return isolate_; } state()108 State state() const { return state_; } 109 name()110 Handle<Name> name() const { 111 DCHECK(!IsElement()); 112 return name_; 113 } 114 inline Handle<Name> GetName(); index()115 uint32_t index() const { return index_; } 116 IsElement()117 bool IsElement() const { return index_ != kMaxUInt32; } 118 IsFound()119 bool IsFound() const { return state_ != NOT_FOUND; } 120 void Next(); NotFound()121 void NotFound() { 122 has_property_ = false; 123 state_ = NOT_FOUND; 124 } 125 heap()126 Heap* heap() const { return isolate_->heap(); } factory()127 Factory* factory() const { return isolate_->factory(); } GetReceiver()128 Handle<Object> GetReceiver() const { return receiver_; } 129 130 template <class T> 131 inline Handle<T> GetStoreTarget() const; 132 inline bool is_dictionary_holder() const; transition_map()133 Handle<Map> transition_map() const { 134 DCHECK_EQ(TRANSITION, state_); 135 return Handle<Map>::cast(transition_); 136 } transition_cell()137 Handle<PropertyCell> transition_cell() const { 138 DCHECK_EQ(TRANSITION, state_); 139 return Handle<PropertyCell>::cast(transition_); 140 } 141 template <class T> GetHolder()142 Handle<T> GetHolder() const { 143 DCHECK(IsFound()); 144 return Handle<T>::cast(holder_); 145 } 146 147 bool HolderIsReceiver() const; 148 bool HolderIsReceiverOrHiddenPrototype() const; 149 check_prototype_chain()150 bool check_prototype_chain() const { 151 return (configuration_ & kPrototypeChain) != 0; 152 } 153 154 /* ACCESS_CHECK */ 155 bool HasAccess() const; 156 157 /* PROPERTY */ 158 inline bool ExtendingNonExtensible(Handle<JSReceiver> receiver); 159 void PrepareForDataProperty(Handle<Object> value); 160 void PrepareTransitionToDataProperty(Handle<JSReceiver> receiver, 161 Handle<Object> value, 162 PropertyAttributes attributes, 163 Object::StoreFromKeyed store_mode); 164 inline bool IsCacheableTransition(); 165 void ApplyTransitionToDataProperty(Handle<JSReceiver> receiver); 166 void ReconfigureDataProperty(Handle<Object> value, 167 PropertyAttributes attributes); 168 void Delete(); 169 void TransitionToAccessorProperty(Handle<Object> getter, 170 Handle<Object> setter, 171 PropertyAttributes attributes); 172 void TransitionToAccessorPair(Handle<Object> pair, 173 PropertyAttributes attributes); property_details()174 PropertyDetails property_details() const { 175 DCHECK(has_property_); 176 return property_details_; 177 } property_attributes()178 PropertyAttributes property_attributes() const { 179 return property_details().attributes(); 180 } IsConfigurable()181 bool IsConfigurable() const { return property_details().IsConfigurable(); } IsReadOnly()182 bool IsReadOnly() const { return property_details().IsReadOnly(); } IsEnumerable()183 bool IsEnumerable() const { return property_details().IsEnumerable(); } representation()184 Representation representation() const { 185 return property_details().representation(); 186 } location()187 PropertyLocation location() const { return property_details().location(); } constness()188 PropertyConstness constness() const { return property_details().constness(); } 189 Handle<Map> GetFieldOwnerMap() const; 190 FieldIndex GetFieldIndex() const; 191 Handle<FieldType> GetFieldType() const; 192 int GetFieldDescriptorIndex() const; 193 int GetAccessorIndex() const; 194 int GetConstantIndex() const; 195 Handle<PropertyCell> GetPropertyCell() const; 196 Handle<Object> GetAccessors() const; 197 inline Handle<InterceptorInfo> GetInterceptor() const; 198 Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const; 199 Handle<Object> GetDataValue() const; 200 void WriteDataValue(Handle<Object> value, bool initializing_store); 201 inline void UpdateProtector(); 202 203 // Lookup a 'cached' private property for an accessor. 204 // If not found returns false and leaves the LookupIterator unmodified. 205 bool TryLookupCachedProperty(); 206 bool LookupCachedProperty(); 207 208 private: 209 // For |ForTransitionHandler|. 210 LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 211 Handle<Map> transition_map, PropertyDetails details, 212 bool has_property); 213 214 void InternalUpdateProtector(); 215 216 enum class InterceptorState { 217 kUninitialized, 218 kSkipNonMasking, 219 kProcessNonMasking 220 }; 221 222 Handle<Map> GetReceiverMap() const; 223 224 V8_WARN_UNUSED_RESULT inline JSReceiver* NextHolder(Map* map); 225 226 template <bool is_element> 227 V8_EXPORT_PRIVATE void Start(); 228 template <bool is_element> 229 void NextInternal(Map* map, JSReceiver* holder); 230 template <bool is_element> LookupInHolder(Map * map,JSReceiver * holder)231 inline State LookupInHolder(Map* map, JSReceiver* holder) { 232 return map->IsSpecialReceiverMap() 233 ? LookupInSpecialHolder<is_element>(map, holder) 234 : LookupInRegularHolder<is_element>(map, holder); 235 } 236 template <bool is_element> 237 State LookupInRegularHolder(Map* map, JSReceiver* holder); 238 template <bool is_element> 239 State LookupInSpecialHolder(Map* map, JSReceiver* holder); 240 template <bool is_element> RestartLookupForNonMaskingInterceptors()241 void RestartLookupForNonMaskingInterceptors() { 242 RestartInternal<is_element>(InterceptorState::kProcessNonMasking); 243 } 244 template <bool is_element> 245 void RestartInternal(InterceptorState interceptor_state); 246 Handle<Object> FetchValue() const; 247 bool IsConstFieldValueEqualTo(Object* value) const; 248 template <bool is_element> 249 void ReloadPropertyInformation(); 250 251 template <bool is_element> 252 bool SkipInterceptor(JSObject* holder); 253 template <bool is_element> GetInterceptor(JSObject * holder)254 inline InterceptorInfo* GetInterceptor(JSObject* holder) const { 255 return is_element ? holder->GetIndexedInterceptor() 256 : holder->GetNamedInterceptor(); 257 } 258 check_interceptor()259 bool check_interceptor() const { 260 return (configuration_ & kInterceptor) != 0; 261 } descriptor_number()262 int descriptor_number() const { 263 DCHECK(!IsElement()); 264 DCHECK(has_property_); 265 DCHECK(holder_->HasFastProperties()); 266 return number_; 267 } dictionary_entry()268 int dictionary_entry() const { 269 DCHECK(!IsElement()); 270 DCHECK(has_property_); 271 DCHECK(!holder_->HasFastProperties()); 272 return number_; 273 } 274 275 static inline Configuration ComputeConfiguration( 276 Configuration configuration, Handle<Name> name); 277 278 static Handle<JSReceiver> GetRootForNonJSReceiver( 279 Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32); 280 static inline Handle<JSReceiver> GetRoot(Isolate* isolate, 281 Handle<Object> receiver, 282 uint32_t index = kMaxUInt32); 283 284 State NotFound(JSReceiver* const holder) const; 285 286 // If configuration_ becomes mutable, update 287 // HolderIsReceiverOrHiddenPrototype. 288 const Configuration configuration_; 289 State state_; 290 bool has_property_; 291 InterceptorState interceptor_state_; 292 PropertyDetails property_details_; 293 Isolate* const isolate_; 294 Handle<Name> name_; 295 Handle<Object> transition_; 296 const Handle<Object> receiver_; 297 Handle<JSReceiver> holder_; 298 const Handle<JSReceiver> initial_holder_; 299 const uint32_t index_; 300 uint32_t number_; 301 }; 302 303 304 } // namespace internal 305 } // namespace v8 306 307 #endif // V8_LOOKUP_H_ 308