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_STUB_CACHE_H_
      6 #define V8_STUB_CACHE_H_
      7 
      8 #include "src/allocation.h"
      9 #include "src/arguments.h"
     10 #include "src/code-stubs.h"
     11 #include "src/ic-inl.h"
     12 #include "src/macro-assembler.h"
     13 #include "src/objects.h"
     14 #include "src/zone-inl.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 
     19 
     20 // The stub cache is used for megamorphic calls and property accesses.
     21 // It maps (map, name, type)->Code*
     22 
     23 // The design of the table uses the inline cache stubs used for
     24 // mono-morphic calls. The beauty of this, we do not have to
     25 // invalidate the cache whenever a prototype map is changed.  The stub
     26 // validates the map chain as in the mono-morphic case.
     27 
     28 
     29 class CallOptimization;
     30 class SmallMapList;
     31 class StubCache;
     32 
     33 
     34 class SCTableReference {
     35  public:
     36   Address address() const { return address_; }
     37 
     38  private:
     39   explicit SCTableReference(Address address) : address_(address) {}
     40 
     41   Address address_;
     42 
     43   friend class StubCache;
     44 };
     45 
     46 
     47 class StubCache {
     48  public:
     49   struct Entry {
     50     Name* key;
     51     Code* value;
     52     Map* map;
     53   };
     54 
     55   void Initialize();
     56 
     57   Handle<JSObject> StubHolder(Handle<JSObject> receiver,
     58                               Handle<JSObject> holder);
     59 
     60   Handle<Code> FindIC(Handle<Name> name,
     61                       Handle<Map> stub_holder_map,
     62                       Code::Kind kind,
     63                       ExtraICState extra_state = kNoExtraICState,
     64                       InlineCacheHolderFlag cache_holder = OWN_MAP);
     65 
     66   Handle<Code> FindHandler(Handle<Name> name,
     67                            Handle<Map> map,
     68                            Code::Kind kind,
     69                            InlineCacheHolderFlag cache_holder,
     70                            Code::StubType type);
     71 
     72   Handle<Code> ComputeMonomorphicIC(Code::Kind kind,
     73                                     Handle<Name> name,
     74                                     Handle<HeapType> type,
     75                                     Handle<Code> handler,
     76                                     ExtraICState extra_ic_state);
     77 
     78   Handle<Code> ComputeLoadNonexistent(Handle<Name> name, Handle<HeapType> type);
     79 
     80   Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
     81 
     82   Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map,
     83                                         StrictMode strict_mode,
     84                                         KeyedAccessStoreMode store_mode);
     85 
     86   // ---
     87 
     88   Handle<Code> ComputeLoad(InlineCacheState ic_state, ExtraICState extra_state);
     89   Handle<Code> ComputeStore(InlineCacheState ic_state,
     90                             ExtraICState extra_state);
     91 
     92   // ---
     93 
     94   Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
     95                                  CompareNilICStub* stub);
     96 
     97   // ---
     98 
     99   Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps);
    100   Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps,
    101                                               KeyedAccessStoreMode store_mode,
    102                                               StrictMode strict_mode);
    103 
    104   Handle<Code> ComputePolymorphicIC(Code::Kind kind,
    105                                     TypeHandleList* types,
    106                                     CodeHandleList* handlers,
    107                                     int number_of_valid_maps,
    108                                     Handle<Name> name,
    109                                     ExtraICState extra_ic_state);
    110 
    111   // Finds the Code object stored in the Heap::non_monomorphic_cache().
    112   Code* FindPreMonomorphicIC(Code::Kind kind, ExtraICState extra_ic_state);
    113 
    114   // Update cache for entry hash(name, map).
    115   Code* Set(Name* name, Map* map, Code* code);
    116 
    117   // Clear the lookup table (@ mark compact collection).
    118   void Clear();
    119 
    120   // Collect all maps that match the name and flags.
    121   void CollectMatchingMaps(SmallMapList* types,
    122                            Handle<Name> name,
    123                            Code::Flags flags,
    124                            Handle<Context> native_context,
    125                            Zone* zone);
    126 
    127   // Generate code for probing the stub cache table.
    128   // Arguments extra, extra2 and extra3 may be used to pass additional scratch
    129   // registers. Set to no_reg if not needed.
    130   void GenerateProbe(MacroAssembler* masm,
    131                      Code::Flags flags,
    132                      Register receiver,
    133                      Register name,
    134                      Register scratch,
    135                      Register extra,
    136                      Register extra2 = no_reg,
    137                      Register extra3 = no_reg);
    138 
    139   enum Table {
    140     kPrimary,
    141     kSecondary
    142   };
    143 
    144 
    145   SCTableReference key_reference(StubCache::Table table) {
    146     return SCTableReference(
    147         reinterpret_cast<Address>(&first_entry(table)->key));
    148   }
    149 
    150 
    151   SCTableReference map_reference(StubCache::Table table) {
    152     return SCTableReference(
    153         reinterpret_cast<Address>(&first_entry(table)->map));
    154   }
    155 
    156 
    157   SCTableReference value_reference(StubCache::Table table) {
    158     return SCTableReference(
    159         reinterpret_cast<Address>(&first_entry(table)->value));
    160   }
    161 
    162 
    163   StubCache::Entry* first_entry(StubCache::Table table) {
    164     switch (table) {
    165       case StubCache::kPrimary: return StubCache::primary_;
    166       case StubCache::kSecondary: return StubCache::secondary_;
    167     }
    168     UNREACHABLE();
    169     return NULL;
    170   }
    171 
    172   Isolate* isolate() { return isolate_; }
    173   Heap* heap() { return isolate()->heap(); }
    174   Factory* factory() { return isolate()->factory(); }
    175 
    176   // These constants describe the structure of the interceptor arguments on the
    177   // stack. The arguments are pushed by the (platform-specific)
    178   // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
    179   // LoadWithInterceptor.
    180   static const int kInterceptorArgsNameIndex = 0;
    181   static const int kInterceptorArgsInfoIndex = 1;
    182   static const int kInterceptorArgsThisIndex = 2;
    183   static const int kInterceptorArgsHolderIndex = 3;
    184   static const int kInterceptorArgsLength = 4;
    185 
    186  private:
    187   explicit StubCache(Isolate* isolate);
    188 
    189   // The stub cache has a primary and secondary level.  The two levels have
    190   // different hashing algorithms in order to avoid simultaneous collisions
    191   // in both caches.  Unlike a probing strategy (quadratic or otherwise) the
    192   // update strategy on updates is fairly clear and simple:  Any existing entry
    193   // in the primary cache is moved to the secondary cache, and secondary cache
    194   // entries are overwritten.
    195 
    196   // Hash algorithm for the primary table.  This algorithm is replicated in
    197   // assembler for every architecture.  Returns an index into the table that
    198   // is scaled by 1 << kHeapObjectTagSize.
    199   static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) {
    200     // This works well because the heap object tag size and the hash
    201     // shift are equal.  Shifting down the length field to get the
    202     // hash code would effectively throw away two bits of the hash
    203     // code.
    204     STATIC_ASSERT(kHeapObjectTagSize == Name::kHashShift);
    205     // Compute the hash of the name (use entire hash field).
    206     ASSERT(name->HasHashCode());
    207     uint32_t field = name->hash_field();
    208     // Using only the low bits in 64-bit mode is unlikely to increase the
    209     // risk of collision even if the heap is spread over an area larger than
    210     // 4Gb (and not at all if it isn't).
    211     uint32_t map_low32bits =
    212         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map));
    213     // We always set the in_loop bit to zero when generating the lookup code
    214     // so do it here too so the hash codes match.
    215     uint32_t iflags =
    216         (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
    217     // Base the offset on a simple combination of name, flags, and map.
    218     uint32_t key = (map_low32bits + field) ^ iflags;
    219     return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize);
    220   }
    221 
    222   // Hash algorithm for the secondary table.  This algorithm is replicated in
    223   // assembler for every architecture.  Returns an index into the table that
    224   // is scaled by 1 << kHeapObjectTagSize.
    225   static int SecondaryOffset(Name* name, Code::Flags flags, int seed) {
    226     // Use the seed from the primary cache in the secondary cache.
    227     uint32_t name_low32bits =
    228         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
    229     // We always set the in_loop bit to zero when generating the lookup code
    230     // so do it here too so the hash codes match.
    231     uint32_t iflags =
    232         (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
    233     uint32_t key = (seed - name_low32bits) + iflags;
    234     return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
    235   }
    236 
    237   // Compute the entry for a given offset in exactly the same way as
    238   // we do in generated code.  We generate an hash code that already
    239   // ends in Name::kHashShift 0s.  Then we multiply it so it is a multiple
    240   // of sizeof(Entry).  This makes it easier to avoid making mistakes
    241   // in the hashed offset computations.
    242   static Entry* entry(Entry* table, int offset) {
    243     const int multiplier = sizeof(*table) >> Name::kHashShift;
    244     return reinterpret_cast<Entry*>(
    245         reinterpret_cast<Address>(table) + offset * multiplier);
    246   }
    247 
    248   static const int kPrimaryTableBits = 11;
    249   static const int kPrimaryTableSize = (1 << kPrimaryTableBits);
    250   static const int kSecondaryTableBits = 9;
    251   static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
    252 
    253   Entry primary_[kPrimaryTableSize];
    254   Entry secondary_[kSecondaryTableSize];
    255   Isolate* isolate_;
    256 
    257   friend class Isolate;
    258   friend class SCTableReference;
    259 
    260   DISALLOW_COPY_AND_ASSIGN(StubCache);
    261 };
    262 
    263 
    264 // ------------------------------------------------------------------------
    265 
    266 
    267 // Support functions for IC stubs for callbacks.
    268 DECLARE_RUNTIME_FUNCTION(StoreCallbackProperty);
    269 
    270 
    271 // Support functions for IC stubs for interceptors.
    272 DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly);
    273 DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptor);
    274 DECLARE_RUNTIME_FUNCTION(StoreInterceptorProperty);
    275 DECLARE_RUNTIME_FUNCTION(KeyedLoadPropertyWithInterceptor);
    276 
    277 
    278 enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
    279 enum IcCheckType { ELEMENT, PROPERTY };
    280 
    281 
    282 // The stub compilers compile stubs for the stub cache.
    283 class StubCompiler BASE_EMBEDDED {
    284  public:
    285   explicit StubCompiler(Isolate* isolate,
    286                         ExtraICState extra_ic_state = kNoExtraICState)
    287       : isolate_(isolate), extra_ic_state_(extra_ic_state),
    288         masm_(isolate, NULL, 256) { }
    289 
    290   Handle<Code> CompileLoadInitialize(Code::Flags flags);
    291   Handle<Code> CompileLoadPreMonomorphic(Code::Flags flags);
    292   Handle<Code> CompileLoadMegamorphic(Code::Flags flags);
    293 
    294   Handle<Code> CompileStoreInitialize(Code::Flags flags);
    295   Handle<Code> CompileStorePreMonomorphic(Code::Flags flags);
    296   Handle<Code> CompileStoreGeneric(Code::Flags flags);
    297   Handle<Code> CompileStoreMegamorphic(Code::Flags flags);
    298 
    299   // Static functions for generating parts of stubs.
    300   static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
    301                                                   int index,
    302                                                   Register prototype);
    303 
    304   // Helper function used to check that the dictionary doesn't contain
    305   // the property. This function may return false negatives, so miss_label
    306   // must always call a backup property check that is complete.
    307   // This function is safe to call if the receiver has fast properties.
    308   // Name must be unique and receiver must be a heap object.
    309   static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
    310                                                Label* miss_label,
    311                                                Register receiver,
    312                                                Handle<Name> name,
    313                                                Register r0,
    314                                                Register r1);
    315 
    316   // Generates prototype loading code that uses the objects from the
    317   // context we were in when this function was called. If the context
    318   // has changed, a jump to miss is performed. This ties the generated
    319   // code to a particular context and so must not be used in cases
    320   // where the generated code is not allowed to have references to
    321   // objects from a context.
    322   static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
    323                                                         int index,
    324                                                         Register prototype,
    325                                                         Label* miss);
    326 
    327   static void GenerateFastPropertyLoad(MacroAssembler* masm,
    328                                        Register dst,
    329                                        Register src,
    330                                        bool inobject,
    331                                        int index,
    332                                        Representation representation);
    333 
    334   static void GenerateLoadArrayLength(MacroAssembler* masm,
    335                                       Register receiver,
    336                                       Register scratch,
    337                                       Label* miss_label);
    338 
    339   static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
    340                                             Register receiver,
    341                                             Register scratch1,
    342                                             Register scratch2,
    343                                             Label* miss_label);
    344 
    345   // Generate code to check that a global property cell is empty. Create
    346   // the property cell at compilation time if no cell exists for the
    347   // property.
    348   static void GenerateCheckPropertyCell(MacroAssembler* masm,
    349                                         Handle<JSGlobalObject> global,
    350                                         Handle<Name> name,
    351                                         Register scratch,
    352                                         Label* miss);
    353 
    354   static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
    355 
    356   // Generates code that verifies that the property holder has not changed
    357   // (checking maps of objects in the prototype chain for fast and global
    358   // objects or doing negative lookup for slow objects, ensures that the
    359   // property cells for global objects are still empty) and checks that the map
    360   // of the holder has not changed. If necessary the function also generates
    361   // code for security check in case of global object holders. Helps to make
    362   // sure that the current IC is still valid.
    363   //
    364   // The scratch and holder registers are always clobbered, but the object
    365   // register is only clobbered if it the same as the holder register. The
    366   // function returns a register containing the holder - either object_reg or
    367   // holder_reg.
    368   Register CheckPrototypes(Handle<HeapType> type,
    369                            Register object_reg,
    370                            Handle<JSObject> holder,
    371                            Register holder_reg,
    372                            Register scratch1,
    373                            Register scratch2,
    374                            Handle<Name> name,
    375                            Label* miss,
    376                            PrototypeCheckType check = CHECK_ALL_MAPS);
    377 
    378   static void GenerateFastApiCall(MacroAssembler* masm,
    379                                   const CallOptimization& optimization,
    380                                   Handle<Map> receiver_map,
    381                                   Register receiver,
    382                                   Register scratch,
    383                                   bool is_store,
    384                                   int argc,
    385                                   Register* values);
    386 
    387  protected:
    388   Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
    389   Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name);
    390 
    391   ExtraICState extra_state() { return extra_ic_state_; }
    392 
    393   MacroAssembler* masm() { return &masm_; }
    394 
    395   static void LookupPostInterceptor(Handle<JSObject> holder,
    396                                     Handle<Name> name,
    397                                     LookupResult* lookup);
    398 
    399   Isolate* isolate() { return isolate_; }
    400   Heap* heap() { return isolate()->heap(); }
    401   Factory* factory() { return isolate()->factory(); }
    402 
    403   static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code);
    404 
    405  private:
    406   Isolate* isolate_;
    407   const ExtraICState extra_ic_state_;
    408   MacroAssembler masm_;
    409 };
    410 
    411 
    412 enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS };
    413 
    414 
    415 class BaseLoadStoreStubCompiler: public StubCompiler {
    416  public:
    417   BaseLoadStoreStubCompiler(Isolate* isolate,
    418                             Code::Kind kind,
    419                             ExtraICState extra_ic_state = kNoExtraICState,
    420                             InlineCacheHolderFlag cache_holder = OWN_MAP)
    421       : StubCompiler(isolate, extra_ic_state),
    422         kind_(kind),
    423         cache_holder_(cache_holder) {
    424     InitializeRegisters();
    425   }
    426   virtual ~BaseLoadStoreStubCompiler() { }
    427 
    428   Handle<Code> CompileMonomorphicIC(Handle<HeapType> type,
    429                                     Handle<Code> handler,
    430                                     Handle<Name> name);
    431 
    432   Handle<Code> CompilePolymorphicIC(TypeHandleList* types,
    433                                     CodeHandleList* handlers,
    434                                     Handle<Name> name,
    435                                     Code::StubType type,
    436                                     IcCheckType check);
    437 
    438   static Builtins::Name MissBuiltin(Code::Kind kind) {
    439     switch (kind) {
    440       case Code::LOAD_IC: return Builtins::kLoadIC_Miss;
    441       case Code::STORE_IC: return Builtins::kStoreIC_Miss;
    442       case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss;
    443       case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss;
    444       default: UNREACHABLE();
    445     }
    446     return Builtins::kLoadIC_Miss;
    447   }
    448 
    449  protected:
    450   virtual Register HandlerFrontendHeader(Handle<HeapType> type,
    451                                          Register object_reg,
    452                                          Handle<JSObject> holder,
    453                                          Handle<Name> name,
    454                                          Label* miss) = 0;
    455 
    456   virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss) = 0;
    457 
    458   Register HandlerFrontend(Handle<HeapType> type,
    459                            Register object_reg,
    460                            Handle<JSObject> holder,
    461                            Handle<Name> name);
    462 
    463   Handle<Code> GetCode(Code::Kind kind,
    464                        Code::StubType type,
    465                        Handle<Name> name);
    466 
    467   Handle<Code> GetICCode(Code::Kind kind,
    468                          Code::StubType type,
    469                          Handle<Name> name,
    470                          InlineCacheState state = MONOMORPHIC);
    471   Code::Kind kind() { return kind_; }
    472 
    473   Logger::LogEventsAndTags log_kind(Handle<Code> code) {
    474     if (!code->is_inline_cache_stub()) return Logger::STUB_TAG;
    475     if (kind_ == Code::LOAD_IC) {
    476       return code->ic_state() == MONOMORPHIC
    477           ? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG;
    478     } else if (kind_ == Code::KEYED_LOAD_IC) {
    479       return code->ic_state() == MONOMORPHIC
    480           ? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG;
    481     } else if (kind_ == Code::STORE_IC) {
    482       return code->ic_state() == MONOMORPHIC
    483           ? Logger::STORE_IC_TAG : Logger::STORE_POLYMORPHIC_IC_TAG;
    484     } else {
    485       return code->ic_state() == MONOMORPHIC
    486           ? Logger::KEYED_STORE_IC_TAG : Logger::KEYED_STORE_POLYMORPHIC_IC_TAG;
    487     }
    488   }
    489   void JitEvent(Handle<Name> name, Handle<Code> code);
    490 
    491   Register receiver() { return registers_[0]; }
    492   Register name()     { return registers_[1]; }
    493   Register scratch1() { return registers_[2]; }
    494   Register scratch2() { return registers_[3]; }
    495   Register scratch3() { return registers_[4]; }
    496 
    497   void InitializeRegisters();
    498 
    499   bool IncludesNumberType(TypeHandleList* types);
    500 
    501   Code::Kind kind_;
    502   InlineCacheHolderFlag cache_holder_;
    503   Register* registers_;
    504 };
    505 
    506 
    507 class LoadStubCompiler: public BaseLoadStoreStubCompiler {
    508  public:
    509   LoadStubCompiler(Isolate* isolate,
    510                    ExtraICState extra_ic_state = kNoExtraICState,
    511                    InlineCacheHolderFlag cache_holder = OWN_MAP,
    512                    Code::Kind kind = Code::LOAD_IC)
    513       : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state,
    514                                   cache_holder) { }
    515   virtual ~LoadStubCompiler() { }
    516 
    517   Handle<Code> CompileLoadField(Handle<HeapType> type,
    518                                 Handle<JSObject> holder,
    519                                 Handle<Name> name,
    520                                 FieldIndex index,
    521                                 Representation representation);
    522 
    523   Handle<Code> CompileLoadCallback(Handle<HeapType> type,
    524                                    Handle<JSObject> holder,
    525                                    Handle<Name> name,
    526                                    Handle<ExecutableAccessorInfo> callback);
    527 
    528   Handle<Code> CompileLoadCallback(Handle<HeapType> type,
    529                                    Handle<JSObject> holder,
    530                                    Handle<Name> name,
    531                                    const CallOptimization& call_optimization);
    532 
    533   Handle<Code> CompileLoadConstant(Handle<HeapType> type,
    534                                    Handle<JSObject> holder,
    535                                    Handle<Name> name,
    536                                    Handle<Object> value);
    537 
    538   Handle<Code> CompileLoadInterceptor(Handle<HeapType> type,
    539                                       Handle<JSObject> holder,
    540                                       Handle<Name> name);
    541 
    542   Handle<Code> CompileLoadViaGetter(Handle<HeapType> type,
    543                                     Handle<JSObject> holder,
    544                                     Handle<Name> name,
    545                                     Handle<JSFunction> getter);
    546 
    547   static void GenerateLoadViaGetter(MacroAssembler* masm,
    548                                     Handle<HeapType> type,
    549                                     Register receiver,
    550                                     Handle<JSFunction> getter);
    551 
    552   static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) {
    553     GenerateLoadViaGetter(
    554         masm, Handle<HeapType>::null(), no_reg, Handle<JSFunction>());
    555   }
    556 
    557   Handle<Code> CompileLoadNonexistent(Handle<HeapType> type,
    558                                       Handle<JSObject> last,
    559                                       Handle<Name> name);
    560 
    561   Handle<Code> CompileLoadGlobal(Handle<HeapType> type,
    562                                  Handle<GlobalObject> holder,
    563                                  Handle<PropertyCell> cell,
    564                                  Handle<Name> name,
    565                                  bool is_dont_delete);
    566 
    567  protected:
    568   ContextualMode contextual_mode() {
    569     return LoadIC::GetContextualMode(extra_state());
    570   }
    571 
    572   virtual Register HandlerFrontendHeader(Handle<HeapType> type,
    573                                          Register object_reg,
    574                                          Handle<JSObject> holder,
    575                                          Handle<Name> name,
    576                                          Label* miss);
    577 
    578   virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss);
    579 
    580   Register CallbackHandlerFrontend(Handle<HeapType> type,
    581                                    Register object_reg,
    582                                    Handle<JSObject> holder,
    583                                    Handle<Name> name,
    584                                    Handle<Object> callback);
    585   void NonexistentHandlerFrontend(Handle<HeapType> type,
    586                                   Handle<JSObject> last,
    587                                   Handle<Name> name);
    588 
    589   void GenerateLoadField(Register reg,
    590                          Handle<JSObject> holder,
    591                          FieldIndex field,
    592                          Representation representation);
    593   void GenerateLoadConstant(Handle<Object> value);
    594   void GenerateLoadCallback(Register reg,
    595                             Handle<ExecutableAccessorInfo> callback);
    596   void GenerateLoadCallback(const CallOptimization& call_optimization,
    597                             Handle<Map> receiver_map);
    598   void GenerateLoadInterceptor(Register holder_reg,
    599                                Handle<Object> object,
    600                                Handle<JSObject> holder,
    601                                LookupResult* lookup,
    602                                Handle<Name> name);
    603   void GenerateLoadPostInterceptor(Register reg,
    604                                    Handle<JSObject> interceptor_holder,
    605                                    Handle<Name> name,
    606                                    LookupResult* lookup);
    607 
    608  private:
    609   static Register* registers();
    610   Register scratch4() { return registers_[5]; }
    611   friend class BaseLoadStoreStubCompiler;
    612 };
    613 
    614 
    615 class KeyedLoadStubCompiler: public LoadStubCompiler {
    616  public:
    617   KeyedLoadStubCompiler(Isolate* isolate,
    618                         ExtraICState extra_ic_state = kNoExtraICState,
    619                         InlineCacheHolderFlag cache_holder = OWN_MAP)
    620       : LoadStubCompiler(isolate, extra_ic_state, cache_holder,
    621                          Code::KEYED_LOAD_IC) { }
    622 
    623   Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
    624 
    625   void CompileElementHandlers(MapHandleList* receiver_maps,
    626                               CodeHandleList* handlers);
    627 
    628   static void GenerateLoadDictionaryElement(MacroAssembler* masm);
    629 
    630  private:
    631   static Register* registers();
    632   friend class BaseLoadStoreStubCompiler;
    633 };
    634 
    635 
    636 class StoreStubCompiler: public BaseLoadStoreStubCompiler {
    637  public:
    638   StoreStubCompiler(Isolate* isolate,
    639                     ExtraICState extra_ic_state,
    640                     Code::Kind kind = Code::STORE_IC)
    641       : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state) {}
    642 
    643   virtual ~StoreStubCompiler() { }
    644 
    645   Handle<Code> CompileStoreTransition(Handle<JSObject> object,
    646                                       LookupResult* lookup,
    647                                       Handle<Map> transition,
    648                                       Handle<Name> name);
    649 
    650   Handle<Code> CompileStoreField(Handle<JSObject> object,
    651                                  LookupResult* lookup,
    652                                  Handle<Name> name);
    653 
    654   Handle<Code> CompileStoreArrayLength(Handle<JSObject> object,
    655                                        LookupResult* lookup,
    656                                        Handle<Name> name);
    657 
    658   void GenerateStoreArrayLength();
    659 
    660   void GenerateNegativeHolderLookup(MacroAssembler* masm,
    661                                     Handle<JSObject> holder,
    662                                     Register holder_reg,
    663                                     Handle<Name> name,
    664                                     Label* miss);
    665 
    666   void GenerateStoreTransition(MacroAssembler* masm,
    667                                Handle<JSObject> object,
    668                                LookupResult* lookup,
    669                                Handle<Map> transition,
    670                                Handle<Name> name,
    671                                Register receiver_reg,
    672                                Register name_reg,
    673                                Register value_reg,
    674                                Register scratch1,
    675                                Register scratch2,
    676                                Register scratch3,
    677                                Label* miss_label,
    678                                Label* slow);
    679 
    680   void GenerateStoreField(MacroAssembler* masm,
    681                           Handle<JSObject> object,
    682                           LookupResult* lookup,
    683                           Register receiver_reg,
    684                           Register name_reg,
    685                           Register value_reg,
    686                           Register scratch1,
    687                           Register scratch2,
    688                           Label* miss_label);
    689 
    690   Handle<Code> CompileStoreCallback(Handle<JSObject> object,
    691                                     Handle<JSObject> holder,
    692                                     Handle<Name> name,
    693                                     Handle<ExecutableAccessorInfo> callback);
    694 
    695   Handle<Code> CompileStoreCallback(Handle<JSObject> object,
    696                                     Handle<JSObject> holder,
    697                                     Handle<Name> name,
    698                                     const CallOptimization& call_optimization);
    699 
    700   static void GenerateStoreViaSetter(MacroAssembler* masm,
    701                                      Handle<HeapType> type,
    702                                      Register receiver,
    703                                      Handle<JSFunction> setter);
    704 
    705   static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) {
    706     GenerateStoreViaSetter(
    707         masm, Handle<HeapType>::null(), no_reg, Handle<JSFunction>());
    708   }
    709 
    710   Handle<Code> CompileStoreViaSetter(Handle<JSObject> object,
    711                                      Handle<JSObject> holder,
    712                                      Handle<Name> name,
    713                                      Handle<JSFunction> setter);
    714 
    715   Handle<Code> CompileStoreInterceptor(Handle<JSObject> object,
    716                                        Handle<Name> name);
    717 
    718   static Builtins::Name SlowBuiltin(Code::Kind kind) {
    719     switch (kind) {
    720       case Code::STORE_IC: return Builtins::kStoreIC_Slow;
    721       case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow;
    722       default: UNREACHABLE();
    723     }
    724     return Builtins::kStoreIC_Slow;
    725   }
    726 
    727  protected:
    728   virtual Register HandlerFrontendHeader(Handle<HeapType> type,
    729                                          Register object_reg,
    730                                          Handle<JSObject> holder,
    731                                          Handle<Name> name,
    732                                          Label* miss);
    733 
    734   virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss);
    735   void GenerateRestoreName(MacroAssembler* masm,
    736                            Label* label,
    737                            Handle<Name> name);
    738 
    739  private:
    740   static Register* registers();
    741   static Register value();
    742   friend class BaseLoadStoreStubCompiler;
    743 };
    744 
    745 
    746 class KeyedStoreStubCompiler: public StoreStubCompiler {
    747  public:
    748   KeyedStoreStubCompiler(Isolate* isolate,
    749                          ExtraICState extra_ic_state)
    750       : StoreStubCompiler(isolate, extra_ic_state, Code::KEYED_STORE_IC) {}
    751 
    752   Handle<Code> CompileStoreElement(Handle<Map> receiver_map);
    753 
    754   Handle<Code> CompileStorePolymorphic(MapHandleList* receiver_maps,
    755                                        CodeHandleList* handler_stubs,
    756                                        MapHandleList* transitioned_maps);
    757 
    758   Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps);
    759 
    760   static void GenerateStoreDictionaryElement(MacroAssembler* masm);
    761 
    762  private:
    763   static Register* registers();
    764 
    765   KeyedAccessStoreMode store_mode() {
    766     return KeyedStoreIC::GetKeyedAccessStoreMode(extra_state());
    767   }
    768 
    769   Register transition_map() { return scratch1(); }
    770 
    771   friend class BaseLoadStoreStubCompiler;
    772 };
    773 
    774 
    775 // Holds information about possible function call optimizations.
    776 class CallOptimization BASE_EMBEDDED {
    777  public:
    778   explicit CallOptimization(LookupResult* lookup);
    779 
    780   explicit CallOptimization(Handle<JSFunction> function);
    781 
    782   bool is_constant_call() const {
    783     return !constant_function_.is_null();
    784   }
    785 
    786   Handle<JSFunction> constant_function() const {
    787     ASSERT(is_constant_call());
    788     return constant_function_;
    789   }
    790 
    791   bool is_simple_api_call() const {
    792     return is_simple_api_call_;
    793   }
    794 
    795   Handle<FunctionTemplateInfo> expected_receiver_type() const {
    796     ASSERT(is_simple_api_call());
    797     return expected_receiver_type_;
    798   }
    799 
    800   Handle<CallHandlerInfo> api_call_info() const {
    801     ASSERT(is_simple_api_call());
    802     return api_call_info_;
    803   }
    804 
    805   enum HolderLookup {
    806     kHolderNotFound,
    807     kHolderIsReceiver,
    808     kHolderFound
    809   };
    810   Handle<JSObject> LookupHolderOfExpectedType(
    811       Handle<Map> receiver_map,
    812       HolderLookup* holder_lookup) const;
    813 
    814   // Check if the api holder is between the receiver and the holder.
    815   bool IsCompatibleReceiver(Handle<Object> receiver,
    816                             Handle<JSObject> holder) const;
    817 
    818  private:
    819   void Initialize(Handle<JSFunction> function);
    820 
    821   // Determines whether the given function can be called using the
    822   // fast api call builtin.
    823   void AnalyzePossibleApiFunction(Handle<JSFunction> function);
    824 
    825   Handle<JSFunction> constant_function_;
    826   bool is_simple_api_call_;
    827   Handle<FunctionTemplateInfo> expected_receiver_type_;
    828   Handle<CallHandlerInfo> api_call_info_;
    829 };
    830 
    831 
    832 } }  // namespace v8::internal
    833 
    834 #endif  // V8_STUB_CACHE_H_
    835