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.
31 #include "macro-assembler.h"
37 const int kMaxKeyedPolymorphism = 4;
40 // IC_UTIL_LIST defines all utility functions called from generated
41 // inline caching code. The argument for the macro, ICU, is the function name.
42 #define IC_UTIL_LIST(ICU) \
44 ICU(KeyedLoadIC_Miss) \
46 ICU(KeyedCallIC_Miss) \
48 ICU(StoreIC_ArrayLength) \
50 ICU(SharedStoreIC_ExtendStorage) \
51 ICU(KeyedStoreIC_Miss) \
52 ICU(KeyedStoreIC_Slow) \
53 /* Utilities for IC stubs. */ \
54 ICU(StoreCallbackProperty) \
55 ICU(LoadPropertyWithInterceptorOnly) \
56 ICU(LoadPropertyWithInterceptorForLoad) \
57 ICU(LoadPropertyWithInterceptorForCall) \
58 ICU(KeyedLoadPropertyWithInterceptor) \
59 ICU(StoreInterceptorProperty) \
61 ICU(BinaryOpIC_Miss) \
62 ICU(CompareNilIC_Miss) \
66 // IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
71 // The ids for utility called from the generated code.
73 #define CONST_NAME(name) k##name,
74 IC_UTIL_LIST(CONST_NAME)
79 // Looks up the address of the named utility.
80 static Address AddressFromUtilityId(UtilityId id);
82 // Alias the inline cache state type to make the IC code more readable.
83 typedef InlineCacheState State;
85 // The IC code is either invoked with no extra frames on the stack
86 // or with a single extra frame for supporting calls.
92 // Construct the IC structure with the given number of extra
93 // JavaScript frames on the stack.
94 IC(FrameDepth depth, Isolate* isolate);
97 State state() const { return state_; }
98 inline Address address() const;
100 // Compute the current IC state based on the target stub, receiver and name.
101 void UpdateState(Handle<Object> receiver, Handle<Object> name);
102 void MarkMonomorphicPrototypeFailure() {
103 state_ = MONOMORPHIC_PROTOTYPE_FAILURE;
106 // Clear the inline cache to initial state.
107 static void Clear(Isolate* isolate, Address address);
110 bool IsLoadStub() const {
111 return target()->is_load_stub() || target()->is_keyed_load_stub();
114 bool IsStoreStub() const {
115 return target()->is_store_stub() || target()->is_keyed_store_stub();
118 bool IsCallStub() const {
119 return target()->is_call_stub() || target()->is_keyed_call_stub();
123 // Determines which map must be used for keeping the code stub.
124 // These methods should not be called with undefined or null.
125 static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object);
126 // TODO(verwaest): This currently returns a HeapObject rather than JSObject*
127 // since loading the IC for loading the length from strings are stored on
128 // the string map directly, rather than on the JSObject-typed prototype.
129 static inline HeapObject* GetCodeCacheHolder(Isolate* isolate,
131 InlineCacheHolderFlag holder);
133 static inline InlineCacheHolderFlag GetCodeCacheFlag(HeapType* type);
134 static inline Handle<Map> GetCodeCacheHolder(InlineCacheHolderFlag flag,
138 static bool IsCleared(Code* code) {
139 InlineCacheState state = code->ic_state();
140 return state == UNINITIALIZED || state == PREMONOMORPHIC;
143 // Utility functions to convert maps to types and back. There are two special
145 // - The heap_number_map is used as a marker which includes heap numbers as
147 // - The oddball map is only used for booleans.
148 static Handle<Map> TypeToMap(HeapType* type, Isolate* isolate);
149 static Handle<HeapType> MapToType(Handle<Map> map);
150 static Handle<HeapType> CurrentTypeOf(
151 Handle<Object> object, Isolate* isolate);
154 // Get the call-site target; used for determining the state.
155 Handle<Code> target() const { return target_; }
157 Address fp() const { return fp_; }
158 Address pc() const { return *pc_address_; }
159 Isolate* isolate() const { return isolate_; }
161 #ifdef ENABLE_DEBUGGER_SUPPORT
162 // Computes the address in the original code when the code running is
163 // containing break points (calls to DebugBreakXXX builtins).
164 Address OriginalCodeAddress() const;
167 // Set the call-site target.
168 void set_target(Code* code) {
169 SetTargetAtAddress(address(), code);
173 bool is_target_set() { return target_set_; }
176 char TransitionMarkFromState(IC::State state);
178 void TraceIC(const char* type, Handle<Object> name);
181 Failure* TypeError(const char* type,
182 Handle<Object> object,
184 Failure* ReferenceError(const char* type, Handle<String> name);
186 // Access the target code for the given IC address.
187 static inline Code* GetTargetAtAddress(Address address);
188 static inline void SetTargetAtAddress(Address address, Code* target);
189 static void PostPatching(Address address, Code* target, Code* old_target);
191 // Compute the handler either by compiling or by retrieving a cached version.
192 Handle<Code> ComputeHandler(LookupResult* lookup,
193 Handle<Object> object,
195 Handle<Object> value = Handle<Code>::null());
196 virtual Handle<Code> CompileHandler(LookupResult* lookup,
197 Handle<Object> object,
199 Handle<Object> value,
200 InlineCacheHolderFlag cache_holder) {
202 return Handle<Code>::null();
205 void UpdateMonomorphicIC(Handle<HeapType> type,
206 Handle<Code> handler,
207 Handle<String> name);
209 bool UpdatePolymorphicIC(Handle<HeapType> type,
213 virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code);
215 void CopyICToMegamorphicCache(Handle<String> name);
216 bool IsTransitionOfMonomorphicTarget(Handle<HeapType> type);
217 void PatchCache(Handle<HeapType> type,
220 virtual Code::Kind kind() const {
224 virtual Handle<Code> slow_stub() const {
226 return Handle<Code>::null();
228 virtual Handle<Code> megamorphic_stub() {
230 return Handle<Code>::null();
232 virtual Handle<Code> generic_stub() const {
234 return Handle<Code>::null();
237 bool TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
238 Handle<String> name);
239 void TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name);
241 ExtraICState extra_ic_state() const { return extra_ic_state_; }
242 void set_extra_ic_state(ExtraICState state) {
243 extra_ic_state_ = state;
247 Code* raw_target() const { return GetTargetAtAddress(address()); }
249 // Frame pointer for the frame that uses (calls) the IC.
252 // All access to the program counter of an IC structure is indirect
253 // to make the code GC safe. This feature is crucial since
254 // GetProperty and SetProperty are called and they in turn might
255 // invoke the garbage collector.
256 Address* pc_address_;
260 // The original code target that missed.
261 Handle<Code> target_;
265 ExtraICState extra_ic_state_;
267 DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
271 // An IC_Utility encapsulates IC::UtilityId. It exists mainly because you
272 // cannot make forward declarations to an enum.
275 explicit IC_Utility(IC::UtilityId id)
276 : address_(IC::AddressFromUtilityId(id)), id_(id) {}
278 Address address() const { return address_; }
280 IC::UtilityId id() const { return id_; }
287 class CallICBase: public IC {
289 // Returns a JSFunction or a Failure.
290 MUST_USE_RESULT MaybeObject* LoadFunction(Handle<Object> object,
291 Handle<String> name);
294 CallICBase(Code::Kind kind, Isolate* isolate)
295 : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {}
297 // Compute a monomorphic stub if possible, otherwise return a null handle.
298 Handle<Code> ComputeMonomorphicStub(LookupResult* lookup,
299 Handle<Object> object,
300 Handle<String> name);
302 // Update the inline cache and the global stub cache based on the lookup
304 void UpdateCaches(LookupResult* lookup,
305 Handle<Object> object,
306 Handle<String> name);
308 // Returns a JSFunction if the object can be called as a function, and
309 // patches the stack to be ready for the call. Otherwise, it returns the
311 Handle<Object> TryCallAsFunction(Handle<Object> object);
313 void ReceiverToObjectIfRequired(Handle<Object> callee, Handle<Object> object);
315 static void Clear(Address address, Code* target);
317 // Platform-specific code generation functions used by both call and
319 static void GenerateMiss(MacroAssembler* masm,
322 ExtraICState extra_state);
324 static void GenerateNormal(MacroAssembler* masm, int argc);
326 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
329 ExtraICState extra_state);
331 virtual Handle<Code> megamorphic_stub();
332 virtual Handle<Code> pre_monomorphic_stub();
340 class CallIC: public CallICBase {
342 explicit CallIC(Isolate* isolate)
343 : CallICBase(Code::CALL_IC, isolate) {
344 ASSERT(target()->is_call_stub());
347 // Code generator routines.
348 static void GenerateInitialize(MacroAssembler* masm,
350 ExtraICState extra_state) {
351 GenerateMiss(masm, argc, extra_state);
354 static void GenerateMiss(MacroAssembler* masm,
356 ExtraICState extra_state) {
357 CallICBase::GenerateMiss(masm, argc, IC::kCallIC_Miss, extra_state);
360 static void GenerateMegamorphic(MacroAssembler* masm,
362 ExtraICState extra_ic_state);
364 static void GenerateNormal(MacroAssembler* masm, int argc) {
365 CallICBase::GenerateNormal(masm, argc);
366 GenerateMiss(masm, argc, kNoExtraICState);
368 bool TryUpdateExtraICState(LookupResult* lookup, Handle<Object> object);
372 class KeyedCallIC: public CallICBase {
374 explicit KeyedCallIC(Isolate* isolate)
375 : CallICBase(Code::KEYED_CALL_IC, isolate) {
376 ASSERT(target()->is_keyed_call_stub());
379 MUST_USE_RESULT MaybeObject* LoadFunction(Handle<Object> object,
382 // Code generator routines.
383 static void GenerateInitialize(MacroAssembler* masm, int argc) {
384 GenerateMiss(masm, argc);
387 static void GenerateMiss(MacroAssembler* masm, int argc) {
388 CallICBase::GenerateMiss(masm, argc, IC::kKeyedCallIC_Miss,
392 static void GenerateMegamorphic(MacroAssembler* masm, int argc);
393 static void GenerateNormal(MacroAssembler* masm, int argc);
394 static void GenerateNonStrictArguments(MacroAssembler* masm, int argc);
398 class LoadIC: public IC {
401 class Contextual: public BitField<ContextualMode, 0, 1> {};
402 STATIC_ASSERT(static_cast<int>(NOT_CONTEXTUAL) == 0);
404 static ExtraICState ComputeExtraICState(ContextualMode mode) {
405 return Contextual::encode(mode);
408 static ContextualMode GetContextualMode(ExtraICState state) {
409 return Contextual::decode(state);
412 ContextualMode contextual_mode() const {
413 return Contextual::decode(extra_ic_state());
416 explicit LoadIC(FrameDepth depth, Isolate* isolate)
417 : IC(depth, isolate) {
418 ASSERT(IsLoadStub());
421 // Returns if this IC is for contextual (no explicit receiver)
422 // access to properties.
423 bool IsUndeclaredGlobal(Handle<Object> receiver) {
424 if (receiver->IsGlobalObject()) {
425 return contextual_mode() == CONTEXTUAL;
427 ASSERT(contextual_mode() != CONTEXTUAL);
432 // Code generator routines.
433 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
434 static void GeneratePreMonomorphic(MacroAssembler* masm) {
437 static void GenerateMiss(MacroAssembler* masm);
438 static void GenerateMegamorphic(MacroAssembler* masm, ContextualMode mode);
439 static void GenerateNormal(MacroAssembler* masm);
440 static void GenerateRuntimeGetProperty(MacroAssembler* masm);
442 static Handle<Code> initialize_stub(Isolate* isolate, ContextualMode mode);
444 MUST_USE_RESULT MaybeObject* Load(Handle<Object> object,
445 Handle<String> name);
448 virtual Code::Kind kind() const { return Code::LOAD_IC; }
450 void set_target(Code* code) {
451 // The contextual mode must be preserved across IC patching.
452 ASSERT(GetContextualMode(code->extra_ic_state()) ==
453 GetContextualMode(target()->extra_ic_state()));
455 IC::set_target(code);
458 virtual Handle<Code> slow_stub() const {
459 return isolate()->builtins()->LoadIC_Slow();
462 virtual Handle<Code> megamorphic_stub();
464 // Update the inline cache and the global stub cache based on the
466 void UpdateCaches(LookupResult* lookup,
467 Handle<Object> object,
468 Handle<String> name);
470 virtual Handle<Code> CompileHandler(LookupResult* lookup,
471 Handle<Object> object,
473 Handle<Object> unused,
474 InlineCacheHolderFlag cache_holder);
478 static Handle<Code> pre_monomorphic_stub(Isolate* isolate,
479 ContextualMode mode);
481 virtual Handle<Code> pre_monomorphic_stub() {
482 return pre_monomorphic_stub(isolate(), contextual_mode());
485 Handle<Code> SimpleFieldLoad(int offset,
486 bool inobject = true,
487 Representation representation =
488 Representation::Tagged());
490 static void Clear(Isolate* isolate, Address address, Code* target);
496 class KeyedLoadIC: public LoadIC {
498 explicit KeyedLoadIC(FrameDepth depth, Isolate* isolate)
499 : LoadIC(depth, isolate) {
500 ASSERT(target()->is_keyed_load_stub());
503 MUST_USE_RESULT MaybeObject* Load(Handle<Object> object,
506 // Code generator routines.
507 static void GenerateMiss(MacroAssembler* masm);
508 static void GenerateRuntimeGetProperty(MacroAssembler* masm);
509 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
510 static void GeneratePreMonomorphic(MacroAssembler* masm) {
513 static void GenerateGeneric(MacroAssembler* masm);
514 static void GenerateString(MacroAssembler* masm);
515 static void GenerateIndexedInterceptor(MacroAssembler* masm);
516 static void GenerateNonStrictArguments(MacroAssembler* masm);
518 // Bit mask to be tested against bit field for the cases when
519 // generic stub should go into slow case.
520 // Access check is necessary explicitly since generic stub does not perform
522 static const int kSlowCaseBitFieldMask =
523 (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
526 virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
528 Handle<Code> LoadElementStub(Handle<JSObject> receiver);
530 virtual Handle<Code> megamorphic_stub() {
531 return isolate()->builtins()->KeyedLoadIC_Generic();
533 virtual Handle<Code> generic_stub() const {
534 return isolate()->builtins()->KeyedLoadIC_Generic();
536 virtual Handle<Code> slow_stub() const {
537 return isolate()->builtins()->KeyedLoadIC_Slow();
540 virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {}
544 static Handle<Code> pre_monomorphic_stub(Isolate* isolate) {
545 return isolate->builtins()->KeyedLoadIC_PreMonomorphic();
547 virtual Handle<Code> pre_monomorphic_stub() {
548 return pre_monomorphic_stub(isolate());
550 Handle<Code> indexed_interceptor_stub() {
551 return isolate()->builtins()->KeyedLoadIC_IndexedInterceptor();
553 Handle<Code> non_strict_arguments_stub() {
554 return isolate()->builtins()->KeyedLoadIC_NonStrictArguments();
556 Handle<Code> string_stub() {
557 return isolate()->builtins()->KeyedLoadIC_String();
560 static void Clear(Isolate* isolate, Address address, Code* target);
566 class StoreIC: public IC {
568 class StrictModeState: public BitField<StrictModeFlag, 1, 1> {};
569 static ExtraICState ComputeExtraICState(StrictModeFlag flag) {
570 return StrictModeState::encode(flag);
573 static StrictModeFlag GetStrictMode(ExtraICState state) {
574 return StrictModeState::decode(state);
577 // For convenience, a statically declared encoding of strict mode extra
579 static const ExtraICState kStrictModeState =
580 1 << StrictModeState::kShift;
582 StoreIC(FrameDepth depth, Isolate* isolate)
583 : IC(depth, isolate) {
584 ASSERT(IsStoreStub());
587 StrictModeFlag strict_mode() const {
588 return StrictModeState::decode(extra_ic_state());
591 // Code generators for stub routines. Only called once at startup.
592 static void GenerateSlow(MacroAssembler* masm);
593 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
594 static void GeneratePreMonomorphic(MacroAssembler* masm) {
597 static void GenerateMiss(MacroAssembler* masm);
598 static void GenerateMegamorphic(MacroAssembler* masm,
599 ExtraICState extra_ic_state);
600 static void GenerateNormal(MacroAssembler* masm);
601 static void GenerateRuntimeSetProperty(MacroAssembler* masm,
602 StrictModeFlag strict_mode);
604 static Handle<Code> initialize_stub(Isolate* isolate,
605 StrictModeFlag strict_mode);
607 MUST_USE_RESULT MaybeObject* Store(
608 Handle<Object> object,
610 Handle<Object> value,
611 JSReceiver::StoreFromKeyed store_mode =
612 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
615 virtual Code::Kind kind() const { return Code::STORE_IC; }
616 virtual Handle<Code> megamorphic_stub();
619 virtual Handle<Code> generic_stub() const;
621 virtual Handle<Code> slow_stub() const {
622 return isolate()->builtins()->StoreIC_Slow();
625 virtual Handle<Code> pre_monomorphic_stub() {
626 return pre_monomorphic_stub(isolate(), strict_mode());
629 static Handle<Code> pre_monomorphic_stub(Isolate* isolate,
630 StrictModeFlag strict_mode);
632 // Update the inline cache and the global stub cache based on the
634 void UpdateCaches(LookupResult* lookup,
635 Handle<JSObject> receiver,
637 Handle<Object> value);
638 virtual Handle<Code> CompileHandler(LookupResult* lookup,
639 Handle<Object> object,
641 Handle<Object> value,
642 InlineCacheHolderFlag cache_holder);
645 void set_target(Code* code) {
646 // Strict mode must be preserved across IC patching.
647 ASSERT(GetStrictMode(code->extra_ic_state()) ==
648 GetStrictMode(target()->extra_ic_state()));
649 IC::set_target(code);
652 static void Clear(Isolate* isolate, Address address, Code* target);
658 enum KeyedStoreCheckMap {
664 enum KeyedStoreIncrementLength {
665 kDontIncrementLength,
670 class KeyedStoreIC: public StoreIC {
672 // ExtraICState bits (building on IC)
674 class ExtraICStateKeyedAccessStoreMode:
675 public BitField<KeyedAccessStoreMode, 2, 4> {}; // NOLINT
677 static ExtraICState ComputeExtraICState(StrictModeFlag flag,
678 KeyedAccessStoreMode mode) {
679 return StrictModeState::encode(flag) |
680 ExtraICStateKeyedAccessStoreMode::encode(mode);
683 static KeyedAccessStoreMode GetKeyedAccessStoreMode(
684 ExtraICState extra_state) {
685 return ExtraICStateKeyedAccessStoreMode::decode(extra_state);
688 KeyedStoreIC(FrameDepth depth, Isolate* isolate)
689 : StoreIC(depth, isolate) {
690 ASSERT(target()->is_keyed_store_stub());
693 MUST_USE_RESULT MaybeObject* Store(Handle<Object> object,
695 Handle<Object> value);
697 // Code generators for stub routines. Only called once at startup.
698 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
699 static void GeneratePreMonomorphic(MacroAssembler* masm) {
702 static void GenerateMiss(MacroAssembler* masm);
703 static void GenerateSlow(MacroAssembler* masm);
704 static void GenerateRuntimeSetProperty(MacroAssembler* masm,
705 StrictModeFlag strict_mode);
706 static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode);
707 static void GenerateNonStrictArguments(MacroAssembler* masm);
710 virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
712 virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {}
714 virtual Handle<Code> pre_monomorphic_stub() {
715 return pre_monomorphic_stub(isolate(), strict_mode());
717 static Handle<Code> pre_monomorphic_stub(Isolate* isolate,
718 StrictModeFlag strict_mode) {
719 if (strict_mode == kStrictMode) {
720 return isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict();
722 return isolate->builtins()->KeyedStoreIC_PreMonomorphic();
725 virtual Handle<Code> slow_stub() const {
726 return isolate()->builtins()->KeyedStoreIC_Slow();
728 virtual Handle<Code> megamorphic_stub() {
729 if (strict_mode() == kStrictMode) {
730 return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
732 return isolate()->builtins()->KeyedStoreIC_Generic();
736 Handle<Code> StoreElementStub(Handle<JSObject> receiver,
737 KeyedAccessStoreMode store_mode);
740 void set_target(Code* code) {
741 // Strict mode must be preserved across IC patching.
742 ASSERT(GetStrictMode(code->extra_ic_state()) == strict_mode());
743 IC::set_target(code);
747 virtual Handle<Code> generic_stub() const {
748 if (strict_mode() == kStrictMode) {
749 return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
751 return isolate()->builtins()->KeyedStoreIC_Generic();
755 Handle<Code> non_strict_arguments_stub() {
756 return isolate()->builtins()->KeyedStoreIC_NonStrictArguments();
759 static void Clear(Isolate* isolate, Address address, Code* target);
761 KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
763 Handle<Object> value);
765 Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
766 KeyedAccessStoreMode store_mode);
772 // Mode to overwrite BinaryExpression values.
773 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
775 // Type Recording BinaryOpIC, that records the types of the inputs and outputs.
776 class BinaryOpIC: public IC {
778 class State V8_FINAL BASE_EMBEDDED {
780 explicit State(ExtraICState extra_ic_state);
782 State(Token::Value op, OverwriteMode mode)
783 : op_(op), mode_(mode), left_kind_(NONE), right_kind_(NONE),
785 ASSERT_LE(FIRST_TOKEN, op);
786 ASSERT_LE(op, LAST_TOKEN);
789 InlineCacheState GetICState() const {
790 if (Max(left_kind_, right_kind_) == NONE) {
791 return ::v8::internal::UNINITIALIZED;
793 if (Max(left_kind_, right_kind_) == GENERIC) {
794 return ::v8::internal::MEGAMORPHIC;
796 if (Min(left_kind_, right_kind_) == GENERIC) {
797 return ::v8::internal::GENERIC;
799 return ::v8::internal::MONOMORPHIC;
802 ExtraICState GetExtraICState() const;
804 static void GenerateAheadOfTime(
805 Isolate*, void (*Generate)(Isolate*, const State&));
807 bool CanReuseDoubleBox() const {
808 return (result_kind_ > SMI && result_kind_ <= NUMBER) &&
809 ((mode_ == OVERWRITE_LEFT &&
810 left_kind_ > SMI && left_kind_ <= NUMBER) ||
811 (mode_ == OVERWRITE_RIGHT &&
812 right_kind_ > SMI && right_kind_ <= NUMBER));
815 // Returns true if the IC _could_ create allocation mementos.
816 bool CouldCreateAllocationMementos() const {
817 if (left_kind_ == STRING || right_kind_ == STRING) {
818 ASSERT_EQ(Token::ADD, op_);
824 // Returns true if the IC _should_ create allocation mementos.
825 bool ShouldCreateAllocationMementos() const {
826 return FLAG_allocation_site_pretenuring &&
827 CouldCreateAllocationMementos();
830 bool HasSideEffects() const {
831 return Max(left_kind_, right_kind_) == GENERIC;
834 // Returns true if the IC should enable the inline smi code (i.e. if either
835 // parameter may be a smi).
836 bool UseInlinedSmiCode() const {
837 return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_);
840 static const int FIRST_TOKEN = Token::BIT_OR;
841 static const int LAST_TOKEN = Token::MOD;
843 Token::Value op() const { return op_; }
844 OverwriteMode mode() const { return mode_; }
845 Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
847 Type* GetLeftType(Zone* zone) const {
848 return KindToType(left_kind_, zone);
850 Type* GetRightType(Zone* zone) const {
851 return KindToType(right_kind_, zone);
853 Type* GetResultType(Zone* zone) const;
855 void Print(StringStream* stream) const;
857 void Update(Handle<Object> left,
858 Handle<Object> right,
859 Handle<Object> result);
862 enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
864 Kind UpdateKind(Handle<Object> object, Kind kind) const;
866 static const char* KindToString(Kind kind);
867 static Type* KindToType(Kind kind, Zone* zone);
868 static bool KindMaybeSmi(Kind kind) {
869 return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
872 // We truncate the last bit of the token.
873 STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4));
874 class OpField: public BitField<int, 0, 4> {};
875 class OverwriteModeField: public BitField<OverwriteMode, 4, 2> {};
876 class SSE2Field: public BitField<bool, 6, 1> {};
877 class ResultKindField: public BitField<Kind, 7, 3> {};
878 class LeftKindField: public BitField<Kind, 10, 3> {};
879 // When fixed right arg is set, we don't need to store the right kind.
880 // Thus the two fields can overlap.
881 class HasFixedRightArgField: public BitField<bool, 13, 1> {};
882 class FixedRightArgValueField: public BitField<int, 14, 4> {};
883 class RightKindField: public BitField<Kind, 14, 3> {};
890 Maybe<int> fixed_right_arg_;
893 explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
895 static Builtins::JavaScript TokenToJSBuiltin(Token::Value op);
897 MaybeObject* Transition(Handle<AllocationSite> allocation_site,
899 Handle<Object> right) V8_WARN_UNUSED_RESULT;
903 class CompareIC: public IC {
905 // The type/state lattice is defined by the following inequations:
906 // UNINITIALIZED < ...
909 // INTERNALIZED_STRING < STRING
910 // KNOWN_OBJECT < OBJECT
917 UNIQUE_NAME, // Symbol or InternalizedString
919 KNOWN_OBJECT, // JSObject with specific map (faster check)
923 static State NewInputState(State old_state, Handle<Object> value);
925 static Type* StateToType(Zone* zone,
927 Handle<Map> map = Handle<Map>());
929 static void StubInfoToType(int stub_minor_key,
936 CompareIC(Isolate* isolate, Token::Value op)
937 : IC(EXTRA_CALL_FRAME, isolate), op_(op) { }
939 // Update the inline cache for the given operands.
940 Code* UpdateCaches(Handle<Object> x, Handle<Object> y);
943 // Factory method for getting an uninitialized compare stub.
944 static Handle<Code> GetUninitialized(Isolate* isolate, Token::Value op);
946 // Helper function for computing the condition for a compare operation.
947 static Condition ComputeCondition(Token::Value op);
949 static const char* GetStateName(State state);
952 static bool HasInlinedSmiCode(Address address);
954 State TargetState(State old_state,
957 bool has_inlined_smi_code,
961 bool strict() const { return op_ == Token::EQ_STRICT; }
962 Condition GetCondition() const { return ComputeCondition(op_); }
964 static Code* GetRawUninitialized(Isolate* isolate, Token::Value op);
966 static void Clear(Isolate* isolate, Address address, Code* target);
974 class CompareNilIC: public IC {
976 explicit CompareNilIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
978 MUST_USE_RESULT MaybeObject* CompareNil(Handle<Object> object);
980 static Handle<Code> GetUninitialized();
982 static void Clear(Address address, Code* target);
984 static MUST_USE_RESULT MaybeObject* DoCompareNilSlow(NilValue nil,
985 Handle<Object> object);
989 class ToBooleanIC: public IC {
991 explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
993 MaybeObject* ToBoolean(Handle<Object> object);
997 // Helper for BinaryOpIC and CompareIC.
998 enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
999 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check);
1001 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure);
1002 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure);
1003 DECLARE_RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss);
1004 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure);
1005 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_MissFromStubFailure);
1006 DECLARE_RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss);
1007 DECLARE_RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss);
1008 DECLARE_RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_MissWithAllocationSite);
1009 DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss);
1010 DECLARE_RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss);
1013 } } // namespace v8::internal