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