@@ -18480,13 +18480,12 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
18480
18480
// Fetch the method that would be called based on the declared type of 'this'
18481
18481
CORINFO_METHOD_HANDLE derivedMethod = info.compCompHnd->resolveVirtualMethod(baseMethod, objClass);
18482
18482
18483
- // Bail if we can't get method info for the derived method
18484
- CORINFO_METHOD_INFO methInfo;
18485
- const bool hasInfo = info.compCompHnd->getMethodInfo(derivedMethod, &methInfo);
18486
-
18487
- if (!hasInfo)
18483
+ // If we failed to get a handle, we can't devirtualize. This can
18484
+ // happen when prejitting, if the devirtualization crosses
18485
+ // servicing bubble boundaries.
18486
+ if (derivedMethod == nullptr)
18488
18487
{
18489
- JITDUMP("--- no method info , sorry\n");
18488
+ JITDUMP("--- no derived method , sorry\n");
18490
18489
return;
18491
18490
}
18492
18491
@@ -18507,88 +18506,66 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
18507
18506
}
18508
18507
#endif // defined(DEBUG)
18509
18508
18510
- // Verify we can inline -- both because we'll want to try and
18511
- // inline if we devirtualize, and also because this appropriately
18512
- // safeguards servicing bubbles.
18513
- //
18514
- // Note we may want to devirtualize even if we can't inline, but
18515
- // unfortunately today we can't distinguish between inlines that
18516
- // are marked noinline for perf reasons versus non-perf reasons.
18517
- // So we have to assume the worst.
18518
- //
18519
- // For instance when crossgenning corelib, we initially allow
18520
- // devirt of StringBuilder.ToString, but once we generate code for
18521
- // it we think it is a poor inline candidate, and mark it as
18522
- // noinline, and after that we refuse to devirtualize calls.
18523
- DWORD restrictions = 0;
18524
- CorInfoInline vmResult = info.compCompHnd->canInline(info.compMethodHnd, derivedMethod, &restrictions);
18525
-
18526
- if ((vmResult == INLINE_PASS) && (restrictions == 0))
18509
+ if (objClassIsFinal || derivedMethodIsFinal)
18527
18510
{
18528
- if (objClassIsFinal || derivedMethodIsFinal)
18529
- {
18530
- JITDUMP("!!! Inlining ok, no restrictions, final; can devirtualize\n");
18511
+ JITDUMP("!!! Inlining ok, no restrictions, final; can devirtualize\n");
18512
+ printf("!!! Inlining ok, no restrictions, final; can devirtualize\n");
18531
18513
18532
- // Make the updates.
18533
- call->gtFlags &= ~GTF_CALL_VIRT_VTABLE;
18534
- call->gtFlags &= ~GTF_CALL_VIRT_STUB;
18535
- call->gtCallMethHnd = derivedMethod;
18514
+ // Make the updates.
18515
+ call->gtFlags &= ~GTF_CALL_VIRT_VTABLE;
18516
+ call->gtFlags &= ~GTF_CALL_VIRT_STUB;
18517
+ call->gtCallMethHnd = derivedMethod;
18536
18518
18537
- // Need to update call info too. This is fragile
18538
- // but hopefully the derived method conforms to
18539
- // the base in most other ways.
18540
- callInfo->hMethod = derivedMethod;
18541
- callInfo->methodFlags = derivedMethodAttribs;
18519
+ // Need to update call info too. This is fragile
18520
+ // but hopefully the derived method conforms to
18521
+ // the base in most other ways.
18522
+ callInfo->hMethod = derivedMethod;
18523
+ callInfo->methodFlags = derivedMethodAttribs;
18542
18524
18543
- // Clear the inline candidate info (may be non-null since
18544
- // it's a union field used for other things by virtual
18545
- // stubs)
18546
- call->gtInlineCandidateInfo = nullptr;
18525
+ // Clear the inline candidate info (may be non-null since
18526
+ // it's a union field used for other things by virtual
18527
+ // stubs)
18528
+ call->gtInlineCandidateInfo = nullptr;
18547
18529
18548
18530
#ifdef FEATURE_READYTORUN_COMPILER
18549
- if (opts.IsReadyToRun())
18550
- {
18551
- // We should refetch the lookup value from the VM.
18552
- call->setEntryPoint(callInfo->codePointerLookup.constLookup);
18553
- call->gtCallMoreFlags &= ~GTF_CALL_M_VIRTSTUB_REL_INDIRECT;
18554
- }
18531
+ if (opts.IsReadyToRun())
18532
+ {
18533
+ // We should refetch the lookup value from the VM.
18534
+ call->setEntryPoint(callInfo->codePointerLookup.constLookup);
18535
+ call->gtCallMoreFlags &= ~GTF_CALL_M_VIRTSTUB_REL_INDIRECT;
18536
+ }
18555
18537
#endif
18556
18538
18557
- // Note this may not equal objClass, if there is a
18558
- // final method that objClass inherits.
18559
- CORINFO_CLASS_HANDLE derivedClass = info.compCompHnd->getMethodClass(derivedMethod);
18539
+ // Note this may not equal objClass, if there is a
18540
+ // final method that objClass inherits.
18541
+ CORINFO_CLASS_HANDLE derivedClass = info.compCompHnd->getMethodClass(derivedMethod);
18560
18542
18561
- // Really should just re-invoke getCallInfo...
18562
- callInfo->contextHandle = MAKE_CLASSCONTEXT(derivedClass);
18543
+ // Really should just re-invoke getCallInfo...
18544
+ callInfo->contextHandle = MAKE_CLASSCONTEXT(derivedClass);
18563
18545
18564
- // Update context handle too...
18565
- *exactContextHandle = MAKE_CLASSCONTEXT(derivedClass);
18546
+ // Update context handle too...
18547
+ *exactContextHandle = MAKE_CLASSCONTEXT(derivedClass);
18566
18548
18567
18549
#if defined(DEBUG)
18568
- if (verbose)
18569
- {
18570
- printf("... after devirt...\n");
18571
- gtDispTree(call);
18572
- }
18573
- #endif // defined(DEBUG)
18574
- }
18575
- else
18550
+ if (verbose)
18576
18551
{
18577
- // Neither class or method is final.
18578
- //
18579
- // We could speculatively devirtualize, but there's no
18580
- // reason to believe the derived method is the one that
18581
- // is likely to be invoked.
18582
- //
18583
- // If there's currently no further overriding (that is, at
18584
- // the time of jitting, objClass has no subclasses that
18585
- // override this method), then perhaps we'd be willing to
18586
- // make a bet...?
18587
- JITDUMP("??? Inlining ok, no restrictions, NOT final; speculative\n");
18552
+ printf("... after devirt...\n");
18553
+ gtDispTree(call);
18588
18554
}
18555
+ #endif // defined(DEBUG)
18589
18556
}
18590
18557
else
18591
18558
{
18592
- JITDUMP("--- can't inline (%d) or has restrictions (%d), sorry\n", vmResult, restrictions);
18559
+ // Neither class or method is final.
18560
+ //
18561
+ // We could speculatively devirtualize, but there's no
18562
+ // reason to believe the derived method is the one that
18563
+ // is likely to be invoked.
18564
+ //
18565
+ // If there's currently no further overriding (that is, at
18566
+ // the time of jitting, objClass has no subclasses that
18567
+ // override this method), then perhaps we'd be willing to
18568
+ // make a bet...?
18569
+ JITDUMP("??? NOT final; speculative devirt?\n");
18593
18570
}
18594
18571
}
0 commit comments