@@ -18407,20 +18407,27 @@ bool Compiler::IsMathIntrinsic(GenTreePtr tree)
18407
18407
// Arguments:
18408
18408
// call -- the call node to examine/modify
18409
18409
// thisObj -- the value of 'this' for the call
18410
- // callInfo -- info about the call from the VM
18410
+ // callInfo -- [IN/OUT] info about the call from the VM
18411
18411
// exactContextHnd -- [OUT] updated context handle iff call devirtualized
18412
18412
//
18413
18413
// Notes:
18414
18414
// Virtual calls in IL will always "invoke" the base class method.
18415
18415
//
18416
18416
// This transformation looks for evidence that the type of 'this'
18417
- // in the call is a final class or would invoke a final method, and
18418
- // if that and other safety checks pan out, modifies the call and
18419
- // the call info to create a direct call.
18417
+ // in the call is exactly known, is a final class or would invoke
18418
+ // a final method, and if that and other safety checks pan out,
18419
+ // modifies the call and the call info to create a direct call.
18420
18420
//
18421
- // This transformation is done in the importer and not in some
18422
- // subsequent optimization pass because we want it to be upstream
18423
- // of inline candidate identification.
18421
+ // This transformation is initially done in the importer and not
18422
+ // in some subsequent optimization pass because we want it to be
18423
+ // upstream of inline candidate identification.
18424
+ //
18425
+ // However, later phases may supply improved type information that
18426
+ // can enable further devirtualization. We currently reinvoke this
18427
+ // code after inlining, if the return value of the inlined call is
18428
+ // the 'this obj' of a subsequent virtual call.
18429
+
18430
+ #if COR_JIT_EE_VERSION > 460
18424
18431
18425
18432
void Compiler::impDevirtualizeCall(GenTreeCall* call,
18426
18433
GenTreePtr thisObj,
@@ -18454,51 +18461,18 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
18454
18461
18455
18462
// Do we know anything about the type of the 'this'?
18456
18463
//
18457
- // Unfortunately the jit tends to only keep track of class handles
18458
- // for struct types, so the type information needed here is
18459
- // missing for most tree nodes. We can add it back selectively,
18460
- // but care is needed: the presence of the class handle is often
18461
- // used to infer struct-ness.
18462
- //
18463
- // A rough accounting in corelib shows this breakdown for node types
18464
- // seen as 'this' obj in vtable calls is as follows:
18465
- //
18466
- // Node Type Count HasType
18467
- // lclVar 4256 3825
18468
- // field 1098 1098
18469
- // retExp 864
18470
- // intrin 318
18471
- // helper 294
18472
- // callv-vtbl 224
18473
- // [] 123
18474
- // call 61
18475
- // box 60
18476
- // call-nchk 27
18477
- // callv-stub 5
18478
- //
18479
- // Note some lclVars are missing class handles; presumably these
18480
- // are locals introduced by the compiler. We might be able to add
18481
- // in type info for them. The table above gives a rough priority
18482
- // order for adding type support.
18464
+ // Unfortunately the jit has historcally only kept track of class
18465
+ // handles for struct types, so the type information needed here
18466
+ // is missing for many tree nodes.
18483
18467
//
18484
18468
// Even when we can deduce the type, we may not be able to
18485
18469
// devirtualize, but if we can't deduce the type, we can't do
18486
18470
// anything.
18487
- //
18488
- // In corelib, devirtualization happens roughly 5% of the time,
18489
- // that is, out of 8014 virtual call sites, we devirtualize at
18490
- // 453. Assuming we could fill in missing types, devirtualization
18491
- // might ultimately kick in for around ~10% of virtual call sites.
18492
- //
18493
- // To get beyond that we'd need to do something speculative,
18494
- // either by adding runtime type tests into the jitted code, or by
18495
- // adding the ability to pitch and replace code to safely undo
18496
- // assumptions made about class hierarchy.
18497
- CORINFO_CLASS_HANDLE objClass = nullptr;
18498
- GenTreePtr obj = thisObj->gtEffectiveVal(false);
18499
- const genTreeOps objOp = obj->OperGet();
18500
- bool nullCheck = true;
18501
- bool isExact = false;
18471
+ CORINFO_CLASS_HANDLE objClass = nullptr;
18472
+ GenTreePtr obj = thisObj->gtEffectiveVal(false);
18473
+ const genTreeOps objOp = obj->OperGet();
18474
+ bool objIsNonNull = false;
18475
+ bool isExact = false;
18502
18476
18503
18477
switch (objOp)
18504
18478
{
@@ -18548,8 +18522,8 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
18548
18522
18549
18523
case GT_CNS_STR:
18550
18524
{
18551
- objClass = impGetStringClass();
18552
- nullCheck = false ;
18525
+ objClass = impGetStringClass();
18526
+ objIsNonNull = true ;
18553
18527
break;
18554
18528
}
18555
18529
@@ -18689,10 +18663,8 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
18689
18663
call->gtCallType = CT_USER_FUNC;
18690
18664
18691
18665
// Virtual calls include an implicit null check, which we may
18692
- // now need to make explicit. Not sure yet if we can restrict
18693
- // this to just a subset or need to do it for all cases, so
18694
- // will do it for all unless we know the object is not null.
18695
- if (nullCheck)
18666
+ // now need to make explicit.
18667
+ if (!objIsNonNull)
18696
18668
{
18697
18669
call->gtFlags |= GTF_CALL_NULLCHECK;
18698
18670
}
@@ -18742,7 +18714,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
18742
18714
callInfo->methodFlags = derivedMethodAttribs;
18743
18715
callInfo->contextHandle = MAKE_METHODCONTEXT(derivedMethod);
18744
18716
18745
- // Update context handle too.. .
18717
+ // Update context handle.
18746
18718
if ((exactContextHandle != nullptr) && (*exactContextHandle != nullptr))
18747
18719
{
18748
18720
*exactContextHandle = MAKE_METHODCONTEXT(derivedMethod);
@@ -18762,3 +18734,16 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
18762
18734
}
18763
18735
#endif // defined(DEBUG)
18764
18736
}
18737
+
18738
+ #else
18739
+
18740
+ // Stubbed out implementation for 4.6 compatjit
18741
+ void Compiler::impDevirtualizeCall(GenTreeCall* call,
18742
+ GenTreePtr thisObj,
18743
+ CORINFO_CALL_INFO* callInfo,
18744
+ CORINFO_CONTEXT_HANDLE* exactContextHandle)
18745
+ {
18746
+ return;
18747
+ }
18748
+
18749
+ #endif // COR_JIT_EE_VERSION > 460
0 commit comments