You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When crossgen'ing an assembly for the browser/wasm target, compilation of a method that makes an unresolvable virtual call to a method whose declaring type lives in another version bubble (e.g. a System.Private.CoreLib type) fails in the ReadyToRun front-end with:
System.NotImplementedException: [S.P.CoreLib]System.Reflection.MemberInfo
at ILCompiler.DependencyAnalysis.ReadyToRun.ModuleTokenResolver.GetModuleTokenForType(...) ModuleTokenResolver.cs:92
at ILCompiler.DependencyAnalysis.ReadyToRun.SignatureContext.GetTargetModule(...)
at ILCompiler.DependencyAnalysis.ReadyToRun.TypeFixupSignature.GetData(...)
at ILCompiler.DependencyAnalysis.ReadyToRun.ImportSectionNode.MaterializeSignature(...)
This is wasm-target-specific — the identical crossgen of the same assembly for x64 succeeds.
Repro
Found while crossgen'ing xunit.runner.utility.netcoreapp10.dll from a CoreCLR wasm test Core_Root.
Minimal single-method repro:
GetAvailableRunnerReporters contains callvirt System.Reflection.MemberInfo::get_Name() on a System.Type value that the JIT cannot devirtualize (the declaring method is not in the version bubble).
Root cause
The wasm JIT lowers the unresolved virtual call through the generic CORINFO_HELP_VIRTUAL_FUNC_PTR helper, which embeds the declaring type's handle:
// src/coreclr/jit/importer.cpp (~2732)// Wasm R2R cannot use the CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR fast path because it// relies on DelayLoad_Helper_Obj dynamic-helper thunks, which are not implemented on wasm.// Fall through to the runtime CORINFO_HELP_VIRTUAL_FUNC_PTR helper instead.#if defined(FEATURE_READYTORUN) && !defined(TARGET_WASM)
elseif (IsAot()) { ... CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR ... } // method-keyed fast path#endifif (call==nullptr) {
GenTree*exactTypeDesc=impParentClassTokenToHandle(pResolvedToken); // <-- embeds MemberInfoGenTree*exactMethodDesc=impTokenToHandle(pResolvedToken);
call=gtNewVirtualFunctionLookupHelperCallNode(CORINFO_HELP_VIRTUAL_FUNC_PTR, TYP_I_IMPL,
thisPtr, exactMethodDesc, exactTypeDesc);
}
On non-wasm R2R, IsAot() takes the CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR fast path, which is
keyed on the method (an entry-point fixup) and never needs the declaring type handle. Wasm is
explicitly excluded from that path (!defined(TARGET_WASM), because the required DelayLoad_Helper_Obj
thunks aren't implemented on wasm), so it falls through and embeds exactTypeDesc = impParentClassTokenToHandle(...) = the declaring type, System.Reflection.MemberInfo.
That handle becomes a TypeHandleTypeFixupSignature. When crossgen2 materializes the import section, ModuleTokenResolver.GetModuleTokenForType(MemberInfo) can't reverse-map MemberInfo to a module token
— the consuming assembly (xunit.runner.utility) has no TypeRef for MemberInfo (it references it
only transitively via the System.Type → get_NameMemberRef), and it isn't in the version bubble —
so it throws NotImplementedException.
JIT dump of the call site:
CALL help CORINFO_HELP_VIRTUAL_FUNC_PTR
this: LCL_VAR ref V15
arg1: IND(CNS_INT(h) 0x4204D8 class) ← MemberInfo type handle (the fixup that fails)
meth hnd: IND(CNS_INT(h) 0x4204E0 token)
Why x64 is unaffected
x64 R2R uses the method-keyed fast path (or virtual stub dispatch); the fixup references the (tokenizable) get_NameMemberRef, never the declaring type MemberInfo, so there is nothing to fail on.
Impact
Any wasm R2R compilation of a method that makes a non-devirtualizable virtual/interface call to a method
whose declaring type is cross-version-bubble and not otherwise TypeRef'd by the consuming assembly will
fail crossgen. Calls to System.Object/MemberInfo/etc. virtual members on framework types are common,
so this is likely to be hit broadly once more wasm R2R assemblies are compiled.
Related
Same underlying gap (missing wasm DelayLoad_Helper_Obj / VirtualFunctionPointer R2R support) as the
runtime traps previously seen for cross-module virtual dispatch on wasm (e.g. the Runtime_45250 / address_d cases). Here it surfaces at crossgen time as a token-resolution failure rather than a runtime
trap.
Note
This issue was drafted with the assistance of GitHub Copilot.
Description
When crossgen'ing an assembly for the
browser/wasmtarget, compilation of a method that makes anunresolvable virtual call to a method whose declaring type lives in another version bubble (e.g. a
System.Private.CoreLibtype) fails in the ReadyToRun front-end with:This is wasm-target-specific — the identical crossgen of the same assembly for
x64succeeds.Repro
Found while crossgen'ing
xunit.runner.utility.netcoreapp10.dllfrom a CoreCLR wasm testCore_Root.Minimal single-method repro:
GetAvailableRunnerReporterscontainscallvirt System.Reflection.MemberInfo::get_Name()on aSystem.Typevalue that the JIT cannot devirtualize (the declaring method is not in the version bubble).Root cause
The wasm JIT lowers the unresolved virtual call through the generic
CORINFO_HELP_VIRTUAL_FUNC_PTRhelper, which embeds the declaring type's handle:On non-wasm R2R,
IsAot()takes theCORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTRfast path, which iskeyed on the method (an entry-point fixup) and never needs the declaring type handle. Wasm is
explicitly excluded from that path (
!defined(TARGET_WASM), because the requiredDelayLoad_Helper_Objthunks aren't implemented on wasm), so it falls through and embeds
exactTypeDesc=impParentClassTokenToHandle(...)= the declaring type,System.Reflection.MemberInfo.That handle becomes a
TypeHandleTypeFixupSignature. When crossgen2 materializes the import section,ModuleTokenResolver.GetModuleTokenForType(MemberInfo)can't reverse-mapMemberInfoto a module token— the consuming assembly (
xunit.runner.utility) has noTypeRefforMemberInfo(it references itonly transitively via the
System.Type→get_NameMemberRef), and it isn't in the version bubble —so it throws
NotImplementedException.JIT dump of the call site:
Why x64 is unaffected
x64 R2R uses the method-keyed fast path (or virtual stub dispatch); the fixup references the (tokenizable)
get_NameMemberRef, never the declaring typeMemberInfo, so there is nothing to fail on.Impact
Any wasm R2R compilation of a method that makes a non-devirtualizable virtual/interface call to a method
whose declaring type is cross-version-bubble and not otherwise
TypeRef'd by the consuming assembly willfail crossgen. Calls to
System.Object/MemberInfo/etc. virtual members on framework types are common,so this is likely to be hit broadly once more wasm R2R assemblies are compiled.
Related
Same underlying gap (missing wasm
DelayLoad_Helper_Obj/VirtualFunctionPointerR2R support) as theruntime traps previously seen for cross-module virtual dispatch on wasm (e.g. the
Runtime_45250/address_dcases). Here it surfaces at crossgen time as a token-resolution failure rather than a runtimetrap.
Note
This issue was drafted with the assistance of GitHub Copilot.