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
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.
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.
28 #ifndef V8_STUB_CACHE_H_
29 #define V8_STUB_CACHE_H_
31 #include "allocation.h"
32 #include "arguments.h"
33 #include "code-stubs.h"
35 #include "macro-assembler.h"
43 // The stub cache is used for megamorphic calls and property accesses.
44 // It maps (map, name, type)->Code*
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.
52 class CallOptimization;
57 class SCTableReference {
59 Address address() const { return address_; }
62 explicit SCTableReference(Address address) : address_(address) {}
66 friend class StubCache;
80 Handle<JSObject> StubHolder(Handle<JSObject> receiver,
81 Handle<JSObject> holder);
83 Handle<Code> FindIC(Handle<Name> name,
84 Handle<Map> stub_holder_map,
86 ExtraICState extra_state = kNoExtraICState,
87 InlineCacheHolderFlag cache_holder = OWN_MAP);
89 Handle<Code> FindHandler(Handle<Name> name,
92 InlineCacheHolderFlag cache_holder = OWN_MAP);
94 Handle<Code> ComputeMonomorphicIC(Handle<Name> name,
95 Handle<HeapType> type,
97 ExtraICState extra_ic_state);
99 Handle<Code> ComputeLoadNonexistent(Handle<Name> name, Handle<HeapType> type);
101 Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
103 Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map,
104 StrictModeFlag strict_mode,
105 KeyedAccessStoreMode store_mode);
107 Handle<Code> ComputeCallField(int argc,
109 ExtraICState extra_state,
111 Handle<Object> object,
112 Handle<JSObject> holder,
113 PropertyIndex index);
115 Handle<Code> ComputeCallConstant(int argc,
117 ExtraICState extra_state,
119 Handle<Object> object,
120 Handle<JSObject> holder,
121 Handle<JSFunction> function);
123 Handle<Code> ComputeCallInterceptor(int argc,
125 ExtraICState extra_state,
127 Handle<Object> object,
128 Handle<JSObject> holder);
130 Handle<Code> ComputeCallGlobal(int argc,
132 ExtraICState extra_state,
134 Handle<JSObject> object,
135 Handle<GlobalObject> holder,
136 Handle<PropertyCell> cell,
137 Handle<JSFunction> function);
141 Handle<Code> ComputeCallInitialize(int argc);
143 Handle<Code> ComputeKeyedCallInitialize(int argc);
145 Handle<Code> ComputeCallPreMonomorphic(int argc,
147 ExtraICState extra_state);
149 Handle<Code> ComputeCallNormal(int argc,
153 Handle<Code> ComputeCallArguments(int argc);
155 Handle<Code> ComputeCallMegamorphic(int argc,
159 Handle<Code> ComputeCallMiss(int argc,
165 Handle<Code> ComputeLoad(InlineCacheState ic_state, ExtraICState extra_state);
166 Handle<Code> ComputeStore(InlineCacheState ic_state,
167 ExtraICState extra_state);
171 Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
172 CompareNilICStub& stub);
176 Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps);
177 Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps,
178 KeyedAccessStoreMode store_mode,
179 StrictModeFlag strict_mode);
181 Handle<Code> ComputePolymorphicIC(TypeHandleList* types,
182 CodeHandleList* handlers,
183 int number_of_valid_maps,
185 ExtraICState extra_ic_state);
187 // Finds the Code object stored in the Heap::non_monomorphic_cache().
188 Code* FindCallInitialize(int argc, Code::Kind kind);
189 Code* FindPreMonomorphicIC(Code::Kind kind, ExtraICState extra_ic_state);
191 #ifdef ENABLE_DEBUGGER_SUPPORT
192 Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind);
194 Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind);
197 // Update cache for entry hash(name, map).
198 Code* Set(Name* name, Map* map, Code* code);
200 // Clear the lookup table (@ mark compact collection).
203 // Collect all maps that match the name and flags.
204 void CollectMatchingMaps(SmallMapList* types,
207 Handle<Context> native_context,
210 // Generate code for probing the stub cache table.
211 // Arguments extra, extra2 and extra3 may be used to pass additional scratch
212 // registers. Set to no_reg if not needed.
213 void GenerateProbe(MacroAssembler* masm,
219 Register extra2 = no_reg,
220 Register extra3 = no_reg);
228 SCTableReference key_reference(StubCache::Table table) {
229 return SCTableReference(
230 reinterpret_cast<Address>(&first_entry(table)->key));
234 SCTableReference map_reference(StubCache::Table table) {
235 return SCTableReference(
236 reinterpret_cast<Address>(&first_entry(table)->map));
240 SCTableReference value_reference(StubCache::Table table) {
241 return SCTableReference(
242 reinterpret_cast<Address>(&first_entry(table)->value));
246 StubCache::Entry* first_entry(StubCache::Table table) {
248 case StubCache::kPrimary: return StubCache::primary_;
249 case StubCache::kSecondary: return StubCache::secondary_;
255 Isolate* isolate() { return isolate_; }
256 Heap* heap() { return isolate()->heap(); }
257 Factory* factory() { return isolate()->factory(); }
259 // These constants describe the structure of the interceptor arguments on the
260 // stack. The arguments are pushed by the (platform-specific)
261 // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
262 // LoadWithInterceptor.
263 static const int kInterceptorArgsNameIndex = 0;
264 static const int kInterceptorArgsInfoIndex = 1;
265 static const int kInterceptorArgsThisIndex = 2;
266 static const int kInterceptorArgsHolderIndex = 3;
267 static const int kInterceptorArgsLength = 4;
270 explicit StubCache(Isolate* isolate);
272 Handle<Code> ComputeCallInitialize(int argc, Code::Kind kind);
274 // The stub cache has a primary and secondary level. The two levels have
275 // different hashing algorithms in order to avoid simultaneous collisions
276 // in both caches. Unlike a probing strategy (quadratic or otherwise) the
277 // update strategy on updates is fairly clear and simple: Any existing entry
278 // in the primary cache is moved to the secondary cache, and secondary cache
279 // entries are overwritten.
281 // Hash algorithm for the primary table. This algorithm is replicated in
282 // assembler for every architecture. Returns an index into the table that
283 // is scaled by 1 << kHeapObjectTagSize.
284 static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) {
285 // This works well because the heap object tag size and the hash
286 // shift are equal. Shifting down the length field to get the
287 // hash code would effectively throw away two bits of the hash
289 STATIC_ASSERT(kHeapObjectTagSize == Name::kHashShift);
290 // Compute the hash of the name (use entire hash field).
291 ASSERT(name->HasHashCode());
292 uint32_t field = name->hash_field();
293 // Using only the low bits in 64-bit mode is unlikely to increase the
294 // risk of collision even if the heap is spread over an area larger than
295 // 4Gb (and not at all if it isn't).
296 uint32_t map_low32bits =
297 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map));
298 // We always set the in_loop bit to zero when generating the lookup code
299 // so do it here too so the hash codes match.
301 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
302 // Base the offset on a simple combination of name, flags, and map.
303 uint32_t key = (map_low32bits + field) ^ iflags;
304 return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize);
307 // Hash algorithm for the secondary table. This algorithm is replicated in
308 // assembler for every architecture. Returns an index into the table that
309 // is scaled by 1 << kHeapObjectTagSize.
310 static int SecondaryOffset(Name* name, Code::Flags flags, int seed) {
311 // Use the seed from the primary cache in the secondary cache.
312 uint32_t name_low32bits =
313 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
314 // We always set the in_loop bit to zero when generating the lookup code
315 // so do it here too so the hash codes match.
317 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
318 uint32_t key = (seed - name_low32bits) + iflags;
319 return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
322 // Compute the entry for a given offset in exactly the same way as
323 // we do in generated code. We generate an hash code that already
324 // ends in Name::kHashShift 0s. Then we multiply it so it is a multiple
325 // of sizeof(Entry). This makes it easier to avoid making mistakes
326 // in the hashed offset computations.
327 static Entry* entry(Entry* table, int offset) {
328 const int multiplier = sizeof(*table) >> Name::kHashShift;
329 return reinterpret_cast<Entry*>(
330 reinterpret_cast<Address>(table) + offset * multiplier);
333 static const int kPrimaryTableBits = 11;
334 static const int kPrimaryTableSize = (1 << kPrimaryTableBits);
335 static const int kSecondaryTableBits = 9;
336 static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
338 Entry primary_[kPrimaryTableSize];
339 Entry secondary_[kSecondaryTableSize];
342 friend class Isolate;
343 friend class SCTableReference;
345 DISALLOW_COPY_AND_ASSIGN(StubCache);
349 // ------------------------------------------------------------------------
352 // Support functions for IC stubs for callbacks.
353 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty);
356 // Support functions for IC stubs for interceptors.
357 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly);
358 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad);
359 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall);
360 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty);
361 DECLARE_RUNTIME_FUNCTION(MaybeObject*, CallInterceptorProperty);
362 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor);
365 enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
366 enum IcCheckType { ELEMENT, PROPERTY };
369 // The stub compilers compile stubs for the stub cache.
370 class StubCompiler BASE_EMBEDDED {
372 explicit StubCompiler(Isolate* isolate,
373 ExtraICState extra_ic_state = kNoExtraICState)
374 : isolate_(isolate), extra_ic_state_(extra_ic_state),
375 masm_(isolate, NULL, 256), failure_(NULL) { }
377 // Functions to compile either CallIC or KeyedCallIC. The specific kind
378 // is extracted from the code flags.
379 Handle<Code> CompileCallInitialize(Code::Flags flags);
380 Handle<Code> CompileCallPreMonomorphic(Code::Flags flags);
381 Handle<Code> CompileCallNormal(Code::Flags flags);
382 Handle<Code> CompileCallMegamorphic(Code::Flags flags);
383 Handle<Code> CompileCallArguments(Code::Flags flags);
384 Handle<Code> CompileCallMiss(Code::Flags flags);
386 Handle<Code> CompileLoadInitialize(Code::Flags flags);
387 Handle<Code> CompileLoadPreMonomorphic(Code::Flags flags);
388 Handle<Code> CompileLoadMegamorphic(Code::Flags flags);
390 Handle<Code> CompileStoreInitialize(Code::Flags flags);
391 Handle<Code> CompileStorePreMonomorphic(Code::Flags flags);
392 Handle<Code> CompileStoreGeneric(Code::Flags flags);
393 Handle<Code> CompileStoreMegamorphic(Code::Flags flags);
395 #ifdef ENABLE_DEBUGGER_SUPPORT
396 Handle<Code> CompileCallDebugBreak(Code::Flags flags);
397 Handle<Code> CompileCallDebugPrepareStepIn(Code::Flags flags);
400 // Static functions for generating parts of stubs.
401 static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
405 // Helper function used to check that the dictionary doesn't contain
406 // the property. This function may return false negatives, so miss_label
407 // must always call a backup property check that is complete.
408 // This function is safe to call if the receiver has fast properties.
409 // Name must be unique and receiver must be a heap object.
410 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
417 // Generates prototype loading code that uses the objects from the
418 // context we were in when this function was called. If the context
419 // has changed, a jump to miss is performed. This ties the generated
420 // code to a particular context and so must not be used in cases
421 // where the generated code is not allowed to have references to
422 // objects from a context.
423 static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
428 static void GenerateFastPropertyLoad(MacroAssembler* masm,
433 Representation representation);
435 static void GenerateLoadArrayLength(MacroAssembler* masm,
440 static void GenerateLoadStringLength(MacroAssembler* masm,
446 static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
452 // Generate code to check that a global property cell is empty. Create
453 // the property cell at compilation time if no cell exists for the
455 static void GenerateCheckPropertyCell(MacroAssembler* masm,
456 Handle<JSGlobalObject> global,
461 static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
463 // Generates code that verifies that the property holder has not changed
464 // (checking maps of objects in the prototype chain for fast and global
465 // objects or doing negative lookup for slow objects, ensures that the
466 // property cells for global objects are still empty) and checks that the map
467 // of the holder has not changed. If necessary the function also generates
468 // code for security check in case of global object holders. Helps to make
469 // sure that the current IC is still valid.
471 // The scratch and holder registers are always clobbered, but the object
472 // register is only clobbered if it the same as the holder register. The
473 // function returns a register containing the holder - either object_reg or
475 Register CheckPrototypes(Handle<HeapType> type,
477 Handle<JSObject> holder,
483 PrototypeCheckType check = CHECK_ALL_MAPS);
485 void GenerateBooleanCheck(Register object, Label* miss);
488 Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
489 Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name);
491 ExtraICState extra_state() { return extra_ic_state_; }
493 MacroAssembler* masm() { return &masm_; }
494 void set_failure(Failure* failure) { failure_ = failure; }
496 static void LookupPostInterceptor(Handle<JSObject> holder,
498 LookupResult* lookup);
500 Isolate* isolate() { return isolate_; }
501 Heap* heap() { return isolate()->heap(); }
502 Factory* factory() { return isolate()->factory(); }
504 static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code);
508 const ExtraICState extra_ic_state_;
509 MacroAssembler masm_;
514 enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS };
517 class BaseLoadStoreStubCompiler: public StubCompiler {
519 BaseLoadStoreStubCompiler(Isolate* isolate,
521 ExtraICState extra_ic_state = kNoExtraICState,
522 InlineCacheHolderFlag cache_holder = OWN_MAP)
523 : StubCompiler(isolate, extra_ic_state),
525 cache_holder_(cache_holder) {
526 InitializeRegisters();
528 virtual ~BaseLoadStoreStubCompiler() { }
530 Handle<Code> CompileMonomorphicIC(Handle<HeapType> type,
531 Handle<Code> handler,
534 Handle<Code> CompilePolymorphicIC(TypeHandleList* types,
535 CodeHandleList* handlers,
540 static Builtins::Name MissBuiltin(Code::Kind kind) {
542 case Code::LOAD_IC: return Builtins::kLoadIC_Miss;
543 case Code::STORE_IC: return Builtins::kStoreIC_Miss;
544 case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss;
545 case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss;
546 default: UNREACHABLE();
548 return Builtins::kLoadIC_Miss;
552 virtual Register HandlerFrontendHeader(Handle<HeapType> type,
554 Handle<JSObject> holder,
558 virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss) = 0;
560 Register HandlerFrontend(Handle<HeapType> type,
562 Handle<JSObject> holder,
565 Handle<Code> GetCode(Code::Kind kind,
569 Handle<Code> GetICCode(Code::Kind kind,
572 InlineCacheState state = MONOMORPHIC);
573 Code::Kind kind() { return kind_; }
575 Logger::LogEventsAndTags log_kind(Handle<Code> code) {
576 if (!code->is_inline_cache_stub()) return Logger::STUB_TAG;
577 if (kind_ == Code::LOAD_IC) {
578 return code->ic_state() == MONOMORPHIC
579 ? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG;
580 } else if (kind_ == Code::KEYED_LOAD_IC) {
581 return code->ic_state() == MONOMORPHIC
582 ? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG;
583 } else if (kind_ == Code::STORE_IC) {
584 return code->ic_state() == MONOMORPHIC
585 ? Logger::STORE_IC_TAG : Logger::STORE_POLYMORPHIC_IC_TAG;
587 return code->ic_state() == MONOMORPHIC
588 ? Logger::KEYED_STORE_IC_TAG : Logger::KEYED_STORE_POLYMORPHIC_IC_TAG;
591 void JitEvent(Handle<Name> name, Handle<Code> code);
593 virtual Register receiver() = 0;
594 virtual Register name() = 0;
595 virtual Register scratch1() = 0;
596 virtual Register scratch2() = 0;
597 virtual Register scratch3() = 0;
599 void InitializeRegisters();
601 bool IncludesNumberType(TypeHandleList* types);
604 InlineCacheHolderFlag cache_holder_;
605 Register* registers_;
609 class LoadStubCompiler: public BaseLoadStoreStubCompiler {
611 LoadStubCompiler(Isolate* isolate,
612 ExtraICState extra_ic_state = kNoExtraICState,
613 InlineCacheHolderFlag cache_holder = OWN_MAP,
614 Code::Kind kind = Code::LOAD_IC)
615 : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state,
617 virtual ~LoadStubCompiler() { }
619 Handle<Code> CompileLoadField(Handle<HeapType> type,
620 Handle<JSObject> holder,
623 Representation representation);
625 Handle<Code> CompileLoadCallback(Handle<HeapType> type,
626 Handle<JSObject> holder,
628 Handle<ExecutableAccessorInfo> callback);
630 Handle<Code> CompileLoadCallback(Handle<HeapType> type,
631 Handle<JSObject> holder,
633 const CallOptimization& call_optimization);
635 Handle<Code> CompileLoadConstant(Handle<HeapType> type,
636 Handle<JSObject> holder,
638 Handle<Object> value);
640 Handle<Code> CompileLoadInterceptor(Handle<HeapType> type,
641 Handle<JSObject> holder,
644 Handle<Code> CompileLoadViaGetter(Handle<HeapType> type,
645 Handle<JSObject> holder,
647 Handle<JSFunction> getter);
649 static void GenerateLoadViaGetter(MacroAssembler* masm,
651 Handle<JSFunction> getter);
653 Handle<Code> CompileLoadNonexistent(Handle<HeapType> type,
654 Handle<JSObject> last,
657 Handle<Code> CompileLoadGlobal(Handle<HeapType> type,
658 Handle<GlobalObject> holder,
659 Handle<PropertyCell> cell,
661 bool is_dont_delete);
663 static Register* registers();
666 ContextualMode contextual_mode() {
667 return LoadIC::GetContextualMode(extra_state());
670 virtual Register HandlerFrontendHeader(Handle<HeapType> type,
672 Handle<JSObject> holder,
676 virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss);
678 Register CallbackHandlerFrontend(Handle<HeapType> type,
680 Handle<JSObject> holder,
682 Handle<Object> callback);
683 void NonexistentHandlerFrontend(Handle<HeapType> type,
684 Handle<JSObject> last,
687 void GenerateLoadField(Register reg,
688 Handle<JSObject> holder,
690 Representation representation);
691 void GenerateLoadConstant(Handle<Object> value);
692 void GenerateLoadCallback(Register reg,
693 Handle<ExecutableAccessorInfo> callback);
694 void GenerateLoadCallback(const CallOptimization& call_optimization);
695 void GenerateLoadInterceptor(Register holder_reg,
696 Handle<Object> object,
697 Handle<JSObject> holder,
698 LookupResult* lookup,
700 void GenerateLoadPostInterceptor(Register reg,
701 Handle<JSObject> interceptor_holder,
703 LookupResult* lookup);
705 virtual Register receiver() { return registers_[0]; }
706 virtual Register name() { return registers_[1]; }
707 virtual Register scratch1() { return registers_[2]; }
708 virtual Register scratch2() { return registers_[3]; }
709 virtual Register scratch3() { return registers_[4]; }
710 Register scratch4() { return registers_[5]; }
714 class KeyedLoadStubCompiler: public LoadStubCompiler {
716 KeyedLoadStubCompiler(Isolate* isolate,
717 ExtraICState extra_ic_state = kNoExtraICState,
718 InlineCacheHolderFlag cache_holder = OWN_MAP)
719 : LoadStubCompiler(isolate, extra_ic_state, cache_holder,
720 Code::KEYED_LOAD_IC) { }
722 Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
724 void CompileElementHandlers(MapHandleList* receiver_maps,
725 CodeHandleList* handlers);
727 static void GenerateLoadDictionaryElement(MacroAssembler* masm);
730 static Register* registers();
731 friend class BaseLoadStoreStubCompiler;
735 class StoreStubCompiler: public BaseLoadStoreStubCompiler {
737 StoreStubCompiler(Isolate* isolate,
738 ExtraICState extra_ic_state,
739 Code::Kind kind = Code::STORE_IC)
740 : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state) {}
742 virtual ~StoreStubCompiler() { }
744 Handle<Code> CompileStoreTransition(Handle<JSObject> object,
745 LookupResult* lookup,
746 Handle<Map> transition,
749 Handle<Code> CompileStoreField(Handle<JSObject> object,
750 LookupResult* lookup,
753 void GenerateNegativeHolderLookup(MacroAssembler* masm,
754 Handle<JSObject> holder,
759 void GenerateStoreTransition(MacroAssembler* masm,
760 Handle<JSObject> object,
761 LookupResult* lookup,
762 Handle<Map> transition,
764 Register receiver_reg,
773 void GenerateStoreField(MacroAssembler* masm,
774 Handle<JSObject> object,
775 LookupResult* lookup,
776 Register receiver_reg,
783 Handle<Code> CompileStoreCallback(Handle<JSObject> object,
784 Handle<JSObject> holder,
786 Handle<ExecutableAccessorInfo> callback);
788 Handle<Code> CompileStoreCallback(Handle<JSObject> object,
789 Handle<JSObject> holder,
791 const CallOptimization& call_optimization);
793 static void GenerateStoreViaSetter(MacroAssembler* masm,
794 Handle<JSFunction> setter);
796 Handle<Code> CompileStoreViaSetter(Handle<JSObject> object,
797 Handle<JSObject> holder,
799 Handle<JSFunction> setter);
801 Handle<Code> CompileStoreInterceptor(Handle<JSObject> object,
804 static Builtins::Name SlowBuiltin(Code::Kind kind) {
806 case Code::STORE_IC: return Builtins::kStoreIC_Slow;
807 case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow;
808 default: UNREACHABLE();
810 return Builtins::kStoreIC_Slow;
814 virtual Register HandlerFrontendHeader(Handle<HeapType> type,
816 Handle<JSObject> holder,
820 virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss);
821 void GenerateRestoreName(MacroAssembler* masm,
825 virtual Register receiver() { return registers_[0]; }
826 virtual Register name() { return registers_[1]; }
827 Register value() { return registers_[2]; }
828 virtual Register scratch1() { return registers_[3]; }
829 virtual Register scratch2() { return registers_[4]; }
830 virtual Register scratch3() { return registers_[5]; }
833 static Register* registers();
836 friend class BaseLoadStoreStubCompiler;
840 class KeyedStoreStubCompiler: public StoreStubCompiler {
842 KeyedStoreStubCompiler(Isolate* isolate,
843 ExtraICState extra_ic_state)
844 : StoreStubCompiler(isolate, extra_ic_state, Code::KEYED_STORE_IC) {}
846 Handle<Code> CompileStoreElement(Handle<Map> receiver_map);
848 Handle<Code> CompileStorePolymorphic(MapHandleList* receiver_maps,
849 CodeHandleList* handler_stubs,
850 MapHandleList* transitioned_maps);
852 Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps);
854 static void GenerateStoreDictionaryElement(MacroAssembler* masm);
857 static Register* registers();
859 KeyedAccessStoreMode store_mode() {
860 return KeyedStoreIC::GetKeyedAccessStoreMode(extra_state());
863 Register transition_map() {
864 return registers()[3];
867 friend class BaseLoadStoreStubCompiler;
871 class CallStubCompiler: public StubCompiler {
873 CallStubCompiler(Isolate* isolate,
876 ExtraICState extra_state,
877 InlineCacheHolderFlag cache_holder = OWN_MAP);
879 Handle<Code> CompileCallField(Handle<JSObject> object,
880 Handle<JSObject> holder,
884 // Patch the implicit receiver over the global object if the global object is
886 void PatchImplicitReceiver(Handle<Object> object);
888 // Returns the register containing the holder of |name|.
889 Register HandlerFrontendHeader(Handle<Object> object,
890 Handle<JSObject> holder,
894 void HandlerFrontendFooter(Label* miss);
896 void GenerateJumpFunctionIgnoreReceiver(Handle<JSFunction> function);
897 void GenerateJumpFunction(Handle<Object> object,
898 Handle<JSFunction> function);
899 void GenerateJumpFunction(Handle<Object> object,
902 // Use to call |actual_closure|, a closure with the same shared function info
904 void GenerateJumpFunction(Handle<Object> object,
905 Register actual_closure,
906 Handle<JSFunction> function);
908 Handle<Code> CompileCallConstant(Handle<Object> object,
909 Handle<JSObject> holder,
912 Handle<JSFunction> function);
914 Handle<Code> CompileCallInterceptor(Handle<JSObject> object,
915 Handle<JSObject> holder,
918 Handle<Code> CompileCallGlobal(Handle<JSObject> object,
919 Handle<GlobalObject> holder,
920 Handle<PropertyCell> cell,
921 Handle<JSFunction> function,
924 static bool HasCustomCallGenerator(Handle<JSFunction> function);
927 // Compiles a custom call constant/global IC. For constant calls cell is
928 // NULL. Returns an empty handle if there is no custom call code for the
930 Handle<Code> CompileCustomCall(Handle<Object> object,
931 Handle<JSObject> holder,
933 Handle<JSFunction> function,
935 Code::StubType type);
937 Handle<Code> CompileFastApiCall(const CallOptimization& optimization,
938 Handle<Object> object,
939 Handle<JSObject> holder,
941 Handle<JSFunction> function,
942 Handle<String> name);
944 Handle<Code> GetCode(Code::StubType type, Handle<Name> name);
945 Handle<Code> GetCode(Handle<JSFunction> function);
947 const ParameterCount& arguments() { return arguments_; }
949 void GenerateNameCheck(Handle<Name> name, Label* miss);
951 // Generates code to load the function from the cell checking that
952 // it still contains the same function.
953 void GenerateLoadFunctionFromCell(Handle<Cell> cell,
954 Handle<JSFunction> function,
957 void GenerateFunctionCheck(Register function, Register scratch, Label* miss);
959 // Generates a jump to CallIC miss stub.
960 void GenerateMissBranch();
962 const ParameterCount arguments_;
963 const Code::Kind kind_;
964 const InlineCacheHolderFlag cache_holder_;
968 // Holds information about possible function call optimizations.
969 class CallOptimization BASE_EMBEDDED {
971 explicit CallOptimization(LookupResult* lookup);
973 explicit CallOptimization(Handle<JSFunction> function);
975 bool is_constant_call() const {
976 return !constant_function_.is_null();
979 Handle<JSFunction> constant_function() const {
980 ASSERT(is_constant_call());
981 return constant_function_;
984 bool is_simple_api_call() const {
985 return is_simple_api_call_;
988 Handle<FunctionTemplateInfo> expected_receiver_type() const {
989 ASSERT(is_simple_api_call());
990 return expected_receiver_type_;
993 Handle<CallHandlerInfo> api_call_info() const {
994 ASSERT(is_simple_api_call());
995 return api_call_info_;
1001 kHolderIsPrototypeOfMap
1003 // Returns a map whose prototype has the expected type in the
1004 // prototype chain between the two arguments
1005 // null will be returned if the first argument has that property
1006 // lookup will be set accordingly
1007 Handle<Map> LookupHolderOfExpectedType(Handle<JSObject> receiver,
1008 Handle<JSObject> object,
1009 Handle<JSObject> holder,
1010 HolderLookup* holder_lookup) const;
1012 bool IsCompatibleReceiver(Object* receiver) {
1013 ASSERT(is_simple_api_call());
1014 if (expected_receiver_type_.is_null()) return true;
1015 return expected_receiver_type_->IsTemplateFor(receiver);
1019 void Initialize(Handle<JSFunction> function);
1021 // Determines whether the given function can be called using the
1022 // fast api call builtin.
1023 void AnalyzePossibleApiFunction(Handle<JSFunction> function);
1025 Handle<JSFunction> constant_function_;
1026 bool is_simple_api_call_;
1027 Handle<FunctionTemplateInfo> expected_receiver_type_;
1028 Handle<CallHandlerInfo> api_call_info_;
1032 } } // namespace v8::internal
1034 #endif // V8_STUB_CACHE_H_