blob: 2ae82e870dd189216228a709d9a5a02b9148d9b8 [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// 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.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"
const Js::ArgSlot StackSym::InvalidSlot = (Js::ArgSlot)-1;
///----------------------------------------------------------------------------
///
/// StackSym::New
///
/// Creates a StackSym
///
///----------------------------------------------------------------------------
StackSym *
StackSym::New(SymID id, IRType type, Js::RegSlot byteCodeRegSlot, Func *func)
{
StackSym * stackSym;
if (byteCodeRegSlot != Js::Constants::NoRegister)
{
stackSym = AnewZ(func->m_alloc, ByteCodeStackSym, byteCodeRegSlot, func);
stackSym->m_hasByteCodeRegSlot = true;
}
else
{
stackSym = AnewZ(func->m_alloc, StackSym);
}
stackSym->m_id = id;
stackSym->m_kind = SymKindStack;
// Assume SingleDef until proven false.
stackSym->m_isConst = false;
stackSym->m_isIntConst = false;
stackSym->m_isTaggableIntConst = false;
stackSym->m_isSingleDef = true;
stackSym->m_isEncodedConstant = false;
stackSym->m_isFltConst = false;
stackSym->m_isInt64Const = false;
stackSym->m_isStrConst = false;
stackSym->m_isStrEmpty = false;
stackSym->m_allocated = false;
stackSym->m_isTypeSpec = false;
stackSym->m_isArgSlotSym = false;
stackSym->m_isArgSlotRegSym = false;
stackSym->m_isParamSym = false;
stackSym->m_isImplicitParamSym = false;
stackSym->m_isBailOutReferenced = false;
stackSym->m_isArgCaptured = false;
stackSym->m_requiresBailOnNotNumber = false;
stackSym->m_isCatchObjectSym = false;
stackSym->m_isClosureSym = false;
stackSym->m_builtInIndex = Js::BuiltinFunction::None;
stackSym->m_slotNum = StackSym::InvalidSlot;
stackSym->m_type = type;
stackSym->m_equivNext = stackSym;
stackSym->m_objectInfo = nullptr;
AssertMsg(func->m_symTable->Find(id) == nullptr, "Trying to add new symbol which already exists.");
func->m_symTable->Add(stackSym);
return stackSym;
}
ObjectSymInfo *
ObjectSymInfo::New(Func * func)
{
ObjectSymInfo * objSymInfo = JitAnewZ(func->m_alloc, ObjectSymInfo);
return objSymInfo;
}
ObjectSymInfo *
ObjectSymInfo::New(StackSym * typeSym, Func * func)
{
ObjectSymInfo * objSymInfo = ObjectSymInfo::New(func);
objSymInfo->m_typeSym = typeSym;
return objSymInfo;
}
ObjectSymInfo *
StackSym::EnsureObjectInfo(Func * func)
{
if (this->m_objectInfo == nullptr)
{
this->m_objectInfo = ObjectSymInfo::New(func);
}
return this->m_objectInfo;
}
///----------------------------------------------------------------------------
///
/// StackSym::New
///
/// Creates a StackSym
///
///----------------------------------------------------------------------------
StackSym *
StackSym::New(Func *func)
{
return StackSym::New(func->m_symTable->NewID(), TyVar, Js::Constants::NoRegister, func);
}
StackSym *
StackSym::New(IRType type, Func *func)
{
return StackSym::New(func->m_symTable->NewID(), type, Js::Constants::NoRegister, func);
}
StackSym *
StackSym::NewImplicitParamSym(Js::ArgSlot paramSlotNum, Func * func)
{
return func->m_symTable->GetImplicitParam(paramSlotNum);
}
StackSym *
StackSym::NewParamSlotSym(Js::ArgSlot paramSlotNum, Func * func)
{
return NewParamSlotSym(paramSlotNum, func, TyVar);
}
StackSym *
StackSym::NewParamSlotSym(Js::ArgSlot paramSlotNum, Func * func, IRType type)
{
StackSym * stackSym = StackSym::New(type, func);
stackSym->m_isParamSym = true;
stackSym->m_slotNum = paramSlotNum;
return stackSym;
}
// Represents a temporary sym which is a copy of an arg slot sym.
StackSym *
StackSym::NewArgSlotRegSym(Js::ArgSlot argSlotNum, Func * func, IRType type /* = TyVar */)
{
StackSym * stackSym = StackSym::New(type, func);
stackSym->m_isArgSlotRegSym = true;
stackSym->m_slotNum = argSlotNum;
#if defined(_M_X64)
stackSym->m_argPosition = 0;
#endif
return stackSym;
}
StackSym *
StackSym::NewArgSlotSym(Js::ArgSlot argSlotNum, Func * func, IRType type /* = TyVar */)
{
StackSym * stackSym = StackSym::New(type, func);
stackSym->m_isArgSlotSym = true;
stackSym->m_slotNum = argSlotNum;
#if defined(_M_X64)
stackSym->m_argPosition = 0;
#endif
return stackSym;
}
bool
StackSym::IsTempReg(Func *const func) const
{
return !HasByteCodeRegSlot() || GetByteCodeRegSlot() >= func->GetJITFunctionBody()->GetFirstTmpReg();
}
#if DBG
void
StackSym::VerifyConstFlags() const
{
if (m_isConst)
{
Assert(this->m_isSingleDef);
Assert(this->m_instrDef);
if (m_isIntConst)
{
Assert(!m_isFltConst);
}
else
{
Assert(!m_isTaggableIntConst);
}
}
else
{
Assert(!m_isIntConst);
Assert(!m_isTaggableIntConst);
Assert(!m_isFltConst);
}
}
#endif
bool
StackSym::IsConst() const
{
#if DBG
VerifyConstFlags();
#endif
return m_isConst;
}
bool
StackSym::IsIntConst() const
{
#if DBG
VerifyConstFlags();
#endif
return m_isIntConst;
}
bool
StackSym::IsInt64Const() const
{
#if DBG
VerifyConstFlags();
#endif
return m_isInt64Const;
}
bool
StackSym::IsTaggableIntConst() const
{
#if DBG
VerifyConstFlags();
#endif
return m_isTaggableIntConst;
}
bool
StackSym::IsFloatConst() const
{
#if DBG
VerifyConstFlags();
#endif
return m_isFltConst;
}
bool
StackSym::IsSimd128Const() const
{
#if DBG
VerifyConstFlags();
#endif
return m_isSimd128Const;
}
void
StackSym::SetIsConst()
{
Assert(this->m_isSingleDef);
Assert(this->m_instrDef);
IR::Opnd * src = this->m_instrDef->GetSrc1();
Assert(src->IsImmediateOpnd() || src->IsFloatConstOpnd() || src->IsSimd128ConstOpnd());
if (src->IsIntConstOpnd())
{
Assert(this->m_instrDef->m_opcode == Js::OpCode::Ld_I4 || this->m_instrDef->m_opcode == Js::OpCode::LdC_A_I4 || LowererMD::IsAssign(this->m_instrDef));
this->SetIsIntConst(src->AsIntConstOpnd()->GetValue());
}
else if (src->IsInt64ConstOpnd())
{
Assert(this->m_instrDef->m_opcode == Js::OpCode::Ld_I4 || LowererMD::IsAssign(this->m_instrDef));
this->SetIsInt64Const();
}
else if (src->IsFloatConstOpnd())
{
Assert(this->m_instrDef->m_opcode == Js::OpCode::LdC_A_R8);
this->SetIsFloatConst();
}
else if (src->IsSimd128ConstOpnd()){
Assert(this->m_instrDef->m_opcode == Js::OpCode::Simd128_LdC);
this->SetIsSimd128Const();
}
else
{
Assert(this->m_instrDef->m_opcode == Js::OpCode::Ld_A || LowererMD::IsAssign(this->m_instrDef));
Assert(src->IsAddrOpnd());
IR::AddrOpnd * addrOpnd = src->AsAddrOpnd();
this->m_isConst = true;
if (addrOpnd->IsVar())
{
Js::Var var = addrOpnd->m_address;
if (Js::TaggedInt::Is(var))
{
this->m_isIntConst = true;
this->m_isTaggableIntConst = true;
}
else if (var)
{
#if !FLOATVAR
if (JITManager::GetJITManager()->IsOOPJITEnabled())
{
if (addrOpnd->m_localAddress && Js::JavascriptNumber::Is(addrOpnd->m_localAddress) && Js::JavascriptNumber::IsInt32_NoChecks(addrOpnd->m_localAddress))
{
this->m_isIntConst = true;
}
}
else
#endif
{
if (Js::JavascriptNumber::Is(var) && Js::JavascriptNumber::IsInt32_NoChecks(var))
{
this->m_isIntConst = true;
}
}
}
}
}
}
void
StackSym::SetIsIntConst(IntConstType value)
{
Assert(this->m_isSingleDef);
Assert(this->m_instrDef);
this->m_isConst = true;
this->m_isIntConst = true;
this->m_isInt64Const = false;
this->m_isTaggableIntConst = !Js::TaggedInt::IsOverflow(value);
this->m_isFltConst = false;
this->m_isStrConst = false;
}
void StackSym::SetIsInt64Const()
{
Assert(this->m_isSingleDef);
Assert(this->m_instrDef);
this->m_isConst = true;
this->m_isInt64Const = true;
this->m_isIntConst = false;
this->m_isTaggableIntConst = false;
this->m_isFltConst = false;
this->m_isStrConst = false;
}
void
StackSym::SetIsFloatConst()
{
Assert(this->m_isSingleDef);
Assert(this->m_instrDef);
this->m_isConst = true;
this->m_isIntConst = false;
this->m_isTaggableIntConst = false;
this->m_isFltConst = true;
this->m_isStrConst = false;
}
void
StackSym::SetIsSimd128Const()
{
Assert(this->m_isSingleDef);
Assert(this->m_instrDef);
this->m_isConst = true;
this->m_isIntConst = false;
this->m_isTaggableIntConst = false;
this->m_isFltConst = false;
this->m_isSimd128Const = true;
this->m_isStrConst = false;
this->m_isNotNumber = true;
}
void
StackSym::SetIsStrConst()
{
Assert(this->m_isSingleDef);
Assert(this->m_instrDef);
this->m_isConst = true;
this->m_isIntConst = false;
this->m_isTaggableIntConst = false;
this->m_isFltConst = false;
this->m_isSimd128Const = false;
this->m_isStrConst = true;
this->m_isNotNumber = true;
}
bool
StackSym::GetIsStrConst()
{
return this->m_isStrConst;
}
Js::RegSlot
StackSym::GetByteCodeRegSlot() const
{
Assert(HasByteCodeRegSlot());
return ((ByteCodeStackSym *)this)->byteCodeRegSlot;
}
Func *
StackSym::GetByteCodeFunc() const
{
Assert(HasByteCodeRegSlot());
return ((ByteCodeStackSym *)this)->byteCodeFunc;
}
void
StackSym::IncrementArgSlotNum()
{
Assert(IsArgSlotSym());
m_slotNum++;
}
void
StackSym::DecrementArgSlotNum()
{
Assert(IsArgSlotSym());
m_slotNum--;
}
void
StackSym::FixupStackOffset(Func * currentFunc)
{
int offsetFixup = 0;
Func * parentFunc = currentFunc->GetParentFunc();
while (parentFunc)
{
if (parentFunc->callSiteToArgumentsOffsetFixupMap)
{
parentFunc->callSiteToArgumentsOffsetFixupMap->TryGetValue(currentFunc->callSiteIdInParentFunc, &offsetFixup);
this->m_offset += offsetFixup * MachPtr;
}
parentFunc = parentFunc->GetParentFunc();
currentFunc = currentFunc->GetParentFunc();
offsetFixup = 0;
}
}
///----------------------------------------------------------------------------
///
/// StackSym::FindOrCreate
///
/// Look for a StackSym with the given ID. If not found, create it.
///
///----------------------------------------------------------------------------
StackSym *
StackSym::FindOrCreate(SymID id, Js::RegSlot byteCodeRegSlot, Func *func, IRType type)
{
StackSym * stackSym;
stackSym = func->m_symTable->FindStackSym(id);
if (stackSym)
{
Assert(!stackSym->HasByteCodeRegSlot() ||
(stackSym->GetByteCodeRegSlot() == byteCodeRegSlot && stackSym->GetByteCodeFunc() == func));
Assert(stackSym->GetType() == type);
return stackSym;
}
return StackSym::New(id, type, byteCodeRegSlot, func);
}
StackSym *
StackSym::CloneDef(Func *func)
{
Cloner * cloner = func->GetCloner();
StackSym * newSym = nullptr;
AssertMsg(cloner, "Use Func::BeginClone to initialize cloner");
if (!this->m_isSingleDef)
{
return this;
}
switch (this->m_instrDef->m_opcode)
{
// Note: we were cloning single-def load constant instr's, but couldn't guarantee
// that we were cloning all the uses.
case Js::OpCode::ArgOut_A:
case Js::OpCode::ArgOut_A_Dynamic:
case Js::OpCode::ArgOut_A_InlineBuiltIn:
case Js::OpCode::ArgOut_A_SpreadArg:
case Js::OpCode::StartCall:
case Js::OpCode::InlineeMetaArg:
// Go ahead and clone: we need a single-def sym.
// Arg/StartCall trees must be single-def.
// Uses of int-const syms may need to find their defining instr's.
break;
default:
return this;
}
if (cloner->symMap == nullptr)
{
cloner->symMap = HashTable<StackSym*>::New(cloner->alloc, 7);
}
else
{
StackSym **entry = cloner->symMap->Get(m_id);
if (entry)
{
newSym = *entry;
}
}
if (newSym == nullptr)
{
// NOTE: We don't care about the bytecode register information for cloned symbol
// As those are the float sym that we will convert back to Var before jumping back
// to the slow path's bailout. The bailout can just track the original symbol.
newSym = StackSym::New(func);
newSym->m_isConst = m_isConst;
newSym->m_isIntConst = m_isIntConst;
newSym->m_isTaggableIntConst = m_isTaggableIntConst;
newSym->m_isArgSlotSym = m_isArgSlotSym;
newSym->m_isArgSlotRegSym = m_isArgSlotRegSym;
newSym->m_isParamSym = m_isParamSym;
newSym->m_isImplicitParamSym = m_isImplicitParamSym;
newSym->m_isArgCaptured = m_isArgCaptured;
newSym->m_isBailOutReferenced = m_isBailOutReferenced;
newSym->m_slotNum = m_slotNum;
#if defined(_M_X64)
newSym->m_argPosition = m_argPosition;
#endif
newSym->m_offset = m_offset;
newSym->m_allocated = m_allocated;
newSym->m_isInlinedArgSlot = m_isInlinedArgSlot;
newSym->m_isCatchObjectSym = m_isCatchObjectSym;
newSym->m_isClosureSym = m_isClosureSym;
newSym->m_type = m_type;
newSym->CopySymAttrs(this);
// NOTE: It is not clear what the right thing to do is here...
newSym->m_equivNext = newSym;
cloner->symMap->FindOrInsert(newSym, m_id);
}
return newSym;
}
StackSym *
StackSym::CloneUse(Func *func)
{
Cloner * cloner = func->GetCloner();
StackSym ** newSym;
AssertMsg(cloner, "Use Func::BeginClone to initialize cloner");
if (cloner->symMap == nullptr)
{
return this;
}
newSym = cloner->symMap->Get(m_id);
if (newSym == nullptr)
{
return this;
}
return *newSym;
}
void
StackSym::CopySymAttrs(StackSym *symSrc)
{
m_isNotNumber = symSrc->m_isNotNumber;
m_isSafeThis = symSrc->m_isSafeThis;
m_builtInIndex = symSrc->m_builtInIndex;
}
// StackSym::GetIntConstValue
int32
StackSym::GetIntConstValue() const
{
Assert(this->IsIntConst());
IR::Instr *defInstr = this->m_instrDef;
IR::Opnd *src1 = defInstr->GetSrc1();
if (src1->IsIntConstOpnd())
{
Assert(defInstr->m_opcode == Js::OpCode::Ld_I4 || defInstr->m_opcode == Js::OpCode::LdC_A_I4 || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn || LowererMD::IsAssign(defInstr));
return src1->AsIntConstOpnd()->AsInt32();
}
if (src1->IsAddrOpnd())
{
Assert(defInstr->m_opcode == Js::OpCode::Ld_A || LowererMD::IsAssign(defInstr) || defInstr->m_opcode == Js::OpCode::ArgOut_A || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn);
IR::AddrOpnd *addr = src1->AsAddrOpnd();
Assert(addr->IsVar());
Js::Var var = src1->AsAddrOpnd()->m_address;
if (Js::TaggedInt::Is(var))
{
return Js::TaggedInt::ToInt32(var);
}
int32 value = 0xCCCCCCCC;
const bool isInt32 = Js::JavascriptNumber::TryGetInt32Value(Js::JavascriptNumber::GetValue(var), &value);
Assert(isInt32);
return value;
}
Assert(src1->IsRegOpnd());
return src1->AsRegOpnd()->m_sym->GetIntConstValue();
}
Js::Var StackSym::GetFloatConstValueAsVar_PostGlobOpt() const
{
Assert(this->IsConst());
IR::Instr *defInstr = this->m_instrDef;
IR::Opnd *src1 = defInstr->GetSrc1();
StackSym * stackSym = nullptr;
if (src1->IsRegOpnd())
{
stackSym = src1->AsRegOpnd()->m_sym;
Assert(!stackSym->m_isEncodedConstant);
if (stackSym->m_isSingleDef)
{
//In ARM constant load is always legalized. Try to get the constant from src def
defInstr = stackSym->m_instrDef;
src1 = defInstr->GetSrc1();
}
}
Assert(this->IsFloatConst() || (stackSym && stackSym->IsFloatConst()));
IR::AddrOpnd *addrOpnd;
if (src1->IsAddrOpnd())
{
Assert(defInstr->m_opcode == Js::OpCode::Ld_A);
addrOpnd = src1->AsAddrOpnd();
}
else
{
Assert(src1->IsFloatConstOpnd());
Assert(defInstr->m_opcode == Js::OpCode::LdC_A_R8);
addrOpnd = src1->AsFloatConstOpnd()->GetAddrOpnd(defInstr->m_func);
// This is just to prevent creating multiple numbers when the sym is used multiple times. We can only do this
// post-GlobOpt, as otherwise it violates some invariants assumed in GlobOpt.
defInstr->ReplaceSrc1(addrOpnd);
defInstr->m_opcode = Js::OpCode::Ld_A;
}
const Js::Var address = addrOpnd->m_address;
Assert(Js::JavascriptNumber::Is(addrOpnd->m_localAddress? addrOpnd->m_localAddress: addrOpnd->m_address));
return address;
}
void *StackSym::GetConstAddress(bool useLocal /*= false*/) const
{
Assert(this->IsConst());
IR::Instr *defInstr = this->m_instrDef;
IR::Opnd *src1 = defInstr->GetSrc1();
StackSym * stackSym = nullptr;
if (src1->IsRegOpnd())
{
stackSym = src1->AsRegOpnd()->m_sym;
Assert(!stackSym->m_isEncodedConstant);
if (stackSym->m_isSingleDef)
{
//In ARM constant load is always legalized. Try to get the constant from src def
defInstr = stackSym->m_instrDef;
src1 = defInstr->GetSrc1();
}
}
Assert(src1->IsAddrOpnd());
Assert(defInstr->m_opcode == Js::OpCode::Ld_A || defInstr->m_opcode == Js::OpCode::LdStr || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn || LowererMD::IsAssign(defInstr));
return useLocal ? src1->AsAddrOpnd()->m_localAddress : src1->AsAddrOpnd()->m_address;
}
intptr_t StackSym::GetLiteralConstValue_PostGlobOpt() const
{
Assert(this->IsConst());
IR::Instr *defInstr = this->m_instrDef;
IR::Opnd *src1 = defInstr->GetSrc1();
StackSym * stackSym = nullptr;
if (src1->IsRegOpnd())
{
stackSym = src1->AsRegOpnd()->m_sym;
if (stackSym->m_isEncodedConstant)
{
Assert(!stackSym->m_isSingleDef);
Assert(LowererMD::IsAssign(defInstr) || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn);
return stackSym->constantValue;
}
if (stackSym->m_isSingleDef)
{
//In ARM constant load is always legalized. Try to get the constant from src def
defInstr = stackSym->m_instrDef;
src1 = defInstr->GetSrc1();
}
}
if (src1->IsAddrOpnd())
{
Assert(defInstr->m_opcode == Js::OpCode::Ld_A || defInstr->m_opcode == Js::OpCode::LdStr || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn || LowererMD::IsAssign(defInstr));
return reinterpret_cast<intptr_t>(src1->AsAddrOpnd()->m_address);
}
if (src1->IsIntConstOpnd())
{
Assert(this->IsIntConst() || (stackSym && stackSym->IsIntConst()));
if (defInstr->m_opcode == Js::OpCode::LdC_A_I4)
{
IR::AddrOpnd *const addrOpnd = IR::AddrOpnd::NewFromNumber(src1->AsIntConstOpnd()->GetValue(), defInstr->m_func);
const Js::Var address = addrOpnd->m_address;
// This is just to prevent creating multiple numbers when the sym is used multiple times. We can only do this
// post-GlobOpt, as otherwise it violates some invariants assumed in GlobOpt.
defInstr->ReplaceSrc1(addrOpnd);
defInstr->m_opcode = Js::OpCode::Ld_A;
return reinterpret_cast<intptr_t>(address);
}
Assert(defInstr->m_opcode == Js::OpCode::Ld_I4 || LowererMD::IsAssign(defInstr) || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn);
return src1->AsIntConstOpnd()->GetValue();
}
if (src1->IsFloatConstOpnd())
{
Assert(this->IsFloatConst() || (stackSym && stackSym->IsFloatConst()));
Assert(defInstr->m_opcode == Js::OpCode::LdC_A_R8);
IR::AddrOpnd *const addrOpnd = src1->AsFloatConstOpnd()->GetAddrOpnd(defInstr->m_func);
const Js::Var address = addrOpnd->m_address;
// This is just to prevent creating multiple numbers when the sym is used multiple times. We can only do this
// post-GlobOpt, as otherwise it violates some invariants assumed in GlobOpt.
defInstr->ReplaceSrc1(addrOpnd);
defInstr->m_opcode = Js::OpCode::Ld_A;
return reinterpret_cast<intptr_t>(address);
}
AssertMsg(UNREACHED, "Unknown const value");
return 0;
}
IR::Opnd *
StackSym::GetConstOpnd() const
{
Assert(IsConst());
IR::Instr *defInstr = this->m_instrDef;
IR::Opnd *src1 = defInstr->GetSrc1();
if (!src1)
{
#if defined(_M_IX86) || defined(_M_X64)
Assert(defInstr->m_opcode == Js::OpCode::MOVSD_ZERO);
#else
Assert(UNREACHED);
#endif
}
else if (src1->IsIntConstOpnd())
{
Assert(this->IsIntConst());
if (defInstr->m_opcode == Js::OpCode::LdC_A_I4)
{
src1 = IR::AddrOpnd::NewFromNumber(src1->AsIntConstOpnd()->GetValue(), defInstr->m_func);
defInstr->ReplaceSrc1(src1);
defInstr->m_opcode = Js::OpCode::Ld_A;
}
else
{
Assert(defInstr->m_opcode == Js::OpCode::Ld_I4 || LowererMD::IsAssign(defInstr) || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn);
}
}
else if (src1->IsInt64ConstOpnd())
{
Assert(this->m_isInt64Const);
Assert(defInstr->m_opcode == Js::OpCode::Ld_I4 || LowererMD::IsAssign(defInstr));
}
else if (src1->IsFloatConstOpnd())
{
Assert(this->IsFloatConst());
Assert(defInstr->m_opcode == Js::OpCode::LdC_A_R8);
src1 = src1->AsFloatConstOpnd()->GetAddrOpnd(defInstr->m_func);
defInstr->ReplaceSrc1(src1);
defInstr->m_opcode = Js::OpCode::Ld_A;
}
else if (src1->IsFloat32ConstOpnd())
{
Assert(this->IsFloatConst());
Assert(defInstr->m_opcode == Js::OpCode::LdC_F8_R8 || LowererMD::IsAssign(defInstr));
}
else if (src1->IsAddrOpnd())
{
Assert(defInstr->m_opcode == Js::OpCode::Ld_A || LowererMD::IsAssign(defInstr) || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn);
}
else if (src1->IsMemRefOpnd())
{
Assert(this->IsFloatConst() || this->IsSimd128Const());
}
else
{
AssertMsg(UNREACHED, "Invalid const value");
}
return src1;
}
BailoutConstantValue StackSym::GetConstValueForBailout() const
{
Assert(this->IsConst());
IR::Instr *defInstr = this->m_instrDef;
IR::Opnd *src1 = defInstr->GetSrc1();
return src1->GetConstValue();
}
StackSym *
StackSym::GetFloat64EquivSym(Func *func)
{
return this->GetTypeEquivSym(TyFloat64, func);
}
StackSym *
StackSym::GetInt32EquivSym(Func *func)
{
return this->GetTypeEquivSym(TyInt32, func);
}
StackSym *
StackSym::GetVarEquivSym(Func *func)
{
return this->GetTypeEquivSym(TyVar, func);
}
StackSym *
StackSym::GetVarEquivSym_NoCreate()
{
return this->GetTypeEquivSym_NoCreate(TyVar);
}
StackSym const *
StackSym::GetVarEquivSym_NoCreate() const
{
return this->GetTypeEquivSym_NoCreate(TyVar);
}
StackSym *
StackSym::GetTypeEquivSym(IRType type, Func *func)
{
StackSym *sym = this->GetTypeEquivSym_NoCreate(type);
if (sym != nullptr)
{
return sym;
}
// Don't allocate if func wasn't passed in.
if (func == nullptr)
{
return nullptr;
}
if (this->HasByteCodeRegSlot())
{
sym = StackSym::New(func->m_symTable->NewID(), type,
this->GetByteCodeRegSlot(), this->GetByteCodeFunc());
}
else
{
sym = StackSym::New(type, func);
}
sym->m_equivNext = this->m_equivNext;
this->m_equivNext = sym;
if (type != TyVar)
{
sym->m_isTypeSpec = true;
}
return sym;
}
StackSym *
StackSym::GetTypeEquivSym_NoCreate(IRType type)
{
return const_cast<StackSym*>(static_cast<const StackSym*>(this)->GetTypeEquivSym_NoCreate(type));
}
StackSym const *
StackSym::GetTypeEquivSym_NoCreate(IRType type) const
{
Assert(this->m_type != type);
StackSym *sym = this->m_equivNext;
int i = 1;
while (sym != this)
{
Assert(i <= 5); // circular of at most 6 syms : var, f64, i32, simd128I4, simd128F4, simd128D2
if (sym->m_type == type)
{
return sym;
}
sym = sym->m_equivNext;
i++;
}
return nullptr;
}
StackSym *StackSym::GetVarEquivStackSym_NoCreate(Sym *const sym)
{
return const_cast<StackSym*>(GetVarEquivStackSym_NoCreate((Sym const * const)sym));
}
StackSym const *StackSym::GetVarEquivStackSym_NoCreate(Sym const * const sym)
{
Assert(sym);
if(!sym->IsStackSym())
{
return nullptr;
}
StackSym const *stackSym = sym->AsStackSym();
if(stackSym->IsTypeSpec())
{
stackSym = stackSym->GetVarEquivSym_NoCreate();
}
return stackSym;
}
StackSym *StackSym::EnsureAuxSlotPtrSym(Func * func)
{
Assert(HasObjectInfo());
StackSym * auxSlotPtrSym = GetObjectInfo()->m_auxSlotPtrSym;
if (auxSlotPtrSym == nullptr)
{
auxSlotPtrSym = GetObjectInfo()->m_auxSlotPtrSym = StackSym::New(func);
}
return auxSlotPtrSym;
}
///----------------------------------------------------------------------------
///
/// PropertySym::New
///
/// Creates a PropertySym
///
///----------------------------------------------------------------------------
PropertySym *
PropertySym::New(SymID stackSymID, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func)
{
StackSym * stackSym;
stackSym = func->m_symTable->FindStackSym(stackSymID);
AssertMsg(stackSym != nullptr, "Adding propertySym to non-existing stackSym... Can this happen??");
return PropertySym::New(stackSym, propertyId, propertyIdIndex, inlineCacheIndex, fieldKind, func);
}
PropertySym *
PropertySym::New(StackSym *stackSym, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func)
{
PropertySym * propertySym;
propertySym = JitAnewZ(func->m_alloc, PropertySym);
propertySym->m_func = func;
propertySym->m_id = func->m_symTable->NewID();
propertySym->m_kind = SymKindProperty;
propertySym->m_propertyId = propertyId;
propertyIdIndex = (uint)-1;
inlineCacheIndex = (uint)-1;
propertySym->m_propertyIdIndex = propertyIdIndex;
propertySym->m_inlineCacheIndex = inlineCacheIndex;
Assert(propertyIdIndex == (uint)-1 || inlineCacheIndex == (uint)-1);
propertySym->m_loadInlineCacheIndex = (uint)-1;
propertySym->m_loadInlineCacheFunc = nullptr;
propertySym->m_fieldKind = fieldKind;
propertySym->m_stackSym = stackSym;
propertySym->m_propertyEquivSet = nullptr;
// Add to list
func->m_symTable->Add(propertySym);
// Keep track of all the property we use from this sym so we can invalidate
// the value in glob opt
ObjectSymInfo * objectSymInfo = stackSym->EnsureObjectInfo(func);
propertySym->m_nextInStackSymList = objectSymInfo->m_propertySymList;
objectSymInfo->m_propertySymList = propertySym;
return propertySym;
}
///----------------------------------------------------------------------------
///
/// PropertySym::FindOrCreate
///
/// Look for a PropertySym with the given ID/propertyId.
///
///----------------------------------------------------------------------------
PropertySym *
PropertySym::Find(SymID stackSymID, int32 propertyId, Func *func)
{
return func->m_symTable->FindPropertySym(stackSymID, propertyId);
}
///----------------------------------------------------------------------------
///
/// PropertySym::FindOrCreate
///
/// Look for a PropertySym with the given ID/propertyId. If not found,
/// create it.
///
///----------------------------------------------------------------------------
PropertySym *
PropertySym::FindOrCreate(SymID stackSymID, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func)
{
PropertySym * propertySym;
propertySym = Find(stackSymID, propertyId, func);
if (propertySym)
{
return propertySym;
}
return PropertySym::New(stackSymID, propertyId, propertyIdIndex, inlineCacheIndex, fieldKind, func);
}
#if DBG_DUMP || defined(ENABLE_IR_VIEWER)
///----------------------------------------------------------------------------
///
/// Sym::Dump
///
///----------------------------------------------------------------------------
void
Sym::Dump(IRDumpFlags flags, const ValueType valueType) const
{
bool const AsmDumpMode = flags & IRDumpFlags_AsmDumpMode;
bool const SimpleForm = !!(flags & IRDumpFlags_SimpleForm);
if (AsmDumpMode)
{
if (this->IsStackSym() && this->AsStackSym()->IsArgSlotSym())
{
Output::Print(_u("arg "));
}
else if (this->IsStackSym() && this->AsStackSym()->IsParamSlotSym())
{
Output::Print(_u("param "));
}
}
else if (this->IsStackSym())
{
StackSym const *stackSym = this->AsStackSym();
if (stackSym->IsArgSlotSym())
{
if (stackSym->m_isInlinedArgSlot)
{
Output::Print(_u("iarg%d"), stackSym->GetArgSlotNum());
}
else
{
Output::Print(_u("arg%d"), stackSym->GetArgSlotNum());
}
Output::Print(_u("(s%d)"), m_id);
}
else if (stackSym->IsParamSlotSym())
{
if (stackSym->IsImplicitParamSym())
{
switch (stackSym->GetParamSlotNum())
{
case 1:
Output::Print(_u("callInfo"));
break;
case 2:
Output::Print(_u("funcInfo"));
break;
case 3:
Output::Print(_u("genObj"));
break;
case 4:
Output::Print(_u("genFrame"));
break;
default:
Output::Print(_u("implPrm%d"), stackSym->GetParamSlotNum());
}
}
else
{
Output::Print(_u("prm%d"), stackSym->GetParamSlotNum());
}
}
else
{
Output::Print(_u("s%d"), m_id);
if (Js::Configuration::Global.flags.Debug && stackSym->HasByteCodeRegSlot())
{
if (!JITManager::GetJITManager()->IsOOPJITEnabled())
{
Js::FunctionBody* functionBody = (Js::FunctionBody*)stackSym->GetByteCodeFunc()->GetJITFunctionBody()->GetAddr();
if (functionBody->GetPropertyIdOnRegSlotsContainer())
{
if (functionBody->IsNonTempLocalVar(stackSym->GetByteCodeRegSlot()))
{
uint index = stackSym->GetByteCodeRegSlot() - stackSym->GetByteCodeFunc()->GetJITFunctionBody()->GetConstCount();
Js::PropertyId propertyId = functionBody->GetPropertyIdOnRegSlotsContainer()->propertyIdsForRegSlots[index];
Output::Print(_u("(%s)"), stackSym->GetByteCodeFunc()->GetInProcThreadContext()->GetPropertyRecord(propertyId)->GetBuffer());
}
}
}
}
if (stackSym->IsVar())
{
if (stackSym->HasObjectTypeSym() && !SimpleForm)
{
Output::Print(_u("<s%d>"), stackSym->GetObjectTypeSym()->m_id);
}
}
else
{
StackSym const *varSym = stackSym->GetVarEquivSym_NoCreate();
if (varSym)
{
Output::Print(_u("(s%d)"), varSym->m_id);
}
}
if (!SimpleForm)
{
if (stackSym->m_builtInIndex != Js::BuiltinFunction::None)
{
Output::Print(_u("[ffunc]"));
}
}
IR::Opnd::DumpValueType(valueType);
}
}
else if (this->IsPropertySym())
{
PropertySym const *propertySym = this->AsPropertySym();
if (!SimpleForm)
{
Output::Print(_u("s%d("), m_id);
}
switch (propertySym->m_fieldKind)
{
case PropertyKindData:
propertySym->m_stackSym->Dump(flags, valueType);
if (JITManager::GetJITManager()->IsOOPJITEnabled())
{
Output::Print(_u("->#%d"), propertySym->m_propertyId);
}
else
{
Js::PropertyRecord const* fieldName = propertySym->m_func->GetInProcThreadContext()->GetPropertyRecord(propertySym->m_propertyId);
Output::Print(_u("->%s"), fieldName->GetBuffer());
}
break;
case PropertyKindSlots:
case PropertyKindSlotArray:
propertySym->m_stackSym->Dump(flags, valueType);
Output::Print(_u("[%d]"), propertySym->m_propertyId);
break;
case PropertyKindLocalSlots:
propertySym->m_stackSym->Dump(flags, valueType);
Output::Print(_u("l[%d]"), propertySym->m_propertyId);
break;
default:
AssertMsg(0, "Unknown field kind");
break;
}
if (!SimpleForm)
{
Output::Print(_u(")"));
}
}
}
void
Sym::Dump(const ValueType valueType) const
{
this->Dump(IRDumpFlags_None, valueType);
}
void
Sym::DumpSimple() const
{
this->Dump(IRDumpFlags_SimpleForm);
}
#endif // DBG_DUMP