//------------------------------------------------------------------------------------------------------- // 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 // Base class for TempTrackers. Contain the basic data and merge logic class TempTrackerBase { public: #if DBG bool HasTempTransferDependencies() const { return tempTransferDependencies != nullptr; } #endif protected: TempTrackerBase(JitArenaAllocator * alloc, bool inLoop); ~TempTrackerBase(); void MergeData(TempTrackerBase * fromData, bool deleteData); void MergeDependencies(HashTable *> * toData, HashTable *> *& fromData, bool deleteData); void AddTransferDependencies(int sourceId, SymID dstSymId, HashTable *> * dependencies); void AddTransferDependencies(BVSparse * bv, SymID dstSymID); void OrHashTableOfBitVector(HashTable *> * toData, HashTable *> *& fromData, bool deleteData); JitArenaAllocator * GetAllocator() const; BVSparse nonTempSyms; BVSparse tempTransferredSyms; HashTable *> * tempTransferDependencies; #if DBG void Dump(char16 const * traceName); #endif }; // Actual temp tracker class, with a template plug-in model to determine what kind of temp we want to track // (Number or Object) template class TempTracker : public T { #if DBG friend class ObjectTempVerify; #endif public: TempTracker(JitArenaAllocator * alloc, bool inLoop); void MergeData(TempTracker * fromData, bool deleteData); // Actual mark temp algorithm that are shared, but have different condition based // on the type of tracker as the template parameter void DisallowMarkTempAcrossYield(BVSparse* bytecodeUpwardExposed); void ProcessUse(StackSym * sym, BackwardPass * backwardPass); void MarkTemp(StackSym * sym, BackwardPass * backwardPass); #if DBG void Dump() { __super::Dump(T::GetTraceName()); } #endif }; class NumberTemp : public TempTrackerBase { public: void ProcessInstr(IR::Instr * instr, BackwardPass * backwardPass); void ProcessPropertySymUse(IR::SymOpnd * symOpnd, IR::Instr * instr, BackwardPass * backwardPass); void ProcessIndirUse(IR::IndirOpnd * indirOpnd, IR::Instr * instr, BackwardPass * backwardPass); protected: NumberTemp(JitArenaAllocator * alloc, bool inLoop); // Overrides of the base class for extra data merging void MergeData(NumberTemp * fromData, bool deleteData); // Function used by the TempTracker static bool IsTempUse(IR::Instr * instr, Sym * sym, BackwardPass * backwardPass); static bool IsTempTransfer(IR::Instr * instr); bool CanMarkTemp(IR::Instr * instr, BackwardPass * backwardPass); static void SetDstIsTemp(bool dstIsTemp, bool dstIsTempTransferred, IR::Instr * instr, BackwardPass * backwardPass); static bool IsTempProducing(IR::Instr * instr); bool HasExposedFieldDependencies(BVSparse * bvTempTransferDependencies, BackwardPass * backwardPass); // Support for property transfer, so we can stack allocate number if it is assigned to another stack allocated object bool IsTempPropertyTransferLoad(IR::Instr * instr, BackwardPass * backwardPass); bool IsTempPropertyTransferStore(IR::Instr * instr, BackwardPass * backwardPass); void PropagateTempPropertyTransferStoreDependencies(SymID usedSymID, PropertySym * propertySym, BackwardPass * backwardPass); SymID GetRepresentativePropertySymId(PropertySym * propertySym, BackwardPass * backwardPass); bool IsTempIndirTransferLoad(IR::Instr * instr, BackwardPass * backwardPass); bool IsInLoop() const { return propertyIdsTempTransferDependencies != nullptr; } bool DoMarkTempNumbersOnTempObjects(BackwardPass * backwardPass) const; #if DBG_DUMP static bool DoTrace(BackwardPass * backwardPass); static char16 const * GetTraceName() { return _u("MarkTempNumber"); } void Dump(char16 const * traceName); #endif // true if we have a LdElem_A from stack object that has non temp uses. bool nonTempElemLoad; // all the uses of values coming from LdElem_A, needed to detect dependencies on value set on stack objects BVSparse elemLoadDependencies; // Per properties dependencies of Ld*Fld HashTable *> * propertyIdsTempTransferDependencies; // Trace upward exposed mark temp object fields to answer // whether if there is any field value is still live on the next iteration HashTable * > * upwardExposedMarkTempObjectSymsProperties; BVSparse upwardExposedMarkTempObjectLiveFields; }; typedef TempTracker TempNumberTracker; class ObjectTemp : public TempTrackerBase { public: static bool CanStoreTemp(IR::Instr * instr); static void ProcessInstr(IR::Instr * instr); void ProcessBailOnNoProfile(IR::Instr * instr); // Used internally and by Globopt::GenerateBailOutMarkTempObjectIfNeeded static StackSym * GetStackSym(IR::Opnd * opnd, IR::PropertySymOpnd ** pPropertySymOpnd); protected: // Place holder functions, only implemented for ObjectTempVerify ObjectTemp(JitArenaAllocator * alloc, bool inLoop) : TempTrackerBase(alloc, inLoop) { /* Do nothing */ } // Function used by the TempTracker static bool IsTempUse(IR::Instr * instr, Sym * sym, BackwardPass * backwardPass); static bool IsTempTransfer(IR::Instr * instr); static bool CanMarkTemp(IR::Instr * instr, BackwardPass * backwardPass); static void SetDstIsTemp(bool dstIsTemp, bool dstIsTempTransferred, IR::Instr * instr, BackwardPass * backwardPass); // Object tracker doesn't support property transfer // (So we don't stack allocate object if it is assigned to another stack allocated object) bool IsTempPropertyTransferLoad(IR::Instr * instr, BackwardPass * backwardPass) { return false; } bool IsTempPropertyTransferStore(IR::Instr * instr, BackwardPass * backwardPass) { return false; } void PropagateTempPropertyTransferStoreDependencies(SymID usedSymID, PropertySym * propertySym, BackwardPass * backwardPass) { Assert(false); } bool IsTempIndirTransferLoad(IR::Instr * instr, BackwardPass * backwardPass) { return false; } bool HasExposedFieldDependencies(BVSparse * bvTempTransferDependencies, BackwardPass * backwardPass) { return false; } #if DBG_DUMP static bool DoTrace(BackwardPass * backwardPass); static char16 const * GetTraceName() { return _u("MarkTempObject"); } #endif private: static bool IsTempProducing(IR::Instr * instr); static bool IsTempUseOpCodeSym(IR::Instr * instr, Js::OpCode opcode, Sym * sym); friend class NumberTemp; #if DBG friend class ObjectTempVerify; #endif }; typedef TempTracker TempObjectTracker; #if DBG class ObjectTempVerify : public TempTrackerBase { friend class GlobOpt; public: void ProcessInstr(IR::Instr * instr, BackwardPass * backwardPass); void NotifyBailOutRemoval(IR:: Instr * instr, BackwardPass * backwardPass); void NotifyDeadStore(IR::Instr * instr, BackwardPass * backwardPass); void NotifyDeadByteCodeUses(IR::Instr * instr); void NotifyReverseCopyProp(IR::Instr * instr); void MergeDeadData(BasicBlock * block); static bool DependencyCheck(IR::Instr *instr, BVSparse * bvTempTransferDependencies, BackwardPass * backwardPass); protected: ObjectTempVerify(JitArenaAllocator * alloc, bool inLoop); void MergeData(ObjectTempVerify * fromData, bool deleteData); // Function used by the TempTracker static bool IsTempUse(IR::Instr * instr, Sym * sym, BackwardPass * backwardPass); static bool IsTempTransfer(IR::Instr * instr); static bool CanMarkTemp(IR::Instr * instr, BackwardPass * backwardPass); void SetDstIsTemp(bool dstIsTemp, bool dstIsTempTransferred, IR::Instr * instr, BackwardPass * backwardPass); // Object tracker doesn't support property transfer // (So we don't stack allocate object if it is assigned to another stack allocated object) bool IsTempPropertyTransferLoad(IR::Instr * instr, BackwardPass * backwardPass) { return false; } bool IsTempPropertyTransferStore(IR::Instr * instr, BackwardPass * backwardPass) { return false; } void PropagateTempPropertyTransferStoreDependencies(SymID usedSymID, PropertySym * propertySym, BackwardPass * backwardPass) { Assert(false); } bool IsTempIndirTransferLoad(IR::Instr * instr, BackwardPass * backwardPass) { return false; } bool HasExposedFieldDependencies(BVSparse * bvTempTransferDependencies, BackwardPass * backwardPass) { return false; } static bool DoTrace(BackwardPass * backwardPass); static char16 const * GetTraceName() { return _u("MarkTempObjectVerify"); } private: BVSparse removedUpwardExposedUse; }; template bool IsObjectTempVerify() { return false; } template <> inline bool IsObjectTempVerify() { return true; } typedef TempTracker TempObjectVerifyTracker; #endif