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
{{ message }}
Repository navigation
[wasm] CORINFO_HELP_CHECK_OBJ is modeled TYP_VOID in fgMorphInit but JIT_CheckObj returns Object* #131378
CORINFO_HELP_CHECK_OBJ is implemented as HCIMPL1_RAW(Object*, JIT_CheckObj, Object* obj) in src/coreclr/vm/jithelpers.cpp — it returns Object*. The JIT models it inconsistently:
src/coreclr/jit/morph.cpp (fgMorphInit, argument check): gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_VOID, op) — models a value-returning helper as void.
On register-based targets the second form is benign (the returned reference is simply left in the return register and dropped). On wasm the call_indirect / call signature is derived from the JIT-modeled return type in CodeGen::genCallInstruction, so a TYP_VOID model for a value-returning helper emits a mismatched signature and the engine traps with function signature mismatch — the same class of defect as #130813 and the inline-unbox slow-path helper.
This only fires under DOTNET_JitGCChecks=1 (opts.compGcChecks) in a Debug/Checked JIT, so it is low severity, but it is the same modeling bug and is cheap to fix.
Reproduction Steps
Checked/Debug JIT, DOTNET_JitGCChecks=1, wasm target, on any method with a TYP_REF argument.
Expected behavior
The helper is modeled with a return type matching JIT_CheckObj (TYP_REF), and the unused result is discarded (e.g. via gtUnusedValNode) so the enclosing statement stays void.
Actual behavior
fgMorphInit creates the call as TYP_VOID; on wasm the emitted call signature does not match the helper.
Correction to the original report: this issue overstates the impact. The modeling bug is real, but the function signature mismatch trap I described is not reachable.
CORINFO_HELP_CHECK_OBJ is not handled anywhere in CorInfoImpl.ReadyToRun.cs. It falls through to default: throw new NotImplementedException, and it is not in the graceful RequiresRuntimeJitException list either. So any method that would emit CHECK_OBJ fails R2R codegen outright, on every target, before return-arity modeling ever reaches call_indirect emission:
ILCompiler.CodeGenerationFailedException: Code generation failed for method 'GcCheck.Foo(object)'
---> System.NotImplementedException: CORINFO_HELP_CHECK_OBJ
at CorInfoImpl.GetHelperFtnUncached(...) CorInfoImpl.ReadyToRun.cs:1342
Confirmed by building a Checked wasm JIT (which does insert CHECK_OBJ under JitGCChecks), deploying it to a Checked crossgen2, and attempting to compile a trivial static void Foo(object o) with --codegenopt:JitGCChecks=1.
So there is no R2R image that can contain a CHECK_OBJ call, and wasm has no runtime JIT (R2R + interpreter only), so there is no other path where the wrong return arity would bite. The interpreter does not derive a call signature from the modeled return type.
What remains accurate:
fgMorphInit models the helper TYP_VOID while JIT_CheckObj returns Object* (vm/jithelpers.cpp:1210).
importer.cpp already models the same helper TYP_REF, so the two sites disagree.
The fix in #131383 is therefore defensive: it aligns the model with the helper's real return type and with the importer, and would become live if CHECK_OBJ ever gains R2R support. It should not be treated as fixing an observable trap, and this issue is not a good candidate for a regression test — there is nothing to reproduce.
Note
This comment was created with assistance from GitHub Copilot (AI).
Activity
dotnet-policy-service commentedon Jul 26, 2026
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.
dotnet-policy-service commentedon Jul 26, 2026
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.
lewing commentedon Jul 26, 2026
Correction to the original report: this issue overstates the impact. The modeling bug is real, but the
function signature mismatchtrap I described is not reachable.CORINFO_HELP_CHECK_OBJis not handled anywhere inCorInfoImpl.ReadyToRun.cs. It falls through todefault: throw new NotImplementedException, and it is not in the gracefulRequiresRuntimeJitExceptionlist either. So any method that would emitCHECK_OBJfails R2R codegen outright, on every target, before return-arity modeling ever reachescall_indirectemission:Confirmed by building a Checked wasm JIT (which does insert
CHECK_OBJunderJitGCChecks), deploying it to a Checked crossgen2, and attempting to compile a trivialstatic void Foo(object o)with--codegenopt:JitGCChecks=1.So there is no R2R image that can contain a
CHECK_OBJcall, and wasm has no runtime JIT (R2R + interpreter only), so there is no other path where the wrong return arity would bite. The interpreter does not derive a call signature from the modeled return type.What remains accurate:
fgMorphInitmodels the helperTYP_VOIDwhileJIT_CheckObjreturnsObject*(vm/jithelpers.cpp:1210).importer.cppalready models the same helperTYP_REF, so the two sites disagree.The fix in #131383 is therefore defensive: it aligns the model with the helper's real return type and with the importer, and would become live if
CHECK_OBJever gains R2R support. It should not be treated as fixing an observable trap, and this issue is not a good candidate for a regression test — there is nothing to reproduce.Note
This comment was created with assistance from GitHub Copilot (AI).
JulieLeeMSFT commentedon Jul 27, 2026
@AndyAyersMS, PTAL. CC @adamperlin.
[wasm] Fix JIT helper calls modeled with the wrong return arity (dotn…