From 80ed48bcf7b7129ed513b870f6bbd280acb3706b Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Wed, 15 Jul 2026 14:20:59 -0500 Subject: [PATCH 1/4] [wasi][prototype] Model wasm class-init helper as value-returning in the JIT Completes gate #2 (91d9e36f660). That change made corelib InitClass/ InitInstantiatedClass (InitHelpers.cs) return void* so the compiled call_indirect signature matches the interpreter's value-returning portable entry point convention, but the JIT caller side still typed CORINFO_HELP_INITCLASS/INITINSTCLASS as TYP_VOID. On wasm the R2R caller therefore emitted a (...)->() call_indirect while the runtime dispatches the cold class-init through the i32-returning thunk, trapping with "function signature mismatch" on the first R2R class-init. Model the class-init helpers as value-returning (TYP_I_IMPL) on wasm at the five sites that create them (fgGetStaticsCCtorHelper, impInitClass runtime lookup, and the three fgInitThisClass generic-lookup cases). The helper result is pushed and discarded via the existing unused-value drop in wasm codegen. Fixes the residual overflow bucket of #129622 (conv_ovf, 127931, indexMinusOne now pass under R2R in both interpreted- and R2R-corelib configs) and removes the class-init signature-mismatch trap in #130634. No regression in the previously passing type-load tests. Prototype-only; for the future WASI R2R PR. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2902374a-f352-4c46-bcec-8a35c97733ae --- src/coreclr/jit/compiler.h | 12 ++++++++++++ src/coreclr/jit/flowgraph.cpp | 2 +- src/coreclr/jit/importer.cpp | 2 +- src/coreclr/jit/morph.cpp | 7 ++++--- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index b2acfa5e21f7db..aa65b6b888a994 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3358,6 +3358,18 @@ class Compiler GenTreeCall* gtNewHelperCallNode( unsigned helper, var_types type, GenTree* arg1 = nullptr, GenTree* arg2 = nullptr, GenTree* arg3 = nullptr, GenTree* arg4 = nullptr); + // Return type used when creating the class-init helper calls (CORINFO_HELP_INITCLASS/INITINSTCLASS). + // On wasm these helpers must be modeled as value-returning so the compiled call_indirect signature + // matches the callee: InitHelpers.InitClass/InitInstantiatedClass return void* (a dummy value) to match + // the interpreter's value-returning portable-entry-point convention. The JIT pushes and then discards + // the result (see the unused-value drop in CodeGen::WasmProduceReg). This modeling therefore depends on + // that CoreLib signature and must land together with it. Other targets model these helpers as void. +#ifdef TARGET_WASM + static constexpr var_types HelperInitClassRetType = TYP_I_IMPL; +#else + static constexpr var_types HelperInitClassRetType = TYP_VOID; +#endif + GenTreeCall* gtNewVirtualFunctionLookupHelperCallNode( unsigned helper, var_types type, GenTree* thisPtr, GenTree* methHnd, GenTree* clsHnd = nullptr); diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 8d0eb82c81e30c..b739e35823d627 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -766,7 +766,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo break; case CORINFO_HELP_INITCLASS: - type = TYP_VOID; + type = HelperInitClassRetType; break; default: diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index f15a3409cbd529..90396e6a294bc5 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3909,7 +3909,7 @@ GenTree* Compiler::impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken) if (runtimeLookup) { - node = gtNewHelperCallNode(CORINFO_HELP_INITCLASS, TYP_VOID, node); + node = gtNewHelperCallNode(CORINFO_HELP_INITCLASS, HelperInitClassRetType, node); } else { diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 0300e8a5f1ea2d..5f3d7ff033e4e9 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -14565,21 +14565,22 @@ GenTree* Compiler::fgInitThisClass() vtTree = gtNewMethodTableLookup(vtTree); GenTree* methodHnd = gtNewIconEmbMethHndNode(info.compMethodHnd); - return gtNewHelperCallNode(CORINFO_HELP_INITINSTCLASS, TYP_VOID, vtTree, methodHnd); + return gtNewHelperCallNode(CORINFO_HELP_INITINSTCLASS, HelperInitClassRetType, vtTree, methodHnd); } case CORINFO_LOOKUP_CLASSPARAM: { GenTree* vtTree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL); vtTree->gtFlags |= GTF_VAR_CONTEXT; - return gtNewHelperCallNode(CORINFO_HELP_INITCLASS, TYP_VOID, vtTree); + return gtNewHelperCallNode(CORINFO_HELP_INITCLASS, HelperInitClassRetType, vtTree); } case CORINFO_LOOKUP_METHODPARAM: { GenTree* methHndTree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL); methHndTree->gtFlags |= GTF_VAR_CONTEXT; - return gtNewHelperCallNode(CORINFO_HELP_INITINSTCLASS, TYP_VOID, gtNewIconNode(0), methHndTree); + return gtNewHelperCallNode(CORINFO_HELP_INITINSTCLASS, HelperInitClassRetType, gtNewIconNode(0), + methHndTree); } default: From 22d665a5582f3ced802c52201fd6064760d9c239 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Wed, 15 Jul 2026 19:51:17 -0500 Subject: [PATCH 2/4] Address review: trim class-init helper return-type comment Per review feedback, condense the HelperInitClassRetType comment to the essential point (on wasm these helpers return void*, so model them as value-returning to match the callee) plus the CoreLib-dependency note. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2902374a-f352-4c46-bcec-8a35c97733ae --- src/coreclr/jit/compiler.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index aa65b6b888a994..6da0f22d1eea97 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3358,12 +3358,8 @@ class Compiler GenTreeCall* gtNewHelperCallNode( unsigned helper, var_types type, GenTree* arg1 = nullptr, GenTree* arg2 = nullptr, GenTree* arg3 = nullptr, GenTree* arg4 = nullptr); - // Return type used when creating the class-init helper calls (CORINFO_HELP_INITCLASS/INITINSTCLASS). - // On wasm these helpers must be modeled as value-returning so the compiled call_indirect signature - // matches the callee: InitHelpers.InitClass/InitInstantiatedClass return void* (a dummy value) to match - // the interpreter's value-returning portable-entry-point convention. The JIT pushes and then discards - // the result (see the unused-value drop in CodeGen::WasmProduceReg). This modeling therefore depends on - // that CoreLib signature and must land together with it. Other targets model these helpers as void. + // On wasm these helpers return void* (InitHelpers.InitClass/InitInstantiatedClass), so model them as + // value-returning to match the callee's call_indirect signature; must land with that CoreLib change. #ifdef TARGET_WASM static constexpr var_types HelperInitClassRetType = TYP_I_IMPL; #else From 637fb5e2d0aa740b10573f80390031a62f86c5e7 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Tue, 21 Jul 2026 19:21:30 -0500 Subject: [PATCH 3/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/coreclr/jit/compiler.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 20c8855351e7da..91999a1fe07a28 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3358,9 +3358,8 @@ class Compiler GenTreeCall* gtNewHelperCallNode( unsigned helper, var_types type, GenTree* arg1 = nullptr, GenTree* arg2 = nullptr, GenTree* arg3 = nullptr, GenTree* arg4 = nullptr); - // On wasm these helpers return void* (InitHelpers.InitClass/InitInstantiatedClass), so model them as - // value-returning to match the callee's call_indirect signature; must land with that CoreLib change. -#ifdef TARGET_WASM + // On wasm these helpers return void* (InitHelpers.InitClass/InitInstantiatedClass). Model them as + // value-returning so the call_indirect signature matches the compiled managed helper; the value is unused. static constexpr var_types HelperInitClassRetType = TYP_I_IMPL; #else static constexpr var_types HelperInitClassRetType = TYP_VOID; From cc8eacf31a5aa73d5a0ef27fcecee6cd2016860b Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Tue, 21 Jul 2026 20:15:39 -0500 Subject: [PATCH 4/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/coreclr/jit/compiler.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 91999a1fe07a28..9894611a963450 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3358,12 +3358,13 @@ class Compiler GenTreeCall* gtNewHelperCallNode( unsigned helper, var_types type, GenTree* arg1 = nullptr, GenTree* arg2 = nullptr, GenTree* arg3 = nullptr, GenTree* arg4 = nullptr); +#ifdef TARGET_WASM // On wasm these helpers return void* (InitHelpers.InitClass/InitInstantiatedClass). Model them as // value-returning so the call_indirect signature matches the compiled managed helper; the value is unused. static constexpr var_types HelperInitClassRetType = TYP_I_IMPL; #else static constexpr var_types HelperInitClassRetType = TYP_VOID; -#endif +#endif // TARGET_WASM GenTreeCall* gtNewVirtualFunctionLookupHelperCallNode( unsigned helper, var_types type, GenTree* thisPtr, GenTree* methHnd, GenTree* clsHnd = nullptr);