blob: d16d77d123e764cbe78495f7dbd26535e041a0b5 [file]
//-------------------------------------------------------------------------------------------------------
// 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<BVSparse<JitArenaAllocator> *> * toData, HashTable<BVSparse<JitArenaAllocator> *> *& fromData, bool deleteData);
void AddTransferDependencies(int sourceId, SymID dstSymId, HashTable<BVSparse<JitArenaAllocator> *> * dependencies);
void AddTransferDependencies(BVSparse<JitArenaAllocator> * bv, SymID dstSymID);
void OrHashTableOfBitVector(HashTable<BVSparse<JitArenaAllocator> *> * toData, HashTable<BVSparse<JitArenaAllocator> *> *& fromData, bool deleteData);
JitArenaAllocator * GetAllocator() const;
BVSparse<JitArenaAllocator> nonTempSyms;
BVSparse<JitArenaAllocator> tempTransferredSyms;
HashTable<BVSparse<JitArenaAllocator> *> * 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 <typename T>
class TempTracker : public T
{
#if DBG
friend class ObjectTempVerify;
#endif
public:
TempTracker(JitArenaAllocator * alloc, bool inLoop);
void MergeData(TempTracker<T> * 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 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<JitArenaAllocator> * 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<JitArenaAllocator> elemLoadDependencies;
// Per properties dependencies of Ld*Fld
HashTable<BVSparse<JitArenaAllocator> *> * 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<BVSparse<JitArenaAllocator> * > * upwardExposedMarkTempObjectSymsProperties;
BVSparse<JitArenaAllocator> upwardExposedMarkTempObjectLiveFields;
};
typedef TempTracker<NumberTemp> 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<JitArenaAllocator> * 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<ObjectTemp> 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<JitArenaAllocator> * 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<JitArenaAllocator> * bvTempTransferDependencies, BackwardPass * backwardPass) { return false; }
static bool DoTrace(BackwardPass * backwardPass);
static char16 const * GetTraceName() { return _u("MarkTempObjectVerify"); }
private:
BVSparse<JitArenaAllocator> removedUpwardExposedUse;
};
template <typename T> bool IsObjectTempVerify() { return false; }
template <> inline bool IsObjectTempVerify<ObjectTempVerify>() { return true; }
typedef TempTracker<ObjectTempVerify> TempObjectVerifyTracker;
#endif