• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
address()36   Address address() const { return address_; }
37 
38  private:
SCTableReference(Address address)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 
key_reference(StubCache::Table table)145   SCTableReference key_reference(StubCache::Table table) {
146     return SCTableReference(
147         reinterpret_cast<Address>(&first_entry(table)->key));
148   }
149 
150 
map_reference(StubCache::Table table)151   SCTableReference map_reference(StubCache::Table table) {
152     return SCTableReference(
153         reinterpret_cast<Address>(&first_entry(table)->map));
154   }
155 
156 
value_reference(StubCache::Table table)157   SCTableReference value_reference(StubCache::Table table) {
158     return SCTableReference(
159         reinterpret_cast<Address>(&first_entry(table)->value));
160   }
161 
162 
first_entry(StubCache::Table table)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 
isolate()172   Isolate* isolate() { return isolate_; }
heap()173   Heap* heap() { return isolate()->heap(); }
factory()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.
PrimaryOffset(Name * name,Code::Flags flags,Map * map)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.
SecondaryOffset(Name * name,Code::Flags flags,int seed)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.
entry(Entry * table,int offset)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)
isolate_(isolate)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 
extra_state()391   ExtraICState extra_state() { return extra_ic_state_; }
392 
masm()393   MacroAssembler* masm() { return &masm_; }
394 
395   static void LookupPostInterceptor(Handle<JSObject> holder,
396                                     Handle<Name> name,
397                                     LookupResult* lookup);
398 
isolate()399   Isolate* isolate() { return isolate_; }
heap()400   Heap* heap() { return isolate()->heap(); }
factory()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)
StubCompiler(isolate,extra_ic_state)421       : StubCompiler(isolate, extra_ic_state),
422         kind_(kind),
423         cache_holder_(cache_holder) {
424     InitializeRegisters();
425   }
~BaseLoadStoreStubCompiler()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 
MissBuiltin(Code::Kind kind)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);
kind()471   Code::Kind kind() { return kind_; }
472 
log_kind(Handle<Code> code)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 
receiver()491   Register receiver() { return registers_[0]; }
name()492   Register name()     { return registers_[1]; }
scratch1()493   Register scratch1() { return registers_[2]; }
scratch2()494   Register scratch2() { return registers_[3]; }
scratch3()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)
BaseLoadStoreStubCompiler(isolate,kind,extra_ic_state,cache_holder)513       : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state,
514                                   cache_holder) { }
~LoadStubCompiler()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 
GenerateLoadViaGetterForDeopt(MacroAssembler * masm)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:
contextual_mode()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();
scratch4()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)
LoadStubCompiler(isolate,extra_ic_state,cache_holder,Code::KEYED_LOAD_IC)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)
BaseLoadStoreStubCompiler(isolate,kind,extra_ic_state)641       : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state) {}
642 
~StoreStubCompiler()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 
GenerateStoreViaSetterForDeopt(MacroAssembler * masm)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 
SlowBuiltin(Code::Kind kind)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:
KeyedStoreStubCompiler(Isolate * isolate,ExtraICState extra_ic_state)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 
store_mode()765   KeyedAccessStoreMode store_mode() {
766     return KeyedStoreIC::GetKeyedAccessStoreMode(extra_state());
767   }
768 
transition_map()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 
is_constant_call()782   bool is_constant_call() const {
783     return !constant_function_.is_null();
784   }
785 
constant_function()786   Handle<JSFunction> constant_function() const {
787     ASSERT(is_constant_call());
788     return constant_function_;
789   }
790 
is_simple_api_call()791   bool is_simple_api_call() const {
792     return is_simple_api_call_;
793   }
794 
expected_receiver_type()795   Handle<FunctionTemplateInfo> expected_receiver_type() const {
796     ASSERT(is_simple_api_call());
797     return expected_receiver_type_;
798   }
799 
api_call_info()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