@@ -174,7 +174,7 @@ GlobOpt::Optimize()
174
174
175
175
// Still need to run the dead store phase to calculate the live reg on back edge
176
176
this->BackwardPass(Js::DeadStorePhase);
177
- CannotAllocateArgumentsObjectOnStack();
177
+ CannotAllocateArgumentsObjectOnStack(nullptr );
178
178
return;
179
179
}
180
180
@@ -883,7 +883,7 @@ GlobOpt::ToTypeSpec(BVSparse<JitArenaAllocator> *bv, BasicBlock *block, IRType t
883
883
// instruction itself should disable arguments object optimization.
884
884
if(block->globOptData.argObjSyms && block->globOptData.IsArgumentsSymID(id))
885
885
{
886
- CannotAllocateArgumentsObjectOnStack();
886
+ CannotAllocateArgumentsObjectOnStack(insertBeforeInstr->m_func );
887
887
}
888
888
889
889
if (block->globOptData.liveVarSyms->Test(id))
@@ -1508,7 +1508,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1508
1508
1509
1509
if (instr->m_func->GetJITFunctionBody()->GetInParamsCount() != 1 && !instr->m_func->IsStackArgsEnabled())
1510
1510
{
1511
- CannotAllocateArgumentsObjectOnStack();
1511
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1512
1512
}
1513
1513
else
1514
1514
{
@@ -1523,7 +1523,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1523
1523
// In the debug mode, we don't want to optimize away the aliases. Since we may have to show them on the inspection.
1524
1524
if (((!AreFromSameBytecodeFunc(src1->AsRegOpnd(), dst->AsRegOpnd()) || this->currentBlock->loop) && instr->m_opcode != Js::OpCode::BytecodeArgOutCapture) || this->func->IsJitInDebugMode())
1525
1525
{
1526
- CannotAllocateArgumentsObjectOnStack();
1526
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1527
1527
return;
1528
1528
}
1529
1529
if(!dst->AsRegOpnd()->GetStackSym()->m_nonEscapingArgObjAlias)
@@ -1546,7 +1546,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1546
1546
}
1547
1547
1548
1548
SymID id = 0;
1549
-
1549
+
1550
1550
switch(instr->m_opcode)
1551
1551
{
1552
1552
case Js::OpCode::LdElemI_A:
@@ -1557,7 +1557,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1557
1557
if (indexOpnd && CurrentBlockData()->IsArgumentsSymID(indexOpnd->m_sym->m_id))
1558
1558
{
1559
1559
// Pathological test cases such as a[arguments]
1560
- CannotAllocateArgumentsObjectOnStack();
1560
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1561
1561
return;
1562
1562
}
1563
1563
@@ -1646,7 +1646,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1646
1646
WritePerfHint(PerfHints::HeapArgumentsCreated, instr->m_func, instr->GetByteCodeOffset());
1647
1647
}
1648
1648
#endif
1649
- CannotAllocateArgumentsObjectOnStack();
1649
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1650
1650
return;
1651
1651
}
1652
1652
}
@@ -1664,7 +1664,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1664
1664
WritePerfHint(PerfHints::HeapArgumentsCreated, instr->m_func, instr->GetByteCodeOffset());
1665
1665
}
1666
1666
#endif
1667
- CannotAllocateArgumentsObjectOnStack();
1667
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1668
1668
return;
1669
1669
}
1670
1670
}
@@ -1683,7 +1683,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1683
1683
WritePerfHint(PerfHints::HeapArgumentsModification, instr->m_func, instr->GetByteCodeOffset());
1684
1684
}
1685
1685
#endif
1686
- CannotAllocateArgumentsObjectOnStack();
1686
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1687
1687
return;
1688
1688
}
1689
1689
}
@@ -1697,7 +1697,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1697
1697
WritePerfHint(PerfHints::HeapArgumentsModification, instr->m_func, instr->GetByteCodeOffset());
1698
1698
}
1699
1699
#endif
1700
- CannotAllocateArgumentsObjectOnStack();
1700
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1701
1701
return;
1702
1702
}
1703
1703
CurrentBlockData()->ClearArgumentsSym(dst->AsRegOpnd());
@@ -2442,6 +2442,7 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
2442
2442
OptimizeChecks(instr);
2443
2443
OptArraySrc(&instr, &src1Val, &src2Val);
2444
2444
OptNewScObject(&instr, src1Val);
2445
+ OptArgLenAndConst(instr, &src1Val);
2445
2446
2446
2447
instr = this->OptPeep(instr, src1Val, src2Val);
2447
2448
@@ -13083,6 +13084,61 @@ GlobOpt::OptArraySrc(IR::Instr ** const instrRef, Value ** src1Val, Value ** src
13083
13084
arraySrcOpt.Optimize();
13084
13085
}
13085
13086
13087
+ void
13088
+ GlobOpt::OptArgLenAndConst(IR::Instr* instr, Value** src1Val)
13089
+ {
13090
+ if (instr->m_func->IsStackArgsEnabled() && instr->IsInlined())
13091
+ {
13092
+ IR::Opnd* src1 = instr->GetSrc1();
13093
+ auto replaceInstr = [&](IR::Instr* instr, IR::Opnd* newopnd, Value** src1Val)
13094
+ {
13095
+ this->CaptureByteCodeSymUses(instr);
13096
+ instr->m_opcode = Js::OpCode::Ld_A;
13097
+ instr->ReplaceSrc1(newopnd);
13098
+ if (instr->HasBailOutInfo())
13099
+ {
13100
+ instr->ClearBailOutInfo();
13101
+ }
13102
+ *src1Val = this->OptSrc(instr->GetSrc1(), &instr);
13103
+ instr->m_func->hasArgLenAndConstOpt = true;
13104
+ };
13105
+ switch(instr->m_opcode)
13106
+ {
13107
+ case Js::OpCode::LdLen_A:
13108
+ {
13109
+ if (CurrentBlockData()->IsArgumentsOpnd(src1))
13110
+ {
13111
+ IR::AddrOpnd* newopnd = IR::AddrOpnd::New(Js::TaggedInt::ToVarUnchecked(instr->m_func->actualCount - 1), IR::AddrOpndKindConstantVar, instr->m_func);
13112
+ replaceInstr(instr, newopnd, src1Val);
13113
+ }
13114
+ break;
13115
+ }
13116
+
13117
+ case Js::OpCode::LdElemI_A:
13118
+ {
13119
+ IR::IndirOpnd* indirOpndSrc1 = src1->AsIndirOpnd();
13120
+ if (!indirOpndSrc1->GetIndexOpnd() && CurrentBlockData()->IsArgumentsOpnd(src1))
13121
+ {
13122
+ int argIndex = indirOpndSrc1->GetOffset() + 1;
13123
+ IR::Instr* defInstr = nullptr;
13124
+ IR::Instr* inlineeStart = instr->m_func->GetInlineeStart();
13125
+ inlineeStart->IterateArgInstrs([&](IR::Instr* argInstr) {
13126
+ StackSym *argSym = argInstr->GetDst()->AsSymOpnd()->m_sym->AsStackSym();
13127
+ if (argSym->GetArgSlotNum() - 1 == argIndex)
13128
+ {
13129
+ defInstr = argInstr;
13130
+ return true;
13131
+ }
13132
+ return false;
13133
+ });
13134
+ replaceInstr(instr, defInstr->GetSrc1(), src1Val);
13135
+ }
13136
+ break;
13137
+ }
13138
+ }
13139
+ }
13140
+ }
13141
+
13086
13142
void
13087
13143
GlobOpt::CaptureNoImplicitCallUses(
13088
13144
IR::Opnd *opnd,
@@ -15609,16 +15665,23 @@ GlobOpt::TrackArgumentsObject()
15609
15665
{
15610
15666
if (PHASE_OFF(Js::StackArgOptPhase, this->func))
15611
15667
{
15612
- this->CannotAllocateArgumentsObjectOnStack();
15668
+ this->CannotAllocateArgumentsObjectOnStack(nullptr );
15613
15669
return false;
15614
15670
}
15615
15671
15616
15672
return func->GetHasStackArgs();
15617
15673
}
15618
15674
15619
15675
void
15620
- GlobOpt::CannotAllocateArgumentsObjectOnStack()
15676
+ GlobOpt::CannotAllocateArgumentsObjectOnStack(Func * curFunc )
15621
15677
{
15678
+ if (curFunc != nullptr && curFunc->hasArgLenAndConstOpt)
15679
+ {
15680
+ Assert(!curFunc->GetJITOutput()->GetOutputData()->disableStackArgOpt);
15681
+ curFunc->GetJITOutput()->GetOutputData()->disableStackArgOpt = true;
15682
+ throw Js::RejitException(RejitReason::DisableStackArgLenAndConstOpt);
15683
+ }
15684
+
15622
15685
func->SetHasStackArgs(false);
15623
15686
15624
15687
#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
0 commit comments