Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_IC_H_
     29 #define V8_IC_H_
     30 
     31 #include "macro-assembler.h"
     32 #include "type-info.h"
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 
     38 // IC_UTIL_LIST defines all utility functions called from generated
     39 // inline caching code. The argument for the macro, ICU, is the function name.
     40 #define IC_UTIL_LIST(ICU)                             \
     41   ICU(LoadIC_Miss)                                    \
     42   ICU(KeyedLoadIC_Miss)                               \
     43   ICU(KeyedLoadIC_MissForceGeneric)                   \
     44   ICU(CallIC_Miss)                                    \
     45   ICU(KeyedCallIC_Miss)                               \
     46   ICU(StoreIC_Miss)                                   \
     47   ICU(StoreIC_ArrayLength)                            \
     48   ICU(SharedStoreIC_ExtendStorage)                    \
     49   ICU(KeyedStoreIC_Miss)                              \
     50   ICU(KeyedStoreIC_MissForceGeneric)                  \
     51   ICU(KeyedStoreIC_Slow)                              \
     52   /* Utilities for IC stubs. */                       \
     53   ICU(LoadCallbackProperty)                           \
     54   ICU(StoreCallbackProperty)                          \
     55   ICU(LoadPropertyWithInterceptorOnly)                \
     56   ICU(LoadPropertyWithInterceptorForLoad)             \
     57   ICU(LoadPropertyWithInterceptorForCall)             \
     58   ICU(KeyedLoadPropertyWithInterceptor)               \
     59   ICU(StoreInterceptorProperty)                       \
     60   ICU(UnaryOp_Patch)                                  \
     61   ICU(BinaryOp_Patch)                                 \
     62   ICU(CompareIC_Miss)                                 \
     63   ICU(ToBoolean_Patch)
     64 //
     65 // IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
     66 // and KeyedStoreIC.
     67 //
     68 class IC {
     69  public:
     70   // The ids for utility called from the generated code.
     71   enum UtilityId {
     72   #define CONST_NAME(name) k##name,
     73     IC_UTIL_LIST(CONST_NAME)
     74   #undef CONST_NAME
     75     kUtilityCount
     76   };
     77 
     78   // Looks up the address of the named utility.
     79   static Address AddressFromUtilityId(UtilityId id);
     80 
     81   // Alias the inline cache state type to make the IC code more readable.
     82   typedef InlineCacheState State;
     83 
     84   // The IC code is either invoked with no extra frames on the stack
     85   // or with a single extra frame for supporting calls.
     86   enum FrameDepth {
     87     NO_EXTRA_FRAME = 0,
     88     EXTRA_CALL_FRAME = 1
     89   };
     90 
     91   // Construct the IC structure with the given number of extra
     92   // JavaScript frames on the stack.
     93   IC(FrameDepth depth, Isolate* isolate);
     94   virtual ~IC() {}
     95 
     96   // Get the call-site target; used for determining the state.
     97   Code* target() const { return GetTargetAtAddress(address()); }
     98   inline Address address() const;
     99 
    100   virtual bool IsGeneric() const { return false; }
    101 
    102   // Compute the current IC state based on the target stub, receiver and name.
    103   static State StateFrom(Code* target, Object* receiver, Object* name);
    104 
    105   // Clear the inline cache to initial state.
    106   static void Clear(Address address);
    107 
    108   // Computes the reloc info for this IC. This is a fairly expensive
    109   // operation as it has to search through the heap to find the code
    110   // object that contains this IC site.
    111   RelocInfo::Mode ComputeMode();
    112 
    113   // Returns if this IC is for contextual (no explicit receiver)
    114   // access to properties.
    115   bool IsContextual(Handle<Object> receiver) {
    116     if (receiver->IsGlobalObject()) {
    117       return SlowIsContextual();
    118     } else {
    119       ASSERT(!SlowIsContextual());
    120       return false;
    121     }
    122   }
    123 
    124   bool SlowIsContextual() {
    125     return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT;
    126   }
    127 
    128   // Determines which map must be used for keeping the code stub.
    129   // These methods should not be called with undefined or null.
    130   static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object,
    131                                                             JSObject* holder);
    132   static inline InlineCacheHolderFlag GetCodeCacheForObject(JSObject* object,
    133                                                             JSObject* holder);
    134   static inline JSObject* GetCodeCacheHolder(Object* object,
    135                                              InlineCacheHolderFlag holder);
    136 
    137  protected:
    138   Address fp() const { return fp_; }
    139   Address pc() const { return *pc_address_; }
    140   Isolate* isolate() const { return isolate_; }
    141 
    142 #ifdef ENABLE_DEBUGGER_SUPPORT
    143   // Computes the address in the original code when the code running is
    144   // containing break points (calls to DebugBreakXXX builtins).
    145   Address OriginalCodeAddress() const;
    146 #endif
    147 
    148   // Set the call-site target.
    149   void set_target(Code* code) { SetTargetAtAddress(address(), code); }
    150 
    151 #ifdef DEBUG
    152   char TransitionMarkFromState(IC::State state);
    153 
    154   void TraceIC(const char* type,
    155                Handle<Object> name,
    156                State old_state,
    157                Code* new_target);
    158 #endif
    159 
    160   Failure* TypeError(const char* type,
    161                      Handle<Object> object,
    162                      Handle<Object> key);
    163   Failure* ReferenceError(const char* type, Handle<String> name);
    164 
    165   // Access the target code for the given IC address.
    166   static inline Code* GetTargetAtAddress(Address address);
    167   static inline void SetTargetAtAddress(Address address, Code* target);
    168   static void PostPatching(Address address, Code* target, Code* old_target);
    169 
    170  private:
    171   // Frame pointer for the frame that uses (calls) the IC.
    172   Address fp_;
    173 
    174   // All access to the program counter of an IC structure is indirect
    175   // to make the code GC safe. This feature is crucial since
    176   // GetProperty and SetProperty are called and they in turn might
    177   // invoke the garbage collector.
    178   Address* pc_address_;
    179 
    180   Isolate* isolate_;
    181 
    182   DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
    183 };
    184 
    185 
    186 // An IC_Utility encapsulates IC::UtilityId. It exists mainly because you
    187 // cannot make forward declarations to an enum.
    188 class IC_Utility {
    189  public:
    190   explicit IC_Utility(IC::UtilityId id)
    191     : address_(IC::AddressFromUtilityId(id)), id_(id) {}
    192 
    193   Address address() const { return address_; }
    194 
    195   IC::UtilityId id() const { return id_; }
    196  private:
    197   Address address_;
    198   IC::UtilityId id_;
    199 };
    200 
    201 
    202 class CallICBase: public IC {
    203  public:
    204   class Contextual: public BitField<bool, 0, 1> {};
    205   class StringStubState: public BitField<StringStubFeedback, 1, 1> {};
    206 
    207   // Returns a JSFunction or a Failure.
    208   MUST_USE_RESULT MaybeObject* LoadFunction(State state,
    209                                             Code::ExtraICState extra_ic_state,
    210                                             Handle<Object> object,
    211                                             Handle<String> name);
    212 
    213  protected:
    214   CallICBase(Code::Kind kind, Isolate* isolate)
    215       : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {}
    216 
    217   bool TryUpdateExtraICState(LookupResult* lookup,
    218                              Handle<Object> object,
    219                              Code::ExtraICState* extra_ic_state);
    220 
    221   // Compute a monomorphic stub if possible, otherwise return a null handle.
    222   Handle<Code> ComputeMonomorphicStub(LookupResult* lookup,
    223                                       State state,
    224                                       Code::ExtraICState extra_state,
    225                                       Handle<Object> object,
    226                                       Handle<String> name);
    227 
    228   // Update the inline cache and the global stub cache based on the lookup
    229   // result.
    230   void UpdateCaches(LookupResult* lookup,
    231                     State state,
    232                     Code::ExtraICState extra_ic_state,
    233                     Handle<Object> object,
    234                     Handle<String> name);
    235 
    236   // Returns a JSFunction if the object can be called as a function, and
    237   // patches the stack to be ready for the call.  Otherwise, it returns the
    238   // undefined value.
    239   Handle<Object> TryCallAsFunction(Handle<Object> object);
    240 
    241   void ReceiverToObjectIfRequired(Handle<Object> callee, Handle<Object> object);
    242 
    243   static void Clear(Address address, Code* target);
    244 
    245   // Platform-specific code generation functions used by both call and
    246   // keyed call.
    247   static void GenerateMiss(MacroAssembler* masm,
    248                            int argc,
    249                            IC::UtilityId id,
    250                            Code::ExtraICState extra_state);
    251 
    252   static void GenerateNormal(MacroAssembler* masm, int argc);
    253 
    254   static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
    255                                             int argc,
    256                                             Code::Kind kind,
    257                                             Code::ExtraICState extra_state);
    258 
    259   Code::Kind kind_;
    260 
    261   friend class IC;
    262 };
    263 
    264 
    265 class CallIC: public CallICBase {
    266  public:
    267   explicit CallIC(Isolate* isolate) : CallICBase(Code::CALL_IC, isolate) {
    268     ASSERT(target()->is_call_stub());
    269   }
    270 
    271   // Code generator routines.
    272   static void GenerateInitialize(MacroAssembler* masm,
    273                                  int argc,
    274                                  Code::ExtraICState extra_state) {
    275     GenerateMiss(masm, argc, extra_state);
    276   }
    277 
    278   static void GenerateMiss(MacroAssembler* masm,
    279                            int argc,
    280                            Code::ExtraICState extra_state) {
    281     CallICBase::GenerateMiss(masm, argc, IC::kCallIC_Miss, extra_state);
    282   }
    283 
    284   static void GenerateMegamorphic(MacroAssembler* masm,
    285                                   int argc,
    286                                   Code::ExtraICState extra_ic_state);
    287 
    288   static void GenerateNormal(MacroAssembler* masm, int argc) {
    289     CallICBase::GenerateNormal(masm, argc);
    290     GenerateMiss(masm, argc, Code::kNoExtraICState);
    291   }
    292 };
    293 
    294 
    295 class KeyedCallIC: public CallICBase {
    296  public:
    297   explicit KeyedCallIC(Isolate* isolate)
    298       : CallICBase(Code::KEYED_CALL_IC, isolate) {
    299     ASSERT(target()->is_keyed_call_stub());
    300   }
    301 
    302   MUST_USE_RESULT MaybeObject* LoadFunction(State state,
    303                                             Handle<Object> object,
    304                                             Handle<Object> key);
    305 
    306   // Code generator routines.
    307   static void GenerateInitialize(MacroAssembler* masm, int argc) {
    308     GenerateMiss(masm, argc);
    309   }
    310 
    311   static void GenerateMiss(MacroAssembler* masm, int argc) {
    312     CallICBase::GenerateMiss(masm, argc, IC::kKeyedCallIC_Miss,
    313                              Code::kNoExtraICState);
    314   }
    315 
    316   static void GenerateMegamorphic(MacroAssembler* masm, int argc);
    317   static void GenerateNormal(MacroAssembler* masm, int argc);
    318   static void GenerateNonStrictArguments(MacroAssembler* masm, int argc);
    319 };
    320 
    321 
    322 class LoadIC: public IC {
    323  public:
    324   explicit LoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
    325     ASSERT(target()->is_load_stub());
    326   }
    327 
    328   MUST_USE_RESULT MaybeObject* Load(State state,
    329                                     Handle<Object> object,
    330                                     Handle<String> name);
    331 
    332   // Code generator routines.
    333   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
    334   static void GeneratePreMonomorphic(MacroAssembler* masm) {
    335     GenerateMiss(masm);
    336   }
    337   static void GenerateMiss(MacroAssembler* masm);
    338   static void GenerateMegamorphic(MacroAssembler* masm);
    339   static void GenerateNormal(MacroAssembler* masm);
    340 
    341   // Specialized code generator routines.
    342   static void GenerateArrayLength(MacroAssembler* masm);
    343   static void GenerateStringLength(MacroAssembler* masm,
    344                                    bool support_wrappers);
    345   static void GenerateFunctionPrototype(MacroAssembler* masm);
    346 
    347  private:
    348   // Update the inline cache and the global stub cache based on the
    349   // lookup result.
    350   void UpdateCaches(LookupResult* lookup,
    351                     State state,
    352                     Handle<Object> object,
    353                     Handle<String> name);
    354 
    355   // Stub accessors.
    356   Handle<Code> megamorphic_stub() {
    357     return isolate()->builtins()->LoadIC_Megamorphic();
    358   }
    359   static Code* initialize_stub() {
    360     return Isolate::Current()->builtins()->builtin(
    361         Builtins::kLoadIC_Initialize);
    362   }
    363   Handle<Code> pre_monomorphic_stub() {
    364     return isolate()->builtins()->LoadIC_PreMonomorphic();
    365   }
    366 
    367   static void Clear(Address address, Code* target);
    368 
    369   friend class IC;
    370 };
    371 
    372 
    373 class KeyedIC: public IC {
    374  public:
    375   enum StubKind {
    376     LOAD,
    377     STORE_NO_TRANSITION,
    378     STORE_TRANSITION_SMI_TO_OBJECT,
    379     STORE_TRANSITION_SMI_TO_DOUBLE,
    380     STORE_TRANSITION_DOUBLE_TO_OBJECT,
    381     STORE_AND_GROW_NO_TRANSITION,
    382     STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT,
    383     STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE,
    384     STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT
    385   };
    386 
    387   static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION -
    388       STORE_NO_TRANSITION;
    389   STATIC_ASSERT(kGrowICDelta ==
    390                 STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT -
    391                 STORE_TRANSITION_SMI_TO_OBJECT);
    392   STATIC_ASSERT(kGrowICDelta ==
    393                 STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE -
    394                 STORE_TRANSITION_SMI_TO_DOUBLE);
    395   STATIC_ASSERT(kGrowICDelta ==
    396                 STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT -
    397                 STORE_TRANSITION_DOUBLE_TO_OBJECT);
    398 
    399   explicit KeyedIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {}
    400   virtual ~KeyedIC() {}
    401 
    402   static inline KeyedAccessGrowMode GetGrowModeFromStubKind(
    403       StubKind stub_kind) {
    404     return (stub_kind >= STORE_AND_GROW_NO_TRANSITION)
    405         ? ALLOW_JSARRAY_GROWTH
    406         : DO_NOT_ALLOW_JSARRAY_GROWTH;
    407   }
    408 
    409   static inline StubKind GetGrowStubKind(StubKind stub_kind) {
    410     ASSERT(stub_kind != LOAD);
    411     if (stub_kind < STORE_AND_GROW_NO_TRANSITION) {
    412       stub_kind = static_cast<StubKind>(static_cast<int>(stub_kind) +
    413                                         kGrowICDelta);
    414     }
    415     return stub_kind;
    416   }
    417 
    418   virtual Handle<Code> GetElementStubWithoutMapCheck(
    419       bool is_js_array,
    420       ElementsKind elements_kind,
    421       KeyedAccessGrowMode grow_mode) = 0;
    422 
    423  protected:
    424   virtual Handle<Code> string_stub() {
    425     return Handle<Code>::null();
    426   }
    427 
    428   virtual Code::Kind kind() const = 0;
    429 
    430   Handle<Code> ComputeStub(Handle<JSObject> receiver,
    431                            StubKind stub_kind,
    432                            StrictModeFlag strict_mode,
    433                            Handle<Code> default_stub);
    434 
    435   virtual Handle<Code> ComputePolymorphicStub(
    436       MapHandleList* receiver_maps,
    437       StrictModeFlag strict_mode,
    438       KeyedAccessGrowMode grow_mode) = 0;
    439 
    440   Handle<Code> ComputeMonomorphicStubWithoutMapCheck(
    441       Handle<Map> receiver_map,
    442       StrictModeFlag strict_mode,
    443       KeyedAccessGrowMode grow_mode);
    444 
    445  private:
    446   void GetReceiverMapsForStub(Handle<Code> stub, MapHandleList* result);
    447 
    448   Handle<Code> ComputeMonomorphicStub(Handle<JSObject> receiver,
    449                                       StubKind stub_kind,
    450                                       StrictModeFlag strict_mode,
    451                                       Handle<Code> default_stub);
    452 
    453   Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
    454                                      StubKind stub_kind);
    455 
    456   static bool IsTransitionStubKind(StubKind stub_kind) {
    457     return stub_kind > STORE_NO_TRANSITION &&
    458         stub_kind != STORE_AND_GROW_NO_TRANSITION;
    459   }
    460 
    461   static bool IsGrowStubKind(StubKind stub_kind) {
    462     return stub_kind >= STORE_AND_GROW_NO_TRANSITION;
    463   }
    464 };
    465 
    466 
    467 class KeyedLoadIC: public KeyedIC {
    468  public:
    469   explicit KeyedLoadIC(Isolate* isolate) : KeyedIC(isolate) {
    470     ASSERT(target()->is_keyed_load_stub());
    471   }
    472 
    473   MUST_USE_RESULT MaybeObject* Load(State state,
    474                                     Handle<Object> object,
    475                                     Handle<Object> key,
    476                                     bool force_generic_stub);
    477 
    478   // Code generator routines.
    479   static void GenerateMiss(MacroAssembler* masm, bool force_generic);
    480   static void GenerateRuntimeGetProperty(MacroAssembler* masm);
    481   static void GenerateInitialize(MacroAssembler* masm) {
    482     GenerateMiss(masm, false);
    483   }
    484   static void GeneratePreMonomorphic(MacroAssembler* masm) {
    485     GenerateMiss(masm, false);
    486   }
    487   static void GenerateGeneric(MacroAssembler* masm);
    488   static void GenerateString(MacroAssembler* masm);
    489   static void GenerateIndexedInterceptor(MacroAssembler* masm);
    490   static void GenerateNonStrictArguments(MacroAssembler* masm);
    491 
    492   // Bit mask to be tested against bit field for the cases when
    493   // generic stub should go into slow case.
    494   // Access check is necessary explicitly since generic stub does not perform
    495   // map checks.
    496   static const int kSlowCaseBitFieldMask =
    497       (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
    498 
    499   virtual Handle<Code> GetElementStubWithoutMapCheck(
    500       bool is_js_array,
    501       ElementsKind elements_kind,
    502       KeyedAccessGrowMode grow_mode);
    503 
    504   virtual bool IsGeneric() const {
    505     return target() == *generic_stub();
    506   }
    507 
    508  protected:
    509   virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
    510 
    511   virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
    512                                               StrictModeFlag strict_mode,
    513                                               KeyedAccessGrowMode grow_mode);
    514 
    515   virtual Handle<Code> string_stub() {
    516     return isolate()->builtins()->KeyedLoadIC_String();
    517   }
    518 
    519  private:
    520   // Update the inline cache.
    521   void UpdateCaches(LookupResult* lookup,
    522                     State state,
    523                     Handle<Object> object,
    524                     Handle<String> name);
    525 
    526   // Stub accessors.
    527   static Code* initialize_stub() {
    528     return Isolate::Current()->builtins()->builtin(
    529         Builtins::kKeyedLoadIC_Initialize);
    530   }
    531   Handle<Code> megamorphic_stub() {
    532     return isolate()->builtins()->KeyedLoadIC_Generic();
    533   }
    534   Handle<Code> generic_stub() const {
    535     return isolate()->builtins()->KeyedLoadIC_Generic();
    536   }
    537   Handle<Code> pre_monomorphic_stub() {
    538     return isolate()->builtins()->KeyedLoadIC_PreMonomorphic();
    539   }
    540   Handle<Code> indexed_interceptor_stub() {
    541     return isolate()->builtins()->KeyedLoadIC_IndexedInterceptor();
    542   }
    543   Handle<Code> non_strict_arguments_stub() {
    544     return isolate()->builtins()->KeyedLoadIC_NonStrictArguments();
    545   }
    546 
    547   static void Clear(Address address, Code* target);
    548 
    549   friend class IC;
    550 };
    551 
    552 
    553 class StoreIC: public IC {
    554  public:
    555   explicit StoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
    556     ASSERT(target()->is_store_stub());
    557   }
    558 
    559   MUST_USE_RESULT MaybeObject* Store(State state,
    560                                      StrictModeFlag strict_mode,
    561                                      Handle<Object> object,
    562                                      Handle<String> name,
    563                                      Handle<Object> value);
    564 
    565   // Code generators for stub routines. Only called once at startup.
    566   static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
    567   static void GenerateMiss(MacroAssembler* masm);
    568   static void GenerateMegamorphic(MacroAssembler* masm,
    569                                   StrictModeFlag strict_mode);
    570   static void GenerateArrayLength(MacroAssembler* masm);
    571   static void GenerateNormal(MacroAssembler* masm);
    572   static void GenerateGlobalProxy(MacroAssembler* masm,
    573                                   StrictModeFlag strict_mode);
    574 
    575  private:
    576   // Update the inline cache and the global stub cache based on the
    577   // lookup result.
    578   void UpdateCaches(LookupResult* lookup,
    579                     State state,
    580                     StrictModeFlag strict_mode,
    581                     Handle<JSObject> receiver,
    582                     Handle<String> name,
    583                     Handle<Object> value);
    584 
    585   void set_target(Code* code) {
    586     // Strict mode must be preserved across IC patching.
    587     ASSERT(Code::GetStrictMode(code->extra_ic_state()) ==
    588            Code::GetStrictMode(target()->extra_ic_state()));
    589     IC::set_target(code);
    590   }
    591 
    592   // Stub accessors.
    593   Code* megamorphic_stub() {
    594     return isolate()->builtins()->builtin(
    595         Builtins::kStoreIC_Megamorphic);
    596   }
    597   Code* megamorphic_stub_strict() {
    598     return isolate()->builtins()->builtin(
    599         Builtins::kStoreIC_Megamorphic_Strict);
    600   }
    601   static Code* initialize_stub() {
    602     return Isolate::Current()->builtins()->builtin(
    603         Builtins::kStoreIC_Initialize);
    604   }
    605   static Code* initialize_stub_strict() {
    606     return Isolate::Current()->builtins()->builtin(
    607         Builtins::kStoreIC_Initialize_Strict);
    608   }
    609   Handle<Code> global_proxy_stub() {
    610     return isolate()->builtins()->StoreIC_GlobalProxy();
    611   }
    612   Handle<Code> global_proxy_stub_strict() {
    613     return isolate()->builtins()->StoreIC_GlobalProxy_Strict();
    614   }
    615 
    616   static void Clear(Address address, Code* target);
    617 
    618   friend class IC;
    619 };
    620 
    621 
    622 class KeyedStoreIC: public KeyedIC {
    623  public:
    624   explicit KeyedStoreIC(Isolate* isolate) : KeyedIC(isolate) {
    625     ASSERT(target()->is_keyed_store_stub());
    626   }
    627 
    628   MUST_USE_RESULT MaybeObject* Store(State state,
    629                                    StrictModeFlag strict_mode,
    630                                      Handle<Object> object,
    631                                      Handle<Object> name,
    632                                      Handle<Object> value,
    633                                      bool force_generic);
    634 
    635   // Code generators for stub routines.  Only called once at startup.
    636   static void GenerateInitialize(MacroAssembler* masm) {
    637     GenerateMiss(masm, false);
    638   }
    639   static void GenerateMiss(MacroAssembler* masm, bool force_generic);
    640   static void GenerateSlow(MacroAssembler* masm);
    641   static void GenerateRuntimeSetProperty(MacroAssembler* masm,
    642                                          StrictModeFlag strict_mode);
    643   static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode);
    644   static void GenerateNonStrictArguments(MacroAssembler* masm);
    645   static void GenerateTransitionElementsSmiToDouble(MacroAssembler* masm);
    646   static void GenerateTransitionElementsDoubleToObject(MacroAssembler* masm);
    647 
    648   virtual Handle<Code> GetElementStubWithoutMapCheck(
    649       bool is_js_array,
    650       ElementsKind elements_kind,
    651       KeyedAccessGrowMode grow_mode);
    652 
    653   virtual bool IsGeneric() const {
    654     return target() == *generic_stub() ||
    655         target() == *generic_stub_strict();
    656   }
    657 
    658  protected:
    659   virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
    660 
    661   virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
    662                                               StrictModeFlag strict_mode,
    663                                               KeyedAccessGrowMode grow_mode);
    664 
    665   private:
    666   // Update the inline cache.
    667   void UpdateCaches(LookupResult* lookup,
    668                     State state,
    669                     StrictModeFlag strict_mode,
    670                     Handle<JSObject> receiver,
    671                     Handle<String> name,
    672                     Handle<Object> value);
    673 
    674   void set_target(Code* code) {
    675     // Strict mode must be preserved across IC patching.
    676     ASSERT(Code::GetStrictMode(code->extra_ic_state()) ==
    677            Code::GetStrictMode(target()->extra_ic_state()));
    678     IC::set_target(code);
    679   }
    680 
    681   // Stub accessors.
    682   static Code* initialize_stub() {
    683     return Isolate::Current()->builtins()->builtin(
    684         Builtins::kKeyedStoreIC_Initialize);
    685   }
    686   static Code* initialize_stub_strict() {
    687     return Isolate::Current()->builtins()->builtin(
    688         Builtins::kKeyedStoreIC_Initialize_Strict);
    689   }
    690   Handle<Code> megamorphic_stub() {
    691     return isolate()->builtins()->KeyedStoreIC_Generic();
    692   }
    693   Handle<Code> megamorphic_stub_strict() {
    694     return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
    695   }
    696   Handle<Code> generic_stub() const {
    697     return isolate()->builtins()->KeyedStoreIC_Generic();
    698   }
    699   Handle<Code> generic_stub_strict() const {
    700     return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
    701   }
    702   Handle<Code> non_strict_arguments_stub() {
    703     return isolate()->builtins()->KeyedStoreIC_NonStrictArguments();
    704   }
    705 
    706   static void Clear(Address address, Code* target);
    707 
    708   StubKind GetStubKind(Handle<JSObject> receiver,
    709                        Handle<Object> key,
    710                        Handle<Object> value);
    711 
    712   friend class IC;
    713 };
    714 
    715 
    716 class UnaryOpIC: public IC {
    717  public:
    718   // sorted: increasingly more unspecific (ignoring UNINITIALIZED)
    719   // TODO(svenpanne) Using enums+switch is an antipattern, use a class instead.
    720   enum TypeInfo {
    721     UNINITIALIZED,
    722     SMI,
    723     HEAP_NUMBER,
    724     GENERIC
    725   };
    726 
    727   explicit UnaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
    728 
    729   void patch(Code* code);
    730 
    731   static const char* GetName(TypeInfo type_info);
    732 
    733   static State ToState(TypeInfo type_info);
    734 
    735   static TypeInfo GetTypeInfo(Handle<Object> operand);
    736 
    737   static TypeInfo ComputeNewType(TypeInfo type, TypeInfo previous);
    738 };
    739 
    740 
    741 // Type Recording BinaryOpIC, that records the types of the inputs and outputs.
    742 class BinaryOpIC: public IC {
    743  public:
    744   enum TypeInfo {
    745     UNINITIALIZED,
    746     SMI,
    747     INT32,
    748     HEAP_NUMBER,
    749     ODDBALL,
    750     BOTH_STRING,  // Only used for addition operation.
    751     STRING,  // Only used for addition operation.  At least one string operand.
    752     GENERIC
    753   };
    754 
    755   explicit BinaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
    756 
    757   void patch(Code* code);
    758 
    759   static const char* GetName(TypeInfo type_info);
    760 
    761   static State ToState(TypeInfo type_info);
    762 
    763   static TypeInfo GetTypeInfo(Handle<Object> left, Handle<Object> right);
    764 
    765   static TypeInfo JoinTypes(TypeInfo x, TypeInfo y);
    766 };
    767 
    768 
    769 class CompareIC: public IC {
    770  public:
    771   enum State {
    772     UNINITIALIZED,
    773     SMIS,
    774     HEAP_NUMBERS,
    775     SYMBOLS,
    776     STRINGS,
    777     OBJECTS,
    778     KNOWN_OBJECTS,
    779     GENERIC
    780   };
    781 
    782   CompareIC(Isolate* isolate, Token::Value op)
    783       : IC(EXTRA_CALL_FRAME, isolate), op_(op) { }
    784 
    785   // Update the inline cache for the given operands.
    786   void UpdateCaches(Handle<Object> x, Handle<Object> y);
    787 
    788   // Factory method for getting an uninitialized compare stub.
    789   static Handle<Code> GetUninitialized(Token::Value op);
    790 
    791   // Helper function for computing the condition for a compare operation.
    792   static Condition ComputeCondition(Token::Value op);
    793 
    794   // Helper function for determining the state of a compare IC.
    795   static State ComputeState(Code* target);
    796 
    797   static const char* GetStateName(State state);
    798 
    799  private:
    800   State TargetState(State state, bool has_inlined_smi_code,
    801                     Handle<Object> x, Handle<Object> y);
    802 
    803   bool strict() const { return op_ == Token::EQ_STRICT; }
    804   Condition GetCondition() const { return ComputeCondition(op_); }
    805   State GetState() { return ComputeState(target()); }
    806 
    807   Token::Value op_;
    808 };
    809 
    810 
    811 class ToBooleanIC: public IC {
    812  public:
    813   explicit ToBooleanIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
    814 
    815   void patch(Code* code);
    816 };
    817 
    818 
    819 // Helper for BinaryOpIC and CompareIC.
    820 void PatchInlinedSmiCode(Address address);
    821 
    822 } }  // namespace v8::internal
    823 
    824 #endif  // V8_IC_H_
    825