Skip to content

Commit 9dac956

Browse files
author
Thomas Moore (CHAKRA)
committed
SwitchOpt determined by AggressiveIntTypeSpec breaks repeated String cases
This change fixes an issue where the function GlobOpt::IsSwitchOptEnabled was updated to add conditions for type specialization. This resulted in bad IR being produced, which impacted how type-specialized BailOuts were constructed and which registers were restored (or, not restored). The fix is to apply align optimization checks in SwitchIRBuilder based on the types of the cases. CR Feedback fixes
1 parent 23984b9 commit 9dac956

File tree

5 files changed

+33
-32
lines changed

5 files changed

+33
-32
lines changed

lib/Backend/GlobOpt.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2917,7 +2917,7 @@ GlobOpt::TypeSpecializeBailoutExpectedInteger(IR::Instr* instr, Value* src1Val,
29172917
{
29182918
if (!src1Val || !src1Val->GetValueInfo()->IsLikelyInt() || instr->GetSrc1()->AsRegOpnd()->m_sym->m_isNotInt)
29192919
{
2920-
Assert(IsSwitchOptEnabled());
2920+
Assert(IsSwitchOptEnabledForIntTypeSpec());
29212921
throw Js::RejitException(RejitReason::DisableSwitchOptExpectingInteger);
29222922
}
29232923

@@ -11365,7 +11365,7 @@ GlobOpt::ToTypeSpecUse(IR::Instr *instr, IR::Opnd *opnd, BasicBlock *block, Valu
1136511365
// restarted with aggressive int type specialization disabled.
1136611366
if(bailOutKind == IR::BailOutExpectingInteger)
1136711367
{
11368-
Assert(IsSwitchOptEnabled());
11368+
Assert(IsSwitchOptEnabledForIntTypeSpec());
1136911369
throw Js::RejitException(RejitReason::DisableSwitchOptExpectingInteger);
1137011370
}
1137111371
else
@@ -11709,7 +11709,7 @@ GlobOpt::ToTypeSpecUse(IR::Instr *instr, IR::Opnd *opnd, BasicBlock *block, Valu
1170911709
// need to bail out.
1171011710
if (bailOutKind == IR::BailOutExpectingInteger)
1171111711
{
11712-
Assert(IsSwitchOptEnabled());
11712+
Assert(IsSwitchOptEnabledForIntTypeSpec());
1171311713
}
1171411714
else
1171511715
{
@@ -17193,8 +17193,13 @@ bool
1719317193
GlobOpt::IsSwitchOptEnabled(Func const * func)
1719417194
{
1719517195
Assert(func->IsTopFunc());
17196-
return !PHASE_OFF(Js::SwitchOptPhase, func) && !func->IsSwitchOptDisabled() && !IsTypeSpecPhaseOff(func)
17197-
&& DoAggressiveIntTypeSpec(func) && func->DoGlobOpt();
17196+
return !PHASE_OFF(Js::SwitchOptPhase, func) && !func->IsSwitchOptDisabled() && func->DoGlobOpt();
17197+
}
17198+
17199+
bool
17200+
GlobOpt::IsSwitchOptEnabledForIntTypeSpec(Func const * func)
17201+
{
17202+
return IsSwitchOptEnabled(func) && !IsTypeSpecPhaseOff(func) && DoAggressiveIntTypeSpec(func);
1719817203
}
1719917204

1720017205
bool

lib/Backend/GlobOpt.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ class GlobOpt
764764
static bool DoTypedArrayTypeSpec(Func const * func);
765765
static bool DoNativeArrayTypeSpec(Func const * func);
766766
static bool IsSwitchOptEnabled(Func const * func);
767+
static bool IsSwitchOptEnabledForIntTypeSpec(Func const * func);
767768
static bool DoInlineArgsOpt(Func const * func);
768769
static bool IsPREInstrCandidateLoad(Js::OpCode opcode);
769770
static bool IsPREInstrCandidateStore(Js::OpCode opcode);
@@ -790,6 +791,7 @@ class GlobOpt
790791
bool DoNativeArrayTypeSpec() const { return GlobOpt::DoNativeArrayTypeSpec(this->func); }
791792
bool DoLdLenIntSpec(IR::Instr * const instr, const ValueType baseValueType);
792793
bool IsSwitchOptEnabled() const { return GlobOpt::IsSwitchOptEnabled(this->func); }
794+
bool IsSwitchOptEnabledForIntTypeSpec() const { return GlobOpt::IsSwitchOptEnabledForIntTypeSpec(this->func); }
793795
bool DoPathDependentValues() const;
794796
bool DoTrackRelativeIntBounds() const;
795797
bool DoBoundCheckElimination() const;

lib/Backend/GlobOptBlockData.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1790,7 +1790,7 @@ GlobOptBlockData::IsTypeSpecialized(Sym const * sym) const
17901790
bool
17911791
GlobOptBlockData::IsSwitchInt32TypeSpecialized(IR::Instr const * instr) const
17921792
{
1793-
return GlobOpt::IsSwitchOptEnabled(instr->m_func->GetTopFunc())
1793+
return GlobOpt::IsSwitchOptEnabledForIntTypeSpec(instr->m_func->GetTopFunc())
17941794
&& instr->GetSrc1()->IsRegOpnd()
17951795
&& this->IsInt32TypeSpecialized(instr->GetSrc1()->AsRegOpnd()->m_sym);
17961796
}

lib/Backend/SwitchIRBuilder.cpp

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,16 @@ SwitchIRBuilder::OnCase(IR::RegOpnd * src1Opnd, IR::Opnd * src2Opnd, uint32 offs
235235
const bool isIntConst = src2Opnd->IsIntConstOpnd() || (sym && sym->IsIntConst());
236236
const bool isStrConst = !isIntConst && sym && sym->m_isStrConst;
237237

238-
if (GlobOpt::IsSwitchOptEnabled(m_func->GetTopFunc()) &&
239-
isIntConst &&
240-
m_intConstSwitchCases->TestAndSet(sym ? sym->GetIntConstValue() : src2Opnd->AsIntConstOpnd()->AsInt32()))
238+
if (isIntConst
239+
&& GlobOpt::IsSwitchOptEnabledForIntTypeSpec(m_func->GetTopFunc())
240+
&& m_intConstSwitchCases->TestAndSet(sym ? sym->GetIntConstValue() : src2Opnd->AsIntConstOpnd()->AsInt32()))
241241
{
242242
// We've already seen a case statement with the same int const value. No need to emit anything for this.
243243
return;
244244
}
245245

246-
if (GlobOpt::IsSwitchOptEnabled(m_func->GetTopFunc()) && isStrConst
246+
if (isStrConst
247+
&& GlobOpt::IsSwitchOptEnabled(m_func->GetTopFunc())
247248
&& TestAndAddStringCaseConst(JITJavascriptString::FromVar(sym->GetConstAddress(true))))
248249
{
249250
// We've already seen a case statement with the same string const value. No need to emit anything for this.
@@ -253,36 +254,27 @@ SwitchIRBuilder::OnCase(IR::RegOpnd * src1Opnd, IR::Opnd * src2Opnd, uint32 offs
253254
branchInstr = IR::BranchInstr::New(m_eqOp, nullptr, src1Opnd, src2Opnd, m_func);
254255
branchInstr->m_isSwitchBr = true;
255256

256-
/*
257257
// Switch optimization
258258
// For Integers - Binary Search or jump table optimization technique is used
259259
// For Strings - Dictionary look up technique is used.
260260
//
261261
// For optimizing, the Load instruction corresponding to the switch instruction is profiled in the interpreter.
262262
// Based on the dynamic profile data, optimization technique is decided.
263-
*/
264-
265-
bool deferred = false;
266-
267-
if (GlobOpt::IsSwitchOptEnabled(m_func->GetTopFunc()))
263+
if (m_switchIntDynProfile && isIntConst && GlobOpt::IsSwitchOptEnabledForIntTypeSpec(m_func->GetTopFunc()))
268264
{
269-
if (m_switchIntDynProfile && isIntConst)
270-
{
271-
CaseNode* caseNode = JitAnew(m_tempAlloc, CaseNode, branchInstr, offset, targetOffset, src2Opnd);
272-
m_caseNodes->Add(caseNode);
273-
deferred = true;
274-
}
275-
else if (m_switchStrDynProfile && isStrConst)
276-
{
277-
CaseNode* caseNode = JitAnew(m_tempAlloc, CaseNode, branchInstr, offset, targetOffset, src2Opnd);
278-
m_caseNodes->Add(caseNode);
279-
m_seenOnlySingleCharStrCaseNodes = m_seenOnlySingleCharStrCaseNodes && caseNode->GetUpperBoundStringConstLocal()->GetLength() == 1;
280-
deferred = true;
281-
}
265+
CaseNode* caseNode = JitAnew(m_tempAlloc, CaseNode, branchInstr, offset, targetOffset, src2Opnd);
266+
m_caseNodes->Add(caseNode);
282267
}
283-
284-
if (!deferred)
268+
else if (m_switchStrDynProfile && isStrConst && GlobOpt::IsSwitchOptEnabled(m_func->GetTopFunc()))
269+
{
270+
CaseNode* caseNode = JitAnew(m_tempAlloc, CaseNode, branchInstr, offset, targetOffset, src2Opnd);
271+
m_caseNodes->Add(caseNode);
272+
m_seenOnlySingleCharStrCaseNodes = m_seenOnlySingleCharStrCaseNodes && caseNode->GetUpperBoundStringConstLocal()->GetLength() == 1;
273+
}
274+
else
285275
{
276+
// Otherwise, there are no optimizations to defer, so add the branch for
277+
// this case instruction now
286278
FlushCases(offset);
287279
m_adapter->AddBranchInstr(branchInstr, offset, targetOffset);
288280
}

lib/Backend/SwitchIRBuilder.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ struct IRBuilderAsmJsSwitchAdapter : public SwitchAdapter {
6060
#endif
6161

6262
/**
63-
* Handles construction of switch statements, with appropriate optimizations
63+
* Handles construction of switch statements, with appropriate optimizations. Note that some of these
64+
* optimizations occur during IR building (rather than GlobOpt) because the abstraction of a switch/case
65+
* block is not maintained with the resulting IR. Thus, some optimizations must occur during this phase.
6466
*/
6567
class SwitchIRBuilder {
6668
private:

0 commit comments

Comments
 (0)