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_H_
      6 #define V8_IC_H_
      7 
      8 #include "src/factory.h"
      9 #include "src/feedback-vector.h"
     10 #include "src/ic/ic-state.h"
     11 #include "src/macro-assembler.h"
     12 #include "src/messages.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 
     17 //
     18 // IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC.
     19 //
     20 class IC {
     21  public:
     22   // Alias the inline cache state type to make the IC code more readable.
     23   typedef InlineCacheState State;
     24 
     25   // The IC code is either invoked with no extra frames on the stack
     26   // or with a single extra frame for supporting calls.
     27   enum FrameDepth { NO_EXTRA_FRAME = 0, EXTRA_CALL_FRAME = 1 };
     28 
     29   // Construct the IC structure with the given number of extra
     30   // JavaScript frames on the stack.
     31   IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL);
     32   virtual ~IC() {}
     33 
     34   State state() const { return state_; }
     35   inline Address address() const;
     36 
     37   // Compute the current IC state based on the target stub, receiver and name.
     38   void UpdateState(Handle<Object> receiver, Handle<Object> name);
     39 
     40   bool RecomputeHandlerForName(Handle<Object> name);
     41   void MarkRecomputeHandler(Handle<Object> name) {
     42     DCHECK(RecomputeHandlerForName(name));
     43     old_state_ = state_;
     44     state_ = RECOMPUTE_HANDLER;
     45   }
     46 
     47   // Clear the inline cache to initial state.
     48   static void Clear(Isolate* isolate, Address address, Address constant_pool);
     49 
     50   bool IsAnyLoad() const {
     51     return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
     52   }
     53   bool IsAnyStore() const {
     54     return IsStoreIC() || IsStoreOwnIC() || IsKeyedStoreIC();
     55   }
     56 
     57   static inline Handle<Map> GetHandlerCacheHolder(Handle<Map> receiver_map,
     58                                                   bool receiver_is_holder,
     59                                                   Isolate* isolate,
     60                                                   CacheHolderFlag* flag);
     61   static inline Handle<Map> GetICCacheHolder(Handle<Map> receiver_map,
     62                                              Isolate* isolate,
     63                                              CacheHolderFlag* flag);
     64 
     65   static bool ICUseVector(Code::Kind kind) {
     66     return kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC ||
     67            kind == Code::KEYED_LOAD_IC || kind == Code::STORE_IC ||
     68            kind == Code::KEYED_STORE_IC;
     69   }
     70   static bool ICUseVector(FeedbackSlotKind kind) {
     71     return IsLoadICKind(kind) || IsLoadGlobalICKind(kind) ||
     72            IsKeyedLoadICKind(kind) || IsStoreICKind(kind) ||
     73            IsStoreOwnICKind(kind) || IsKeyedStoreICKind(kind);
     74   }
     75 
     76   // The ICs that don't pass slot and vector through the stack have to
     77   // save/restore them in the dispatcher.
     78   static bool ShouldPushPopSlotAndVector(Code::Kind kind);
     79 
     80   static InlineCacheState StateFromCode(Code* code);
     81 
     82   static inline bool IsHandler(Object* object);
     83 
     84   // Nofity the IC system that a feedback has changed.
     85   static void OnFeedbackChanged(Isolate* isolate, JSFunction* host_function);
     86 
     87  protected:
     88   Address fp() const { return fp_; }
     89   Address pc() const { return *pc_address_; }
     90 
     91   void set_slow_stub_reason(const char* reason) { slow_stub_reason_ = reason; }
     92 
     93   Address GetAbstractPC(int* line, int* column) const;
     94   Isolate* isolate() const { return isolate_; }
     95 
     96   // Get the caller function object.
     97   JSFunction* GetHostFunction() const;
     98 
     99   inline bool AddressIsDeoptimizedCode() const;
    100   inline static bool AddressIsDeoptimizedCode(Isolate* isolate,
    101                                               Address address);
    102 
    103   // Set the call-site target.
    104   inline void set_target(Code* code);
    105   bool is_vector_set() { return vector_set_; }
    106 
    107   bool UseVector() const {
    108     bool use = ICUseVector(kind());
    109     // If we are supposed to use the nexus, verify the nexus is non-null.
    110     DCHECK(!use || nexus_ != nullptr);
    111     return use;
    112   }
    113 
    114   // Configure for most states.
    115   void ConfigureVectorState(IC::State new_state, Handle<Object> key);
    116   // Configure the vector for MONOMORPHIC.
    117   void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
    118                             Handle<Object> handler);
    119   // Configure the vector for POLYMORPHIC.
    120   void ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
    121                             List<Handle<Object>>* handlers);
    122   // Configure the vector for POLYMORPHIC with transitions (only for element
    123   // keyed stores).
    124   void ConfigureVectorState(MapHandleList* maps,
    125                             MapHandleList* transitioned_maps,
    126                             List<Handle<Object>>* handlers);
    127 
    128   char TransitionMarkFromState(IC::State state);
    129   void TraceIC(const char* type, Handle<Object> name);
    130   void TraceIC(const char* type, Handle<Object> name, State old_state,
    131                State new_state);
    132 
    133   MaybeHandle<Object> TypeError(MessageTemplate::Template,
    134                                 Handle<Object> object, Handle<Object> key);
    135   MaybeHandle<Object> ReferenceError(Handle<Name> name);
    136 
    137   // Access the target code for the given IC address.
    138   static inline Code* GetTargetAtAddress(Address address,
    139                                          Address constant_pool);
    140   static inline void SetTargetAtAddress(Address address, Code* target,
    141                                         Address constant_pool);
    142   static void PostPatching(Address address, Code* target, Code* old_target);
    143 
    144   void TraceHandlerCacheHitStats(LookupIterator* lookup);
    145 
    146   // Compute the handler either by compiling or by retrieving a cached version.
    147   Handle<Object> ComputeHandler(LookupIterator* lookup,
    148                                 Handle<Object> value = Handle<Code>::null());
    149   virtual Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) {
    150     UNREACHABLE();
    151     return Handle<Code>::null();
    152   }
    153   virtual Handle<Object> CompileHandler(LookupIterator* lookup,
    154                                         Handle<Object> value,
    155                                         CacheHolderFlag cache_holder) {
    156     UNREACHABLE();
    157     return Handle<Object>::null();
    158   }
    159 
    160   void UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name);
    161   bool UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code);
    162   void UpdateMegamorphicCache(Map* map, Name* name, Object* code);
    163 
    164   StubCache* stub_cache();
    165 
    166   void CopyICToMegamorphicCache(Handle<Name> name);
    167   bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
    168   void PatchCache(Handle<Name> name, Handle<Object> code);
    169   FeedbackSlotKind kind() const { return kind_; }
    170   bool IsLoadIC() const { return IsLoadICKind(kind_); }
    171   bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
    172   bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
    173   bool IsStoreIC() const { return IsStoreICKind(kind_); }
    174   bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
    175   bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
    176   bool is_keyed() const { return IsKeyedLoadIC() || IsKeyedStoreIC(); }
    177   Code::Kind handler_kind() const {
    178     if (IsAnyLoad()) return Code::LOAD_IC;
    179     DCHECK(IsAnyStore());
    180     return Code::STORE_IC;
    181   }
    182   bool ShouldRecomputeHandler(Handle<String> name);
    183 
    184   ExtraICState extra_ic_state() const { return extra_ic_state_; }
    185 
    186   Handle<Map> receiver_map() { return receiver_map_; }
    187   void update_receiver_map(Handle<Object> receiver) {
    188     if (receiver->IsSmi()) {
    189       receiver_map_ = isolate_->factory()->heap_number_map();
    190     } else {
    191       receiver_map_ = handle(HeapObject::cast(*receiver)->map());
    192     }
    193   }
    194 
    195   void TargetMaps(MapHandleList* list) {
    196     FindTargetMaps();
    197     for (int i = 0; i < target_maps_.length(); i++) {
    198       list->Add(target_maps_.at(i));
    199     }
    200   }
    201 
    202   Map* FirstTargetMap() {
    203     FindTargetMaps();
    204     return target_maps_.length() > 0 ? *target_maps_.at(0) : NULL;
    205   }
    206 
    207   Handle<FeedbackVector> vector() const { return nexus()->vector_handle(); }
    208   FeedbackSlot slot() const { return nexus()->slot(); }
    209   State saved_state() const {
    210     return state() == RECOMPUTE_HANDLER ? old_state_ : state();
    211   }
    212 
    213   template <class NexusClass>
    214   NexusClass* casted_nexus() {
    215     return static_cast<NexusClass*>(nexus_);
    216   }
    217   FeedbackNexus* nexus() const { return nexus_; }
    218 
    219   inline Code* target() const;
    220 
    221  private:
    222   inline Address constant_pool() const;
    223   inline Address raw_constant_pool() const;
    224 
    225   void FindTargetMaps() {
    226     if (target_maps_set_) return;
    227     target_maps_set_ = true;
    228     DCHECK(UseVector());
    229     nexus()->ExtractMaps(&target_maps_);
    230   }
    231 
    232   // Frame pointer for the frame that uses (calls) the IC.
    233   Address fp_;
    234 
    235   // All access to the program counter and constant pool of an IC structure is
    236   // indirect to make the code GC safe. This feature is crucial since
    237   // GetProperty and SetProperty are called and they in turn might
    238   // invoke the garbage collector.
    239   Address* pc_address_;
    240 
    241   // The constant pool of the code which originally called the IC (which might
    242   // be for the breakpointed copy of the original code).
    243   Address* constant_pool_address_;
    244 
    245   Isolate* isolate_;
    246 
    247   bool vector_set_;
    248   State old_state_;  // For saving if we marked as prototype failure.
    249   State state_;
    250   FeedbackSlotKind kind_;
    251   Handle<Map> receiver_map_;
    252   MaybeHandle<Object> maybe_handler_;
    253 
    254   ExtraICState extra_ic_state_;
    255   MapHandleList target_maps_;
    256   bool target_maps_set_;
    257 
    258   const char* slow_stub_reason_;
    259 
    260   FeedbackNexus* nexus_;
    261 
    262   DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
    263 };
    264 
    265 
    266 class CallIC : public IC {
    267  public:
    268   CallIC(Isolate* isolate, CallICNexus* nexus)
    269       : IC(EXTRA_CALL_FRAME, isolate, nexus) {
    270     DCHECK(nexus != NULL);
    271   }
    272 };
    273 
    274 
    275 class LoadIC : public IC {
    276  public:
    277   LoadIC(Isolate* isolate, FeedbackNexus* nexus)
    278       : IC(NO_EXTRA_FRAME, isolate, nexus) {
    279     DCHECK(nexus != NULL);
    280     DCHECK(IsAnyLoad());
    281   }
    282 
    283   static bool ShouldThrowReferenceError(FeedbackSlotKind kind) {
    284     return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
    285   }
    286 
    287   bool ShouldThrowReferenceError() const {
    288     return ShouldThrowReferenceError(kind());
    289   }
    290 
    291   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
    292                                            Handle<Name> name);
    293 
    294  protected:
    295   virtual Handle<Code> slow_stub() const {
    296     return isolate()->builtins()->LoadIC_Slow();
    297   }
    298 
    299   // Update the inline cache and the global stub cache based on the
    300   // lookup result.
    301   void UpdateCaches(LookupIterator* lookup);
    302 
    303   Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
    304 
    305   Handle<Object> CompileHandler(LookupIterator* lookup, Handle<Object> unused,
    306                                 CacheHolderFlag cache_holder) override;
    307 
    308  private:
    309   // Creates a data handler that represents a load of a field by given index.
    310   static Handle<Object> SimpleFieldLoad(Isolate* isolate, FieldIndex index);
    311 
    312   // Creates a data handler that represents a prototype chain check followed
    313   // by given Smi-handler that encoded a load from the holder.
    314   // Can be used only if GetPrototypeCheckCount() returns non negative value.
    315   Handle<Object> LoadFromPrototype(Handle<Map> receiver_map,
    316                                    Handle<JSObject> holder, Handle<Name> name,
    317                                    Handle<Object> smi_handler);
    318 
    319   // Creates a data handler that represents a load of a non-existent property.
    320   Handle<Object> LoadNonExistent(Handle<Map> receiver_map, Handle<Name> name);
    321 
    322   friend class IC;
    323   friend class NamedLoadHandlerCompiler;
    324 };
    325 
    326 class LoadGlobalIC : public LoadIC {
    327  public:
    328   LoadGlobalIC(Isolate* isolate, FeedbackNexus* nexus)
    329       : LoadIC(isolate, nexus) {}
    330 
    331   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Name> name);
    332 
    333  protected:
    334   Handle<Code> slow_stub() const override {
    335     return isolate()->builtins()->LoadGlobalIC_Slow();
    336   }
    337 };
    338 
    339 class KeyedLoadIC : public LoadIC {
    340  public:
    341   KeyedLoadIC(Isolate* isolate, KeyedLoadICNexus* nexus)
    342       : LoadIC(isolate, nexus) {
    343     DCHECK(nexus != NULL);
    344   }
    345 
    346   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
    347                                            Handle<Object> key);
    348 
    349  protected:
    350   // receiver is HeapObject because it could be a String or a JSObject
    351   void UpdateLoadElement(Handle<HeapObject> receiver);
    352 
    353  private:
    354   friend class IC;
    355 };
    356 
    357 
    358 class StoreIC : public IC {
    359  public:
    360   StoreIC(Isolate* isolate, FeedbackNexus* nexus)
    361       : IC(NO_EXTRA_FRAME, isolate, nexus) {
    362     DCHECK(IsAnyStore());
    363   }
    364 
    365   LanguageMode language_mode() const {
    366     return nexus()->vector()->GetLanguageMode(nexus()->slot());
    367   }
    368 
    369   MUST_USE_RESULT MaybeHandle<Object> Store(
    370       Handle<Object> object, Handle<Name> name, Handle<Object> value,
    371       JSReceiver::StoreFromKeyed store_mode =
    372           JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
    373 
    374   bool LookupForWrite(LookupIterator* it, Handle<Object> value,
    375                       JSReceiver::StoreFromKeyed store_mode);
    376 
    377  protected:
    378   // Stub accessors.
    379   Handle<Code> slow_stub() const {
    380     // StoreIC and KeyedStoreIC share the same slow stub.
    381     return isolate()->builtins()->KeyedStoreIC_Slow();
    382   }
    383 
    384   // Update the inline cache and the global stub cache based on the
    385   // lookup result.
    386   void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
    387                     JSReceiver::StoreFromKeyed store_mode);
    388   Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
    389   Handle<Object> CompileHandler(LookupIterator* lookup, Handle<Object> value,
    390                                 CacheHolderFlag cache_holder) override;
    391 
    392  private:
    393   Handle<Object> StoreTransition(Handle<Map> receiver_map,
    394                                  Handle<JSObject> holder,
    395                                  Handle<Map> transition, Handle<Name> name);
    396 
    397   friend class IC;
    398 };
    399 
    400 
    401 enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
    402 
    403 
    404 enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
    405 
    406 
    407 class KeyedStoreIC : public StoreIC {
    408  public:
    409   KeyedAccessStoreMode GetKeyedAccessStoreMode() {
    410     return casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
    411   }
    412 
    413   KeyedStoreIC(Isolate* isolate, KeyedStoreICNexus* nexus)
    414       : StoreIC(isolate, nexus) {}
    415 
    416   MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object,
    417                                             Handle<Object> name,
    418                                             Handle<Object> value);
    419 
    420  protected:
    421   void UpdateStoreElement(Handle<Map> receiver_map,
    422                           KeyedAccessStoreMode store_mode);
    423 
    424  private:
    425   Handle<Map> ComputeTransitionedMap(Handle<Map> map,
    426                                      KeyedAccessStoreMode store_mode);
    427 
    428   Handle<Object> StoreElementHandler(Handle<Map> receiver_map,
    429                                      KeyedAccessStoreMode store_mode);
    430 
    431   void StoreElementPolymorphicHandlers(MapHandleList* receiver_maps,
    432                                        MapHandleList* transitioned_maps,
    433                                        List<Handle<Object>>* handlers,
    434                                        KeyedAccessStoreMode store_mode);
    435 
    436   friend class IC;
    437 };
    438 
    439 
    440 // Type Recording BinaryOpIC, that records the types of the inputs and outputs.
    441 class BinaryOpIC : public IC {
    442  public:
    443   explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
    444 
    445   MaybeHandle<Object> Transition(Handle<AllocationSite> allocation_site,
    446                                  Handle<Object> left,
    447                                  Handle<Object> right) WARN_UNUSED_RESULT;
    448 };
    449 
    450 
    451 class CompareIC : public IC {
    452  public:
    453   CompareIC(Isolate* isolate, Token::Value op)
    454       : IC(EXTRA_CALL_FRAME, isolate), op_(op) {}
    455 
    456   // Update the inline cache for the given operands.
    457   Code* UpdateCaches(Handle<Object> x, Handle<Object> y);
    458 
    459   // Helper function for computing the condition for a compare operation.
    460   static Condition ComputeCondition(Token::Value op);
    461 
    462  private:
    463   static bool HasInlinedSmiCode(Address address);
    464 
    465   bool strict() const { return op_ == Token::EQ_STRICT; }
    466   Condition GetCondition() const { return ComputeCondition(op_); }
    467 
    468   static Code* GetRawUninitialized(Isolate* isolate, Token::Value op);
    469 
    470   static void Clear(Isolate* isolate, Address address, Code* target,
    471                     Address constant_pool);
    472 
    473   Token::Value op_;
    474 
    475   friend class IC;
    476 };
    477 
    478 
    479 class ToBooleanIC : public IC {
    480  public:
    481   explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
    482 
    483   Handle<Object> ToBoolean(Handle<Object> object);
    484 };
    485 
    486 
    487 // Helper for BinaryOpIC and CompareIC.
    488 enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
    489 void PatchInlinedSmiCode(Isolate* isolate, Address address,
    490                          InlinedSmiCheck check);
    491 
    492 }  // namespace internal
    493 }  // namespace v8
    494 
    495 #endif  // V8_IC_H_
    496