From 931c0bd9b89f1c13c52e6aa622e9276d453336f1 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 13 Oct 2025 15:19:43 +0200 Subject: [PATCH 1/2] [wasm][coreclr] Fix GetOffsetOfArgumentRegisters Fixes remaining issue mentioned in https://github.com/dotnet/runtime/pull/120613 This fixes offset calculation of This and other special cased arguments. Without that fix, we ended writing the this argument value to a wrong offset. --- src/coreclr/vm/callingconvention.h | 33 +++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 83bb208c89bb41..68148422395b39 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -109,6 +109,12 @@ struct ArgLocDesc } }; +#ifdef TARGET_WASM +#define TARGET_REGISTER_SIZE INTERP_STACK_SLOT_SIZE +#else +#define TARGET_REGISTER_SIZE TARGET_POINTER_SIZE +#endif + // // TransitionBlock is layout of stack frame of method call, saved argument registers and saved callee saved registers. Even though not // all fields are used all the time, we use uniform form for simplicity. @@ -243,7 +249,10 @@ struct TransitionBlock { LIMITED_METHOD_CONTRACT; int offs; -#if defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI) + // on wasm we don't have registers, so instead we put the arguments + // which would be in registers on other architectures + // on the stack right after the transition block +#if defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI) || defined(TARGET_WASM) offs = sizeof(TransitionBlock); #else offs = offsetof(TransitionBlock, m_argumentRegisters); @@ -281,15 +290,15 @@ struct TransitionBlock _ASSERTE(offset != TransitionBlock::StructInRegsOffset); #endif offset -= GetOffsetOfArgumentRegisters(); - _ASSERTE((offset % TARGET_POINTER_SIZE) == 0); - return offset / TARGET_POINTER_SIZE; + _ASSERTE((offset % TARGET_REGISTER_SIZE) == 0); + return offset / TARGET_REGISTER_SIZE; } static UINT GetStackArgumentIndexFromOffset(int offset) { LIMITED_METHOD_CONTRACT; - return (offset - TransitionBlock::GetOffsetOfArgs()) / TARGET_POINTER_SIZE; + return (offset - TransitionBlock::GetOffsetOfArgs()) / TARGET_REGISTER_SIZE; } static UINT GetStackArgumentByteIndexFromOffset(int offset) @@ -1082,7 +1091,7 @@ int ArgIteratorTemplate::GetRetBuffArgOffset() ret = TransitionBlock::GetOffsetOfRetBuffArgReg(); #else if (this->HasThis()) - ret += TARGET_POINTER_SIZE; + ret += TARGET_REGISTER_SIZE; #endif return ret; @@ -1104,12 +1113,12 @@ int ArgIteratorTemplate::GetVASigCookieOffset() if (this->HasThis()) { - ret += TARGET_POINTER_SIZE; + ret += TARGET_REGISTER_SIZE; } if (this->HasRetBuffArg() && IsRetBuffPassedAsFirstArg()) { - ret += TARGET_POINTER_SIZE; + ret += TARGET_REGISTER_SIZE; } return ret; @@ -1157,12 +1166,12 @@ int ArgIteratorTemplate::GetParamTypeArgOffset() if (this->HasThis()) { - ret += TARGET_POINTER_SIZE; + ret += TARGET_REGISTER_SIZE; } if (this->HasRetBuffArg() && IsRetBuffPassedAsFirstArg()) { - ret += TARGET_POINTER_SIZE; + ret += TARGET_REGISTER_SIZE; } return ret; @@ -1214,17 +1223,17 @@ int ArgIteratorTemplate::GetAsyncContinuationArgOffset() if (this->HasThis()) { - ret += TARGET_POINTER_SIZE; + ret += TARGET_REGISTER_SIZE; } if (this->HasRetBuffArg() && IsRetBuffPassedAsFirstArg()) { - ret += TARGET_POINTER_SIZE; + ret += TARGET_REGISTER_SIZE; } if (this->HasParamType()) { - ret += TARGET_POINTER_SIZE; + ret += TARGET_REGISTER_SIZE; } return ret; From a243a391fb19d4db3e1028451169bf2048361d0a Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 13 Oct 2025 15:53:45 +0200 Subject: [PATCH 2/2] Update src/coreclr/vm/callingconvention.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/vm/callingconvention.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 68148422395b39..70fc6ef34c6b4b 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -252,7 +252,7 @@ struct TransitionBlock // on wasm we don't have registers, so instead we put the arguments // which would be in registers on other architectures // on the stack right after the transition block -#if defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI) || defined(TARGET_WASM) +#if (defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)) || defined(TARGET_WASM) offs = sizeof(TransitionBlock); #else offs = offsetof(TransitionBlock, m_argumentRegisters);