| // 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, |
| 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<Object> receiver, Handle<Name> name, |
| Configuration configuration = PROTOTYPE_CHAIN) |
| : configuration_(ComputeConfiguration(configuration, name)), |
| state_(NOT_FOUND), |
| property_details_(NONE, NORMAL, Representation::None()), |
| isolate_(name->GetIsolate()), |
| name_(name), |
| receiver_(receiver), |
| number_(DescriptorArray::kNotFound) { |
| holder_ = GetRoot(); |
| holder_map_ = handle(holder_->map(), isolate_); |
| Next(); |
| } |
| |
| LookupIterator(Handle<Object> receiver, Handle<Name> name, |
| Handle<JSReceiver> holder, |
| Configuration configuration = PROTOTYPE_CHAIN) |
| : configuration_(ComputeConfiguration(configuration, name)), |
| state_(NOT_FOUND), |
| property_details_(NONE, NORMAL, Representation::None()), |
| isolate_(name->GetIsolate()), |
| name_(name), |
| holder_map_(holder->map(), isolate_), |
| receiver_(receiver), |
| holder_(holder), |
| number_(DescriptorArray::kNotFound) { |
| Next(); |
| } |
| |
| Isolate* isolate() const { return isolate_; } |
| State state() const { return state_; } |
| Handle<Name> 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<Object> GetReceiver() const { return receiver_; } |
| Handle<JSObject> GetStoreTarget() const; |
| bool is_dictionary_holder() const { return holder_map_->is_dictionary_map(); } |
| Handle<Map> transition_map() const { |
| DCHECK_EQ(TRANSITION, state_); |
| return transition_map_; |
| } |
| template <class T> |
| Handle<T> GetHolder() const { |
| DCHECK(IsFound()); |
| return Handle<T>::cast(holder_); |
| } |
| Handle<JSReceiver> GetRoot() const; |
| bool HolderIsReceiverOrHiddenPrototype() const; |
| |
| /* ACCESS_CHECK */ |
| bool HasAccess(v8::AccessType access_type) const; |
| |
| /* PROPERTY */ |
| void PrepareForDataProperty(Handle<Object> value); |
| void PrepareTransitionToDataProperty(Handle<Object> value, |
| PropertyAttributes attributes, |
| Object::StoreFromKeyed store_mode); |
| bool IsCacheableTransition() { |
| bool cacheable = |
| state_ == TRANSITION && transition_map()->GetBackPointer()->IsMap(); |
| if (cacheable) { |
| property_details_ = transition_map_->GetLastDescriptorDetails(); |
| has_property_ = true; |
| } |
| return cacheable; |
| } |
| void ApplyTransitionToDataProperty(); |
| void ReconfigureDataProperty(Handle<Object> value, |
| PropertyAttributes attributes); |
| void TransitionToAccessorProperty(AccessorComponent component, |
| Handle<Object> 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<HeapType> GetFieldType() const; |
| int GetConstantIndex() const; |
| Handle<PropertyCell> GetPropertyCell() const; |
| Handle<Object> GetAccessors() const; |
| Handle<Object> GetDataValue() const; |
| void WriteDataValue(Handle<Object> value); |
| |
| void InternalizeName(); |
| |
| private: |
| Handle<Map> GetReceiverMap() const; |
| |
| MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map); |
| inline State LookupInHolder(Map* map, JSReceiver* holder); |
| Handle<Object> FetchValue() const; |
| void ReloadPropertyInformation(); |
| |
| 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> name) { |
| if (name->IsOwn()) { |
| return static_cast<Configuration>(configuration & HIDDEN); |
| } else { |
| return configuration; |
| } |
| } |
| |
| // If configuration_ becomes mutable, update |
| // HolderIsReceiverOrHiddenPrototype. |
| Configuration configuration_; |
| State state_; |
| bool has_property_; |
| PropertyDetails property_details_; |
| Isolate* isolate_; |
| Handle<Name> name_; |
| Handle<Map> holder_map_; |
| Handle<Map> transition_map_; |
| Handle<Object> receiver_; |
| Handle<JSReceiver> holder_; |
| |
| int number_; |
| }; |
| |
| |
| } } // namespace v8::internal |
| |
| #endif // V8_LOOKUP_H_ |