blob: 5ab48cdb155c5a8691f233fd1ec1399d2be6b383 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
class Lifetime;
namespace IR
{
class Instr;
class Opnd;
}
class StackSym;
class PropertySym;
typedef JsUtil::BaseDictionary<StackSym*, StackSym*, JitArenaAllocator, PrimeSizePolicy> StackSymMap;
typedef JsUtil::BaseDictionary<StackSym*, IR::Instr*, JitArenaAllocator, PrimeSizePolicy> SymInstrMap;
enum SymKind : BYTE
{
SymKindInvalid,
SymKindStack,
SymKindProperty
};
typedef uint32 SymID;
///---------------------------------------------------------------------------
///
/// class Sym
/// StackSym
/// PropertySym
///
///---------------------------------------------------------------------------
class Sym
{
public:
bool IsStackSym() const;
StackSym * AsStackSym();
StackSym const * AsStackSym() const;
bool IsPropertySym() const;
PropertySym * AsPropertySym();
PropertySym const * AsPropertySym() const;
#if DBG_DUMP || defined(ENABLE_IR_VIEWER)
void Dump(IRDumpFlags flags, const ValueType valueType = ValueType::Uninitialized) const;
void Dump(const ValueType valueType = ValueType::Uninitialized) const;
void DumpSimple() const;
#endif
#if DBG_DUMP
// Having a VTable helps the VS debugger determine which derived class we have
void virtual DummyVirtualFunc() {};
#endif
public:
Sym * m_next;
SymID m_id;
SymKind m_kind;
};
class ObjectSymInfo
{
public:
static ObjectSymInfo * New(Func * func);
static ObjectSymInfo * New(StackSym * typeSym, Func * func);
ObjectSymInfo(): m_typeSym(nullptr), m_propertySymList(nullptr) {};
public:
StackSym * m_typeSym;
PropertySym * m_propertySymList;
};
///---------------------------------------------------------------------------
///
/// class StackSym
///
/// Used for stack symbols. These are the register candidates.
///
///---------------------------------------------------------------------------
class StackSym: public Sym
{
private:
static StackSym * New(SymID id, IRType type, Js::RegSlot byteCodeRegSlot, Func *func);
public:
static StackSym * NewArgSlotSym(Js::ArgSlot argSlotNum, Func * func, IRType = TyVar);
static StackSym * NewArgSlotRegSym(Js::ArgSlot argSlotNum, Func * func, IRType = TyVar);
static StackSym * NewParamSlotSym(Js::ArgSlot argSlotNum, Func * func);
static StackSym * NewParamSlotSym(Js::ArgSlot argSlotNum, Func * func, IRType type);
static StackSym *NewImplicitParamSym(Js::ArgSlot paramSlotNum, Func * func);
static StackSym * New(IRType type, Func *func);
static StackSym * New(Func *func);
static StackSym * FindOrCreate(SymID id, Js::RegSlot byteCodeRegSlot, Func *func, IRType type = TyVar);
IRType GetType() const { return this->m_type; }
bool IsArgSlotSym() const;
bool IsParamSlotSym() const;
bool IsImplicitParamSym() const { return this->m_isImplicitParamSym; }
bool IsAllocated() const;
int32 GetIntConstValue() const;
Js::Var GetFloatConstValueAsVar_PostGlobOpt() const;
void * GetConstAddress(bool useLocal = false) const;
StackSym * CloneDef(Func *func);
StackSym * CloneUse(Func *func);
void CopySymAttrs(StackSym *symSrc);
bool IsSingleDef() const { return this->m_isSingleDef && this->m_instrDef; }
bool IsConst() const;
bool IsIntConst() const;
bool IsInt64Const() const;
bool IsTaggableIntConst() const;
bool IsFloatConst() const;
// SIMD_JS
bool IsSimd128Const() const;
void SetIsConst();
void SetIsIntConst(IntConstType value);
void SetIsInt64Const();
void SetIsFloatConst();
// SIMD_JS
void SetIsSimd128Const();
intptr_t GetLiteralConstValue_PostGlobOpt() const;
IR::Opnd * GetConstOpnd() const;
BailoutConstantValue GetConstValueForBailout() const;
// SIMD_JS
StackSym * GetSimd128EquivSym(IRType type, Func *func);
StackSym * GetSimd128F4EquivSym(Func *func);
StackSym * GetSimd128I4EquivSym(Func *func);
StackSym * GetSimd128I16EquivSym(Func *func);
StackSym * GetSimd128D2EquivSym(Func *func);
bool IsSimd128() const { return IRType_IsSimd128(this->GetType()); }
bool IsSimd128F4() const { return this->GetType() == TySimd128F4; }
bool IsSimd128I4() const { return this->GetType() == TySimd128I4; }
bool IsSimd128I8() const { return this->GetType() == TySimd128I8; }
bool IsSimd128I16() const { return this->GetType() == TySimd128I16; }
bool IsSimd128U4() const { return this->GetType() == TySimd128U4; }
bool IsSimd128U8() const { return this->GetType() == TySimd128U8; }
bool IsSimd128U16() const { return this->GetType() == TySimd128U16; }
bool IsSimd128B4() const { return this->GetType() == TySimd128B4; }
bool IsSimd128B8() const { return this->GetType() == TySimd128B8; }
bool IsSimd128B16() const { return this->GetType() == TySimd128B16; }
bool IsSimd128D2() const { return this->GetType() == TySimd128D2; }
StackSym * GetFloat64EquivSym(Func *func);
bool IsFloat64() const { return this->GetType() == TyFloat64; }
bool IsFloat32() const { return this->GetType() == TyFloat32; }
StackSym * GetInt32EquivSym(Func *func);
bool IsInt32() const { return this->GetType() == TyInt32; }
bool IsUInt32() const { return this->GetType() == TyUint32; }
bool IsInt64() const { return this->GetType() == TyInt64; }
bool IsUint64() const { return this->GetType() == TyUint64; }
StackSym * GetVarEquivSym(Func *func);
StackSym * GetVarEquivSym_NoCreate();
StackSym const * GetVarEquivSym_NoCreate() const;
bool IsVar() const { return this->GetType() == TyVar; }
bool IsTypeSpec() const { return this->m_isTypeSpec; }
static StackSym *GetVarEquivStackSym_NoCreate(Sym * sym);
static StackSym const *GetVarEquivStackSym_NoCreate(Sym const * const sym);
bool HasByteCodeRegSlot() const { return m_hasByteCodeRegSlot; }
Func * GetByteCodeFunc() const;
Js::RegSlot GetByteCodeRegSlot() const;
bool IsTempReg(Func *const func) const;
bool IsFromByteCodeConstantTable() const { return m_isFromByteCodeConstantTable; }
void SetIsFromByteCodeConstantTable() { this->m_isFromByteCodeConstantTable = true; }
Js::ArgSlot GetArgSlotNum() const { Assert(HasArgSlotNum()); return m_slotNum; }
bool HasArgSlotNum() const { return !!(m_isArgSlotSym | m_isArgSlotRegSym); }
void IncrementArgSlotNum();
void DecrementArgSlotNum();
Js::ArgSlot GetParamSlotNum() const { Assert(IsParamSlotSym()); return m_slotNum; }
IR::Instr * GetInstrDef() const { return this->IsSingleDef() ? this->m_instrDef : nullptr; }
bool HasObjectInfo() const { Assert(!IsTypeSpec()); return this->m_objectInfo != nullptr; };
ObjectSymInfo * GetObjectInfo() const { Assert(this->m_objectInfo); return this->m_objectInfo; }
void SetObjectInfo(ObjectSymInfo * value) { this->m_objectInfo = value; }
ObjectSymInfo * EnsureObjectInfo(Func * func);
bool HasObjectTypeSym() const { return HasObjectInfo() && GetObjectInfo()->m_typeSym; }
StackSym * GetObjectTypeSym() const { Assert(HasObjectTypeSym()); return GetObjectInfo()->m_typeSym; }
int GetSymSize(){ return TySize[m_type]; }
void FixupStackOffset(Func * currentFunc);
private:
StackSym * GetTypeEquivSym(IRType type, Func *func);
StackSym * GetTypeEquivSym_NoCreate(IRType type);
StackSym const * GetTypeEquivSym_NoCreate(IRType type) const;
#if DBG
void VerifyConstFlags() const;
#endif
private:
Js::ArgSlot m_slotNum;
public:
uint8 m_isSingleDef:1; // the symbol only has a single definition in the IR
uint8 m_isNotInt:1;
uint8 m_isSafeThis : 1;
uint8 m_isConst : 1; // single def and it is a constant
uint8 m_isIntConst : 1; // a constant and it's value is an Int32
uint8 m_isTaggableIntConst : 1; // a constant and it's value is taggable (Int31 in 32-bit, Int32 in x64)
uint8 m_isEncodedConstant : 1; // the constant has
uint8 m_isInt64Const: 1;
uint8 m_isFltConst: 1;
uint8 m_isSimd128Const : 1;
uint8 m_isStrConst:1;
uint8 m_isStrEmpty:1;
uint8 m_allocated:1;
uint8 m_hasByteCodeRegSlot:1;
uint8 m_isInlinedArgSlot:1;
uint8 m_isOrphanedArg :1;
uint8 m_isTypeSpec:1;
uint8 m_requiresBailOnNotNumber:1;
uint8 m_isFromByteCodeConstantTable:1;
uint8 m_mayNotBeTempLastUse:1;
uint8 m_isArgSlotSym: 1; // When set this implies an argument stack slot with no lifetime for register allocation
uint8 m_isArgSlotRegSym : 1;
uint8 m_isParamSym : 1;
uint8 m_isImplicitParamSym : 1;
uint8 m_isBailOutReferenced: 1; // argument sym referenced by bailout
uint8 m_isArgCaptured: 1; // True if there is a ByteCodeArgOutCapture for this symbol
uint8 m_nonEscapingArgObjAlias : 1;
uint8 m_isCatchObjectSym : 1; // a catch object sym (used while jitting loop bodies)
IRType m_type;
Js::BuiltinFunction m_builtInIndex;
int32 m_offset;
#ifdef _M_AMD64
// Only for AsmJs on x64. Argument position for ArgSyms.
int32 m_argPosition;
#endif
union
{
IR::Instr * m_instrDef; // m_isSingleDef
size_t constantValue; // !m_isSingleDef && m_isEncodedConstant
};
StackSym * m_tempNumberSym;
StackSym * m_equivNext;
ObjectSymInfo * m_objectInfo;
union {
struct GlobOpt
{
int numCompoundedAddSubUses;
} globOpt;
struct LinearScan
{
Lifetime * lifetime;
} linearScan;
struct Peeps
{
RegNum reg;
} peeps;
}scratch;
static const Js::ArgSlot InvalidSlot;
};
class ByteCodeStackSym : public StackSym
{
private:
ByteCodeStackSym(Js::RegSlot byteCodeRegSlot, Func * byteCodeFunc)
: byteCodeRegSlot(byteCodeRegSlot), byteCodeFunc(byteCodeFunc) {}
Js::RegSlot byteCodeRegSlot;
Func * byteCodeFunc;
friend class StackSym;
};
///---------------------------------------------------------------------------
///
/// class PropertySym
///
/// Used for field symbols. Property syms for a given objects are linked
/// together.
///
///---------------------------------------------------------------------------
enum PropertyKind : BYTE
{
PropertyKindData,
PropertyKindSlots,
PropertyKindLocalSlots,
PropertyKindSlotArray,
PropertyKindWriteGuard
};
class PropertySym: public Sym
{
friend class Sym;
public:
static PropertySym * New(SymID stackSymID, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func);
static PropertySym * New(StackSym *stackSym, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func);
static PropertySym * Find(SymID stackSymID, int32 propertyId, Func *func);
static PropertySym * FindOrCreate(SymID stackSymID, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func);
Func *GetFunc() { return m_func; }
bool HasPropertyIdIndex() { return m_propertyIdIndex != -1; }
int32 GetPropertyIdIndex() { return m_propertyIdIndex; }
bool HasInlineCacheIndex() { return m_inlineCacheIndex != -1; }
int32 GetInlineCacheIndex() { return m_inlineCacheIndex; }
bool HasObjectTypeSym() const { return this->m_stackSym->HasObjectTypeSym(); }
bool HasWriteGuardSym() const { return this->m_writeGuardSym != nullptr; }
StackSym * GetObjectTypeSym() const { return this->m_stackSym->GetObjectTypeSym(); }
public:
PropertyKind m_fieldKind;
int32 m_propertyId;
StackSym * m_stackSym;
BVSparse<JitArenaAllocator> *m_propertyEquivSet; // Bit vector of all propertySyms with same propertyId
PropertySym * m_nextInStackSymList;
PropertySym * m_writeGuardSym;
Func * m_func;
Func * m_loadInlineCacheFunc;
uint m_loadInlineCacheIndex;
private:
uint32 m_propertyIdIndex;
uint m_inlineCacheIndex;
};