Skip to content

Commit eb584a0

Browse files
committed
Allow LdSlot to be optimized across calls if the variable being loaded is known not to be written to by any nested function.
1 parent 100d3ec commit eb584a0

16 files changed

+10993
-10812
lines changed

lib/Backend/GlobOpt.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,7 @@ BOOL GlobOpt::PRE::PreloadPRECandidate(Loop *loop, GlobHashBucket* candidate)
10441044

10451045
// T3.y
10461046
PropertySym *newPropSym = PropertySym::FindOrCreate(
1047-
objPtrCopyPropSym->m_id, propertySym->m_propertyId, propertySym->GetPropertyIdIndex(), propertySym->GetInlineCacheIndex(), propertySym->m_fieldKind, this->globOpt->func);
1047+
objPtrCopyPropSym->m_id, propertySym->m_propertyId, propertySym->GetPropertyIdIndex(), propertySym->GetInlineCacheIndex(), propertySym->m_fieldKind, this->globOpt->func, this->globOpt->func->IsStableSlotSym(propertySym));
10481048

10491049
if (!landingPad->globOptData.FindValue(newPropSym))
10501050
{

lib/Backend/IRBuilder.cpp

+71-16
Original file line numberDiff line numberDiff line change
@@ -3528,19 +3528,34 @@ IRBuilder::BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
35283528
StackSym * stackFuncPtrSym = nullptr;
35293529
SymID symID = m_func->GetJITFunctionBody()->GetLocalClosureReg();
35303530
bool isLdSlotThatWasNotProfiled = false;
3531+
bool stableSlot = false;
35313532
StackSym* closureSym = m_func->GetLocalClosureSym();
35323533

35333534
uint scopeSlotSize = this->IsParamScopeDone() ? m_func->GetJITFunctionBody()->GetScopeSlotArraySize() : m_func->GetJITFunctionBody()->GetParamScopeSlotArraySize();
35343535

35353536
switch (newOpcode)
35363537
{
3538+
case Js::OpCode::LdStableParamSlot:
3539+
stableSlot = true;
3540+
goto ParamSlotCommon;
3541+
35373542
case Js::OpCode::LdParamSlot:
3543+
stableSlot = false;
3544+
3545+
ParamSlotCommon:
35383546
scopeSlotSize = m_func->GetJITFunctionBody()->GetParamScopeSlotArraySize();
35393547
closureSym = m_func->GetParamClosureSym();
35403548
symID = m_func->GetJITFunctionBody()->GetParamClosureReg();
3541-
// Fall through
3549+
goto LocalSlotCommon;
3550+
3551+
case Js::OpCode::LdStableLocalSlot:
3552+
stableSlot = true;
3553+
goto LocalSlotCommon;
35423554

35433555
case Js::OpCode::LdLocalSlot:
3556+
stableSlot = false;
3557+
3558+
LocalSlotCommon:
35443559
if (!PHASE_OFF(Js::ClosureRangeCheckPhase, m_func))
35453560
{
35463561
if ((uint32)slotId >= scopeSlotSize + Js::ScopeSlots::FirstSlotIndex)
@@ -3580,7 +3595,7 @@ IRBuilder::BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
35803595
this->EnsureLoopBodyLoadSlot(symID);
35813596
}
35823597

3583-
fieldSym = PropertySym::FindOrCreate(symID, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
3598+
fieldSym = PropertySym::FindOrCreate(symID, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func, stableSlot);
35843599
fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
35853600
regOpnd = this->BuildDstOpnd(regSlot);
35863601
instr = nullptr;
@@ -3637,16 +3652,32 @@ IRBuilder::BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
36373652
this->AddInstr(instr, offset);
36383653
break;
36393654

3655+
case Js::OpCode::StStableParamSlot:
3656+
case Js::OpCode::StStableParamSlotChkUndecl:
3657+
stableSlot = true;
3658+
goto StParamSlotCommon;
3659+
36403660
case Js::OpCode::StParamSlot:
36413661
case Js::OpCode::StParamSlotChkUndecl:
3662+
stableSlot = false;
3663+
3664+
StParamSlotCommon:
36423665
scopeSlotSize = m_func->GetJITFunctionBody()->GetParamScopeSlotArraySize();
36433666
closureSym = m_func->GetParamClosureSym();
36443667
symID = m_func->GetJITFunctionBody()->GetParamClosureReg();
3645-
newOpcode = newOpcode == Js::OpCode::StParamSlot ? Js::OpCode::StLocalSlot : Js::OpCode::StLocalSlotChkUndecl;
3646-
// Fall through
3668+
newOpcode = newOpcode == Js::OpCode::StParamSlot || newOpcode == Js::OpCode::StStableParamSlot ? Js::OpCode::StLocalSlot : Js::OpCode::StLocalSlotChkUndecl;
3669+
goto StLocalSlotCommon;
3670+
3671+
case Js::OpCode::StStableLocalSlot:
3672+
case Js::OpCode::StStableLocalSlotChkUndecl:
3673+
stableSlot = true;
3674+
goto StLocalSlotCommon;
36473675

36483676
case Js::OpCode::StLocalSlot:
36493677
case Js::OpCode::StLocalSlotChkUndecl:
3678+
stableSlot = false;
3679+
3680+
StLocalSlotCommon:
36503681
if (!PHASE_OFF(Js::ClosureRangeCheckPhase, m_func))
36513682
{
36523683
if ((uint32)slotId >= scopeSlotSize + Js::ScopeSlots::FirstSlotIndex)
@@ -3662,7 +3693,7 @@ IRBuilder::BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
36623693
this->AddInstr(byteCodeUse, offset);
36633694
}
36643695

3665-
newOpcode = newOpcode == Js::OpCode::StLocalSlot ? Js::OpCode::StSlot : Js::OpCode::StSlotChkUndecl;
3696+
newOpcode = newOpcode == Js::OpCode::StLocalSlot || newOpcode == Js::OpCode::StStableLocalSlot ? Js::OpCode::StSlot : Js::OpCode::StSlotChkUndecl;
36663697
if (m_func->DoStackFrameDisplay())
36673698
{
36683699
regOpnd = IR::RegOpnd::New(TyVar, m_func);
@@ -3687,7 +3718,7 @@ IRBuilder::BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
36873718
this->EnsureLoopBodyLoadSlot(symID);
36883719
}
36893720
}
3690-
fieldSym = PropertySym::FindOrCreate(symID, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
3721+
fieldSym = PropertySym::FindOrCreate(symID, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func, stableSlot);
36913722
fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
36923723
regOpnd = this->BuildSrcOpnd(regSlot);
36933724
instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
@@ -3882,7 +3913,8 @@ IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
38823913
IR::Instr *instr;
38833914
PropertySym *fieldSym;
38843915
bool isLdSlotThatWasNotProfiled = false;
3885-
bool stableSlots = false;
3916+
bool stableSlotArray = false;
3917+
bool stableSlot = false;
38863918

38873919
switch (newOpcode)
38883920
{
@@ -3916,19 +3948,26 @@ IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
39163948
break;
39173949
}
39183950

3951+
case Js::OpCode::LdStableEnvSlot:
3952+
stableSlotArray = true;
3953+
stableSlot = true;
3954+
goto EnvSlotCommon;
3955+
39193956
case Js::OpCode::LdEnvSlot:
39203957
case Js::OpCode::StEnvSlot:
39213958
case Js::OpCode::StEnvSlotChkUndecl:
3922-
stableSlots = true;
3923-
goto SlotsCommon;
3959+
stableSlotArray = true;
3960+
stableSlot = false;
3961+
goto EnvSlotCommon;
39243962

39253963
case Js::OpCode::LdEnvObjSlot:
39263964
case Js::OpCode::StEnvObjSlot:
39273965
case Js::OpCode::StEnvObjSlotChkUndecl:
3928-
stableSlots = false;
3966+
stableSlotArray = false;
3967+
stableSlot = false;
39293968

3930-
SlotsCommon:
3931-
fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, this->GetEnvReg(), slotId1, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray, (uint)-1, stableSlots);
3969+
EnvSlotCommon:
3970+
fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, this->GetEnvReg(), slotId1, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray, (uint)-1, stableSlotArray);
39323971
regOpnd = IR::RegOpnd::New(TyVar, m_func);
39333972
instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
39343973
this->AddInstr(instr, offset);
@@ -3953,12 +3992,13 @@ IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
39533992
break;
39543993
}
39553994

