From a8486e5f7229f71d444471ed8128a678c0226488 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 10 Nov 2025 11:17:58 +0100 Subject: [PATCH 01/10] [wasm][coreclr] First part of the call generator, interp to native It can be now used to update wasm callhelpers manually. Example usage: ./dotnet.sh build /t:RunGenerator /p:GeneratorOutputPath="./" /p:AssembliesScanPath="" src/tasks/WasmAppBuilder/WasmAppBuilder.csproj The call helper files are split to 2 files, similar as on mono. The pinvoke/reverse parts of the generator will be updated in the followup PR. --- src/coreclr/vm/CMakeLists.txt | 3 +- ....cpp => callhelpers-interp-to-managed.cpp} | 267 +++++------------- src/coreclr/vm/wasm/callhelpers-reverse.cpp | 55 ++++ .../WasmAppBuilder/WasmAppBuilder.csproj | 32 +++ .../coreclr/InterpToNativeGenerator.cs | 135 +++++++++ .../coreclr/ManagedToNativeGenerator.cs | 225 +++++++++++++++ .../WasmAppBuilder/coreclr/SignatureMapper.cs | 145 ++++++++++ .../{ => mono}/InterpToNativeGenerator.cs | 0 .../{ => mono}/ManagedToNativeGenerator.cs | 0 .../{ => mono}/SignatureMapper.cs | 0 10 files changed, 663 insertions(+), 199 deletions(-) rename src/coreclr/vm/wasm/{callhelpers.cpp => callhelpers-interp-to-managed.cpp} (72%) create mode 100644 src/coreclr/vm/wasm/callhelpers-reverse.cpp create mode 100644 src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs create mode 100644 src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs create mode 100644 src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs rename src/tasks/WasmAppBuilder/{ => mono}/InterpToNativeGenerator.cs (100%) rename src/tasks/WasmAppBuilder/{ => mono}/ManagedToNativeGenerator.cs (100%) rename src/tasks/WasmAppBuilder/{ => mono}/SignatureMapper.cs (100%) diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index 09a3e5a53e6784..dc8edcc7643596 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -922,7 +922,8 @@ elseif(CLR_CMAKE_TARGET_ARCH_WASM) ${ARCH_SOURCES_DIR}/calldescrworkerwasm.cpp ${ARCH_SOURCES_DIR}/profiler.cpp ${ARCH_SOURCES_DIR}/helpers.cpp - ${ARCH_SOURCES_DIR}/callhelpers.cpp + ${ARCH_SOURCES_DIR}/callhelpers-interp-to-managed.cpp + ${ARCH_SOURCES_DIR}/callhelpers-reverse.cpp exceptionhandling.cpp gcinfodecoder.cpp ) diff --git a/src/coreclr/vm/wasm/callhelpers.cpp b/src/coreclr/vm/wasm/callhelpers-interp-to-managed.cpp similarity index 72% rename from src/coreclr/vm/wasm/callhelpers.cpp rename to src/coreclr/vm/wasm/callhelpers-interp-to-managed.cpp index b4d7bdb752a197..8125b45098f617 100644 --- a/src/coreclr/vm/wasm/callhelpers.cpp +++ b/src/coreclr/vm/wasm/callhelpers-interp-to-managed.cpp @@ -19,6 +19,12 @@ namespace { + void CallFunc_Void_RetF64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + { + double (*fptr)() = (double (*)())pcode; + *((double*)pRet) = (*fptr)(); + } + void CallFunc_F64_RetF64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) { double (*fptr)(double) = (double (*)(double))pcode; @@ -79,12 +85,42 @@ namespace *((int32_t*)pRet) = (*fptr)(); } + void CallFunc_F64_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + { + int32_t (*fptr)(double, int32_t) = (int32_t (*)(double, int32_t))pcode; + *((int32_t*)pRet) = (*fptr)(ARG_F64(0), ARG_I32(1)); + } + + void CallFunc_F32_F32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + { + int32_t (*fptr)(float, float) = (int32_t (*)(float, float))pcode; + *((int32_t*)pRet) = (*fptr)(ARG_F32(0), ARG_F32(1)); + } + void CallFunc_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) { int32_t (*fptr)(int32_t) = (int32_t (*)(int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0)); } + void CallFunc_I32_F64_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + { + int32_t (*fptr)(int32_t, double) = (int32_t (*)(int32_t, double))pcode; + *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_F64(1)); + } + + void CallFunc_I32_F32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + { + int32_t (*fptr)(int32_t, float) = (int32_t (*)(int32_t, float))pcode; + *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_F32(1)); + } + + void CallFunc_I32_F32_I32_I32_F32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + { + int32_t (*fptr)(int32_t, float, int32_t, int32_t, float) = (int32_t (*)(int32_t, float, int32_t, int32_t, float))pcode; + *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_F32(1), ARG_I32(2), ARG_I32(3), ARG_F32(4)); + } + void CallFunc_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) { int32_t (*fptr)(int32_t, int32_t) = (int32_t (*)(int32_t, int32_t))pcode; @@ -127,10 +163,10 @@ namespace *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6), ARG_I32(7), ARG_I32(8), ARG_I32(9), ARG_I32(10)); } - void CallFunc_I32_I32_I32_I32_I64_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + void CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) { - int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int64_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int64_t))pcode; - *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I64(4)); + int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; + *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6), ARG_I32(7), ARG_I32(8), ARG_I32(9), ARG_I32(10), ARG_I32(11), ARG_I32(12), ARG_I32(13), ARG_I32(14), ARG_I32(15), ARG_I32(16)); } void CallFunc_I32_I32_I32_I64_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) @@ -151,12 +187,6 @@ namespace *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I64(2)); } - void CallFunc_I32_I32_I64_I32_I32_I64_I64_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - int32_t (*fptr)(int32_t, int32_t, int64_t, int32_t, int32_t, int64_t, int64_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int64_t, int32_t, int32_t, int64_t, int64_t, int32_t, int32_t))pcode; - *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I64(2), ARG_I32(3), ARG_I32(4), ARG_I64(5), ARG_I64(6), ARG_I32(7), ARG_I32(8)); - } - void CallFunc_I32_I32_IND_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; @@ -199,6 +229,12 @@ namespace *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I64(1), ARG_I64(2), ARG_I32(3)); } + void CallFunc_I32_IND_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + { + int32_t (*fptr)(int32_t, int32_t) = (int32_t (*)(int32_t, int32_t))pcode; + *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_IND(1)); + } + void CallFunc_I32_IND_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t))pcode; @@ -217,34 +253,10 @@ namespace *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_IND(1), ARG_I32(2), ARG_IND(3), ARG_I32(4)); } - void CallFunc_I64_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + void CallFunc_I32_IND_IND_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) { - int32_t (*fptr)(int64_t) = (int32_t (*)(int64_t))pcode; - *((int32_t*)pRet) = (*fptr)(ARG_I64(0)); - } - - void CallFunc_I64_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - int32_t (*fptr)(int64_t, int32_t) = (int32_t (*)(int64_t, int32_t))pcode; - *((int32_t*)pRet) = (*fptr)(ARG_I64(0), ARG_I32(1)); - } - - void CallFunc_I64_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - int32_t (*fptr)(int64_t, int32_t, int32_t, int32_t) = (int32_t (*)(int64_t, int32_t, int32_t, int32_t))pcode; - *((int32_t*)pRet) = (*fptr)(ARG_I64(0), ARG_I32(1), ARG_I32(2), ARG_I32(3)); - } - - void CallFunc_I64_I32_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - int32_t (*fptr)(int64_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int64_t, int32_t, int32_t, int32_t, int32_t))pcode; - *((int32_t*)pRet) = (*fptr)(ARG_I64(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); - } - - void CallFunc_I64_I32_I32_I32_I64_I64_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - int32_t (*fptr)(int64_t, int32_t, int32_t, int32_t, int64_t, int64_t, int32_t, int32_t) = (int32_t (*)(int64_t, int32_t, int32_t, int32_t, int64_t, int64_t, int32_t, int32_t))pcode; - *((int32_t*)pRet) = (*fptr)(ARG_I64(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I64(4), ARG_I64(5), ARG_I32(6), ARG_I32(7)); + int32_t (*fptr)(int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t))pcode; + *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_IND(1), ARG_IND(2)); } void CallFunc_I64_I32_I64_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) @@ -301,12 +313,6 @@ namespace *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_I32(1), ARG_IND(2), ARG_IND(3)); } - void CallFunc_IND_IND_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - int32_t (*fptr)(int32_t, int32_t) = (int32_t (*)(int32_t, int32_t))pcode; - *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_IND(1)); - } - void CallFunc_IND_IND_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t))pcode; @@ -373,13 +379,6 @@ namespace *((int64_t*)pRet) = (*fptr)(ARG_I64(0), ARG_I64(1)); } - void CallFunc_Void_RetIND (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - int32_t (*fptr)() = (int32_t (*)())pcode; - PORTABILITY_ASSERT("Indirect struct return is not yet implemented."); - *((int32_t*)pRet) = (*fptr)(); - } - void CallFunc_I32_RetIND (PCODE pcode, int8_t *pArgs, int8_t *pRet) { int32_t (*fptr)(int32_t) = (int32_t (*)(int32_t))pcode; @@ -448,30 +447,6 @@ namespace (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5)); } - void CallFunc_I32_I32_I32_I32_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; - (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6)); - } - - void CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; - (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6), ARG_I32(7)); - } - - void CallFunc_I32_I32_I32_I32_I64_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int32_t, int32_t, int32_t, int32_t, int64_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int64_t, int32_t))pcode; - (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I64(4), ARG_I32(5)); - } - - void CallFunc_I32_I32_I32_I64_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int32_t, int32_t, int32_t, int64_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int64_t, int32_t))pcode; - (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I64(3), ARG_I32(4)); - } - void CallFunc_I32_I32_I32_IND_IND_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; @@ -484,6 +459,12 @@ namespace (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_IND(3), ARG_IND(4), ARG_I32(5)); } + void CallFunc_I32_I32_IND_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + { + void (*fptr)(int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t))pcode; + (*fptr)(ARG_I32(0), ARG_I32(1), ARG_IND(2)); + } + void CallFunc_I32_I32_IND_IND_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; @@ -496,28 +477,10 @@ namespace (*fptr)(ARG_I32(0), ARG_I32(1), ARG_IND(2), ARG_IND(3), ARG_I32(4), ARG_I32(5)); } - void CallFunc_I32_I64_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + void CallFunc_I32_IND_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) { - void (*fptr)(int32_t, int64_t) = (void (*)(int32_t, int64_t))pcode; - (*fptr)(ARG_I32(0), ARG_I64(1)); - } - - void CallFunc_I32_I64_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int32_t, int64_t, int32_t) = (void (*)(int32_t, int64_t, int32_t))pcode; - (*fptr)(ARG_I32(0), ARG_I64(1), ARG_I32(2)); - } - - void CallFunc_I32_I64_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int32_t, int64_t, int32_t, int32_t) = (void (*)(int32_t, int64_t, int32_t, int32_t))pcode; - (*fptr)(ARG_I32(0), ARG_I64(1), ARG_I32(2), ARG_I32(3)); - } - - void CallFunc_I32_I64_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int32_t, int64_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int64_t, int32_t, int32_t, int32_t))pcode; - (*fptr)(ARG_I32(0), ARG_I64(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); + void (*fptr)(int32_t, int32_t) = (void (*)(int32_t, int32_t))pcode; + (*fptr)(ARG_I32(0), ARG_IND(1)); } void CallFunc_I32_IND_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) @@ -538,36 +501,6 @@ namespace (*fptr)(ARG_I64(0)); } - void CallFunc_I64_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int64_t, int32_t) = (void (*)(int64_t, int32_t))pcode; - (*fptr)(ARG_I64(0), ARG_I32(1)); - } - - void CallFunc_I64_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int64_t, int32_t, int32_t) = (void (*)(int64_t, int32_t, int32_t))pcode; - (*fptr)(ARG_I64(0), ARG_I32(1), ARG_I32(2)); - } - - void CallFunc_I64_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int64_t, int32_t, int32_t, int32_t) = (void (*)(int64_t, int32_t, int32_t, int32_t))pcode; - (*fptr)(ARG_I64(0), ARG_I32(1), ARG_I32(2), ARG_I32(3)); - } - - void CallFunc_I64_I32_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int64_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int64_t, int32_t, int32_t, int32_t, int32_t))pcode; - (*fptr)(ARG_I64(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); - } - - void CallFunc_I64_I64_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) - { - void (*fptr)(int64_t, int64_t, int32_t) = (void (*)(int64_t, int64_t, int32_t))pcode; - (*fptr)(ARG_I64(0), ARG_I64(1), ARG_I32(2)); - } - void CallFunc_IND_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) { void (*fptr)(int32_t) = (void (*)(int32_t))pcode; @@ -627,10 +560,10 @@ namespace void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_IND(0), ARG_IND(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); } - } const StringToWasmSigThunk g_wasmThunks[] = { + { "d", (void*)&CallFunc_Void_RetF64 }, { "dd", (void*)&CallFunc_F64_RetF64 }, { "ddd", (void*)&CallFunc_F64_F64_RetF64 }, { "dddd", (void*)&CallFunc_F64_F64_F64_RetF64 }, @@ -641,7 +574,12 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "ffff", (void*)&CallFunc_F32_F32_F32_RetF32 }, { "ffi", (void*)&CallFunc_F32_I32_RetF32 }, { "i", (void*)&CallFunc_Void_RetI32 }, + { "idi", (void*)&CallFunc_F64_I32_RetI32 }, + { "iff", (void*)&CallFunc_F32_F32_RetI32 }, { "ii", (void*)&CallFunc_I32_RetI32 }, + { "iid", (void*)&CallFunc_I32_F64_RetI32 }, + { "iif", (void*)&CallFunc_I32_F32_RetI32 }, + { "iifiif", (void*)&CallFunc_I32_F32_I32_I32_F32_RetI32 }, { "iii", (void*)&CallFunc_I32_I32_RetI32 }, { "iiii", (void*)&CallFunc_I32_I32_I32_RetI32 }, { "iiiii", (void*)&CallFunc_I32_I32_I32_I32_RetI32 }, @@ -649,11 +587,10 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "iiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_RetI32 }, { "iiiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_RetI32 }, { "iiiiiiiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 }, - { "iiiiil", (void*)&CallFunc_I32_I32_I32_I32_I64_RetI32 }, + { "iiiiiiiiiiiiiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 }, { "iiiil", (void*)&CallFunc_I32_I32_I32_I64_RetI32 }, { "iiiini", (void*)&CallFunc_I32_I32_I32_IND_I32_RetI32 }, { "iiil", (void*)&CallFunc_I32_I32_I64_RetI32 }, - { "iiiliillii", (void*)&CallFunc_I32_I32_I64_I32_I32_I64_I64_I32_I32_RetI32 }, { "iiinii", (void*)&CallFunc_I32_I32_IND_I32_I32_RetI32 }, { "iiiniin", (void*)&CallFunc_I32_I32_IND_I32_I32_IND_RetI32 }, { "iil", (void*)&CallFunc_I32_I64_RetI32 }, @@ -661,14 +598,11 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "iiliiil", (void*)&CallFunc_I32_I64_I32_I32_I32_I64_RetI32 }, { "iill", (void*)&CallFunc_I32_I64_I64_RetI32 }, { "iilli", (void*)&CallFunc_I32_I64_I64_I32_RetI32 }, + { "iin", (void*)&CallFunc_I32_IND_RetI32 }, { "iini", (void*)&CallFunc_I32_IND_I32_RetI32 }, { "iiniii", (void*)&CallFunc_I32_IND_I32_I32_I32_RetI32 }, { "iinini", (void*)&CallFunc_I32_IND_I32_IND_I32_RetI32 }, - { "il", (void*)&CallFunc_I64_RetI32 }, - { "ili", (void*)&CallFunc_I64_I32_RetI32 }, - { "iliii", (void*)&CallFunc_I64_I32_I32_I32_RetI32 }, - { "iliiii", (void*)&CallFunc_I64_I32_I32_I32_I32_RetI32 }, - { "iliiillii", (void*)&CallFunc_I64_I32_I32_I32_I64_I64_I32_I32_RetI32 }, + { "iinn", (void*)&CallFunc_I32_IND_IND_RetI32 }, { "ilili", (void*)&CallFunc_I64_I32_I64_I32_RetI32 }, { "in", (void*)&CallFunc_IND_RetI32 }, { "ini", (void*)&CallFunc_IND_I32_RetI32 }, @@ -678,7 +612,6 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "iniiiii", (void*)&CallFunc_IND_I32_I32_I32_I32_I32_RetI32 }, { "inini", (void*)&CallFunc_IND_I32_IND_I32_RetI32 }, { "ininn", (void*)&CallFunc_IND_I32_IND_IND_RetI32 }, - { "inn", (void*)&CallFunc_IND_IND_RetI32 }, { "inni", (void*)&CallFunc_IND_IND_I32_RetI32 }, { "innii", (void*)&CallFunc_IND_IND_I32_I32_RetI32 }, { "innin", (void*)&CallFunc_IND_IND_I32_IND_RetI32 }, @@ -690,7 +623,6 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "lili", (void*)&CallFunc_I32_I64_I32_RetI64 }, { "lill", (void*)&CallFunc_I32_I64_I64_RetI64 }, { "lll", (void*)&CallFunc_I64_I64_RetI64 }, - { "n", (void*)&CallFunc_Void_RetIND }, { "ni", (void*)&CallFunc_I32_RetIND }, { "nii", (void*)&CallFunc_I32_I32_RetIND }, { "v", (void*)&CallFunc_Void_RetVoid }, @@ -702,26 +634,15 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "viiii", (void*)&CallFunc_I32_I32_I32_I32_RetVoid }, { "viiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_RetVoid }, { "viiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_RetVoid }, - { "viiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_RetVoid }, - { "viiiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_RetVoid }, - { "viiiili", (void*)&CallFunc_I32_I32_I32_I32_I64_I32_RetVoid }, - { "viiili", (void*)&CallFunc_I32_I32_I32_I64_I32_RetVoid }, { "viiinn", (void*)&CallFunc_I32_I32_I32_IND_IND_RetVoid }, { "viiinni", (void*)&CallFunc_I32_I32_I32_IND_IND_I32_RetVoid }, + { "viin", (void*)&CallFunc_I32_I32_IND_RetVoid }, { "viinni", (void*)&CallFunc_I32_I32_IND_IND_I32_RetVoid }, { "viinnii", (void*)&CallFunc_I32_I32_IND_IND_I32_I32_RetVoid }, - { "vil", (void*)&CallFunc_I32_I64_RetVoid }, - { "vili", (void*)&CallFunc_I32_I64_I32_RetVoid }, - { "vilii", (void*)&CallFunc_I32_I64_I32_I32_RetVoid }, - { "viliii", (void*)&CallFunc_I32_I64_I32_I32_I32_RetVoid }, + { "vin", (void*)&CallFunc_I32_IND_RetVoid }, { "vini", (void*)&CallFunc_I32_IND_I32_RetVoid }, { "vinni", (void*)&CallFunc_I32_IND_IND_I32_RetVoid }, { "vl", (void*)&CallFunc_I64_RetVoid }, - { "vli", (void*)&CallFunc_I64_I32_RetVoid }, - { "vlii", (void*)&CallFunc_I64_I32_I32_RetVoid }, - { "vliii", (void*)&CallFunc_I64_I32_I32_I32_RetVoid }, - { "vliiii", (void*)&CallFunc_I64_I32_I32_I32_I32_RetVoid }, - { "vlli", (void*)&CallFunc_I64_I64_I32_RetVoid }, { "vn", (void*)&CallFunc_IND_RetVoid }, { "vni", (void*)&CallFunc_IND_I32_RetVoid }, { "vnii", (void*)&CallFunc_IND_I32_I32_RetVoid }, @@ -734,54 +655,4 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "vnniii", (void*)&CallFunc_IND_IND_I32_I32_I32_RetVoid } }; -const size_t g_wasmThunksCount = sizeof(g_wasmThunks) / sizeof(g_wasmThunks[0]); - -// Define reverse thunks here - -// Entry point for interpreted method execution from unmanaged code -class MethodDesc; - -// WASM-TODO: The method lookup would ideally be fully qualified assembly and then methodDef token. -// The current approach has limitations with overloaded methods. -extern "C" void LookupMethodByName(const char* fullQualifiedTypeName, const char* methodName, MethodDesc** ppMD); -extern "C" void ExecuteInterpretedMethodFromUnmanaged(MethodDesc* pMD, int8_t* args, size_t argSize, int8_t* ret); - -static MethodDesc* MD_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler_Void_RetVoid = nullptr; -static void Call_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler() -{ - // Lazy lookup of MethodDesc for the function export scenario. - if (!MD_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler_Void_RetVoid) - { - LookupMethodByName("System.Threading.ThreadPool, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, System.Private.CoreLib", "BackgroundJobHandler", &MD_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler_Void_RetVoid); - } - ExecuteInterpretedMethodFromUnmanaged(MD_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler_Void_RetVoid, nullptr, 0, nullptr); -} - -extern "C" void SystemJS_ExecuteBackgroundJobCallback() -{ - Call_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler(); -} - -static MethodDesc* MD_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler_Void_RetVoid = nullptr; -static void Call_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler() -{ - // Lazy lookup of MethodDesc for the function export scenario. - if (!MD_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler_Void_RetVoid) - { - LookupMethodByName("System.Threading.TimerQueue, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, System.Private.CoreLib", "TimerHandler", &MD_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler_Void_RetVoid); - } - ExecuteInterpretedMethodFromUnmanaged(MD_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler_Void_RetVoid, nullptr, 0, nullptr); -} - -extern "C" void SystemJS_ExecuteTimerCallback() -{ - Call_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler(); -} - -extern const ReverseThunkMapEntry g_ReverseThunks[] = -{ - { 100678287, { &MD_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler_Void_RetVoid, (void*)&Call_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler } }, - { 100678363, { &MD_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler_Void_RetVoid, (void*)&Call_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler } }, -}; - -const size_t g_ReverseThunksCount = sizeof(g_ReverseThunks) / sizeof(g_ReverseThunks[0]); +const size_t g_wasmThunksCount = sizeof(g_wasmThunks) / sizeof(g_wasmThunks[0]); \ No newline at end of file diff --git a/src/coreclr/vm/wasm/callhelpers-reverse.cpp b/src/coreclr/vm/wasm/callhelpers-reverse.cpp new file mode 100644 index 00000000000000..2be9ba25e1b18e --- /dev/null +++ b/src/coreclr/vm/wasm/callhelpers-reverse.cpp @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#include + +// Define reverse thunks here + +// Entry point for interpreted method execution from unmanaged code +class MethodDesc; + +// WASM-TODO: The method lookup would ideally be fully qualified assembly and then methodDef token. +// The current approach has limitations with overloaded methods. +extern "C" void LookupMethodByName(const char* fullQualifiedTypeName, const char* methodName, MethodDesc** ppMD); +extern "C" void ExecuteInterpretedMethodFromUnmanaged(MethodDesc* pMD, int8_t* args, size_t argSize, int8_t* ret); + +static MethodDesc* MD_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler_Void_RetVoid = nullptr; +static void Call_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler() +{ + // Lazy lookup of MethodDesc for the function export scenario. + if (!MD_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler_Void_RetVoid) + { + LookupMethodByName("System.Threading.ThreadPool, System.Private.CoreLib", "BackgroundJobHandler", &MD_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler_Void_RetVoid); + } + ExecuteInterpretedMethodFromUnmanaged(MD_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler_Void_RetVoid, nullptr, 0, nullptr); +} + +extern "C" void SystemJS_ExecuteBackgroundJobCallback() +{ + Call_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler(); +} + +static MethodDesc* MD_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler_Void_RetVoid = nullptr; +static void Call_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler() +{ + // Lazy lookup of MethodDesc for the function export scenario. + if (!MD_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler_Void_RetVoid) + { + LookupMethodByName("System.Threading.TimerQueue, System.Private.CoreLib", "TimerHandler", &MD_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler_Void_RetVoid); + } + ExecuteInterpretedMethodFromUnmanaged(MD_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler_Void_RetVoid, nullptr, 0, nullptr); +} + +extern "C" void SystemJS_ExecuteTimerCallback() +{ + Call_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler(); +} + +extern const ReverseThunkMapEntry g_ReverseThunks[] = +{ + { 100678287, { &MD_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler_Void_RetVoid, (void*)&Call_System_Private_CoreLib_System_Threading_ThreadPool_BackgroundJobHandler } }, + { 100678363, { &MD_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler_Void_RetVoid, (void*)&Call_System_Private_CoreLib_System_Threading_TimerQueue_TimerHandler } }, +}; + +const size_t g_ReverseThunksCount = sizeof(g_ReverseThunks) / sizeof(g_ReverseThunks[0]); diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj index 77bdf6cafb6789..d2ac1c19c76bdf 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj @@ -16,6 +16,14 @@ + + + + + + + + @@ -50,4 +58,28 @@ + + + + + $(OutputPath)generator-test-output + + + + + + + + + + + + + + + diff --git a/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs new file mode 100644 index 00000000000000..a292da0187f99a --- /dev/null +++ b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs @@ -0,0 +1,135 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Collections.Generic; +using System.Globalization; +using Microsoft.Build.Utilities; +using Microsoft.Build.Framework; +using System.Diagnostics.CodeAnalysis; +using WasmAppBuilder; + +using JoinedString; +// +// This class generates the icall_trampoline_dispatch () function used by the interpreter to call native code on WASM. +// It should be kept in sync with mono_wasm_interp_to_native_trampoline () in the runtime. +// + +#nullable enable + +internal sealed class InterpToNativeGenerator +{ + private LogAdapter Log { get; set; } + + public InterpToNativeGenerator(LogAdapter log) => Log = log; + + public void Generate(IEnumerable cookies, string outputPath) + { + using TempFileName tmpFileName = new(); + using (var w = File.CreateText(tmpFileName.Path)) + { + Emit(w, cookies); + } + + if (Utils.CopyIfDifferent(tmpFileName.Path, outputPath, useHash: false)) + Log.LogMessage(MessageImportance.Low, $"Generating managed2native table to '{outputPath}'."); + else + Log.LogMessage(MessageImportance.Low, $"Managed2native table in {outputPath} is unchanged."); + } + + private static string SignatureToArguments(string signature) + { + if (signature.Length <= 1) + return "void"; + + return string.Join(", ", signature.Skip(1).Select(static c => SignatureMapper.CharToNativeType(c))); + } + + private static string CallFuncName(IEnumerable args, string result) + { + var paramTypes = args.Any() ? args.Join("_", (p, i) => SignatureMapper.CharToNameType(p)).ToString() : "Void"; + + return $"CallFunc_{paramTypes}_Ret{result}"; + } + + private static void Emit(StreamWriter w, IEnumerable cookies) + { + // Use OrderBy because Order() is not available on .NET Framework + var signatures = cookies.OrderBy(c => c).Distinct().ToArray(); + Array.Sort(signatures, StringComparer.Ordinal); + + + static IEnumerable Args(string signature) + { + for (int i = 1; i < signature.Length; ++i) + yield return signature[i]; + } + + static (bool isVoid, string nativeType) Result(string signature) + => new(SignatureMapper.IsVoidSignature(signature), SignatureMapper.CharToNativeType(signature[0])); + + w.Write( + """ + // Licensed to the .NET Foundation under one or more agreements. + // The .NET Foundation licenses this file to you under the MIT license. + // + + // + // GENERATED FILE, DON'T EDIT + // Generated by coreclr InterpToNativeGenerator + // + + #include + + // Arguments are passed on the stack with each argument aligned to INTERP_STACK_SLOT_SIZE. + #define ARG_ADDR(i) (pArgs + (i * INTERP_STACK_SLOT_SIZE)) + #define ARG_IND(i) ((int32_t)((int32_t*)ARG_ADDR(i))) + #define ARG_I32(i) (*(int32_t*)ARG_ADDR(i)) + #define ARG_I64(i) (*(int64_t*)ARG_ADDR(i)) + #define ARG_F32(i) (*(float*)ARG_ADDR(i)) + #define ARG_F64(i) (*(double*)ARG_ADDR(i)) + + namespace + { + """); + + foreach (var signature in signatures) + { + try + { + var result = Result(signature); + var args = Args(signature); + var portabilityAssert = signature[0] == 'n' ? "PORTABILITY_ASSERT(\"Indirect struct return is not yet implemented.\");\n " : ""; + w.Write( + $$""" + + void {{CallFuncName(args, SignatureMapper.CharToNameType(signature[0]))}} (PCODE pcode, int8_t *pArgs, int8_t *pRet) + { + {{result.nativeType}} (*fptr)({{args.Join(", ", (p, i) => SignatureMapper.CharToNativeType(p))}}) = ({{result.nativeType}} (*)({{args.Join(", ", (p, i) => SignatureMapper.CharToNativeType(p))}}))pcode; + {{portabilityAssert}}{{(result.isVoid ? "" : "*" + "((" + result.nativeType + "*)pRet) = ")}}(*fptr)({{args.Join(", ", (p, i) => $"ARG_{SignatureMapper.CharToNameType(p)}({i})")}}); + } + + """); + } + catch (InvalidSignatureCharException e) + { + throw new LogAsErrorException($"Element '{e.Char}' of signature '{signature}' can't be handled by managed2native generator"); + } + } + + w.Write( + $$""" + } + + const StringToWasmSigThunk g_wasmThunks[] = { + {{signatures.Join($",{w.NewLine}", signature => + $" {{ \"{signature}\", (void*)&{CallFuncName(Args(signature), SignatureMapper.CharToNameType(signature[0]))} }}")}} + }; + + const size_t g_wasmThunksCount = sizeof(g_wasmThunks) / sizeof(g_wasmThunks[0]); + """); + } +} diff --git a/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs new file mode 100644 index 00000000000000..17cac5e716d0c6 --- /dev/null +++ b/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs @@ -0,0 +1,225 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using WasmAppBuilder; + +namespace Microsoft.WebAssembly.Build.Tasks; + +public class ManagedToNativeGenerator : Task +{ + [Required] + public string[] Assemblies { get; set; } = Array.Empty(); + + public string? RuntimeIcallTableFile { get; set; } + + public string? IcallOutputPath { get; set; } + + [Required, NotNull] + public string[]? PInvokeModules { get; set; } + + [Required, NotNull] + public string? PInvokeOutputPath { get; set; } + + [Required, NotNull] + public string? InterpToNativeOutputPath { get; set; } + public string? CacheFilePath { get; set; } + + public bool IsLibraryMode { get; set; } + + [Output] + public string[]? FileWrites { get; private set; } + + public override bool Execute() + { + if (Assemblies!.Length == 0) + { + Log.LogError($"{nameof(ManagedToNativeGenerator)}.{nameof(Assemblies)} cannot be empty"); + return false; + } + + if (PInvokeModules!.Length == 0) + { + Log.LogError($"{nameof(ManagedToNativeGenerator)}.{nameof(PInvokeModules)} cannot be empty"); + return false; + } + + try + { + var logAdapter = new LogAdapter(Log); + ExecuteInternal(logAdapter); + return !Log.HasLoggedErrors; + } + catch (LogAsErrorException e) + { + Log.LogError(e.Message); + return false; + } + } + + // WASM-TODO: + // add missing signatures temporarily + // part is for runtime tests and delegates + // active issue https://github.com/dotnet/runtime/issues/121222 + private static readonly string[] missingCookies = + [ + "d", + "idi", + "iff", + "iid", + "iif", + "iifiif", + "iiiiiiiiiiiiiiiiii", + "iin", + "iinn", + "lii", + "ni", + "nii", + "viin", + "vin", + "vinni", + "iinini", + ]; + + private void ExecuteInternal(LogAdapter log) + { + Dictionary _symbolNameFixups = new(); + List managedAssemblies = FilterOutUnmanagedBinaries(Assemblies); + if (ShouldRun(managedAssemblies)) + { + var pinvoke = new PInvokeTableGenerator(FixupSymbolName, log, IsLibraryMode); + var icall = new IcallTableGenerator(RuntimeIcallTableFile, FixupSymbolName, log); + + var resolver = new PathAssemblyResolver(managedAssemblies); + using var mlc = new MetadataLoadContext(resolver, "System.Private.CoreLib"); + foreach (string asmPath in managedAssemblies) + { + log.LogMessage(MessageImportance.Low, $"Loading {asmPath} to scan for pinvokes, and icalls"); + Assembly asm = mlc.LoadFromAssemblyPath(asmPath); + pinvoke.ScanAssembly(asm); + icall.ScanAssembly(asm); + } + + + IEnumerable cookies = Enumerable.Concat( + pinvoke.Generate(PInvokeModules, PInvokeOutputPath), + Enumerable.Concat(icall.Generate(IcallOutputPath), + missingCookies)); + + var m2n = new InterpToNativeGenerator(log); + m2n.Generate(cookies, InterpToNativeOutputPath); + + if (!string.IsNullOrEmpty(CacheFilePath)) + File.WriteAllLines(CacheFilePath, PInvokeModules); + } + + List fileWritesList = new() { PInvokeOutputPath, InterpToNativeOutputPath }; + if (IcallOutputPath != null) + fileWritesList.Add(IcallOutputPath); + if (!string.IsNullOrEmpty(CacheFilePath)) + fileWritesList.Add(CacheFilePath); + + FileWrites = fileWritesList.ToArray(); + + string FixupSymbolName(string name) + { + if (_symbolNameFixups.TryGetValue(name, out string? fixedName)) + return fixedName; + + fixedName = Utils.FixupSymbolName(name); + _symbolNameFixups[name] = fixedName; + return fixedName; + } + + } + + private bool ShouldRun(IList managedAssemblies) + { + if (string.IsNullOrEmpty(CacheFilePath) || !File.Exists(CacheFilePath)) + { + Log.LogMessage(MessageImportance.Low, $"Running because no cache file found at '{CacheFilePath}'."); + return true; + } + + string oldModules = string.Join(",", File.ReadLines(CacheFilePath).OrderBy(l => l)); + string newModules = string.Join(",", PInvokeModules.OrderBy(l => l)); + if (!string.Equals(oldModules, newModules, StringComparison.InvariantCulture)) + { + Log.LogMessage(MessageImportance.Low, $"Running because the list of pinvoke modules has changed from: {oldModules} to {newModules} ."); + return true; + } + + // compare against the output files + // get the timestamp for oldest output file + DateTime oldestOutputDt = DateTime.MaxValue; + if (CheckShouldRunBecauseOfOutputFile(IcallOutputPath, ref oldestOutputDt) || + CheckShouldRunBecauseOfOutputFile(PInvokeOutputPath, ref oldestOutputDt) || + CheckShouldRunBecauseOfOutputFile(InterpToNativeOutputPath, ref oldestOutputDt)) + { + return true; + } + + foreach (string asm in managedAssemblies) + { + if (File.GetLastWriteTimeUtc(asm) >= oldestOutputDt) + { + Log.LogMessage(MessageImportance.Low, $"Running because {asm} is newer than one of the output files."); + return true; + } + } + + Log.LogMessage(MessageImportance.Low, $"Skipping because all of the assemblies are older than the output files."); + return false; + + bool CheckShouldRunBecauseOfOutputFile(string? path, ref DateTime oldestDt) + { + if (string.IsNullOrEmpty(path)) + return false; + + if (!File.Exists(path)) + { + Log.LogMessage(MessageImportance.Low, $"Running because output file '{path}' does not exist."); + return true; + } + DateTime utc = File.GetLastWriteTimeUtc(path); + oldestDt = utc < oldestDt ? utc : oldestDt; + return false; + } + } + + private List FilterOutUnmanagedBinaries(string[] assemblies) + { + List managedAssemblies = new(assemblies.Length); + foreach (string asmPath in Assemblies) + { + if (!File.Exists(asmPath)) + throw new LogAsErrorException($"Cannot find assembly {asmPath}"); + + try + { + if (!Utils.IsManagedAssembly(asmPath)) + { + Log.LogMessage(MessageImportance.Low, $"Skipping unmanaged {asmPath}."); + continue; + } + } + catch (Exception ex) + { + Log.LogMessage(MessageImportance.Low, $"Failed to read assembly {asmPath}: {ex}"); + throw new LogAsErrorException($"Failed to read assembly {asmPath}: {ex.Message}"); + } + + managedAssemblies.Add(asmPath); + } + + return managedAssemblies; + } +} diff --git a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs new file mode 100644 index 00000000000000..4c8f9ad642a71d --- /dev/null +++ b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs @@ -0,0 +1,145 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using WasmAppBuilder; + +internal static class SignatureMapper +{ + internal static char? TypeToChar(Type t, LogAdapter log, out bool isByRefStruct, int depth = 0) + { + isByRefStruct = false; + + if (depth > 5) { + log.Warning("WASM0064", $"Unbounded recursion detected through parameter type '{t.Name}'"); + return null; + } + + char? c = null; + if (t.Namespace == "System") { + c = t.Name switch + { + nameof(String) => 'i', + nameof(Boolean) => 'i', + nameof(Char) => 'i', + nameof(SByte) => 'i', + nameof(Byte) => 'i', + nameof(Int16) => 'i', + nameof(UInt16) => 'i', + nameof(Int32) => 'i', + nameof(UInt32) => 'i', + nameof(Int64) => 'l', + nameof(UInt64) => 'l', + nameof(Single) => 'f', + nameof(Double) => 'd', + // FIXME: These will need to be L for wasm64 + nameof(IntPtr) => 'i', + nameof(UIntPtr) => 'i', + "Void" => 'v', + _ => null + }; + } + + if (c != null) + return c; + + // FIXME: Most of these need to be L for wasm64 + if (t.IsArray) + c = 'i'; + else if (t.IsByRef) + c = 'i'; + else if (typeof(Delegate).IsAssignableFrom(t)) + // FIXME: Should we narrow this to only certain types of delegates? + c = 'i'; + else if (t.IsClass) + c = 'i'; + else if (t.IsInterface) + c = 'i'; + else if (t.IsEnum) { + Type underlyingType = t.GetEnumUnderlyingType(); + c = TypeToChar(underlyingType, log, out _, ++depth); + } else if (t.IsPointer) + c = 'i'; + else if (PInvokeTableGenerator.IsFunctionPointer(t)) + c = 'i'; + else if (t.IsValueType) + { + var fields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + if (fields.Length == 1) + { + Type fieldType = fields[0].FieldType; + return TypeToChar(fieldType, log, out isByRefStruct, ++depth); + } + else if (PInvokeTableGenerator.IsBlittable(t, log)) + c = 'n'; + + isByRefStruct = true; + } + else + log.Warning("WASM0064", $"Unsupported parameter type '{t.Name}'"); + + return c; + } + + public static string? MethodToSignature(MethodInfo method, LogAdapter log) + { + string? result = TypeToChar(method.ReturnType, log, out bool resultIsByRef)?.ToString(); + if (result == null) + { + return null; + } + + if (resultIsByRef) { + result = "n"; + } + + foreach (var parameter in method.GetParameters()) + { + char? parameterChar = TypeToChar(parameter.ParameterType, log, out _); + if (parameterChar == null) + { + return null; + } + + result += parameterChar; + } + + return result; + } + + public static string CharToNativeType(char c) => c switch + { + 'v' => "void", + 'i' => "int32_t", + 'l' => "int64_t", + 'f' => "float", + 'd' => "double", + 'n' => "int32_t", + _ => throw new InvalidSignatureCharException(c) + }; + + public static string CharToNameType(char c) => c switch + { + 'v' => "Void", + 'i' => "I32", + 'l' => "I64", + 'f' => "F32", + 'd' => "F64", + 'n' => "IND", + _ => throw new InvalidSignatureCharException(c) + }; + + public static bool IsVoidSignature(string signature) => signature[0] == 'v'; +} + +internal sealed class InvalidSignatureCharException : Exception +{ + public char Char { get; private set; } + + public InvalidSignatureCharException(char c) : base($"Can't handle signature '{c}'") => Char = c; +} diff --git a/src/tasks/WasmAppBuilder/InterpToNativeGenerator.cs b/src/tasks/WasmAppBuilder/mono/InterpToNativeGenerator.cs similarity index 100% rename from src/tasks/WasmAppBuilder/InterpToNativeGenerator.cs rename to src/tasks/WasmAppBuilder/mono/InterpToNativeGenerator.cs diff --git a/src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs b/src/tasks/WasmAppBuilder/mono/ManagedToNativeGenerator.cs similarity index 100% rename from src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs rename to src/tasks/WasmAppBuilder/mono/ManagedToNativeGenerator.cs diff --git a/src/tasks/WasmAppBuilder/SignatureMapper.cs b/src/tasks/WasmAppBuilder/mono/SignatureMapper.cs similarity index 100% rename from src/tasks/WasmAppBuilder/SignatureMapper.cs rename to src/tasks/WasmAppBuilder/mono/SignatureMapper.cs From b21949fb06da30cafe2ff510a0126269b9143adb Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 10 Nov 2025 13:04:33 +0100 Subject: [PATCH 02/10] Feedback Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/tasks/WasmAppBuilder/WasmAppBuilder.csproj | 4 ---- src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs | 6 +++--- src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj index d2ac1c19c76bdf..2c32d089ffc246 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj @@ -61,10 +61,6 @@ - - $(OutputPath)generator-test-output - - diff --git a/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs index a292da0187f99a..db0cda77d34cc1 100644 --- a/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs +++ b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -14,8 +14,8 @@ using JoinedString; // -// This class generates the icall_trampoline_dispatch () function used by the interpreter to call native code on WASM. -// It should be kept in sync with mono_wasm_interp_to_native_trampoline () in the runtime. +// This class generates the g_wasmThunks array and CallFunc_* functions used by the CoreCLR interpreter to call native code on WASM. +// The generated code should be kept in sync with the corresponding CoreCLR runtime code that consumes these thunks and call functions. // #nullable enable diff --git a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs index 4c8f9ad642a71d..de7c830c5d5da3 100644 --- a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs +++ b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -6,7 +6,6 @@ using System.Linq; using System.Reflection; using System.Text; -using System.Threading.Tasks; using WasmAppBuilder; internal static class SignatureMapper From 8e966ad32ae4129a704c4c8b4766d58239481bb2 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 10 Nov 2025 21:25:03 +0100 Subject: [PATCH 03/10] Feedback Co-authored-by: Aaron R Robinson --- src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs | 2 +- src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs index db0cda77d34cc1..32865dc2f09883 100644 --- a/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs +++ b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs @@ -106,7 +106,7 @@ static IEnumerable Args(string signature) w.Write( $$""" - void {{CallFuncName(args, SignatureMapper.CharToNameType(signature[0]))}} (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void {{CallFuncName(args, SignatureMapper.CharToNameType(signature[0]))}}(PCODE pcode, int8_t* pArgs, int8_t* pRet) { {{result.nativeType}} (*fptr)({{args.Join(", ", (p, i) => SignatureMapper.CharToNativeType(p))}}) = ({{result.nativeType}} (*)({{args.Join(", ", (p, i) => SignatureMapper.CharToNativeType(p))}}))pcode; {{portabilityAssert}}{{(result.isVoid ? "" : "*" + "((" + result.nativeType + "*)pRet) = ")}}(*fptr)({{args.Join(", ", (p, i) => $"ARG_{SignatureMapper.CharToNameType(p)}({i})")}}); diff --git a/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs index 17cac5e716d0c6..0ad11bb97c97b4 100644 --- a/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs +++ b/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs @@ -108,7 +108,6 @@ private void ExecuteInternal(LogAdapter log) icall.ScanAssembly(asm); } - IEnumerable cookies = Enumerable.Concat( pinvoke.Generate(PInvokeModules, PInvokeOutputPath), Enumerable.Concat(icall.Generate(IcallOutputPath), @@ -122,7 +121,7 @@ private void ExecuteInternal(LogAdapter log) } List fileWritesList = new() { PInvokeOutputPath, InterpToNativeOutputPath }; - if (IcallOutputPath != null) + if (!string.IsNullOrEmpty(IcallOutputPath)) fileWritesList.Add(IcallOutputPath); if (!string.IsNullOrEmpty(CacheFilePath)) fileWritesList.Add(CacheFilePath); @@ -138,7 +137,6 @@ string FixupSymbolName(string name) _symbolNameFixups[name] = fixedName; return fixedName; } - } private bool ShouldRun(IList managedAssemblies) From ddecf731abf2b3e5fbff4a7c1fcc8da7b99046a6 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 10 Nov 2025 22:18:31 +0100 Subject: [PATCH 04/10] Feedback --- .../vm/wasm/callhelpers-interp-to-managed.cpp | 182 +++++++++--------- .../coreclr/InterpToNativeGenerator.cs | 3 +- .../WasmAppBuilder/coreclr/SignatureMapper.cs | 11 ++ 3 files changed, 104 insertions(+), 92 deletions(-) diff --git a/src/coreclr/vm/wasm/callhelpers-interp-to-managed.cpp b/src/coreclr/vm/wasm/callhelpers-interp-to-managed.cpp index 8125b45098f617..91cd17b5a2de1a 100644 --- a/src/coreclr/vm/wasm/callhelpers-interp-to-managed.cpp +++ b/src/coreclr/vm/wasm/callhelpers-interp-to-managed.cpp @@ -19,543 +19,543 @@ namespace { - void CallFunc_Void_RetF64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_Void_RetF64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { double (*fptr)() = (double (*)())pcode; *((double*)pRet) = (*fptr)(); } - void CallFunc_F64_RetF64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F64_RetF64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { double (*fptr)(double) = (double (*)(double))pcode; *((double*)pRet) = (*fptr)(ARG_F64(0)); } - void CallFunc_F64_F64_RetF64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F64_F64_RetF64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { double (*fptr)(double, double) = (double (*)(double, double))pcode; *((double*)pRet) = (*fptr)(ARG_F64(0), ARG_F64(1)); } - void CallFunc_F64_F64_F64_RetF64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F64_F64_F64_RetF64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { double (*fptr)(double, double, double) = (double (*)(double, double, double))pcode; *((double*)pRet) = (*fptr)(ARG_F64(0), ARG_F64(1), ARG_F64(2)); } - void CallFunc_F64_I32_RetF64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F64_I32_RetF64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { double (*fptr)(double, int32_t) = (double (*)(double, int32_t))pcode; *((double*)pRet) = (*fptr)(ARG_F64(0), ARG_I32(1)); } - void CallFunc_I32_RetF64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_RetF64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { double (*fptr)(int32_t) = (double (*)(int32_t))pcode; *((double*)pRet) = (*fptr)(ARG_I32(0)); } - void CallFunc_F32_RetF32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F32_RetF32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { float (*fptr)(float) = (float (*)(float))pcode; *((float*)pRet) = (*fptr)(ARG_F32(0)); } - void CallFunc_F32_F32_RetF32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F32_F32_RetF32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { float (*fptr)(float, float) = (float (*)(float, float))pcode; *((float*)pRet) = (*fptr)(ARG_F32(0), ARG_F32(1)); } - void CallFunc_F32_F32_F32_RetF32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F32_F32_F32_RetF32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { float (*fptr)(float, float, float) = (float (*)(float, float, float))pcode; *((float*)pRet) = (*fptr)(ARG_F32(0), ARG_F32(1), ARG_F32(2)); } - void CallFunc_F32_I32_RetF32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F32_I32_RetF32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { float (*fptr)(float, int32_t) = (float (*)(float, int32_t))pcode; *((float*)pRet) = (*fptr)(ARG_F32(0), ARG_I32(1)); } - void CallFunc_Void_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_Void_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)() = (int32_t (*)())pcode; *((int32_t*)pRet) = (*fptr)(); } - void CallFunc_F64_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F64_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(double, int32_t) = (int32_t (*)(double, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_F64(0), ARG_I32(1)); } - void CallFunc_F32_F32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F32_F32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(float, float) = (int32_t (*)(float, float))pcode; *((int32_t*)pRet) = (*fptr)(ARG_F32(0), ARG_F32(1)); } - void CallFunc_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t) = (int32_t (*)(int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0)); } - void CallFunc_I32_F64_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_F64_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, double) = (int32_t (*)(int32_t, double))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_F64(1)); } - void CallFunc_I32_F32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_F32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, float) = (int32_t (*)(int32_t, float))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_F32(1)); } - void CallFunc_I32_F32_I32_I32_F32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_F32_I32_I32_F32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, float, int32_t, int32_t, float) = (int32_t (*)(int32_t, float, int32_t, int32_t, float))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_F32(1), ARG_I32(2), ARG_I32(3), ARG_F32(4)); } - void CallFunc_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t) = (int32_t (*)(int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1)); } - void CallFunc_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2)); } - void CallFunc_I32_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3)); } - void CallFunc_I32_I32_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); } - void CallFunc_I32_I32_I32_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5)); } - void CallFunc_I32_I32_I32_I32_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_I32_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6)); } - void CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6), ARG_I32(7), ARG_I32(8), ARG_I32(9), ARG_I32(10)); } - void CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6), ARG_I32(7), ARG_I32(8), ARG_I32(9), ARG_I32(10), ARG_I32(11), ARG_I32(12), ARG_I32(13), ARG_I32(14), ARG_I32(15), ARG_I32(16)); } - void CallFunc_I32_I32_I32_I64_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_I64_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int64_t) = (int32_t (*)(int32_t, int32_t, int32_t, int64_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I64(3)); } - void CallFunc_I32_I32_I32_IND_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_IND_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_IND(3), ARG_I32(4)); } - void CallFunc_I32_I32_I64_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I64_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int64_t) = (int32_t (*)(int32_t, int32_t, int64_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I64(2)); } - void CallFunc_I32_I32_IND_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_IND_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_IND(2), ARG_I32(3), ARG_I32(4)); } - void CallFunc_I32_I32_IND_I32_I32_IND_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_IND_I32_I32_IND_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_IND(2), ARG_I32(3), ARG_I32(4), ARG_IND(5)); } - void CallFunc_I32_I64_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I64_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int64_t) = (int32_t (*)(int32_t, int64_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I64(1)); } - void CallFunc_I32_I64_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I64_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int64_t, int32_t) = (int32_t (*)(int32_t, int64_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I64(1), ARG_I32(2)); } - void CallFunc_I32_I64_I32_I32_I32_I64_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I64_I32_I32_I32_I64_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int64_t, int32_t, int32_t, int32_t, int64_t) = (int32_t (*)(int32_t, int64_t, int32_t, int32_t, int32_t, int64_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I64(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I64(5)); } - void CallFunc_I32_I64_I64_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I64_I64_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int64_t, int64_t) = (int32_t (*)(int32_t, int64_t, int64_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I64(1), ARG_I64(2)); } - void CallFunc_I32_I64_I64_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I64_I64_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int64_t, int64_t, int32_t) = (int32_t (*)(int32_t, int64_t, int64_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I64(1), ARG_I64(2), ARG_I32(3)); } - void CallFunc_I32_IND_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_IND_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t) = (int32_t (*)(int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_IND(1)); } - void CallFunc_I32_IND_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_IND_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_IND(1), ARG_I32(2)); } - void CallFunc_I32_IND_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_IND_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_IND(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); } - void CallFunc_I32_IND_I32_IND_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_IND_I32_IND_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_IND(1), ARG_I32(2), ARG_IND(3), ARG_I32(4)); } - void CallFunc_I32_IND_IND_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_IND_IND_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_IND(1), ARG_IND(2)); } - void CallFunc_I64_I32_I64_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I64_I32_I64_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int64_t, int32_t, int64_t, int32_t) = (int32_t (*)(int64_t, int32_t, int64_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_I64(0), ARG_I32(1), ARG_I64(2), ARG_I32(3)); } - void CallFunc_IND_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t) = (int32_t (*)(int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_IND(0)); } - void CallFunc_IND_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t) = (int32_t (*)(int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_I32(1)); } - void CallFunc_IND_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2)); } - void CallFunc_IND_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2), ARG_I32(3)); } - void CallFunc_IND_I32_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); } - void CallFunc_IND_I32_I32_I32_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_I32_I32_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5)); } - void CallFunc_IND_I32_IND_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_IND_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_I32(1), ARG_IND(2), ARG_I32(3)); } - void CallFunc_IND_I32_IND_IND_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_IND_IND_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_I32(1), ARG_IND(2), ARG_IND(3)); } - void CallFunc_IND_IND_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_IND_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_IND(1), ARG_I32(2)); } - void CallFunc_IND_IND_I32_I32_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_IND_I32_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_IND(1), ARG_I32(2), ARG_I32(3)); } - void CallFunc_IND_IND_I32_IND_RetI32 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_IND_I32_IND_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t, int32_t, int32_t) = (int32_t (*)(int32_t, int32_t, int32_t, int32_t))pcode; *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_IND(1), ARG_I32(2), ARG_IND(3)); } - void CallFunc_Void_RetI64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_Void_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)() = (int64_t (*)())pcode; *((int64_t*)pRet) = (*fptr)(); } - void CallFunc_I32_RetI64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)(int32_t) = (int64_t (*)(int32_t))pcode; *((int64_t*)pRet) = (*fptr)(ARG_I32(0)); } - void CallFunc_I32_I32_RetI64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)(int32_t, int32_t) = (int64_t (*)(int32_t, int32_t))pcode; *((int64_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1)); } - void CallFunc_I32_I32_I32_I64_RetI64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_I64_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)(int32_t, int32_t, int32_t, int64_t) = (int64_t (*)(int32_t, int32_t, int32_t, int64_t))pcode; *((int64_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I64(3)); } - void CallFunc_I32_I64_RetI64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I64_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)(int32_t, int64_t) = (int64_t (*)(int32_t, int64_t))pcode; *((int64_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I64(1)); } - void CallFunc_I32_I64_I32_RetI64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I64_I32_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)(int32_t, int64_t, int32_t) = (int64_t (*)(int32_t, int64_t, int32_t))pcode; *((int64_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I64(1), ARG_I32(2)); } - void CallFunc_I32_I64_I64_RetI64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I64_I64_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)(int32_t, int64_t, int64_t) = (int64_t (*)(int32_t, int64_t, int64_t))pcode; *((int64_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I64(1), ARG_I64(2)); } - void CallFunc_I64_I64_RetI64 (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I64_I64_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)(int64_t, int64_t) = (int64_t (*)(int64_t, int64_t))pcode; *((int64_t*)pRet) = (*fptr)(ARG_I64(0), ARG_I64(1)); } - void CallFunc_I32_RetIND (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_RetIND(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t) = (int32_t (*)(int32_t))pcode; PORTABILITY_ASSERT("Indirect struct return is not yet implemented."); *((int32_t*)pRet) = (*fptr)(ARG_I32(0)); } - void CallFunc_I32_I32_RetIND (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_RetIND(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t, int32_t) = (int32_t (*)(int32_t, int32_t))pcode; PORTABILITY_ASSERT("Indirect struct return is not yet implemented."); *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_I32(1)); } - void CallFunc_Void_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_Void_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)() = (void (*)())pcode; (*fptr)(); } - void CallFunc_F64_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F64_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(double, int32_t, int32_t) = (void (*)(double, int32_t, int32_t))pcode; (*fptr)(ARG_F64(0), ARG_I32(1), ARG_I32(2)); } - void CallFunc_F32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_F32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(float, int32_t, int32_t) = (void (*)(float, int32_t, int32_t))pcode; (*fptr)(ARG_F32(0), ARG_I32(1), ARG_I32(2)); } - void CallFunc_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t) = (void (*)(int32_t))pcode; (*fptr)(ARG_I32(0)); } - void CallFunc_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t) = (void (*)(int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_I32(1)); } - void CallFunc_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2)); } - void CallFunc_I32_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3)); } - void CallFunc_I32_I32_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); } - void CallFunc_I32_I32_I32_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5)); } - void CallFunc_I32_I32_I32_IND_IND_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_IND_IND_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_IND(3), ARG_IND(4)); } - void CallFunc_I32_I32_I32_IND_IND_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_I32_IND_IND_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_IND(3), ARG_IND(4), ARG_I32(5)); } - void CallFunc_I32_I32_IND_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_IND_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_I32(1), ARG_IND(2)); } - void CallFunc_I32_I32_IND_IND_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_IND_IND_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_I32(1), ARG_IND(2), ARG_IND(3), ARG_I32(4)); } - void CallFunc_I32_I32_IND_IND_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_I32_IND_IND_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_I32(1), ARG_IND(2), ARG_IND(3), ARG_I32(4), ARG_I32(5)); } - void CallFunc_I32_IND_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_IND_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t) = (void (*)(int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_IND(1)); } - void CallFunc_I32_IND_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_IND_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_IND(1), ARG_I32(2)); } - void CallFunc_I32_IND_IND_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I32_IND_IND_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_I32(0), ARG_IND(1), ARG_IND(2), ARG_I32(3)); } - void CallFunc_I64_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_I64_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int64_t) = (void (*)(int64_t))pcode; (*fptr)(ARG_I64(0)); } - void CallFunc_IND_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t) = (void (*)(int32_t))pcode; (*fptr)(ARG_IND(0)); } - void CallFunc_IND_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t) = (void (*)(int32_t, int32_t))pcode; (*fptr)(ARG_IND(0), ARG_I32(1)); } - void CallFunc_IND_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2)); } - void CallFunc_IND_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2), ARG_I32(3)); } - void CallFunc_IND_I32_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); } - void CallFunc_IND_I32_I32_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_I32_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5)); } - void CallFunc_IND_I32_I32_I32_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_I32_I32_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6)); } - void CallFunc_IND_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6), ARG_I32(7), ARG_I32(8), ARG_I32(9), ARG_I32(10), ARG_I32(11)); } - void CallFunc_IND_IND_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_IND_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t) = (void (*)(int32_t, int32_t))pcode; (*fptr)(ARG_IND(0), ARG_IND(1)); } - void CallFunc_IND_IND_I32_I32_I32_RetVoid (PCODE pcode, int8_t *pArgs, int8_t *pRet) + static void CallFunc_IND_IND_I32_I32_I32_RetVoid(PCODE pcode, int8_t* pArgs, int8_t* pRet) { void (*fptr)(int32_t, int32_t, int32_t, int32_t, int32_t) = (void (*)(int32_t, int32_t, int32_t, int32_t, int32_t))pcode; (*fptr)(ARG_IND(0), ARG_IND(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); @@ -655,4 +655,4 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "vnniii", (void*)&CallFunc_IND_IND_I32_I32_I32_RetVoid } }; -const size_t g_wasmThunksCount = sizeof(g_wasmThunks) / sizeof(g_wasmThunks[0]); \ No newline at end of file +const size_t g_wasmThunksCount = sizeof(g_wasmThunks) / sizeof(g_wasmThunks[0]); diff --git a/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs index 32865dc2f09883..fa61bfed821233 100644 --- a/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs +++ b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs @@ -109,7 +109,7 @@ static IEnumerable Args(string signature) static void {{CallFuncName(args, SignatureMapper.CharToNameType(signature[0]))}}(PCODE pcode, int8_t* pArgs, int8_t* pRet) { {{result.nativeType}} (*fptr)({{args.Join(", ", (p, i) => SignatureMapper.CharToNativeType(p))}}) = ({{result.nativeType}} (*)({{args.Join(", ", (p, i) => SignatureMapper.CharToNativeType(p))}}))pcode; - {{portabilityAssert}}{{(result.isVoid ? "" : "*" + "((" + result.nativeType + "*)pRet) = ")}}(*fptr)({{args.Join(", ", (p, i) => $"ARG_{SignatureMapper.CharToNameType(p)}({i})")}}); + {{portabilityAssert}}{{(result.isVoid ? "" : "*" + "((" + result.nativeType + "*)pRet) = ")}}(*fptr)({{args.Join(", ", (p, i) => $"{SignatureMapper.CharToArgType(p)}({i})")}}); } """); @@ -130,6 +130,7 @@ static IEnumerable Args(string signature) }; const size_t g_wasmThunksCount = sizeof(g_wasmThunks) / sizeof(g_wasmThunks[0]); + """); } } diff --git a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs index de7c830c5d5da3..aa9521ac1897ae 100644 --- a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs +++ b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs @@ -19,6 +19,7 @@ internal static class SignatureMapper return null; } + // See https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md char? c = null; if (t.Namespace == "System") { c = t.Name switch @@ -133,6 +134,16 @@ internal static class SignatureMapper _ => throw new InvalidSignatureCharException(c) }; + public static string CharToArgType(char c) => c switch + { + 'i' => "ARG_I32", + 'l' => "ARG_I64", + 'f' => "ARG_F32", + 'd' => "ARG_F64", + 'n' => "ARG_IND", + _ => throw new InvalidSignatureCharException(c) + }; + public static bool IsVoidSignature(string signature) => signature[0] == 'v'; } From 497ef225c548aacb5c74263943fd48573325e41a Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 10 Nov 2025 22:29:42 +0100 Subject: [PATCH 05/10] Feedback --- .../coreclr/InterpToNativeGenerator.cs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs index fa61bfed821233..6bf40b396ec20b 100644 --- a/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs +++ b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs @@ -61,16 +61,6 @@ private static void Emit(StreamWriter w, IEnumerable cookies) var signatures = cookies.OrderBy(c => c).Distinct().ToArray(); Array.Sort(signatures, StringComparer.Ordinal); - - static IEnumerable Args(string signature) - { - for (int i = 1; i < signature.Length; ++i) - yield return signature[i]; - } - - static (bool isVoid, string nativeType) Result(string signature) - => new(SignatureMapper.IsVoidSignature(signature), SignatureMapper.CharToNativeType(signature[0])); - w.Write( """ // Licensed to the .NET Foundation under one or more agreements. @@ -130,7 +120,16 @@ static IEnumerable Args(string signature) }; const size_t g_wasmThunksCount = sizeof(g_wasmThunks) / sizeof(g_wasmThunks[0]); - + """); + + static IEnumerable Args(string signature) + { + for (int i = 1; i < signature.Length; ++i) + yield return signature[i]; + } + + static (bool isVoid, string nativeType) Result(string signature) + => new(SignatureMapper.IsVoidSignature(signature), SignatureMapper.CharToNativeType(signature[0])); } } From 68882f1a16d767728282f13cdfd6829a6a92eed4 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 10 Nov 2025 22:37:33 +0100 Subject: [PATCH 06/10] Feedback --- src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs index aa9521ac1897ae..a3919ec9f63ffa 100644 --- a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs +++ b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs @@ -21,7 +21,8 @@ internal static class SignatureMapper // See https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md char? c = null; - if (t.Namespace == "System") { + if (t.Namespace == "System") + { c = t.Name switch { nameof(String) => 'i', @@ -60,10 +61,12 @@ internal static class SignatureMapper c = 'i'; else if (t.IsInterface) c = 'i'; - else if (t.IsEnum) { + else if (t.IsEnum) + { Type underlyingType = t.GetEnumUnderlyingType(); c = TypeToChar(underlyingType, log, out _, ++depth); - } else if (t.IsPointer) + } + else if (t.IsPointer) c = 'i'; else if (PInvokeTableGenerator.IsFunctionPointer(t)) c = 'i'; @@ -94,7 +97,8 @@ internal static class SignatureMapper return null; } - if (resultIsByRef) { + if (resultIsByRef) + { result = "n"; } From b25f206ec92943c227d3641860bfb424a0fd6b59 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Wed, 12 Nov 2025 17:10:22 +0100 Subject: [PATCH 07/10] Feedback Remove the build logic from the task, let handle it at msbuild level --- .../coreclr/ManagedToNativeGenerator.cs | 95 ++++--------------- 1 file changed, 19 insertions(+), 76 deletions(-) diff --git a/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs index 0ad11bb97c97b4..eee06a7eaeecce 100644 --- a/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs +++ b/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs @@ -93,32 +93,29 @@ private void ExecuteInternal(LogAdapter log) { Dictionary _symbolNameFixups = new(); List managedAssemblies = FilterOutUnmanagedBinaries(Assemblies); - if (ShouldRun(managedAssemblies)) - { - var pinvoke = new PInvokeTableGenerator(FixupSymbolName, log, IsLibraryMode); - var icall = new IcallTableGenerator(RuntimeIcallTableFile, FixupSymbolName, log); + var pinvoke = new PInvokeTableGenerator(FixupSymbolName, log, IsLibraryMode); + var icall = new IcallTableGenerator(RuntimeIcallTableFile, FixupSymbolName, log); - var resolver = new PathAssemblyResolver(managedAssemblies); - using var mlc = new MetadataLoadContext(resolver, "System.Private.CoreLib"); - foreach (string asmPath in managedAssemblies) - { - log.LogMessage(MessageImportance.Low, $"Loading {asmPath} to scan for pinvokes, and icalls"); - Assembly asm = mlc.LoadFromAssemblyPath(asmPath); - pinvoke.ScanAssembly(asm); - icall.ScanAssembly(asm); - } + var resolver = new PathAssemblyResolver(managedAssemblies); + using var mlc = new MetadataLoadContext(resolver, "System.Private.CoreLib"); + foreach (string asmPath in managedAssemblies) + { + log.LogMessage(MessageImportance.Low, $"Loading {asmPath} to scan for pinvokes, and icalls"); + Assembly asm = mlc.LoadFromAssemblyPath(asmPath); + pinvoke.ScanAssembly(asm); + icall.ScanAssembly(asm); + } - IEnumerable cookies = Enumerable.Concat( - pinvoke.Generate(PInvokeModules, PInvokeOutputPath), - Enumerable.Concat(icall.Generate(IcallOutputPath), - missingCookies)); + IEnumerable cookies = Enumerable.Concat( + pinvoke.Generate(PInvokeModules, PInvokeOutputPath), + Enumerable.Concat(icall.Generate(IcallOutputPath), + missingCookies)); - var m2n = new InterpToNativeGenerator(log); - m2n.Generate(cookies, InterpToNativeOutputPath); + var m2n = new InterpToNativeGenerator(log); + m2n.Generate(cookies, InterpToNativeOutputPath); - if (!string.IsNullOrEmpty(CacheFilePath)) - File.WriteAllLines(CacheFilePath, PInvokeModules); - } + if (!string.IsNullOrEmpty(CacheFilePath)) + File.WriteAllLines(CacheFilePath, PInvokeModules); List fileWritesList = new() { PInvokeOutputPath, InterpToNativeOutputPath }; if (!string.IsNullOrEmpty(IcallOutputPath)) @@ -139,60 +136,6 @@ string FixupSymbolName(string name) } } - private bool ShouldRun(IList managedAssemblies) - { - if (string.IsNullOrEmpty(CacheFilePath) || !File.Exists(CacheFilePath)) - { - Log.LogMessage(MessageImportance.Low, $"Running because no cache file found at '{CacheFilePath}'."); - return true; - } - - string oldModules = string.Join(",", File.ReadLines(CacheFilePath).OrderBy(l => l)); - string newModules = string.Join(",", PInvokeModules.OrderBy(l => l)); - if (!string.Equals(oldModules, newModules, StringComparison.InvariantCulture)) - { - Log.LogMessage(MessageImportance.Low, $"Running because the list of pinvoke modules has changed from: {oldModules} to {newModules} ."); - return true; - } - - // compare against the output files - // get the timestamp for oldest output file - DateTime oldestOutputDt = DateTime.MaxValue; - if (CheckShouldRunBecauseOfOutputFile(IcallOutputPath, ref oldestOutputDt) || - CheckShouldRunBecauseOfOutputFile(PInvokeOutputPath, ref oldestOutputDt) || - CheckShouldRunBecauseOfOutputFile(InterpToNativeOutputPath, ref oldestOutputDt)) - { - return true; - } - - foreach (string asm in managedAssemblies) - { - if (File.GetLastWriteTimeUtc(asm) >= oldestOutputDt) - { - Log.LogMessage(MessageImportance.Low, $"Running because {asm} is newer than one of the output files."); - return true; - } - } - - Log.LogMessage(MessageImportance.Low, $"Skipping because all of the assemblies are older than the output files."); - return false; - - bool CheckShouldRunBecauseOfOutputFile(string? path, ref DateTime oldestDt) - { - if (string.IsNullOrEmpty(path)) - return false; - - if (!File.Exists(path)) - { - Log.LogMessage(MessageImportance.Low, $"Running because output file '{path}' does not exist."); - return true; - } - DateTime utc = File.GetLastWriteTimeUtc(path); - oldestDt = utc < oldestDt ? utc : oldestDt; - return false; - } - } - private List FilterOutUnmanagedBinaries(string[] assemblies) { List managedAssemblies = new(assemblies.Length); From 97713851d005fe0d56573f700d1506a866edb389 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Thu, 13 Nov 2025 11:16:59 +0100 Subject: [PATCH 08/10] Feedback Co-authored-by: Jan Kotas --- src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs index a3919ec9f63ffa..cb662cc7f92f4c 100644 --- a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs +++ b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs @@ -54,9 +54,6 @@ internal static class SignatureMapper c = 'i'; else if (t.IsByRef) c = 'i'; - else if (typeof(Delegate).IsAssignableFrom(t)) - // FIXME: Should we narrow this to only certain types of delegates? - c = 'i'; else if (t.IsClass) c = 'i'; else if (t.IsInterface) From 5bfe1a285c4ff3f1cf2dd79fa29266603b393a3b Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Thu, 13 Nov 2025 11:23:04 +0100 Subject: [PATCH 09/10] Feedback --- src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs index cb662cc7f92f4c..21b47c309f1429 100644 --- a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs +++ b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs @@ -50,9 +50,7 @@ internal static class SignatureMapper return c; // FIXME: Most of these need to be L for wasm64 - if (t.IsArray) - c = 'i'; - else if (t.IsByRef) + if (t.IsByRef) c = 'i'; else if (t.IsClass) c = 'i'; @@ -81,7 +79,7 @@ internal static class SignatureMapper isByRefStruct = true; } else - log.Warning("WASM0064", $"Unsupported parameter type '{t.Name}'"); + log.Warning("WASM0065", $"Unsupported parameter type '{t.Name}'"); return c; } From 880e5e164dc9f251cd61faf95885714ce548dc09 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 18 Nov 2025 09:55:37 +0100 Subject: [PATCH 10/10] Feedback Co-authored-by: Larry Ewing --- src/tasks/WasmAppBuilder/WasmAppBuilder.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj index 2c32d089ffc246..3fc33e370b1558 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj @@ -58,7 +58,7 @@ - +