@@ -2065,19 +2065,7 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo *
2065
2065
StackSym* originalCallTargetStackSym = callInstr->GetSrc1 ()->GetStackSym ();
2066
2066
bool originalCallTargetOpndIsJITOpt = callInstr->GetSrc1 ()->GetIsJITOptimizedReg ();
2067
2067
2068
- // We are committed to inlining, optimize the call instruction for fixed fields now and don't attempt it later.
2069
- bool safeThis = false ;
2070
- if (TryOptimizeCallInstrWithFixedMethod (callInstr, inlineeData, false /* isPolymorphic*/ , true /* isBuiltIn*/ , false /* isCtor*/ , true /* isInlined*/ , safeThis /* unused here*/ ))
2071
- {
2072
- Assert (callInstr->m_opcode == Js::OpCode::CallIFixed);
2073
- Assert (callInstr->GetFixedFunction ()->GetFuncInfoAddr () == inlineeData->GetFunctionInfoAddr ());
2074
- }
2075
- else
2076
- {
2077
- // FunctionObject check for built-ins
2078
- IR::BailOutInstr * bailOutInstr = IR::BailOutInstr::New (Js::OpCode::BailOnNotBuiltIn, IR::BailOutOnInlineFunction, callInstr, callInstr->m_func );
2079
- InsertFunctionObjectCheck (callInstr, callInstr, bailOutInstr, inlineeData);
2080
- }
2068
+ IR::ByteCodeUsesInstr* useCallTargetInstr = EmitFixedMethodOrFunctionObjectChecksForBuiltIns (callInstr, callInstr, inlineeData, false , true , false , true );
2081
2069
2082
2070
// To push function object for cases when we have to make calls to helper method to assist in inlining
2083
2071
if (inlineCallOpCode == Js::OpCode::CallDirect)
@@ -2113,11 +2101,9 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo *
2113
2101
}
2114
2102
}
2115
2103
2116
- // Insert a byteCodeUsesInstr to make sure the function object's lifetime is extended beyond the last bailout point
2117
- // at which we may need to call the inlinee again in the interpreter.
2104
+ if (useCallTargetInstr)
2118
2105
{
2119
- IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New (callInstr);
2120
- useCallTargetInstr->SetRemovedOpndSymbol (originalCallTargetOpndIsJITOpt, originalCallTargetStackSym->m_id );
2106
+ useCallTargetInstr->Unlink ();
2121
2107
callInstr->InsertBefore (useCallTargetInstr);
2122
2108
}
2123
2109
@@ -2153,7 +2139,7 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo *
2153
2139
2154
2140
// Insert a byteCodeUsesInstr to make sure the function object's lifetime is extended beyond the last bailout point
2155
2141
// at which we may need to call the inlinee again in the interpreter.
2156
- IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New (callInstr->GetPrevRealInstrOrLabel ());
2142
+ useCallTargetInstr = IR::ByteCodeUsesInstr::New (callInstr->GetPrevRealInstrOrLabel ());
2157
2143
useCallTargetInstr->SetRemovedOpndSymbol (originalCallTargetOpndIsJITOpt, originalCallTargetStackSym->m_id );
2158
2144
2159
2145
if (inlineCallOpCode == Js::OpCode::InlineArrayPop)
@@ -2451,7 +2437,7 @@ IR::Instr* Inline::InlineApply(IR::Instr *callInstr, const FunctionJITTimeInfo *
2451
2437
2452
2438
// TODO: OOP JIT enable assert (readprocessmemory?)
2453
2439
// Assert((inlineeData->GetFunctionInfo()->GetAttributes() & Js::FunctionInfo::Attributes::BuiltInInlinableAsLdFldInlinee) != 0);
2454
- return InlineApplyWithArray (callInstr, applyData, Js::JavascriptLibrary::GetBuiltInForFuncInfo ( inlineeData-> GetFunctionInfoAddr (), this -> topFunc -> GetThreadContextInfo ()) );
2440
+ return InlineApplyBuiltInTargetWithArray (callInstr, applyData, inlineeData);
2455
2441
}
2456
2442
else
2457
2443
{
@@ -2568,7 +2554,7 @@ IR::Instr * Inline::InlineApplyWithArgumentsObject(IR::Instr * callInstr, IR::In
2568
2554
/*
2569
2555
This method will only do CallDirect style inlining of built-in targets. No script function inlining.
2570
2556
*/
2571
- IR::Instr * Inline::InlineApplyWithArray (IR::Instr * callInstr, const FunctionJITTimeInfo * funcInfo, Js::BuiltinFunction builtInId )
2557
+ IR::Instr * Inline::InlineApplyBuiltInTargetWithArray (IR::Instr * callInstr, const FunctionJITTimeInfo * applyInfo, const FunctionJITTimeInfo * builtInInfo )
2572
2558
{
2573
2559
IR::Instr * implicitThisArgOut = nullptr ;
2574
2560
IR::Instr * explicitThisArgOut = nullptr ;
@@ -2579,8 +2565,25 @@ IR::Instr * Inline::InlineApplyWithArray(IR::Instr * callInstr, const FunctionJI
2579
2565
Assert (implicitThisArgOut);
2580
2566
Assert (explicitThisArgOut);
2581
2567
Assert (arrayArgOut);
2568
+ Js::OpCode originalCallOpcode = callInstr->m_opcode ;
2569
+ IR::Opnd * originalCallSrc1 = callInstr->GetSrc1 ()->Copy (this ->topFunc );
2570
+ IR::AutoReuseOpnd autoReuseOriginalCallSrc1 (originalCallSrc1, this ->topFunc );
2582
2571
2583
- TryFixedMethodAndPrepareInsertionPoint (callInstr, funcInfo, false /* isPolymorphic*/ , true /* isBuiltIn*/ , false /* isCtor*/ , true /* isInlined*/ );
2572
+ IR::Instr* applyLdInstr = nullptr ;
2573
+ IR::Instr* applyTargetLdInstr = nullptr ;
2574
+ if (!TryGetApplyAndTargetLdInstrs (callInstr, &applyLdInstr, &applyTargetLdInstr))
2575
+ {
2576
+ return callInstr;
2577
+ }
2578
+ AnalysisAssert (applyTargetLdInstr != nullptr );
2579
+ // Fixed function/function object checks for target built-in
2580
+ callInstr->ReplaceSrc1 (applyTargetLdInstr->GetDst ());
2581
+ EmitFixedMethodOrFunctionObjectChecksForBuiltIns (callInstr, callInstr, builtInInfo, false /* isPolymorphic*/ , true /* isBuiltIn*/ , false /* isCtor*/ , true /* isInlined*/ );
2582
+
2583
+ // Fixed function/function object checks for .apply
2584
+ callInstr->m_opcode = originalCallOpcode;
2585
+ callInstr->ReplaceSrc1 (originalCallSrc1);
2586
+ EmitFixedMethodOrFunctionObjectChecksForBuiltIns (callInstr, callInstr, applyInfo, false /* isPolymorphic*/ , true /* isBuiltIn*/ , false /* isCtor*/ , true /* isInlined*/ );
2584
2587
2585
2588
IR::Instr* builtInEndInstr = InsertInlineeBuiltInStartEndTags (callInstr, 3 ); // 3 args (implicit this + explicit this + array = 3)
2586
2589
builtInEndInstr->m_opcode = Js::OpCode::InlineNonTrackingBuiltInEnd; // We will call EndTrackCall when we see CallDirect for reasons explained in GlobOpt::TrackCalls
@@ -2608,6 +2611,7 @@ IR::Instr * Inline::InlineApplyWithArray(IR::Instr * callInstr, const FunctionJI
2608
2611
argOut = IR::Instr::New (Js::OpCode::ArgOut_A_InlineSpecialized, linkOpnd, implicitThisArgOut->GetSrc1 (), argOut->GetDst (), callInstr->m_func );
2609
2612
callInstr->InsertBefore (argOut);
2610
2613
2614
+ Js::BuiltinFunction builtInId = Js::JavascriptLibrary::GetBuiltInForFuncInfo (builtInInfo->GetFunctionInfoAddr (), this ->topFunc ->GetThreadContextInfo ());
2611
2615
IR::HelperCallOpnd * helperCallOpnd = nullptr ;
2612
2616
switch (builtInId)
2613
2617
{
@@ -2641,7 +2645,7 @@ IR::Instr * Inline::InlineApplyWithoutArrayArgument(IR::Instr *callInstr, const
2641
2645
Assert (implicitThisArgOut);
2642
2646
Assert (explicitThisArgOut);
2643
2647
2644
- TryFixedMethodAndPrepareInsertionPoint ( callInstr, applyInfo, false /* isPolymorphic*/ , true /* isBuiltIn*/ , false /* isCtor*/ , true /* isInlined*/ );
2648
+ EmitFixedMethodOrFunctionObjectChecksForBuiltIns (callInstr, callInstr, applyInfo, false /* isPolymorphic*/ , true /* isBuiltIn*/ , false /* isCtor*/ , true /* isInlined*/ );
2645
2649
2646
2650
InsertInlineeBuiltInStartEndTags (callInstr, 2 ); // 2 args (implicit this + explicit this)
2647
2651
@@ -2714,6 +2718,22 @@ void Inline::GetArgInstrsForCallAndApply(IR::Instr* callInstr, IR::Instr** impli
2714
2718
linkOpnd->AsRegOpnd ()->m_sym ->m_isInlinedArgSlot = true ;
2715
2719
}
2716
2720
2721
+ bool Inline::TryGetApplyAndTargetLdInstrs (IR::Instr * callInstr, _Outptr_result_maybenull_ IR::Instr ** applyLdInstr, _Outptr_result_maybenull_ IR::Instr ** applyTargetLdInstr)
2722
+ {
2723
+ IR::Opnd* applyOpnd = callInstr->GetSrc1 ();
2724
+ Assert (applyOpnd->IsRegOpnd ());
2725
+ StackSym* applySym = applyOpnd->AsRegOpnd ()->m_sym ->AsStackSym ();
2726
+ if (!applySym->IsSingleDef ())
2727
+ {
2728
+ *applyLdInstr = nullptr ;
2729
+ *applyTargetLdInstr = nullptr ;
2730
+ return false ;
2731
+ }
2732
+ *applyLdInstr = applySym->GetInstrDef ();;
2733
+ *applyTargetLdInstr = (*applyLdInstr)->m_prev ;
2734
+ return true ;
2735
+ }
2736
+
2717
2737
/*
2718
2738
This method only inlines targets which are script functions, under the
2719
2739
condition that the second argument (if any) passed to apply is arguments object.
@@ -2735,16 +2755,14 @@ bool Inline::InlineApplyScriptTarget(IR::Instr *callInstr, const FunctionJITTime
2735
2755
2736
2756
// Begin inlining apply target
2737
2757
2738
- IR::Opnd* applyOpnd = callInstr->GetSrc1 ();
2739
- Assert (applyOpnd->IsRegOpnd ());
2740
- StackSym* applySym = applyOpnd->AsRegOpnd ()->m_sym ->AsStackSym ();
2741
- if (!applySym->IsSingleDef ())
2758
+ IR::Instr* applyLdInstr = nullptr ;
2759
+ IR::Instr* applyTargetLdInstr = nullptr ;
2760
+ if (!TryGetApplyAndTargetLdInstrs (callInstr, &applyLdInstr, &applyTargetLdInstr))
2742
2761
{
2743
2762
return false ;
2744
2763
}
2745
- IR::Instr* applyLdInstr = applySym->GetInstrDef ();
2746
- IR::Instr* applyTargetLdInstr = applyLdInstr->m_prev ;
2747
-
2764
+ AnalysisAssert (applyTargetLdInstr != nullptr );
2765
+
2748
2766
if (applyTargetLdInstr->m_opcode != Js::OpCode::LdFldForCallApplyTarget ||
2749
2767
((applyTargetLdInstr->AsProfiledInstr ()->u .FldInfo ().flags & Js::FldInfo_FromAccessor) != 0 ))
2750
2768
{
@@ -3008,7 +3026,7 @@ Inline::InlineCall(IR::Instr *callInstr, const FunctionJITTimeInfo *funcInfo, co
3008
3026
3009
3027
IR::SymOpnd* orgLinkOpnd = callInstr->GetSrc2 ()->AsSymOpnd ();
3010
3028
3011
- TryFixedMethodAndPrepareInsertionPoint ( callInstr, funcInfo, false /* isPolymorphic*/ , true /* isBuiltIn*/ , false /* isCtor*/ , true /* isInlined*/ );
3029
+ EmitFixedMethodOrFunctionObjectChecksForBuiltIns (callInstr, callInstr, funcInfo, false /* isPolymorphic*/ , true /* isBuiltIn*/ , false /* isCtor*/ , true /* isInlined*/ );
3012
3030
3013
3031
InsertInlineeBuiltInStartEndTags (callInstr, actualCount);
3014
3032
@@ -4330,26 +4348,29 @@ Inline::PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *f
4330
4348
return primaryBailOutInstr;
4331
4349
}
4332
4350
4333
- void
4334
- Inline::TryFixedMethodAndPrepareInsertionPoint (IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined)
4351
+ IR::ByteCodeUsesInstr*
4352
+ Inline::EmitFixedMethodOrFunctionObjectChecksForBuiltIns (IR::Instr *callInstr, IR::Instr * funcObjCheckInsertInstr , const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined)
4335
4353
{
4336
4354
StackSym* originalCallTargetStackSym = callInstr->GetSrc1 ()->GetStackSym ();
4337
4355
bool originalCallTargetIsJITOpt = callInstr->GetSrc1 ()->GetIsJITOptimizedReg ();
4338
4356
4357
+ IR::ByteCodeUsesInstr * useCallTargetInstr = nullptr ;
4339
4358
bool safeThis = false ;
4340
4359
if (TryOptimizeCallInstrWithFixedMethod (callInstr, inlineeInfo, isPolymorphic, isBuiltIn, isCtor, isInlined, safeThis))
4341
4360
{
4342
4361
Assert (callInstr->m_opcode == Js::OpCode::CallIFixed);
4343
-
4362
+ Assert (callInstr-> GetFixedFunction ()-> GetFuncInfoAddr () == inlineeInfo-> GetFunctionInfoAddr ());
4344
4363
// 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.
4345
- IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New (callInstr);
4364
+ useCallTargetInstr = IR::ByteCodeUsesInstr::New (callInstr);
4346
4365
useCallTargetInstr->SetRemovedOpndSymbol (originalCallTargetIsJITOpt, originalCallTargetStackSym->m_id );
4347
4366
callInstr->InsertBefore (useCallTargetInstr);
4348
4367
}
4349
4368
else
4350
4369
{
4351
- PrepareInsertionPoint (callInstr, inlineeInfo, callInstr);
4370
+ IR::BailOutInstr * bailOutInstr = IR::BailOutInstr::New (Js::OpCode::BailOnNotBuiltIn, IR::BailOutOnInlineFunction, callInstr, callInstr->m_func );
4371
+ InsertFunctionObjectCheck (callInstr, funcObjCheckInsertInstr, bailOutInstr, inlineeInfo);
4352
4372
}
4373
+ return useCallTargetInstr;
4353
4374
}
4354
4375
4355
4376
uint Inline::CountActuals (IR::Instr *callInstr)
0 commit comments