| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #pragma once
- // DisableJit-TODO
- #if ENABLE_PROFILE_INFO
- #ifdef DYNAMIC_PROFILE_MUTATOR
- class DynamicProfileMutatorImpl;
- #endif
- #define PolymorphicInlineCacheUtilizationMinValue 0
- #define PolymorphicInlineCacheUtilizationMaxValue 0xFF
- #define PolymorphicInlineCacheUtilizationThreshold 0x80
- #define PolymorphicInlineCacheUtilizationIncrement 10
- #define PolymorphicInlineCacheUtilizationDecrement 1
- namespace IR
- {
- enum BailOutKind : uint
- {
- #define BAIL_OUT_KIND_LAST(n) n
- #define BAIL_OUT_KIND(n, ...) BAIL_OUT_KIND_LAST(n),
- #define BAIL_OUT_KIND_VALUE_LAST(n, v) n = v
- #define BAIL_OUT_KIND_VALUE(n, v) BAIL_OUT_KIND_VALUE_LAST(n, v),
- #include "BailOutKind.h"
- };
- ENUM_CLASS_HELPERS(BailOutKind, uint);
- CompileAssert(BailOutKind::BailOutKindEnd < BailOutKind::BailOutKindBitsStart);
- bool IsTypeCheckBailOutKind(BailOutKind kind);
- bool IsEquivalentTypeCheckBailOutKind(BailOutKind kind);
- BailOutKind EquivalentToMonoTypeCheckBailOutKind(BailOutKind kind);
- }
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- const char *GetBailOutKindName(IR::BailOutKind kind);
- bool IsValidBailOutKindAndBits(IR::BailOutKind bailOutKind);
- #endif
- namespace Js
- {
- enum CacheType : byte;
- enum SlotType : byte;
- struct PolymorphicCallSiteInfo;
- // Information about dynamic profile information loaded from cache.
- // Used to verify whether the loaded information matches the paired function body.
- class DynamicProfileFunctionInfo
- {
- public:
- Field(Js::ArgSlot) paramInfoCount;
- Field(ProfileId) ldElemInfoCount;
- Field(ProfileId) stElemInfoCount;
- Field(ProfileId) arrayCallSiteCount;
- Field(ProfileId) slotInfoCount;
- Field(ProfileId) callSiteInfoCount;
- Field(ProfileId) returnTypeInfoCount;
- Field(ProfileId) divCount;
- Field(ProfileId) switchCount;
- Field(uint) loopCount;
- Field(uint) fldInfoCount;
- };
- enum ThisType : BYTE
- {
- ThisType_Unknown = 0,
- ThisType_Simple,
- ThisType_Mapped
- };
- struct ThisInfo
- {
- Field(ValueType) valueType;
- Field(ThisType) thisType;
- ThisInfo() : thisType(ThisType_Unknown)
- {
- }
- };
- struct CallSiteInfo
- {
- Field(ValueType) returnType;
- Field(uint16) isArgConstant : 13;
- Field(uint16) isConstructorCall : 1;
- Field(uint16) dontInline : 1;
- Field(uint16) isPolymorphic : 1;
- Field(InlineCacheIndex) ldFldInlineCacheId;
- union _u_type
- {
- struct
- {
- Field(Js::SourceId) sourceId;
- Field(Js::LocalFunctionId) functionId;
- } functionData;
- // As of now polymorphic info is allocated only if the source Id is current
- Field(PolymorphicCallSiteInfo*) polymorphicCallSiteInfo;
- _u_type() {}
- } u;
- };
- // TODO: include ImplicitCallFlags in this structure
- struct LoopFlags
- {
- // maintain the bits and the enum at the same time, it must match
- bool isInterpreted : 1;
- bool memopMinCountReached : 1;
- enum
- {
- INTERPRETED,
- MEMOP_MIN_COUNT_FOUND,
- COUNT
- };
- LoopFlags() :
- isInterpreted(false),
- memopMinCountReached(false)
- {
- CompileAssert((sizeof(LoopFlags) * 8) >= LoopFlags::COUNT);
- }
- // Right now supports up to 8 bits.
- typedef byte LoopFlags_t;
- LoopFlags(uint64 flags)
- {
- Assert(flags >> LoopFlags::COUNT == 0);
- LoopFlags_t* thisFlags = (LoopFlags_t *)this;
- CompileAssert(sizeof(LoopFlags_t) == sizeof(LoopFlags));
- *thisFlags = (LoopFlags_t)flags;
- }
- };
- enum FldInfoFlags : BYTE
- {
- FldInfo_NoInfo = 0x00,
- FldInfo_FromLocal = 0x01,
- FldInfo_FromProto = 0x02,
- FldInfo_FromLocalWithoutProperty = 0x04,
- FldInfo_FromAccessor = 0x08,
- FldInfo_Polymorphic = 0x10,
- FldInfo_FromInlineSlots = 0x20,
- FldInfo_FromAuxSlots = 0x40,
- FldInfo_InlineCandidate = 0x80
- };
- struct FldInfo
- {
- typedef struct { ValueType::TSize f1; byte f2; byte f3; } TSize;
- ValueType valueType;
- FldInfoFlags flags;
- byte polymorphicInlineCacheUtilization;
- bool ShouldUsePolymorphicInlineCache()
- {
- #if DBG
- if (PHASE_FORCE1(PolymorphicInlineCachePhase))
- {
- return true;
- }
- #endif
- return polymorphicInlineCacheUtilization > PolymorphicInlineCacheUtilizationThreshold;
- }
- bool WasLdFldProfiled() const
- {
- return !valueType.IsUninitialized();
- }
- static uint32 GetOffsetOfFlags() { return offsetof(FldInfo, flags); }
- };
- CompileAssert(sizeof(FldInfo::TSize) == sizeof(FldInfo));
- struct LdElemInfo
- {
- ValueType arrayType;
- ValueType elemType;
- union
- {
- struct
- {
- bool wasProfiled : 1;
- bool neededHelperCall : 1;
- };
- byte bits;
- };
- LdElemInfo() : bits(0)
- {
- wasProfiled = true;
- }
- void Merge(const LdElemInfo &other)
- {
- arrayType = arrayType.Merge(other.arrayType);
- elemType = elemType.Merge(other.elemType);
- bits |= other.bits;
- }
- ValueType GetArrayType() const
- {
- return arrayType;
- }
- ValueType GetElementType() const
- {
- return elemType;
- }
- bool WasProfiled() const
- {
- return wasProfiled;
- }
- bool LikelyNeedsHelperCall() const
- {
- return neededHelperCall;
- }
- };
- struct StElemInfo
- {
- ValueType arrayType;
- union
- {
- struct
- {
- bool wasProfiled : 1;
- bool createdMissingValue : 1;
- bool filledMissingValue : 1;
- bool neededHelperCall : 1;
- bool storedOutsideHeadSegmentBounds : 1;
- bool storedOutsideArrayBounds : 1;
- };
- byte bits;
- };
- StElemInfo() : bits(0)
- {
- wasProfiled = true;
- }
- void Merge(const StElemInfo &other)
- {
- arrayType = arrayType.Merge(other.arrayType);
- bits |= other.bits;
- }
- ValueType GetArrayType() const
- {
- return arrayType;
- }
- bool WasProfiled() const
- {
- return wasProfiled;
- }
- bool LikelyCreatesMissingValue() const
- {
- return createdMissingValue;
- }
- bool LikelyFillsMissingValue() const
- {
- return filledMissingValue;
- }
- bool LikelyNeedsHelperCall() const
- {
- return createdMissingValue || filledMissingValue || neededHelperCall || storedOutsideHeadSegmentBounds;
- }
- bool LikelyStoresOutsideHeadSegmentBounds() const
- {
- return createdMissingValue || storedOutsideHeadSegmentBounds;
- }
- bool LikelyStoresOutsideArrayBounds() const
- {
- return storedOutsideArrayBounds;
- }
- };
- struct ArrayCallSiteInfo
- {
- union {
- struct {
- byte isNotNativeInt : 1;
- byte isNotNativeFloat : 1;
- #if ENABLE_COPYONACCESS_ARRAY
- byte isNotCopyOnAccessArray : 1;
- byte copyOnAccessArrayCacheIndex : 5;
- #endif
- };
- byte bits;
- };
- #if DBG
- uint functionNumber;
- ProfileId callSiteNumber;
- #endif
- bool IsNativeIntArray() const { return !(bits & NotNativeIntBit) && !PHASE_OFF1(NativeArrayPhase); }
- bool IsNativeFloatArray() const { return !(bits & NotNativeFloatBit) && !PHASE_OFF1(NativeArrayPhase); }
- bool IsNativeArray() const { return IsNativeFloatArray(); }
- void SetIsNotNativeIntArray();
- void SetIsNotNativeFloatArray();
- void SetIsNotNativeArray();
- static uint32 GetOffsetOfBits() { return offsetof(ArrayCallSiteInfo, bits); }
- static byte const NotNativeIntBit = 1;
- static byte const NotNativeFloatBit = 2;
- };
- class DynamicProfileInfo;
- typedef SListBase<DynamicProfileInfo*, Recycler> DynamicProfileInfoList;
- class DynamicProfileInfo
- {
- public:
- static DynamicProfileInfo* New(Recycler* recycler, FunctionBody* functionBody, bool persistsAcrossScriptContexts = false);
- void Initialize(FunctionBody *const functionBody);
- public:
- static bool IsEnabledForAtLeastOneFunction(const ScriptContext *const scriptContext);
- static bool IsEnabled(const FunctionBody *const functionBody);
- private:
- static bool IsEnabled_OptionalFunctionBody(const FunctionBody *const functionBody, const ScriptContext *const scriptContext);
- public:
- static bool IsEnabledForAtLeastOneFunction(const Js::Phase phase, const ScriptContext *const scriptContext);
- static bool IsEnabled(const Js::Phase phase, const FunctionBody *const functionBody);
- private:
- static bool IsEnabled_OptionalFunctionBody(const Js::Phase phase, const FunctionBody *const functionBody, const ScriptContext *const scriptContext);
- public:
- static bool EnableImplicitCallFlags(const FunctionBody *const functionBody);
- static Var EnsureDynamicProfileInfoThunk(RecyclableObject * function, CallInfo callInfo, ...);
- #ifdef DYNAMIC_PROFILE_STORAGE
- bool HasFunctionBody() const { return hasFunctionBody; }
- FunctionBody * GetFunctionBody() const { Assert(hasFunctionBody); return functionBody; }
- #endif
- void RecordElementLoad(FunctionBody* functionBody, ProfileId ldElemId, const LdElemInfo& info);
- void RecordElementLoadAsProfiled(FunctionBody *const functionBody, const ProfileId ldElemId);
- const LdElemInfo *GetLdElemInfo() const { return ldElemInfo; }
- void RecordElementStore(FunctionBody* functionBody, ProfileId stElemId, const StElemInfo& info);
- void RecordElementStoreAsProfiled(FunctionBody *const functionBody, const ProfileId stElemId);
- const StElemInfo *GetStElemInfo() const { return stElemInfo; }
- ArrayCallSiteInfo *GetArrayCallSiteInfo(FunctionBody *functionBody, ProfileId index) const;
- ArrayCallSiteInfo *GetArrayCallSiteInfo() const { return arrayCallSiteInfo; }
- void RecordFieldAccess(FunctionBody* functionBody, uint fieldAccessId, Var object, FldInfoFlags flags);
- void RecordPolymorphicFieldAccess(FunctionBody *functionBody, uint fieldAccessid);
- bool HasPolymorphicFldAccess() const { return bits.hasPolymorphicFldAccess; }
- FldInfo * GetFldInfo(FunctionBody* functionBody, uint fieldAccessId) const;
- FldInfo * GetFldInfo() const { return fldInfo; }
- void RecordSlotLoad(FunctionBody* functionBody, ProfileId slotLoadId, Var object);
- ValueType GetSlotLoad(FunctionBody* functionBody, ProfileId slotLoadId) const;
- ValueType * GetSlotInfo() const { return slotInfo; }
- void RecordThisInfo(Var object, ThisType thisType);
- ThisInfo GetThisInfo() const;
- void RecordDivideResultType(FunctionBody* body, ProfileId divideId, Var object);
- ValueType GetDivideResultType(FunctionBody* body, ProfileId divideId) const;
- ValueType * GetDivideTypeInfo() const { return divideTypeInfo; }
- void RecordModulusOpType(FunctionBody* body, ProfileId profileId, bool isModByPowerOf2);
- bool IsModulusOpByPowerOf2(FunctionBody* body, ProfileId profileId) const;
- void RecordSwitchType(FunctionBody* body, ProfileId switchId, Var object);
- ValueType GetSwitchType(FunctionBody* body, ProfileId switchId) const;
- ValueType * GetSwitchTypeInfo() const { return switchTypeInfo; }
- void RecordCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId, FunctionInfo * calleeFunctionInfo, JavascriptFunction* calleeFunction, ArgSlot actualArgCount, bool isConstructorCall, InlineCacheIndex ldFldInlineCacheId = Js::Constants::NoInlineCacheIndex);
- void RecordConstParameterAtCallSite(ProfileId callSiteId, int argNum);
- static bool HasCallSiteInfo(FunctionBody* functionBody);
- bool HasCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId); // Does a particular callsite have ProfileInfo?
- FunctionInfo * GetCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId, bool *isConstructorCall, bool *isPolymorphicCall);
- CallSiteInfo * GetCallSiteInfo() const { return callSiteInfo; }
- uint16 GetConstantArgInfo(ProfileId callSiteId);
- uint GetLdFldCacheIndexFromCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId);
- bool GetPolymorphicCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId, bool *isConstructorCall, __inout_ecount(functionBodyArrayLength) FunctionBody** functionBodyArray, uint functionBodyArrayLength);
- bool RecordLdFldCallSiteInfo(FunctionBody* functionBody, RecyclableObject* callee, bool callApplyTarget);
- bool HasLdFldCallSiteInfo() const;
- void RecordReturnTypeOnCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId, Var object);
- void RecordReturnType(FunctionBody* functionBody, ProfileId callSiteId, Var object);
- ValueType GetReturnType(FunctionBody* functionBody, Js::OpCode opcode, ProfileId callSiteId) const;
- ValueType * GetReturnTypeInfo() const { return returnTypeInfo; }
- void RecordParameterInfo(FunctionBody* functionBody, ArgSlot index, Var object);
- ValueType GetParameterInfo(FunctionBody* functionBody, ArgSlot index) const;
- ValueType * GetParameterInfo() const { return parameterInfo; }
- void RecordLoopImplicitCallFlags(FunctionBody* functionBody, uint loopNum, ImplicitCallFlags flags);
- ImplicitCallFlags GetLoopImplicitCallFlags(FunctionBody* functionBody, uint loopNum) const;
- ImplicitCallFlags * GetLoopImplicitCallFlags() const { return loopImplicitCallFlags; }
- void RecordImplicitCallFlags(ImplicitCallFlags flags);
- ImplicitCallFlags GetImplicitCallFlags() const;
- static void Save(ScriptContext * scriptContext);
- void UpdateFunctionInfo(FunctionBody* functionBody, Recycler* allocator);
- void ResetAllPolymorphicCallSiteInfo();
- bool CallSiteHasProfileData(ProfileId callSiteId)
- {
- return this->callSiteInfo[callSiteId].isPolymorphic
- || this->callSiteInfo[callSiteId].u.functionData.sourceId != NoSourceId
- || this->callSiteInfo[callSiteId].dontInline;
- }
- static bool IsProfiledCallOp(OpCode op);
- static bool IsProfiledReturnTypeOp(OpCode op);
- static FldInfoFlags FldInfoFlagsFromCacheType(CacheType cacheType);
- static FldInfoFlags FldInfoFlagsFromSlotType(SlotType slotType);
- static FldInfoFlags MergeFldInfoFlags(FldInfoFlags oldFlags, FldInfoFlags newFlags);
- const static uint maxPolymorphicInliningSize = 4;
- #if DBG_DUMP
- static void DumpScriptContext(ScriptContext * scriptContext);
- static char16 const * GetImplicitCallFlagsString(ImplicitCallFlags flags);
- #endif
- #ifdef RUNTIME_DATA_COLLECTION
- static void DumpScriptContextToFile(ScriptContext * scriptContext);
- #endif
- #if DBG_DUMP || defined(DYNAMIC_PROFILE_STORAGE) || defined(RUNTIME_DATA_COLLECTION)
- static bool NeedProfileInfoList();
- #endif
- #ifdef DYNAMIC_PROFILE_MUTATOR
- friend class DynamicProfileMutatorImpl;
- #endif
- #if JS_PROFILE_DATA_INTERFACE
- friend class ProfileDataObject;
- #endif
- private:
- // Have the dynamicProfileFunctionInfo after loaded from cache.
- // Replaced with the function body it is verified and matched (See DynamicProfileInfo::MatchFunctionBody)
- Field(DynamicProfileFunctionInfo *) dynamicProfileFunctionInfo;
- Field(CallSiteInfo *) callSiteInfo;
- Field(ValueType *) returnTypeInfo; // return type of calls for non inline call sites
- Field(ValueType *) divideTypeInfo;
- Field(ValueType *) switchTypeInfo;
- Field(LdElemInfo *) ldElemInfo;
- Field(StElemInfo *) stElemInfo;
- Field(ArrayCallSiteInfo *) arrayCallSiteInfo;
- Field(ValueType *) parameterInfo;
- Field(FldInfo *) fldInfo;
- Field(ValueType *) slotInfo;
- Field(ImplicitCallFlags *) loopImplicitCallFlags;
- Field(ImplicitCallFlags) implicitCallFlags;
- Field(BVFixed*) loopFlags;
- Field(ThisInfo) thisInfo;
- // TODO (jedmiad): Consider storing a pair of property ID bit vectors indicating which properties are
- // known to be non-fixed or non-equivalent. We could turn these on if we bailed out of fixed field type
- // checks and equivalent type checks in a way that indicates one of these failures as opposed to type
- // mismatch.
- struct Bits
- {
- Field(bool) disableAggressiveIntTypeSpec : 1;
- Field(bool) disableAggressiveIntTypeSpec_jitLoopBody : 1;
- Field(bool) disableAggressiveMulIntTypeSpec : 1;
- Field(bool) disableAggressiveMulIntTypeSpec_jitLoopBody : 1;
- Field(bool) disableDivIntTypeSpec : 1;
- Field(bool) disableDivIntTypeSpec_jitLoopBody : 1;
- Field(bool) disableLossyIntTypeSpec : 1;
- // TODO: put this flag in LoopFlags if we can find a reliable way to determine the loopNumber in bailout for a hoisted instr
- Field(bool) disableMemOp : 1;
- Field(bool) disableTrackCompoundedIntOverflow : 1;
- Field(bool) disableFloatTypeSpec : 1;
- Field(bool) disableCheckThis : 1;
- Field(bool) disableArrayCheckHoist : 1;
- Field(bool) disableArrayCheckHoist_jitLoopBody : 1;
- Field(bool) disableArrayMissingValueCheckHoist : 1;
- Field(bool) disableArrayMissingValueCheckHoist_jitLoopBody : 1;
- Field(bool) disableJsArraySegmentHoist : 1;
- Field(bool) disableJsArraySegmentHoist_jitLoopBody : 1;
- Field(bool) disableArrayLengthHoist : 1;
- Field(bool) disableArrayLengthHoist_jitLoopBody : 1;
- Field(bool) disableTypedArrayTypeSpec : 1;
- Field(bool) disableTypedArrayTypeSpec_jitLoopBody : 1;
- Field(bool) disableLdLenIntSpec : 1;
- Field(bool) disableBoundCheckHoist : 1;
- Field(bool) disableBoundCheckHoist_jitLoopBody : 1;
- Field(bool) disableLoopCountBasedBoundCheckHoist : 1;
- Field(bool) disableLoopCountBasedBoundCheckHoist_jitLoopBody : 1;
- Field(bool) hasPolymorphicFldAccess : 1;
- Field(bool) hasLdFldCallSite : 1; // getters, setters, .apply (possibly .call too in future)
- Field(bool) disableFloorInlining : 1;
- Field(bool) disableNoProfileBailouts : 1;
- Field(bool) disableSwitchOpt : 1;
- Field(bool) disableEquivalentObjTypeSpec : 1;
- Field(bool) disableObjTypeSpec_jitLoopBody : 1;
- Field(bool) disablePowIntIntTypeSpec : 1;
- Field(bool) disableLoopImplicitCallInfo : 1;
- Field(bool) disableStackArgOpt : 1;
- Field(bool) disableTagCheck : 1;
- };
- Field(Bits) bits;
- Field(uint32) m_recursiveInlineInfo; // Bit is set for each callsites where the function is called recursively
- Field(uint32) polymorphicCacheState;
- Field(uint32) bailOutOffsetForLastRejit;
- Field(bool) hasFunctionBody; // this is likely 1, try avoid 4-byte GC force reference
- Field(BYTE) currentInlinerVersion; // Used to detect when inlining profile changes
- Field(uint16) rejitCount;
- #if DBG
- Field(bool) persistsAcrossScriptContexts;
- #endif
- static JavascriptMethod EnsureDynamicProfileInfo(Js::ScriptFunction * function);
- #if DBG_DUMP
- static void DumpList(DynamicProfileInfoList * profileInfoList, ArenaAllocator * dynamicProfileInfoAllocator);
- static void DumpProfiledValue(char16 const * name, uint * value, uint count);
- static void DumpProfiledValue(char16 const * name, ValueType * value, uint count);
- static void DumpProfiledValue(char16 const * name, CallSiteInfo * callSiteInfo, uint count);
- static void DumpProfiledValue(char16 const * name, ArrayCallSiteInfo * arrayCallSiteInfo, uint count);
- static void DumpProfiledValue(char16 const * name, ImplicitCallFlags * loopImplicitCallFlags, uint count);
- template<class TData, class FGetValueType>
- static void DumpProfiledValuesGroupedByValue(const char16 *const name, const TData *const data, const uint count, const FGetValueType GetValueType, ArenaAllocator *const dynamicProfileInfoAllocator);
- static void DumpFldInfoFlags(char16 const * name, FldInfo * fldInfo, uint count, FldInfoFlags value, char16 const * valueName);
- static void DumpLoopInfo(FunctionBody *fbody);
- #endif
- bool IsPolymorphicCallSite(Js::LocalFunctionId curFunctionId, Js::SourceId curSourceId, Js::LocalFunctionId oldFunctionId, Js::SourceId oldSourceId);
- void CreatePolymorphicDynamicProfileCallSiteInfo(FunctionBody * funcBody, ProfileId callSiteId, Js::LocalFunctionId functionId, Js::LocalFunctionId oldFunctionId, Js::SourceId sourceId, Js::SourceId oldSourceId);
- void ResetPolymorphicCallSiteInfo(ProfileId callSiteId, Js::LocalFunctionId functionId);
- void SetFunctionIdSlotForNewPolymorphicCall(ProfileId callSiteId, Js::LocalFunctionId curFunctionId, Js::SourceId curSourceId, Js::FunctionBody *inliner);
- void RecordPolymorphicCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId, FunctionInfo * calleeFunctionInfo);
- #ifdef RUNTIME_DATA_COLLECTION
- static CriticalSection s_csOutput;
- template <typename T>
- static void WriteData(const T& data, FILE * file);
- #if defined(_MSC_VER) && !defined(__clang__)
- template <>
- static void WriteData<char16 const *>(char16 const * const& sz, FILE * file);
- template <>
- static void WriteData<FunctionInfo *>(FunctionInfo * const& functionInfo, FILE * file); // Not defined, to prevent accidentally writing function info
- template <>
- static void WriteData<FunctionBody *>(FunctionBody * const& functionInfo, FILE * file);
- #endif
- template <typename T>
- static void WriteArray(uint count, T * arr, FILE * file);
- template <typename T>
- static void WriteArray(uint count, WriteBarrierPtr<T> arr, FILE * file);
- #endif
- #if DBG_DUMP || defined(DYNAMIC_PROFILE_STORAGE) || defined(RUNTIME_DATA_COLLECTION)
- Field(FunctionBody *) functionBody; // This will only be populated if NeedProfileInfoList is true
- #endif
- #ifdef DYNAMIC_PROFILE_STORAGE
- // Used by de-serialize
- DynamicProfileInfo();
- template <typename T>
- static DynamicProfileInfo * Deserialize(T * reader, Recycler* allocator, Js::LocalFunctionId * functionId);
- template <typename T>
- bool Serialize(T * writer);
- static void UpdateSourceDynamicProfileManagers(ScriptContext * scriptContext);
- #endif
- static Js::LocalFunctionId const CallSiteMixed = (Js::LocalFunctionId)-1;
- static Js::LocalFunctionId const CallSiteCrossContext = (Js::LocalFunctionId)-2;
- static Js::LocalFunctionId const CallSiteNonFunction = (Js::LocalFunctionId)-3;
- static Js::LocalFunctionId const CallSiteNoInfo = (Js::LocalFunctionId)-4;
- static Js::LocalFunctionId const StartInvalidFunction = (Js::LocalFunctionId)-4;
- static Js::SourceId const NoSourceId = (SourceId)-1;
- static Js::SourceId const BuiltInSourceId = (SourceId)-2;
- static Js::SourceId const CurrentSourceId = (SourceId)-3; // caller and callee in the same file
- static Js::SourceId const InvalidSourceId = (SourceId)-4;
- bool MatchFunctionBody(FunctionBody * functionBody);
- DynamicProfileInfo(FunctionBody * functionBody);
- friend class SourceDynamicProfileManager;
- public:
- bool IsAggressiveIntTypeSpecDisabled(const bool isJitLoopBody) const
- {
- return
- isJitLoopBody
- ? this->bits.disableAggressiveIntTypeSpec_jitLoopBody
- : this->bits.disableAggressiveIntTypeSpec;
- }
- void DisableAggressiveIntTypeSpec(const bool isJitLoopBody)
- {
- this->bits.disableAggressiveIntTypeSpec_jitLoopBody = true;
- if (!isJitLoopBody)
- {
- this->bits.disableAggressiveIntTypeSpec = true;
- }
- }
- bool IsAggressiveMulIntTypeSpecDisabled(const bool isJitLoopBody) const
- {
- return
- isJitLoopBody
- ? this->bits.disableAggressiveMulIntTypeSpec_jitLoopBody
- : this->bits.disableAggressiveMulIntTypeSpec;
- }
- void DisableAggressiveMulIntTypeSpec(const bool isJitLoopBody)
- {
- this->bits.disableAggressiveMulIntTypeSpec_jitLoopBody = true;
- if (!isJitLoopBody)
- {
- this->bits.disableAggressiveMulIntTypeSpec = true;
- }
- }
- bool IsDivIntTypeSpecDisabled(const bool isJitLoopBody) const
- {
- return
- isJitLoopBody
- ? this->bits.disableDivIntTypeSpec_jitLoopBody
- : this->bits.disableDivIntTypeSpec;
- }
- void DisableDivIntTypeSpec(const bool isJitLoopBody)
- {
- this->bits.disableDivIntTypeSpec_jitLoopBody = true;
- if (!isJitLoopBody)
- {
- this->bits.disableDivIntTypeSpec = true;
- }
- }
- bool IsLossyIntTypeSpecDisabled() const { return bits.disableLossyIntTypeSpec; }
- void DisableLossyIntTypeSpec() { this->bits.disableLossyIntTypeSpec = true; }
- LoopFlags GetLoopFlags(int loopNumber) const
- {
- Assert(loopFlags);
- return loopFlags->GetRange<LoopFlags>(loopNumber * LoopFlags::COUNT, LoopFlags::COUNT);
- }
- BVFixed * GetLoopFlags() const { return loopFlags; }
- void SetLoopInterpreted(int loopNumber) { loopFlags->Set(loopNumber * LoopFlags::COUNT + LoopFlags::INTERPRETED); }
- void SetMemOpMinReached(int loopNumber) { loopFlags->Set(loopNumber * LoopFlags::COUNT + LoopFlags::MEMOP_MIN_COUNT_FOUND); }
- bool IsMemOpDisabled() const { return this->bits.disableMemOp; }
- void DisableMemOp() { this->bits.disableMemOp = true; }
- bool IsTrackCompoundedIntOverflowDisabled() const { return this->bits.disableTrackCompoundedIntOverflow; }
- void DisableTrackCompoundedIntOverflow() { this->bits.disableTrackCompoundedIntOverflow = true; }
- bool IsFloatTypeSpecDisabled() const { return this->bits.disableFloatTypeSpec; }
- void DisableFloatTypeSpec() { this->bits.disableFloatTypeSpec = true; }
- bool IsCheckThisDisabled() const { return this->bits.disableCheckThis; }
- void DisableCheckThis() { this->bits.disableCheckThis = true; }
- bool IsLoopImplicitCallInfoDisabled() const { return this->bits.disableLoopImplicitCallInfo; }
- void DisableLoopImplicitCallInfo() { this->bits.disableLoopImplicitCallInfo = true; }
- bool IsArrayCheckHoistDisabled(const bool isJitLoopBody) const
- {
- return
- isJitLoopBody
- ? this->bits.disableArrayCheckHoist_jitLoopBody
- : this->bits.disableArrayCheckHoist;
- }
- void DisableArrayCheckHoist(const bool isJitLoopBody)
- {
- this->bits.disableArrayCheckHoist_jitLoopBody = true;
- if (!isJitLoopBody)
- {
- this->bits.disableArrayCheckHoist = true;
- }
- }
- bool IsArrayMissingValueCheckHoistDisabled(const bool isJitLoopBody) const
- {
- return
- isJitLoopBody
- ? this->bits.disableArrayMissingValueCheckHoist_jitLoopBody
- : this->bits.disableArrayMissingValueCheckHoist;
- }
- void DisableArrayMissingValueCheckHoist(const bool isJitLoopBody)
- {
- this->bits.disableArrayMissingValueCheckHoist_jitLoopBody = true;
- if (!isJitLoopBody)
- {
- this->bits.disableArrayMissingValueCheckHoist = true;
- }
- }
- bool IsJsArraySegmentHoistDisabled(const bool isJitLoopBody) const
- {
- return
- isJitLoopBody
- ? this->bits.disableJsArraySegmentHoist_jitLoopBody
- : this->bits.disableJsArraySegmentHoist;
- }
- void DisableJsArraySegmentHoist(const bool isJitLoopBody)
- {
- this->bits.disableJsArraySegmentHoist_jitLoopBody = true;
- if (!isJitLoopBody)
- {
- this->bits.disableJsArraySegmentHoist = true;
- }
- }
- bool IsArrayLengthHoistDisabled(const bool isJitLoopBody) const
- {
- return
- isJitLoopBody
- ? this->bits.disableArrayLengthHoist_jitLoopBody
- : this->bits.disableArrayLengthHoist;
- }
- void DisableArrayLengthHoist(const bool isJitLoopBody)
- {
- this->bits.disableArrayLengthHoist_jitLoopBody = true;
- if (!isJitLoopBody)
- {
- this->bits.disableArrayLengthHoist = true;
- }
- }
- bool IsTypedArrayTypeSpecDisabled(const bool isJitLoopBody) const
- {
- return
- isJitLoopBody
- ? this->bits.disableTypedArrayTypeSpec_jitLoopBody
- : this->bits.disableTypedArrayTypeSpec;
- }
- void DisableTypedArrayTypeSpec(const bool isJitLoopBody)
- {
- this->bits.disableTypedArrayTypeSpec_jitLoopBody = true;
- if (!isJitLoopBody)
- {
- this->bits.disableTypedArrayTypeSpec = true;
- }
- }
- bool IsLdLenIntSpecDisabled() const { return this->bits.disableLdLenIntSpec; }
- void DisableLdLenIntSpec() { this->bits.disableLdLenIntSpec = true; }
- bool IsBoundCheckHoistDisabled(const bool isJitLoopBody) const
- {
- return
- isJitLoopBody
- ? this->bits.disableBoundCheckHoist_jitLoopBody
- : this->bits.disableBoundCheckHoist;
- }
- void DisableBoundCheckHoist(const bool isJitLoopBody)
- {
- this->bits.disableBoundCheckHoist_jitLoopBody = true;
- if (!isJitLoopBody)
- {
- this->bits.disableBoundCheckHoist = true;
- }
- }
- bool IsLoopCountBasedBoundCheckHoistDisabled(const bool isJitLoopBody) const
- {
- return
- isJitLoopBody
- ? this->bits.disableLoopCountBasedBoundCheckHoist_jitLoopBody
- : this->bits.disableLoopCountBasedBoundCheckHoist;
- }
- void DisableLoopCountBasedBoundCheckHoist(const bool isJitLoopBody)
- {
- this->bits.disableLoopCountBasedBoundCheckHoist_jitLoopBody = true;
- if (!isJitLoopBody)
- {
- this->bits.disableLoopCountBasedBoundCheckHoist = true;
- }
- }
- BYTE GetInlinerVersion() { return this->currentInlinerVersion; }
- uint32 GetPolymorphicCacheState() const { return this->polymorphicCacheState; }
- uint32 GetRecursiveInlineInfo() const { return this->m_recursiveInlineInfo; }
- void SetHasNewPolyFieldAccess(FunctionBody *functionBody);
- bool IsFloorInliningDisabled() const { return this->bits.disableFloorInlining; }
- void DisableFloorInlining() { this->bits.disableFloorInlining = true; }
- bool IsNoProfileBailoutsDisabled() const { return this->bits.disableNoProfileBailouts; }
- void DisableNoProfileBailouts() { this->bits.disableNoProfileBailouts = true; }
- bool IsSwitchOptDisabled() const { return this->bits.disableSwitchOpt; }
- void DisableSwitchOpt() { this->bits.disableSwitchOpt = true; }
- bool IsStackArgOptDisabled() const { return this->bits.disableStackArgOpt; }
- void DisableStackArgOpt() { this->bits.disableStackArgOpt = true; }
- bool IsEquivalentObjTypeSpecDisabled() const { return this->bits.disableEquivalentObjTypeSpec; }
- void DisableEquivalentObjTypeSpec() { this->bits.disableEquivalentObjTypeSpec = true; }
- bool IsObjTypeSpecDisabledInJitLoopBody() const { return this->bits.disableObjTypeSpec_jitLoopBody; }
- void DisableObjTypeSpecInJitLoopBody() { this->bits.disableObjTypeSpec_jitLoopBody = true; }
- bool IsPowIntIntTypeSpecDisabled() const { return bits.disablePowIntIntTypeSpec; }
- void DisablePowIntIntTypeSpec() { this->bits.disablePowIntIntTypeSpec = true; }
- bool IsTagCheckDisabled() const { return bits.disableTagCheck; }
- void DisableTagCheck() { this->bits.disableTagCheck = true; }
- static bool IsCallSiteNoInfo(Js::LocalFunctionId functionId) { return functionId == CallSiteNoInfo; }
- int IncRejitCount() { return this->rejitCount++; }
- int GetRejitCount() { return this->rejitCount; }
- void SetBailOutOffsetForLastRejit(uint32 offset) { this->bailOutOffsetForLastRejit = offset; }
- uint32 GetBailOutOffsetForLastRejit() { return this->bailOutOffsetForLastRejit; }
- #if DBG_DUMP
- void Dump(FunctionBody* functionBody, ArenaAllocator * dynamicProfileInfoAllocator = nullptr);
- #endif
- private:
- static void InstantiateForceInlinedMembers();
- };
- struct PolymorphicCallSiteInfo
- {
- Field(Js::LocalFunctionId) functionIds[DynamicProfileInfo::maxPolymorphicInliningSize];
- Field(Js::SourceId) sourceIds[DynamicProfileInfo::maxPolymorphicInliningSize];
- Field(PolymorphicCallSiteInfo *) next;
- bool GetFunction(uint index, Js::LocalFunctionId *functionId, Js::SourceId *sourceId)
- {
- Assert(index < DynamicProfileInfo::maxPolymorphicInliningSize);
- Assert(functionId);
- Assert(sourceId);
- if (DynamicProfileInfo::IsCallSiteNoInfo(functionIds[index]))
- {
- return false;
- }
- *functionId = functionIds[index];
- *sourceId = sourceIds[index];
- return true;
- }
- };
- #ifdef DYNAMIC_PROFILE_STORAGE
- class BufferReader
- {
- public:
- BufferReader(__in_ecount(length) char const * buffer, size_t length) : current(buffer), lengthLeft(length) {}
- template <typename T>
- bool Read(T * data)
- {
- if (lengthLeft < sizeof(T))
- {
- return false;
- }
- *data = *(T *)current;
- current += sizeof(T);
- lengthLeft -= sizeof(T);
- return true;
- }
- template <typename T>
- bool Peek(T * data)
- {
- if (lengthLeft < sizeof(T))
- {
- return false;
- }
- *data = *(T *)current;
- return true;
- }
- template <typename T>
- bool ReadArray(__inout_ecount(len) T * data, size_t len)
- {
- size_t size = sizeof(T) * len;
- if (lengthLeft < size)
- {
- return false;
- }
- memcpy_s(data, size, current, size);
- current += size;
- lengthLeft -= size;
- return true;
- }
- private:
- char const * current;
- size_t lengthLeft;
- };
- class BufferSizeCounter
- {
- public:
- BufferSizeCounter() : count(0) {}
- size_t GetByteCount() const { return count; }
- template <typename T>
- bool Write(T const& data)
- {
- return WriteArray(&data, 1);
- }
- #if DBG_DUMP
- void Log(DynamicProfileInfo* info) {}
- #endif
- template <typename T>
- bool WriteArray(__in_ecount(len) T * data, size_t len)
- {
- count += sizeof(T) * len;
- return true;
- }
- template <typename T>
- bool WriteArray(WriteBarrierPtr<T> data, size_t len)
- {
- return WriteArray(static_cast<T*>(data), len);
- }
- private:
- size_t count;
- };
- class BufferWriter
- {
- public:
- BufferWriter(__in_ecount(length) char * buffer, size_t length) : current(buffer), lengthLeft(length) {}
- template <typename T>
- bool Write(T const& data)
- {
- return WriteArray(&data, 1);
- }
- #if DBG_DUMP
- void Log(DynamicProfileInfo* info);
- #endif
- template <typename T>
- bool WriteArray(__in_ecount(len) T * data, size_t len)
- {
- size_t size = sizeof(T) * len;
- if (lengthLeft < size)
- {
- return false;
- }
- memcpy_s(current, size, data, size);
- current += size;
- lengthLeft -= size;
- return true;
- }
- template <typename T>
- bool WriteArray(WriteBarrierPtr<T> data, size_t len)
- {
- return WriteArray(static_cast<T*>(data), len);
- }
- private:
- char * current;
- size_t lengthLeft;
- };
- #endif
- };
- #endif
|