Home | History | Annotate | Download | only in ic
      1 // Copyright 2012 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_IC_IC_H_
      6 #define V8_IC_IC_H_
      7 
      8 #include <vector>
      9 
     10 #include "src/feedback-vector.h"
     11 #include "src/heap/factory.h"
     12 #include "src/ic/stub-cache.h"
     13 #include "src/isolate.h"
     14 #include "src/macro-assembler.h"
     15 #include "src/messages.h"
     16 #include "src/objects/map.h"
     17 #include "src/objects/maybe-object.h"
     18 
     19 namespace v8 {
     20 namespace internal {
     21 
     22 //
     23 // IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC.
     24 //
     25 class IC {
     26  public:
     27   // Alias the inline cache state type to make the IC code more readable.
     28   typedef InlineCacheState State;
     29 
     30   static constexpr int kMaxKeyedPolymorphism = 4;
     31 
     32   // A polymorphic IC can handle at most 4 distinct maps before transitioning
     33   // to megamorphic state.
     34   static constexpr int kMaxPolymorphicMapCount = 4;
     35 
     36   // Construct the IC structure with the given number of extra
     37   // JavaScript frames on the stack.
     38   IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot);
     39   virtual ~IC() {}
     40 
     41   State state() const { return state_; }
     42   inline Address address() const;
     43 
     44   // Compute the current IC state based on the target stub, receiver and name.
     45   void UpdateState(Handle<Object> receiver, Handle<Object> name);
     46 
     47   bool RecomputeHandlerForName(Handle<Object> name);
     48   void MarkRecomputeHandler(Handle<Object> name) {
     49     DCHECK(RecomputeHandlerForName(name));
     50     old_state_ = state_;
     51     state_ = RECOMPUTE_HANDLER;
     52   }
     53 
     54   bool IsAnyLoad() const {
     55     return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
     56   }
     57   bool IsAnyStore() const {
     58     return IsStoreIC() || IsStoreOwnIC() || IsStoreGlobalIC() ||
     59            IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind());
     60   }
     61 
     62   static inline bool IsHandler(MaybeObject* object);
     63 
     64   // Nofity the IC system that a feedback has changed.
     65   static void OnFeedbackChanged(Isolate* isolate, FeedbackVector* vector,
     66                                 FeedbackSlot slot, JSFunction* host_function,
     67                                 const char* reason);
     68 
     69   static void OnFeedbackChanged(Isolate* isolate, FeedbackNexus* nexus,
     70                                 JSFunction* host_function, const char* reason);
     71 
     72  protected:
     73   Address fp() const { return fp_; }
     74   Address pc() const { return *pc_address_; }
     75 
     76   void set_slow_stub_reason(const char* reason) { slow_stub_reason_ = reason; }
     77 
     78   Isolate* isolate() const { return isolate_; }
     79 
     80   // Get the caller function object.
     81   JSFunction* GetHostFunction() const;
     82 
     83   inline bool AddressIsDeoptimizedCode() const;
     84   inline static bool AddressIsDeoptimizedCode(Isolate* isolate,
     85                                               Address address);
     86 
     87   bool is_vector_set() { return vector_set_; }
     88   bool vector_needs_update() {
     89     return (!vector_set_ &&
     90             (state() != MEGAMORPHIC ||
     91              Smi::ToInt(nexus()->GetFeedbackExtra()->ToSmi()) != ELEMENT));
     92   }
     93 
     94   // Configure for most states.
     95   bool ConfigureVectorState(IC::State new_state, Handle<Object> key);
     96   // Configure the vector for PREMONOMORPHIC.
     97   void ConfigureVectorState(Handle<Map> map);
     98   // Configure the vector for MONOMORPHIC.
     99   void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
    100                             Handle<Object> handler);
    101   void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
    102                             const MaybeObjectHandle& handler);
    103   // Configure the vector for POLYMORPHIC.
    104   void ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
    105                             MaybeObjectHandles* handlers);
    106 
    107   char TransitionMarkFromState(IC::State state);
    108   void TraceIC(const char* type, Handle<Object> name);
    109   void TraceIC(const char* type, Handle<Object> name, State old_state,
    110                State new_state);
    111 
    112   MaybeHandle<Object> TypeError(MessageTemplate::Template,
    113                                 Handle<Object> object, Handle<Object> key);
    114   MaybeHandle<Object> ReferenceError(Handle<Name> name);
    115 
    116   void TraceHandlerCacheHitStats(LookupIterator* lookup);
    117 
    118   void UpdateMonomorphicIC(const MaybeObjectHandle& handler, Handle<Name> name);
    119   bool UpdatePolymorphicIC(Handle<Name> name, const MaybeObjectHandle& handler);
    120   void UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
    121                               const MaybeObjectHandle& handler);
    122 
    123   StubCache* stub_cache();
    124 
    125   void CopyICToMegamorphicCache(Handle<Name> name);
    126   bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
    127   void PatchCache(Handle<Name> name, Handle<Object> handler);
    128   void PatchCache(Handle<Name> name, const MaybeObjectHandle& handler);
    129   FeedbackSlotKind kind() const { return kind_; }
    130   bool IsGlobalIC() const { return IsLoadGlobalIC() || IsStoreGlobalIC(); }
    131   bool IsLoadIC() const { return IsLoadICKind(kind_); }
    132   bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
    133   bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
    134   bool IsStoreGlobalIC() const { return IsStoreGlobalICKind(kind_); }
    135   bool IsStoreIC() const { return IsStoreICKind(kind_); }
    136   bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
    137   bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
    138   bool is_keyed() const {
    139     return IsKeyedLoadIC() || IsKeyedStoreIC() ||
    140            IsStoreInArrayLiteralICKind(kind_);
    141   }
    142   bool ShouldRecomputeHandler(Handle<String> name);
    143 
    144   Handle<Map> receiver_map() { return receiver_map_; }
    145   inline void update_receiver_map(Handle<Object> receiver);
    146 
    147   void TargetMaps(MapHandles* list) {
    148     FindTargetMaps();
    149     for (Handle<Map> map : target_maps_) {
    150       list->push_back(map);
    151     }
    152   }
    153 
    154   Map* FirstTargetMap() {
    155     FindTargetMaps();
    156     return !target_maps_.empty() ? *target_maps_[0] : nullptr;
    157   }
    158 
    159   State saved_state() const {
    160     return state() == RECOMPUTE_HANDLER ? old_state_ : state();
    161   }
    162 
    163   const FeedbackNexus* nexus() const { return &nexus_; }
    164   FeedbackNexus* nexus() { return &nexus_; }
    165 
    166  private:
    167   inline Address constant_pool() const;
    168   inline Address raw_constant_pool() const;
    169 
    170   void FindTargetMaps() {
    171     if (target_maps_set_) return;
    172     target_maps_set_ = true;
    173     nexus()->ExtractMaps(&target_maps_);
    174   }
    175 
    176   // Frame pointer for the frame that uses (calls) the IC.
    177   Address fp_;
    178 
    179   // All access to the program counter and constant pool of an IC structure is
    180   // indirect to make the code GC safe. This feature is crucial since
    181   // GetProperty and SetProperty are called and they in turn might
    182   // invoke the garbage collector.
    183   Address* pc_address_;
    184 
    185   // The constant pool of the code which originally called the IC (which might
    186   // be for the breakpointed copy of the original code).
    187   Address* constant_pool_address_;
    188 
    189   Isolate* isolate_;
    190 
    191   bool vector_set_;
    192   State old_state_;  // For saving if we marked as prototype failure.
    193   State state_;
    194   FeedbackSlotKind kind_;
    195   Handle<Map> receiver_map_;
    196   MaybeObjectHandle maybe_handler_;
    197 
    198   MapHandles target_maps_;
    199   bool target_maps_set_;
    200 
    201   const char* slow_stub_reason_;
    202 
    203   FeedbackNexus nexus_;
    204 
    205   DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
    206 };
    207 
    208 
    209 class LoadIC : public IC {
    210  public:
    211   LoadIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
    212       : IC(isolate, vector, slot) {
    213     DCHECK(IsAnyLoad());
    214   }
    215 
    216   static bool ShouldThrowReferenceError(FeedbackSlotKind kind) {
    217     return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
    218   }
    219 
    220   bool ShouldThrowReferenceError() const {
    221     return ShouldThrowReferenceError(kind());
    222   }
    223 
    224   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Object> object,
    225                                                  Handle<Name> name);
    226 
    227  protected:
    228   virtual Handle<Code> slow_stub() const {
    229     return BUILTIN_CODE(isolate(), LoadIC_Slow);
    230   }
    231 
    232   // Update the inline cache and the global stub cache based on the
    233   // lookup result.
    234   void UpdateCaches(LookupIterator* lookup);
    235 
    236  private:
    237   Handle<Object> ComputeHandler(LookupIterator* lookup);
    238 
    239   friend class IC;
    240   friend class NamedLoadHandlerCompiler;
    241 };
    242 
    243 class LoadGlobalIC : public LoadIC {
    244  public:
    245   LoadGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
    246                FeedbackSlot slot)
    247       : LoadIC(isolate, vector, slot) {}
    248 
    249   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Name> name);
    250 
    251  protected:
    252   Handle<Code> slow_stub() const override {
    253     return BUILTIN_CODE(isolate(), LoadGlobalIC_Slow);
    254   }
    255 };
    256 
    257 class KeyedLoadIC : public LoadIC {
    258  public:
    259   KeyedLoadIC(Isolate* isolate, Handle<FeedbackVector> vector,
    260               FeedbackSlot slot)
    261       : LoadIC(isolate, vector, slot) {}
    262 
    263   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Object> object,
    264                                                  Handle<Object> key);
    265 
    266  protected:
    267   // receiver is HeapObject because it could be a String or a JSObject
    268   void UpdateLoadElement(Handle<HeapObject> receiver,
    269                          KeyedAccessLoadMode load_mode);
    270 
    271  private:
    272   friend class IC;
    273 
    274   Handle<Object> LoadElementHandler(Handle<Map> receiver_map,
    275                                     KeyedAccessLoadMode load_mode);
    276 
    277   void LoadElementPolymorphicHandlers(MapHandles* receiver_maps,
    278                                       MaybeObjectHandles* handlers,
    279                                       KeyedAccessLoadMode load_mode);
    280 
    281   // Returns true if the receiver_map has a kElement or kIndexedString
    282   // handler in the nexus currently but didn't yet allow out of bounds
    283   // accesses.
    284   bool CanChangeToAllowOutOfBounds(Handle<Map> receiver_map);
    285 };
    286 
    287 
    288 class StoreIC : public IC {
    289  public:
    290   StoreIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
    291       : IC(isolate, vector, slot) {
    292     DCHECK(IsAnyStore());
    293   }
    294 
    295   LanguageMode language_mode() const { return nexus()->GetLanguageMode(); }
    296 
    297   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(
    298       Handle<Object> object, Handle<Name> name, Handle<Object> value,
    299       JSReceiver::StoreFromKeyed store_mode =
    300           JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
    301 
    302   bool LookupForWrite(LookupIterator* it, Handle<Object> value,
    303                       JSReceiver::StoreFromKeyed store_mode);
    304 
    305  protected:
    306   // Stub accessors.
    307   virtual Handle<Code> slow_stub() const {
    308     // All StoreICs share the same slow stub.
    309     return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
    310   }
    311 
    312   // Update the inline cache and the global stub cache based on the
    313   // lookup result.
    314   void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
    315                     JSReceiver::StoreFromKeyed store_mode);
    316 
    317  private:
    318   MaybeObjectHandle ComputeHandler(LookupIterator* lookup);
    319 
    320   friend class IC;
    321 };
    322 
    323 class StoreGlobalIC : public StoreIC {
    324  public:
    325   StoreGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
    326                 FeedbackSlot slot)
    327       : StoreIC(isolate, vector, slot) {}
    328 
    329   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Name> name,
    330                                                   Handle<Object> value);
    331 
    332  protected:
    333   Handle<Code> slow_stub() const override {
    334     return BUILTIN_CODE(isolate(), StoreGlobalIC_Slow);
    335   }
    336 };
    337 
    338 enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
    339 
    340 
    341 enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
    342 
    343 
    344 class KeyedStoreIC : public StoreIC {
    345  public:
    346   KeyedAccessStoreMode GetKeyedAccessStoreMode() {
    347     return nexus()->GetKeyedAccessStoreMode();
    348   }
    349 
    350   KeyedStoreIC(Isolate* isolate, Handle<FeedbackVector> vector,
    351                FeedbackSlot slot)
    352       : StoreIC(isolate, vector, slot) {}
    353 
    354   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Object> object,
    355                                                   Handle<Object> name,
    356                                                   Handle<Object> value);
    357 
    358  protected:
    359   void UpdateStoreElement(Handle<Map> receiver_map,
    360                           KeyedAccessStoreMode store_mode,
    361                           bool receiver_was_cow);
    362 
    363   Handle<Code> slow_stub() const override {
    364     return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
    365   }
    366 
    367  private:
    368   Handle<Map> ComputeTransitionedMap(Handle<Map> map,
    369                                      KeyedAccessStoreMode store_mode);
    370 
    371   Handle<Object> StoreElementHandler(Handle<Map> receiver_map,
    372                                      KeyedAccessStoreMode store_mode);
    373 
    374   void StoreElementPolymorphicHandlers(MapHandles* receiver_maps,
    375                                        MaybeObjectHandles* handlers,
    376                                        KeyedAccessStoreMode store_mode);
    377 
    378   friend class IC;
    379 };
    380 
    381 class StoreInArrayLiteralIC : public KeyedStoreIC {
    382  public:
    383   StoreInArrayLiteralIC(Isolate* isolate, Handle<FeedbackVector> vector,
    384                         FeedbackSlot slot)
    385       : KeyedStoreIC(isolate, vector, slot) {
    386     DCHECK(IsStoreInArrayLiteralICKind(kind()));
    387   }
    388 
    389   void Store(Handle<JSArray> array, Handle<Object> index, Handle<Object> value);
    390 
    391  private:
    392   Handle<Code> slow_stub() const override {
    393     return BUILTIN_CODE(isolate(), StoreInArrayLiteralIC_Slow);
    394   }
    395 };
    396 
    397 }  // namespace internal
    398 }  // namespace v8
    399 
    400 #endif  // V8_IC_IC_H_
    401