// 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_LOOKUP_H_ #define V8_LOOKUP_H_ #include "src/factory.h" #include "src/isolate.h" #include "src/objects.h" namespace v8 { namespace internal { class LookupIterator FINAL BASE_EMBEDDED { public: enum Configuration { // Configuration bits. kHidden = 1 << 0, kInterceptor = 1 << 1, kPrototypeChain = 1 << 2, // Convience combinations of bits. OWN_SKIP_INTERCEPTOR = 0, OWN = kInterceptor, HIDDEN_SKIP_INTERCEPTOR = kHidden, HIDDEN = kHidden | kInterceptor, PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kHidden | kPrototypeChain, PROTOTYPE_CHAIN = kHidden | kPrototypeChain | kInterceptor }; 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 }; LookupIterator(Handle receiver, Handle name, Configuration configuration = PROTOTYPE_CHAIN) : configuration_(ComputeConfiguration(configuration, name)), state_(NOT_FOUND), exotic_index_state_(ExoticIndexState::kUninitialized), interceptor_state_(InterceptorState::kUninitialized), property_details_(PropertyDetails::Empty()), isolate_(name->GetIsolate()), name_(name), receiver_(receiver), holder_(GetRoot(receiver_, isolate_)), holder_map_(holder_->map(), isolate_), initial_holder_(holder_), number_(DescriptorArray::kNotFound) { Next(); } LookupIterator(Handle receiver, Handle name, Handle holder, Configuration configuration = PROTOTYPE_CHAIN) : configuration_(ComputeConfiguration(configuration, name)), state_(NOT_FOUND), exotic_index_state_(ExoticIndexState::kUninitialized), interceptor_state_(InterceptorState::kUninitialized), property_details_(PropertyDetails::Empty()), isolate_(name->GetIsolate()), name_(name), receiver_(receiver), holder_(holder), holder_map_(holder_->map(), isolate_), initial_holder_(holder_), number_(DescriptorArray::kNotFound) { Next(); } Isolate* isolate() const { return isolate_; } State state() const { return state_; } Handle name() const { return name_; } bool IsFound() const { return state_ != NOT_FOUND; } void Next(); void NotFound() { has_property_ = false; state_ = NOT_FOUND; } Factory* factory() const { return isolate_->factory(); } Handle GetReceiver() const { return receiver_; } Handle GetStoreTarget() const; bool is_dictionary_holder() const { return holder_map_->is_dictionary_map(); } Handle transition_map() const { DCHECK_EQ(TRANSITION, state_); return Handle::cast(transition_); } template Handle GetHolder() const { DCHECK(IsFound()); return Handle::cast(holder_); } static Handle GetRoot(Handle receiver, Isolate* isolate); bool HolderIsReceiverOrHiddenPrototype() const; /* ACCESS_CHECK */ bool HasAccess() const; /* PROPERTY */ void PrepareForDataProperty(Handle value); void PrepareTransitionToDataProperty(Handle value, PropertyAttributes attributes, Object::StoreFromKeyed store_mode); bool IsCacheableTransition() { if (state_ != TRANSITION) return false; return transition_->IsPropertyCell() || transition_map()->GetBackPointer()->IsMap(); } void ApplyTransitionToDataProperty(); void ReconfigureDataProperty(Handle value, PropertyAttributes attributes); void TransitionToAccessorProperty(AccessorComponent component, Handle accessor, PropertyAttributes attributes); PropertyDetails property_details() const { DCHECK(has_property_); return property_details_; } bool IsConfigurable() const { return property_details().IsConfigurable(); } bool IsReadOnly() const { return property_details().IsReadOnly(); } Representation representation() const { return property_details().representation(); } FieldIndex GetFieldIndex() const; Handle GetFieldType() const; int GetAccessorIndex() const; int GetConstantIndex() const; Handle GetPropertyCell() const; Handle GetTransitionPropertyCell() const { DCHECK_EQ(TRANSITION, state_); return Handle::cast(transition_); } Handle GetAccessors() const; Handle GetDataValue() const; // Usually returns the value that was passed in, but may perform // non-observable modifications on it, such as internalize strings. Handle WriteDataValue(Handle value); void InternalizeName(); private: enum class InterceptorState { kUninitialized, kSkipNonMasking, kProcessNonMasking }; Handle GetReceiverMap() const; MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map); inline State LookupInHolder(Map* map, JSReceiver* holder); void RestartLookupForNonMaskingInterceptors(); State LookupNonMaskingInterceptorInHolder(Map* map, JSReceiver* holder); Handle FetchValue() const; void ReloadPropertyInformation(); bool SkipInterceptor(JSObject* holder); bool IsBootstrapping() const; bool check_hidden() const { return (configuration_ & kHidden) != 0; } bool check_interceptor() const { return !IsBootstrapping() && (configuration_ & kInterceptor) != 0; } bool check_prototype_chain() const { return (configuration_ & kPrototypeChain) != 0; } int descriptor_number() const { DCHECK(has_property_); DCHECK(!holder_map_->is_dictionary_map()); return number_; } int dictionary_entry() const { DCHECK(has_property_); DCHECK(holder_map_->is_dictionary_map()); return number_; } static Configuration ComputeConfiguration( Configuration configuration, Handle name) { if (name->IsOwn()) { return static_cast(configuration & HIDDEN_SKIP_INTERCEPTOR); } else { return configuration; } } enum class ExoticIndexState { kUninitialized, kNoIndex, kIndex }; bool IsIntegerIndexedExotic(JSReceiver* holder); // If configuration_ becomes mutable, update // HolderIsReceiverOrHiddenPrototype. const Configuration configuration_; State state_; bool has_property_; ExoticIndexState exotic_index_state_; InterceptorState interceptor_state_; PropertyDetails property_details_; Isolate* const isolate_; Handle name_; Handle transition_; const Handle receiver_; Handle holder_; Handle holder_map_; const Handle initial_holder_; int number_; }; } } // namespace v8::internal #endif // V8_LOOKUP_H_