diff options
Diffstat (limited to 'deps/v8/src/ic.h')
-rw-r--r-- | deps/v8/src/ic.h | 592 |
1 files changed, 305 insertions, 287 deletions
diff --git a/deps/v8/src/ic.h b/deps/v8/src/ic.h index fde4bc77a5..fce585f6d7 100644 --- a/deps/v8/src/ic.h +++ b/deps/v8/src/ic.h @@ -29,26 +29,24 @@ #define V8_IC_H_ #include "macro-assembler.h" -#include "type-info.h" namespace v8 { namespace internal { +const int kMaxKeyedPolymorphism = 4; + + // IC_UTIL_LIST defines all utility functions called from generated // inline caching code. The argument for the macro, ICU, is the function name. #define IC_UTIL_LIST(ICU) \ ICU(LoadIC_Miss) \ ICU(KeyedLoadIC_Miss) \ - ICU(KeyedLoadIC_MissForceGeneric) \ - ICU(CallIC_Miss) \ - ICU(KeyedCallIC_Miss) \ ICU(StoreIC_Miss) \ ICU(StoreIC_ArrayLength) \ ICU(StoreIC_Slow) \ ICU(SharedStoreIC_ExtendStorage) \ ICU(KeyedStoreIC_Miss) \ - ICU(KeyedStoreIC_MissForceGeneric) \ ICU(KeyedStoreIC_Slow) \ /* Utilities for IC stubs. */ \ ICU(StoreCallbackProperty) \ @@ -63,8 +61,7 @@ namespace internal { ICU(Unreachable) \ ICU(ToBooleanIC_Miss) // -// IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC, -// and KeyedStoreIC. +// IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC. // class IC { public: @@ -94,10 +91,6 @@ class IC { IC(FrameDepth depth, Isolate* isolate); virtual ~IC() {} - // Get the call-site target; used for determining the state. - Handle<Code> target() const { return target_; } - Code* raw_target() const { return GetTargetAtAddress(address()); } - State state() const { return state_; } inline Address address() const; @@ -110,40 +103,66 @@ class IC { // Clear the inline cache to initial state. static void Clear(Isolate* isolate, Address address); - // Computes the reloc info for this IC. This is a fairly expensive - // operation as it has to search through the heap to find the code - // object that contains this IC site. - RelocInfo::Mode ComputeMode(); - - // Returns if this IC is for contextual (no explicit receiver) - // access to properties. - bool IsUndeclaredGlobal(Handle<Object> receiver) { - if (receiver->IsGlobalObject()) { - return SlowIsUndeclaredGlobal(); - } else { - ASSERT(!SlowIsUndeclaredGlobal()); - return false; - } +#ifdef DEBUG + bool IsLoadStub() const { + return target()->is_load_stub() || target()->is_keyed_load_stub(); } - bool SlowIsUndeclaredGlobal() { - return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT; + bool IsStoreStub() const { + return target()->is_store_stub() || target()->is_keyed_store_stub(); } +#endif // Determines which map must be used for keeping the code stub. // These methods should not be called with undefined or null. - static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object, - JSObject* holder); - static inline JSObject* GetCodeCacheHolder(Isolate* isolate, - Object* object, - InlineCacheHolderFlag holder); + static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object); + // TODO(verwaest): This currently returns a HeapObject rather than JSObject* + // since loading the IC for loading the length from strings are stored on + // the string map directly, rather than on the JSObject-typed prototype. + static inline HeapObject* GetCodeCacheHolder(Isolate* isolate, + Object* object, + InlineCacheHolderFlag holder); + + static inline InlineCacheHolderFlag GetCodeCacheFlag(HeapType* type); + static inline Handle<Map> GetCodeCacheHolder(InlineCacheHolderFlag flag, + HeapType* type, + Isolate* isolate); static bool IsCleared(Code* code) { InlineCacheState state = code->ic_state(); return state == UNINITIALIZED || state == PREMONOMORPHIC; } + // Utility functions to convert maps to types and back. There are two special + // cases: + // - The heap_number_map is used as a marker which includes heap numbers as + // well as smis. + // - The oddball map is only used for booleans. + static Handle<Map> TypeToMap(HeapType* type, Isolate* isolate); + template <class T> + static typename T::TypeHandle MapToType(Handle<Map> map, + typename T::Region* region); + + static Handle<HeapType> CurrentTypeOf(Handle<Object> object, + Isolate* isolate); + protected: + // Get the call-site target; used for determining the state. + Handle<Code> target() const { return target_; } + + TypeHandleList* types() { return &types_; } + CodeHandleList* handlers() { return &handlers_; } + Map* first_map() { + return types_.length() == 0 ? NULL : *TypeToMap(*types_.at(0), isolate_); + } + Code* first_handler() { + return handlers_.length() == 0 ? NULL : *handlers_.at(0); + } + void GetMapsFromTypes(MapHandleList* maps) { + for (int i = 0; i < types_.length(); ++i) { + maps->Add(TypeToMap(*types_.at(i), isolate_)); + } + } Address fp() const { return fp_; } Address pc() const { return *pc_address_; } Isolate* isolate() const { return isolate_; } @@ -180,30 +199,33 @@ class IC { // Compute the handler either by compiling or by retrieving a cached version. Handle<Code> ComputeHandler(LookupResult* lookup, - Handle<JSObject> receiver, + Handle<Object> object, Handle<String> name, Handle<Object> value = Handle<Code>::null()); virtual Handle<Code> CompileHandler(LookupResult* lookup, - Handle<JSObject> receiver, + Handle<Object> object, Handle<String> name, - Handle<Object> value) { + Handle<Object> value, + InlineCacheHolderFlag cache_holder) { UNREACHABLE(); return Handle<Code>::null(); } - void UpdateMonomorphicIC(Handle<HeapObject> receiver, + + void UpdateMonomorphicIC(Handle<HeapType> type, Handle<Code> handler, Handle<String> name); - bool UpdatePolymorphicIC(Handle<HeapObject> receiver, + bool UpdatePolymorphicIC(Handle<HeapType> type, Handle<String> name, Handle<Code> code); + virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code); + void CopyICToMegamorphicCache(Handle<String> name); - bool IsTransitionedMapOfMonomorphicTarget(Map* receiver_map); - void PatchCache(Handle<HeapObject> receiver, + bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map); + void PatchCache(Handle<HeapType> type, Handle<String> name, Handle<Code> code); - virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code); virtual Code::Kind kind() const { UNREACHABLE(); return Code::STUB; @@ -220,12 +242,19 @@ class IC { UNREACHABLE(); return Handle<Code>::null(); } - virtual StrictModeFlag strict_mode() const { return kNonStrictMode; } + bool TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, Handle<String> name); void TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name); + ExtraICState extra_ic_state() const { return extra_ic_state_; } + void set_extra_ic_state(ExtraICState state) { + extra_ic_state_ = state; + } + private: + Code* raw_target() const { return GetTargetAtAddress(address()); } + // Frame pointer for the frame that uses (calls) the IC. Address fp_; @@ -242,6 +271,11 @@ class IC { State state_; bool target_set_; + ExtraICState extra_ic_state_; + + TypeHandleList types_; + CodeHandleList handlers_; + DISALLOW_IMPLICIT_CONSTRUCTORS(IC); }; @@ -262,133 +296,38 @@ class IC_Utility { }; -class CallICBase: public IC { - public: - class Contextual: public BitField<bool, 0, 1> {}; - class StringStubState: public BitField<StringStubFeedback, 1, 1> {}; - - // Returns a JSFunction or a Failure. - MUST_USE_RESULT MaybeObject* LoadFunction(Handle<Object> object, - Handle<String> name); - - protected: - CallICBase(Code::Kind kind, Isolate* isolate) - : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {} - - virtual Code::ExtraICState extra_ic_state() { return Code::kNoExtraICState; } - - // Compute a monomorphic stub if possible, otherwise return a null handle. - Handle<Code> ComputeMonomorphicStub(LookupResult* lookup, - Handle<Object> object, - Handle<String> name); - - // Update the inline cache and the global stub cache based on the lookup - // result. - void UpdateCaches(LookupResult* lookup, - Handle<Object> object, - Handle<String> name); - - // Returns a JSFunction if the object can be called as a function, and - // patches the stack to be ready for the call. Otherwise, it returns the - // undefined value. - Handle<Object> TryCallAsFunction(Handle<Object> object); - - void ReceiverToObjectIfRequired(Handle<Object> callee, Handle<Object> object); - - static void Clear(Address address, Code* target); - - // Platform-specific code generation functions used by both call and - // keyed call. - static void GenerateMiss(MacroAssembler* masm, - int argc, - IC::UtilityId id, - Code::ExtraICState extra_state); - - static void GenerateNormal(MacroAssembler* masm, int argc); - - static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, - int argc, - Code::Kind kind, - Code::ExtraICState extra_state); - - virtual Handle<Code> megamorphic_stub(); - virtual Handle<Code> pre_monomorphic_stub(); - - Code::Kind kind_; - - friend class IC; -}; - - -class CallIC: public CallICBase { +class LoadIC: public IC { public: - explicit CallIC(Isolate* isolate) - : CallICBase(Code::CALL_IC, isolate), - extra_ic_state_(target()->extra_ic_state()) { - ASSERT(target()->is_call_stub()); - } - - // Code generator routines. - static void GenerateInitialize(MacroAssembler* masm, - int argc, - Code::ExtraICState extra_state) { - GenerateMiss(masm, argc, extra_state); - } + // ExtraICState bits + class ContextualModeBits: public BitField<ContextualMode, 0, 1> {}; + STATIC_ASSERT(static_cast<int>(NOT_CONTEXTUAL) == 0); - static void GenerateMiss(MacroAssembler* masm, - int argc, - Code::ExtraICState extra_state) { - CallICBase::GenerateMiss(masm, argc, IC::kCallIC_Miss, extra_state); + static ExtraICState ComputeExtraICState(ContextualMode contextual_mode) { + return ContextualModeBits::encode(contextual_mode); } - static void GenerateMegamorphic(MacroAssembler* masm, - int argc, - Code::ExtraICState extra_ic_state); - - static void GenerateNormal(MacroAssembler* masm, int argc) { - CallICBase::GenerateNormal(masm, argc); - GenerateMiss(masm, argc, Code::kNoExtraICState); + static ContextualMode GetContextualMode(ExtraICState state) { + return ContextualModeBits::decode(state); } - bool TryUpdateExtraICState(LookupResult* lookup, Handle<Object> object); - - protected: - virtual Code::ExtraICState extra_ic_state() { return extra_ic_state_; } - - private: - Code::ExtraICState extra_ic_state_; -}; - -class KeyedCallIC: public CallICBase { - public: - explicit KeyedCallIC(Isolate* isolate) - : CallICBase(Code::KEYED_CALL_IC, isolate) { - ASSERT(target()->is_keyed_call_stub()); - } - - MUST_USE_RESULT MaybeObject* LoadFunction(Handle<Object> object, - Handle<Object> key); - - // Code generator routines. - static void GenerateInitialize(MacroAssembler* masm, int argc) { - GenerateMiss(masm, argc); + ContextualMode contextual_mode() const { + return ContextualModeBits::decode(extra_ic_state()); } - static void GenerateMiss(MacroAssembler* masm, int argc) { - CallICBase::GenerateMiss(masm, argc, IC::kKeyedCallIC_Miss, - Code::kNoExtraICState); + explicit LoadIC(FrameDepth depth, Isolate* isolate) + : IC(depth, isolate) { + ASSERT(IsLoadStub()); } - static void GenerateMegamorphic(MacroAssembler* masm, int argc); - static void GenerateNormal(MacroAssembler* masm, int argc); - static void GenerateNonStrictArguments(MacroAssembler* masm, int argc); -}; - - -class LoadIC: public IC { - public: - explicit LoadIC(FrameDepth depth, Isolate* isolate) : IC(depth, isolate) { - ASSERT(target()->is_load_stub() || target()->is_keyed_load_stub()); + // Returns if this IC is for contextual (no explicit receiver) + // access to properties. + bool IsUndeclaredGlobal(Handle<Object> receiver) { + if (receiver->IsGlobalObject()) { + return contextual_mode() == CONTEXTUAL; + } else { + ASSERT(contextual_mode() != CONTEXTUAL); + return false; + } } // Code generator routines. @@ -401,19 +340,28 @@ class LoadIC: public IC { static void GenerateNormal(MacroAssembler* masm); static void GenerateRuntimeGetProperty(MacroAssembler* masm); + static Handle<Code> initialize_stub(Isolate* isolate, + ExtraICState extra_state); + MUST_USE_RESULT MaybeObject* Load(Handle<Object> object, Handle<String> name); protected: virtual Code::Kind kind() const { return Code::LOAD_IC; } + void set_target(Code* code) { + // The contextual mode must be preserved across IC patching. + ASSERT(GetContextualMode(code->extra_ic_state()) == + GetContextualMode(target()->extra_ic_state())); + + IC::set_target(code); + } + virtual Handle<Code> slow_stub() const { return isolate()->builtins()->LoadIC_Slow(); } - virtual Handle<Code> megamorphic_stub() { - return isolate()->builtins()->LoadIC_Megamorphic(); - } + virtual Handle<Code> megamorphic_stub(); // Update the inline cache and the global stub cache based on the // lookup result. @@ -422,22 +370,18 @@ class LoadIC: public IC { Handle<String> name); virtual Handle<Code> CompileHandler(LookupResult* lookup, - Handle<JSObject> receiver, + Handle<Object> object, Handle<String> name, - Handle<Object> unused); + Handle<Object> unused, + InlineCacheHolderFlag cache_holder); private: // Stub accessors. - static Handle<Code> initialize_stub(Isolate* isolate) { - return isolate->builtins()->LoadIC_Initialize(); - } - - static Handle<Code> pre_monomorphic_stub(Isolate* isolate) { - return isolate->builtins()->LoadIC_PreMonomorphic(); - } + static Handle<Code> pre_monomorphic_stub(Isolate* isolate, + ExtraICState exstra_state); virtual Handle<Code> pre_monomorphic_stub() { - return pre_monomorphic_stub(isolate()); + return pre_monomorphic_stub(isolate(), extra_ic_state()); } Handle<Code> SimpleFieldLoad(int offset, @@ -451,12 +395,6 @@ class LoadIC: public IC { }; -enum ICMissMode { - MISS_FORCE_GENERIC, - MISS -}; - - class KeyedLoadIC: public LoadIC { public: explicit KeyedLoadIC(FrameDepth depth, Isolate* isolate) @@ -465,17 +403,14 @@ class KeyedLoadIC: public LoadIC { } MUST_USE_RESULT MaybeObject* Load(Handle<Object> object, - Handle<Object> key, - ICMissMode force_generic); + Handle<Object> key); // Code generator routines. - static void GenerateMiss(MacroAssembler* masm, ICMissMode force_generic); + static void GenerateMiss(MacroAssembler* masm); static void GenerateRuntimeGetProperty(MacroAssembler* masm); - static void GenerateInitialize(MacroAssembler* masm) { - GenerateMiss(masm, MISS); - } + static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } static void GeneratePreMonomorphic(MacroAssembler* masm) { - GenerateMiss(masm, MISS); + GenerateMiss(masm); } static void GenerateGeneric(MacroAssembler* masm); static void GenerateString(MacroAssembler* masm); @@ -504,13 +439,10 @@ class KeyedLoadIC: public LoadIC { return isolate()->builtins()->KeyedLoadIC_Slow(); } - virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code) { } + virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {} private: // Stub accessors. - static Handle<Code> initialize_stub(Isolate* isolate) { - return isolate->builtins()->KeyedLoadIC_Initialize(); - } static Handle<Code> pre_monomorphic_stub(Isolate* isolate) { return isolate->builtins()->KeyedLoadIC_PreMonomorphic(); } @@ -535,13 +467,28 @@ class KeyedLoadIC: public LoadIC { class StoreIC: public IC { public: + class StrictModeState: public BitField<StrictModeFlag, 1, 1> {}; + static ExtraICState ComputeExtraICState(StrictModeFlag flag) { + return StrictModeState::encode(flag); + } + + static StrictModeFlag GetStrictMode(ExtraICState state) { + return StrictModeState::decode(state); + } + + // For convenience, a statically declared encoding of strict mode extra + // IC state. + static const ExtraICState kStrictModeState = + 1 << StrictModeState::kShift; + StoreIC(FrameDepth depth, Isolate* isolate) - : IC(depth, isolate), - strict_mode_(Code::GetStrictMode(target()->extra_ic_state())) { - ASSERT(target()->is_store_stub() || target()->is_keyed_store_stub()); + : IC(depth, isolate) { + ASSERT(IsStoreStub()); } - virtual StrictModeFlag strict_mode() const { return strict_mode_; } + StrictModeFlag strict_mode() const { + return StrictModeState::decode(extra_ic_state()); + } // Code generators for stub routines. Only called once at startup. static void GenerateSlow(MacroAssembler* masm); @@ -550,12 +497,14 @@ class StoreIC: public IC { GenerateMiss(masm); } static void GenerateMiss(MacroAssembler* masm); - static void GenerateMegamorphic(MacroAssembler* masm, - StrictModeFlag strict_mode); + static void GenerateMegamorphic(MacroAssembler* masm); static void GenerateNormal(MacroAssembler* masm); static void GenerateRuntimeSetProperty(MacroAssembler* masm, StrictModeFlag strict_mode); + static Handle<Code> initialize_stub(Isolate* isolate, + StrictModeFlag strict_mode); + MUST_USE_RESULT MaybeObject* Store( Handle<Object> object, Handle<String> name, @@ -565,28 +514,13 @@ class StoreIC: public IC { protected: virtual Code::Kind kind() const { return Code::STORE_IC; } - virtual Handle<Code> megamorphic_stub() { - if (strict_mode() == kStrictMode) { - return isolate()->builtins()->StoreIC_Megamorphic_Strict(); - } else { - return isolate()->builtins()->StoreIC_Megamorphic(); - } - } + virtual Handle<Code> megamorphic_stub(); + // Stub accessors. - virtual Handle<Code> generic_stub() const { - if (strict_mode() == kStrictMode) { - return isolate()->builtins()->StoreIC_Generic_Strict(); - } else { - return isolate()->builtins()->StoreIC_Generic(); - } - } + virtual Handle<Code> generic_stub() const; virtual Handle<Code> slow_stub() const { - if (strict_mode() == kStrictMode) { - return isolate()->builtins()->StoreIC_Slow_Strict(); - } else { - return isolate()->builtins()->StoreIC_Slow(); - } + return isolate()->builtins()->StoreIC_Slow(); } virtual Handle<Code> pre_monomorphic_stub() { @@ -594,21 +528,7 @@ class StoreIC: public IC { } static Handle<Code> pre_monomorphic_stub(Isolate* isolate, - StrictModeFlag strict_mode) { - if (strict_mode == kStrictMode) { - return isolate->builtins()->StoreIC_PreMonomorphic_Strict(); - } else { - return isolate->builtins()->StoreIC_PreMonomorphic(); - } - } - - virtual Handle<Code> global_proxy_stub() { - if (strict_mode() == kStrictMode) { - return isolate()->builtins()->StoreIC_GlobalProxy_Strict(); - } else { - return isolate()->builtins()->StoreIC_GlobalProxy(); - } - } + StrictModeFlag strict_mode); // Update the inline cache and the global stub cache based on the // lookup result. @@ -617,31 +537,21 @@ class StoreIC: public IC { Handle<String> name, Handle<Object> value); virtual Handle<Code> CompileHandler(LookupResult* lookup, - Handle<JSObject> receiver, + Handle<Object> object, Handle<String> name, - Handle<Object> value); + Handle<Object> value, + InlineCacheHolderFlag cache_holder); private: void set_target(Code* code) { // Strict mode must be preserved across IC patching. - ASSERT(Code::GetStrictMode(code->extra_ic_state()) == - Code::GetStrictMode(target()->extra_ic_state())); + ASSERT(GetStrictMode(code->extra_ic_state()) == + GetStrictMode(target()->extra_ic_state())); IC::set_target(code); } - static Handle<Code> initialize_stub(Isolate* isolate, - StrictModeFlag strict_mode) { - if (strict_mode == kStrictMode) { - return isolate->builtins()->StoreIC_Initialize_Strict(); - } else { - return isolate->builtins()->StoreIC_Initialize(); - } - } - static void Clear(Isolate* isolate, Address address, Code* target); - StrictModeFlag strict_mode_; - friend class IC; }; @@ -660,6 +570,22 @@ enum KeyedStoreIncrementLength { class KeyedStoreIC: public StoreIC { public: + // ExtraICState bits (building on IC) + // ExtraICState bits + class ExtraICStateKeyedAccessStoreMode: + public BitField<KeyedAccessStoreMode, 2, 4> {}; // NOLINT + + static ExtraICState ComputeExtraICState(StrictModeFlag flag, + KeyedAccessStoreMode mode) { + return StrictModeState::encode(flag) | + ExtraICStateKeyedAccessStoreMode::encode(mode); + } + + static KeyedAccessStoreMode GetKeyedAccessStoreMode( + ExtraICState extra_state) { + return ExtraICStateKeyedAccessStoreMode::decode(extra_state); + } + KeyedStoreIC(FrameDepth depth, Isolate* isolate) : StoreIC(depth, isolate) { ASSERT(target()->is_keyed_store_stub()); @@ -667,17 +593,14 @@ class KeyedStoreIC: public StoreIC { MUST_USE_RESULT MaybeObject* Store(Handle<Object> object, Handle<Object> name, - Handle<Object> value, - ICMissMode force_generic); + Handle<Object> value); // Code generators for stub routines. Only called once at startup. - static void GenerateInitialize(MacroAssembler* masm) { - GenerateMiss(masm, MISS); - } + static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } static void GeneratePreMonomorphic(MacroAssembler* masm) { - GenerateMiss(masm, MISS); + GenerateMiss(masm); } - static void GenerateMiss(MacroAssembler* masm, ICMissMode force_generic); + static void GenerateMiss(MacroAssembler* masm); static void GenerateSlow(MacroAssembler* masm); static void GenerateRuntimeSetProperty(MacroAssembler* masm, StrictModeFlag strict_mode); @@ -687,7 +610,7 @@ class KeyedStoreIC: public StoreIC { protected: virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; } - virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code) { } + virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {} virtual Handle<Code> pre_monomorphic_stub() { return pre_monomorphic_stub(isolate(), strict_mode()); @@ -701,11 +624,7 @@ class KeyedStoreIC: public StoreIC { } } virtual Handle<Code> slow_stub() const { - if (strict_mode() == kStrictMode) { - return isolate()->builtins()->KeyedStoreIC_Slow_Strict(); - } else { - return isolate()->builtins()->KeyedStoreIC_Slow(); - } + return isolate()->builtins()->KeyedStoreIC_Slow(); } virtual Handle<Code> megamorphic_stub() { if (strict_mode() == kStrictMode) { @@ -721,20 +640,11 @@ class KeyedStoreIC: public StoreIC { private: void set_target(Code* code) { // Strict mode must be preserved across IC patching. - ASSERT(Code::GetStrictMode(code->extra_ic_state()) == strict_mode()); + ASSERT(GetStrictMode(code->extra_ic_state()) == strict_mode()); IC::set_target(code); } // Stub accessors. - static Handle<Code> initialize_stub(Isolate* isolate, - StrictModeFlag strict_mode) { - if (strict_mode == kStrictMode) { - return isolate->builtins()->KeyedStoreIC_Initialize_Strict(); - } else { - return isolate->builtins()->KeyedStoreIC_Initialize(); - } - } - virtual Handle<Code> generic_stub() const { if (strict_mode() == kStrictMode) { return isolate()->builtins()->KeyedStoreIC_Generic_Strict(); @@ -760,27 +670,134 @@ class KeyedStoreIC: public StoreIC { }; +// Mode to overwrite BinaryExpression values. +enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; + // Type Recording BinaryOpIC, that records the types of the inputs and outputs. class BinaryOpIC: public IC { public: - enum TypeInfo { - UNINITIALIZED, - SMI, - INT32, - NUMBER, - ODDBALL, - STRING, // Only used for addition operation. - GENERIC + class State V8_FINAL BASE_EMBEDDED { + public: + explicit State(ExtraICState extra_ic_state); + + State(Token::Value op, OverwriteMode mode) + : op_(op), mode_(mode), left_kind_(NONE), right_kind_(NONE), + result_kind_(NONE) { + ASSERT_LE(FIRST_TOKEN, op); + ASSERT_LE(op, LAST_TOKEN); + } + + InlineCacheState GetICState() const { + if (Max(left_kind_, right_kind_) == NONE) { + return ::v8::internal::UNINITIALIZED; + } + if (Max(left_kind_, right_kind_) == GENERIC) { + return ::v8::internal::MEGAMORPHIC; + } + if (Min(left_kind_, right_kind_) == GENERIC) { + return ::v8::internal::GENERIC; + } + return ::v8::internal::MONOMORPHIC; + } + + ExtraICState GetExtraICState() const; + + static void GenerateAheadOfTime( + Isolate*, void (*Generate)(Isolate*, const State&)); + + bool CanReuseDoubleBox() const { + return (result_kind_ > SMI && result_kind_ <= NUMBER) && + ((mode_ == OVERWRITE_LEFT && + left_kind_ > SMI && left_kind_ <= NUMBER) || + (mode_ == OVERWRITE_RIGHT && + right_kind_ > SMI && right_kind_ <= NUMBER)); + } + + // Returns true if the IC _could_ create allocation mementos. + bool CouldCreateAllocationMementos() const { + if (left_kind_ == STRING || right_kind_ == STRING) { + ASSERT_EQ(Token::ADD, op_); + return true; + } + return false; + } + + // Returns true if the IC _should_ create allocation mementos. + bool ShouldCreateAllocationMementos() const { + return FLAG_allocation_site_pretenuring && + CouldCreateAllocationMementos(); + } + + bool HasSideEffects() const { + return Max(left_kind_, right_kind_) == GENERIC; + } + + // Returns true if the IC should enable the inline smi code (i.e. if either + // parameter may be a smi). + bool UseInlinedSmiCode() const { + return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_); + } + + static const int FIRST_TOKEN = Token::BIT_OR; + static const int LAST_TOKEN = Token::MOD; + + Token::Value op() const { return op_; } + OverwriteMode mode() const { return mode_; } + Maybe<int> fixed_right_arg() const { return fixed_right_arg_; } + + Type* GetLeftType(Zone* zone) const { + return KindToType(left_kind_, zone); + } + Type* GetRightType(Zone* zone) const { + return KindToType(right_kind_, zone); + } + Type* GetResultType(Zone* zone) const; + + void Print(StringStream* stream) const; + + void Update(Handle<Object> left, + Handle<Object> right, + Handle<Object> result); + + private: + enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC }; + + Kind UpdateKind(Handle<Object> object, Kind kind) const; + + static const char* KindToString(Kind kind); + static Type* KindToType(Kind kind, Zone* zone); + static bool KindMaybeSmi(Kind kind) { + return (kind >= SMI && kind <= NUMBER) || kind == GENERIC; + } + + // We truncate the last bit of the token. + STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4)); + class OpField: public BitField<int, 0, 4> {}; + class OverwriteModeField: public BitField<OverwriteMode, 4, 2> {}; + class SSE2Field: public BitField<bool, 6, 1> {}; + class ResultKindField: public BitField<Kind, 7, 3> {}; + class LeftKindField: public BitField<Kind, 10, 3> {}; + // When fixed right arg is set, we don't need to store the right kind. + // Thus the two fields can overlap. + class HasFixedRightArgField: public BitField<bool, 13, 1> {}; + class FixedRightArgValueField: public BitField<int, 14, 4> {}; + class RightKindField: public BitField<Kind, 14, 3> {}; + + Token::Value op_; + OverwriteMode mode_; + Kind left_kind_; + Kind right_kind_; + Kind result_kind_; + Maybe<int> fixed_right_arg_; }; explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { } static Builtins::JavaScript TokenToJSBuiltin(Token::Value op); - static const char* GetName(TypeInfo type_info); - - MUST_USE_RESULT MaybeObject* Transition(Handle<Object> left, - Handle<Object> right); + MaybeObject* Transition(Handle<AllocationSite> allocation_site, + Handle<Object> left, + Handle<Object> right) V8_WARN_UNUSED_RESULT; }; @@ -806,22 +823,22 @@ class CompareIC: public IC { static State NewInputState(State old_state, Handle<Object> value); - static Handle<Type> StateToType(Isolate* isolate, - State state, - Handle<Map> map = Handle<Map>()); + static Type* StateToType(Zone* zone, + State state, + Handle<Map> map = Handle<Map>()); static void StubInfoToType(int stub_minor_key, - Handle<Type>* left_type, - Handle<Type>* right_type, - Handle<Type>* overall_type, + Type** left_type, + Type** right_type, + Type** overall_type, Handle<Map> map, - Isolate* isolate); + Zone* zone); CompareIC(Isolate* isolate, Token::Value op) : IC(EXTRA_CALL_FRAME, isolate), op_(op) { } // Update the inline cache for the given operands. - void UpdateCaches(Handle<Object> x, Handle<Object> y); + Code* UpdateCaches(Handle<Object> x, Handle<Object> y); // Factory method for getting an uninitialized compare stub. @@ -874,7 +891,7 @@ class ToBooleanIC: public IC { public: explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { } - MaybeObject* ToBoolean(Handle<Object> object, Code::ExtraICState state); + MaybeObject* ToBoolean(Handle<Object> object); }; @@ -888,6 +905,7 @@ DECLARE_RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss); DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure); DECLARE_RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss); DECLARE_RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss); +DECLARE_RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_MissWithAllocationSite); DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss); DECLARE_RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss); |