@@ -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
+
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,13 @@ 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
+
2650
2668
if (applyTargetLdInstr->m_opcode != Js::OpCode::LdFldForCallApplyTarget ||
2651
2669
((applyTargetLdInstr->AsProfiledInstr ()->u .FldInfo ().flags & Js::FldInfo_FromAccessor) != 0 ))
2652
2670
{
@@ -2908,7 +2926,7 @@ Inline::InlineCall(IR::Instr *callInstr, const FunctionJITTimeInfo *funcInfo, co
2908
2926
2909
2927
IR::SymOpnd* orgLinkOpnd = callInstr->GetSrc2 ()->AsSymOpnd ();
2910
2928
2911
- TryFixedMethodAndPrepareInsertionPoint ( callInstr, funcInfo, false /* isPolymorphic*/ , true /* isBuiltIn*/ , false /* isCtor*/ , true /* isInlined*/ );
2929
+ EmitFixedMethodOrFunctionObjectChecksForBuiltIns (callInstr, callInstr, funcInfo, false /* isPolymorphic*/ , true /* isBuiltIn*/ , false /* isCtor*/ , true /* isInlined*/ );
2912
2930
2913
2931
InsertInlineeBuiltInStartEndTags (callInstr, actualCount);
2914
2932
@@ -4225,26 +4243,29 @@ Inline::PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *f
4225
4243
return primaryBailOutInstr;
4226
4244
}
4227
4245
4228
- void
4229
- Inline::TryFixedMethodAndPrepareInsertionPoint (IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined)
4246
+ IR::ByteCodeUsesInstr*
4247
+ Inline::EmitFixedMethodOrFunctionObjectChecksForBuiltIns (IR::Instr *callInstr, IR::Instr * funcObjCheckInsertInstr , const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined)
4230
4248
{
4231
4249
StackSym* originalCallTargetStackSym = callInstr->GetSrc1 ()->GetStackSym ();
4232
4250
bool originalCallTargetIsJITOpt = callInstr->GetSrc1 ()->GetIsJITOptimizedReg ();
4233
4251
4252
+ IR::ByteCodeUsesInstr * useCallTargetInstr = nullptr ;
4234
4253
bool safeThis = false ;
4235
4254
if (TryOptimizeCallInstrWithFixedMethod (callInstr, inlineeInfo, isPolymorphic, isBuiltIn, isCtor, isInlined, safeThis))
4236
4255
{
4237
4256
Assert (callInstr->m_opcode == Js::OpCode::CallIFixed);
4238
-
4257
+ Assert (callInstr-> GetFixedFunction ()-> GetFuncInfoAddr () == inlineeInfo-> GetFunctionInfoAddr ());
4239
4258
// 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);
4259
+ useCallTargetInstr = IR::ByteCodeUsesInstr::New (callInstr);
4241
4260
useCallTargetInstr->SetRemovedOpndSymbol (originalCallTargetIsJITOpt, originalCallTargetStackSym->m_id );
4242
4261
callInstr->InsertBefore (useCallTargetInstr);
4243
4262
}
4244
4263
else
4245
4264
{
4246
- PrepareInsertionPoint (callInstr, inlineeInfo, callInstr);
4265
+ IR::BailOutInstr * bailOutInstr = IR::BailOutInstr::New (Js::OpCode::BailOnNotBuiltIn, IR::BailOutOnInlineFunction, callInstr, callInstr->m_func );
4266
+ InsertFunctionObjectCheck (callInstr, funcObjCheckInsertInstr, bailOutInstr, inlineeInfo);
4247
4267
}
4268
+ return useCallTargetInstr;
4248
4269
}
4249
4270
4250
4271
uint Inline::CountActuals (IR::Instr *callInstr)
0 commit comments