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<JSReceiver> holder, 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<JSReceiver> holder, 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<JSReceiver> holder, 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 131 bool HolderIsReceiver() const; 132 bool HolderIsReceiverOrHiddenPrototype() const; 133 check_prototype_chain()134 bool check_prototype_chain() const { 135 return (configuration_ & kPrototypeChain) != 0; 136 } 137 138 /* ACCESS_CHECK */ 139 bool HasAccess() const; 140 141 /* PROPERTY */ 142 inline bool ExtendingNonExtensible(Handle<JSReceiver> receiver); 143 void PrepareForDataProperty(Handle<Object> value); 144 void PrepareTransitionToDataProperty(Handle<JSReceiver> receiver, 145 Handle<Object> value, 146 PropertyAttributes attributes, 147 StoreOrigin store_origin); 148 inline bool IsCacheableTransition(); 149 void ApplyTransitionToDataProperty(Handle<JSReceiver> receiver); 150 void ReconfigureDataProperty(Handle<Object> value, 151 PropertyAttributes attributes); 152 void Delete(); 153 void TransitionToAccessorProperty(Handle<Object> getter, 154 Handle<Object> setter, 155 PropertyAttributes attributes); 156 void TransitionToAccessorPair(Handle<Object> pair, 157 PropertyAttributes attributes); property_details()158 PropertyDetails property_details() const { 159 DCHECK(has_property_); 160 return property_details_; 161 } property_attributes()162 PropertyAttributes property_attributes() const { 163 return property_details().attributes(); 164 } IsConfigurable()165 bool IsConfigurable() const { return property_details().IsConfigurable(); } IsReadOnly()166 bool IsReadOnly() const { return property_details().IsReadOnly(); } IsEnumerable()167 bool IsEnumerable() const { return property_details().IsEnumerable(); } representation()168 Representation representation() const { 169 return property_details().representation(); 170 } location()171 PropertyLocation location() const { return property_details().location(); } constness()172 PropertyConstness constness() const { return property_details().constness(); } 173 Handle<Map> GetFieldOwnerMap() const; 174 FieldIndex GetFieldIndex() const; 175 Handle<FieldType> GetFieldType() const; 176 int GetFieldDescriptorIndex() const; 177 int GetAccessorIndex() const; 178 Handle<PropertyCell> GetPropertyCell() const; 179 Handle<Object> GetAccessors() const; 180 inline Handle<InterceptorInfo> GetInterceptor() const; 181 Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const; 182 Handle<Object> GetDataValue(AllocationPolicy allocation_policy = 183 AllocationPolicy::kAllocationAllowed) const; 184 void WriteDataValue(Handle<Object> value, bool initializing_store); 185 inline void UpdateProtector(); 186 static inline void UpdateProtector(Isolate* isolate, Handle<Object> receiver, 187 Handle<Name> name); 188 189 // Lookup a 'cached' private property for an accessor. 190 // If not found returns false and leaves the LookupIterator unmodified. 191 bool TryLookupCachedProperty(); 192 bool LookupCachedProperty(); 193 194 private: 195 static const size_t kInvalidIndex = std::numeric_limits<size_t>::max(); 196 197 inline LookupIterator(Isolate* isolate, Handle<Object> receiver, 198 Handle<Name> name, size_t index, 199 Handle<JSReceiver> holder, Configuration configuration); 200 201 // For |ForTransitionHandler|. 202 LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name, 203 Handle<Map> transition_map, PropertyDetails details, 204 bool has_property); 205 206 static void InternalUpdateProtector(Isolate* isolate, Handle<Object> receiver, 207 Handle<Name> name); 208 209 enum class InterceptorState { 210 kUninitialized, 211 kSkipNonMasking, 212 kProcessNonMasking 213 }; 214 215 Handle<Map> GetReceiverMap() const; 216 217 V8_WARN_UNUSED_RESULT inline JSReceiver NextHolder(Map map); 218 is_js_array_element(bool is_element)219 bool is_js_array_element(bool is_element) const { 220 return is_element && index_ <= JSArray::kMaxArrayIndex; 221 } 222 template <bool is_element> 223 V8_EXPORT_PRIVATE void Start(); 224 template <bool is_element> 225 void NextInternal(Map map, JSReceiver holder); 226 template <bool is_element> LookupInHolder(Map map,JSReceiver holder)227 inline State LookupInHolder(Map map, JSReceiver holder) { 228 return map.IsSpecialReceiverMap() 229 ? LookupInSpecialHolder<is_element>(map, holder) 230 : LookupInRegularHolder<is_element>(map, holder); 231 } 232 template <bool is_element> 233 State LookupInRegularHolder(Map map, JSReceiver holder); 234 template <bool is_element> 235 State LookupInSpecialHolder(Map map, JSReceiver holder); 236 template <bool is_element> RestartLookupForNonMaskingInterceptors()237 void RestartLookupForNonMaskingInterceptors() { 238 RestartInternal<is_element>(InterceptorState::kProcessNonMasking); 239 } 240 template <bool is_element> 241 void RestartInternal(InterceptorState interceptor_state); 242 Handle<Object> FetchValue(AllocationPolicy allocation_policy = 243 AllocationPolicy::kAllocationAllowed) const; 244 bool IsConstFieldValueEqualTo(Object value) const; 245 template <bool is_element> 246 void ReloadPropertyInformation(); 247 248 template <bool is_element> 249 bool SkipInterceptor(JSObject holder); 250 template <bool is_element> 251 inline InterceptorInfo GetInterceptor(JSObject holder) const; 252 check_interceptor()253 bool check_interceptor() const { 254 return (configuration_ & kInterceptor) != 0; 255 } 256 inline InternalIndex descriptor_number() const; 257 inline InternalIndex dictionary_entry() const; 258 259 static inline Configuration ComputeConfiguration(Isolate* isolate, 260 Configuration configuration, 261 Handle<Name> name); 262 263 static Handle<JSReceiver> GetRootForNonJSReceiver( 264 Isolate* isolate, Handle<Object> receiver, size_t index = kInvalidIndex); 265 static inline Handle<JSReceiver> GetRoot(Isolate* isolate, 266 Handle<Object> receiver, 267 size_t index = kInvalidIndex); 268 269 State NotFound(JSReceiver const holder) const; 270 271 // If configuration_ becomes mutable, update 272 // HolderIsReceiverOrHiddenPrototype. 273 const Configuration configuration_; 274 State state_ = NOT_FOUND; 275 bool has_property_ = false; 276 InterceptorState interceptor_state_ = InterceptorState::kUninitialized; 277 PropertyDetails property_details_ = PropertyDetails::Empty(); 278 Isolate* const isolate_; 279 Handle<Name> name_; 280 Handle<Object> transition_; 281 const Handle<Object> receiver_; 282 Handle<JSReceiver> holder_; 283 const Handle<JSReceiver> initial_holder_; 284 const size_t index_; 285 InternalIndex number_ = InternalIndex::NotFound(); 286 }; 287 288 } // namespace internal 289 } // namespace v8 290 291 #endif // V8_OBJECTS_LOOKUP_H_ 292