diff --git a/lib/Backend/Func.cpp b/lib/Backend/Func.cpp index c95c6bfed27..5716c074d02 100644 --- a/lib/Backend/Func.cpp +++ b/lib/Backend/Func.cpp @@ -126,6 +126,7 @@ Func::Func(JitArenaAllocator *alloc, JITTimeWorkItem * workItem, #endif , m_funcStartLabel(nullptr) , m_funcEndLabel(nullptr) + , bvStableSlotSyms(nullptr) #if DBG , hasCalledSetDoFastPaths(false) , allowRemoveBailOutArgInstr(false) @@ -172,6 +173,8 @@ Func::Func(JitArenaAllocator *alloc, JITTimeWorkItem * workItem, outputData->hasJittedStackClosure = false; outputData->localVarSlotsOffset = m_localVarSlotsOffset; outputData->localVarChangedOffset = m_hasLocalVarChangedOffset; + + this->bvStableSlotSyms = Anew(this->m_alloc, BVSparse, this->m_alloc); } if (this->IsInlined()) @@ -808,6 +811,21 @@ void Func::OnAddSym(Sym* sym) } } +void Func::AddStableSlotSym(PropertySym *sym) +{ + this->GetTopFunc()->bvStableSlotSyms->Set(sym->m_id); +} + +bool Func::IsStableSlotSym(PropertySym *sym) const +{ + return this->GetTopFunc()->bvStableSlotSyms->Test(sym->m_id); +} + +BVSparse *Func::GetStableSlotSyms() const +{ + return this->GetTopFunc()->bvStableSlotSyms; +} + /// /// Returns offset of the flag (1 byte) whether any local was changed (in debugger). /// If the function does not have any locals, returns -1. diff --git a/lib/Backend/Func.h b/lib/Backend/Func.h index a964d32044b..5ab65165334 100644 --- a/lib/Backend/Func.h +++ b/lib/Backend/Func.h @@ -442,6 +442,10 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece; StackSym *GetLocalFrameDisplaySym() const { return m_localFrameDisplaySym; } void SetLocalFrameDisplaySym(StackSym *sym) { m_localFrameDisplaySym = sym; } + void AddStableSlotSym(PropertySym *sym); + bool IsStableSlotSym(PropertySym *sym) const; + BVSparse *GetStableSlotSyms() const; + intptr_t GetJittedLoopIterationsSinceLastBailoutAddress() const; void EnsurePinnedTypeRefs(); void PinTypeRef(void* typeRef); @@ -724,6 +728,7 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece; BitVector m_regsUsed; StackSym * tempSymDouble; StackSym * tempSymBool; + BVSparse * bvStableSlotSyms; uint32 loopCount; uint32 unoptimizableArgumentsObjReference; Js::ProfileId callSiteIdInParentFunc; diff --git a/lib/Backend/GlobOptFields.cpp b/lib/Backend/GlobOptFields.cpp index 37a8c95dcb0..d2887daed98 100644 --- a/lib/Backend/GlobOptFields.cpp +++ b/lib/Backend/GlobOptFields.cpp @@ -242,7 +242,7 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse * void GlobOpt::KillAllFields(BVSparse * bv) { - bv->ClearAll(); + bv->And(func->GetStableSlotSyms()); if (this->IsLoopPrePass()) { for (Loop * loop = this->rootLoopPrePass; loop != nullptr; loop = loop->parent) @@ -447,9 +447,8 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse *bv, bo void GlobOpt::ProcessFieldKills(IR::Instr * instr) { - if (!this->DoFieldCopyProp() && !this->DoFieldRefOpts() && !DoCSE()) + if (this->currentBlock->globOptData.liveFields->IsEmpty()) { - Assert(this->currentBlock->globOptData.liveFields->IsEmpty()); return; } @@ -1808,7 +1807,7 @@ GlobOpt::CopyPropPropertySymObj(IR::SymOpnd *symOpnd, IR::Instr *instr) if (copySym != nullptr) { PropertySym *newProp = PropertySym::FindOrCreate( - copySym->m_id, propertySym->m_propertyId, propertySym->GetPropertyIdIndex(), propertySym->GetInlineCacheIndex(), propertySym->m_fieldKind, this->func); + copySym->m_id, propertySym->m_propertyId, propertySym->GetPropertyIdIndex(), propertySym->GetInlineCacheIndex(), propertySym->m_fieldKind, this->func, this->func->IsStableSlotSym(propertySym)); if (!this->IsLoopPrePass() || SafeToCopyPropInPrepass(objSym, copySym, val)) { diff --git a/lib/Backend/IRBuilder.cpp b/lib/Backend/IRBuilder.cpp index 099c05ff3ea..84b595ae4e1 100644 --- a/lib/Backend/IRBuilder.cpp +++ b/lib/Backend/IRBuilder.cpp @@ -1212,10 +1212,10 @@ IRBuilder::BuildIndirOpnd(IR::RegOpnd *baseReg, uint32 offset, const char16 *des #endif IR::SymOpnd * -IRBuilder::BuildFieldOpnd(Js::OpCode newOpcode, Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, PropertyKind propertyKind, uint inlineCacheIndex) +IRBuilder::BuildFieldOpnd(Js::OpCode newOpcode, Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, PropertyKind propertyKind, uint inlineCacheIndex, bool stableSlotSym) { AssertOrFailFast(inlineCacheIndex < m_func->GetJITFunctionBody()->GetInlineCacheCount() || inlineCacheIndex == Js::Constants::NoInlineCacheIndex); - PropertySym * propertySym = BuildFieldSym(reg, propertyId, propertyIdIndex, inlineCacheIndex, propertyKind); + PropertySym * propertySym = BuildFieldSym(reg, propertyId, propertyIdIndex, inlineCacheIndex, propertyKind, stableSlotSym); IR::SymOpnd * symOpnd; // If we plan to apply object type optimization to this instruction or if we intend to emit a fast path using an inline @@ -1243,14 +1243,14 @@ IRBuilder::BuildFieldOpnd(Js::OpCode newOpcode, Js::RegSlot reg, Js::PropertyId } PropertySym * -IRBuilder::BuildFieldSym(Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, uint inlineCacheIndex, PropertyKind propertyKind) +IRBuilder::BuildFieldSym(Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, uint inlineCacheIndex, PropertyKind propertyKind, bool stableSlotSym) { PropertySym * propertySym; SymID symId = this->BuildSrcStackSymID(reg); AssertMsg(m_func->m_symTable->FindStackSym(symId), "Tried to use an undefined stacksym?"); - propertySym = PropertySym::FindOrCreate(symId, propertyId, propertyIdIndex, inlineCacheIndex, propertyKind, m_func); + propertySym = PropertySym::FindOrCreate(symId, propertyId, propertyIdIndex, inlineCacheIndex, propertyKind, m_func, stableSlotSym); return propertySym; } @@ -3882,6 +3882,7 @@ IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r IR::Instr *instr; PropertySym *fieldSym; bool isLdSlotThatWasNotProfiled = false; + bool stableSlots = false; switch (newOpcode) { @@ -3916,13 +3917,18 @@ IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r } case Js::OpCode::LdEnvSlot: - case Js::OpCode::LdEnvObjSlot: case Js::OpCode::StEnvSlot: case Js::OpCode::StEnvSlotChkUndecl: + stableSlots = true; + goto SlotsCommon; + + case Js::OpCode::LdEnvObjSlot: case Js::OpCode::StEnvObjSlot: case Js::OpCode::StEnvObjSlotChkUndecl: + stableSlots = false; - fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, this->GetEnvReg(), slotId1, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray); +SlotsCommon: + fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, this->GetEnvReg(), slotId1, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray, (uint)-1, stableSlots); regOpnd = IR::RegOpnd::New(TyVar, m_func); instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func); this->AddInstr(instr, offset); diff --git a/lib/Backend/IRBuilder.h b/lib/Backend/IRBuilder.h index f1abb4bd18a..3b4ec82c025 100644 --- a/lib/Backend/IRBuilder.h +++ b/lib/Backend/IRBuilder.h @@ -211,8 +211,8 @@ class IRBuilder #if DBG_DUMP || defined(ENABLE_IR_VIEWER) IR::IndirOpnd * BuildIndirOpnd(IR::RegOpnd *baseReg, uint32 offset, const char16 *desc); #endif - IR::SymOpnd * BuildFieldOpnd(Js::OpCode newOpCode, Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, PropertyKind propertyKind, uint inlineCacheIndex = -1); - PropertySym * BuildFieldSym(Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, uint inlineCacheIndex, PropertyKind propertyKind); + IR::SymOpnd * BuildFieldOpnd(Js::OpCode newOpCode, Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, PropertyKind propertyKind, uint inlineCacheIndex = -1, bool stableSlotSym = false); + PropertySym * BuildFieldSym(Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, uint inlineCacheIndex, PropertyKind propertyKind, bool stableSlotSym = false); SymID BuildSrcStackSymID(Js::RegSlot regSlot); IR::RegOpnd * BuildDstOpnd(Js::RegSlot dstRegSlot, IRType type = TyVar, bool isCatchObjectSym = false); IR::RegOpnd * BuildSrcOpnd(Js::RegSlot srcRegSlot, IRType type = TyVar); diff --git a/lib/Backend/Sym.cpp b/lib/Backend/Sym.cpp index 2ae82e870dd..67da862ae0e 100644 --- a/lib/Backend/Sym.cpp +++ b/lib/Backend/Sym.cpp @@ -949,18 +949,18 @@ StackSym *StackSym::EnsureAuxSlotPtrSym(Func * func) ///---------------------------------------------------------------------------- PropertySym * -PropertySym::New(SymID stackSymID, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func) +PropertySym::New(SymID stackSymID, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func, bool stableSlotSym) { 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); + return PropertySym::New(stackSym, propertyId, propertyIdIndex, inlineCacheIndex, fieldKind, func, stableSlotSym); } PropertySym * -PropertySym::New(StackSym *stackSym, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func) +PropertySym::New(StackSym *stackSym, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func, bool stableSlotSym) { PropertySym * propertySym; @@ -989,6 +989,12 @@ PropertySym::New(StackSym *stackSym, int32 propertyId, uint32 propertyIdIndex, u func->m_symTable->Add(propertySym); + if (stableSlotSym) + { + Assert(fieldKind == PropertyKindSlots || fieldKind == PropertyKindLocalSlots || fieldKind == PropertyKindSlotArray); + func->AddStableSlotSym(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); @@ -1022,7 +1028,7 @@ PropertySym::Find(SymID stackSymID, int32 propertyId, Func *func) ///---------------------------------------------------------------------------- PropertySym * -PropertySym::FindOrCreate(SymID stackSymID, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func) +PropertySym::FindOrCreate(SymID stackSymID, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func, bool stableSlotSym) { PropertySym * propertySym; @@ -1030,10 +1036,11 @@ PropertySym::FindOrCreate(SymID stackSymID, int32 propertyId, uint32 propertyIdI if (propertySym) { + Assert(stableSlotSym == func->IsStableSlotSym(propertySym)); return propertySym; } - return PropertySym::New(stackSymID, propertyId, propertyIdIndex, inlineCacheIndex, fieldKind, func); + return PropertySym::New(stackSymID, propertyId, propertyIdIndex, inlineCacheIndex, fieldKind, func, stableSlotSym); } #if DBG_DUMP || defined(ENABLE_IR_VIEWER) diff --git a/lib/Backend/Sym.h b/lib/Backend/Sym.h index 5cd929ee024..e1dc1f43cf9 100644 --- a/lib/Backend/Sym.h +++ b/lib/Backend/Sym.h @@ -304,10 +304,10 @@ 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 * New(SymID stackSymID, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func, bool stableSlotSym = false); + static PropertySym * New(StackSym *stackSym, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func, bool stableSlotSym = false); static PropertySym * Find(SymID stackSymID, int32 propertyId, Func *func); - static PropertySym * FindOrCreate(SymID stackSymID, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func); + static PropertySym * FindOrCreate(SymID stackSymID, int32 propertyId, uint32 propertyIdIndex, uint inlineCacheIndex, PropertyKind fieldKind, Func *func, bool stableSlotSym = false); Func *GetFunc() { return m_func; } bool HasPropertyIdIndex() { return m_propertyIdIndex != -1; }