// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_OBJECTS_LOOKUP_H_ #define V8_OBJECTS_LOOKUP_H_ #include "src/common/globals.h" #include "src/execution/isolate.h" #include "src/heap/factory.h" #include "src/objects/descriptor-array.h" #include "src/objects/js-objects.h" #include "src/objects/map.h" #include "src/objects/objects.h" namespace v8 { namespace internal { class V8_EXPORT_PRIVATE LookupIterator final { public: enum Configuration { // Configuration bits. kInterceptor = 1 << 0, kPrototypeChain = 1 << 1, // Convenience combinations of bits. OWN_SKIP_INTERCEPTOR = 0, OWN = kInterceptor, PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain, PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor, DEFAULT = PROTOTYPE_CHAIN }; enum State { ACCESS_CHECK, INTEGER_INDEXED_EXOTIC, INTERCEPTOR, JSPROXY, NOT_FOUND, ACCESSOR, DATA, TRANSITION, // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a // PROPERTY lookup. BEFORE_PROPERTY = INTERCEPTOR }; inline LookupIterator(Isolate* isolate, Handle receiver, Handle name, Configuration configuration = DEFAULT); inline LookupIterator(Handle receiver, Handle name, Handle holder, Configuration configuration = DEFAULT); inline LookupIterator(Isolate* isolate, Handle receiver, Handle name, Handle holder, Configuration configuration = DEFAULT); inline LookupIterator(Isolate* isolate, Handle receiver, uint32_t index, Configuration configuration = DEFAULT); LookupIterator(Isolate* isolate, Handle receiver, uint32_t index, Handle holder, Configuration configuration = DEFAULT) : configuration_(configuration), interceptor_state_(InterceptorState::kUninitialized), property_details_(PropertyDetails::Empty()), isolate_(isolate), receiver_(receiver), initial_holder_(holder), index_(index), number_(static_cast(DescriptorArray::kNotFound)) { // kMaxUInt32 isn't a valid index. DCHECK_NE(kMaxUInt32, index_); Start(); } static inline LookupIterator PropertyOrElement( Isolate* isolate, Handle receiver, Handle name, Configuration configuration = DEFAULT); static inline LookupIterator PropertyOrElement( Isolate* isolate, Handle receiver, Handle name, Handle holder, Configuration configuration = DEFAULT); static LookupIterator PropertyOrElement( Isolate* isolate, Handle receiver, Handle key, bool* success, Handle holder, Configuration configuration = DEFAULT); static LookupIterator PropertyOrElement( Isolate* isolate, Handle receiver, Handle key, bool* success, Configuration configuration = DEFAULT); void Restart() { InterceptorState state = InterceptorState::kUninitialized; IsElement() ? RestartInternal(state) : RestartInternal(state); } Isolate* isolate() const { return isolate_; } State state() const { return state_; } Handle name() const { DCHECK(!IsElement()); return name_; } inline Handle GetName(); uint32_t index() const { return index_; } bool IsElement() const { return index_ != kMaxUInt32; } bool IsFound() const { return state_ != NOT_FOUND; } void Next(); void NotFound() { has_property_ = false; state_ = NOT_FOUND; } Heap* heap() const { return isolate_->heap(); } Factory* factory() const { return isolate_->factory(); } Handle GetReceiver() const { return receiver_; } template inline Handle GetStoreTarget() const; inline bool is_dictionary_holder() const; inline Handle transition_map() const; inline Handle transition_cell() const; template inline Handle GetHolder() const; bool HolderIsReceiver() const; bool HolderIsReceiverOrHiddenPrototype() const; bool check_prototype_chain() const { return (configuration_ & kPrototypeChain) != 0; } /* ACCESS_CHECK */ bool HasAccess() const; /* PROPERTY */ inline bool ExtendingNonExtensible(Handle receiver); void PrepareForDataProperty(Handle value); void PrepareTransitionToDataProperty(Handle receiver, Handle value, PropertyAttributes attributes, StoreOrigin store_origin); inline bool IsCacheableTransition(); void ApplyTransitionToDataProperty(Handle receiver); void ReconfigureDataProperty(Handle value, PropertyAttributes attributes); void Delete(); void TransitionToAccessorProperty(Handle getter, Handle setter, PropertyAttributes attributes); void TransitionToAccessorPair(Handle pair, PropertyAttributes attributes); PropertyDetails property_details() const { DCHECK(has_property_); return property_details_; } PropertyAttributes property_attributes() const { return property_details().attributes(); } bool IsConfigurable() const { return property_details().IsConfigurable(); } bool IsReadOnly() const { return property_details().IsReadOnly(); } bool IsEnumerable() const { return property_details().IsEnumerable(); } Representation representation() const { return property_details().representation(); } PropertyLocation location() const { return property_details().location(); } PropertyConstness constness() const { return property_details().constness(); } Handle GetFieldOwnerMap() const; FieldIndex GetFieldIndex() const; Handle GetFieldType() const; int GetFieldDescriptorIndex() const; int GetAccessorIndex() const; Handle GetPropertyCell() const; Handle GetAccessors() const; inline Handle GetInterceptor() const; Handle GetInterceptorForFailedAccessCheck() const; Handle GetDataValue() const; void WriteDataValue(Handle value, bool initializing_store); inline void UpdateProtector(); // Lookup a 'cached' private property for an accessor. // If not found returns false and leaves the LookupIterator unmodified. bool TryLookupCachedProperty(); bool LookupCachedProperty(); private: // For |ForTransitionHandler|. LookupIterator(Isolate* isolate, Handle receiver, Handle name, Handle transition_map, PropertyDetails details, bool has_property); void InternalUpdateProtector(); enum class InterceptorState { kUninitialized, kSkipNonMasking, kProcessNonMasking }; Handle GetReceiverMap() const; V8_WARN_UNUSED_RESULT inline JSReceiver NextHolder(Map map); template V8_EXPORT_PRIVATE void Start(); template void NextInternal(Map map, JSReceiver holder); template inline State LookupInHolder(Map map, JSReceiver holder) { return map.IsSpecialReceiverMap() ? LookupInSpecialHolder(map, holder) : LookupInRegularHolder(map, holder); } template State LookupInRegularHolder(Map map, JSReceiver holder); template State LookupInSpecialHolder(Map map, JSReceiver holder); template void RestartLookupForNonMaskingInterceptors() { RestartInternal(InterceptorState::kProcessNonMasking); } template void RestartInternal(InterceptorState interceptor_state); Handle FetchValue() const; bool IsConstFieldValueEqualTo(Object value) const; template void ReloadPropertyInformation(); template bool SkipInterceptor(JSObject holder); template static inline InterceptorInfo GetInterceptor(Isolate* isolate, JSObject holder); bool check_interceptor() const { return (configuration_ & kInterceptor) != 0; } inline int descriptor_number() const; inline int dictionary_entry() const; static inline Configuration ComputeConfiguration(Isolate* isolate, Configuration configuration, Handle name); static Handle GetRootForNonJSReceiver( Isolate* isolate, Handle receiver, uint32_t index = kMaxUInt32); static inline Handle GetRoot(Isolate* isolate, Handle receiver, uint32_t index = kMaxUInt32); State NotFound(JSReceiver const holder) const; // If configuration_ becomes mutable, update // HolderIsReceiverOrHiddenPrototype. const Configuration configuration_; State state_; bool has_property_; InterceptorState interceptor_state_; PropertyDetails property_details_; Isolate* const isolate_; Handle name_; Handle transition_; const Handle receiver_; Handle holder_; const Handle initial_holder_; const uint32_t index_; uint32_t number_; }; } // namespace internal } // namespace v8 #endif // V8_OBJECTS_LOOKUP_H_