Home | History | Annotate | Download | only in src
      1 // Copyright 2006-2008 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_STUB_CACHE_H_
     29 #define V8_STUB_CACHE_H_
     30 
     31 #include "macro-assembler.h"
     32 
     33 namespace v8 {
     34 namespace internal {
     35 
     36 
     37 // The stub cache is used for megamorphic calls and property accesses.
     38 // It maps (map, name, type)->Code*
     39 
     40 // The design of the table uses the inline cache stubs used for
     41 // mono-morphic calls. The beauty of this, we do not have to
     42 // invalidate the cache whenever a prototype map is changed.  The stub
     43 // validates the map chain as in the mono-morphic case.
     44 
     45 class SCTableReference;
     46 
     47 class StubCache : public AllStatic {
     48  public:
     49   struct Entry {
     50     String* key;
     51     Code* value;
     52   };
     53 
     54 
     55   static void Initialize(bool create_heap_objects);
     56 
     57   // Computes the right stub matching. Inserts the result in the
     58   // cache before returning.  This might compile a stub if needed.
     59   static Object* ComputeLoadField(String* name,
     60                                   JSObject* receiver,
     61                                   JSObject* holder,
     62                                   int field_index);
     63 
     64   static Object* ComputeLoadCallback(String* name,
     65                                      JSObject* receiver,
     66                                      JSObject* holder,
     67                                      AccessorInfo* callback);
     68 
     69   static Object* ComputeLoadConstant(String* name,
     70                                      JSObject* receiver,
     71                                      JSObject* holder,
     72                                      Object* value);
     73 
     74   static Object* ComputeLoadInterceptor(String* name,
     75                                         JSObject* receiver,
     76                                         JSObject* holder);
     77 
     78   static Object* ComputeLoadNormal(String* name, JSObject* receiver);
     79 
     80 
     81   static Object* ComputeLoadGlobal(String* name,
     82                                    JSObject* receiver,
     83                                    GlobalObject* holder,
     84                                    JSGlobalPropertyCell* cell,
     85                                    bool is_dont_delete);
     86 
     87 
     88   // ---
     89 
     90   static Object* ComputeKeyedLoadField(String* name,
     91                                        JSObject* receiver,
     92                                        JSObject* holder,
     93                                        int field_index);
     94 
     95   static Object* ComputeKeyedLoadCallback(String* name,
     96                                           JSObject* receiver,
     97                                           JSObject* holder,
     98                                           AccessorInfo* callback);
     99 
    100   static Object* ComputeKeyedLoadConstant(String* name, JSObject* receiver,
    101                                           JSObject* holder, Object* value);
    102 
    103   static Object* ComputeKeyedLoadInterceptor(String* name,
    104                                              JSObject* receiver,
    105                                              JSObject* holder);
    106 
    107   static Object* ComputeKeyedLoadArrayLength(String* name, JSArray* receiver);
    108 
    109   static Object* ComputeKeyedLoadStringLength(String* name,
    110                                               String* receiver);
    111 
    112   static Object* ComputeKeyedLoadFunctionPrototype(String* name,
    113                                                    JSFunction* receiver);
    114 
    115   // ---
    116 
    117   static Object* ComputeStoreField(String* name,
    118                                    JSObject* receiver,
    119                                    int field_index,
    120                                    Map* transition = NULL);
    121 
    122   static Object* ComputeStoreGlobal(String* name,
    123                                     GlobalObject* receiver,
    124                                     JSGlobalPropertyCell* cell);
    125 
    126   static Object* ComputeStoreCallback(String* name,
    127                                       JSObject* receiver,
    128                                       AccessorInfo* callback);
    129 
    130   static Object* ComputeStoreInterceptor(String* name, JSObject* receiver);
    131 
    132   // ---
    133 
    134   static Object* ComputeKeyedStoreField(String* name,
    135                                         JSObject* receiver,
    136                                         int field_index,
    137                                         Map* transition = NULL);
    138 
    139   // ---
    140 
    141   static Object* ComputeCallField(int argc,
    142                                   InLoopFlag in_loop,
    143                                   String* name,
    144                                   Object* object,
    145                                   JSObject* holder,
    146                                   int index);
    147 
    148   static Object* ComputeCallConstant(int argc,
    149                                      InLoopFlag in_loop,
    150                                      String* name,
    151                                      Object* object,
    152                                      JSObject* holder,
    153                                      JSFunction* function);
    154 
    155   static Object* ComputeCallNormal(int argc,
    156                                    InLoopFlag in_loop,
    157                                    String* name,
    158                                    JSObject* receiver);
    159 
    160   static Object* ComputeCallInterceptor(int argc,
    161                                         String* name,
    162                                         Object* object,
    163                                         JSObject* holder);
    164 
    165   static Object* ComputeCallGlobal(int argc,
    166                                    InLoopFlag in_loop,
    167                                    String* name,
    168                                    JSObject* receiver,
    169                                    GlobalObject* holder,
    170                                    JSGlobalPropertyCell* cell,
    171                                    JSFunction* function);
    172 
    173   // ---
    174 
    175   static Object* ComputeCallInitialize(int argc, InLoopFlag in_loop);
    176   static Object* ComputeCallPreMonomorphic(int argc, InLoopFlag in_loop);
    177   static Object* ComputeCallNormal(int argc, InLoopFlag in_loop);
    178   static Object* ComputeCallMegamorphic(int argc, InLoopFlag in_loop);
    179   static Object* ComputeCallMiss(int argc);
    180 
    181   // Finds the Code object stored in the Heap::non_monomorphic_cache().
    182   static Code* FindCallInitialize(int argc, InLoopFlag in_loop);
    183 
    184 #ifdef ENABLE_DEBUGGER_SUPPORT
    185   static Object* ComputeCallDebugBreak(int argc);
    186   static Object* ComputeCallDebugPrepareStepIn(int argc);
    187 #endif
    188 
    189   static Object* ComputeLazyCompile(int argc);
    190 
    191 
    192   // Update cache for entry hash(name, map).
    193   static Code* Set(String* name, Map* map, Code* code);
    194 
    195   // Clear the lookup table (@ mark compact collection).
    196   static void Clear();
    197 
    198   // Functions for generating stubs at startup.
    199   static void GenerateMiss(MacroAssembler* masm);
    200 
    201   // Generate code for probing the stub cache table.
    202   // If extra != no_reg it might be used as am extra scratch register.
    203   static void GenerateProbe(MacroAssembler* masm,
    204                             Code::Flags flags,
    205                             Register receiver,
    206                             Register name,
    207                             Register scratch,
    208                             Register extra);
    209 
    210   enum Table {
    211     kPrimary,
    212     kSecondary
    213   };
    214 
    215  private:
    216   friend class SCTableReference;
    217   static const int kPrimaryTableSize = 2048;
    218   static const int kSecondaryTableSize = 512;
    219   static Entry primary_[];
    220   static Entry secondary_[];
    221 
    222   // Computes the hashed offsets for primary and secondary caches.
    223   static int PrimaryOffset(String* name, Code::Flags flags, Map* map) {
    224     // This works well because the heap object tag size and the hash
    225     // shift are equal.  Shifting down the length field to get the
    226     // hash code would effectively throw away two bits of the hash
    227     // code.
    228     ASSERT(kHeapObjectTagSize == String::kHashShift);
    229     // Compute the hash of the name (use entire hash field).
    230     ASSERT(name->HasHashCode());
    231     uint32_t field = name->hash_field();
    232     // Using only the low bits in 64-bit mode is unlikely to increase the
    233     // risk of collision even if the heap is spread over an area larger than
    234     // 4Gb (and not at all if it isn't).
    235     uint32_t map_low32bits =
    236         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map));
    237     // We always set the in_loop bit to zero when generating the lookup code
    238     // so do it here too so the hash codes match.
    239     uint32_t iflags =
    240         (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
    241     // Base the offset on a simple combination of name, flags, and map.
    242     uint32_t key = (map_low32bits + field) ^ iflags;
    243     return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize);
    244   }
    245 
    246   static int SecondaryOffset(String* name, Code::Flags flags, int seed) {
    247     // Use the seed from the primary cache in the secondary cache.
    248     uint32_t string_low32bits =
    249         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
    250     // We always set the in_loop bit to zero when generating the lookup code
    251     // so do it here too so the hash codes match.
    252     uint32_t iflags =
    253         (static_cast<uint32_t>(flags) & ~Code::kFlagsICInLoopMask);
    254     uint32_t key = seed - string_low32bits + iflags;
    255     return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
    256   }
    257 
    258   // Compute the entry for a given offset in exactly the same way as
    259   // we do in generated code.  We generate an hash code that already
    260   // ends in String::kHashShift 0s.  Then we shift it so it is a multiple
    261   // of sizeof(Entry).  This makes it easier to avoid making mistakes
    262   // in the hashed offset computations.
    263   static Entry* entry(Entry* table, int offset) {
    264     const int shift_amount = kPointerSizeLog2 + 1 - String::kHashShift;
    265     return reinterpret_cast<Entry*>(
    266         reinterpret_cast<Address>(table) + (offset << shift_amount));
    267   }
    268 };
    269 
    270 
    271 class SCTableReference {
    272  public:
    273   static SCTableReference keyReference(StubCache::Table table) {
    274     return SCTableReference(
    275         reinterpret_cast<Address>(&first_entry(table)->key));
    276   }
    277 
    278 
    279   static SCTableReference valueReference(StubCache::Table table) {
    280     return SCTableReference(
    281         reinterpret_cast<Address>(&first_entry(table)->value));
    282   }
    283 
    284   Address address() const { return address_; }
    285 
    286  private:
    287   explicit SCTableReference(Address address) : address_(address) {}
    288 
    289   static StubCache::Entry* first_entry(StubCache::Table table) {
    290     switch (table) {
    291       case StubCache::kPrimary: return StubCache::primary_;
    292       case StubCache::kSecondary: return StubCache::secondary_;
    293     }
    294     UNREACHABLE();
    295     return NULL;
    296   }
    297 
    298   Address address_;
    299 };
    300 
    301 // ------------------------------------------------------------------------
    302 
    303 
    304 // Support functions for IC stubs for callbacks.
    305 Object* LoadCallbackProperty(Arguments args);
    306 Object* StoreCallbackProperty(Arguments args);
    307 
    308 
    309 // Support functions for IC stubs for interceptors.
    310 Object* LoadPropertyWithInterceptorOnly(Arguments args);
    311 Object* LoadPropertyWithInterceptorForLoad(Arguments args);
    312 Object* LoadPropertyWithInterceptorForCall(Arguments args);
    313 Object* StoreInterceptorProperty(Arguments args);
    314 Object* CallInterceptorProperty(Arguments args);
    315 Object* KeyedLoadPropertyWithInterceptor(Arguments args);
    316 
    317 
    318 // Support function for computing call IC miss stubs.
    319 Handle<Code> ComputeCallMiss(int argc);
    320 
    321 
    322 // The stub compiler compiles stubs for the stub cache.
    323 class StubCompiler BASE_EMBEDDED {
    324  public:
    325   enum CheckType {
    326     RECEIVER_MAP_CHECK,
    327     STRING_CHECK,
    328     NUMBER_CHECK,
    329     BOOLEAN_CHECK,
    330     JSARRAY_HAS_FAST_ELEMENTS_CHECK
    331   };
    332 
    333   StubCompiler() : scope_(), masm_(NULL, 256), failure_(NULL) { }
    334 
    335   Object* CompileCallInitialize(Code::Flags flags);
    336   Object* CompileCallPreMonomorphic(Code::Flags flags);
    337   Object* CompileCallNormal(Code::Flags flags);
    338   Object* CompileCallMegamorphic(Code::Flags flags);
    339   Object* CompileCallMiss(Code::Flags flags);
    340 #ifdef ENABLE_DEBUGGER_SUPPORT
    341   Object* CompileCallDebugBreak(Code::Flags flags);
    342   Object* CompileCallDebugPrepareStepIn(Code::Flags flags);
    343 #endif
    344   Object* CompileLazyCompile(Code::Flags flags);
    345 
    346   // Static functions for generating parts of stubs.
    347   static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
    348                                                   int index,
    349                                                   Register prototype);
    350 
    351   static void GenerateFastPropertyLoad(MacroAssembler* masm,
    352                                        Register dst, Register src,
    353                                        JSObject* holder, int index);
    354 
    355   static void GenerateLoadArrayLength(MacroAssembler* masm,
    356                                       Register receiver,
    357                                       Register scratch,
    358                                       Label* miss_label);
    359 
    360   static void GenerateLoadStringLength(MacroAssembler* masm,
    361                                        Register receiver,
    362                                        Register scratch1,
    363                                        Register scratch2,
    364                                        Label* miss_label);
    365 
    366   static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
    367                                             Register receiver,
    368                                             Register scratch1,
    369                                             Register scratch2,
    370                                             Label* miss_label);
    371 
    372   static void GenerateStoreField(MacroAssembler* masm,
    373                                  JSObject* object,
    374                                  int index,
    375                                  Map* transition,
    376                                  Register receiver_reg,
    377                                  Register name_reg,
    378                                  Register scratch,
    379                                  Label* miss_label);
    380 
    381   static void GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind);
    382 
    383   // Check the integrity of the prototype chain to make sure that the
    384   // current IC is still valid.
    385 
    386   Register CheckPrototypes(JSObject* object,
    387                            Register object_reg,
    388                            JSObject* holder,
    389                            Register holder_reg,
    390                            Register scratch,
    391                            String* name,
    392                            Label* miss) {
    393     return CheckPrototypes(object, object_reg, holder, holder_reg, scratch,
    394                            name, kInvalidProtoDepth, miss);
    395   }
    396 
    397   Register CheckPrototypes(JSObject* object,
    398                            Register object_reg,
    399                            JSObject* holder,
    400                            Register holder_reg,
    401                            Register scratch,
    402                            String* name,
    403                            int save_at_depth,
    404                            Label* miss);
    405 
    406  protected:
    407   Object* GetCodeWithFlags(Code::Flags flags, const char* name);
    408   Object* GetCodeWithFlags(Code::Flags flags, String* name);
    409 
    410   MacroAssembler* masm() { return &masm_; }
    411   void set_failure(Failure* failure) { failure_ = failure; }
    412 
    413   void GenerateLoadField(JSObject* object,
    414                          JSObject* holder,
    415                          Register receiver,
    416                          Register scratch1,
    417                          Register scratch2,
    418                          int index,
    419                          String* name,
    420                          Label* miss);
    421 
    422   bool GenerateLoadCallback(JSObject* object,
    423                             JSObject* holder,
    424                             Register receiver,
    425                             Register name_reg,
    426                             Register scratch1,
    427                             Register scratch2,
    428                             AccessorInfo* callback,
    429                             String* name,
    430                             Label* miss,
    431                             Failure** failure);
    432 
    433   void GenerateLoadConstant(JSObject* object,
    434                             JSObject* holder,
    435                             Register receiver,
    436                             Register scratch1,
    437                             Register scratch2,
    438                             Object* value,
    439                             String* name,
    440                             Label* miss);
    441 
    442   void GenerateLoadInterceptor(JSObject* object,
    443                                JSObject* holder,
    444                                LookupResult* lookup,
    445                                Register receiver,
    446                                Register name_reg,
    447                                Register scratch1,
    448                                Register scratch2,
    449                                String* name,
    450                                Label* miss);
    451 
    452   static void LookupPostInterceptor(JSObject* holder,
    453                                     String* name,
    454                                     LookupResult* lookup);
    455 
    456  private:
    457   HandleScope scope_;
    458   MacroAssembler masm_;
    459   Failure* failure_;
    460 };
    461 
    462 
    463 class LoadStubCompiler: public StubCompiler {
    464  public:
    465   Object* CompileLoadField(JSObject* object,
    466                            JSObject* holder,
    467                            int index,
    468                            String* name);
    469   Object* CompileLoadCallback(String* name,
    470                               JSObject* object,
    471                               JSObject* holder,
    472                               AccessorInfo* callback);
    473   Object* CompileLoadConstant(JSObject* object,
    474                               JSObject* holder,
    475                               Object* value,
    476                               String* name);
    477   Object* CompileLoadInterceptor(JSObject* object,
    478                                  JSObject* holder,
    479                                  String* name);
    480 
    481   Object* CompileLoadGlobal(JSObject* object,
    482                             GlobalObject* holder,
    483                             JSGlobalPropertyCell* cell,
    484                             String* name,
    485                             bool is_dont_delete);
    486 
    487  private:
    488   Object* GetCode(PropertyType type, String* name);
    489 };
    490 
    491 
    492 class KeyedLoadStubCompiler: public StubCompiler {
    493  public:
    494   Object* CompileLoadField(String* name,
    495                            JSObject* object,
    496                            JSObject* holder,
    497                            int index);
    498   Object* CompileLoadCallback(String* name,
    499                               JSObject* object,
    500                               JSObject* holder,
    501                               AccessorInfo* callback);
    502   Object* CompileLoadConstant(String* name,
    503                               JSObject* object,
    504                               JSObject* holder,
    505                               Object* value);
    506   Object* CompileLoadInterceptor(JSObject* object,
    507                                  JSObject* holder,
    508                                  String* name);
    509   Object* CompileLoadArrayLength(String* name);
    510   Object* CompileLoadStringLength(String* name);
    511   Object* CompileLoadFunctionPrototype(String* name);
    512 
    513  private:
    514   Object* GetCode(PropertyType type, String* name);
    515 };
    516 
    517 
    518 class StoreStubCompiler: public StubCompiler {
    519  public:
    520   Object* CompileStoreField(JSObject* object,
    521                             int index,
    522                             Map* transition,
    523                             String* name);
    524   Object* CompileStoreCallback(JSObject* object,
    525                                AccessorInfo* callbacks,
    526                                String* name);
    527   Object* CompileStoreInterceptor(JSObject* object, String* name);
    528   Object* CompileStoreGlobal(GlobalObject* object,
    529                              JSGlobalPropertyCell* holder,
    530                              String* name);
    531 
    532 
    533  private:
    534   Object* GetCode(PropertyType type, String* name);
    535 };
    536 
    537 
    538 class KeyedStoreStubCompiler: public StubCompiler {
    539  public:
    540   Object* CompileStoreField(JSObject* object,
    541                             int index,
    542                             Map* transition,
    543                             String* name);
    544 
    545  private:
    546   Object* GetCode(PropertyType type, String* name);
    547 };
    548 
    549 
    550 class CallStubCompiler: public StubCompiler {
    551  public:
    552   explicit CallStubCompiler(int argc, InLoopFlag in_loop)
    553       : arguments_(argc), in_loop_(in_loop) { }
    554 
    555   Object* CompileCallField(JSObject* object,
    556                            JSObject* holder,
    557                            int index,
    558                            String* name);
    559   Object* CompileCallConstant(Object* object,
    560                               JSObject* holder,
    561                               JSFunction* function,
    562                               String* name,
    563                               CheckType check);
    564   Object* CompileCallInterceptor(JSObject* object,
    565                                  JSObject* holder,
    566                                  String* name);
    567   Object* CompileCallGlobal(JSObject* object,
    568                             GlobalObject* holder,
    569                             JSGlobalPropertyCell* cell,
    570                             JSFunction* function,
    571                             String* name);
    572 
    573  private:
    574   const ParameterCount arguments_;
    575   const InLoopFlag in_loop_;
    576 
    577   const ParameterCount& arguments() { return arguments_; }
    578 
    579   Object* GetCode(PropertyType type, String* name);
    580 };
    581 
    582 
    583 class ConstructStubCompiler: public StubCompiler {
    584  public:
    585   explicit ConstructStubCompiler() {}
    586 
    587   Object* CompileConstructStub(SharedFunctionInfo* shared);
    588 
    589  private:
    590   Object* GetCode();
    591 };
    592 
    593 
    594 } }  // namespace v8::internal
    595 
    596 #endif  // V8_STUB_CACHE_H_
    597