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