@@ -1983,19 +1983,7 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo *
1983
1983
StackSym* originalCallTargetStackSym = callInstr->GetSrc1()->GetStackSym();
1984
1984
bool originalCallTargetOpndIsJITOpt = callInstr->GetSrc1()->GetIsJITOptimizedReg();
1985
1985
1986
- // We are committed to inlining, optimize the call instruction for fixed fields now and don't attempt it later.
1987
- bool safeThis = false;
1988
- if (TryOptimizeCallInstrWithFixedMethod(callInstr, inlineeData, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/, safeThis /*unused here*/))
1989
- {
1990
- Assert(callInstr->m_opcode == Js::OpCode::CallIFixed);
1991
- Assert(callInstr->GetFixedFunction()->GetFuncInfoAddr() == inlineeData->GetFunctionInfoAddr());
1992
- }
1993
- else
1994
- {
1995
- // FunctionObject check for built-ins
1996
- IR::BailOutInstr * bailOutInstr = IR::BailOutInstr::New(Js::OpCode::BailOnNotBuiltIn, IR::BailOutOnInlineFunction, callInstr, callInstr->m_func);
1997
- InsertFunctionObjectCheck(callInstr, callInstr, bailOutInstr, inlineeData);
1998
- }
1986
+ IR::ByteCodeUsesInstr* useCallTargetInstr = EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, inlineeData, false, true, false, true);
1999
1987
2000
1988
// To push function object for cases when we have to make calls to helper method to assist in inlining
2001
1989
if(inlineCallOpCode == Js::OpCode::CallDirect)
@@ -2031,11 +2019,9 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo *
2031
2019
}
2032
2020
}
2033
2021
2034
- // Insert a byteCodeUsesInstr to make sure the function object's lifetime is extended beyond the last bailout point
2035
- // at which we may need to call the inlinee again in the interpreter.
2022
+ if (useCallTargetInstr)
2036
2023
{
2037
- IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr);
2038
- useCallTargetInstr->SetRemovedOpndSymbol(originalCallTargetOpndIsJITOpt, originalCallTargetStackSym->m_id);
2024
+ useCallTargetInstr->Unlink();
2039
2025
callInstr->InsertBefore(useCallTargetInstr);
2040
2026
}
2041
2027
@@ -2071,7 +2057,7 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo *
2071
2057
2072
2058
// Insert a byteCodeUsesInstr to make sure the function object's lifetime is extended beyond the last bailout point
2073
2059
// at which we may need to call the inlinee again in the interpreter.
2074
- IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr->GetPrevRealInstrOrLabel());
2060
+ useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr->GetPrevRealInstrOrLabel());
2075
2061
useCallTargetInstr->SetRemovedOpndSymbol(originalCallTargetOpndIsJITOpt, originalCallTargetStackSym->m_id);
2076
2062
2077
2063
if(inlineCallOpCode == Js::OpCode::InlineArrayPop)
@@ -2364,7 +2350,7 @@ IR::Instr* Inline::InlineApply(IR::Instr *callInstr, const FunctionJITTimeInfo *
2364
2350
2365
2351
// TODO: OOP JIT enable assert (readprocessmemory?)
2366
2352
//Assert((inlineeData->GetFunctionInfo()->GetAttributes() & Js::FunctionInfo::Attributes::BuiltInInlinableAsLdFldInlinee) != 0);
2367
- return InlineApplyWithArray (callInstr, applyData, Js::JavascriptLibrary::GetBuiltInForFuncInfo( inlineeData->GetFunctionInfoAddr(), this->topFunc->GetThreadContextInfo()) );
2353
+ return InlineApplyBuiltInTargetWithArray (callInstr, applyData, inlineeData);
2368
2354
}
2369
2355
else
2370
2356
{
@@ -2477,15 +2463,33 @@ IR::Instr * Inline::InlineApplyWithArgumentsObject(IR::Instr * callInstr, IR::In
2477
2463
/*
2478
2464
This method will only do CallDirect style inlining of built-in targets. No script function inlining.
2479
2465
*/
2480
- IR::Instr * Inline::InlineApplyWithArray (IR::Instr * callInstr, const FunctionJITTimeInfo * funcInfo, Js::BuiltinFunction builtInId )
2466
+ IR::Instr * Inline::InlineApplyBuiltInTargetWithArray (IR::Instr * callInstr, const FunctionJITTimeInfo * applyInfo, const FunctionJITTimeInfo * builtInInfo )
2481
2467
{
2482
2468
IR::Instr * implicitThisArgOut = nullptr;
2483
2469
IR::Instr * explicitThisArgOut = nullptr;
2484
2470
IR::Instr * arrayArgOut = nullptr;
2485
2471
uint argOutCount = 0;
2486
2472
this->GetArgInstrsForCallAndApply(callInstr, &implicitThisArgOut, &explicitThisArgOut, &arrayArgOut, argOutCount);
2487
2473
2488
- TryFixedMethodAndPrepareInsertionPoint(callInstr, funcInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
2474
+ Js::OpCode originalCallOpcode = callInstr->m_opcode;
2475
+ IR::Opnd * originalCallSrc1 = callInstr->GetSrc1()->Copy(this->topFunc);
2476
+ IR::AutoReuseOpnd autoReuseOriginalCallSrc1(originalCallSrc1, this->topFunc);
2477
+
2478
+ IR::Instr* applyLdInstr = nullptr;
2479
+ IR::Instr* applyTargetLdInstr = nullptr;
2480
+ if (!TryGetApplyAndTargetLdInstrs(callInstr, &applyLdInstr, &applyTargetLdInstr))
2481
+ {
2482
+ return callInstr;
2483
+ }
2484
+ AnalysisAssert(applyTargetLdInstr != nullptr);
2485
+ // Fixed function/function object checks for target built-in
2486
+ callInstr->ReplaceSrc1(applyTargetLdInstr->GetDst());
2487
+ EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, builtInInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
2488
+
2489
+ // Fixed function/function object checks for .apply
2490
+ callInstr->m_opcode = originalCallOpcode;
2491
+ callInstr->ReplaceSrc1(originalCallSrc1);
2492
+ EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, applyInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
2489
2493
2490
2494
IR::Instr* builtInEndInstr = InsertInlineeBuiltInStartEndTags(callInstr, 3); // 3 args (implicit this + explicit this + array = 3)
2491
2495
builtInEndInstr->m_opcode = Js::OpCode::InlineNonTrackingBuiltInEnd; // We will call EndTrackCall when we see CallDirect for reasons explained in GlobOpt::TrackCalls
@@ -2513,6 +2517,7 @@ IR::Instr * Inline::InlineApplyWithArray(IR::Instr * callInstr, const FunctionJI
2513
2517
argOut = IR::Instr::New(Js::OpCode::ArgOut_A_InlineSpecialized, linkOpnd, implicitThisArgOut->GetSrc1(), argOut->GetDst(), callInstr->m_func);
2514
2518
callInstr->InsertBefore(argOut);
2515
2519
2520
+ Js::BuiltinFunction builtInId = Js::JavascriptLibrary::GetBuiltInForFuncInfo(builtInInfo->GetFunctionInfoAddr(), this->topFunc->GetThreadContextInfo());
2516
2521
IR::HelperCallOpnd * helperCallOpnd = nullptr;
2517
2522
switch (builtInId)
2518
2523
{
@@ -2543,7 +2548,7 @@ IR::Instr * Inline::InlineApplyWithoutArrayArgument(IR::Instr *callInstr, const
2543
2548
uint argOutCount = 0;
2544
2549
this->GetArgInstrsForCallAndApply(callInstr, &implicitThisArgOut, &explicitThisArgOut, &dummyInstr, argOutCount);
2545
2550
2546
- TryFixedMethodAndPrepareInsertionPoint( callInstr, applyInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
2551
+ EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, applyInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
2547
2552
2548
2553
InsertInlineeBuiltInStartEndTags(callInstr, 2); // 2 args (implicit this + explicit this)
2549
2554
@@ -2616,6 +2621,22 @@ void Inline::GetArgInstrsForCallAndApply(IR::Instr* callInstr, IR::Instr** impli
2616
2621
linkOpnd->AsRegOpnd()->m_sym->m_isInlinedArgSlot = true;
2617
2622
}
2618
2623
2624
+ bool Inline::TryGetApplyAndTargetLdInstrs(IR::Instr * callInstr, _Outptr_result_maybenull_ IR::Instr ** applyLdInstr, _Outptr_result_maybenull_ IR::Instr ** applyTargetLdInstr)
2625
+ {
2626
+ IR::Opnd* applyOpnd = callInstr->GetSrc1();
2627
+ Assert(applyOpnd->IsRegOpnd());
2628
+ StackSym* applySym = applyOpnd->AsRegOpnd()->m_sym->AsStackSym();
2629
+ if (!applySym->IsSingleDef())
2630
+ {
2631
+ *applyLdInstr = nullptr;
2632
+ *applyTargetLdInstr = nullptr;
2633
+ return false;
2634
+ }
2635
+ *applyLdInstr = applySym->GetInstrDef();;
2636
+ *applyTargetLdInstr = (*applyLdInstr)->m_prev;
2637
+ return true;
2638
+ }
2639
+
2619
2640
/*
2620
2641
This method only inlines targets which are script functions, under the
2621
2642
condition that the second argument (if any) passed to apply is arguments object.
@@ -2637,16 +2658,14 @@ bool Inline::InlineApplyScriptTarget(IR::Instr *callInstr, const FunctionJITTime
2637
2658
2638
2659
// Begin inlining apply target
2639
2660
2640
- IR::Opnd* applyOpnd = callInstr->GetSrc1();
2641
- Assert(applyOpnd->IsRegOpnd());
2642
- StackSym* applySym = applyOpnd->AsRegOpnd()->m_sym->AsStackSym();
2643
- if (!applySym->IsSingleDef())
2661
+ IR::Instr* applyLdInstr = nullptr;
2662
+ IR::Instr* applyTargetLdInstr = nullptr;
2663
+ if (!TryGetApplyAndTargetLdInstrs(callInstr, &applyLdInstr, &applyTargetLdInstr))
2644
2664
{
2645
2665
return false;
2646
2666
}
2647
- IR::Instr* applyLdInstr = applySym->GetInstrDef();
2648
- IR::Instr* applyTargetLdInstr = applyLdInstr->m_prev;
2649
-
2667
+ AnalysisAssert(applyTargetLdInstr != nullptr);
2668
+
2650
2669
if(applyTargetLdInstr->m_opcode != Js::OpCode::LdFldForCallApplyTarget ||
2651
2670
((applyTargetLdInstr->AsProfiledInstr()->u.FldInfo().flags & Js::FldInfo_FromAccessor) != 0))
2652
2671
{
@@ -2908,7 +2927,7 @@ Inline::InlineCall(IR::Instr *callInstr, const FunctionJITTimeInfo *funcInfo, co
2908
2927
2909
2928
IR::SymOpnd* orgLinkOpnd = callInstr->GetSrc2()->AsSymOpnd();
2910
2929
2911
- TryFixedMethodAndPrepareInsertionPoint( callInstr, funcInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
2930
+ EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, funcInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
2912
2931
2913
2932
InsertInlineeBuiltInStartEndTags(callInstr, actualCount);
2914
2933
@@ -4225,26 +4244,29 @@ Inline::PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *f
4225
4244
return primaryBailOutInstr;
4226
4245
}
4227
4246
4228
- void
4229
- Inline::TryFixedMethodAndPrepareInsertionPoint (IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined)
4247
+ IR::ByteCodeUsesInstr*
4248
+ Inline::EmitFixedMethodOrFunctionObjectChecksForBuiltIns (IR::Instr *callInstr, IR::Instr * funcObjCheckInsertInstr , const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined)
4230
4249
{
4231
4250
StackSym* originalCallTargetStackSym = callInstr->GetSrc1()->GetStackSym();
4232
4251
bool originalCallTargetIsJITOpt = callInstr->GetSrc1()->GetIsJITOptimizedReg();
4233
4252
4253
+ IR::ByteCodeUsesInstr * useCallTargetInstr = nullptr;
4234
4254
bool safeThis = false;
4235
4255
if (TryOptimizeCallInstrWithFixedMethod(callInstr, inlineeInfo, isPolymorphic, isBuiltIn, isCtor, isInlined, safeThis))
4236
4256
{
4237
4257
Assert(callInstr->m_opcode == Js::OpCode::CallIFixed);
4238
-
4258
+ Assert(callInstr->GetFixedFunction()->GetFuncInfoAddr() == inlineeInfo->GetFunctionInfoAddr());
4239
4259
// If we optimized the call instruction for a fixed function, we must extend the function object's lifetime until after the last bailout before the call.
4240
- IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr);
4260
+ useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr);
4241
4261
useCallTargetInstr->SetRemovedOpndSymbol(originalCallTargetIsJITOpt, originalCallTargetStackSym->m_id);
4242
4262
callInstr->InsertBefore(useCallTargetInstr);
4243
4263
}
4244
4264
else
4245
4265
{
4246
- PrepareInsertionPoint(callInstr, inlineeInfo, callInstr);
4266
+ IR::BailOutInstr * bailOutInstr = IR::BailOutInstr::New(Js::OpCode::BailOnNotBuiltIn, IR::BailOutOnInlineFunction, callInstr, callInstr->m_func);
4267
+ InsertFunctionObjectCheck(callInstr, funcObjCheckInsertInstr, bailOutInstr, inlineeInfo);
4247
4268
}
4269
+ return useCallTargetInstr;
4248
4270
}
4249
4271
4250
4272
uint Inline::CountActuals(IR::Instr *callInstr)
0 commit comments