diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake index 2ccced093f6b38..a9ddb0d18aec41 100644 --- a/eng/native/configureplatform.cmake +++ b/eng/native/configureplatform.cmake @@ -221,10 +221,10 @@ if(CLR_CMAKE_HOST_OS STREQUAL emscripten) set(CLR_CMAKE_HOST_BROWSER 1) endif(CLR_CMAKE_HOST_OS STREQUAL emscripten) -if(CLR_CMAKE_TARGET_OS STREQUAL wasi) +if(CLR_CMAKE_HOST_OS STREQUAL wasi) set(CLR_CMAKE_HOST_WASI 1) set(CLR_CMAKE_HOST_UNIX 1) -endif(CLR_CMAKE_TARGET_OS STREQUAL wasi) +endif(CLR_CMAKE_HOST_OS STREQUAL wasi) #-------------------------------------------- # This repo builds two set of binaries diff --git a/src/coreclr/build-runtime.cmd b/src/coreclr/build-runtime.cmd index 4374e13face5ae..77788bbf6c21ff 100644 --- a/src/coreclr/build-runtime.cmd +++ b/src/coreclr/build-runtime.cmd @@ -281,6 +281,9 @@ if "%__TargetOS%"=="android" ( if "%__TargetOS%"=="browser" ( set __CrossTarget=1 ) +if "%__TargetOS%"=="wasi" ( + set __CrossTarget=1 +) if %__CrossTarget% EQU 0 ( call "%__RepoRootDir%\eng\native\version\copy_version_files.cmd" diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj index 1c77956d8bbe6b..13811c03632ff8 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj @@ -37,6 +37,14 @@ + + + + + + ThunkShapes() + { + // (description, isStatic, expected signature key) + TheoryData data = new() + { + { "void(int)", true, "vip" }, + { "int(int)", false, "iTip" }, + { "long(double)", true, "ldp" }, + { "int(float, double, long)", false, "iTfdlp" }, + { "void()", false, "vTp" }, + // Struct returns: the shape both encoders previously disagreed on. + { "S8()", true, "S8p" }, + { "S8(int)", false, "S8Tip" }, + { "S16(long, int)", true, "S16lip" }, + { "S12(S12, int)", false, "S12TS12ip" }, + { "void(S8)", false, "vTS8p" }, + }; + + return data; + } + + /// + /// The R2R-to-interpreter thunks are written by the WasmAppBuilder generator but called by code + /// crossgen2 emits, so the two have to agree on the wasm signature behind every key. This checks + /// arity and types: a missing hidden return buffer — which is what returning the struct by value + /// produces, since the compiler then inserts its own pointer ahead of the stack pointer — or a + /// wrong scalar width shows up here. It cannot see two same-typed parameters swapped; + /// covers the order. + /// + [Theory] + [MemberData(nameof(ThunkShapes))] + public void GeneratedThunkMatchesLoweredWasmSignature(string description, bool isStatic, string expectedKey) + { + _output.WriteLine($"{description} => {expectedKey}"); + + ReadyToRunCompilerContext context = CreateWasmContext(); + WasmSignature lowered = WasmLowering.GetSignature(MakeThunkSignature(context, description, isStatic), WasmLowering.LoweringFlags.None); + + Assert.Equal(expectedKey, lowered.SignatureString); + Assert.Equal(lowered.FuncType.Params.Types.ToArray(), GetThunkWasmParameters(lowered.SignatureString)); + } + + /// + /// A generic context argument is an ordinary pointer slot that follows the return buffer, so it + /// encodes exactly like a leading int parameter and must lay out the same way. + /// + [Fact] + public void GenericContextArgumentFollowsTheReturnBuffer() + { + ReadyToRunCompilerContext context = CreateWasmContext(); + MethodSignature signature = new( + MethodSignatureFlags.None, + genericParameterCount: 0, + returnType: MakeBlobOfSize(context, 8), + parameters: Array.Empty()); + + WasmSignature lowered = WasmLowering.GetSignature(signature, WasmLowering.LoweringFlags.HasGenericContextArg); + + Assert.Equal("S8Tip", lowered.SignatureString); + Assert.Equal(lowered.FuncType.Params.Types.ToArray(), GetThunkWasmParameters(lowered.SignatureString)); + } + + public static TheoryData ThunkParameterOrder() + { + // Transcribed from WasmR2RToInterpreterThunkNode.EmitCode, which stores 'this' from the + // local after the stack pointer and then reads the buffer from + // retBufLocalIndex = 1 + (hasThis ? 1 : 0). A generic context is an ordinary slot that + // follows the buffer, so it is spelled like any other argument here. + return new TheoryData + { + { Array.Empty(), true, new[] { "retBuf" } }, + { new[] { "i" }, true, new[] { "retBuf", "arg0" } }, + { new[] { "T" }, true, new[] { "arg0", "retBuf" } }, + { new[] { "T", "i" }, true, new[] { "arg0", "retBuf", "arg1" } }, + { new[] { "T", "i", "S8" }, true, new[] { "arg0", "retBuf", "arg1", "arg2" } }, + { new[] { "T", "i" }, false, new[] { "arg0", "arg1" } }, + { new[] { "i", "l" }, false, new[] { "arg0", "arg1" } }, + }; + } + + /// + /// The transposition that shipped broken, and the reason it needs its own test: for an instance + /// method the hidden return buffer follows this, and both are i32, so getting the + /// order wrong leaves the wasm type sequence unchanged. Comparing lowered parameter types cannot + /// see it — only the positions can. + /// + [Theory] + [MemberData(nameof(ThunkParameterOrder))] + public void ThunkParametersFollowCrossgen2Order(string[] args, bool isStructReturn, string[] expectedNames) + { + Assert.Equal( + expectedNames, + PortableEntryPointThunkSignature.GetDeclaredParameters(args, isStructReturn).Select(static p => p.Name)); + } + + /// + /// Builds the signature named by in . + /// + private static MethodSignature MakeThunkSignature(ReadyToRunCompilerContext context, string description, bool isStatic) + { + TypeDesc Int32() => context.GetWellKnownType(WellKnownType.Int32); + + (TypeDesc Return, TypeDesc[] Parameters) shape = description switch + { + "void(int)" => (context.GetWellKnownType(WellKnownType.Void), new[] { Int32() }), + "int(int)" => (Int32(), new[] { Int32() }), + "long(double)" => (context.GetWellKnownType(WellKnownType.Int64), new[] { context.GetWellKnownType(WellKnownType.Double) }), + "int(float, double, long)" => (Int32(), new[] + { + context.GetWellKnownType(WellKnownType.Single), + context.GetWellKnownType(WellKnownType.Double), + context.GetWellKnownType(WellKnownType.Int64), + }), + "void()" => (context.GetWellKnownType(WellKnownType.Void), Array.Empty()), + "S8()" => (MakeBlobOfSize(context, 8), Array.Empty()), + "S8(int)" => (MakeBlobOfSize(context, 8), new[] { Int32() }), + "S16(long, int)" => (MakeBlobOfSize(context, 16), new[] { context.GetWellKnownType(WellKnownType.Int64), Int32() }), + "S12(S12, int)" => (MakeBlobOfSize(context, 12), new TypeDesc[] { MakeBlobOfSize(context, 12), Int32() }), + "void(S8)" => (context.GetWellKnownType(WellKnownType.Void), new TypeDesc[] { MakeBlobOfSize(context, 8) }), + _ => throw new ArgumentOutOfRangeException(nameof(description), description, null), + }; + + return new MethodSignature( + isStatic ? MethodSignatureFlags.Static : MethodSignatureFlags.None, + genericParameterCount: 0, + returnType: shape.Return, + parameters: shape.Parameters); + } + + /// + /// A multi-field struct of the given size. It needs more than one field: a single-field struct + /// is lowered to the field's own type and would never reach the S<N> encoding. + /// + private static DefType MakeBlobOfSize(ReadyToRunCompilerContext context, int size) + { + TypeDesc int32 = context.GetWellKnownType(WellKnownType.Int32); + TypeDesc int64 = context.GetWellKnownType(WellKnownType.Int64); + + DefType result = size switch + { + 8 => MakeValueTuple(context, int32, int32), + 12 => MakeValueTuple(context, int32, int32, int32), + 16 => MakeValueTuple(context, int64, int64), + _ => throw new ArgumentOutOfRangeException(nameof(size), size, null), + }; + + Assert.Equal(size, result.InstanceFieldSize.AsInt); + return result; + } + + /// + /// The wasm parameters of the thunk the generator emits for . + /// The stack pointer comes from the WASM_CALLABLE_FUNC macro and the portable entrypoint is + /// appended after the declared arguments, so neither is part of the generator's own list. + /// + private static List GetThunkWasmParameters(string signatureKey) + { + List tokens = SignatureMapper.ParseSignatureTokens(signatureKey); + string returnToken = tokens[0]; + + Assert.Equal("p", tokens[tokens.Count - 1]); + tokens.RemoveAt(tokens.Count - 1); + List args = tokens.GetRange(1, tokens.Count - 1); + + List parameters = new() { WasmValueType.I32 }; // callersStackPointer + foreach (PortableEntryPointThunkSignature.Parameter parameter in + PortableEntryPointThunkSignature.GetDeclaredParameters(args, PortableEntryPointThunkSignature.IsStructToken(returnToken))) + { + parameters.Add(NativeTypeToWasmType(parameter.NativeType)); + } + + parameters.Add(WasmValueType.I32); // portable entrypoint + return parameters; + } + + /// + /// Maps a C type the generator emits onto the wasm type clang gives it on wasm32. Reading the + /// generator's own type strings, rather than re-deriving them from the signature, is what makes + /// this a check of the emitted thunk instead of a restatement of the encoding rules. + /// + private static WasmValueType NativeTypeToWasmType(string nativeType) => nativeType switch + { + "int32_t" or "int8_t*" or "PCODE" => WasmValueType.I32, + "int64_t" => WasmValueType.I64, + "float" => WasmValueType.F32, + "double" => WasmValueType.F64, + _ => throw new ArgumentOutOfRangeException(nameof(nativeType), nativeType, null), + }; + private static DefType MakeValueTuple(ReadyToRunCompilerContext context, params TypeDesc[] fields) => ((MetadataType)context.SystemModule.GetType( "System"u8, System.Text.Encoding.UTF8.GetBytes($"ValueTuple`{fields.Length}"))) diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index bcc0a0d6e791cc..aa6b9d10ffaff7 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -973,6 +973,11 @@ elseif(CLR_CMAKE_TARGET_ARCH_WASM) else() set(WASM_THUNK_SUBDIR browser) endif() + # Unlike the other generated call helpers, the portable entrypoint thunks are not regenerated + # per app, so they belong in the shipped static library rather than in cee_wks_gen. + list(APPEND VM_SOURCES_WKS_ARCH + ${ARCH_SOURCES_DIR}/${WASM_THUNK_SUBDIR}/callhelpers-portable-entrypoints.cpp + ) set(VM_SOURCES_WKS_GEN ${ARCH_SOURCES_DIR}/${WASM_THUNK_SUBDIR}/callhelpers-interp-to-managed.cpp ${ARCH_SOURCES_DIR}/${WASM_THUNK_SUBDIR}/callhelpers-reverse.cpp diff --git a/src/coreclr/vm/wasm/browser/callhelpers-interp-to-managed.cpp b/src/coreclr/vm/wasm/browser/callhelpers-interp-to-managed.cpp index dc7af3ffa4ea3a..a82b48a6c00b7e 100644 --- a/src/coreclr/vm/wasm/browser/callhelpers-interp-to-managed.cpp +++ b/src/coreclr/vm/wasm/browser/callhelpers-interp-to-managed.cpp @@ -17,9 +17,83 @@ #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)) +typedef struct { char d[1]; } wasm_ret_S1; +typedef struct { char d[8]; } wasm_ret_S8; +typedef struct { char d[12]; } wasm_ret_S12; +typedef struct { char d[16]; } wasm_ret_S16; namespace { + NOINLINE static void CallFunc_This_S12_I32_RetS12_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_IND(1), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_S12_I32_RetS12_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_I32(1), ARG_IND(2), ARG_I32(4), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_RetS12_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_I32(1), ARG_I32(2), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_RetS12_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_I32(1), ARG_I32(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_RetS16_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, PCODE) = *(void (**)(int*, int32_t, int8_t*, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, pPortableEntryPoint); + } + + NOINLINE static void CallFunc_L2_I32_RetS16_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int8_t*, int64_t, int64_t, int32_t, PCODE) = *(void (**)(int*, int8_t*, int64_t, int64_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, pRet, ARG_I64(0), ARG_I64(1), ARG_I32(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_RetS1_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, PCODE) = *(void (**)(int*, int32_t, int8_t*, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_RetS8_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_I32(1), ARG_I32(2), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_RetS8_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_I32(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_RetS8_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, PCODE) = *(void (**)(int*, int32_t, int8_t*, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, pPortableEntryPoint); + } + NOINLINE static void CallFunc_F64_F64_F64_RetF64_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -166,6 +240,97 @@ namespace *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5)); } + NOINLINE static void CallFunc_S8_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_IND(0), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S12_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S12_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_S8_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_IND(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_I32_S8_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_I32(2), ARG_IND(3), ARG_I32(4), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_I32(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_S12_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_IND(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_S8_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_IND(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), pPortableEntryPoint); + } + NOINLINE static void CallFunc_This_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -180,6 +345,13 @@ namespace *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), pPortableEntryPoint); } + NOINLINE static void CallFunc_F64_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, double, PCODE) = *(int32_t (**)(int*, double, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_F64(0), pPortableEntryPoint); + } + static void CallFunc_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t) = (int32_t (*)(int32_t))pcode; @@ -198,6 +370,13 @@ namespace *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_IND(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); } + NOINLINE static void CallFunc_I32_S8_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + 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; @@ -258,6 +437,20 @@ 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), ARG_I32(11), ARG_I32(12), ARG_I32(13)); } + NOINLINE static void CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6), ARG_I32(7), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_I32_I32_I32_I32_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6), pPortableEntryPoint); + } + NOINLINE static void CallFunc_I32_I32_I32_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -379,6 +572,13 @@ namespace *((int64_t*)pRet) = (*fptr)(); } + NOINLINE static void CallFunc_F64_RetI64_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int64_t (*fptr)(int*, double, PCODE) = *(int64_t (**)(int*, double, PCODE))(pPortableEntryPoint); + *((int64_t*)pRet) = (*fptr)(&framePointer, ARG_F64(0), pPortableEntryPoint); + } + static void CallFunc_I32_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)(int32_t) = (int64_t (*)(int32_t))pcode; @@ -510,6 +710,90 @@ namespace (*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)); } + NOINLINE static void CallFunc_This_S12_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_S8_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_IND(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_I32(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_S8_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_IND(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_S8_S8_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_IND(3), ARG_IND(4), ARG_I32(5), ARG_I32(6), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), pPortableEntryPoint); + } + NOINLINE static void CallFunc_This_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -627,6 +911,13 @@ namespace (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I64(4)); } + NOINLINE static void CallFunc_I32_I32_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), pPortableEntryPoint); + } + NOINLINE static void CallFunc_I32_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -663,6 +954,16 @@ namespace } const StringToWasmSigThunk g_wasmThunks[] = { + { "MS12TS12ip", (void*)&CallFunc_This_S12_I32_RetS12_PE }, + { "MS12TiS12ip", (void*)&CallFunc_This_I32_S12_I32_RetS12_PE }, + { "MS12Tiiip", (void*)&CallFunc_This_I32_I32_I32_RetS12_PE }, + { "MS12Tiip", (void*)&CallFunc_This_I32_I32_RetS12_PE }, + { "MS16Tp", (void*)&CallFunc_This_RetS16_PE }, + { "MS16l2ip", (void*)&CallFunc_L2_I32_RetS16_PE }, + { "MS1Tp", (void*)&CallFunc_This_RetS1_PE }, + { "MS8Tiiip", (void*)&CallFunc_This_I32_I32_I32_RetS8_PE }, + { "MS8Tip", (void*)&CallFunc_This_I32_RetS8_PE }, + { "MS8Tp", (void*)&CallFunc_This_RetS8_PE }, { "Mddddp", (void*)&CallFunc_F64_F64_F64_RetF64_PE }, { "Mdddp", (void*)&CallFunc_F64_F64_RetF64_PE }, { "Mddip", (void*)&CallFunc_F64_I32_RetF64_PE }, @@ -686,11 +987,26 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "MiS8iii", (void*)&CallFunc_S8_I32_I32_I32_RetI32 }, { "MiS8iiii", (void*)&CallFunc_S8_I32_I32_I32_I32_RetI32 }, { "MiS8iiiii", (void*)&CallFunc_S8_I32_I32_I32_I32_I32_RetI32 }, + { "MiS8p", (void*)&CallFunc_S8_RetI32_PE }, + { "MiTS12ip", (void*)&CallFunc_This_S12_I32_RetI32_PE }, + { "MiTS12p", (void*)&CallFunc_This_S12_RetI32_PE }, + { "MiTS8S8p", (void*)&CallFunc_This_S8_S8_RetI32_PE }, + { "MiTS8iS8ip", (void*)&CallFunc_This_S8_I32_S8_I32_RetI32_PE }, + { "MiTS8iiip", (void*)&CallFunc_This_S8_I32_I32_I32_RetI32_PE }, + { "MiTS8ip", (void*)&CallFunc_This_S8_I32_RetI32_PE }, + { "MiTS8p", (void*)&CallFunc_This_S8_RetI32_PE }, + { "MiTiS12p", (void*)&CallFunc_This_I32_S12_RetI32_PE }, + { "MiTiS8p", (void*)&CallFunc_This_I32_S8_RetI32_PE }, + { "MiTiiiip", (void*)&CallFunc_This_I32_I32_I32_I32_RetI32_PE }, + { "MiTiiip", (void*)&CallFunc_This_I32_I32_I32_RetI32_PE }, + { "MiTiip", (void*)&CallFunc_This_I32_I32_RetI32_PE }, { "MiTip", (void*)&CallFunc_This_I32_RetI32_PE }, { "MiTp", (void*)&CallFunc_This_RetI32_PE }, + { "Midp", (void*)&CallFunc_F64_RetI32_PE }, { "Mii", (void*)&CallFunc_I32_RetI32 }, { "MiiS8i", (void*)&CallFunc_I32_S8_I32_RetI32 }, { "MiiS8iii", (void*)&CallFunc_I32_S8_I32_I32_I32_RetI32 }, + { "MiiS8p", (void*)&CallFunc_I32_S8_RetI32_PE }, { "Miii", (void*)&CallFunc_I32_I32_RetI32 }, { "MiiiS8iiS8", (void*)&CallFunc_I32_I32_S8_I32_I32_S8_RetI32 }, { "MiiiS8iiii", (void*)&CallFunc_I32_I32_S8_I32_I32_I32_I32_RetI32 }, @@ -701,6 +1017,8 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "Miiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_RetI32 }, { "Miiiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_RetI32 }, { "Miiiiiiiiiiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 }, + { "Miiiiiiiiip", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_RetI32_PE }, + { "Miiiiiiiip", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_RetI32_PE }, { "Miiiiiiip", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_RetI32_PE }, { "Miiiiiip", (void*)&CallFunc_I32_I32_I32_I32_I32_RetI32_PE }, { "Miiiiip", (void*)&CallFunc_I32_I32_I32_I32_RetI32_PE }, @@ -720,6 +1038,7 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "Milili", (void*)&CallFunc_I64_I32_I64_I32_RetI32 }, { "Mip", (void*)&CallFunc_Void_RetI32_PE }, { "Ml", (void*)&CallFunc_Void_RetI64 }, + { "Mldp", (void*)&CallFunc_F64_RetI64_PE }, { "Mli", (void*)&CallFunc_I32_RetI64 }, { "Mliii", (void*)&CallFunc_I32_I32_I32_RetI64 }, { "Mliiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_RetI64 }, @@ -741,6 +1060,18 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "MvS8iiiii", (void*)&CallFunc_S8_I32_I32_I32_I32_I32_RetVoid }, { "MvS8iiiiii", (void*)&CallFunc_S8_I32_I32_I32_I32_I32_I32_RetVoid }, { "MvS8iiiiiiiiiii", (void*)&CallFunc_S8_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetVoid }, + { "MvTS12p", (void*)&CallFunc_This_S12_RetVoid_PE }, + { "MvTS32p", (void*)&CallFunc_This_S32_RetVoid_PE }, + { "MvTS8S8p", (void*)&CallFunc_This_S8_S8_RetVoid_PE }, + { "MvTS8ip", (void*)&CallFunc_This_S8_I32_RetVoid_PE }, + { "MvTS8p", (void*)&CallFunc_This_S8_RetVoid_PE }, + { "MvTiS8p", (void*)&CallFunc_This_I32_S8_RetVoid_PE }, + { "MvTiiS8S8iip", (void*)&CallFunc_This_I32_I32_S8_S8_I32_I32_RetVoid_PE }, + { "MvTiiiiip", (void*)&CallFunc_This_I32_I32_I32_I32_I32_RetVoid_PE }, + { "MvTiiiip", (void*)&CallFunc_This_I32_I32_I32_I32_RetVoid_PE }, + { "MvTiiip", (void*)&CallFunc_This_I32_I32_I32_RetVoid_PE }, + { "MvTiip", (void*)&CallFunc_This_I32_I32_RetVoid_PE }, + { "MvTip", (void*)&CallFunc_This_I32_RetVoid_PE }, { "MvTp", (void*)&CallFunc_This_RetVoid_PE }, { "Mvdddddddddii", (void*)&CallFunc_F64_F64_F64_F64_F64_F64_F64_F64_F64_I32_I32_RetVoid }, { "Mvdi", (void*)&CallFunc_F64_I32_RetVoid }, @@ -760,6 +1091,7 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "Mviiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_RetVoid }, { "Mviiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_RetVoid }, { "Mviiiil", (void*)&CallFunc_I32_I32_I32_I32_I64_RetVoid }, + { "Mviiiip", (void*)&CallFunc_I32_I32_I32_I32_RetVoid_PE }, { "Mviiip", (void*)&CallFunc_I32_I32_I32_RetVoid_PE }, { "Mviip", (void*)&CallFunc_I32_I32_RetVoid_PE }, { "Mvip", (void*)&CallFunc_I32_RetVoid_PE }, diff --git a/src/coreclr/vm/wasm/browser/callhelpers-pinvoke.cpp b/src/coreclr/vm/wasm/browser/callhelpers-pinvoke.cpp index 9dbd7f579c68e6..2248bb068804aa 100644 --- a/src/coreclr/vm/wasm/browser/callhelpers-pinvoke.cpp +++ b/src/coreclr/vm/wasm/browser/callhelpers-pinvoke.cpp @@ -11,7 +11,6 @@ #include extern "C" { - uint32_t CompressionNative_CompressBound (uint32_t); uint32_t CompressionNative_Crc32 (uint32_t, void *, int32_t); int32_t CompressionNative_Deflate (void *, int32_t); int32_t CompressionNative_DeflateEnd (void *); @@ -196,7 +195,6 @@ static const Entry s_libSystem_Globalization_Native [] = { }; static const Entry s_libSystem_IO_Compression_Native [] = { - DllImportEntry(CompressionNative_CompressBound) // System.IO.Compression DllImportEntry(CompressionNative_Crc32) // System.IO.Compression DllImportEntry(CompressionNative_Deflate) // System.IO.Compression, System.Net.WebSockets DllImportEntry(CompressionNative_DeflateEnd) // System.IO.Compression, System.Net.WebSockets @@ -236,7 +234,7 @@ static const Entry s_libSystem_Native [] = { DllImportEntry(SystemNative_Free) // System.Private.CoreLib DllImportEntry(SystemNative_FreeLibrary) // System.Private.CoreLib DllImportEntry(SystemNative_GetCpuUtilization) // System.Private.CoreLib - DllImportEntry(SystemNative_GetCryptographicallySecureRandomBytes) // System.Private.CoreLib, System.Security.Cryptography + DllImportEntry(SystemNative_GetCryptographicallySecureRandomBytes) // System.IO.Compression, System.Private.CoreLib, System.Security.Cryptography DllImportEntry(SystemNative_GetCwd) // System.Private.CoreLib DllImportEntry(SystemNative_GetDefaultSearchOrderPseudoHandle) // System.Private.CoreLib DllImportEntry(SystemNative_GetErrNo) // System.Private.CoreLib @@ -326,7 +324,7 @@ typedef struct PInvokeTable { static PInvokeTable s_PInvokeTables[] = { {"libSystem.Globalization.Native", s_libSystem_Globalization_Native, 34}, - {"libSystem.IO.Compression.Native", s_libSystem_IO_Compression_Native, 10}, + {"libSystem.IO.Compression.Native", s_libSystem_IO_Compression_Native, 9}, {"libSystem.Native", s_libSystem_Native, 94}, {"libSystem.Native.Browser", s_libSystem_Native_Browser, 1}, {"libSystem.Runtime.InteropServices.JavaScript.Native", s_libSystem_Runtime_InteropServices_JavaScript_Native, 6} diff --git a/src/coreclr/vm/wasm/browser/callhelpers-portable-entrypoints.cpp b/src/coreclr/vm/wasm/browser/callhelpers-portable-entrypoints.cpp new file mode 100644 index 00000000000000..cbe20c0ef987a0 --- /dev/null +++ b/src/coreclr/vm/wasm/browser/callhelpers-portable-entrypoints.cpp @@ -0,0 +1,1461 @@ +// 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 +#include +#include "callhelpers.hpp" + +void ExecuteInterpretedMethodWithArgs_PortableEntryPoint(PCODE portableEntrypoint, TransitionBlock* block, size_t argsSize, int8_t* retBuff); + +namespace +{ + FCDECL4(void, CallInterpreter_This_S12_I32_RetS12, int32_t, int8_t*, int8_t*, int32_t); + WASM_CALLABLE_FUNC_5(void, CallInterpreter_This_S12_I32_RetS12, int32_t arg0, int8_t* retBuf, int8_t* arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 12); + transitionBlock.args[3] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL5(void, CallInterpreter_This_I32_S12_I32_RetS12, int32_t, int8_t*, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_6(void, CallInterpreter_This_I32_S12_I32_RetS12, int32_t arg0, int8_t* retBuf, int32_t arg1, int8_t* arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + memcpy(&transitionBlock.args[2], arg2, 12); + transitionBlock.args[4] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL5(void, CallInterpreter_This_I32_I32_I32_RetS12, int32_t, int8_t*, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(void, CallInterpreter_This_I32_I32_I32_RetS12, int32_t arg0, int8_t* retBuf, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL4(void, CallInterpreter_This_I32_I32_RetS12, int32_t, int8_t*, int32_t, int32_t); + WASM_CALLABLE_FUNC_5(void, CallInterpreter_This_I32_I32_RetS12, int32_t arg0, int8_t* retBuf, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL2(void, CallInterpreter_This_RetS16, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_RetS16, int32_t arg0, int8_t* retBuf, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL4(void, CallInterpreter_L2_I32_RetS16, int8_t*, int64_t, int64_t, int32_t); + WASM_CALLABLE_FUNC_5(void, CallInterpreter_L2_I32_RetS16, int8_t* retBuf, int64_t arg0Lo, int64_t arg0Hi, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = arg0Lo; + transitionBlock.args[1] = arg0Hi; + transitionBlock.args[2] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL2(void, CallInterpreter_This_RetS1, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_RetS1, int32_t arg0, int8_t* retBuf, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL5(void, CallInterpreter_This_I32_I32_I32_RetS8, int32_t, int8_t*, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(void, CallInterpreter_This_I32_I32_I32_RetS8, int32_t arg0, int8_t* retBuf, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL3(void, CallInterpreter_This_I32_RetS8, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_This_I32_RetS8, int32_t arg0, int8_t* retBuf, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL2(void, CallInterpreter_This_RetS8, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_RetS8, int32_t arg0, int8_t* retBuf, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL3(double, CallInterpreter_F64_F64_F64_RetF64, double, double, double); + WASM_CALLABLE_FUNC_4(double, CallInterpreter_F64_F64_F64_RetF64, double arg0, double arg1, double arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + *(double*)&transitionBlock.args[1] = arg1; + *(double*)&transitionBlock.args[2] = arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + double result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(double, CallInterpreter_F64_F64_RetF64, double, double); + WASM_CALLABLE_FUNC_3(double, CallInterpreter_F64_F64_RetF64, double arg0, double arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + *(double*)&transitionBlock.args[1] = arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + double result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(double, CallInterpreter_F64_I32_RetF64, double, int32_t); + WASM_CALLABLE_FUNC_3(double, CallInterpreter_F64_I32_RetF64, double arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + double result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(double, CallInterpreter_F64_RetF64, double); + WASM_CALLABLE_FUNC_2(double, CallInterpreter_F64_RetF64, double arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + double result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(float, CallInterpreter_F32_F32_F32_RetF32, float, float, float); + WASM_CALLABLE_FUNC_4(float, CallInterpreter_F32_F32_F32_RetF32, float arg0, float arg1, float arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(float*)&transitionBlock.args[0] = arg0; + *(float*)&transitionBlock.args[1] = arg1; + *(float*)&transitionBlock.args[2] = arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + float result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(float, CallInterpreter_F32_F32_RetF32, float, float); + WASM_CALLABLE_FUNC_3(float, CallInterpreter_F32_F32_RetF32, float arg0, float arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(float*)&transitionBlock.args[0] = arg0; + *(float*)&transitionBlock.args[1] = arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + float result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(float, CallInterpreter_F32_I32_RetF32, float, int32_t); + WASM_CALLABLE_FUNC_3(float, CallInterpreter_F32_I32_RetF32, float arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(float*)&transitionBlock.args[0] = arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + float result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(float, CallInterpreter_F32_RetF32, float); + WASM_CALLABLE_FUNC_2(float, CallInterpreter_F32_RetF32, float arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(float*)&transitionBlock.args[0] = arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + float result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(int32_t, CallInterpreter_S8_RetI32, int8_t*); + WASM_CALLABLE_FUNC_2(int32_t, CallInterpreter_S8_RetI32, int8_t* arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + memcpy(&transitionBlock.args[0], arg0, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_S12_I32_RetI32, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_S12_I32_RetI32, int32_t arg0, int8_t* arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 12); + transitionBlock.args[3] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int32_t, CallInterpreter_This_S12_RetI32, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_This_S12_RetI32, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 12); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_S8_S8_RetI32, int32_t, int8_t*, int8_t*); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_S8_S8_RetI32, int32_t arg0, int8_t* arg1, int8_t* arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + memcpy(&transitionBlock.args[2], arg2, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL5(int32_t, CallInterpreter_This_S8_I32_S8_I32_RetI32, int32_t, int8_t*, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_6(int32_t, CallInterpreter_This_S8_I32_S8_I32_RetI32, int32_t arg0, int8_t* arg1, int32_t arg2, int8_t* arg3, int32_t arg4, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + transitionBlock.args[2] = (int64_t)arg2; + memcpy(&transitionBlock.args[3], arg3, 8); + transitionBlock.args[4] = (int64_t)arg4; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL5(int32_t, CallInterpreter_This_S8_I32_I32_I32_RetI32, int32_t, int8_t*, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(int32_t, CallInterpreter_This_S8_I32_I32_I32_RetI32, int32_t arg0, int8_t* arg1, int32_t arg2, int32_t arg3, int32_t arg4, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_S8_I32_RetI32, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_S8_I32_RetI32, int32_t arg0, int8_t* arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int32_t, CallInterpreter_This_S8_RetI32, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_This_S8_RetI32, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_I32_S12_RetI32, int32_t, int32_t, int8_t*); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_I32_S12_RetI32, int32_t arg0, int32_t arg1, int8_t* arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + memcpy(&transitionBlock.args[2], arg2, 12); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_I32_S8_RetI32, int32_t, int32_t, int8_t*); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_I32_S8_RetI32, int32_t arg0, int32_t arg1, int8_t* arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + memcpy(&transitionBlock.args[2], arg2, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL5(int32_t, CallInterpreter_This_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(int32_t, CallInterpreter_This_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL4(int32_t, CallInterpreter_This_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_5(int32_t, CallInterpreter_This_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_I32_I32_RetI32, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int32_t, CallInterpreter_This_I32_RetI32, int32_t, int32_t); + WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_This_I32_RetI32, int32_t arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(int32_t, CallInterpreter_This_RetI32, int32_t); + WASM_CALLABLE_FUNC_2(int32_t, CallInterpreter_This_RetI32, int32_t arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(int32_t, CallInterpreter_F64_RetI32, double); + WASM_CALLABLE_FUNC_2(int32_t, CallInterpreter_F64_RetI32, double arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int32_t, CallInterpreter_I32_S8_RetI32, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_I32_S8_RetI32, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL8(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_9(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[8]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + transitionBlock.args[5] = (int64_t)arg5; + transitionBlock.args[6] = (int64_t)arg6; + transitionBlock.args[7] = (int64_t)arg7; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL7(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_8(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, int32_t arg6, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[7]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + transitionBlock.args[5] = (int64_t)arg5; + transitionBlock.args[6] = (int64_t)arg6; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL6(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_7(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[6]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + transitionBlock.args[5] = (int64_t)arg5; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL5(int32_t, CallInterpreter_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(int32_t, CallInterpreter_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL4(int32_t, CallInterpreter_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_5(int32_t, CallInterpreter_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_I32_I32_I32_RetI32, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int32_t, CallInterpreter_I32_I32_RetI32, int32_t, int32_t); + WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_I32_I32_RetI32, int32_t arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(int32_t, CallInterpreter_I32_RetI32, int32_t); + WASM_CALLABLE_FUNC_2(int32_t, CallInterpreter_I32_RetI32, int32_t arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL0(int32_t, CallInterpreter_Void_RetI32); + WASM_CALLABLE_FUNC_1(int32_t, CallInterpreter_Void_RetI32, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, 0, (int8_t*)&result); + return result; + } + + FCDECL1(int64_t, CallInterpreter_F64_RetI64, double); + WASM_CALLABLE_FUNC_2(int64_t, CallInterpreter_F64_RetI64, double arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int64_t, CallInterpreter_I32_I64_I64_RetI64, int32_t, int64_t, int64_t); + WASM_CALLABLE_FUNC_4(int64_t, CallInterpreter_I32_I64_I64_RetI64, int32_t arg0, int64_t arg1, int64_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int64_t, CallInterpreter_I32_I64_RetI64, int32_t, int64_t); + WASM_CALLABLE_FUNC_3(int64_t, CallInterpreter_I32_I64_RetI64, int32_t arg0, int64_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(int64_t, CallInterpreter_I32_RetI64, int32_t); + WASM_CALLABLE_FUNC_2(int64_t, CallInterpreter_I32_RetI64, int32_t arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int64_t, CallInterpreter_I64_I64_RetI64, int64_t, int64_t); + WASM_CALLABLE_FUNC_3(int64_t, CallInterpreter_I64_I64_RetI64, int64_t arg0, int64_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL0(int64_t, CallInterpreter_Void_RetI64); + WASM_CALLABLE_FUNC_1(int64_t, CallInterpreter_Void_RetI64, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, 0, (int8_t*)&result); + return result; + } + + FCDECL2(void, CallInterpreter_This_S12_RetVoid, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_S12_RetVoid, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 12); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL2(void, CallInterpreter_This_S32_RetVoid, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_S32_RetVoid, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 32); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_This_S8_S8_RetVoid, int32_t, int8_t*, int8_t*); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_This_S8_S8_RetVoid, int32_t arg0, int8_t* arg1, int8_t* arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + memcpy(&transitionBlock.args[2], arg2, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_This_S8_I32_RetVoid, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_This_S8_I32_RetVoid, int32_t arg0, int8_t* arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL2(void, CallInterpreter_This_S8_RetVoid, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_S8_RetVoid, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_This_I32_S8_RetVoid, int32_t, int32_t, int8_t*); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_This_I32_S8_RetVoid, int32_t arg0, int32_t arg1, int8_t* arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + memcpy(&transitionBlock.args[2], arg2, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL7(void, CallInterpreter_This_I32_I32_S8_S8_I32_I32_RetVoid, int32_t, int32_t, int32_t, int8_t*, int8_t*, int32_t, int32_t); + WASM_CALLABLE_FUNC_8(void, CallInterpreter_This_I32_I32_S8_S8_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, int8_t* arg3, int8_t* arg4, int32_t arg5, int32_t arg6, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[7]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + memcpy(&transitionBlock.args[3], arg3, 8); + memcpy(&transitionBlock.args[4], arg4, 8); + transitionBlock.args[5] = (int64_t)arg5; + transitionBlock.args[6] = (int64_t)arg6; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL6(void, CallInterpreter_This_I32_I32_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_7(void, CallInterpreter_This_I32_I32_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[6]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + transitionBlock.args[5] = (int64_t)arg5; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL5(void, CallInterpreter_This_I32_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(void, CallInterpreter_This_I32_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL4(void, CallInterpreter_This_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_5(void, CallInterpreter_This_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_This_I32_I32_RetVoid, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_This_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL2(void, CallInterpreter_This_I32_RetVoid, int32_t, int32_t); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_I32_RetVoid, int32_t arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL1(void, CallInterpreter_This_RetVoid, int32_t); + WASM_CALLABLE_FUNC_2(void, CallInterpreter_This_RetVoid, int32_t arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_F64_I32_I32_RetVoid, double, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_F64_I32_I32_RetVoid, double arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_F32_I32_I32_RetVoid, float, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_F32_I32_I32_RetVoid, float arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(float*)&transitionBlock.args[0] = arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL4(void, CallInterpreter_I32_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_5(void, CallInterpreter_I32_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL2(void, CallInterpreter_I32_I32_RetVoid, int32_t, int32_t); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_I32_I32_RetVoid, int32_t arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL1(void, CallInterpreter_I32_RetVoid, int32_t); + WASM_CALLABLE_FUNC_2(void, CallInterpreter_I32_RetVoid, int32_t arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL0(void, CallInterpreter_Void_RetVoid); + WASM_CALLABLE_FUNC_1(void, CallInterpreter_Void_RetVoid, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, 0, (int8_t*)&result); + return; + } + +} + +const StringToWasmSigThunk g_wasmGeneratedPortableEntryPointThunks[] = { + { "IS12TS12ip", (void*)&CallInterpreter_This_S12_I32_RetS12 }, + { "IS12TiS12ip", (void*)&CallInterpreter_This_I32_S12_I32_RetS12 }, + { "IS12Tiiip", (void*)&CallInterpreter_This_I32_I32_I32_RetS12 }, + { "IS12Tiip", (void*)&CallInterpreter_This_I32_I32_RetS12 }, + { "IS16Tp", (void*)&CallInterpreter_This_RetS16 }, + { "IS16l2ip", (void*)&CallInterpreter_L2_I32_RetS16 }, + { "IS1Tp", (void*)&CallInterpreter_This_RetS1 }, + { "IS8Tiiip", (void*)&CallInterpreter_This_I32_I32_I32_RetS8 }, + { "IS8Tip", (void*)&CallInterpreter_This_I32_RetS8 }, + { "IS8Tp", (void*)&CallInterpreter_This_RetS8 }, + { "Iddddp", (void*)&CallInterpreter_F64_F64_F64_RetF64 }, + { "Idddp", (void*)&CallInterpreter_F64_F64_RetF64 }, + { "Iddip", (void*)&CallInterpreter_F64_I32_RetF64 }, + { "Iddp", (void*)&CallInterpreter_F64_RetF64 }, + { "Iffffp", (void*)&CallInterpreter_F32_F32_F32_RetF32 }, + { "Ifffp", (void*)&CallInterpreter_F32_F32_RetF32 }, + { "Iffip", (void*)&CallInterpreter_F32_I32_RetF32 }, + { "Iffp", (void*)&CallInterpreter_F32_RetF32 }, + { "IiS8p", (void*)&CallInterpreter_S8_RetI32 }, + { "IiTS12ip", (void*)&CallInterpreter_This_S12_I32_RetI32 }, + { "IiTS12p", (void*)&CallInterpreter_This_S12_RetI32 }, + { "IiTS8S8p", (void*)&CallInterpreter_This_S8_S8_RetI32 }, + { "IiTS8iS8ip", (void*)&CallInterpreter_This_S8_I32_S8_I32_RetI32 }, + { "IiTS8iiip", (void*)&CallInterpreter_This_S8_I32_I32_I32_RetI32 }, + { "IiTS8ip", (void*)&CallInterpreter_This_S8_I32_RetI32 }, + { "IiTS8p", (void*)&CallInterpreter_This_S8_RetI32 }, + { "IiTiS12p", (void*)&CallInterpreter_This_I32_S12_RetI32 }, + { "IiTiS8p", (void*)&CallInterpreter_This_I32_S8_RetI32 }, + { "IiTiiiip", (void*)&CallInterpreter_This_I32_I32_I32_I32_RetI32 }, + { "IiTiiip", (void*)&CallInterpreter_This_I32_I32_I32_RetI32 }, + { "IiTiip", (void*)&CallInterpreter_This_I32_I32_RetI32 }, + { "IiTip", (void*)&CallInterpreter_This_I32_RetI32 }, + { "IiTp", (void*)&CallInterpreter_This_RetI32 }, + { "Iidp", (void*)&CallInterpreter_F64_RetI32 }, + { "IiiS8p", (void*)&CallInterpreter_I32_S8_RetI32 }, + { "Iiiiiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 }, + { "Iiiiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_I32_I32_RetI32 }, + { "Iiiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_I32_RetI32 }, + { "Iiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_RetI32 }, + { "Iiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_RetI32 }, + { "Iiiiip", (void*)&CallInterpreter_I32_I32_I32_RetI32 }, + { "Iiiip", (void*)&CallInterpreter_I32_I32_RetI32 }, + { "Iiip", (void*)&CallInterpreter_I32_RetI32 }, + { "Iip", (void*)&CallInterpreter_Void_RetI32 }, + { "Ildp", (void*)&CallInterpreter_F64_RetI64 }, + { "Ilillp", (void*)&CallInterpreter_I32_I64_I64_RetI64 }, + { "Ililp", (void*)&CallInterpreter_I32_I64_RetI64 }, + { "Ilip", (void*)&CallInterpreter_I32_RetI64 }, + { "Illlp", (void*)&CallInterpreter_I64_I64_RetI64 }, + { "Ilp", (void*)&CallInterpreter_Void_RetI64 }, + { "IvTS12p", (void*)&CallInterpreter_This_S12_RetVoid }, + { "IvTS32p", (void*)&CallInterpreter_This_S32_RetVoid }, + { "IvTS8S8p", (void*)&CallInterpreter_This_S8_S8_RetVoid }, + { "IvTS8ip", (void*)&CallInterpreter_This_S8_I32_RetVoid }, + { "IvTS8p", (void*)&CallInterpreter_This_S8_RetVoid }, + { "IvTiS8p", (void*)&CallInterpreter_This_I32_S8_RetVoid }, + { "IvTiiS8S8iip", (void*)&CallInterpreter_This_I32_I32_S8_S8_I32_I32_RetVoid }, + { "IvTiiiiip", (void*)&CallInterpreter_This_I32_I32_I32_I32_I32_RetVoid }, + { "IvTiiiip", (void*)&CallInterpreter_This_I32_I32_I32_I32_RetVoid }, + { "IvTiiip", (void*)&CallInterpreter_This_I32_I32_I32_RetVoid }, + { "IvTiip", (void*)&CallInterpreter_This_I32_I32_RetVoid }, + { "IvTip", (void*)&CallInterpreter_This_I32_RetVoid }, + { "IvTp", (void*)&CallInterpreter_This_RetVoid }, + { "Ivdiip", (void*)&CallInterpreter_F64_I32_I32_RetVoid }, + { "Ivfiip", (void*)&CallInterpreter_F32_I32_I32_RetVoid }, + { "Iviiiip", (void*)&CallInterpreter_I32_I32_I32_I32_RetVoid }, + { "Iviiip", (void*)&CallInterpreter_I32_I32_I32_RetVoid }, + { "Iviip", (void*)&CallInterpreter_I32_I32_RetVoid }, + { "Ivip", (void*)&CallInterpreter_I32_RetVoid }, + { "Ivp", (void*)&CallInterpreter_Void_RetVoid }, +}; + +const size_t g_wasmGeneratedPortableEntryPointThunksCount = sizeof(g_wasmGeneratedPortableEntryPointThunks) / sizeof(g_wasmGeneratedPortableEntryPointThunks[0]); diff --git a/src/coreclr/vm/wasm/callhelpers.hpp b/src/coreclr/vm/wasm/callhelpers.hpp index 6f60164ffa87c9..ddd394cb3f2ec6 100644 --- a/src/coreclr/vm/wasm/callhelpers.hpp +++ b/src/coreclr/vm/wasm/callhelpers.hpp @@ -43,6 +43,9 @@ struct StringToWasmSigThunk extern const StringToWasmSigThunk g_wasmThunks[]; extern const size_t g_wasmThunksCount; +extern const StringToWasmSigThunk g_wasmGeneratedPortableEntryPointThunks[]; +extern const size_t g_wasmGeneratedPortableEntryPointThunksCount; + struct ReverseThunkMapValue { MethodDesc** Target; diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp index 05ad28e3b94eea..77b31d3dacaf86 100644 --- a/src/coreclr/vm/wasm/helpers.cpp +++ b/src/coreclr/vm/wasm/helpers.cpp @@ -17,353 +17,8 @@ void ExecuteInterpretedMethodWithArgs_PortableEntryPoint(PCODE portableEntrypoint, TransitionBlock* block, size_t argsSize, int8_t* retBuff); // ------------------------------------------------- -// Logic that will eventually mostly be pregenerated for R2R to interpreter code -// ------------------------------------------------- -namespace -{ - FCDECL0(void, CallInterpreter_RetVoid); - WASM_CALLABLE_FUNC_1(void, CallInterpreter_RetVoid, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - void * result = NULL; - - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, 0, (int8_t*)&result); - return; - } - FCDECL1(void, CallInterpreter_I32_RetVoid, int32_t); - WASM_CALLABLE_FUNC_2(void, CallInterpreter_I32_RetVoid, int32_t arg0, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[1]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return; - } - FCDECL2(void, CallInterpreter_I32_I32_RetVoid, int32_t, int32_t); - WASM_CALLABLE_FUNC_3(void, CallInterpreter_I32_I32_RetVoid, int32_t arg0, int32_t arg1, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[2]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - transitionBlock.args[1] = (int64_t)arg1; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return; - } - FCDECL3(void, CallInterpreter_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t); - WASM_CALLABLE_FUNC_4(void, CallInterpreter_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[3]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - transitionBlock.args[1] = (int64_t)arg1; - transitionBlock.args[2] = (int64_t)arg2; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return; - } - FCDECL4(void, CallInterpreter_I32_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t, int32_t); - WASM_CALLABLE_FUNC_5(void, CallInterpreter_I32_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[4]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - transitionBlock.args[1] = (int64_t)arg1; - transitionBlock.args[2] = (int64_t)arg2; - transitionBlock.args[3] = (int64_t)arg3; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return; - } - FCDECL0(int32_t, CallInterpreter_RetI32); - WASM_CALLABLE_FUNC_1(int32_t, CallInterpreter_RetI32, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, 0, (int8_t*)&result); - return (int32_t)result; - } - FCDECL1(int32_t, CallInterpreter_I32_RetI32, int32_t); - WASM_CALLABLE_FUNC_2(int32_t, CallInterpreter_I32_RetI32, int32_t arg0, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[1]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return (int32_t)result; - } - FCDECL1(int32_t, CallInterpreter_D64_RetI32, double); - WASM_CALLABLE_FUNC_2(int32_t, CallInterpreter_D64_RetI32, double arg0, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - double args[1]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = arg0; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return (int32_t)result; - } - FCDECL1(int64_t, CallInterpreter_D64_RetI64, double); - WASM_CALLABLE_FUNC_2(int64_t, CallInterpreter_D64_RetI64, double arg0, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - double args[1]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = arg0; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - int64_t result = 0; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return result; - } - FCDECL2(int32_t, CallInterpreter_I32_I32_RetI32, int32_t, int32_t); - WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_I32_I32_RetI32, int32_t arg0, int32_t arg1, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[2]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - transitionBlock.args[1] = (int64_t)arg1; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return (int32_t)result; - } - FCDECL2(int32_t, CallInterpreter_I32_S8_RetI32, int32_t, int8_t*); - WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_I32_S8_RetI32, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[2]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - memcpy(&transitionBlock.args[1], arg1, 8); - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return (int32_t)result; - } - FCDECL3(int32_t, CallInterpreter_I32_I32_I32_RetI32, int32_t, int32_t, int32_t); - WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[3]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - transitionBlock.args[1] = (int64_t)arg1; - transitionBlock.args[2] = (int64_t)arg2; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return (int32_t)result; - } - FCDECL4(int32_t, CallInterpreter_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t); - WASM_CALLABLE_FUNC_5(int32_t, CallInterpreter_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[4]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - transitionBlock.args[1] = (int64_t)arg1; - transitionBlock.args[2] = (int64_t)arg2; - transitionBlock.args[3] = (int64_t)arg3; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return (int32_t)result; - } - FCDECL5(int32_t, CallInterpreter_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t); - WASM_CALLABLE_FUNC_6(int32_t, CallInterpreter_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[5]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - transitionBlock.args[1] = (int64_t)arg1; - transitionBlock.args[2] = (int64_t)arg2; - transitionBlock.args[3] = (int64_t)arg3; - transitionBlock.args[4] = (int64_t)arg4; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return (int32_t)result; - } - FCDECL6(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); - WASM_CALLABLE_FUNC_7(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[6]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - transitionBlock.args[1] = (int64_t)arg1; - transitionBlock.args[2] = (int64_t)arg2; - transitionBlock.args[3] = (int64_t)arg3; - transitionBlock.args[4] = (int64_t)arg4; - transitionBlock.args[5] = (int64_t)arg5; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return (int32_t)result; - } - FCDECL7(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); - WASM_CALLABLE_FUNC_8(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, int32_t arg6, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[7]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - transitionBlock.args[1] = (int64_t)arg1; - transitionBlock.args[2] = (int64_t)arg2; - transitionBlock.args[3] = (int64_t)arg3; - transitionBlock.args[4] = (int64_t)arg4; - transitionBlock.args[5] = (int64_t)arg5; - transitionBlock.args[6] = (int64_t)arg6; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return (int32_t)result; - } - FCDECL8(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); - WASM_CALLABLE_FUNC_9(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7, PCODE portableEntrypoint) - { - struct - { - TransitionBlock block; - int64_t args[8]; - } transitionBlock; - transitionBlock.block.m_ReturnAddress = 0; - transitionBlock.block.m_StackPointer = callersStackPointer; - transitionBlock.args[0] = (int64_t)arg0; - transitionBlock.args[1] = (int64_t)arg1; - transitionBlock.args[2] = (int64_t)arg2; - transitionBlock.args[3] = (int64_t)arg3; - transitionBlock.args[4] = (int64_t)arg4; - transitionBlock.args[5] = (int64_t)arg5; - transitionBlock.args[6] = (int64_t)arg6; - transitionBlock.args[7] = (int64_t)arg7; - static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); - - void * result = NULL; - ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); - return (int32_t)result; - } -} - -const StringToWasmSigThunk g_wasmPortableEntryPointThunks[] = { - { "Ivp", (void*)&CallInterpreter_RetVoid }, - { "Ivip", (void*)&CallInterpreter_I32_RetVoid }, - { "Iviip", (void*)&CallInterpreter_I32_I32_RetVoid }, - { "Iviiip", (void*)&CallInterpreter_I32_I32_I32_RetVoid }, - { "Iviiiip", (void*)&CallInterpreter_I32_I32_I32_I32_RetVoid }, - { "Iip", (void*)&CallInterpreter_RetI32 }, - { "Iiip", (void*)&CallInterpreter_I32_RetI32 }, - { "Iiiip", (void*)&CallInterpreter_I32_I32_RetI32 }, - { "Iiiiip", (void*)&CallInterpreter_I32_I32_I32_RetI32 }, - { "Iiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_RetI32 }, - { "Iiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_RetI32 }, - { "Iiiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_I32_RetI32 }, - { "Iiiiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_I32_I32_RetI32 }, - { "Iiiiiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 }, - { "Iidp", (void*)&CallInterpreter_D64_RetI32 }, - { "Ildp", (void*)&CallInterpreter_D64_RetI64 }, - { "IiiS8p", (void*)&CallInterpreter_I32_S8_RetI32 } -}; - -const size_t g_wasmPortableEntryPointThunksCount = sizeof(g_wasmPortableEntryPointThunks) / sizeof(g_wasmPortableEntryPointThunks[0]); -// ------------------------------------------------- -// END Logic that will eventually mostly be pregenerated for R2R to interpreter code END +// The R2R to interpreter thunks are generated into callhelpers-portable-entrypoints.cpp by the +// WasmAppBuilder generator, one table per target. // ------------------------------------------------- extern "C" void STDCALL CallCountingStubCode() @@ -1486,10 +1141,10 @@ namespace } InterpreterCalliCookie thunk = LookupThunk(keyBuffer); -#ifdef _DEBUG if (thunk == NULL) - printf("WASM calli missing for key: %s\n", keyBuffer); -#endif + { + printf("WASM: no interpreter-to-R2R calli thunk for signature key '%s'. Add it to g_wasmThunks.\n", keyBuffer); + } return thunk; } @@ -1532,12 +1187,13 @@ namespace } void* thunk = LookupPortableEntryPointThunk(keyBuffer); -#ifdef _DEBUG if (thunk == NULL) { - LOG((LF_STUBS, LL_INFO100000, "WASM R2R to interpreter call missing for key: %s\n", keyBuffer)); + // Printed rather than only asserted: the caller's assert compiles out in release, where these + // gaps surface, and cannot carry the key. A miss leaves the entry point's table index 0 and + // traps later as "null function", far from here. + printf("WASM: no R2R-to-interpreter thunk for signature key '%s'. Add it to pregeneratedInterpreterToNativeSignatures in ManagedToNativeGenerator and regenerate.\n", keyBuffer); } -#endif return thunk; } @@ -1652,10 +1308,10 @@ void InitializeWasmThunkCaches() { StringToWasmSigThunkHash* newTable = new StringToWasmSigThunkHash(); - newTable->Reallocate(g_wasmPortableEntryPointThunksCount * StringToWasmSigThunkHash::s_density_factor_denominator / StringToWasmSigThunkHash::s_density_factor_numerator + 1); - for (size_t i = 0; i < g_wasmPortableEntryPointThunksCount; i++) + newTable->Reallocate(g_wasmGeneratedPortableEntryPointThunksCount * StringToWasmSigThunkHash::s_density_factor_denominator / StringToWasmSigThunkHash::s_density_factor_numerator + 1); + for (size_t i = 0; i < g_wasmGeneratedPortableEntryPointThunksCount; i++) { - newTable->Add(g_wasmPortableEntryPointThunks[i].key, g_wasmPortableEntryPointThunks[i].value); + newTable->Add(g_wasmGeneratedPortableEntryPointThunks[i].key, g_wasmGeneratedPortableEntryPointThunks[i].value); } portableEntrypointThunkCache = newTable; } @@ -1786,10 +1442,18 @@ void* GetPortableEntryPointToInterpreterThunk(MethodDesc *pMD) } thunk = LookupPortableEntryPointThunk(thunkKey); + if (thunk == NULL) + { + PORTABILITY_ASSERT("GetPortableEntryPointToInterpreterThunk: unknown thunk for string constructor"); + } } else { thunk = ComputePortableEntryPointToInterpreterThunk(sig); + if (thunk == NULL) + { + PORTABILITY_ASSERT("ComputePortableEntryPointToInterpreterThunk: unknown thunk signature"); + } } return thunk; diff --git a/src/coreclr/vm/wasm/wasi/callhelpers-interp-to-managed.cpp b/src/coreclr/vm/wasm/wasi/callhelpers-interp-to-managed.cpp index 0033e59ea2469e..1f128e9aa9f94c 100644 --- a/src/coreclr/vm/wasm/wasi/callhelpers-interp-to-managed.cpp +++ b/src/coreclr/vm/wasm/wasi/callhelpers-interp-to-managed.cpp @@ -17,9 +17,83 @@ #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)) +typedef struct { char d[1]; } wasm_ret_S1; +typedef struct { char d[8]; } wasm_ret_S8; +typedef struct { char d[12]; } wasm_ret_S12; +typedef struct { char d[16]; } wasm_ret_S16; namespace { + NOINLINE static void CallFunc_This_S12_I32_RetS12_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_IND(1), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_S12_I32_RetS12_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_I32(1), ARG_IND(2), ARG_I32(4), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_RetS12_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_I32(1), ARG_I32(2), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_RetS12_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_I32(1), ARG_I32(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_RetS16_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, PCODE) = *(void (**)(int*, int32_t, int8_t*, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, pPortableEntryPoint); + } + + NOINLINE static void CallFunc_L2_I32_RetS16_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int8_t*, int64_t, int64_t, int32_t, PCODE) = *(void (**)(int*, int8_t*, int64_t, int64_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, pRet, ARG_I64(0), ARG_I64(1), ARG_I32(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_RetS1_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, PCODE) = *(void (**)(int*, int32_t, int8_t*, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_RetS8_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_I32(1), ARG_I32(2), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_RetS8_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, int32_t, PCODE) = *(void (**)(int*, int32_t, int8_t*, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, ARG_I32(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_RetS8_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int8_t*, PCODE) = *(void (**)(int*, int32_t, int8_t*, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), pRet, pPortableEntryPoint); + } + NOINLINE static void CallFunc_F64_F64_F64_RetF64_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -166,6 +240,97 @@ namespace *((int32_t*)pRet) = (*fptr)(ARG_IND(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5)); } + NOINLINE static void CallFunc_S8_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_IND(0), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S12_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S12_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_S8_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_IND(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_I32_S8_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_I32(2), ARG_IND(3), ARG_I32(4), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_I32(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_S12_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_IND(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_S8_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_IND(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), pPortableEntryPoint); + } + NOINLINE static void CallFunc_This_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -180,6 +345,13 @@ namespace *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), pPortableEntryPoint); } + NOINLINE static void CallFunc_F64_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, double, PCODE) = *(int32_t (**)(int*, double, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_F64(0), pPortableEntryPoint); + } + static void CallFunc_I32_RetI32(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int32_t (*fptr)(int32_t) = (int32_t (*)(int32_t))pcode; @@ -198,6 +370,13 @@ namespace *((int32_t*)pRet) = (*fptr)(ARG_I32(0), ARG_IND(1), ARG_I32(2), ARG_I32(3), ARG_I32(4)); } + NOINLINE static void CallFunc_I32_S8_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + 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; @@ -270,6 +449,20 @@ 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), ARG_I32(11), ARG_I32(12), ARG_I32(13)); } + NOINLINE static void CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6), ARG_I32(7), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_I32_I32_I32_I32_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int32_t (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(int32_t (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + *((int32_t*)pRet) = (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), ARG_I32(6), pPortableEntryPoint); + } + NOINLINE static void CallFunc_I32_I32_I32_I32_I32_I32_RetI32_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -385,6 +578,13 @@ namespace *((int64_t*)pRet) = (*fptr)(); } + NOINLINE static void CallFunc_F64_RetI64_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + int64_t (*fptr)(int*, double, PCODE) = *(int64_t (**)(int*, double, PCODE))(pPortableEntryPoint); + *((int64_t*)pRet) = (*fptr)(&framePointer, ARG_F64(0), pPortableEntryPoint); + } + static void CallFunc_I32_RetI64(PCODE pcode, int8_t* pArgs, int8_t* pRet) { int64_t (*fptr)(int32_t) = (int64_t (*)(int32_t))pcode; @@ -510,6 +710,90 @@ namespace (*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)); } + NOINLINE static void CallFunc_This_S12_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_S8_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_IND(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), ARG_I32(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_S8_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_IND(1), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_S8_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_IND(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_S8_S8_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_IND(3), ARG_IND(4), ARG_I32(5), ARG_I32(6), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), pPortableEntryPoint); + } + + NOINLINE static void CallFunc_This_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), pPortableEntryPoint); + } + NOINLINE static void CallFunc_This_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -597,6 +881,13 @@ namespace (*fptr)(ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), ARG_I32(4), ARG_I32(5)); } + NOINLINE static void CallFunc_I32_I32_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) + { + alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; + void (*fptr)(int*, int32_t, int32_t, int32_t, int32_t, PCODE) = *(void (**)(int*, int32_t, int32_t, int32_t, int32_t, PCODE))(pPortableEntryPoint); + (*fptr)(&framePointer, ARG_I32(0), ARG_I32(1), ARG_I32(2), ARG_I32(3), pPortableEntryPoint); + } + NOINLINE static void CallFunc_I32_I32_I32_RetVoid_PE(PCODE pPortableEntryPoint, int8_t* pArgs, int8_t* pRet) { alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK; @@ -639,6 +930,16 @@ namespace } const StringToWasmSigThunk g_wasmThunks[] = { + { "MS12TS12ip", (void*)&CallFunc_This_S12_I32_RetS12_PE }, + { "MS12TiS12ip", (void*)&CallFunc_This_I32_S12_I32_RetS12_PE }, + { "MS12Tiiip", (void*)&CallFunc_This_I32_I32_I32_RetS12_PE }, + { "MS12Tiip", (void*)&CallFunc_This_I32_I32_RetS12_PE }, + { "MS16Tp", (void*)&CallFunc_This_RetS16_PE }, + { "MS16l2ip", (void*)&CallFunc_L2_I32_RetS16_PE }, + { "MS1Tp", (void*)&CallFunc_This_RetS1_PE }, + { "MS8Tiiip", (void*)&CallFunc_This_I32_I32_I32_RetS8_PE }, + { "MS8Tip", (void*)&CallFunc_This_I32_RetS8_PE }, + { "MS8Tp", (void*)&CallFunc_This_RetS8_PE }, { "Mddddp", (void*)&CallFunc_F64_F64_F64_RetF64_PE }, { "Mdddp", (void*)&CallFunc_F64_F64_RetF64_PE }, { "Mddip", (void*)&CallFunc_F64_I32_RetF64_PE }, @@ -662,11 +963,26 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "MiS8iii", (void*)&CallFunc_S8_I32_I32_I32_RetI32 }, { "MiS8iiii", (void*)&CallFunc_S8_I32_I32_I32_I32_RetI32 }, { "MiS8iiiii", (void*)&CallFunc_S8_I32_I32_I32_I32_I32_RetI32 }, + { "MiS8p", (void*)&CallFunc_S8_RetI32_PE }, + { "MiTS12ip", (void*)&CallFunc_This_S12_I32_RetI32_PE }, + { "MiTS12p", (void*)&CallFunc_This_S12_RetI32_PE }, + { "MiTS8S8p", (void*)&CallFunc_This_S8_S8_RetI32_PE }, + { "MiTS8iS8ip", (void*)&CallFunc_This_S8_I32_S8_I32_RetI32_PE }, + { "MiTS8iiip", (void*)&CallFunc_This_S8_I32_I32_I32_RetI32_PE }, + { "MiTS8ip", (void*)&CallFunc_This_S8_I32_RetI32_PE }, + { "MiTS8p", (void*)&CallFunc_This_S8_RetI32_PE }, + { "MiTiS12p", (void*)&CallFunc_This_I32_S12_RetI32_PE }, + { "MiTiS8p", (void*)&CallFunc_This_I32_S8_RetI32_PE }, + { "MiTiiiip", (void*)&CallFunc_This_I32_I32_I32_I32_RetI32_PE }, + { "MiTiiip", (void*)&CallFunc_This_I32_I32_I32_RetI32_PE }, + { "MiTiip", (void*)&CallFunc_This_I32_I32_RetI32_PE }, { "MiTip", (void*)&CallFunc_This_I32_RetI32_PE }, { "MiTp", (void*)&CallFunc_This_RetI32_PE }, + { "Midp", (void*)&CallFunc_F64_RetI32_PE }, { "Mii", (void*)&CallFunc_I32_RetI32 }, { "MiiS8i", (void*)&CallFunc_I32_S8_I32_RetI32 }, { "MiiS8iii", (void*)&CallFunc_I32_S8_I32_I32_I32_RetI32 }, + { "MiiS8p", (void*)&CallFunc_I32_S8_RetI32_PE }, { "Miii", (void*)&CallFunc_I32_I32_RetI32 }, { "MiiiS8iiS8", (void*)&CallFunc_I32_I32_S8_I32_I32_S8_RetI32 }, { "MiiiS8iiii", (void*)&CallFunc_I32_I32_S8_I32_I32_I32_I32_RetI32 }, @@ -679,6 +995,8 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "Miiiiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 }, { "Miiiiiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 }, { "Miiiiiiiiiiiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 }, + { "Miiiiiiiiip", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_I32_RetI32_PE }, + { "Miiiiiiiip", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_I32_RetI32_PE }, { "Miiiiiiip", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_RetI32_PE }, { "Miiiiiip", (void*)&CallFunc_I32_I32_I32_I32_I32_RetI32_PE }, { "Miiiiip", (void*)&CallFunc_I32_I32_I32_I32_RetI32_PE }, @@ -697,6 +1015,7 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "Milili", (void*)&CallFunc_I64_I32_I64_I32_RetI32 }, { "Mip", (void*)&CallFunc_Void_RetI32_PE }, { "Ml", (void*)&CallFunc_Void_RetI64 }, + { "Mldp", (void*)&CallFunc_F64_RetI64_PE }, { "Mli", (void*)&CallFunc_I32_RetI64 }, { "Mliii", (void*)&CallFunc_I32_I32_I32_RetI64 }, { "Mliiil", (void*)&CallFunc_I32_I32_I32_I64_RetI64 }, @@ -717,6 +1036,18 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "MvS8iiiii", (void*)&CallFunc_S8_I32_I32_I32_I32_I32_RetVoid }, { "MvS8iiiiii", (void*)&CallFunc_S8_I32_I32_I32_I32_I32_I32_RetVoid }, { "MvS8iiiiiiiiiii", (void*)&CallFunc_S8_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_I32_RetVoid }, + { "MvTS12p", (void*)&CallFunc_This_S12_RetVoid_PE }, + { "MvTS32p", (void*)&CallFunc_This_S32_RetVoid_PE }, + { "MvTS8S8p", (void*)&CallFunc_This_S8_S8_RetVoid_PE }, + { "MvTS8ip", (void*)&CallFunc_This_S8_I32_RetVoid_PE }, + { "MvTS8p", (void*)&CallFunc_This_S8_RetVoid_PE }, + { "MvTiS8p", (void*)&CallFunc_This_I32_S8_RetVoid_PE }, + { "MvTiiS8S8iip", (void*)&CallFunc_This_I32_I32_S8_S8_I32_I32_RetVoid_PE }, + { "MvTiiiiip", (void*)&CallFunc_This_I32_I32_I32_I32_I32_RetVoid_PE }, + { "MvTiiiip", (void*)&CallFunc_This_I32_I32_I32_I32_RetVoid_PE }, + { "MvTiiip", (void*)&CallFunc_This_I32_I32_I32_RetVoid_PE }, + { "MvTiip", (void*)&CallFunc_This_I32_I32_RetVoid_PE }, + { "MvTip", (void*)&CallFunc_This_I32_RetVoid_PE }, { "MvTp", (void*)&CallFunc_This_RetVoid_PE }, { "Mvdiip", (void*)&CallFunc_F64_I32_I32_RetVoid_PE }, { "Mvfiip", (void*)&CallFunc_F32_I32_I32_RetVoid_PE }, @@ -731,6 +1062,7 @@ const StringToWasmSigThunk g_wasmThunks[] = { { "Mviiii", (void*)&CallFunc_I32_I32_I32_I32_RetVoid }, { "Mviiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_RetVoid }, { "Mviiiiii", (void*)&CallFunc_I32_I32_I32_I32_I32_I32_RetVoid }, + { "Mviiiip", (void*)&CallFunc_I32_I32_I32_I32_RetVoid_PE }, { "Mviiip", (void*)&CallFunc_I32_I32_I32_RetVoid_PE }, { "Mviip", (void*)&CallFunc_I32_I32_RetVoid_PE }, { "Mvili", (void*)&CallFunc_I32_I64_I32_RetVoid }, diff --git a/src/coreclr/vm/wasm/wasi/callhelpers-pinvoke.cpp b/src/coreclr/vm/wasm/wasi/callhelpers-pinvoke.cpp index e128a77b7bd640..493539a07f5216 100644 --- a/src/coreclr/vm/wasm/wasi/callhelpers-pinvoke.cpp +++ b/src/coreclr/vm/wasm/wasi/callhelpers-pinvoke.cpp @@ -11,7 +11,6 @@ #include extern "C" { - uint32_t CompressionNative_CompressBound (uint32_t); uint32_t CompressionNative_Crc32 (uint32_t, void *, int32_t); int32_t CompressionNative_Deflate (void *, int32_t); int32_t CompressionNative_DeflateEnd (void *); @@ -94,6 +93,7 @@ extern "C" { int32_t SystemNative_GetBytesAvailable (void *, void *); int32_t SystemNative_GetControlMessageBufferSize (int32_t, int32_t); double SystemNative_GetCpuUtilization (void *); + int32_t SystemNative_GetCryptographicallySecureRandomBytes (void *, int32_t); void * SystemNative_GetCwd (void *, int32_t); void * SystemNative_GetDefaultSearchOrderPseudoHandle (); int32_t SystemNative_GetErrNo (); @@ -290,7 +290,6 @@ static const Entry s_libSystem_Globalization_Native [] = { }; static const Entry s_libSystem_IO_Compression_Native [] = { - DllImportEntry(CompressionNative_CompressBound) // System.IO.Compression DllImportEntry(CompressionNative_Crc32) // System.IO.Compression DllImportEntry(CompressionNative_Deflate) // System.IO.Compression DllImportEntry(CompressionNative_DeflateEnd) // System.IO.Compression @@ -342,9 +341,10 @@ static const Entry s_libSystem_Native [] = { DllImportEntry(SystemNative_GetBytesAvailable) // System.Net.Sockets DllImportEntry(SystemNative_GetControlMessageBufferSize) // System.Net.Sockets DllImportEntry(SystemNative_GetCpuUtilization) // System.Private.CoreLib + DllImportEntry(SystemNative_GetCryptographicallySecureRandomBytes) // System.IO.Compression DllImportEntry(SystemNative_GetCwd) // System.Private.CoreLib DllImportEntry(SystemNative_GetDefaultSearchOrderPseudoHandle) // System.Private.CoreLib - DllImportEntry(SystemNative_GetErrNo) // System.Net.NameResolution, System.Private.CoreLib + DllImportEntry(SystemNative_GetErrNo) // System.Private.CoreLib DllImportEntry(SystemNative_GetHostEntryForName) // System.Net.NameResolution DllImportEntry(SystemNative_GetHostName) // System.Net.NameResolution DllImportEntry(SystemNative_GetIPv4Address) // System.Net.Primitives, System.Net.Sockets @@ -526,8 +526,8 @@ typedef struct PInvokeTable { static PInvokeTable s_PInvokeTables[] = { {"libSystem.Globalization.Native", s_libSystem_Globalization_Native, 34}, - {"libSystem.IO.Compression.Native", s_libSystem_IO_Compression_Native, 10}, - {"libSystem.Native", s_libSystem_Native, 147}, + {"libSystem.IO.Compression.Native", s_libSystem_IO_Compression_Native, 9}, + {"libSystem.Native", s_libSystem_Native, 148}, {"libSystem.Native.Browser", s_libSystem_Native_Browser, 0}, {"libSystem.Runtime.InteropServices.JavaScript.Native", s_libSystem_Runtime_InteropServices_JavaScript_Native, 0}, {"wasi:clocks/monotonic-clock@0.2.8", s_wasi_3A_clocks_2F_monotonic_clock_40_0_2_8, 4}, diff --git a/src/coreclr/vm/wasm/wasi/callhelpers-portable-entrypoints.cpp b/src/coreclr/vm/wasm/wasi/callhelpers-portable-entrypoints.cpp new file mode 100644 index 00000000000000..cbe20c0ef987a0 --- /dev/null +++ b/src/coreclr/vm/wasm/wasi/callhelpers-portable-entrypoints.cpp @@ -0,0 +1,1461 @@ +// 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 +#include +#include "callhelpers.hpp" + +void ExecuteInterpretedMethodWithArgs_PortableEntryPoint(PCODE portableEntrypoint, TransitionBlock* block, size_t argsSize, int8_t* retBuff); + +namespace +{ + FCDECL4(void, CallInterpreter_This_S12_I32_RetS12, int32_t, int8_t*, int8_t*, int32_t); + WASM_CALLABLE_FUNC_5(void, CallInterpreter_This_S12_I32_RetS12, int32_t arg0, int8_t* retBuf, int8_t* arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 12); + transitionBlock.args[3] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL5(void, CallInterpreter_This_I32_S12_I32_RetS12, int32_t, int8_t*, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_6(void, CallInterpreter_This_I32_S12_I32_RetS12, int32_t arg0, int8_t* retBuf, int32_t arg1, int8_t* arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + memcpy(&transitionBlock.args[2], arg2, 12); + transitionBlock.args[4] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL5(void, CallInterpreter_This_I32_I32_I32_RetS12, int32_t, int8_t*, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(void, CallInterpreter_This_I32_I32_I32_RetS12, int32_t arg0, int8_t* retBuf, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL4(void, CallInterpreter_This_I32_I32_RetS12, int32_t, int8_t*, int32_t, int32_t); + WASM_CALLABLE_FUNC_5(void, CallInterpreter_This_I32_I32_RetS12, int32_t arg0, int8_t* retBuf, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL2(void, CallInterpreter_This_RetS16, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_RetS16, int32_t arg0, int8_t* retBuf, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL4(void, CallInterpreter_L2_I32_RetS16, int8_t*, int64_t, int64_t, int32_t); + WASM_CALLABLE_FUNC_5(void, CallInterpreter_L2_I32_RetS16, int8_t* retBuf, int64_t arg0Lo, int64_t arg0Hi, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = arg0Lo; + transitionBlock.args[1] = arg0Hi; + transitionBlock.args[2] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL2(void, CallInterpreter_This_RetS1, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_RetS1, int32_t arg0, int8_t* retBuf, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL5(void, CallInterpreter_This_I32_I32_I32_RetS8, int32_t, int8_t*, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(void, CallInterpreter_This_I32_I32_I32_RetS8, int32_t arg0, int8_t* retBuf, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL3(void, CallInterpreter_This_I32_RetS8, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_This_I32_RetS8, int32_t arg0, int8_t* retBuf, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL2(void, CallInterpreter_This_RetS8, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_RetS8, int32_t arg0, int8_t* retBuf, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), retBuf); + return; + } + + FCDECL3(double, CallInterpreter_F64_F64_F64_RetF64, double, double, double); + WASM_CALLABLE_FUNC_4(double, CallInterpreter_F64_F64_F64_RetF64, double arg0, double arg1, double arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + *(double*)&transitionBlock.args[1] = arg1; + *(double*)&transitionBlock.args[2] = arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + double result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(double, CallInterpreter_F64_F64_RetF64, double, double); + WASM_CALLABLE_FUNC_3(double, CallInterpreter_F64_F64_RetF64, double arg0, double arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + *(double*)&transitionBlock.args[1] = arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + double result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(double, CallInterpreter_F64_I32_RetF64, double, int32_t); + WASM_CALLABLE_FUNC_3(double, CallInterpreter_F64_I32_RetF64, double arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + double result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(double, CallInterpreter_F64_RetF64, double); + WASM_CALLABLE_FUNC_2(double, CallInterpreter_F64_RetF64, double arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + double result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(float, CallInterpreter_F32_F32_F32_RetF32, float, float, float); + WASM_CALLABLE_FUNC_4(float, CallInterpreter_F32_F32_F32_RetF32, float arg0, float arg1, float arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(float*)&transitionBlock.args[0] = arg0; + *(float*)&transitionBlock.args[1] = arg1; + *(float*)&transitionBlock.args[2] = arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + float result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(float, CallInterpreter_F32_F32_RetF32, float, float); + WASM_CALLABLE_FUNC_3(float, CallInterpreter_F32_F32_RetF32, float arg0, float arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(float*)&transitionBlock.args[0] = arg0; + *(float*)&transitionBlock.args[1] = arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + float result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(float, CallInterpreter_F32_I32_RetF32, float, int32_t); + WASM_CALLABLE_FUNC_3(float, CallInterpreter_F32_I32_RetF32, float arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(float*)&transitionBlock.args[0] = arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + float result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(float, CallInterpreter_F32_RetF32, float); + WASM_CALLABLE_FUNC_2(float, CallInterpreter_F32_RetF32, float arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(float*)&transitionBlock.args[0] = arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + float result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(int32_t, CallInterpreter_S8_RetI32, int8_t*); + WASM_CALLABLE_FUNC_2(int32_t, CallInterpreter_S8_RetI32, int8_t* arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + memcpy(&transitionBlock.args[0], arg0, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_S12_I32_RetI32, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_S12_I32_RetI32, int32_t arg0, int8_t* arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 12); + transitionBlock.args[3] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int32_t, CallInterpreter_This_S12_RetI32, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_This_S12_RetI32, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 12); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_S8_S8_RetI32, int32_t, int8_t*, int8_t*); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_S8_S8_RetI32, int32_t arg0, int8_t* arg1, int8_t* arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + memcpy(&transitionBlock.args[2], arg2, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL5(int32_t, CallInterpreter_This_S8_I32_S8_I32_RetI32, int32_t, int8_t*, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_6(int32_t, CallInterpreter_This_S8_I32_S8_I32_RetI32, int32_t arg0, int8_t* arg1, int32_t arg2, int8_t* arg3, int32_t arg4, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + transitionBlock.args[2] = (int64_t)arg2; + memcpy(&transitionBlock.args[3], arg3, 8); + transitionBlock.args[4] = (int64_t)arg4; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL5(int32_t, CallInterpreter_This_S8_I32_I32_I32_RetI32, int32_t, int8_t*, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(int32_t, CallInterpreter_This_S8_I32_I32_I32_RetI32, int32_t arg0, int8_t* arg1, int32_t arg2, int32_t arg3, int32_t arg4, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_S8_I32_RetI32, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_S8_I32_RetI32, int32_t arg0, int8_t* arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int32_t, CallInterpreter_This_S8_RetI32, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_This_S8_RetI32, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_I32_S12_RetI32, int32_t, int32_t, int8_t*); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_I32_S12_RetI32, int32_t arg0, int32_t arg1, int8_t* arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + memcpy(&transitionBlock.args[2], arg2, 12); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_I32_S8_RetI32, int32_t, int32_t, int8_t*); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_I32_S8_RetI32, int32_t arg0, int32_t arg1, int8_t* arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + memcpy(&transitionBlock.args[2], arg2, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL5(int32_t, CallInterpreter_This_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(int32_t, CallInterpreter_This_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL4(int32_t, CallInterpreter_This_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_5(int32_t, CallInterpreter_This_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_This_I32_I32_RetI32, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_This_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int32_t, CallInterpreter_This_I32_RetI32, int32_t, int32_t); + WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_This_I32_RetI32, int32_t arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(int32_t, CallInterpreter_This_RetI32, int32_t); + WASM_CALLABLE_FUNC_2(int32_t, CallInterpreter_This_RetI32, int32_t arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(int32_t, CallInterpreter_F64_RetI32, double); + WASM_CALLABLE_FUNC_2(int32_t, CallInterpreter_F64_RetI32, double arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int32_t, CallInterpreter_I32_S8_RetI32, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_I32_S8_RetI32, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL8(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_9(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[8]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + transitionBlock.args[5] = (int64_t)arg5; + transitionBlock.args[6] = (int64_t)arg6; + transitionBlock.args[7] = (int64_t)arg7; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL7(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_8(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, int32_t arg6, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[7]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + transitionBlock.args[5] = (int64_t)arg5; + transitionBlock.args[6] = (int64_t)arg6; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL6(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_7(int32_t, CallInterpreter_I32_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[6]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + transitionBlock.args[5] = (int64_t)arg5; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL5(int32_t, CallInterpreter_I32_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(int32_t, CallInterpreter_I32_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL4(int32_t, CallInterpreter_I32_I32_I32_I32_RetI32, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_5(int32_t, CallInterpreter_I32_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int32_t, CallInterpreter_I32_I32_I32_RetI32, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(int32_t, CallInterpreter_I32_I32_I32_RetI32, int32_t arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int32_t, CallInterpreter_I32_I32_RetI32, int32_t, int32_t); + WASM_CALLABLE_FUNC_3(int32_t, CallInterpreter_I32_I32_RetI32, int32_t arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(int32_t, CallInterpreter_I32_RetI32, int32_t); + WASM_CALLABLE_FUNC_2(int32_t, CallInterpreter_I32_RetI32, int32_t arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL0(int32_t, CallInterpreter_Void_RetI32); + WASM_CALLABLE_FUNC_1(int32_t, CallInterpreter_Void_RetI32, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + + int32_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, 0, (int8_t*)&result); + return result; + } + + FCDECL1(int64_t, CallInterpreter_F64_RetI64, double); + WASM_CALLABLE_FUNC_2(int64_t, CallInterpreter_F64_RetI64, double arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL3(int64_t, CallInterpreter_I32_I64_I64_RetI64, int32_t, int64_t, int64_t); + WASM_CALLABLE_FUNC_4(int64_t, CallInterpreter_I32_I64_I64_RetI64, int32_t arg0, int64_t arg1, int64_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int64_t, CallInterpreter_I32_I64_RetI64, int32_t, int64_t); + WASM_CALLABLE_FUNC_3(int64_t, CallInterpreter_I32_I64_RetI64, int32_t arg0, int64_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL1(int64_t, CallInterpreter_I32_RetI64, int32_t); + WASM_CALLABLE_FUNC_2(int64_t, CallInterpreter_I32_RetI64, int32_t arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL2(int64_t, CallInterpreter_I64_I64_RetI64, int64_t, int64_t); + WASM_CALLABLE_FUNC_3(int64_t, CallInterpreter_I64_I64_RetI64, int64_t arg0, int64_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return result; + } + + FCDECL0(int64_t, CallInterpreter_Void_RetI64); + WASM_CALLABLE_FUNC_1(int64_t, CallInterpreter_Void_RetI64, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + + int64_t result = 0; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, 0, (int8_t*)&result); + return result; + } + + FCDECL2(void, CallInterpreter_This_S12_RetVoid, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_S12_RetVoid, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 12); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL2(void, CallInterpreter_This_S32_RetVoid, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_S32_RetVoid, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 32); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_This_S8_S8_RetVoid, int32_t, int8_t*, int8_t*); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_This_S8_S8_RetVoid, int32_t arg0, int8_t* arg1, int8_t* arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + memcpy(&transitionBlock.args[2], arg2, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_This_S8_I32_RetVoid, int32_t, int8_t*, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_This_S8_I32_RetVoid, int32_t arg0, int8_t* arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL2(void, CallInterpreter_This_S8_RetVoid, int32_t, int8_t*); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_S8_RetVoid, int32_t arg0, int8_t* arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + memcpy(&transitionBlock.args[1], arg1, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_This_I32_S8_RetVoid, int32_t, int32_t, int8_t*); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_This_I32_S8_RetVoid, int32_t arg0, int32_t arg1, int8_t* arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + memcpy(&transitionBlock.args[2], arg2, 8); + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL7(void, CallInterpreter_This_I32_I32_S8_S8_I32_I32_RetVoid, int32_t, int32_t, int32_t, int8_t*, int8_t*, int32_t, int32_t); + WASM_CALLABLE_FUNC_8(void, CallInterpreter_This_I32_I32_S8_S8_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, int8_t* arg3, int8_t* arg4, int32_t arg5, int32_t arg6, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[7]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + memcpy(&transitionBlock.args[3], arg3, 8); + memcpy(&transitionBlock.args[4], arg4, 8); + transitionBlock.args[5] = (int64_t)arg5; + transitionBlock.args[6] = (int64_t)arg6; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL6(void, CallInterpreter_This_I32_I32_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_7(void, CallInterpreter_This_I32_I32_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[6]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + transitionBlock.args[5] = (int64_t)arg5; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL5(void, CallInterpreter_This_I32_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_6(void, CallInterpreter_This_I32_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[5]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + transitionBlock.args[4] = (int64_t)arg4; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL4(void, CallInterpreter_This_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_5(void, CallInterpreter_This_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_This_I32_I32_RetVoid, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_This_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL2(void, CallInterpreter_This_I32_RetVoid, int32_t, int32_t); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_This_I32_RetVoid, int32_t arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL1(void, CallInterpreter_This_RetVoid, int32_t); + WASM_CALLABLE_FUNC_2(void, CallInterpreter_This_RetVoid, int32_t arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_F64_I32_I32_RetVoid, double, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_F64_I32_I32_RetVoid, double arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(double*)&transitionBlock.args[0] = arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_F32_I32_I32_RetVoid, float, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_F32_I32_I32_RetVoid, float arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + *(float*)&transitionBlock.args[0] = arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL4(void, CallInterpreter_I32_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_5(void, CallInterpreter_I32_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[4]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + transitionBlock.args[3] = (int64_t)arg3; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL3(void, CallInterpreter_I32_I32_I32_RetVoid, int32_t, int32_t, int32_t); + WASM_CALLABLE_FUNC_4(void, CallInterpreter_I32_I32_I32_RetVoid, int32_t arg0, int32_t arg1, int32_t arg2, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[3]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + transitionBlock.args[2] = (int64_t)arg2; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL2(void, CallInterpreter_I32_I32_RetVoid, int32_t, int32_t); + WASM_CALLABLE_FUNC_3(void, CallInterpreter_I32_I32_RetVoid, int32_t arg0, int32_t arg1, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[2]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + transitionBlock.args[1] = (int64_t)arg1; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL1(void, CallInterpreter_I32_RetVoid, int32_t); + WASM_CALLABLE_FUNC_2(void, CallInterpreter_I32_RetVoid, int32_t arg0, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + int64_t args[1]; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + transitionBlock.args[0] = (int64_t)arg0; + static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), "Args array must be at a TransitionBlock offset from the start of the block"); + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, sizeof(transitionBlock.args), (int8_t*)&result); + return; + } + + FCDECL0(void, CallInterpreter_Void_RetVoid); + WASM_CALLABLE_FUNC_1(void, CallInterpreter_Void_RetVoid, PCODE portableEntrypoint) + { + struct + { + TransitionBlock block; + } transitionBlock; + transitionBlock.block.m_ReturnAddress = 0; + transitionBlock.block.m_StackPointer = callersStackPointer; + + void * result = NULL; + ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, 0, (int8_t*)&result); + return; + } + +} + +const StringToWasmSigThunk g_wasmGeneratedPortableEntryPointThunks[] = { + { "IS12TS12ip", (void*)&CallInterpreter_This_S12_I32_RetS12 }, + { "IS12TiS12ip", (void*)&CallInterpreter_This_I32_S12_I32_RetS12 }, + { "IS12Tiiip", (void*)&CallInterpreter_This_I32_I32_I32_RetS12 }, + { "IS12Tiip", (void*)&CallInterpreter_This_I32_I32_RetS12 }, + { "IS16Tp", (void*)&CallInterpreter_This_RetS16 }, + { "IS16l2ip", (void*)&CallInterpreter_L2_I32_RetS16 }, + { "IS1Tp", (void*)&CallInterpreter_This_RetS1 }, + { "IS8Tiiip", (void*)&CallInterpreter_This_I32_I32_I32_RetS8 }, + { "IS8Tip", (void*)&CallInterpreter_This_I32_RetS8 }, + { "IS8Tp", (void*)&CallInterpreter_This_RetS8 }, + { "Iddddp", (void*)&CallInterpreter_F64_F64_F64_RetF64 }, + { "Idddp", (void*)&CallInterpreter_F64_F64_RetF64 }, + { "Iddip", (void*)&CallInterpreter_F64_I32_RetF64 }, + { "Iddp", (void*)&CallInterpreter_F64_RetF64 }, + { "Iffffp", (void*)&CallInterpreter_F32_F32_F32_RetF32 }, + { "Ifffp", (void*)&CallInterpreter_F32_F32_RetF32 }, + { "Iffip", (void*)&CallInterpreter_F32_I32_RetF32 }, + { "Iffp", (void*)&CallInterpreter_F32_RetF32 }, + { "IiS8p", (void*)&CallInterpreter_S8_RetI32 }, + { "IiTS12ip", (void*)&CallInterpreter_This_S12_I32_RetI32 }, + { "IiTS12p", (void*)&CallInterpreter_This_S12_RetI32 }, + { "IiTS8S8p", (void*)&CallInterpreter_This_S8_S8_RetI32 }, + { "IiTS8iS8ip", (void*)&CallInterpreter_This_S8_I32_S8_I32_RetI32 }, + { "IiTS8iiip", (void*)&CallInterpreter_This_S8_I32_I32_I32_RetI32 }, + { "IiTS8ip", (void*)&CallInterpreter_This_S8_I32_RetI32 }, + { "IiTS8p", (void*)&CallInterpreter_This_S8_RetI32 }, + { "IiTiS12p", (void*)&CallInterpreter_This_I32_S12_RetI32 }, + { "IiTiS8p", (void*)&CallInterpreter_This_I32_S8_RetI32 }, + { "IiTiiiip", (void*)&CallInterpreter_This_I32_I32_I32_I32_RetI32 }, + { "IiTiiip", (void*)&CallInterpreter_This_I32_I32_I32_RetI32 }, + { "IiTiip", (void*)&CallInterpreter_This_I32_I32_RetI32 }, + { "IiTip", (void*)&CallInterpreter_This_I32_RetI32 }, + { "IiTp", (void*)&CallInterpreter_This_RetI32 }, + { "Iidp", (void*)&CallInterpreter_F64_RetI32 }, + { "IiiS8p", (void*)&CallInterpreter_I32_S8_RetI32 }, + { "Iiiiiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_I32_I32_I32_RetI32 }, + { "Iiiiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_I32_I32_RetI32 }, + { "Iiiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_I32_RetI32 }, + { "Iiiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_I32_RetI32 }, + { "Iiiiiip", (void*)&CallInterpreter_I32_I32_I32_I32_RetI32 }, + { "Iiiiip", (void*)&CallInterpreter_I32_I32_I32_RetI32 }, + { "Iiiip", (void*)&CallInterpreter_I32_I32_RetI32 }, + { "Iiip", (void*)&CallInterpreter_I32_RetI32 }, + { "Iip", (void*)&CallInterpreter_Void_RetI32 }, + { "Ildp", (void*)&CallInterpreter_F64_RetI64 }, + { "Ilillp", (void*)&CallInterpreter_I32_I64_I64_RetI64 }, + { "Ililp", (void*)&CallInterpreter_I32_I64_RetI64 }, + { "Ilip", (void*)&CallInterpreter_I32_RetI64 }, + { "Illlp", (void*)&CallInterpreter_I64_I64_RetI64 }, + { "Ilp", (void*)&CallInterpreter_Void_RetI64 }, + { "IvTS12p", (void*)&CallInterpreter_This_S12_RetVoid }, + { "IvTS32p", (void*)&CallInterpreter_This_S32_RetVoid }, + { "IvTS8S8p", (void*)&CallInterpreter_This_S8_S8_RetVoid }, + { "IvTS8ip", (void*)&CallInterpreter_This_S8_I32_RetVoid }, + { "IvTS8p", (void*)&CallInterpreter_This_S8_RetVoid }, + { "IvTiS8p", (void*)&CallInterpreter_This_I32_S8_RetVoid }, + { "IvTiiS8S8iip", (void*)&CallInterpreter_This_I32_I32_S8_S8_I32_I32_RetVoid }, + { "IvTiiiiip", (void*)&CallInterpreter_This_I32_I32_I32_I32_I32_RetVoid }, + { "IvTiiiip", (void*)&CallInterpreter_This_I32_I32_I32_I32_RetVoid }, + { "IvTiiip", (void*)&CallInterpreter_This_I32_I32_I32_RetVoid }, + { "IvTiip", (void*)&CallInterpreter_This_I32_I32_RetVoid }, + { "IvTip", (void*)&CallInterpreter_This_I32_RetVoid }, + { "IvTp", (void*)&CallInterpreter_This_RetVoid }, + { "Ivdiip", (void*)&CallInterpreter_F64_I32_I32_RetVoid }, + { "Ivfiip", (void*)&CallInterpreter_F32_I32_I32_RetVoid }, + { "Iviiiip", (void*)&CallInterpreter_I32_I32_I32_I32_RetVoid }, + { "Iviiip", (void*)&CallInterpreter_I32_I32_I32_RetVoid }, + { "Iviip", (void*)&CallInterpreter_I32_I32_RetVoid }, + { "Ivip", (void*)&CallInterpreter_I32_RetVoid }, + { "Ivp", (void*)&CallInterpreter_Void_RetVoid }, +}; + +const size_t g_wasmGeneratedPortableEntryPointThunksCount = sizeof(g_wasmGeneratedPortableEntryPointThunks) / sizeof(g_wasmGeneratedPortableEntryPointThunks[0]); diff --git a/src/native/libs/build-native.cmd b/src/native/libs/build-native.cmd index 0369fc8db2e684..0c96c064b590aa 100644 --- a/src/native/libs/build-native.cmd +++ b/src/native/libs/build-native.cmd @@ -63,6 +63,9 @@ if "%__TargetOS%"=="android" ( if "%__TargetOS%"=="browser" ( set __CrossTarget=1 ) +if "%__TargetOS%"=="wasi" ( + set __CrossTarget=1 +) if %__CrossTarget% EQU 0 ( call "%__repoRoot%\eng\native\version\copy_version_files.cmd" diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj index 32cac2b06a82d4..701a1d062af057 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj @@ -81,7 +81,8 @@ TargetOS="$(_RunGeneratorTargetOS)" PInvokeOutputPath="$(GeneratorOutputPath)callhelpers-pinvoke.cpp" ReversePInvokeOutputPath="$(GeneratorOutputPath)callhelpers-reverse.cpp" - InterpToNativeOutputPath="$(GeneratorOutputPath)callhelpers-interp-to-managed.cpp"> + InterpToNativeOutputPath="$(GeneratorOutputPath)callhelpers-interp-to-managed.cpp" + PortableEntryPointOutputPath="$(GeneratorOutputPath)callhelpers-portable-entrypoints.cpp"> diff --git a/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs index e5183182df8088..821214d6e6420b 100644 --- a/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs +++ b/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs @@ -57,6 +57,160 @@ private static string CallFuncName(IEnumerable args, string result, bool return $"CallFunc_{paramTypes}_Ret{result}{(isPortableEntryPointCall ? "_PE" : "")}"; } + /// + /// Emits the R2R-to-interpreter side of the portable entrypoint boundary: the thunks that + /// g_wasmThunks' _PE helpers call into. Struct returns are not emitted yet; their + /// wasm sret convention across this boundary is not settled, and no _PE helper exercises one. + /// + public void GeneratePortableEntryPoints(IEnumerable cookies, string outputPath) + { + using TempFileName tmpFileName = new(); + using (var w = File.CreateText(tmpFileName.Path)) + { + EmitPortableEntryPoints(w, cookies); + } + + if (Utils.CopyIfDifferent(tmpFileName.Path, outputPath, useHash: false)) + Log.LogMessage(MessageImportance.Low, $"Generating portable entrypoint thunks to '{outputPath}'."); + else + Log.LogMessage(MessageImportance.Low, $"Portable entrypoint thunks in {outputPath} are unchanged."); + } + + private static string CallInterpreterName(IEnumerable args, string result) + { + var paramTypes = args.Any() ? string.Join("_", args.Select(static t => SignatureMapper.TokenToNameType(t))) : "Void"; + + return $"CallInterpreter_{paramTypes}_Ret{result}"; + } + + private static bool IsStructToken(string token) => PortableEntryPointThunkSignature.IsStructToken(token); + + private static void EmitPortableEntryPoints(StreamWriter w, IEnumerable cookies) + { + var signatures = cookies.Distinct().OrderBy(c => c, StringComparer.Ordinal).ToArray(); + + 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 + #include + #include "callhelpers.hpp" + + void ExecuteInterpretedMethodWithArgs_PortableEntryPoint(PCODE portableEntrypoint, TransitionBlock* block, size_t argsSize, int8_t* retBuff); + + namespace + { + + """); + + var emitted = new List<(string Key, string Name)>(); + + foreach (var signature in signatures) + { + var tokens = SignatureMapper.ParseSignatureTokens(signature); + if (!IsPortableEntryPointCall(tokens)) + continue; + + string returnToken = tokens[0]; + + tokens.RemoveAt(tokens.Count - 1); + RemoveAsyncCallMarker(tokens); + var args = Args(tokens); + + string retName = SignatureMapper.TokenToNameType(returnToken); + string name = CallInterpreterName(args, retName); + if (emitted.Any(e => e.Name == name)) + continue; + + // crossgen2 passes a struct return through an explicit buffer parameter rather than by value. + // Returning the struct by value instead would make the compiler insert its own sret pointer + // ahead of callersStackPointer, silently transposing the two. + bool isStructReturn = IsStructToken(returnToken); + string retType = isStructReturn ? "void" : SignatureMapper.TokenToNativeType(returnToken); + bool isVoid = isStructReturn || returnToken == "v"; + + var parameters = PortableEntryPointThunkSignature.GetDeclaredParameters(args, isStructReturn); + var declTypes = parameters.Select(static p => p.NativeType).ToList(); + var namedArgs = parameters.Select(static p => $"{p.NativeType} {p.Name}").ToList(); + + int slot = 0; + var stores = new List(); + for (int i = 0; i < args.Count; i++) + { + string t = args[i]; + if (t[0] == 'A') + slot = (slot + 1) & ~1; + + // A float or double occupies its slot as itself: casting to int64_t would convert the + // value rather than store its bits, and the interpreter reads the slot back through + // ARG_F32/ARG_F64. + if (SignatureMapper.TryGetMultiSlotToken(t, out int multiSlotCount)) + { + for (int s = 0; s < multiSlotCount; s++) + stores.Add($" transitionBlock.args[{slot + s}] = {PortableEntryPointThunkSignature.MultiSlotParameterName(i, s, multiSlotCount)};"); + } + else + { + stores.Add(t switch + { + _ when IsStructToken(t) => $" memcpy(&transitionBlock.args[{slot}], arg{i}, {SignatureMapper.GetStructSize(t)});", + "f" => $" *(float*)&transitionBlock.args[{slot}] = arg{i};", + "d" => $" *(double*)&transitionBlock.args[{slot}] = arg{i};", + _ => $" transitionBlock.args[{slot}] = (int64_t)arg{i};", + }); + } + + slot += SignatureMapper.TokenToSlotCount(t); + } + + string declArgs = declTypes.Count > 0 ? ", " + string.Join(", ", declTypes) : ""; + string sigArgs = namedArgs.Count > 0 ? string.Join(", ", namedArgs) + ", " : ""; + + w.WriteLine($" FCDECL{declTypes.Count}({retType}, {name}{declArgs});"); + w.WriteLine($" WASM_CALLABLE_FUNC_{declTypes.Count + 1}({retType}, {name}, {sigArgs}PCODE portableEntrypoint)"); + w.WriteLine(" {"); + w.WriteLine(" struct"); + w.WriteLine(" {"); + w.WriteLine(" TransitionBlock block;"); + if (slot > 0) + w.WriteLine($" int64_t args[{slot}];"); + w.WriteLine(" } transitionBlock;"); + w.WriteLine(" transitionBlock.block.m_ReturnAddress = 0;"); + w.WriteLine(" transitionBlock.block.m_StackPointer = callersStackPointer;"); + foreach (var store in stores) + w.WriteLine(store); + if (slot > 0) + w.WriteLine(" static_assert(offsetof(decltype(transitionBlock), args) == sizeof(TransitionBlock), \"Args array must be at a TransitionBlock offset from the start of the block\");"); + w.WriteLine(); + if (!isStructReturn) + w.WriteLine(isVoid ? " void * result = NULL;" : $" {retType} result = 0;"); + string retBuffArg = isStructReturn ? "retBuf" : "(int8_t*)&result"; + w.WriteLine($" ExecuteInterpretedMethodWithArgs_PortableEntryPoint(portableEntrypoint, &transitionBlock.block, {(slot > 0 ? "sizeof(transitionBlock.args)" : "0")}, {retBuffArg});"); + w.WriteLine(isVoid ? " return;" : " return result;"); + w.WriteLine(" }"); + w.WriteLine(); + + emitted.Add(("I" + signature, name)); + } + + w.WriteLine("}"); + w.WriteLine(); + w.WriteLine("const StringToWasmSigThunk g_wasmGeneratedPortableEntryPointThunks[] = {"); + foreach (var (key, name) in emitted) + w.WriteLine($" {{ \"{key}\", (void*)&{name} }},"); + w.WriteLine("};"); + w.WriteLine(); + w.WriteLine("const size_t g_wasmGeneratedPortableEntryPointThunksCount = sizeof(g_wasmGeneratedPortableEntryPointThunks) / sizeof(g_wasmGeneratedPortableEntryPointThunks[0]);"); + } + private static void Emit(StreamWriter w, IEnumerable cookies) { // Use OrderBy because Order() is not available on .NET Framework @@ -128,7 +282,39 @@ private static void Emit(StreamWriter w, IEnumerable cookies) var args = Args(tokens); - var portableEntryPointComma = args.Count > 0 ? ", " : ""; + var argTypes = new List(); + foreach (var argToken in args) + { + if (SignatureMapper.TryGetMultiSlotToken(argToken, out int multiSlotCount)) + { + string slotType = SignatureMapper.MultiSlotElementNativeType(argToken); + for (int s = 0; s < multiSlotCount; s++) + argTypes.Add(slotType); + } + else + { + argTypes.Add(SignatureMapper.TokenToNativeType(argToken)); + } + } + + var argValues = ArgsWithSlotOffsets(args).ToList(); + + // R2R code takes a struct return through an explicit buffer that follows the stack + // pointer and 'this', so the pointer this calls through must spell it out. Declaring + // the call as returning the struct would make the compiler insert its own sret + // pointer at parameter 0 instead, ahead of the stack pointer. Native callees keep the + // by-value form, which is what their own C ABI gives them. + bool isStructReturn = isPortableEntryPointCall && IsStructToken(returnToken); + if (isStructReturn) + { + argTypes.Insert(args.Count > 0 && args[0] == "T" ? 1 : 0, "int8_t*"); + argValues.Insert(args.Count > 0 && args[0] == "T" ? 1 : 0, "pRet"); + } + + string fptrReturn = isStructReturn ? "void" : result.nativeType; + string assignResult = isStructReturn || result.isVoid ? "" : $"*(({result.nativeType}*)pRet) = "; + + var portableEntryPointComma = argTypes.Count > 0 ? ", " : ""; var portableEntrypointDeclaration = isPortableEntryPointCall ? portableEntryPointComma + "PCODE" : ""; var portableEntrypointParam = isPortableEntryPointCall ? portableEntryPointComma + "pPortableEntryPoint" : ""; var portableEntrypointStackDeclaration = isPortableEntryPointCall ? "int*, " : ""; @@ -139,8 +325,8 @@ private static void Emit(StreamWriter w, IEnumerable cookies) {{(isPortableEntryPointCall ? "NOINLINE " : "")}}static void {{CallFuncName(args, SignatureMapper.TokenToNameType(returnToken), isPortableEntryPointCall)}}(PCODE {{(isPortableEntryPointCall ? "pPortableEntryPoint" : "pcode")}}, int8_t* pArgs, int8_t* pRet) {{{(isPortableEntryPointCall ? "\n alignas(16) int framePointer = TERMINATE_R2R_STACK_WALK;" : "")}} - {{result.nativeType}} (*fptr)({{portableEntrypointStackDeclaration}}{{string.Join(", ", args.Select(static t => SignatureMapper.TokenToNativeType(t)))}}{{portableEntrypointDeclaration}}) = {{portableEntrypointPointerRD}}({{result.nativeType}} ({{portableEntrypointPointerRD}}*)({{portableEntrypointStackDeclaration}}{{string.Join(", ", args.Select(static t => SignatureMapper.TokenToNativeType(t)))}}{{portableEntrypointDeclaration}})){{(isPortableEntryPointCall ? "(pPortableEntryPoint)" : "pcode")}}; - {{(result.isVoid ? "" : "*" + "((" + result.nativeType + "*)pRet) = ")}}(*fptr)({{portableEntrypointStackParam}}{{string.Join(", ", ArgsWithSlotOffsets(args))}}{{portableEntrypointParam}}); + {{fptrReturn}} (*fptr)({{portableEntrypointStackDeclaration}}{{string.Join(", ", argTypes)}}{{portableEntrypointDeclaration}}) = {{portableEntrypointPointerRD}}({{fptrReturn}} ({{portableEntrypointPointerRD}}*)({{portableEntrypointStackDeclaration}}{{string.Join(", ", argTypes)}}{{portableEntrypointDeclaration}})){{(isPortableEntryPointCall ? "(pPortableEntryPoint)" : "pcode")}}; + {{assignResult}}(*fptr)({{portableEntrypointStackParam}}{{string.Join(", ", argValues)}}{{portableEntrypointParam}}); } """); @@ -173,11 +359,6 @@ private static void Emit(StreamWriter w, IEnumerable cookies) """); - static List Args(List tokens) - { - return tokens.Count > 1 ? tokens.GetRange(1, tokens.Count - 1) : new List(); - } - static List ArgsWithSlotOffsets(List args) { var result = new List(); @@ -189,7 +370,17 @@ static List ArgsWithSlotOffsets(List args) slot = (slot + 1) & ~1; } - result.Add($"{SignatureMapper.TokenToArgType(token)}({slot})"); + if (SignatureMapper.TryGetMultiSlotToken(token, out int multiSlotCount)) + { + string slotArgType = SignatureMapper.MultiSlotElementArgType(token); + for (int s = 0; s < multiSlotCount; s++) + result.Add($"{slotArgType}({slot + s})"); + } + else + { + result.Add($"{SignatureMapper.TokenToArgType(token)}({slot})"); + } + slot += SignatureMapper.TokenToSlotCount(token); } @@ -204,19 +395,25 @@ static List ArgsWithSlotOffsets(List args) return new(returnToken == "v", SignatureMapper.TokenToNativeType(returnToken)); } - static bool IsPortableEntryPointCall(List tokens) - { - return tokens.Count > 0 && tokens[tokens.Count - 1] == "p"; - } + } - static bool RemoveAsyncCallMarker(List tokens) - { - int asyncMarkerIndex = tokens.IndexOf("a"); - if (asyncMarkerIndex < 0) - return false; + private static List Args(List tokens) + { + return tokens.Count > 1 ? tokens.GetRange(1, tokens.Count - 1) : new List(); + } - tokens.RemoveAt(asyncMarkerIndex); - return true; - } + private static bool IsPortableEntryPointCall(List tokens) + { + return tokens.Count > 0 && tokens[tokens.Count - 1] == "p"; + } + + private static bool RemoveAsyncCallMarker(List tokens) + { + int asyncMarkerIndex = tokens.IndexOf("a"); + if (asyncMarkerIndex < 0) + return false; + + tokens.RemoveAt(asyncMarkerIndex); + return true; } } diff --git a/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs index f033d8b39ca3ed..7e92fbfd71beb4 100644 --- a/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs +++ b/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs @@ -31,6 +31,9 @@ public class ManagedToNativeGenerator : Task [Required, NotNull] public string? InterpToNativeOutputPath { get; set; } + + /// Set only by the in-tree RunGenerator target; app builds use the runtime's copy. + public string? PortableEntryPointOutputPath { get; set; } public string? CacheFilePath { get; set; } public bool IsLibraryMode { get; set; } @@ -117,7 +120,19 @@ private void ExecuteInternal(LogAdapter log) // The signatures should be in the form of a string where the first character represents the return type and the // following characters represent the argument types. The type characters should match those used by the // SignatureMapper.CharToNativeType method. - string[] pregeneratedInterpreterToNativeSignatures = Array.Empty(); // Currently none, but can be added here as needed in the future. + // The instance ('T') shapes below are the ones a Blazor app hits on startup. The static shapes on + // the last line were hand-written in vm/wasm/helpers.cpp before this generator emitted the table. + string[] pregeneratedInterpreterToNativeSignatures = new[] + { + "iTp", "iTip", "iTiip", "iTiiip", "iTiiiip", + "vTp", "vTip", "vTiip", "vTiiip", "vTiiiip", "vTiiiiip", + "iTS8p", "iTS8ip", "iTS8S8p", "iTS8iS8ip", "iTS8iiip", "iTiS8p", + "iTS12p", "iTS12ip", "iTiS12p", + "vTS8p", "vTS8ip", "vTS8S8p", "vTiS8p", "vTS12p", "vTS32p", "vTiiS8S8iip", + "S8Tp", "S8Tip", "S8Tiiip", "S12Tiip", "S12Tiiip", "S12TS12ip", "S16Tp", "S1Tp", + "S12TiS12ip", + "viiiip", "iiiiiiiip", "iiiiiiiiip", "idp", "ldp", "iiS8p", "iS8p", "S16l2ip", + }; IEnumerable cookies = pinvoke.Generate(PInvokeModules, IgnoredPInvokeModules, PInvokeOutputPath, ReversePInvokeOutputPath); cookies = cookies.Concat(internalCallCollector.GetSignatures()); @@ -126,6 +141,9 @@ private void ExecuteInternal(LogAdapter log) var m2n = new InterpToNativeGenerator(log); m2n.Generate(cookies, InterpToNativeOutputPath); + if (!string.IsNullOrEmpty(PortableEntryPointOutputPath)) + m2n.GeneratePortableEntryPoints(cookies, PortableEntryPointOutputPath); + if (!string.IsNullOrEmpty(CacheFilePath)) { IEnumerable cacheLines = PInvokeModules diff --git a/src/tasks/WasmAppBuilder/coreclr/PortableEntryPointThunkSignature.cs b/src/tasks/WasmAppBuilder/coreclr/PortableEntryPointThunkSignature.cs new file mode 100644 index 00000000000000..2f70740df0807f --- /dev/null +++ b/src/tasks/WasmAppBuilder/coreclr/PortableEntryPointThunkSignature.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; + +namespace Microsoft.WebAssembly.Build.Tasks.CoreClr; + +// Parameter layout of a generated R2R-to-interpreter thunk. Shared with the tests, which compare +// it against the wasm signature crossgen2 computes for the same key, so it must stay free of +// MSBuild dependencies. +internal static class PortableEntryPointThunkSignature +{ + internal readonly struct Parameter + { + public Parameter(string nativeType, string name) + { + NativeType = nativeType; + Name = name; + } + + public string NativeType { get; } + public string Name { get; } + } + + public static bool IsStructToken(string token) => token[0] is 'S' or 'A' && token.Length > 1; + + // A struct argument arrives as the address of its interpreter stack slot. + public static string DeclType(string token) + => IsStructToken(token) ? "int8_t*" : SignatureMapper.TokenToNativeType(token); + + /// + /// The name of one slot of a multi-slot argument, which occupies several wasm parameters. + /// + public static string MultiSlotParameterName(int argIndex, int slot, int slotCount) + => slotCount == 2 ? $"arg{argIndex}{(slot == 0 ? "Lo" : "Hi")}" : $"arg{argIndex}_{slot}"; + + /// + /// The thunk's declared C parameters, in the order crossgen2 passes them: + /// (callersStackPointer, [this], retBuf, args..., portableEntrypoint). The stack pointer comes + /// from the WASM_CALLABLE_FUNC macro and the entrypoint is appended by the caller, so neither + /// appears here. + /// + public static List GetDeclaredParameters(IReadOnlyList args, bool isStructReturn) + { + var parameters = new List(args.Count + 1); + for (int i = 0; i < args.Count; i++) + { + if (SignatureMapper.TryGetMultiSlotToken(args[i], out int slotCount)) + { + string slotType = SignatureMapper.MultiSlotElementNativeType(args[i]); + for (int slot = 0; slot < slotCount; slot++) + parameters.Add(new Parameter(slotType, MultiSlotParameterName(i, slot, slotCount))); + } + else + { + parameters.Add(new Parameter(DeclType(args[i]), $"arg{i}")); + } + } + + if (isStructReturn) + { + // The hidden return buffer follows the 'this' pointer rather than preceding it. + // See WasmR2RToInterpreterThunkNode.EmitCode: retBufLocalIndex = 1 + (hasThis ? 1 : 0). + int retBufIndex = args.Count > 0 && args[0] == "T" ? 1 : 0; + parameters.Insert(retBufIndex, new Parameter("int8_t*", "retBuf")); + } + + return parameters; + } +} diff --git a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.Tokens.cs b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.Tokens.cs new file mode 100644 index 00000000000000..a025fb04d702cb --- /dev/null +++ b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.Tokens.cs @@ -0,0 +1,177 @@ +// 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; + +namespace Microsoft.WebAssembly.Build.Tasks.CoreClr; + +// The half of SignatureMapper that maps signature tokens to native types. It is kept free of +// MSBuild dependencies so that tests can compile it directly; the reflection-based half needs a +// LogAdapter and cannot be linked on its own. +internal static partial class SignatureMapper +{ + /// + /// Parses a signature string into individual tokens. + /// Single-char types produce one-char tokens; struct encodings produce multi-char tokens like + /// "S8" or "A32", and a multi-slot parameter produces a two-char token like "l2" or "V4". + /// The 'a' and 'p' suffixes are included as their own tokens. + /// + public static List ParseSignatureTokens(string signature) + { + var tokens = new List(); + int i = 0; + while (i < signature.Length) + { + if (signature[i] is 'S' or 'A') + { + int start = i; + i++; // skip 'S'/'A' + while (i < signature.Length && char.IsDigit(signature[i])) + i++; + tokens.Add(signature.Substring(start, i - start)); + } + else if (signature[i] is 'l' or 'V' && i + 1 < signature.Length && char.IsDigit(signature[i + 1])) + { + tokens.Add(signature.Substring(i, 2)); + i += 2; + } + else + { + tokens.Add(signature[i].ToString()); + i++; + } + } + + return tokens; + } + + /// + /// True for a token describing a type passed by value across several wasm parameters ("l2", + /// "V2", "V4"), reporting how many it occupies. A caller has to expand it into one parameter per + /// slot; the single-type accessors below still reject it so an unexpanded token cannot slip + /// through as one parameter. + /// + public static bool TryGetMultiSlotToken(string token, out int slotCount) + { + if (token.Length == 2 && token[0] is 'l' or 'V' && char.IsDigit(token[1])) + { + slotCount = token[1] - '0'; + return true; + } + + slotCount = 0; + return false; + } + + /// The type of one slot of a multi-slot token. + public static string MultiSlotElementNativeType(string token) => token[0] switch + { + 'l' => "int64_t", + _ => throw new NotSupportedException($"Multi-slot token '{token}' has no native type these thunks can spell") + }; + + /// The interpreter stack accessor for one slot of a multi-slot token. + public static string MultiSlotElementArgType(string token) => token[0] switch + { + 'l' => "ARG_I64", + _ => throw new NotSupportedException($"Multi-slot token '{token}' has no interpreter stack accessor") + }; + + private static void RejectMultiSlotToken(string token) + { + if (TryGetMultiSlotToken(token, out _)) + throw new NotSupportedException($"Multi-slot signature token '{token}' must be expanded into one parameter per slot"); + } + + public static string TokenToNativeType(string token) + { + RejectMultiSlotToken(token); + return token[0] switch + { + 'v' => "void", + 'i' => "int32_t", + 'l' => "int64_t", + 'f' => "float", + 'd' => "double", + 'S' or 'A' => "int32_t", + 'T' => "int32_t", + 'p' => "PCODE", + _ => throw new InvalidSignatureCharException(token[0]) + }; + } + + public static string TokenToNameType(string token) + { + if (TryGetMultiSlotToken(token, out int multiSlotCount)) + return $"{char.ToUpperInvariant(token[0])}{multiSlotCount}"; + + return token[0] switch + { + 'v' => "Void", + 'i' => "I32", + 'l' => "I64", + 'f' => "F32", + 'd' => "F64", + 'S' or 'A' => token, + 'T' => "This", + 'p' => "PE", + _ => throw new InvalidSignatureCharException(token[0]) + }; + } + + public static string TokenToArgType(string token) + { + RejectMultiSlotToken(token); + return token[0] switch + { + 'i' => "ARG_I32", + 'l' => "ARG_I64", + 'f' => "ARG_F32", + 'd' => "ARG_F64", + 'S' or 'A' => "ARG_IND", + 'T' => "ARG_I32", + _ => throw new InvalidSignatureCharException(token[0]) + }; + } + + /// + /// Returns the number of INTERP_STACK_SLOT_SIZE slots consumed by a token. + /// Struct tokens consume max((size + 7) / 8, 1) slots; all others consume 1. + /// + public static int TokenToSlotCount(string token) + { + if (TryGetMultiSlotToken(token, out int multiSlotCount)) + { + // An i64 slot is one interpreter slot; a v128 slot would be two, but nothing spells one yet. + return token[0] == 'l' + ? multiSlotCount + : throw new NotSupportedException($"Multi-slot token '{token}' has no known interpreter slot size"); + } + + if (token[0] is not ('S' or 'A') || token.Length < 2) + return 1; + + int size = GetStructSize(token); + return Math.Max((size + 7) / 8, 1); + } + + internal static int GetStructSize(string token) + { + return int.Parse(token.Substring(1)); + } + + // Legacy single-char overloads — still used by consumers that don't encounter S tokens. + public static string CharToNativeType(char c) => TokenToNativeType(c.ToString()); + public static string CharToNameType(char c) => TokenToNameType(c.ToString()); + public static string CharToArgType(char c) => TokenToArgType(c.ToString()); + + 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/coreclr/SignatureMapper.cs b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs index c1f07ec01067d9..395cd7dbb75049 100644 --- a/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs +++ b/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs @@ -13,7 +13,7 @@ namespace Microsoft.WebAssembly.Build.Tasks.CoreClr; // Computes Wasm signature strings from reflection metadata. // The signature string format is documented in docs/design/coreclr/botr/readytorun-format.md // (section "Wasm Signature String Encoding"). -internal static class SignatureMapper +internal static partial class SignatureMapper { // Hardcoded struct layouts for types that crossgen2 encodes as struct tokens. // The fully general case is handled by crossgen2's type system; these @@ -262,126 +262,6 @@ private static bool HasNumericElementType(Type t) return sb.ToString(); } - /// - /// Parses a signature string into individual tokens. - /// Single-char types produce one-char tokens; struct encodings produce multi-char tokens like - /// "S8" or "A32", and a multi-slot parameter produces a two-char token like "l2" or "V4". - /// The 'a' and 'p' suffixes are included as their own tokens. - /// - public static List ParseSignatureTokens(string signature) - { - var tokens = new List(); - int i = 0; - while (i < signature.Length) - { - if (signature[i] is 'S' or 'A') - { - int start = i; - i++; // skip 'S'/'A' - while (i < signature.Length && char.IsDigit(signature[i])) - i++; - tokens.Add(signature.Substring(start, i - start)); - } - else if (signature[i] is 'l' or 'V' && i + 1 < signature.Length && char.IsDigit(signature[i + 1])) - { - tokens.Add(signature.Substring(i, 2)); - i += 2; - } - else - { - tokens.Add(signature[i].ToString()); - i++; - } - } - - return tokens; - } - - /// - /// True for a token describing a type passed by value across several wasm parameters - /// ("l2", "V2", "V4"). Interop signatures do not use these today. - /// - private static bool IsMultiSlotToken(string token) - => token.Length == 2 && token[0] is 'l' or 'V' && char.IsDigit(token[1]); - - private static void RejectMultiSlotToken(string token) - { - if (IsMultiSlotToken(token)) - throw new NotSupportedException($"Multi-slot signature token '{token}' is not supported in interop thunks"); - } - - public static string TokenToNativeType(string token) - { - RejectMultiSlotToken(token); - return token[0] switch - { - 'v' => "void", - 'i' => "int32_t", - 'l' => "int64_t", - 'f' => "float", - 'd' => "double", - 'S' or 'A' => "int32_t", - 'T' => "int32_t", - 'p' => "PCODE", - _ => throw new InvalidSignatureCharException(token[0]) - }; - } - - public static string TokenToNameType(string token) - { - RejectMultiSlotToken(token); - return token[0] switch - { - 'v' => "Void", - 'i' => "I32", - 'l' => "I64", - 'f' => "F32", - 'd' => "F64", - 'S' or 'A' => token, - 'T' => "This", - 'p' => "PE", - _ => throw new InvalidSignatureCharException(token[0]) - }; - } - - public static string TokenToArgType(string token) - { - RejectMultiSlotToken(token); - return token[0] switch - { - 'i' => "ARG_I32", - 'l' => "ARG_I64", - 'f' => "ARG_F32", - 'd' => "ARG_F64", - 'S' or 'A' => "ARG_IND", - 'T' => "ARG_I32", - _ => throw new InvalidSignatureCharException(token[0]) - }; - } - - /// - /// Returns the number of INTERP_STACK_SLOT_SIZE slots consumed by a token. - /// Struct tokens consume max((size + 7) / 8, 1) slots; all others consume 1. - /// - public static int TokenToSlotCount(string token) - { - if (token[0] is not ('S' or 'A') || token.Length < 2) - return 1; - - int size = GetStructSize(token); - return Math.Max((size + 7) / 8, 1); - } - - internal static int GetStructSize(string token) - { - return int.Parse(token.Substring(1)); - } - - // Legacy single-char overloads — still used by consumers that don't encounter S tokens. - public static string CharToNativeType(char c) => TokenToNativeType(c.ToString()); - public static string CharToNameType(char c) => TokenToNameType(c.ToString()); - public static string CharToArgType(char c) => TokenToArgType(c.ToString()); - public static string TypeToNameType(Type t, LogAdapter log) { char? c = TypeToChar(t, log, out _); @@ -390,13 +270,4 @@ public static string TypeToNameType(Type t, LogAdapter log) return CharToNameType(c.Value); } - - 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/tests/readytorun/wasm/WasmInterpreterTransitions/WasmInterpreterTransitions.cs b/src/tests/readytorun/wasm/WasmInterpreterTransitions/WasmInterpreterTransitions.cs new file mode 100644 index 00000000000000..b93ee83ed46229 --- /dev/null +++ b/src/tests/readytorun/wasm/WasmInterpreterTransitions/WasmInterpreterTransitions.cs @@ -0,0 +1,165 @@ +// 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.Runtime; +using System.Runtime.CompilerServices; +using Xunit; + +namespace System.Runtime +{ + [AttributeUsage(AttributeTargets.Method)] + internal sealed class BypassReadyToRunAttribute : Attribute + { + } +} + +/// +/// Exercises the thunks that carry a call between R2R code and the interpreter on wasm. Methods +/// marked are skipped by crossgen2 and so run interpreted, +/// while the rest of the assembly is compiled, which puts a thunk on every call between the two. +/// +/// Each case returns values chosen so that a wrong answer is visible. That matters more than usual +/// here: the stack pointer, the hidden return buffer, 'this' and every by-reference argument are +/// all i32, so a thunk whose parameters are in the wrong order still passes wasm's call_indirect +/// type check. It does not trap — it writes through the wrong pointer, and the only symptom is +/// data that quietly comes back wrong. +/// +public class WasmInterpreterTransitions +{ + private const int A = 0x11223344; + private const int B = 0x55667788; + private const int C = 0x1234567; + private const long Wide = 0x1122334455667788; + + public struct S8 + { + public int A; + public int B; + } + + public struct S12 + { + public int A; + public int B; + public int C; + } + + public struct S16 + { + public long A; + public long B; + } + + private readonly int _state = C; + + [Fact] + public static void TestEntryPoint() + { + WasmInterpreterTransitions self = new(); + + // R2R -> interpreted, struct returns. The return buffer follows 'this' for an instance + // method and the stack pointer for a static one, which is where the two forms differ. + S8 s8 = self.InterpretedInstanceReturnsS8(A); + Assert.Equal(A, s8.A); + Assert.Equal(C, s8.B); + + S8 staticS8 = InterpretedStaticReturnsS8(A); + Assert.Equal(A, staticS8.A); + Assert.Equal(B, staticS8.B); + + S16 s16 = self.InterpretedInstanceReturnsS16(); + Assert.Equal(Wide, s16.A); + Assert.Equal(C, s16.B); + + S16 staticS16 = InterpretedStaticReturnsS16(Wide, A); + Assert.Equal(Wide, staticS16.A); + Assert.Equal(A, staticS16.B); + + // A struct that is not a whole number of 8-byte slots, passed and returned. + S12 s12 = self.InterpretedInstanceRoundTripsS12(new S12 { A = A, B = B, C = C }, A); + Assert.Equal(B, s12.A); + Assert.Equal(C, s12.B); + Assert.Equal(A, s12.C); + + // R2R -> interpreted, scalar and void shapes. + Assert.Equal(A + C, self.InterpretedInstanceReturnsI32(A)); + Assert.Equal(Wide, InterpretedStaticReturnsI64(1.5)); + Assert.Equal(A + B + C, InterpretedStaticSumsFour(A, B, C, 0)); + Assert.Equal(A, self.InterpretedInstanceMixedScalars(1.5f, 2.5, Wide)); + + // A struct argument arrives as the address of its interpreter stack slot. + Assert.Equal(A + B, self.InterpretedInstanceTakesS8(new S8 { A = A, B = B })); + + s_sideEffect = 0; + self.InterpretedInstanceTakesS8ReturnsVoid(new S8 { A = A, B = B }); + Assert.Equal(A + B, s_sideEffect); + + // interpreted -> R2R, the opposite direction over the same shapes. + Assert.Equal(A + C, self.InterpretedCallsBackIntoR2R()); + + S16 fromInterpreter = self.InterpretedCallsR2RReturningS16(); + Assert.Equal(Wide, fromInterpreter.A); + Assert.Equal(C, fromInterpreter.B); + } + + private static int s_sideEffect; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private S8 InterpretedInstanceReturnsS8(int a) => new S8 { A = a, B = _state }; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private static S8 InterpretedStaticReturnsS8(int a) => new S8 { A = a, B = B }; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private S16 InterpretedInstanceReturnsS16() => new S16 { A = Wide, B = _state }; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private static S16 InterpretedStaticReturnsS16(long wide, int a) => new S16 { A = wide, B = a }; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private S12 InterpretedInstanceRoundTripsS12(S12 value, int a) => new S12 { A = value.B, B = value.C, C = a }; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private int InterpretedInstanceReturnsI32(int a) => a + _state; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private static long InterpretedStaticReturnsI64(double unused) => Wide; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private static int InterpretedStaticSumsFour(int a, int b, int c, int d) => a + b + c + d; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private int InterpretedInstanceMixedScalars(float f, double d, long l) => l == Wide && f == 1.5f && d == 2.5 ? A : 0; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private int InterpretedInstanceTakesS8(S8 value) => value.A + value.B; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private void InterpretedInstanceTakesS8ReturnsVoid(S8 value) => s_sideEffect = value.A + value.B; + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private int InterpretedCallsBackIntoR2R() => R2RInstanceReturnsI32(A); + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private S16 InterpretedCallsR2RReturningS16() => R2RInstanceReturnsS16(); + + [MethodImpl(MethodImplOptions.NoInlining)] + private int R2RInstanceReturnsI32(int a) => a + _state; + + [MethodImpl(MethodImplOptions.NoInlining)] + private S16 R2RInstanceReturnsS16() => new S16 { A = Wide, B = _state }; +} diff --git a/src/tests/readytorun/wasm/WasmInterpreterTransitions/WasmInterpreterTransitions.csproj b/src/tests/readytorun/wasm/WasmInterpreterTransitions/WasmInterpreterTransitions.csproj new file mode 100644 index 00000000000000..092b4f60c765b9 --- /dev/null +++ b/src/tests/readytorun/wasm/WasmInterpreterTransitions/WasmInterpreterTransitions.csproj @@ -0,0 +1,14 @@ + + + true + true + + true + true + + + + +