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/globals.h"
      9 #include "src/heap/factory.h"
     10 #include "src/isolate.h"
     11 #include "src/objects.h"
     12 #include "src/objects/descriptor-array.h"
     13 #include "src/objects/map.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED {
     19  public:
     20   enum Configuration {
     21     // Configuration bits.
     22     kInterceptor = 1 << 0,
     23     kPrototypeChain = 1 << 1,
     24 
     25     // Convenience combinations of bits.
     26     OWN_SKIP_INTERCEPTOR = 0,
     27     OWN = kInterceptor,
     28     PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
     29     PROTOTYPE_CHAIN = 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(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
     48                  Configuration configuration = DEFAULT)
     49       : LookupIterator(isolate, receiver, name, GetRoot(isolate, receiver),
     50                        configuration) {}
     51 
     52   inline LookupIterator(Handle<Object> receiver, Handle<Name> name,
     53                         Handle<JSReceiver> holder,
     54                         Configuration configuration = DEFAULT);
     55 
     56   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
     57                         Handle<Name> name, Handle<JSReceiver> holder,
     58                         Configuration configuration = DEFAULT);
     59 
     60   LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
     61                  Configuration configuration = DEFAULT)
     62       : LookupIterator(isolate, receiver, index,
     63                        GetRoot(isolate, receiver, index), configuration) {}
     64 
     65   LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
     66                  Handle<JSReceiver> holder,
     67                  Configuration configuration = DEFAULT)
     68       : configuration_(configuration),
     69         interceptor_state_(InterceptorState::kUninitialized),
     70         property_details_(PropertyDetails::Empty()),
     71         isolate_(isolate),
     72         receiver_(receiver),
     73         initial_holder_(holder),
     74         index_(index),
     75         number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
     76     // kMaxUInt32 isn't a valid index.
     77     DCHECK_NE(kMaxUInt32, index_);
     78     Start<true>();
     79   }
     80 
     81   static inline LookupIterator PropertyOrElement(
     82       Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
     83       Configuration configuration = DEFAULT);
     84 
     85   static inline LookupIterator PropertyOrElement(
     86       Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
     87       Handle<JSReceiver> holder, Configuration configuration = DEFAULT);
     88 
     89   static LookupIterator PropertyOrElement(
     90       Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
     91       bool* success, Handle<JSReceiver> holder,
     92       Configuration configuration = DEFAULT);
     93 
     94   static LookupIterator PropertyOrElement(
     95       Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
     96       bool* success, Configuration configuration = DEFAULT);
     97 
     98   static LookupIterator ForTransitionHandler(
     99       Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
    100       Handle<Object> value, MaybeHandle<Map> maybe_transition_map);
    101 
    102   void Restart() {
    103     InterceptorState state = InterceptorState::kUninitialized;
    104     IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
    105   }
    106 
    107   Isolate* isolate() const { return isolate_; }
    108   State state() const { return state_; }
    109 
    110   Handle<Name> name() const {
    111     DCHECK(!IsElement());
    112     return name_;
    113   }
    114   inline Handle<Name> GetName();
    115   uint32_t index() const { return index_; }
    116 
    117   bool IsElement() const { return index_ != kMaxUInt32; }
    118 
    119   bool IsFound() const { return state_ != NOT_FOUND; }
    120   void Next();
    121   void NotFound() {
    122     has_property_ = false;
    123     state_ = NOT_FOUND;
    124   }
    125 
    126   Heap* heap() const { return isolate_->heap(); }
    127   Factory* factory() const { return isolate_->factory(); }
    128   Handle<Object> GetReceiver() const { return receiver_; }
    129 
    130   template <class T>
    131   inline Handle<T> GetStoreTarget() const;
    132   inline bool is_dictionary_holder() const;
    133   Handle<Map> transition_map() const {
    134     DCHECK_EQ(TRANSITION, state_);
    135     return Handle<Map>::cast(transition_);
    136   }
    137   Handle<PropertyCell> transition_cell() const {
    138     DCHECK_EQ(TRANSITION, state_);
    139     return Handle<PropertyCell>::cast(transition_);
    140   }
    141   template <class T>
    142   Handle<T> GetHolder() const {
    143     DCHECK(IsFound());
    144     return Handle<T>::cast(holder_);
    145   }
    146 
    147   bool HolderIsReceiver() const;
    148   bool HolderIsReceiverOrHiddenPrototype() const;
    149 
    150   bool check_prototype_chain() const {
    151     return (configuration_ & kPrototypeChain) != 0;
    152   }
    153 
    154   /* ACCESS_CHECK */
    155   bool HasAccess() const;
    156 
    157   /* PROPERTY */
    158   inline bool ExtendingNonExtensible(Handle<JSReceiver> receiver);
    159   void PrepareForDataProperty(Handle<Object> value);
    160   void PrepareTransitionToDataProperty(Handle<JSReceiver> receiver,
    161                                        Handle<Object> value,
    162                                        PropertyAttributes attributes,
    163                                        Object::StoreFromKeyed store_mode);
    164   inline bool IsCacheableTransition();
    165   void ApplyTransitionToDataProperty(Handle<JSReceiver> receiver);
    166   void ReconfigureDataProperty(Handle<Object> value,
    167                                PropertyAttributes attributes);
    168   void Delete();
    169   void TransitionToAccessorProperty(Handle<Object> getter,
    170                                     Handle<Object> setter,
    171                                     PropertyAttributes attributes);
    172   void TransitionToAccessorPair(Handle<Object> pair,
    173                                 PropertyAttributes attributes);
    174   PropertyDetails property_details() const {
    175     DCHECK(has_property_);
    176     return property_details_;
    177   }
    178   PropertyAttributes property_attributes() const {
    179     return property_details().attributes();
    180   }
    181   bool IsConfigurable() const { return property_details().IsConfigurable(); }
    182   bool IsReadOnly() const { return property_details().IsReadOnly(); }
    183   bool IsEnumerable() const { return property_details().IsEnumerable(); }
    184   Representation representation() const {
    185     return property_details().representation();
    186   }
    187   PropertyLocation location() const { return property_details().location(); }
    188   PropertyConstness constness() const { return property_details().constness(); }
    189   Handle<Map> GetFieldOwnerMap() const;
    190   FieldIndex GetFieldIndex() const;
    191   Handle<FieldType> GetFieldType() const;
    192   int GetFieldDescriptorIndex() const;
    193   int GetAccessorIndex() const;
    194   int GetConstantIndex() const;
    195   Handle<PropertyCell> GetPropertyCell() const;
    196   Handle<Object> GetAccessors() const;
    197   inline Handle<InterceptorInfo> GetInterceptor() const;
    198   Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const;
    199   Handle<Object> GetDataValue() const;
    200   void WriteDataValue(Handle<Object> value, bool initializing_store);
    201   inline void UpdateProtector();
    202 
    203   // Lookup a 'cached' private property for an accessor.
    204   // If not found returns false and leaves the LookupIterator unmodified.
    205   bool TryLookupCachedProperty();
    206   bool LookupCachedProperty();
    207 
    208  private:
    209   // For |ForTransitionHandler|.
    210   LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
    211                  Handle<Map> transition_map, PropertyDetails details,
    212                  bool has_property);
    213 
    214   void InternalUpdateProtector();
    215 
    216   enum class InterceptorState {
    217     kUninitialized,
    218     kSkipNonMasking,
    219     kProcessNonMasking
    220   };
    221 
    222   Handle<Map> GetReceiverMap() const;
    223 
    224   V8_WARN_UNUSED_RESULT inline JSReceiver* NextHolder(Map* map);
    225 
    226   template <bool is_element>
    227   V8_EXPORT_PRIVATE void Start();
    228   template <bool is_element>
    229   void NextInternal(Map* map, JSReceiver* holder);
    230   template <bool is_element>
    231   inline State LookupInHolder(Map* map, JSReceiver* holder) {
    232     return map->IsSpecialReceiverMap()
    233                ? LookupInSpecialHolder<is_element>(map, holder)
    234                : LookupInRegularHolder<is_element>(map, holder);
    235   }
    236   template <bool is_element>
    237   State LookupInRegularHolder(Map* map, JSReceiver* holder);
    238   template <bool is_element>
    239   State LookupInSpecialHolder(Map* map, JSReceiver* holder);
    240   template <bool is_element>
    241   void RestartLookupForNonMaskingInterceptors() {
    242     RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
    243   }
    244   template <bool is_element>
    245   void RestartInternal(InterceptorState interceptor_state);
    246   Handle<Object> FetchValue() const;
    247   bool IsConstFieldValueEqualTo(Object* value) const;
    248   template <bool is_element>
    249   void ReloadPropertyInformation();
    250 
    251   template <bool is_element>
    252   bool SkipInterceptor(JSObject* holder);
    253   template <bool is_element>
    254   inline InterceptorInfo* GetInterceptor(JSObject* holder) const {
    255     return is_element ? holder->GetIndexedInterceptor()
    256                       : holder->GetNamedInterceptor();
    257   }
    258 
    259   bool check_interceptor() const {
    260     return (configuration_ & kInterceptor) != 0;
    261   }
    262   int descriptor_number() const {
    263     DCHECK(!IsElement());
    264     DCHECK(has_property_);
    265     DCHECK(holder_->HasFastProperties());
    266     return number_;
    267   }
    268   int dictionary_entry() const {
    269     DCHECK(!IsElement());
    270     DCHECK(has_property_);
    271     DCHECK(!holder_->HasFastProperties());
    272     return number_;
    273   }
    274 
    275   static inline Configuration ComputeConfiguration(
    276       Configuration configuration, Handle<Name> name);
    277 
    278   static Handle<JSReceiver> GetRootForNonJSReceiver(
    279       Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32);
    280   static inline Handle<JSReceiver> GetRoot(Isolate* isolate,
    281                                            Handle<Object> receiver,
    282                                            uint32_t index = kMaxUInt32);
    283 
    284   State NotFound(JSReceiver* const holder) const;
    285 
    286   // If configuration_ becomes mutable, update
    287   // HolderIsReceiverOrHiddenPrototype.
    288   const Configuration configuration_;
    289   State state_;
    290   bool has_property_;
    291   InterceptorState interceptor_state_;
    292   PropertyDetails property_details_;
    293   Isolate* const isolate_;
    294   Handle<Name> name_;
    295   Handle<Object> transition_;
    296   const Handle<Object> receiver_;
    297   Handle<JSReceiver> holder_;
    298   const Handle<JSReceiver> initial_holder_;
    299   const uint32_t index_;
    300   uint32_t number_;
    301 };
    302 
    303 
    304 }  // namespace internal
    305 }  // namespace v8
    306 
    307 #endif  // V8_LOOKUP_H_
    308