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_OBJECTS_LOOKUP_H_ 6 #define V8_OBJECTS_LOOKUP_H_ 7 8 #include "src/common/globals.h" 9 #include "src/execution/isolate.h" 10 #include "src/heap/factory.h" 11 #include "src/objects/descriptor-array.h" 12 #include "src/objects/js-objects.h" 13 #include "src/objects/map.h" 14 #include "src/objects/objects.h" 15 16 namespace v8 { 17 namespace internal { 18 19 class V8_EXPORT_PRIVATE LookupIterator final { 20 public: 21 enum Configuration { 22 // Configuration bits. 23 kInterceptor = 1 << 0, 24 kPrototypeChain = 1 << 1, 25 26 // Convenience combinations of bits. 27 OWN_SKIP_INTERCEPTOR = 0, 28 OWN = kInterceptor, 29 PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain, 30 PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor, 31 DEFAULT = PROTOTYPE_CHAIN 32 }; 33 34 enum State { 35 ACCESS_CHECK, 36 INTEGER_INDEXED_EXOTIC, 37 INTERCEPTOR, 38 JSPROXY, 39 NOT_FOUND, 40 ACCESSOR, 41 DATA, 42 TRANSITION, 43 // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a 44 // PROPERTY lookup. 45 BEFORE_PROPERTY = INTERCEPTOR 46 }; 47 48 class Key { 49 public: 50 inline Key(Isolate* isolate, double index); 51 // {name} might be a string representation of an element index. 52 inline Key(Isolate* isolate, Handle<Name> name); 53 // {valid_key} is a Name or Number. 54 inline Key(Isolate* isolate, Handle<Object> valid_key); 55 // {key} could be anything. 56 Key(Isolate* isolate, Handle<Object> key, bool* success); 57 is_element()58 bool is_element() { return index_ != LookupIterator::kInvalidIndex; } name()59 Handle<Name> name() const { return name_; } index()60 size_t index() const { return index_; } 61 inline Handle<Name> GetName(Isolate* isolate); 62 63 private: 64 Handle<Name> name_; 65 size_t index_; 66 }; 67 68 // {name} is guaranteed to be a property name (and not e.g. "123"). 69 inline LookupIterator(Isolate* isolate, Handle<Object> receiver, 70 Handle<Name> name, 71 Configuration configuration = DEFAULT); 72 inline LookupIterator(Isolate* isolate, Handle<Object> receiver, 73 Handle<Name> name, Handle<Object> lookup_start_object, 74 Configuration configuration = DEFAULT); 75 76 inline LookupIterator(Isolate* isolate, Handle<Object> receiver, size_t index, 77 Configuration configuration = DEFAULT); 78 inline LookupIterator(Isolate* isolate, Handle<Object> receiver, size_t index, 79 Handle<Object> lookup_start_object, 80 Configuration configuration = DEFAULT); 81 82 inline LookupIterator(Isolate* isolate, Handle<Object> receiver, 83 const Key& key, Configuration configuration = DEFAULT); 84 inline LookupIterator(Isolate* isolate, Handle<Object> receiver, 85 const Key& key, Handle<Object> lookup_start_object, 86 Configuration configuration = DEFAULT); 87 Restart()88 void Restart() { 89 InterceptorState state = InterceptorState::kUninitialized; 90 IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state); 91 } 92 isolate()93 Isolate* isolate() const { return isolate_; } state()94 State state() const { return state_; } 95 96 inline Handle<Name> name() const; 97 inline Handle<Name> GetName(); index()98 size_t index() const { return index_; } array_index()99 uint32_t array_index() const { 100 DCHECK_LE(index_, JSArray::kMaxArrayIndex); 101 return static_cast<uint32_t>(index_); 102 } 103 104 // Returns true if this LookupIterator has an index in the range 105 // [0, size_t::max). IsElement()106 bool IsElement() const { return index_ != kInvalidIndex; } 107 // Returns true if this LookupIterator has an index that counts as an 108 // element for the given object (up to kMaxArrayIndex for JSArrays, 109 // any integer for JSTypedArrays). 110 inline bool IsElement(JSReceiver object) const; 111 IsFound()112 bool IsFound() const { return state_ != NOT_FOUND; } 113 void Next(); NotFound()114 void NotFound() { 115 has_property_ = false; 116 state_ = NOT_FOUND; 117 } 118 heap()119 Heap* heap() const { return isolate_->heap(); } factory()120 Factory* factory() const { return isolate_->factory(); } GetReceiver()121 Handle<Object> GetReceiver() const { return receiver_; } 122 123 template <class T> 124 inline Handle<T> GetStoreTarget() const; 125 inline bool is_dictionary_holder() const; 126 inline Handle<Map> transition_map() const; 127 inline Handle<PropertyCell> transition_cell() const; 128 template <class T> 129 inline Handle<T> GetHolder() const; 130 lookup_start_object()131 Handle<Object> lookup_start_object() const { return lookup_start_object_; } 132 133 bool HolderIsReceiver() const; 134 bool HolderIsReceiverOrHiddenPrototype() const; 135 check_prototype_chain()136 bool check_prototype_chain() const { 137 return (configuration_ & kPrototypeChain) != 0; 138 } 139 140 /* ACCESS_CHECK */ 141 bool HasAccess() const; 142 143 /* PROPERTY */ 144 inline bool ExtendingNonExtensible(Handle<JSReceiver> receiver); 145 void PrepareForDataProperty(Handle<Object> value); 146 void PrepareTransitionToDataProperty(Handle<JSReceiver> receiver, 147 Handle<Object> value, 148 PropertyAttributes attributes, 149 StoreOrigin store_origin); 150 inline bool IsCacheableTransition(); 151 void ApplyTransitionToDataProperty(Handle<JSReceiver> receiver); 152 void ReconfigureDataProperty(Handle<Object> value, 153 PropertyAttributes attributes); 154 void Delete(); 155 void TransitionToAccessorProperty(Handle<Object> getter, 156 Handle<Object> setter, 157 PropertyAttributes attributes); 158 void TransitionToAccessorPair(Handle<Object> pair, 159 PropertyAttributes attributes); property_details()160 PropertyDetails property_details() const { 161 DCHECK(has_property_); 162 return property_details_; 163 } property_attributes()164 PropertyAttributes property_attributes() const { 165 return property_details().attributes(); 166 } IsConfigurable()167 bool IsConfigurable() const { return property_details().IsConfigurable(); } IsReadOnly()168 bool IsReadOnly() const { return property_details().IsReadOnly(); } IsEnumerable()169 bool IsEnumerable() const { return property_details().IsEnumerable(); } representation()170 Representation representation() const { 171 return property_details().representation(); 172 } location()173 PropertyLocation location() const { return property_details().location(); } constness()174 PropertyConstness constness() const { return property_details().constness(); } 175 Handle<Map> GetFieldOwnerMap() const; 176 FieldIndex GetFieldIndex() const; 177 Handle<FieldType> GetFieldType() const; 178 int GetFieldDescriptorIndex() const; 179 int GetAccessorIndex() const; 180 Handle<PropertyCell> GetPropertyCell() const; 181 Handle<Object> GetAccessors() const; 182 inline Handle<InterceptorInfo> GetInterceptor() const; 183 Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const; 184 Handle<Object> GetDataValue(AllocationPolicy allocation_policy = 185 AllocationPolicy::kAllocationAllowed) const; 186 void WriteDataValue(Handle<Object> value, bool initializing_store); 187 inline void UpdateProtector(); 188 static inline void UpdateProtector(Isolate* isolate, Handle<Object> receiver, 189 Handle<Name> name); 190 191 // Lookup a 'cached' private property for an accessor. 192 // If not found returns false and leaves the LookupIterator unmodified. 193 bool TryLookupCachedProperty(); 194 bool LookupCachedProperty(); 195 196 private: 197 static const size_t kInvalidIndex = std::numeric_limits<size_t>::max(); 198 199 inline LookupIterator(Isolate* isolate, Handle<Object> receiver, 200 Handle<Name> name, size_t index, 201 Handle<Object> lookup_start_object, 202 Configuration configuration); 203 204 // For |ForTransitionHandler|. 205 LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 206 Handle<Map> transition_map, PropertyDetails details, 207 bool has_property); 208 209 static void InternalUpdateProtector(Isolate* isolate, Handle<Object> receiver, 210 Handle<Name> name); 211 212 enum class InterceptorState { 213 kUninitialized, 214 kSkipNonMasking, 215 kProcessNonMasking 216 }; 217 218 Handle<Map> GetReceiverMap() const; 219 220 V8_WARN_UNUSED_RESULT inline JSReceiver NextHolder(Map map); 221 is_js_array_element(bool is_element)222 bool is_js_array_element(bool is_element) const { 223 return is_element && index_ <= JSArray::kMaxArrayIndex; 224 } 225 template <bool is_element> 226 V8_EXPORT_PRIVATE void Start(); 227 template <bool is_element> 228 void NextInternal(Map map, JSReceiver holder); 229 template <bool is_element> LookupInHolder(Map map,JSReceiver holder)230 inline State LookupInHolder(Map map, JSReceiver holder) { 231 return map.IsSpecialReceiverMap() 232 ? LookupInSpecialHolder<is_element>(map, holder) 233 : LookupInRegularHolder<is_element>(map, holder); 234 } 235 template <bool is_element> 236 State LookupInRegularHolder(Map map, JSReceiver holder); 237 template <bool is_element> 238 State LookupInSpecialHolder(Map map, JSReceiver holder); 239 template <bool is_element> RestartLookupForNonMaskingInterceptors()240 void RestartLookupForNonMaskingInterceptors() { 241 RestartInternal<is_element>(InterceptorState::kProcessNonMasking); 242 } 243 template <bool is_element> 244 void RestartInternal(InterceptorState interceptor_state); 245 Handle<Object> FetchValue(AllocationPolicy allocation_policy = 246 AllocationPolicy::kAllocationAllowed) 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> 254 inline InterceptorInfo GetInterceptor(JSObject holder) const; 255 check_interceptor()256 bool check_interceptor() const { 257 return (configuration_ & kInterceptor) != 0; 258 } 259 inline InternalIndex descriptor_number() const; 260 inline InternalIndex dictionary_entry() const; 261 262 static inline Configuration ComputeConfiguration(Isolate* isolate, 263 Configuration configuration, 264 Handle<Name> name); 265 266 static Handle<JSReceiver> GetRootForNonJSReceiver( 267 Isolate* isolate, Handle<Object> lookup_start_object, 268 size_t index = kInvalidIndex); 269 static inline Handle<JSReceiver> GetRoot(Isolate* isolate, 270 Handle<Object> lookup_start_object, 271 size_t index = kInvalidIndex); 272 273 State NotFound(JSReceiver const holder) const; 274 275 // If configuration_ becomes mutable, update 276 // HolderIsReceiverOrHiddenPrototype. 277 const Configuration configuration_; 278 State state_ = NOT_FOUND; 279 bool has_property_ = false; 280 InterceptorState interceptor_state_ = InterceptorState::kUninitialized; 281 PropertyDetails property_details_ = PropertyDetails::Empty(); 282 Isolate* const isolate_; 283 Handle<Name> name_; 284 Handle<Object> transition_; 285 const Handle<Object> receiver_; 286 Handle<JSReceiver> holder_; 287 const Handle<Object> lookup_start_object_; 288 const size_t index_; 289 InternalIndex number_ = InternalIndex::NotFound(); 290 }; 291 292 } // namespace internal 293 } // namespace v8 294 295 #endif // V8_OBJECTS_LOOKUP_H_ 296