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