• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_STUB_CACHE_H_
29 #define V8_STUB_CACHE_H_
30 
31 #include "allocation.h"
32 #include "arguments.h"
33 #include "code-stubs.h"
34 #include "ic-inl.h"
35 #include "macro-assembler.h"
36 #include "objects.h"
37 #include "zone-inl.h"
38 
39 namespace v8 {
40 namespace internal {
41 
42 
43 // The stub cache is used for megamorphic calls and property accesses.
44 // It maps (map, name, type)->Code*
45 
46 // The design of the table uses the inline cache stubs used for
47 // mono-morphic calls. The beauty of this, we do not have to
48 // invalidate the cache whenever a prototype map is changed.  The stub
49 // validates the map chain as in the mono-morphic case.
50 
51 
52 class CallOptimization;
53 class SmallMapList;
54 class StubCache;
55 
56 
57 class SCTableReference {
58  public:
address()59   Address address() const { return address_; }
60 
61  private:
SCTableReference(Address address)62   explicit SCTableReference(Address address) : address_(address) {}
63 
64   Address address_;
65 
66   friend class StubCache;
67 };
68 
69 
70 class StubCache {
71  public:
72   struct Entry {
73     Name* key;
74     Code* value;
75     Map* map;
76   };
77 
78   void Initialize();
79 
80   Handle<JSObject> StubHolder(Handle<JSObject> receiver,
81                               Handle<JSObject> holder);
82 
83   Handle<Code> FindIC(Handle<Name> name,
84                       Handle<Map> stub_holder_map,
85                       Code::Kind kind,
86                       ExtraICState extra_state = kNoExtraICState,
87                       InlineCacheHolderFlag cache_holder = OWN_MAP);
88 
89   Handle<Code> FindHandler(Handle<Name> name,
90                            Handle<Map> map,
91                            Code::Kind kind,
92                            InlineCacheHolderFlag cache_holder = OWN_MAP);
93 
94   Handle<Code> ComputeMonomorphicIC(Handle<Name> name,
95                                     Handle<Type> type,
96                                     Handle<Code> handler,
97                                     ExtraICState extra_ic_state);
98 
99   Handle<Code> ComputeLoadNonexistent(Handle<Name> name, Handle<Type> type);
100 
101   Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
102 
103   Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map,
104                                         StrictModeFlag strict_mode,
105                                         KeyedAccessStoreMode store_mode);
106 
107   Handle<Code> ComputeCallField(int argc,
108                                 Code::Kind,
109                                 ExtraICState extra_state,
110                                 Handle<Name> name,
111                                 Handle<Object> object,
112                                 Handle<JSObject> holder,
113                                 PropertyIndex index);
114 
115   Handle<Code> ComputeCallConstant(int argc,
116                                    Code::Kind,
117                                    ExtraICState extra_state,
118                                    Handle<Name> name,
119                                    Handle<Object> object,
120                                    Handle<JSObject> holder,
121                                    Handle<JSFunction> function);
122 
123   Handle<Code> ComputeCallInterceptor(int argc,
124                                       Code::Kind,
125                                       ExtraICState extra_state,
126                                       Handle<Name> name,
127                                       Handle<Object> object,
128                                       Handle<JSObject> holder);
129 
130   Handle<Code> ComputeCallGlobal(int argc,
131                                  Code::Kind,
132                                  ExtraICState extra_state,
133                                  Handle<Name> name,
134                                  Handle<JSObject> object,
135                                  Handle<GlobalObject> holder,
136                                  Handle<PropertyCell> cell,
137                                  Handle<JSFunction> function);
138 
139   // ---
140 
141   Handle<Code> ComputeCallInitialize(int argc, RelocInfo::Mode mode);
142 
143   Handle<Code> ComputeKeyedCallInitialize(int argc);
144 
145   Handle<Code> ComputeCallPreMonomorphic(int argc,
146                                          Code::Kind kind,
147                                          ExtraICState extra_state);
148 
149   Handle<Code> ComputeCallNormal(int argc,
150                                  Code::Kind kind,
151                                  ExtraICState state);
152 
153   Handle<Code> ComputeCallArguments(int argc);
154 
155   Handle<Code> ComputeCallMegamorphic(int argc,
156                                       Code::Kind kind,
157                                       ExtraICState state);
158 
159   Handle<Code> ComputeCallMiss(int argc,
160                                Code::Kind kind,
161                                ExtraICState state);
162 
163   // ---
164 
165   Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
166                                  CompareNilICStub& stub);
167 
168   // ---
169 
170   Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps);
171   Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps,
172                                               KeyedAccessStoreMode store_mode,
173                                               StrictModeFlag strict_mode);
174 
175   Handle<Code> ComputePolymorphicIC(TypeHandleList* types,
176                                     CodeHandleList* handlers,
177                                     int number_of_valid_maps,
178                                     Handle<Name> name,
179                                     ExtraICState extra_ic_state);
180 
181   // Finds the Code object stored in the Heap::non_monomorphic_cache().
182   Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind);
183 
184 #ifdef ENABLE_DEBUGGER_SUPPORT
185   Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind);
186 
187   Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind);
188 #endif
189 
190   // Update cache for entry hash(name, map).
191   Code* Set(Name* name, Map* map, Code* code);
192 
193   // Clear the lookup table (@ mark compact collection).
194   void Clear();
195 
196   // Collect all maps that match the name and flags.
197   void CollectMatchingMaps(SmallMapList* types,
198                            Handle<Name> name,
199                            Code::Flags flags,
200                            Handle<Context> native_context,
201                            Zone* zone);
202 
203   // Generate code for probing the stub cache table.
204   // Arguments extra, extra2 and extra3 may be used to pass additional scratch
205   // registers. Set to no_reg if not needed.
206   void GenerateProbe(MacroAssembler* masm,
207                      Code::Flags flags,
208                      Register receiver,
209                      Register name,
210                      Register scratch,
211                      Register extra,
212                      Register extra2 = no_reg,
213                      Register extra3 = no_reg);
214 
215   enum Table {
216     kPrimary,
217     kSecondary
218   };
219 
220 
key_reference(StubCache::Table table)221   SCTableReference key_reference(StubCache::Table table) {
222     return SCTableReference(
223         reinterpret_cast<Address>(&first_entry(table)->key));
224   }
225 
226 
map_reference(StubCache::Table table)227   SCTableReference map_reference(StubCache::Table table) {
228     return SCTableReference(
229         reinterpret_cast<Address>(&first_entry(table)->map));
230   }
231 
232 
value_reference(StubCache::Table table)233   SCTableReference value_reference(StubCache::Table table) {
234     return SCTableReference(
235         reinterpret_cast<Address>(&first_entry(table)->value));
236   }
237 
238 
first_entry(StubCache::Table table)239   StubCache::Entry* first_entry(StubCache::Table table) {
240     switch (table) {
241       case StubCache::kPrimary: return StubCache::primary_;
242       case StubCache::kSecondary: return StubCache::secondary_;
243     }
244     UNREACHABLE();
245     return NULL;
246   }
247 
isolate()248   Isolate* isolate() { return isolate_; }
heap()249   Heap* heap() { return isolate()->heap(); }
factory()250   Factory* factory() { return isolate()->factory(); }
251 
252   // These constants describe the structure of the interceptor arguments on the
253   // stack. The arguments are pushed by the (platform-specific)
254   // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
255   // LoadWithInterceptor.
256   static const int kInterceptorArgsNameIndex = 0;
257   static const int kInterceptorArgsInfoIndex = 1;
258   static const int kInterceptorArgsThisIndex = 2;
259   static const int kInterceptorArgsHolderIndex = 3;
260   static const int kInterceptorArgsLength = 4;
261 
262  private:
263   explicit StubCache(Isolate* isolate);
264 
265   Handle<Code> ComputeCallInitialize(int argc,
266                                      RelocInfo::Mode mode,
267                                      Code::Kind kind);
268 
269   // The stub cache has a primary and secondary level.  The two levels have
270   // different hashing algorithms in order to avoid simultaneous collisions
271   // in both caches.  Unlike a probing strategy (quadratic or otherwise) the
272   // update strategy on updates is fairly clear and simple:  Any existing entry
273   // in the primary cache is moved to the secondary cache, and secondary cache
274   // entries are overwritten.
275 
276   // Hash algorithm for the primary table.  This algorithm is replicated in
277   // assembler for every architecture.  Returns an index into the table that
278   // is scaled by 1 << kHeapObjectTagSize.
PrimaryOffset(Name * name,Code::Flags flags,Map * map)279   static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) {
280     // This works well because the heap object tag size and the hash
281     // shift are equal.  Shifting down the length field to get the
282     // hash code would effectively throw away two bits of the hash
283     // code.
284     STATIC_ASSERT(kHeapObjectTagSize == Name::kHashShift);
285     // Compute the hash of the name (use entire hash field).
286     ASSERT(name->HasHashCode());
287     uint32_t field = name->hash_field();
288     // Using only the low bits in 64-bit mode is unlikely to increase the
289     // risk of collision even if the heap is spread over an area larger than
290     // 4Gb (and not at all if it isn't).
291     uint32_t map_low32bits =
292         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map));
293     // We always set the in_loop bit to zero when generating the lookup code
294     // so do it here too so the hash codes match.
295     uint32_t iflags =
296         (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
297     // Base the offset on a simple combination of name, flags, and map.
298     uint32_t key = (map_low32bits + field) ^ iflags;
299     return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize);
300   }
301 
302   // Hash algorithm for the secondary table.  This algorithm is replicated in
303   // assembler for every architecture.  Returns an index into the table that
304   // is scaled by 1 << kHeapObjectTagSize.
SecondaryOffset(Name * name,Code::Flags flags,int seed)305   static int SecondaryOffset(Name* name, Code::Flags flags, int seed) {
306     // Use the seed from the primary cache in the secondary cache.
307     uint32_t name_low32bits =
308         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
309     // We always set the in_loop bit to zero when generating the lookup code
310     // so do it here too so the hash codes match.
311     uint32_t iflags =
312         (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
313     uint32_t key = (seed - name_low32bits) + iflags;
314     return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
315   }
316 
317   // Compute the entry for a given offset in exactly the same way as
318   // we do in generated code.  We generate an hash code that already
319   // ends in Name::kHashShift 0s.  Then we multiply it so it is a multiple
320   // of sizeof(Entry).  This makes it easier to avoid making mistakes
321   // in the hashed offset computations.
entry(Entry * table,int offset)322   static Entry* entry(Entry* table, int offset) {
323     const int multiplier = sizeof(*table) >> Name::kHashShift;
324     return reinterpret_cast<Entry*>(
325         reinterpret_cast<Address>(table) + offset * multiplier);
326   }
327 
328   static const int kPrimaryTableBits = 11;
329   static const int kPrimaryTableSize = (1 << kPrimaryTableBits);
330   static const int kSecondaryTableBits = 9;
331   static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
332 
333   Entry primary_[kPrimaryTableSize];
334   Entry secondary_[kSecondaryTableSize];
335   Isolate* isolate_;
336 
337   friend class Isolate;
338   friend class SCTableReference;
339 
340   DISALLOW_COPY_AND_ASSIGN(StubCache);
341 };
342 
343 
344 // ------------------------------------------------------------------------
345 
346 
347 // Support functions for IC stubs for callbacks.
348 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty);
349 
350 
351 // Support functions for IC stubs for interceptors.
352 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly);
353 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad);
354 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall);
355 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty);
356 DECLARE_RUNTIME_FUNCTION(MaybeObject*, CallInterceptorProperty);
357 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor);
358 
359 
360 enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
361 enum IcCheckType { ELEMENT, PROPERTY };
362 
363 
364 // The stub compilers compile stubs for the stub cache.
365 class StubCompiler BASE_EMBEDDED {
366  public:
367   explicit StubCompiler(Isolate* isolate,
368                         ExtraICState extra_ic_state = kNoExtraICState)
isolate_(isolate)369       : isolate_(isolate), extra_ic_state_(extra_ic_state),
370         masm_(isolate, NULL, 256), failure_(NULL) { }
371 
372   // Functions to compile either CallIC or KeyedCallIC.  The specific kind
373   // is extracted from the code flags.
374   Handle<Code> CompileCallInitialize(Code::Flags flags);
375   Handle<Code> CompileCallPreMonomorphic(Code::Flags flags);
376   Handle<Code> CompileCallNormal(Code::Flags flags);
377   Handle<Code> CompileCallMegamorphic(Code::Flags flags);
378   Handle<Code> CompileCallArguments(Code::Flags flags);
379   Handle<Code> CompileCallMiss(Code::Flags flags);
380 
381 #ifdef ENABLE_DEBUGGER_SUPPORT
382   Handle<Code> CompileCallDebugBreak(Code::Flags flags);
383   Handle<Code> CompileCallDebugPrepareStepIn(Code::Flags flags);
384 #endif
385 
386   // Static functions for generating parts of stubs.
387   static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
388                                                   int index,
389                                                   Register prototype);
390 
391   // Helper function used to check that the dictionary doesn't contain
392   // the property. This function may return false negatives, so miss_label
393   // must always call a backup property check that is complete.
394   // This function is safe to call if the receiver has fast properties.
395   // Name must be unique and receiver must be a heap object.
396   static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
397                                                Label* miss_label,
398                                                Register receiver,
399                                                Handle<Name> name,
400                                                Register r0,
401                                                Register r1);
402 
403   // Generates prototype loading code that uses the objects from the
404   // context we were in when this function was called. If the context
405   // has changed, a jump to miss is performed. This ties the generated
406   // code to a particular context and so must not be used in cases
407   // where the generated code is not allowed to have references to
408   // objects from a context.
409   static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
410                                                         int index,
411                                                         Register prototype,
412                                                         Label* miss);
413 
414   static void GenerateFastPropertyLoad(MacroAssembler* masm,
415                                        Register dst,
416                                        Register src,
417                                        bool inobject,
418                                        int index,
419                                        Representation representation);
420 
421   static void GenerateLoadArrayLength(MacroAssembler* masm,
422                                       Register receiver,
423                                       Register scratch,
424                                       Label* miss_label);
425 
426   static void GenerateLoadStringLength(MacroAssembler* masm,
427                                        Register receiver,
428                                        Register scratch1,
429                                        Register scratch2,
430                                        Label* miss_label);
431 
432   static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
433                                             Register receiver,
434                                             Register scratch1,
435                                             Register scratch2,
436                                             Label* miss_label);
437 
438   // Generate code to check that a global property cell is empty. Create
439   // the property cell at compilation time if no cell exists for the
440   // property.
441   static void GenerateCheckPropertyCell(MacroAssembler* masm,
442                                         Handle<JSGlobalObject> global,
443                                         Handle<Name> name,
444                                         Register scratch,
445                                         Label* miss);
446 
447   static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
448 
449   // Generates code that verifies that the property holder has not changed
450   // (checking maps of objects in the prototype chain for fast and global
451   // objects or doing negative lookup for slow objects, ensures that the
452   // property cells for global objects are still empty) and checks that the map
453   // of the holder has not changed. If necessary the function also generates
454   // code for security check in case of global object holders. Helps to make
455   // sure that the current IC is still valid.
456   //
457   // The scratch and holder registers are always clobbered, but the object
458   // register is only clobbered if it the same as the holder register. The
459   // function returns a register containing the holder - either object_reg or
460   // holder_reg.
461   // The function can optionally (when save_at_depth !=
462   // kInvalidProtoDepth) save the object at the given depth by moving
463   // it to [esp + kPointerSize].
464   Register CheckPrototypes(Handle<Type> type,
465                            Register object_reg,
466                            Handle<JSObject> holder,
467                            Register holder_reg,
468                            Register scratch1,
469                            Register scratch2,
470                            Handle<Name> name,
471                            Label* miss,
472                            PrototypeCheckType check = CHECK_ALL_MAPS) {
473     return CheckPrototypes(type, object_reg, holder, holder_reg, scratch1,
474                            scratch2, name, kInvalidProtoDepth, miss, check);
475   }
476 
477   Register CheckPrototypes(Handle<Type> type,
478                            Register object_reg,
479                            Handle<JSObject> holder,
480                            Register holder_reg,
481                            Register scratch1,
482                            Register scratch2,
483                            Handle<Name> name,
484                            int save_at_depth,
485                            Label* miss,
486                            PrototypeCheckType check = CHECK_ALL_MAPS);
487 
488   void GenerateBooleanCheck(Register object, Label* miss);
489 
490  protected:
491   Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
492   Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name);
493 
extra_state()494   ExtraICState extra_state() { return extra_ic_state_; }
495 
masm()496   MacroAssembler* masm() { return &masm_; }
set_failure(Failure * failure)497   void set_failure(Failure* failure) { failure_ = failure; }
498 
499   static void LookupPostInterceptor(Handle<JSObject> holder,
500                                     Handle<Name> name,
501                                     LookupResult* lookup);
502 
isolate()503   Isolate* isolate() { return isolate_; }
heap()504   Heap* heap() { return isolate()->heap(); }
factory()505   Factory* factory() { return isolate()->factory(); }
506 
507   static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code);
508 
509  private:
510   Isolate* isolate_;
511   const ExtraICState extra_ic_state_;
512   MacroAssembler masm_;
513   Failure* failure_;
514 };
515 
516 
517 enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS };
518 
519 
520 class BaseLoadStoreStubCompiler: public StubCompiler {
521  public:
522   BaseLoadStoreStubCompiler(Isolate* isolate,
523                             Code::Kind kind,
524                             ExtraICState extra_ic_state = kNoExtraICState,
525                             InlineCacheHolderFlag cache_holder = OWN_MAP)
StubCompiler(isolate,extra_ic_state)526       : StubCompiler(isolate, extra_ic_state),
527         kind_(kind),
528         cache_holder_(cache_holder) {
529     InitializeRegisters();
530   }
~BaseLoadStoreStubCompiler()531   virtual ~BaseLoadStoreStubCompiler() { }
532 
533   Handle<Code> CompileMonomorphicIC(Handle<Type> type,
534                                     Handle<Code> handler,
535                                     Handle<Name> name);
536 
537   Handle<Code> CompilePolymorphicIC(TypeHandleList* types,
538                                     CodeHandleList* handlers,
539                                     Handle<Name> name,
540                                     Code::StubType type,
541                                     IcCheckType check);
542 
GenerateNameCheck(Handle<Name> name,Register name_reg,Label * miss)543   virtual void GenerateNameCheck(Handle<Name> name,
544                                  Register name_reg,
545                                  Label* miss) { }
546 
MissBuiltin(Code::Kind kind)547   static Builtins::Name MissBuiltin(Code::Kind kind) {
548     switch (kind) {
549       case Code::LOAD_IC: return Builtins::kLoadIC_Miss;
550       case Code::STORE_IC: return Builtins::kStoreIC_Miss;
551       case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss;
552       case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss;
553       default: UNREACHABLE();
554     }
555     return Builtins::kLoadIC_Miss;
556   }
557 
558  protected:
559   virtual Register HandlerFrontendHeader(Handle<Type> type,
560                                          Register object_reg,
561                                          Handle<JSObject> holder,
562                                          Handle<Name> name,
563                                          Label* miss) = 0;
564 
565   virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss) = 0;
566 
567   Register HandlerFrontend(Handle<Type> type,
568                            Register object_reg,
569                            Handle<JSObject> holder,
570                            Handle<Name> name);
571 
572   Handle<Code> GetCode(Code::Kind kind,
573                        Code::StubType type,
574                        Handle<Name> name);
575 
576   Handle<Code> GetICCode(Code::Kind kind,
577                          Code::StubType type,
578                          Handle<Name> name,
579                          InlineCacheState state = MONOMORPHIC);
kind()580   Code::Kind kind() { return kind_; }
581 
log_kind(Handle<Code> code)582   Logger::LogEventsAndTags log_kind(Handle<Code> code) {
583     if (!code->is_inline_cache_stub()) return Logger::STUB_TAG;
584     if (kind_ == Code::LOAD_IC) {
585       return code->ic_state() == MONOMORPHIC
586           ? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG;
587     } else if (kind_ == Code::KEYED_LOAD_IC) {
588       return code->ic_state() == MONOMORPHIC
589           ? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG;
590     } else if (kind_ == Code::STORE_IC) {
591       return code->ic_state() == MONOMORPHIC
592           ? Logger::STORE_IC_TAG : Logger::STORE_POLYMORPHIC_IC_TAG;
593     } else {
594       return code->ic_state() == MONOMORPHIC
595           ? Logger::KEYED_STORE_IC_TAG : Logger::KEYED_STORE_POLYMORPHIC_IC_TAG;
596     }
597   }
598   void JitEvent(Handle<Name> name, Handle<Code> code);
599 
600   virtual Register receiver() = 0;
601   virtual Register name() = 0;
602   virtual Register scratch1() = 0;
603   virtual Register scratch2() = 0;
604   virtual Register scratch3() = 0;
605 
606   void InitializeRegisters();
607 
608   bool IncludesNumberType(TypeHandleList* types);
609 
610   Code::Kind kind_;
611   InlineCacheHolderFlag cache_holder_;
612   Register* registers_;
613 };
614 
615 
616 class LoadStubCompiler: public BaseLoadStoreStubCompiler {
617  public:
618   LoadStubCompiler(Isolate* isolate,
619                    ExtraICState extra_ic_state = kNoExtraICState,
620                    InlineCacheHolderFlag cache_holder = OWN_MAP,
621                    Code::Kind kind = Code::LOAD_IC)
BaseLoadStoreStubCompiler(isolate,kind,extra_ic_state,cache_holder)622       : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state,
623                                   cache_holder) { }
~LoadStubCompiler()624   virtual ~LoadStubCompiler() { }
625 
626   Handle<Code> CompileLoadField(Handle<Type> type,
627                                 Handle<JSObject> holder,
628                                 Handle<Name> name,
629                                 PropertyIndex index,
630                                 Representation representation);
631 
632   Handle<Code> CompileLoadCallback(Handle<Type> type,
633                                    Handle<JSObject> holder,
634                                    Handle<Name> name,
635                                    Handle<ExecutableAccessorInfo> callback);
636 
637   Handle<Code> CompileLoadCallback(Handle<Type> type,
638                                    Handle<JSObject> holder,
639                                    Handle<Name> name,
640                                    const CallOptimization& call_optimization);
641 
642   Handle<Code> CompileLoadConstant(Handle<Type> type,
643                                    Handle<JSObject> holder,
644                                    Handle<Name> name,
645                                    Handle<Object> value);
646 
647   Handle<Code> CompileLoadInterceptor(Handle<Type> type,
648                                       Handle<JSObject> holder,
649                                       Handle<Name> name);
650 
651   Handle<Code> CompileLoadViaGetter(Handle<Type> type,
652                                     Handle<JSObject> holder,
653                                     Handle<Name> name,
654                                     Handle<JSFunction> getter);
655 
656   static void GenerateLoadViaGetter(MacroAssembler* masm,
657                                     Register receiver,
658                                     Handle<JSFunction> getter);
659 
660   Handle<Code> CompileLoadNonexistent(Handle<Type> type,
661                                       Handle<JSObject> last,
662                                       Handle<Name> name);
663 
664   Handle<Code> CompileLoadGlobal(Handle<Type> type,
665                                  Handle<GlobalObject> holder,
666                                  Handle<PropertyCell> cell,
667                                  Handle<Name> name,
668                                  bool is_dont_delete);
669 
670   static Register* registers();
671 
672  protected:
673   virtual Register HandlerFrontendHeader(Handle<Type> type,
674                                          Register object_reg,
675                                          Handle<JSObject> holder,
676                                          Handle<Name> name,
677                                          Label* miss);
678 
679   virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss);
680 
681   Register CallbackHandlerFrontend(Handle<Type> type,
682                                    Register object_reg,
683                                    Handle<JSObject> holder,
684                                    Handle<Name> name,
685                                    Handle<Object> callback);
686   void NonexistentHandlerFrontend(Handle<Type> type,
687                                   Handle<JSObject> last,
688                                   Handle<Name> name);
689 
690   void GenerateLoadField(Register reg,
691                          Handle<JSObject> holder,
692                          PropertyIndex field,
693                          Representation representation);
694   void GenerateLoadConstant(Handle<Object> value);
695   void GenerateLoadCallback(Register reg,
696                             Handle<ExecutableAccessorInfo> callback);
697   void GenerateLoadCallback(const CallOptimization& call_optimization);
698   void GenerateLoadInterceptor(Register holder_reg,
699                                Handle<Object> object,
700                                Handle<JSObject> holder,
701                                LookupResult* lookup,
702                                Handle<Name> name);
703   void GenerateLoadPostInterceptor(Register reg,
704                                    Handle<JSObject> interceptor_holder,
705                                    Handle<Name> name,
706                                    LookupResult* lookup);
707 
receiver()708   virtual Register receiver() { return registers_[0]; }
name()709   virtual Register name()     { return registers_[1]; }
scratch1()710   virtual Register scratch1() { return registers_[2]; }
scratch2()711   virtual Register scratch2() { return registers_[3]; }
scratch3()712   virtual Register scratch3() { return registers_[4]; }
scratch4()713   Register scratch4() { return registers_[5]; }
714 };
715 
716 
717 class KeyedLoadStubCompiler: public LoadStubCompiler {
718  public:
719   KeyedLoadStubCompiler(Isolate* isolate,
720                         ExtraICState extra_ic_state = kNoExtraICState,
721                         InlineCacheHolderFlag cache_holder = OWN_MAP)
LoadStubCompiler(isolate,extra_ic_state,cache_holder,Code::KEYED_LOAD_IC)722       : LoadStubCompiler(isolate, extra_ic_state, cache_holder,
723                          Code::KEYED_LOAD_IC) { }
724 
725   Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
726 
727   void CompileElementHandlers(MapHandleList* receiver_maps,
728                               CodeHandleList* handlers);
729 
730   static void GenerateLoadDictionaryElement(MacroAssembler* masm);
731 
732  protected:
733   static Register* registers();
734 
735  private:
736   virtual void GenerateNameCheck(Handle<Name> name,
737                                  Register name_reg,
738                                  Label* miss);
739   friend class BaseLoadStoreStubCompiler;
740 };
741 
742 
743 class StoreStubCompiler: public BaseLoadStoreStubCompiler {
744  public:
745   StoreStubCompiler(Isolate* isolate,
746                     ExtraICState extra_ic_state,
747                     Code::Kind kind = Code::STORE_IC)
BaseLoadStoreStubCompiler(isolate,kind,extra_ic_state)748       : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state) {}
749 
~StoreStubCompiler()750   virtual ~StoreStubCompiler() { }
751 
752   Handle<Code> CompileStoreTransition(Handle<JSObject> object,
753                                       LookupResult* lookup,
754                                       Handle<Map> transition,
755                                       Handle<Name> name);
756 
757   Handle<Code> CompileStoreField(Handle<JSObject> object,
758                                  LookupResult* lookup,
759                                  Handle<Name> name);
760 
761   void GenerateNegativeHolderLookup(MacroAssembler* masm,
762                                     Handle<JSObject> holder,
763                                     Register holder_reg,
764                                     Handle<Name> name,
765                                     Label* miss);
766 
767   void GenerateStoreTransition(MacroAssembler* masm,
768                                Handle<JSObject> object,
769                                LookupResult* lookup,
770                                Handle<Map> transition,
771                                Handle<Name> name,
772                                Register receiver_reg,
773                                Register name_reg,
774                                Register value_reg,
775                                Register scratch1,
776                                Register scratch2,
777                                Register scratch3,
778                                Label* miss_label,
779                                Label* slow);
780 
781   void GenerateStoreField(MacroAssembler* masm,
782                           Handle<JSObject> object,
783                           LookupResult* lookup,
784                           Register receiver_reg,
785                           Register name_reg,
786                           Register value_reg,
787                           Register scratch1,
788                           Register scratch2,
789                           Label* miss_label);
790 
791   Handle<Code> CompileStoreCallback(Handle<JSObject> object,
792                                     Handle<JSObject> holder,
793                                     Handle<Name> name,
794                                     Handle<ExecutableAccessorInfo> callback);
795 
796   Handle<Code> CompileStoreCallback(Handle<JSObject> object,
797                                     Handle<JSObject> holder,
798                                     Handle<Name> name,
799                                     const CallOptimization& call_optimization);
800 
801   static void GenerateStoreViaSetter(MacroAssembler* masm,
802                                      Handle<JSFunction> setter);
803 
804   Handle<Code> CompileStoreViaSetter(Handle<JSObject> object,
805                                      Handle<JSObject> holder,
806                                      Handle<Name> name,
807                                      Handle<JSFunction> setter);
808 
809   Handle<Code> CompileStoreInterceptor(Handle<JSObject> object,
810                                        Handle<Name> name);
811 
SlowBuiltin(Code::Kind kind)812   static Builtins::Name SlowBuiltin(Code::Kind kind) {
813     switch (kind) {
814       case Code::STORE_IC: return Builtins::kStoreIC_Slow;
815       case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow;
816       default: UNREACHABLE();
817     }
818     return Builtins::kStoreIC_Slow;
819   }
820 
821  protected:
822   virtual Register HandlerFrontendHeader(Handle<Type> type,
823                                          Register object_reg,
824                                          Handle<JSObject> holder,
825                                          Handle<Name> name,
826                                          Label* miss);
827 
828   virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss);
829   void GenerateRestoreName(MacroAssembler* masm,
830                            Label* label,
831                            Handle<Name> name);
832 
receiver()833   virtual Register receiver() { return registers_[0]; }
name()834   virtual Register name()     { return registers_[1]; }
value()835   Register value()    { return registers_[2]; }
scratch1()836   virtual Register scratch1() { return registers_[3]; }
scratch2()837   virtual Register scratch2() { return registers_[4]; }
scratch3()838   virtual Register scratch3() { return registers_[5]; }
839 
840  protected:
841   static Register* registers();
842 
843  private:
844   friend class BaseLoadStoreStubCompiler;
845 };
846 
847 
848 class KeyedStoreStubCompiler: public StoreStubCompiler {
849  public:
KeyedStoreStubCompiler(Isolate * isolate,ExtraICState extra_ic_state)850   KeyedStoreStubCompiler(Isolate* isolate,
851                          ExtraICState extra_ic_state)
852       : StoreStubCompiler(isolate, extra_ic_state, Code::KEYED_STORE_IC) {}
853 
854   Handle<Code> CompileStoreElement(Handle<Map> receiver_map);
855 
856   Handle<Code> CompileStorePolymorphic(MapHandleList* receiver_maps,
857                                        CodeHandleList* handler_stubs,
858                                        MapHandleList* transitioned_maps);
859 
860   Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps);
861 
862   static void GenerateStoreDictionaryElement(MacroAssembler* masm);
863 
864  protected:
865   static Register* registers();
866 
store_mode()867   KeyedAccessStoreMode store_mode() {
868     return KeyedStoreIC::GetKeyedAccessStoreMode(extra_state());
869   }
870 
871  private:
transition_map()872   Register transition_map() {
873     return registers()[3];
874   }
875 
876   virtual void GenerateNameCheck(Handle<Name> name,
877                                  Register name_reg,
878                                  Label* miss);
879   friend class BaseLoadStoreStubCompiler;
880 };
881 
882 
883 // Subset of FUNCTIONS_WITH_ID_LIST with custom constant/global call
884 // IC stubs.
885 #define CUSTOM_CALL_IC_GENERATORS(V)            \
886   V(ArrayPush)                                  \
887   V(ArrayPop)                                   \
888   V(StringCharCodeAt)                           \
889   V(StringCharAt)                               \
890   V(StringFromCharCode)                         \
891   V(MathFloor)                                  \
892   V(MathAbs)                                    \
893   V(ArrayCode)
894 
895 
896 #define SITE_SPECIFIC_CALL_GENERATORS(V)        \
897   V(ArrayCode)
898 
899 
900 class CallStubCompiler: public StubCompiler {
901  public:
902   CallStubCompiler(Isolate* isolate,
903                    int argc,
904                    Code::Kind kind,
905                    ExtraICState extra_state,
906                    InlineCacheHolderFlag cache_holder = OWN_MAP);
907 
908   Handle<Code> CompileCallField(Handle<JSObject> object,
909                                 Handle<JSObject> holder,
910                                 PropertyIndex index,
911                                 Handle<Name> name);
912 
913   // Patch the global proxy over the global object if the global object is the
914   // receiver.
915   void PatchGlobalProxy(Handle<Object> object);
916 
917   // Returns the register containing the holder of |name|.
918   Register HandlerFrontendHeader(Handle<Object> object,
919                                  Handle<JSObject> holder,
920                                  Handle<Name> name,
921                                  CheckType check,
922                                  Label* miss);
923   void HandlerFrontendFooter(Label* miss);
924 
925   void GenerateJumpFunctionIgnoreReceiver(Handle<JSFunction> function);
926   void GenerateJumpFunction(Handle<Object> object,
927                             Handle<JSFunction> function);
928   void GenerateJumpFunction(Handle<Object> object,
929                             Register function,
930                             Label* miss);
931   // Use to call |actual_closure|, a closure with the same shared function info
932   // as |function|.
933   void GenerateJumpFunction(Handle<Object> object,
934                             Register actual_closure,
935                             Handle<JSFunction> function);
936 
937   Handle<Code> CompileCallConstant(Handle<Object> object,
938                                    Handle<JSObject> holder,
939                                    Handle<Name> name,
940                                    CheckType check,
941                                    Handle<JSFunction> function);
942 
943   Handle<Code> CompileCallInterceptor(Handle<JSObject> object,
944                                       Handle<JSObject> holder,
945                                       Handle<Name> name);
946 
947   Handle<Code> CompileCallGlobal(Handle<JSObject> object,
948                                  Handle<GlobalObject> holder,
949                                  Handle<PropertyCell> cell,
950                                  Handle<JSFunction> function,
951                                  Handle<Name> name);
952 
953   static bool HasCustomCallGenerator(Handle<JSFunction> function);
954   static bool CanBeCached(Handle<JSFunction> function);
955 
956  private:
957   // Compiles a custom call constant/global IC.  For constant calls cell is
958   // NULL.  Returns an empty handle if there is no custom call code for the
959   // given function.
960   Handle<Code> CompileCustomCall(Handle<Object> object,
961                                  Handle<JSObject> holder,
962                                  Handle<Cell> cell,
963                                  Handle<JSFunction> function,
964                                  Handle<String> name,
965                                  Code::StubType type);
966 
967 #define DECLARE_CALL_GENERATOR(name)                                    \
968   Handle<Code> Compile##name##Call(Handle<Object> object,               \
969                                    Handle<JSObject> holder,             \
970                                    Handle<Cell> cell,                   \
971                                    Handle<JSFunction> function,         \
972                                    Handle<String> fname,                \
973                                    Code::StubType type);
974   CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR)
975 #undef DECLARE_CALL_GENERATOR
976 
977   Handle<Code> CompileFastApiCall(const CallOptimization& optimization,
978                                   Handle<Object> object,
979                                   Handle<JSObject> holder,
980                                   Handle<Cell> cell,
981                                   Handle<JSFunction> function,
982                                   Handle<String> name);
983 
984   CallKind call_kind();
985 
986   Handle<Code> GetCode(Code::StubType type, Handle<Name> name);
987   Handle<Code> GetCode(Handle<JSFunction> function);
988 
arguments()989   const ParameterCount& arguments() { return arguments_; }
990 
991   void GenerateNameCheck(Handle<Name> name, Label* miss);
992 
993   // Generates code to load the function from the cell checking that
994   // it still contains the same function.
995   void GenerateLoadFunctionFromCell(Handle<Cell> cell,
996                                     Handle<JSFunction> function,
997                                     Label* miss);
998 
999   void GenerateFunctionCheck(Register function, Register scratch, Label* miss);
1000 
1001   // Generates a jump to CallIC miss stub.
1002   void GenerateMissBranch();
1003 
1004   const ParameterCount arguments_;
1005   const Code::Kind kind_;
1006   const InlineCacheHolderFlag cache_holder_;
1007 };
1008 
1009 
1010 // Holds information about possible function call optimizations.
1011 class CallOptimization BASE_EMBEDDED {
1012  public:
1013   explicit CallOptimization(LookupResult* lookup);
1014 
1015   explicit CallOptimization(Handle<JSFunction> function);
1016 
is_constant_call()1017   bool is_constant_call() const {
1018     return !constant_function_.is_null();
1019   }
1020 
constant_function()1021   Handle<JSFunction> constant_function() const {
1022     ASSERT(is_constant_call());
1023     return constant_function_;
1024   }
1025 
is_simple_api_call()1026   bool is_simple_api_call() const {
1027     return is_simple_api_call_;
1028   }
1029 
expected_receiver_type()1030   Handle<FunctionTemplateInfo> expected_receiver_type() const {
1031     ASSERT(is_simple_api_call());
1032     return expected_receiver_type_;
1033   }
1034 
api_call_info()1035   Handle<CallHandlerInfo> api_call_info() const {
1036     ASSERT(is_simple_api_call());
1037     return api_call_info_;
1038   }
1039 
1040   // Returns the depth of the object having the expected type in the
1041   // prototype chain between the two arguments.
1042   int GetPrototypeDepthOfExpectedType(Handle<JSObject> object,
1043                                       Handle<JSObject> holder) const;
1044 
IsCompatibleReceiver(Object * receiver)1045   bool IsCompatibleReceiver(Object* receiver) {
1046     ASSERT(is_simple_api_call());
1047     if (expected_receiver_type_.is_null()) return true;
1048     return expected_receiver_type_->IsTemplateFor(receiver);
1049   }
1050 
1051  private:
1052   void Initialize(Handle<JSFunction> function);
1053 
1054   // Determines whether the given function can be called using the
1055   // fast api call builtin.
1056   void AnalyzePossibleApiFunction(Handle<JSFunction> function);
1057 
1058   Handle<JSFunction> constant_function_;
1059   bool is_simple_api_call_;
1060   Handle<FunctionTemplateInfo> expected_receiver_type_;
1061   Handle<CallHandlerInfo> api_call_info_;
1062 };
1063 
1064 
1065 } }  // namespace v8::internal
1066 
1067 #endif  // V8_STUB_CACHE_H_
1068