3956-
fieldSym = PropertySym::New(regOpnd->m_sym, slotId2, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
3995+
fieldSym = PropertySym::New(regOpnd->m_sym, slotId2, (uint32)-1, (uint)-1, PropertyKindSlots, m_func, stableSlot);
39573996
fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
39583997

39593998
switch (newOpcode)
39603999
{
39614000
case Js::OpCode::LdEnvSlot:
4001+
case Js::OpCode::LdStableEnvSlot:
39624002
case Js::OpCode::LdEnvObjSlot:
39634003
newOpcode = Js::OpCode::LdSlot;
39644004
regOpnd = this->BuildDstOpnd(regSlot);
@@ -3992,10 +4032,18 @@ IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
39924032
}
39934033
break;
39944034

4035+
case Js::OpCode::StStableInnerSlot:
4036+
case Js::OpCode::StStableInnerSlotChkUndecl:
4037+
stableSlot = true;
4038+
goto StInnerSlotCommon;
4039+
39954040
case Js::OpCode::StInnerObjSlot:
39964041
case Js::OpCode::StInnerObjSlotChkUndecl:
39974042
case Js::OpCode::StInnerSlot:
39984043
case Js::OpCode::StInnerSlotChkUndecl:
4044+
stableSlot = false;
4045+
4046+
StInnerSlotCommon:
39994047
if ((uint)slotId1 >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
40004048
{
40014049
Js::Throw::FatalInternalError();
@@ -4018,15 +4066,15 @@ IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
40184066
}
40194067
else
40204068
{
4021-
fieldOpnd = this->BuildFieldOpnd(Js::OpCode::StSlot, slotId1, slotId2, (Js::PropertyIdIndexType)-1, PropertyKindSlots);
4069+
fieldOpnd = this->BuildFieldOpnd(Js::OpCode::StSlot, slotId1, slotId2, (Js::PropertyIdIndexType)-1, PropertyKindSlots, (uint)-1, stableSlot);
40224070
if (!this->DoSlotArrayCheck(fieldOpnd, IsLoopBody()))
40234071
{
40244072
// Need a dynamic check on the size of the local slot array.
40254073
m_func->GetTopFunc()->AddSlotArrayCheck(fieldOpnd);
40264074
}
40274075
}
40284076
newOpcode =
4029-
newOpcode == Js::OpCode::StInnerObjSlot || newOpcode == Js::OpCode::StInnerSlot ?
4077+
newOpcode == Js::OpCode::StInnerObjSlot || newOpcode == Js::OpCode::StInnerSlot || newOpcode == Js::OpCode::StStableInnerSlot ?
40304078
Js::OpCode::StSlot : Js::OpCode::StSlotChkUndecl;
40314079
instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
40324080
if (newOpcode == Js::OpCode::StSlotChkUndecl)
@@ -4038,8 +4086,15 @@ IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
40384086

40394087
break;
40404088

4089+
case Js::OpCode::LdStableInnerSlot:
4090+
stableSlot = true;
4091+
goto LdInnerSlotCommon;
4092+
40414093
case Js::OpCode::LdInnerSlot:
40424094
case Js::OpCode::LdInnerObjSlot:
4095+
stableSlot = false;
4096+
4097+
LdInnerSlotCommon:
40434098
if ((uint)slotId1 >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
40444099
{
40454100
Js::Throw::FatalInternalError();
@@ -4061,7 +4116,7 @@ IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r
40614116
}
40624117
else
40634118
{
4064-
fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlot, slotId1, slotId2, (Js::PropertyIdIndexType)-1, PropertyKindSlots);
4119+
fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlot, slotId1, slotId2, (Js::PropertyIdIndexType)-1, PropertyKindSlots, (uint)-1, stableSlot);
40654120
if (!this->DoSlotArrayCheck(fieldOpnd, IsLoopBody()))
40664121
{
40674122
// Need a dynamic check on the size of the local slot array.

lib/Parser/Parse.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1938,6 +1938,10 @@ void Parser::BindPidRefsInScope(IdentPtr pid, Symbol *sym, int blockId, uint max
19381938
{
19391939
sym->SetNeedsScopeObject();
19401940
}
1941+
if (ref->IsAssignment())
1942+
{
1943+
sym->SetHasNonLocalAssignment();
1944+
}
19411945
}
19421946

19431947
if (ref->IsFuncAssignment())

lib/Runtime/ByteCode/ByteCodeDumper.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -881,17 +881,23 @@ namespace Js
881881
switch (op)
882882
{
883883
case OpCode::StLocalSlot:
884+
case OpCode::StStableLocalSlot:
884885
case OpCode::StParamSlot:
886+
case OpCode::StStableParamSlot:
885887
case OpCode::StLocalObjSlot:
886888
case OpCode::StParamObjSlot:
887889
case OpCode::StLocalSlotChkUndecl:
890+
case OpCode::StStableLocalSlotChkUndecl:
888891
case OpCode::StParamSlotChkUndecl:
892+
case OpCode::StStableParamSlotChkUndecl:
889893
case OpCode::StLocalObjSlotChkUndecl:
890894
case OpCode::StParamObjSlotChkUndecl:
891895
Output::Print(_u(" [%d] = R%d "),data->SlotIndex, data->Value);
892896
break;
893897
case OpCode::LdLocalSlot:
898+
case OpCode::LdStableLocalSlot:
894899
case OpCode::LdParamSlot:
900+
case OpCode::LdStableParamSlot:
895901
case OpCode::LdEnvObj:
896902
case OpCode::LdLocalObjSlot:
897903
case OpCode::LdParamObjSlot:
@@ -920,7 +926,9 @@ namespace Js
920926
switch (op)
921927
{
922928
case OpCode::StInnerSlot:
929+
case OpCode::StStableInnerSlot:
923930
case OpCode::StInnerSlotChkUndecl:
931+
case OpCode::StStableInnerSlotChkUndecl:
924932
case OpCode::StInnerObjSlot:
925933
case OpCode::StInnerObjSlotChkUndecl:
926934
case OpCode::StEnvSlot:
@@ -931,8 +939,10 @@ namespace Js
931939
Output::Print(_u(" [%d][%d] = R%d "),data->SlotIndex1, data->SlotIndex2, data->Value);
932940
break;
933941
case OpCode::LdInnerSlot:
942+
case OpCode::LdStableInnerSlot:
934943
case OpCode::LdInnerObjSlot:
935944
case OpCode::LdEnvSlot:
945+
case OpCode::LdStableEnvSlot:
936946
case OpCode::LdEnvObjSlot:
937947
case OpCode::LdModuleSlot:
938948
Output::Print(_u(" R%d = [%d][%d] "),data->Value, data->SlotIndex1, data->SlotIndex2);

0 commit comments

Comments
 (0)