Home | History | Annotate | Download | only in src
      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/macro-assembler.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 
     13 
     14 const int kMaxKeyedPolymorphism = 4;
     15 
     16 
     17 // IC_UTIL_LIST defines all utility functions called from generated
     18 // inline caching code. The argument for the macro, ICU, is the function name.
     19 #define IC_UTIL_LIST(ICU)                             \
     20   ICU(LoadIC_Miss)                                    \
     21   ICU(KeyedLoadIC_Miss)                               \
     22   ICU(CallIC_Miss)                                    \
     23   ICU(CallIC_Customization_Miss)                      \
     24   ICU(StoreIC_Miss)                                   \
     25   ICU(StoreIC_ArrayLength)                            \
     26   ICU(StoreIC_Slow)                                   \
     27   ICU(SharedStoreIC_ExtendStorage)                    \
     28   ICU(KeyedStoreIC_Miss)                              \
     29   ICU(KeyedStoreIC_Slow)                              \
     30   /* Utilities for IC stubs. */                       \
     31   ICU(StoreCallbackProperty)                          \
     32   ICU(LoadPropertyWithInterceptorOnly)                \
     33   ICU(LoadPropertyWithInterceptor)                    \
     34   ICU(KeyedLoadPropertyWithInterceptor)               \
     35   ICU(StoreInterceptorProperty)                       \
     36   ICU(CompareIC_Miss)                                 \
     37   ICU(BinaryOpIC_Miss)                                \
     38   ICU(CompareNilIC_Miss)                              \
     39   ICU(Unreachable)                                    \
     40   ICU(ToBooleanIC_Miss)
     41 //
     42 // IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC.
     43 //
     44 class IC {
     45  public:
     46   // The ids for utility called from the generated code.
     47   enum UtilityId {
     48   #define CONST_NAME(name) k##name,
     49     IC_UTIL_LIST(CONST_NAME)
     50   #undef CONST_NAME
     51     kUtilityCount
     52   };
     53 
     54   // Looks up the address of the named utility.
     55   static Address AddressFromUtilityId(UtilityId id);
     56 
     57   // Alias the inline cache state type to make the IC code more readable.
     58   typedef InlineCacheState State;
     59 
     60   // The IC code is either invoked with no extra frames on the stack
     61   // or with a single extra frame for supporting calls.
     62   enum FrameDepth {
     63     NO_EXTRA_FRAME = 0,
     64     EXTRA_CALL_FRAME = 1
     65   };
     66 
     67   // Construct the IC structure with the given number of extra
     68   // JavaScript frames on the stack.
     69   IC(FrameDepth depth, Isolate* isolate);
     70   virtual ~IC() {}
     71 
     72   State state() const { return state_; }
     73   inline Address address() const;
     74 
     75   // Compute the current IC state based on the target stub, receiver and name.
     76   void UpdateState(Handle<Object> receiver, Handle<Object> name);
     77 
     78   bool IsNameCompatibleWithMonomorphicPrototypeFailure(Handle<Object> name);
     79   bool TryMarkMonomorphicPrototypeFailure(Handle<Object> name) {
     80     if (IsNameCompatibleWithMonomorphicPrototypeFailure(name)) {
     81       state_ = MONOMORPHIC_PROTOTYPE_FAILURE;
     82       return true;
     83     }
     84     return false;
     85   }
     86 
     87   // If the stub contains weak maps then this function adds the stub to
     88   // the dependent code array of each weak map.
     89   static void RegisterWeakMapDependency(Handle<Code> stub);
     90 
     91   // This function is called when a weak map in the stub is dying,
     92   // invalidates the stub by setting maps in it to undefined.
     93   static void InvalidateMaps(Code* stub);
     94 
     95   // Clear the inline cache to initial state.
     96   static void Clear(Isolate* isolate,
     97                     Address address,
     98                     ConstantPoolArray* constant_pool);
     99 
    100 #ifdef DEBUG
    101   bool IsLoadStub() const {
    102     return target()->is_load_stub() || target()->is_keyed_load_stub();
    103   }
    104 
    105   bool IsStoreStub() const {
    106     return target()->is_store_stub() || target()->is_keyed_store_stub();
    107   }
    108 
    109   bool IsCallStub() const {
    110     return target()->is_call_stub();
    111   }
    112 #endif
    113 
    114   // Determines which map must be used for keeping the code stub.
    115   // These methods should not be called with undefined or null.
    116   static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object);
    117   // TODO(verwaest): This currently returns a HeapObject rather than JSObject*
    118   // since loading the IC for loading the length from strings are stored on
    119   // the string map directly, rather than on the JSObject-typed prototype.
    120   static inline HeapObject* GetCodeCacheHolder(Isolate* isolate,
    121                                                Object* object,
    122                                                InlineCacheHolderFlag holder);
    123 
    124   static inline InlineCacheHolderFlag GetCodeCacheFlag(HeapType* type);
    125   static inline Handle<Map> GetCodeCacheHolder(InlineCacheHolderFlag flag,
    126                                                HeapType* type,
    127                                                Isolate* isolate);
    128 
    129   static bool IsCleared(Code* code) {
    130     InlineCacheState state = code->ic_state();
    131     return state == UNINITIALIZED || state == PREMONOMORPHIC;
    132   }
    133 
    134   // Utility functions to convert maps to types and back. There are two special
    135   // cases:
    136   // - The heap_number_map is used as a marker which includes heap numbers as
    137   //   well as smis.
    138   // - The oddball map is only used for booleans.
    139   static Handle<Map> TypeToMap(HeapType* type, Isolate* isolate);
    140   template <class T>
    141   static typename T::TypeHandle MapToType(Handle<Map> map,
    142                                           typename T::Region* region);
    143 
    144   static Handle<HeapType> CurrentTypeOf(Handle<Object> object,
    145                                         Isolate* isolate);
    146 
    147  protected:
    148   // Get the call-site target; used for determining the state.
    149   Handle<Code> target() const { return target_; }
    150 
    151   Address fp() const { return fp_; }
    152   Address pc() const { return *pc_address_; }
    153   Isolate* isolate() const { return isolate_; }
    154 
    155   // Get the shared function info of the caller.
    156   SharedFunctionInfo* GetSharedFunctionInfo() const;
    157   // Get the code object of the caller.
    158   Code* GetCode() const;
    159   // Get the original (non-breakpointed) code object of the caller.
    160   Code* GetOriginalCode() const;
    161 
    162   // Set the call-site target.
    163   void set_target(Code* code) {
    164 #ifdef VERIFY_HEAP
    165     code->VerifyEmbeddedObjectsDependency();
    166 #endif
    167     SetTargetAtAddress(address(), code, constant_pool());
    168     target_set_ = true;
    169   }
    170 
    171   bool is_target_set() { return target_set_; }
    172 
    173 #ifdef DEBUG
    174   char TransitionMarkFromState(IC::State state);
    175 
    176   void TraceIC(const char* type, Handle<Object> name);
    177 #endif
    178 
    179   MaybeHandle<Object> TypeError(const char* type,
    180                                 Handle<Object> object,
    181                                 Handle<Object> key);
    182   MaybeHandle<Object> ReferenceError(const char* type, Handle<String> name);
    183 
    184   // Access the target code for the given IC address.
    185   static inline Code* GetTargetAtAddress(Address address,
    186                                          ConstantPoolArray* constant_pool);
    187   static inline void SetTargetAtAddress(Address address,
    188                                         Code* target,
    189                                         ConstantPoolArray* constant_pool);
    190   static void PostPatching(Address address, Code* target, Code* old_target);
    191 
    192   // Compute the handler either by compiling or by retrieving a cached version.
    193   Handle<Code> ComputeHandler(LookupResult* lookup,
    194                               Handle<Object> object,
    195                               Handle<String> name,
    196                               Handle<Object> value = Handle<Code>::null());
    197   virtual Handle<Code> CompileHandler(LookupResult* lookup,
    198                                       Handle<Object> object,
    199                                       Handle<String> name,
    200                                       Handle<Object> value,
    201                                       InlineCacheHolderFlag cache_holder) {
    202     UNREACHABLE();
    203     return Handle<Code>::null();
    204   }
    205 
    206   void UpdateMonomorphicIC(Handle<HeapType> type,
    207                            Handle<Code> handler,
    208                            Handle<String> name);
    209 
    210   bool UpdatePolymorphicIC(Handle<HeapType> type,
    211                            Handle<String> name,
    212                            Handle<Code> code);
    213 
    214   virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code);
    215 
    216   void CopyICToMegamorphicCache(Handle<String> name);
    217   bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
    218   void PatchCache(Handle<HeapType> type,
    219                   Handle<String> name,
    220                   Handle<Code> code);
    221   virtual Code::Kind kind() const {
    222     UNREACHABLE();
    223     return Code::STUB;
    224   }
    225   virtual Handle<Code> slow_stub() const {
    226     UNREACHABLE();
    227     return Handle<Code>::null();
    228   }
    229   virtual Handle<Code> megamorphic_stub() {
    230     UNREACHABLE();
    231     return Handle<Code>::null();
    232   }
    233   virtual Handle<Code> generic_stub() const {
    234     UNREACHABLE();
    235     return Handle<Code>::null();
    236   }
    237 
    238   bool TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
    239                                               Handle<String> name);
    240   void TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name);
    241 
    242   ExtraICState extra_ic_state() const { return extra_ic_state_; }
    243   void set_extra_ic_state(ExtraICState state) {
    244     extra_ic_state_ = state;
    245   }
    246 
    247   void TargetMaps(MapHandleList* list) {
    248     FindTargetMaps();
    249     for (int i = 0; i < target_maps_.length(); i++) {
    250       list->Add(target_maps_.at(i));
    251     }
    252   }
    253 
    254   void TargetTypes(TypeHandleList* list) {
    255     FindTargetMaps();
    256     for (int i = 0; i < target_maps_.length(); i++) {
    257       list->Add(IC::MapToType<HeapType>(target_maps_.at(i), isolate_));
    258     }
    259   }
    260 
    261   Map* FirstTargetMap() {
    262     FindTargetMaps();
    263     return target_maps_.length() > 0 ? *target_maps_.at(0) : NULL;
    264   }
    265 
    266  protected:
    267   void UpdateTarget() {
    268     target_ = handle(raw_target(), isolate_);
    269   }
    270 
    271  private:
    272   Code* raw_target() const {
    273     return GetTargetAtAddress(address(), constant_pool());
    274   }
    275   inline ConstantPoolArray* constant_pool() const;
    276   inline ConstantPoolArray* raw_constant_pool() const;
    277 
    278   void FindTargetMaps() {
    279     if (target_maps_set_) return;
    280     target_maps_set_ = true;
    281     if (state_ == MONOMORPHIC) {
    282       Map* map = target_->FindFirstMap();
    283       if (map != NULL) target_maps_.Add(handle(map));
    284     } else if (state_ != UNINITIALIZED && state_ != PREMONOMORPHIC) {
    285       target_->FindAllMaps(&target_maps_);
    286     }
    287   }
    288 
    289   // Frame pointer for the frame that uses (calls) the IC.
    290   Address fp_;
    291 
    292   // All access to the program counter of an IC structure is indirect
    293   // to make the code GC safe. This feature is crucial since
    294   // GetProperty and SetProperty are called and they in turn might
    295   // invoke the garbage collector.
    296   Address* pc_address_;
    297 
    298   Isolate* isolate_;
    299 
    300   // The constant pool of the code which originally called the IC (which might
    301   // be for the breakpointed copy of the original code).
    302   Handle<ConstantPoolArray> raw_constant_pool_;
    303 
    304   // The original code target that missed.
    305   Handle<Code> target_;
    306   State state_;
    307   bool target_set_;
    308 
    309   ExtraICState extra_ic_state_;
    310   MapHandleList target_maps_;
    311   bool target_maps_set_;
    312 
    313   DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
    314 };
    315 
    316 
    317 // An IC_Utility encapsulates IC::UtilityId. It exists mainly because you
    318 // cannot make forward declarations to an enum.
    319 class IC_Utility {
    320  public:
    321   explicit IC_Utility(IC::UtilityId id)
    322     : address_(IC::AddressFromUtilityId(id)), id_(id) {}
    323 
    324   Address address() const { return address_; }
    325 
    326   IC::UtilityId id() const { return id_; }
    327  private:
    328   Address address_;
    329   IC::UtilityId id_;
    330 };
    331 
    332 
    333 class CallIC: public IC {
    334  public:
    335   enum CallType { METHOD, FUNCTION };
    336 
    337   class State V8_FINAL BASE_EMBEDDED {
    338    public:
    339     explicit State(ExtraICState extra_ic_state);
    340 
    341     State(int argc, CallType call_type)
    342         : argc_(argc), call_type_(call_type) {
    343     }
    344 
    345     InlineCacheState GetICState() const { return ::v8::internal::GENERIC; }
    346 
    347     ExtraICState GetExtraICState() const;
    348 
    349     static void GenerateAheadOfTime(
    350         Isolate*, void (*Generate)(Isolate*, const State&));
    351 
    352     int arg_count() const { return argc_; }
    353     CallType call_type() const { return call_type_; }
    354 
    355     bool CallAsMethod() const { return call_type_ == METHOD; }
    356 
    357     void Print(StringStream* stream) const;
    358 
    359    private:
    360     class ArgcBits: public BitField<int, 0, Code::kArgumentsBits> {};
    361     class CallTypeBits: public BitField<CallType, Code::kArgumentsBits, 1> {};
    362 
    363     const int argc_;
    364     const CallType call_type_;
    365   };
    366 
    367   explicit CallIC(Isolate* isolate)
    368       : IC(EXTRA_CALL_FRAME, isolate) {
    369   }
    370 
    371   void PatchMegamorphic(Handle<FixedArray> vector, Handle<Smi> slot);
    372 
    373   void HandleMiss(Handle<Object> receiver,
    374                   Handle<Object> function,
    375                   Handle<FixedArray> vector,
    376                   Handle<Smi> slot);
    377 
    378   // Returns true if a custom handler was installed.
    379   bool DoCustomHandler(Handle<Object> receiver,
    380                        Handle<Object> function,
    381                        Handle<FixedArray> vector,
    382                        Handle<Smi> slot,
    383                        const State& state);
    384 
    385   // Code generator routines.
    386   static Handle<Code> initialize_stub(Isolate* isolate,
    387                                       int argc,
    388                                       CallType call_type);
    389 
    390   static void Clear(Isolate* isolate, Address address, Code* target,
    391                     ConstantPoolArray* constant_pool);
    392 };
    393 
    394 
    395 class LoadIC: public IC {
    396  public:
    397   // ExtraICState bits
    398   class ContextualModeBits: public BitField<ContextualMode, 0, 1> {};
    399   STATIC_ASSERT(static_cast<int>(NOT_CONTEXTUAL) == 0);
    400 
    401   static ExtraICState ComputeExtraICState(ContextualMode contextual_mode) {
    402     return ContextualModeBits::encode(contextual_mode);
    403   }
    404 
    405   static ContextualMode GetContextualMode(ExtraICState state) {
    406     return ContextualModeBits::decode(state);
    407   }
    408 
    409   ContextualMode contextual_mode() const {
    410     return ContextualModeBits::decode(extra_ic_state());
    411   }
    412 
    413   explicit LoadIC(FrameDepth depth, Isolate* isolate)
    414       : IC(depth, isolate) {
    415     ASSERT(IsLoadStub());
    416   }
    417 
    418   // Returns if this IC is for contextual (no explicit receiver)
    419   // access to properties.
    420   bool IsUndeclaredGlobal(Handle<Object> receiver) {
    421     if (receiver->IsGlobalObject()) {
    422       return contextual_mode() == CONTEXTUAL;
    423     } else {
    424       ASSERT(contextual_mode() != CONTEXTUAL);
    425       return false;
    426     }
    427   }
    428 
    429   // Code generator routines.
    430   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
    431   static void GeneratePreMonomorphic(MacroAssembler* masm) {
    432     GenerateMiss(masm);
    433   }
    434   static void GenerateMiss(MacroAssembler* masm);
    435   static void GenerateMegamorphic(MacroAssembler* masm);
    436   static void GenerateNormal(MacroAssembler* masm);
    437   static void GenerateRuntimeGetProperty(MacroAssembler* masm);
    438 
    439   static Handle<Code> initialize_stub(Isolate* isolate,
    440                                       ExtraICState extra_state);
    441 
    442   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
    443                                            Handle<String> name);
    444 
    445  protected:
    446   virtual Code::Kind kind() const { return Code::LOAD_IC; }
    447 
    448   void set_target(Code* code) {
    449     // The contextual mode must be preserved across IC patching.
    450     ASSERT(GetContextualMode(code->extra_ic_state()) ==
    451            GetContextualMode(target()->extra_ic_state()));
    452 
    453     IC::set_target(code);
    454   }
    455 
    456   virtual Handle<Code> slow_stub() const {
    457     return isolate()->builtins()->LoadIC_Slow();
    458   }
    459 
    460   virtual Handle<Code> megamorphic_stub();
    461 
    462   // Update the inline cache and the global stub cache based on the
    463   // lookup result.
    464   void UpdateCaches(LookupResult* lookup,
    465                     Handle<Object> object,
    466                     Handle<String> name);
    467 
    468   virtual Handle<Code> CompileHandler(LookupResult* lookup,
    469                                       Handle<Object> object,
    470                                       Handle<String> name,
    471                                       Handle<Object> unused,
    472                                       InlineCacheHolderFlag cache_holder);
    473 
    474  private:
    475   // Stub accessors.
    476   static Handle<Code> pre_monomorphic_stub(Isolate* isolate,
    477                                            ExtraICState exstra_state);
    478 
    479   virtual Handle<Code> pre_monomorphic_stub() {
    480     return pre_monomorphic_stub(isolate(), extra_ic_state());
    481   }
    482 
    483   Handle<Code> SimpleFieldLoad(FieldIndex index);
    484 
    485   static void Clear(Isolate* isolate,
    486                     Address address,
    487                     Code* target,
    488                     ConstantPoolArray* constant_pool);
    489 
    490   friend class IC;
    491 };
    492 
    493 
    494 class KeyedLoadIC: public LoadIC {
    495  public:
    496   explicit KeyedLoadIC(FrameDepth depth, Isolate* isolate)
    497       : LoadIC(depth, isolate) {
    498     ASSERT(target()->is_keyed_load_stub());
    499   }
    500 
    501   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
    502                                            Handle<Object> key);
    503 
    504   // Code generator routines.
    505   static void GenerateMiss(MacroAssembler* masm);
    506   static void GenerateRuntimeGetProperty(MacroAssembler* masm);
    507   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
    508   static void GeneratePreMonomorphic(MacroAssembler* masm) {
    509     GenerateMiss(masm);
    510   }
    511   static void GenerateGeneric(MacroAssembler* masm);
    512   static void GenerateString(MacroAssembler* masm);
    513   static void GenerateIndexedInterceptor(MacroAssembler* masm);
    514   static void GenerateSloppyArguments(MacroAssembler* masm);
    515 
    516   // Bit mask to be tested against bit field for the cases when
    517   // generic stub should go into slow case.
    518   // Access check is necessary explicitly since generic stub does not perform
    519   // map checks.
    520   static const int kSlowCaseBitFieldMask =
    521       (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
    522 
    523  protected:
    524   virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
    525 
    526   Handle<Code> LoadElementStub(Handle<JSObject> receiver);
    527 
    528   virtual Handle<Code> megamorphic_stub();
    529   virtual Handle<Code> generic_stub() const;
    530 
    531   virtual Handle<Code> slow_stub() const {
    532     return isolate()->builtins()->KeyedLoadIC_Slow();
    533   }
    534 
    535   virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {}
    536 
    537  private:
    538   // Stub accessors.
    539   static Handle<Code> pre_monomorphic_stub(Isolate* isolate) {
    540     return isolate->builtins()->KeyedLoadIC_PreMonomorphic();
    541   }
    542   virtual Handle<Code> pre_monomorphic_stub() {
    543     return pre_monomorphic_stub(isolate());
    544   }
    545   Handle<Code> indexed_interceptor_stub() {
    546     return isolate()->builtins()->KeyedLoadIC_IndexedInterceptor();
    547   }
    548   Handle<Code> sloppy_arguments_stub() {
    549     return isolate()->builtins()->KeyedLoadIC_SloppyArguments();
    550   }
    551   Handle<Code> string_stub() {
    552     return isolate()->builtins()->KeyedLoadIC_String();
    553   }
    554 
    555   static void Clear(Isolate* isolate,
    556                     Address address,
    557                     Code* target,
    558                     ConstantPoolArray* constant_pool);
    559 
    560   friend class IC;
    561 };
    562 
    563 
    564 class StoreIC: public IC {
    565  public:
    566   class StrictModeState: public BitField<StrictMode, 1, 1> {};
    567   static ExtraICState ComputeExtraICState(StrictMode flag) {
    568     return StrictModeState::encode(flag);
    569   }
    570   static StrictMode GetStrictMode(ExtraICState state) {
    571     return StrictModeState::decode(state);
    572   }
    573 
    574   // For convenience, a statically declared encoding of strict mode extra
    575   // IC state.
    576   static const ExtraICState kStrictModeState =
    577       1 << StrictModeState::kShift;
    578 
    579   StoreIC(FrameDepth depth, Isolate* isolate)
    580       : IC(depth, isolate) {
    581     ASSERT(IsStoreStub());
    582   }
    583 
    584   StrictMode strict_mode() const {
    585     return StrictModeState::decode(extra_ic_state());
    586   }
    587 
    588   // Code generators for stub routines. Only called once at startup.
    589   static void GenerateSlow(MacroAssembler* masm);
    590   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
    591   static void GeneratePreMonomorphic(MacroAssembler* masm) {
    592     GenerateMiss(masm);
    593   }
    594   static void GenerateMiss(MacroAssembler* masm);
    595   static void GenerateMegamorphic(MacroAssembler* masm);
    596   static void GenerateNormal(MacroAssembler* masm);
    597   static void GenerateRuntimeSetProperty(MacroAssembler* masm,
    598                                          StrictMode strict_mode);
    599 
    600   static Handle<Code> initialize_stub(Isolate* isolate,
    601                                       StrictMode strict_mode);
    602 
    603   MUST_USE_RESULT MaybeHandle<Object> Store(
    604       Handle<Object> object,
    605       Handle<String> name,
    606       Handle<Object> value,
    607       JSReceiver::StoreFromKeyed store_mode =
    608           JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
    609 
    610  protected:
    611   virtual Code::Kind kind() const { return Code::STORE_IC; }
    612   virtual Handle<Code> megamorphic_stub();
    613 
    614   // Stub accessors.
    615   virtual Handle<Code> generic_stub() const;
    616 
    617   virtual Handle<Code> slow_stub() const {
    618     return isolate()->builtins()->StoreIC_Slow();
    619   }
    620 
    621   virtual Handle<Code> pre_monomorphic_stub() {
    622     return pre_monomorphic_stub(isolate(), strict_mode());
    623   }
    624 
    625   static Handle<Code> pre_monomorphic_stub(Isolate* isolate,
    626                                            StrictMode strict_mode);
    627 
    628   // Update the inline cache and the global stub cache based on the
    629   // lookup result.
    630   void UpdateCaches(LookupResult* lookup,
    631                     Handle<JSObject> receiver,
    632                     Handle<String> name,
    633                     Handle<Object> value);
    634   virtual Handle<Code> CompileHandler(LookupResult* lookup,
    635                                       Handle<Object> object,
    636                                       Handle<String> name,
    637                                       Handle<Object> value,
    638                                       InlineCacheHolderFlag cache_holder);
    639 
    640  private:
    641   void set_target(Code* code) {
    642     // Strict mode must be preserved across IC patching.
    643     ASSERT(GetStrictMode(code->extra_ic_state()) ==
    644            GetStrictMode(target()->extra_ic_state()));
    645     IC::set_target(code);
    646   }
    647 
    648   static void Clear(Isolate* isolate,
    649                     Address address,
    650                     Code* target,
    651                     ConstantPoolArray* constant_pool);
    652 
    653   friend class IC;
    654 };
    655 
    656 
    657 enum KeyedStoreCheckMap {
    658   kDontCheckMap,
    659   kCheckMap
    660 };
    661 
    662 
    663 enum KeyedStoreIncrementLength {
    664   kDontIncrementLength,
    665   kIncrementLength
    666 };
    667 
    668 
    669 class KeyedStoreIC: public StoreIC {
    670  public:
    671   // ExtraICState bits (building on IC)
    672   // ExtraICState bits
    673   class ExtraICStateKeyedAccessStoreMode:
    674       public BitField<KeyedAccessStoreMode, 2, 4> {};  // NOLINT
    675 
    676   static ExtraICState ComputeExtraICState(StrictMode flag,
    677                                           KeyedAccessStoreMode mode) {
    678     return StrictModeState::encode(flag) |
    679         ExtraICStateKeyedAccessStoreMode::encode(mode);
    680   }
    681 
    682   static KeyedAccessStoreMode GetKeyedAccessStoreMode(
    683       ExtraICState extra_state) {
    684     return ExtraICStateKeyedAccessStoreMode::decode(extra_state);
    685   }
    686 
    687   KeyedStoreIC(FrameDepth depth, Isolate* isolate)
    688       : StoreIC(depth, isolate) {
    689     ASSERT(target()->is_keyed_store_stub());
    690   }
    691 
    692   MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object,
    693                                             Handle<Object> name,
    694                                             Handle<Object> value);
    695 
    696   // Code generators for stub routines.  Only called once at startup.
    697   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
    698   static void GeneratePreMonomorphic(MacroAssembler* masm) {
    699     GenerateMiss(masm);
    700   }
    701   static void GenerateMiss(MacroAssembler* masm);
    702   static void GenerateSlow(MacroAssembler* masm);
    703   static void GenerateRuntimeSetProperty(MacroAssembler* masm,
    704                                          StrictMode strict_mode);
    705   static void GenerateGeneric(MacroAssembler* masm, StrictMode strict_mode);
    706   static void GenerateSloppyArguments(MacroAssembler* masm);
    707 
    708  protected:
    709   virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
    710 
    711   virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {}
    712 
    713   virtual Handle<Code> pre_monomorphic_stub() {
    714     return pre_monomorphic_stub(isolate(), strict_mode());
    715   }
    716   static Handle<Code> pre_monomorphic_stub(Isolate* isolate,
    717                                            StrictMode strict_mode) {
    718     if (strict_mode == STRICT) {
    719       return isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict();
    720     } else {
    721       return isolate->builtins()->KeyedStoreIC_PreMonomorphic();
    722     }
    723   }
    724   virtual Handle<Code> slow_stub() const {
    725     return isolate()->builtins()->KeyedStoreIC_Slow();
    726   }
    727   virtual Handle<Code> megamorphic_stub() {
    728     if (strict_mode() == STRICT) {
    729       return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
    730     } else {
    731       return isolate()->builtins()->KeyedStoreIC_Generic();
    732     }
    733   }
    734 
    735   Handle<Code> StoreElementStub(Handle<JSObject> receiver,
    736                                 KeyedAccessStoreMode store_mode);
    737 
    738  private:
    739   void set_target(Code* code) {
    740     // Strict mode must be preserved across IC patching.
    741     ASSERT(GetStrictMode(code->extra_ic_state()) == strict_mode());
    742     IC::set_target(code);
    743   }
    744 
    745   // Stub accessors.
    746   virtual Handle<Code> generic_stub() const {
    747     if (strict_mode() == STRICT) {
    748       return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
    749     } else {
    750       return isolate()->builtins()->KeyedStoreIC_Generic();
    751     }
    752   }
    753 
    754   Handle<Code> sloppy_arguments_stub() {
    755     return isolate()->builtins()->KeyedStoreIC_SloppyArguments();
    756   }
    757 
    758   static void Clear(Isolate* isolate,
    759                     Address address,
    760                     Code* target,
    761                     ConstantPoolArray* constant_pool);
    762 
    763   KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
    764                                     Handle<Object> key,
    765                                     Handle<Object> value);
    766 
    767   Handle<Map> ComputeTransitionedMap(Handle<Map> map,
    768                                      KeyedAccessStoreMode store_mode);
    769 
    770   friend class IC;
    771 };
    772 
    773 
    774 // Mode to overwrite BinaryExpression values.
    775 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
    776 
    777 // Type Recording BinaryOpIC, that records the types of the inputs and outputs.
    778 class BinaryOpIC: public IC {
    779  public:
    780   class State V8_FINAL BASE_EMBEDDED {
    781    public:
    782     State(Isolate* isolate, ExtraICState extra_ic_state);
    783 
    784     State(Isolate* isolate, Token::Value op, OverwriteMode mode)
    785         : op_(op), mode_(mode), left_kind_(NONE), right_kind_(NONE),
    786           result_kind_(NONE), isolate_(isolate) {
    787       ASSERT_LE(FIRST_TOKEN, op);
    788       ASSERT_LE(op, LAST_TOKEN);
    789     }
    790 
    791     InlineCacheState GetICState() const {
    792       if (Max(left_kind_, right_kind_) == NONE) {
    793         return ::v8::internal::UNINITIALIZED;
    794       }
    795       if (Max(left_kind_, right_kind_) == GENERIC) {
    796         return ::v8::internal::MEGAMORPHIC;
    797       }
    798       if (Min(left_kind_, right_kind_) == GENERIC) {
    799         return ::v8::internal::GENERIC;
    800       }
    801       return ::v8::internal::MONOMORPHIC;
    802     }
    803 
    804     ExtraICState GetExtraICState() const;
    805 
    806     static void GenerateAheadOfTime(
    807         Isolate*, void (*Generate)(Isolate*, const State&));
    808 
    809     bool CanReuseDoubleBox() const {
    810       return (result_kind_ > SMI && result_kind_ <= NUMBER) &&
    811           ((mode_ == OVERWRITE_LEFT &&
    812             left_kind_ > SMI && left_kind_ <= NUMBER) ||
    813            (mode_ == OVERWRITE_RIGHT &&
    814             right_kind_ > SMI && right_kind_ <= NUMBER));
    815     }
    816 
    817     // Returns true if the IC _could_ create allocation mementos.
    818     bool CouldCreateAllocationMementos() const {
    819       if (left_kind_ == STRING || right_kind_ == STRING) {
    820         ASSERT_EQ(Token::ADD, op_);
    821         return true;
    822       }
    823       return false;
    824     }
    825 
    826     // Returns true if the IC _should_ create allocation mementos.
    827     bool ShouldCreateAllocationMementos() const {
    828       return FLAG_allocation_site_pretenuring &&
    829           CouldCreateAllocationMementos();
    830     }
    831 
    832     bool HasSideEffects() const {
    833       return Max(left_kind_, right_kind_) == GENERIC;
    834     }
    835 
    836     // Returns true if the IC should enable the inline smi code (i.e. if either
    837     // parameter may be a smi).
    838     bool UseInlinedSmiCode() const {
    839       return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_);
    840     }
    841 
    842     static const int FIRST_TOKEN = Token::BIT_OR;
    843     static const int LAST_TOKEN = Token::MOD;
    844 
    845     Token::Value op() const { return op_; }
    846     OverwriteMode mode() const { return mode_; }
    847     Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
    848 
    849     Type* GetLeftType(Zone* zone) const {
    850       return KindToType(left_kind_, zone);
    851     }
    852     Type* GetRightType(Zone* zone) const {
    853       return KindToType(right_kind_, zone);
    854     }
    855     Type* GetResultType(Zone* zone) const;
    856 
    857     void Print(StringStream* stream) const;
    858 
    859     void Update(Handle<Object> left,
    860                 Handle<Object> right,
    861                 Handle<Object> result);
    862 
    863     Isolate* isolate() const { return isolate_; }
    864 
    865    private:
    866     enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
    867 
    868     Kind UpdateKind(Handle<Object> object, Kind kind) const;
    869 
    870     static const char* KindToString(Kind kind);
    871     static Type* KindToType(Kind kind, Zone* zone);
    872     static bool KindMaybeSmi(Kind kind) {
    873       return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
    874     }
    875 
    876     // We truncate the last bit of the token.
    877     STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4));
    878     class OpField:                 public BitField<int, 0, 4> {};
    879     class OverwriteModeField:      public BitField<OverwriteMode, 4, 2> {};
    880     class ResultKindField:         public BitField<Kind, 6, 3> {};
    881     class LeftKindField:           public BitField<Kind, 9,  3> {};
    882     // When fixed right arg is set, we don't need to store the right kind.
    883     // Thus the two fields can overlap.
    884     class HasFixedRightArgField:   public BitField<bool, 12, 1> {};
    885     class FixedRightArgValueField: public BitField<int,  13, 4> {};
    886     class RightKindField:          public BitField<Kind, 13, 3> {};
    887 
    888     Token::Value op_;
    889     OverwriteMode mode_;
    890     Kind left_kind_;
    891     Kind right_kind_;
    892     Kind result_kind_;
    893     Maybe<int> fixed_right_arg_;
    894     Isolate* isolate_;
    895   };
    896 
    897   explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
    898 
    899   static Builtins::JavaScript TokenToJSBuiltin(Token::Value op);
    900 
    901   MaybeHandle<Object> Transition(Handle<AllocationSite> allocation_site,
    902                                  Handle<Object> left,
    903                                  Handle<Object> right) V8_WARN_UNUSED_RESULT;
    904 };
    905 
    906 
    907 class CompareIC: public IC {
    908  public:
    909   // The type/state lattice is defined by the following inequations:
    910   //   UNINITIALIZED < ...
    911   //   ... < GENERIC
    912   //   SMI < NUMBER
    913   //   INTERNALIZED_STRING < STRING
    914   //   KNOWN_OBJECT < OBJECT
    915   enum State {
    916     UNINITIALIZED,
    917     SMI,
    918     NUMBER,
    919     STRING,
    920     INTERNALIZED_STRING,
    921     UNIQUE_NAME,    // Symbol or InternalizedString
    922     OBJECT,         // JSObject
    923     KNOWN_OBJECT,   // JSObject with specific map (faster check)
    924     GENERIC
    925   };
    926 
    927   static State NewInputState(State old_state, Handle<Object> value);
    928 
    929   static Type* StateToType(Zone* zone,
    930                            State state,
    931                            Handle<Map> map = Handle<Map>());
    932 
    933   static void StubInfoToType(int stub_minor_key,
    934                              Type** left_type,
    935                              Type** right_type,
    936                              Type** overall_type,
    937                              Handle<Map> map,
    938                              Zone* zone);
    939 
    940   CompareIC(Isolate* isolate, Token::Value op)
    941       : IC(EXTRA_CALL_FRAME, isolate), op_(op) { }
    942 
    943   // Update the inline cache for the given operands.
    944   Code* UpdateCaches(Handle<Object> x, Handle<Object> y);
    945 
    946 
    947   // Factory method for getting an uninitialized compare stub.
    948   static Handle<Code> GetUninitialized(Isolate* isolate, Token::Value op);
    949 
    950   // Helper function for computing the condition for a compare operation.
    951   static Condition ComputeCondition(Token::Value op);
    952 
    953   static const char* GetStateName(State state);
    954 
    955  private:
    956   static bool HasInlinedSmiCode(Address address);
    957 
    958   State TargetState(State old_state,
    959                     State old_left,
    960                     State old_right,
    961                     bool has_inlined_smi_code,
    962                     Handle<Object> x,
    963                     Handle<Object> y);
    964 
    965   bool strict() const { return op_ == Token::EQ_STRICT; }
    966   Condition GetCondition() const { return ComputeCondition(op_); }
    967 
    968   static Code* GetRawUninitialized(Isolate* isolate, Token::Value op);
    969 
    970   static void Clear(Isolate* isolate,
    971                     Address address,
    972                     Code* target,
    973                     ConstantPoolArray* constant_pool);
    974 
    975   Token::Value op_;
    976 
    977   friend class IC;
    978 };
    979 
    980 
    981 class CompareNilIC: public IC {
    982  public:
    983   explicit CompareNilIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
    984 
    985   Handle<Object> CompareNil(Handle<Object> object);
    986 
    987   static Handle<Code> GetUninitialized();
    988 
    989   static void Clear(Address address,
    990                     Code* target,
    991                     ConstantPoolArray* constant_pool);
    992 
    993   static Handle<Object> DoCompareNilSlow(Isolate* isolate, NilValue nil,
    994                                          Handle<Object> object);
    995 };
    996 
    997 
    998 class ToBooleanIC: public IC {
    999  public:
   1000   explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
   1001 
   1002   Handle<Object> ToBoolean(Handle<Object> object);
   1003 };
   1004 
   1005 
   1006 // Helper for BinaryOpIC and CompareIC.
   1007 enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
   1008 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check);
   1009 
   1010 DECLARE_RUNTIME_FUNCTION(KeyedLoadIC_MissFromStubFailure);
   1011 DECLARE_RUNTIME_FUNCTION(KeyedStoreIC_MissFromStubFailure);
   1012 DECLARE_RUNTIME_FUNCTION(UnaryOpIC_Miss);
   1013 DECLARE_RUNTIME_FUNCTION(StoreIC_MissFromStubFailure);
   1014 DECLARE_RUNTIME_FUNCTION(ElementsTransitionAndStoreIC_Miss);
   1015 DECLARE_RUNTIME_FUNCTION(BinaryOpIC_Miss);
   1016 DECLARE_RUNTIME_FUNCTION(BinaryOpIC_MissWithAllocationSite);
   1017 DECLARE_RUNTIME_FUNCTION(CompareNilIC_Miss);
   1018 DECLARE_RUNTIME_FUNCTION(ToBooleanIC_Miss);
   1019 
   1020 
   1021 } }  // namespace v8::internal
   1022 
   1023 #endif  // V8_IC_H_
   1024