@@ -175,7 +175,7 @@ GlobOpt::Optimize()
175
175
176
176
// Still need to run the dead store phase to calculate the live reg on back edge
177
177
this->BackwardPass(Js::DeadStorePhase);
178
- CannotAllocateArgumentsObjectOnStack();
178
+ CannotAllocateArgumentsObjectOnStack(nullptr );
179
179
return;
180
180
}
181
181
@@ -887,7 +887,7 @@ GlobOpt::ToTypeSpec(BVSparse<JitArenaAllocator> *bv, BasicBlock *block, IRType t
887
887
// instruction itself should disable arguments object optimization.
888
888
if(block->globOptData.argObjSyms && block->globOptData.IsArgumentsSymID(id))
889
889
{
890
- CannotAllocateArgumentsObjectOnStack();
890
+ CannotAllocateArgumentsObjectOnStack(nullptr );
891
891
}
892
892
893
893
if (block->globOptData.liveVarSyms->Test(id))
@@ -1512,7 +1512,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1512
1512
1513
1513
if (instr->m_func->GetJITFunctionBody()->GetInParamsCount() != 1 && !instr->m_func->IsStackArgsEnabled())
1514
1514
{
1515
- CannotAllocateArgumentsObjectOnStack();
1515
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1516
1516
}
1517
1517
else
1518
1518
{
@@ -1527,7 +1527,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1527
1527
// In the debug mode, we don't want to optimize away the aliases. Since we may have to show them on the inspection.
1528
1528
if (((!AreFromSameBytecodeFunc(src1->AsRegOpnd(), dst->AsRegOpnd()) || this->currentBlock->loop) && instr->m_opcode != Js::OpCode::BytecodeArgOutCapture) || this->func->IsJitInDebugMode())
1529
1529
{
1530
- CannotAllocateArgumentsObjectOnStack();
1530
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1531
1531
return;
1532
1532
}
1533
1533
if(!dst->AsRegOpnd()->GetStackSym()->m_nonEscapingArgObjAlias)
@@ -1550,7 +1550,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1550
1550
}
1551
1551
1552
1552
SymID id = 0;
1553
-
1553
+
1554
1554
switch(instr->m_opcode)
1555
1555
{
1556
1556
case Js::OpCode::LdElemI_A:
@@ -1561,7 +1561,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1561
1561
if (indexOpnd && CurrentBlockData()->IsArgumentsSymID(indexOpnd->m_sym->m_id))
1562
1562
{
1563
1563
// Pathological test cases such as a[arguments]
1564
- CannotAllocateArgumentsObjectOnStack();
1564
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1565
1565
return;
1566
1566
}
1567
1567
@@ -1650,7 +1650,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1650
1650
WritePerfHint(PerfHints::HeapArgumentsCreated, instr->m_func, instr->GetByteCodeOffset());
1651
1651
}
1652
1652
#endif
1653
- CannotAllocateArgumentsObjectOnStack();
1653
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1654
1654
return;
1655
1655
}
1656
1656
}
@@ -1668,7 +1668,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1668
1668
WritePerfHint(PerfHints::HeapArgumentsCreated, instr->m_func, instr->GetByteCodeOffset());
1669
1669
}
1670
1670
#endif
1671
- CannotAllocateArgumentsObjectOnStack();
1671
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1672
1672
return;
1673
1673
}
1674
1674
}
@@ -1687,7 +1687,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1687
1687
WritePerfHint(PerfHints::HeapArgumentsModification, instr->m_func, instr->GetByteCodeOffset());
1688
1688
}
1689
1689
#endif
1690
- CannotAllocateArgumentsObjectOnStack();
1690
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1691
1691
return;
1692
1692
}
1693
1693
}
@@ -1701,7 +1701,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
1701
1701
WritePerfHint(PerfHints::HeapArgumentsModification, instr->m_func, instr->GetByteCodeOffset());
1702
1702
}
1703
1703
#endif
1704
- CannotAllocateArgumentsObjectOnStack();
1704
+ CannotAllocateArgumentsObjectOnStack(instr->m_func );
1705
1705
return;
1706
1706
}
1707
1707
CurrentBlockData()->ClearArgumentsSym(dst->AsRegOpnd());
@@ -2446,6 +2446,7 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
2446
2446
OptimizeChecks(instr);
2447
2447
OptArraySrc(&instr, &src1Val, &src2Val);
2448
2448
OptNewScObject(&instr, src1Val);
2449
+ OptArgLenAndConst(instr, &src1Val);
2449
2450
2450
2451
instr = this->OptPeep(instr, src1Val, src2Val);
2451
2452
@@ -13196,6 +13197,69 @@ GlobOpt::OptArraySrc(IR::Instr ** const instrRef, Value ** src1Val, Value ** src
13196
13197
arraySrcOpt.Optimize();
13197
13198
}
13198
13199
13200
+ void
13201
+ GlobOpt::OptArgLenAndConst(IR::Instr* instr, Value** src1Val)
13202
+ {
13203
+ if (instr->usesStackArgumentsObject && instr->IsInlined())
13204
+ {
13205
+ IR::Opnd* src1 = instr->GetSrc1();
13206
+ auto replaceInstr = [&](IR::Opnd* newopnd)
13207
+ {
13208
+ this->CaptureByteCodeSymUses(instr);
13209
+ instr->m_opcode = Js::OpCode::Ld_A;
13210
+ instr->ReplaceSrc1(newopnd);
13211
+ if (instr->HasBailOutInfo())
13212
+ {
13213
+ instr->ClearBailOutInfo();
13214
+ }
13215
+ *src1Val = this->OptSrc(instr->GetSrc1(), &instr);
13216
+ instr->m_func->hasArgLenAndConstOpt = true;
13217
+ };
13218
+ Assert(CurrentBlockData()->IsArgumentsOpnd(src1));
13219
+ switch(instr->m_opcode)
13220
+ {
13221
+ case Js::OpCode::LdLen_A:
13222
+ {
13223
+ IR::AddrOpnd* newopnd = IR::AddrOpnd::New(Js::TaggedInt::ToVarUnchecked(instr->m_func->actualCount - 1), IR::AddrOpndKindConstantVar, instr->m_func);
13224
+ replaceInstr(newopnd);
13225
+ break;
13226
+ }
13227
+
13228
+ case Js::OpCode::LdElemI_A:
13229
+ {
13230
+ IR::IndirOpnd* indirOpndSrc1 = src1->AsIndirOpnd();
13231
+ if (!indirOpndSrc1->GetIndexOpnd())
13232
+ {
13233
+ int argIndex = indirOpndSrc1->GetOffset() + 1;
13234
+ IR::Instr* defInstr = nullptr;
13235
+ IR::Instr* inlineeStart = instr->m_func->GetInlineeStart();
13236
+ inlineeStart->IterateArgInstrs([&](IR::Instr* argInstr) {
13237
+ StackSym *argSym = argInstr->GetDst()->AsSymOpnd()->m_sym->AsStackSym();
13238
+ if (argSym->GetArgSlotNum() - 1 == argIndex)
13239
+ {
13240
+ defInstr = argInstr;
13241
+ return true;
13242
+ }
13243
+ return false;
13244
+ });
13245
+ // If we cannot find the right instruction. I.E. When calling arguments[2] and no arguments were passed to the func
13246
+ if (defInstr == nullptr)
13247
+ {
13248
+ IR::Opnd * undefined = IR::AddrOpnd::New(instr->m_func->GetScriptContextInfo()->GetUndefinedAddr(), IR::AddrOpndKindDynamicVar, instr->m_func, true);
13249
+ undefined->SetValueType(ValueType::Undefined);
13250
+ replaceInstr(undefined);
13251
+ }
13252
+ else
13253
+ {
13254
+ replaceInstr(defInstr->GetSrc1());
13255
+ }
13256
+ }
13257
+ break;
13258
+ }
13259
+ }
13260
+ }
13261
+ }
13262
+
13199
13263
void
13200
13264
GlobOpt::CaptureNoImplicitCallUses(
13201
13265
IR::Opnd *opnd,
@@ -15722,16 +15786,23 @@ GlobOpt::TrackArgumentsObject()
15722
15786
{
15723
15787
if (PHASE_OFF(Js::StackArgOptPhase, this->func))
15724
15788
{
15725
- this->CannotAllocateArgumentsObjectOnStack();
15789
+ this->CannotAllocateArgumentsObjectOnStack(nullptr );
15726
15790
return false;
15727
15791
}
15728
15792
15729
15793
return func->GetHasStackArgs();
15730
15794
}
15731
15795
15732
15796
void
15733
- GlobOpt::CannotAllocateArgumentsObjectOnStack()
15797
+ GlobOpt::CannotAllocateArgumentsObjectOnStack(Func * curFunc )
15734
15798
{
15799
+ if (curFunc != nullptr && curFunc->hasArgLenAndConstOpt)
15800
+ {
15801
+ Assert(!curFunc->GetJITOutput()->GetOutputData()->disableStackArgOpt);
15802
+ curFunc->GetJITOutput()->GetOutputData()->disableStackArgOpt = true;
15803
+ throw Js::RejitException(RejitReason::DisableStackArgLenAndConstOpt);
15804
+ }
15805
+
15735
15806
func->SetHasStackArgs(false);
15736
15807
15737
15808
#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
0 commit comments