Home | History | Annotate | Download | only in src
      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_LOOKUP_H_
      6 #define V8_LOOKUP_H_
      7 
      8 #include "src/factory.h"
      9 #include "src/isolate.h"
     10 #include "src/objects.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 class LookupIterator final BASE_EMBEDDED {
     16  public:
     17   enum Configuration {
     18     // Configuration bits.
     19     kHidden = 1 << 0,
     20     kInterceptor = 1 << 1,
     21     kPrototypeChain = 1 << 2,
     22 
     23     // Convience combinations of bits.
     24     OWN_SKIP_INTERCEPTOR = 0,
     25     OWN = kInterceptor,
     26     HIDDEN_SKIP_INTERCEPTOR = kHidden,
     27     HIDDEN = kHidden | kInterceptor,
     28     PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kHidden | kPrototypeChain,
     29     PROTOTYPE_CHAIN = kHidden | kPrototypeChain | kInterceptor,
     30     DEFAULT = PROTOTYPE_CHAIN
     31   };
     32 
     33   enum State {
     34     ACCESS_CHECK,
     35     INTEGER_INDEXED_EXOTIC,
     36     INTERCEPTOR,
     37     JSPROXY,
     38     NOT_FOUND,
     39     ACCESSOR,
     40     DATA,
     41     TRANSITION,
     42     // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
     43     // PROPERTY lookup.
     44     BEFORE_PROPERTY = INTERCEPTOR
     45   };
     46 
     47   LookupIterator(Handle<Object> receiver, Handle<Name> name,
     48                  Configuration configuration = DEFAULT)
     49       : configuration_(ComputeConfiguration(configuration, name)),
     50         state_(NOT_FOUND),
     51         exotic_index_state_(ExoticIndexState::kUninitialized),
     52         interceptor_state_(InterceptorState::kUninitialized),
     53         property_details_(PropertyDetails::Empty()),
     54         isolate_(name->GetIsolate()),
     55         name_(Name::Flatten(name)),
     56         // kMaxUInt32 isn't a valid index.
     57         index_(kMaxUInt32),
     58         receiver_(receiver),
     59         holder_(GetRoot(isolate_, receiver)),
     60         holder_map_(holder_->map(), isolate_),
     61         initial_holder_(holder_),
     62         number_(DescriptorArray::kNotFound) {
     63 #ifdef DEBUG
     64     uint32_t index;  // Assert that the name is not an array index.
     65     DCHECK(!name->AsArrayIndex(&index));
     66 #endif  // DEBUG
     67     Next();
     68   }
     69 
     70   LookupIterator(Handle<Object> receiver, Handle<Name> name,
     71                  Handle<JSReceiver> holder,
     72                  Configuration configuration = DEFAULT)
     73       : configuration_(ComputeConfiguration(configuration, name)),
     74         state_(NOT_FOUND),
     75         exotic_index_state_(ExoticIndexState::kUninitialized),
     76         interceptor_state_(InterceptorState::kUninitialized),
     77         property_details_(PropertyDetails::Empty()),
     78         isolate_(name->GetIsolate()),
     79         name_(Name::Flatten(name)),
     80         // kMaxUInt32 isn't a valid index.
     81         index_(kMaxUInt32),
     82         receiver_(receiver),
     83         holder_(holder),
     84         holder_map_(holder_->map(), isolate_),
     85         initial_holder_(holder_),
     86         number_(DescriptorArray::kNotFound) {
     87 #ifdef DEBUG
     88     uint32_t index;  // Assert that the name is not an array index.
     89     DCHECK(!name->AsArrayIndex(&index));
     90 #endif  // DEBUG
     91     Next();
     92   }
     93 
     94   LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
     95                  Configuration configuration = DEFAULT)
     96       : configuration_(configuration),
     97         state_(NOT_FOUND),
     98         exotic_index_state_(ExoticIndexState::kUninitialized),
     99         interceptor_state_(InterceptorState::kUninitialized),
    100         property_details_(PropertyDetails::Empty()),
    101         isolate_(isolate),
    102         name_(),
    103         index_(index),
    104         receiver_(receiver),
    105         holder_(GetRoot(isolate, receiver, index)),
    106         holder_map_(holder_->map(), isolate_),
    107         initial_holder_(holder_),
    108         number_(DescriptorArray::kNotFound) {
    109     // kMaxUInt32 isn't a valid index.
    110     DCHECK_NE(kMaxUInt32, index_);
    111     Next();
    112   }
    113 
    114   LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
    115                  Handle<JSReceiver> holder,
    116                  Configuration configuration = DEFAULT)
    117       : configuration_(configuration),
    118         state_(NOT_FOUND),
    119         exotic_index_state_(ExoticIndexState::kUninitialized),
    120         interceptor_state_(InterceptorState::kUninitialized),
    121         property_details_(PropertyDetails::Empty()),
    122         isolate_(isolate),
    123         name_(),
    124         index_(index),
    125         receiver_(receiver),
    126         holder_(holder),
    127         holder_map_(holder_->map(), isolate_),
    128         initial_holder_(holder_),
    129         number_(DescriptorArray::kNotFound) {
    130     // kMaxUInt32 isn't a valid index.
    131     DCHECK_NE(kMaxUInt32, index_);
    132     Next();
    133   }
    134 
    135   static LookupIterator PropertyOrElement(
    136       Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
    137       Configuration configuration = DEFAULT) {
    138     name = Name::Flatten(name);
    139     uint32_t index;
    140     LookupIterator it =
    141         name->AsArrayIndex(&index)
    142             ? LookupIterator(isolate, receiver, index, configuration)
    143             : LookupIterator(receiver, name, configuration);
    144     it.name_ = name;
    145     return it;
    146   }
    147 
    148   static LookupIterator PropertyOrElement(
    149       Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
    150       Handle<JSReceiver> holder, Configuration configuration = DEFAULT) {
    151     name = Name::Flatten(name);
    152     uint32_t index;
    153     LookupIterator it =
    154         name->AsArrayIndex(&index)
    155             ? LookupIterator(isolate, receiver, index, holder, configuration)
    156             : LookupIterator(receiver, name, holder, configuration);
    157     it.name_ = name;
    158     return it;
    159   }
    160 
    161   static LookupIterator PropertyOrElement(
    162       Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
    163       bool* success, Configuration configuration = DEFAULT);
    164 
    165   void Restart() { RestartInternal(InterceptorState::kUninitialized); }
    166 
    167   Isolate* isolate() const { return isolate_; }
    168   State state() const { return state_; }
    169 
    170   Handle<Name> name() const {
    171     DCHECK(!IsElement());
    172     return name_;
    173   }
    174   Handle<Name> GetName() {
    175     if (name_.is_null()) {
    176       DCHECK(IsElement());
    177       name_ = factory()->Uint32ToString(index_);
    178     }
    179     return name_;
    180   }
    181   uint32_t index() const { return index_; }
    182 
    183   bool IsElement() const { return index_ != kMaxUInt32; }
    184 
    185   bool IsFound() const { return state_ != NOT_FOUND; }
    186   void Next();
    187   void NotFound() {
    188     has_property_ = false;
    189     state_ = NOT_FOUND;
    190   }
    191 
    192   Heap* heap() const { return isolate_->heap(); }
    193   Factory* factory() const { return isolate_->factory(); }
    194   Handle<Object> GetReceiver() const { return receiver_; }
    195   Handle<JSObject> GetStoreTarget() const;
    196   bool is_dictionary_holder() const { return holder_map_->is_dictionary_map(); }
    197   Handle<Map> transition_map() const {
    198     DCHECK_EQ(TRANSITION, state_);
    199     return Handle<Map>::cast(transition_);
    200   }
    201   template <class T>
    202   Handle<T> GetHolder() const {
    203     DCHECK(IsFound());
    204     return Handle<T>::cast(holder_);
    205   }
    206 
    207   bool HolderIsReceiverOrHiddenPrototype() const;
    208 
    209   bool check_prototype_chain() const {
    210     return (configuration_ & kPrototypeChain) != 0;
    211   }
    212 
    213   /* ACCESS_CHECK */
    214   bool HasAccess() const;
    215 
    216   /* PROPERTY */
    217   void PrepareForDataProperty(Handle<Object> value);
    218   void PrepareTransitionToDataProperty(Handle<Object> value,
    219                                        PropertyAttributes attributes,
    220                                        Object::StoreFromKeyed store_mode);
    221   bool IsCacheableTransition() {
    222     if (state_ != TRANSITION) return false;
    223     return transition_->IsPropertyCell() ||
    224            (!transition_map()->is_dictionary_map() &&
    225             transition_map()->GetBackPointer()->IsMap());
    226   }
    227   void ApplyTransitionToDataProperty();
    228   void ReconfigureDataProperty(Handle<Object> value,
    229                                PropertyAttributes attributes);
    230   void Delete();
    231   void TransitionToAccessorProperty(AccessorComponent component,
    232                                     Handle<Object> accessor,
    233                                     PropertyAttributes attributes);
    234   void TransitionToAccessorPair(Handle<Object> pair,
    235                                 PropertyAttributes attributes);
    236   PropertyDetails property_details() const {
    237     DCHECK(has_property_);
    238     return property_details_;
    239   }
    240   bool IsConfigurable() const { return property_details().IsConfigurable(); }
    241   bool IsReadOnly() const { return property_details().IsReadOnly(); }
    242   Representation representation() const {
    243     return property_details().representation();
    244   }
    245   FieldIndex GetFieldIndex() const;
    246   Handle<HeapType> GetFieldType() const;
    247   int GetAccessorIndex() const;
    248   int GetConstantIndex() const;
    249   Handle<PropertyCell> GetPropertyCell() const;
    250   Handle<Object> GetAccessors() const;
    251   inline Handle<InterceptorInfo> GetInterceptor() const {
    252     DCHECK_EQ(INTERCEPTOR, state_);
    253     return handle(GetInterceptor(JSObject::cast(*holder_)), isolate_);
    254   }
    255   Handle<Object> GetDataValue() const;
    256   void WriteDataValue(Handle<Object> value);
    257   void InternalizeName();
    258   void ReloadHolderMap();
    259 
    260  private:
    261   enum class InterceptorState {
    262     kUninitialized,
    263     kSkipNonMasking,
    264     kProcessNonMasking
    265   };
    266 
    267   Handle<Map> GetReceiverMap() const;
    268 
    269   MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
    270   inline State LookupInHolder(Map* map, JSReceiver* holder);
    271   void RestartLookupForNonMaskingInterceptors() {
    272     RestartInternal(InterceptorState::kProcessNonMasking);
    273   }
    274   void RestartInternal(InterceptorState interceptor_state);
    275   State LookupNonMaskingInterceptorInHolder(Map* map, JSReceiver* holder);
    276   Handle<Object> FetchValue() const;
    277   void ReloadPropertyInformation();
    278   inline bool SkipInterceptor(JSObject* holder);
    279   bool HasInterceptor(Map* map) const;
    280   bool InternalHolderIsReceiverOrHiddenPrototype() const;
    281   inline InterceptorInfo* GetInterceptor(JSObject* holder) const {
    282     if (IsElement()) return holder->GetIndexedInterceptor();
    283     return holder->GetNamedInterceptor();
    284   }
    285 
    286   bool check_hidden() const { return (configuration_ & kHidden) != 0; }
    287   bool check_interceptor() const {
    288     return (configuration_ & kInterceptor) != 0;
    289   }
    290   int descriptor_number() const {
    291     DCHECK(has_property_);
    292     DCHECK(!holder_map_->is_dictionary_map());
    293     return number_;
    294   }
    295   int dictionary_entry() const {
    296     DCHECK(has_property_);
    297     DCHECK(holder_map_->is_dictionary_map());
    298     return number_;
    299   }
    300 
    301   static Configuration ComputeConfiguration(
    302       Configuration configuration, Handle<Name> name) {
    303     if (name->IsPrivate()) {
    304       return static_cast<Configuration>(configuration &
    305                                         HIDDEN_SKIP_INTERCEPTOR);
    306     } else {
    307       return configuration;
    308     }
    309   }
    310 
    311   static Handle<JSReceiver> GetRootForNonJSReceiver(
    312       Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32);
    313   inline static Handle<JSReceiver> GetRoot(Isolate* isolate,
    314                                            Handle<Object> receiver,
    315                                            uint32_t index = kMaxUInt32) {
    316     if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
    317     return GetRootForNonJSReceiver(isolate, receiver, index);
    318   }
    319 
    320   enum class ExoticIndexState { kUninitialized, kNotExotic, kExotic };
    321   inline bool IsIntegerIndexedExotic(JSReceiver* holder);
    322 
    323   // If configuration_ becomes mutable, update
    324   // HolderIsReceiverOrHiddenPrototype.
    325   const Configuration configuration_;
    326   State state_;
    327   bool has_property_;
    328   ExoticIndexState exotic_index_state_;
    329   InterceptorState interceptor_state_;
    330   PropertyDetails property_details_;
    331   Isolate* const isolate_;
    332   Handle<Name> name_;
    333   uint32_t index_;
    334   Handle<Object> transition_;
    335   const Handle<Object> receiver_;
    336   Handle<JSReceiver> holder_;
    337   Handle<Map> holder_map_;
    338   const Handle<JSReceiver> initial_holder_;
    339   uint32_t number_;
    340 };
    341 
    342 
    343 }  // namespace internal
    344 }  // namespace v8
    345 
    346 #endif  // V8_LOOKUP_H_
    347