diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake index ee9d2b574c543d..0969caf1fb98e8 100644 --- a/eng/native/configurecompiler.cmake +++ b/eng/native/configurecompiler.cmake @@ -1133,7 +1133,14 @@ if (CLR_CMAKE_HOST_WIN32) message(FATAL_ERROR "MC not found") endif() -elseif (NOT CLR_CMAKE_HOST_BROWSER AND NOT CLR_CMAKE_HOST_WASI) +elseif (CLR_CMAKE_HOST_BROWSER OR CLR_CMAKE_HOST_WASI) + # The wasm toolchains (emscripten / wasi-sdk) use clang, which can assemble + # preprocessed (.S) wasm assembly files directly. + set (CMAKE_ASM_COMPILER_VERSION "${CMAKE_C_COMPILER_VERSION}") + + enable_language(ASM) + +else() # This is a workaround for upstream issue: https://gitlab.kitware.com/cmake/cmake/-/issues/22995. # # In Clang.cmake, the decision to use single or double hyphen for target and gcc-toolchain diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs index 668af18398026c..0785747f40e9b7 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs @@ -41,15 +41,7 @@ public DelayLoadHelperImport( _useJumpableStub = useJumpableStub; if (factory.Target.Architecture == TargetArchitecture.Wasm32) { - if (instanceSignature is GenericLookupSignature) - { - // Generic lookups are resolved via eager fixups and don't need import thunks - _delayLoadHelper = null; - } - else - { - _delayLoadHelper = factory.WasmImportThunkPortableEntrypoint(this); - } + _delayLoadHelper = factory.WasmImportThunkPortableEntrypoint(this); } else { diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/WasmImportThunkPortableEntrypoint.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/WasmImportThunkPortableEntrypoint.cs index b11a7115897b6e..22971bdf245370 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/WasmImportThunkPortableEntrypoint.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/WasmImportThunkPortableEntrypoint.cs @@ -57,14 +57,14 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer private static readonly WasmSignature _genericLookupSignature32Bit = new WasmSignature( new WasmFuncType( - new WasmResultType(new[] { WasmValueType.I32, WasmValueType.I32 }), + new WasmResultType(new[] { WasmValueType.I32, WasmValueType.I32, WasmValueType.I32 }), new WasmResultType(new[] { WasmValueType.I32 })), - "iii"); + "iip"); private static readonly WasmSignature _genericLookupSignature64Bit = new WasmSignature( new WasmFuncType( - new WasmResultType(new[] { WasmValueType.I64, WasmValueType.I64 }), + new WasmResultType(new[] { WasmValueType.I64, WasmValueType.I64, WasmValueType.I64 }), new WasmResultType(new[] { WasmValueType.I64 })), - "lll"); + "llp"); public override ObjectData GetData(NodeFactory factory, System.Boolean relocsOnly = false) { diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index bd14df4d4364f1..993787c8339d85 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -943,12 +943,17 @@ elseif(CLR_CMAKE_TARGET_ARCH_RISCV64) elseif(CLR_CMAKE_TARGET_ARCH_WASM) set(VM_HEADERS_WKS_ARCH_ASM ${ARCH_SOURCES_DIR}/entrypoints.h + ${ARCH_SOURCES_DIR}/asmconstants.h + ) + set(VM_SOURCES_WKS_ARCH_ASM + ${ARCH_SOURCES_DIR}/dynamichelpers.S ) set(VM_SOURCES_WKS_ARCH ${RUNTIME_DIR}/${ARCH_SOURCES_DIR}/writebarriers.cpp ${ARCH_SOURCES_DIR}/calldescrworkerwasm.cpp ${ARCH_SOURCES_DIR}/profiler.cpp ${ARCH_SOURCES_DIR}/helpers.cpp + ${ARCH_SOURCES_DIR}/dynamichelpers.cpp exceptionhandling.cpp gcinfodecoder.cpp ) diff --git a/src/coreclr/vm/cgensys.h b/src/coreclr/vm/cgensys.h index 92636fc0cdc2ec..3f32aca5cdcecb 100644 --- a/src/coreclr/vm/cgensys.h +++ b/src/coreclr/vm/cgensys.h @@ -68,7 +68,11 @@ extern "C" PCODE STDCALL DelayLoad_MethodCall(TransitionBlock* pTransitionBlock, extern "C" void STDCALL DelayLoad_MethodCall(); #endif +#ifdef TARGET_WASM +extern "C" SIZE_T STDCALL DelayLoad_Helper(TransitionBlock* pTransitionBlock, READYTORUN_IMPORT_THUNK_PORTABLE_ENTRYPOINT* pImportThunkEntry, uint8_t *moduleBase, int32_t rvaOfModuleFixup); +#else extern "C" void STDCALL DelayLoad_Helper(); +#endif extern "C" void STDCALL DelayLoad_Helper_Obj(); extern "C" void STDCALL DelayLoad_Helper_ObjObj(); #endif diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index d73d250b409c2e..1761082a14c2fa 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10869,6 +10869,9 @@ void CEECodeGenInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN { helperMD = GetMethodDescForILBasedDynamicJitHelper(dynamicFtnNum); _ASSERTE(PortableEntryPoint::GetMethodDesc((PCODE)targetAddr) == helperMD); +#ifdef FEATURE_READYTORUN + _ASSERTE(PortableEntryPoint::GetActualCode((PCODE)targetAddr) != NULL); +#endif } #else // !FEATURE_PORTABLE_ENTRYPOINTS diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 17cff51ae1a062..e2d162d4c8bf92 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -3361,7 +3361,17 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR RVA rva = pNativeImage->GetDataRva((TADDR)pCell); - PTR_READYTORUN_IMPORT_SECTION pImportSection = pModule->GetImportSectionFromIndex(sectionIndex); + PTR_READYTORUN_IMPORT_SECTION pImportSection; + if (sectionIndex != (DWORD)-1) + { + pImportSection = pModule->GetImportSectionFromIndex(sectionIndex); + _ASSERTE(pImportSection == pModule->GetImportSectionForRVA(rva)); + } + else + { + pImportSection = pModule->GetImportSectionForRVA(rva); + } + _ASSERTE(pImportSection == pModule->GetImportSectionForRVA(rva)); _ASSERTE(pImportSection->EntrySize == sizeof(TADDR)); @@ -3392,6 +3402,7 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR switch (kind) { +#ifndef TARGET_WASM case READYTORUN_FIXUP_NewObject: th = ZapSig::DecodeType(pModule, pInfoModule, pBlob); th.AsMethodTable()->EnsureInstanceActive(); @@ -3443,7 +3454,7 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR pMD->EnsureActive(); } break; - +#endif // !TARGET_WASM case READYTORUN_FIXUP_ThisObjDictionaryLookup: case READYTORUN_FIXUP_TypeDictionaryLookup: case READYTORUN_FIXUP_MethodDictionaryLookup: @@ -3464,6 +3475,7 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR { switch (kind) { +#ifndef TARGET_WASM case READYTORUN_FIXUP_IsInstanceOf: case READYTORUN_FIXUP_ChkCast: { @@ -3553,7 +3565,7 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR } } break; - +#endif // !TARGET_WASM default: UNREACHABLE(); } @@ -3577,6 +3589,7 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR { switch (kind) { +#ifndef TARGET_WASM case READYTORUN_FIXUP_NewObject: { bool fHasSideEffectsUnused; @@ -3650,7 +3663,7 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR } } break; - +#endif // !TARGET_WASM case READYTORUN_FIXUP_ThisObjDictionaryLookup: case READYTORUN_FIXUP_TypeDictionaryLookup: case READYTORUN_FIXUP_MethodDictionaryLookup: diff --git a/src/coreclr/vm/readytoruninfo.h b/src/coreclr/vm/readytoruninfo.h index 8127e05f6385fd..a5ab695970b2d6 100644 --- a/src/coreclr/vm/readytoruninfo.h +++ b/src/coreclr/vm/readytoruninfo.h @@ -479,6 +479,14 @@ struct GenericDictionaryDynamicHelperStubData GenericHandleArgs *HandleArgs; }; +#ifdef FEATURE_PORTABLE_ENTRYPOINTS +struct GenericDictionaryDynamicHelperStubData_PortableEntryPoint +{ + PCODE HelperFunctionTableIndex; + GenericDictionaryDynamicHelperStubData stubData; +}; +#endif + class ReadyToRunLoadedImage { TADDR m_pImageBase; diff --git a/src/coreclr/vm/wasm/asmconstants.h b/src/coreclr/vm/wasm/asmconstants.h index c43f599357ea26..f1520b4eac4b4d 100644 --- a/src/coreclr/vm/wasm/asmconstants.h +++ b/src/coreclr/vm/wasm/asmconstants.h @@ -6,5 +6,55 @@ // Be sure to rebuild clr/src/vm/ceemain.cpp after changing this file, to // ensure that the constants match the expected C/C++ values +#ifndef ASMCONSTANTS_C_ASSERT +#define ASMCONSTANTS_C_ASSERT(cond) +#endif + +#ifndef ASMCONSTANTS_RUNTIME_ASSERT +#define ASMCONSTANTS_RUNTIME_ASSERT(cond) +#endif + +// Some constants are different in _DEBUG builds. This macro factors out ifdefs from below. +#ifdef _DEBUG +#define DBG_FRE(dbg,fre) dbg +#else +#define DBG_FRE(dbg,fre) fre +#endif + #define DynamicHelperFrameFlags_ObjectArg 1 #define DynamicHelperFrameFlags_ObjectArg2 2 + +#define OFFSETOF__MethodTable__m_pPerInstInfo DBG_FRE(0x24, 0x20) +ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_pPerInstInfo + == offsetof(MethodTable, m_pPerInstInfo)); + +#define OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo DBG_FRE(0x28, 0x14) +ASMCONSTANTS_C_ASSERT(OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo + == offsetof(InstantiatedMethodDesc, m_pPerInstInfo)); + +#define OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__stubData 0x04 +ASMCONSTANTS_C_ASSERT(OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__stubData + == offsetof(GenericDictionaryDynamicHelperStubData_PortableEntryPoint, stubData)); + +#define OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SecondIndir 0x4 +ASMCONSTANTS_C_ASSERT(OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SecondIndir + == offsetof(GenericDictionaryDynamicHelperStubData, SecondIndir) + offsetof(GenericDictionaryDynamicHelperStubData_PortableEntryPoint, stubData)); + +#define OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__LastIndir 0x8 +ASMCONSTANTS_C_ASSERT(OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__LastIndir + == offsetof(GenericDictionaryDynamicHelperStubData, LastIndir) + offsetof(GenericDictionaryDynamicHelperStubData_PortableEntryPoint, stubData)); + +#define OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SizeOffset 0xC +ASMCONSTANTS_C_ASSERT(OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SizeOffset + == offsetof(GenericDictionaryDynamicHelperStubData, SizeOffset) + offsetof(GenericDictionaryDynamicHelperStubData_PortableEntryPoint, stubData)); + +#define OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SlotOffset 0x10 +ASMCONSTANTS_C_ASSERT(OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SlotOffset + == offsetof(GenericDictionaryDynamicHelperStubData, SlotOffset) + offsetof(GenericDictionaryDynamicHelperStubData_PortableEntryPoint, stubData)); + +#define OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__HandleArgs 0x14 +ASMCONSTANTS_C_ASSERT(OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__HandleArgs + == offsetof(GenericDictionaryDynamicHelperStubData, HandleArgs) + offsetof(GenericDictionaryDynamicHelperStubData_PortableEntryPoint, stubData)); + +#undef ASMCONSTANTS_RUNTIME_ASSERT +#undef ASMCONSTANTS_C_ASSERT diff --git a/src/coreclr/vm/wasm/dynamichelpers.S b/src/coreclr/vm/wasm/dynamichelpers.S new file mode 100644 index 00000000000000..dd340691fee6c9 --- /dev/null +++ b/src/coreclr/vm/wasm/dynamichelpers.S @@ -0,0 +1,371 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "asmconstants.h" + +.size g_pClassWithSlotAndModule, 4 +.size g_pMethodWithSlotAndModule, 4 + + +.functype DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull +.globl DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull +.type DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull,@function +DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull: + .functype DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull (i32, i32, i32) -> (i32) + .local i32 + block + block + local.get 1 // Load the GenericContext + i32.load OFFSETOF__MethodTable__m_pPerInstInfo + local.get 2 // Load the GenericClassDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SecondIndir + i32.add + i32.load 0 // Load the SecondDir indirection + local.tee 3 // Store the loaded indirection into local 3, but keep it on the stack as well + local.get 2 // Load the GenericClassDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SizeOffset + i32.add + i32.load 0 // Load the size of the actual GenericDictionary on the Class + local.get 2 // Load the GenericClassDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SlotOffset + i32.lt_s + br_if 0 // Branch to the logic to call the helper function if the size of the actual GenericDictionary on the Class is less than the SlotOffset + local.get 3 // Load the SecondDir indirection + local.get 2 // Load the GenericClassDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__LastIndir + i32.add + i32.load 0 // Load the last indirection + local.tee 3 // Store the loaded indirection into local 3, but keep it on the stack as well + br_if 1 // Branch to return if the result is not null + end_block + local.get 0 // Load the stack pointer + local.get 1 // Load the GenericContext + local.get 2 // Load the GenericClassDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__HandleArgs + i32.const 0 + i32.load g_pClassWithSlotAndModule + local.tee 2 + local.get 2 + i32.load 0 + call_indirect __indirect_function_table, (i32, i32, i32, i32) -> (i32) + local.set 3 + end_block + local.get 3 // Return the result. + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull +.globl DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull +.type DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull,@function +DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull: + .functype DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull (i32, i32, i32) -> (i32) + .local i32 + block + block + local.get 1 // Load the GenericContext + i32.load OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo + local.tee 3 // Store the loaded GenericDictionary into local 3, but keep it on the stack as well + local.get 2 // Load the GenericMethodDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SizeOffset + i32.add + i32.load 0 // Load the size of the actual GenericDictionary on the Method + local.get 2 // Load the GenericMethodDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SlotOffset + i32.lt_s + br_if 0 // Branch to the logic to call the helper function if the size of the actual GenericDictionary on the Method is less than the SlotOffset + local.get 3 // Load the GenericDictionary + local.get 2 // Load the GenericMethodDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__LastIndir + i32.add + i32.load 0 // Load the last indirection + local.tee 3 // Store the loaded indirection into local 3, but keep it on the stack as well + br_if 1 // Branch to return if the result is not null + end_block + local.get 0 // Load the stack pointer + local.get 1 // Load the GenericContext + local.get 2 // Load the GenericMethodDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__HandleArgs + i32.const 0 + i32.load g_pMethodWithSlotAndModule + local.tee 2 + local.get 2 + i32.load 0 + call_indirect __indirect_function_table, (i32, i32, i32, i32) -> (i32) + local.set 3 + end_block + local.get 3 // Return the result. + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Class_TestForNull (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Class_TestForNull,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Class_TestForNull +.globl DynamicHelper_GenericDictionaryLookup_Class_TestForNull +.type DynamicHelper_GenericDictionaryLookup_Class_TestForNull,@function +DynamicHelper_GenericDictionaryLookup_Class_TestForNull: + .functype DynamicHelper_GenericDictionaryLookup_Class_TestForNull (i32, i32, i32) -> (i32) + .local i32 + block + local.get 1 // Load the GenericContext + i32.load OFFSETOF__MethodTable__m_pPerInstInfo + local.get 2 // Load the GenericClassDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SecondIndir + i32.add + i32.load 0 // Load the SecondDir indirection + local.get 2 // Load the GenericClassDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__LastIndir + i32.add + i32.load 0 // Load the last indirection + local.tee 3 // Store the loaded indirection into local 3, but keep it on the stack as well + br_if 0 // Branch to return if the result is not null + local.get 0 // Load the stack pointer + local.get 1 // Load the GenericContext + local.get 2 // Load the GenericClassDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__HandleArgs + i32.const 0 + i32.load g_pClassWithSlotAndModule + local.tee 2 + local.get 2 + i32.load 0 + call_indirect __indirect_function_table, (i32, i32, i32, i32) -> (i32) + local.set 3 + end_block + local.get 3 // Return the result. + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Class (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Class,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Class +.globl DynamicHelper_GenericDictionaryLookup_Class +.type DynamicHelper_GenericDictionaryLookup_Class,@function +DynamicHelper_GenericDictionaryLookup_Class: + .functype DynamicHelper_GenericDictionaryLookup_Class (i32, i32, i32) -> (i32) + local.get 1 // Load the GenericContext + i32.load OFFSETOF__MethodTable__m_pPerInstInfo + local.get 2 // Load the GenericClassDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__SecondIndir + i32.add + i32.load 0 // Load the SecondDir indirection + local.get 2 // Load the GenericClassDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__LastIndir + i32.add + i32.load 0 // Load the last indirection + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Class_0_0 (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Class_0_0,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Class_0_0 +.globl DynamicHelper_GenericDictionaryLookup_Class_0_0 +.type DynamicHelper_GenericDictionaryLookup_Class_0_0,@function +DynamicHelper_GenericDictionaryLookup_Class_0_0: + .functype DynamicHelper_GenericDictionaryLookup_Class_0_0 (i32, i32, i32) -> (i32) + local.get 1 // Load the GenericContext + i32.load OFFSETOF__MethodTable__m_pPerInstInfo + i32.load 0 // Load the SecondDir indirection (offset 0) + i32.load 0 // Load the last indirection (offset 0) + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Class_0_1 (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Class_0_1,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Class_0_1 +.globl DynamicHelper_GenericDictionaryLookup_Class_0_1 +.type DynamicHelper_GenericDictionaryLookup_Class_0_1,@function +DynamicHelper_GenericDictionaryLookup_Class_0_1: + .functype DynamicHelper_GenericDictionaryLookup_Class_0_1 (i32, i32, i32) -> (i32) + local.get 1 // Load the GenericContext + i32.load OFFSETOF__MethodTable__m_pPerInstInfo + i32.load 0 // Load the SecondDir indirection (offset 0) + i32.load 0x4 // Load the last indirection (offset sizeof(TADDR) * 1) + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Class_0_2 (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Class_0_2,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Class_0_2 +.globl DynamicHelper_GenericDictionaryLookup_Class_0_2 +.type DynamicHelper_GenericDictionaryLookup_Class_0_2,@function +DynamicHelper_GenericDictionaryLookup_Class_0_2: + .functype DynamicHelper_GenericDictionaryLookup_Class_0_2 (i32, i32, i32) -> (i32) + local.get 1 // Load the GenericContext + i32.load OFFSETOF__MethodTable__m_pPerInstInfo + i32.load 0 // Load the SecondDir indirection (offset 0) + i32.load 0x8 // Load the last indirection (offset sizeof(TADDR) * 2) + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Class_0_3 (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Class_0_3,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Class_0_3 +.globl DynamicHelper_GenericDictionaryLookup_Class_0_3 +.type DynamicHelper_GenericDictionaryLookup_Class_0_3,@function +DynamicHelper_GenericDictionaryLookup_Class_0_3: + .functype DynamicHelper_GenericDictionaryLookup_Class_0_3 (i32, i32, i32) -> (i32) + local.get 1 // Load the GenericContext + i32.load OFFSETOF__MethodTable__m_pPerInstInfo + i32.load 0 // Load the SecondDir indirection (offset 0) + i32.load 0xC // Load the last indirection (offset sizeof(TADDR) * 3) + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Method_TestForNull (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Method_TestForNull,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Method_TestForNull +.globl DynamicHelper_GenericDictionaryLookup_Method_TestForNull +.type DynamicHelper_GenericDictionaryLookup_Method_TestForNull,@function +DynamicHelper_GenericDictionaryLookup_Method_TestForNull: + .functype DynamicHelper_GenericDictionaryLookup_Method_TestForNull (i32, i32, i32) -> (i32) + .local i32 + block + local.get 1 // Load the GenericContext + i32.load OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo + local.get 2 // Load the GenericMethodDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__LastIndir + i32.add + i32.load 0 // Load the last indirection + local.tee 3 // Store the loaded indirection into local 3, but keep it on the stack as well + br_if 0 // Branch to return if the result is not null + local.get 0 // Load the stack pointer + local.get 1 // Load the GenericContext + local.get 2 // Load the GenericMethodDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__HandleArgs + i32.const 0 + i32.load g_pMethodWithSlotAndModule + local.tee 2 + local.get 2 + i32.load 0 + call_indirect __indirect_function_table, (i32, i32, i32, i32) -> (i32) + local.set 3 + end_block + local.get 3 // Return the result. + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Method (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Method,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Method +.globl DynamicHelper_GenericDictionaryLookup_Method +.type DynamicHelper_GenericDictionaryLookup_Method,@function +DynamicHelper_GenericDictionaryLookup_Method: + .functype DynamicHelper_GenericDictionaryLookup_Method (i32, i32, i32) -> (i32) + local.get 1 // Load the GenericContext + i32.load OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo + local.get 2 // Load the GenericMethodDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__LastIndir + i32.add + i32.load 0 // Load the last indirection + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Method_0 (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Method_0,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Method_0 +.globl DynamicHelper_GenericDictionaryLookup_Method_0 +.type DynamicHelper_GenericDictionaryLookup_Method_0,@function +DynamicHelper_GenericDictionaryLookup_Method_0: + .functype DynamicHelper_GenericDictionaryLookup_Method_0 (i32, i32, i32) -> (i32) + local.get 1 // Load the GenericContext + i32.load OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo + i32.load 0 // Load the last indirection (offset 0) + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Method_1 (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Method_1,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Method_1 +.globl DynamicHelper_GenericDictionaryLookup_Method_1 +.type DynamicHelper_GenericDictionaryLookup_Method_1,@function +DynamicHelper_GenericDictionaryLookup_Method_1: + .functype DynamicHelper_GenericDictionaryLookup_Method_1 (i32, i32, i32) -> (i32) + local.get 1 // Load the GenericContext + i32.load OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo + i32.load 0x4 // Load the last indirection (offset sizeof(TADDR) * 1) + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Method_2 (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Method_2,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Method_2 +.globl DynamicHelper_GenericDictionaryLookup_Method_2 +.type DynamicHelper_GenericDictionaryLookup_Method_2,@function +DynamicHelper_GenericDictionaryLookup_Method_2: + .functype DynamicHelper_GenericDictionaryLookup_Method_2 (i32, i32, i32) -> (i32) + local.get 1 // Load the GenericContext + i32.load OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo + i32.load 0x8 // Load the last indirection (offset sizeof(TADDR) * 2) + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Method_3 (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Method_3,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Method_3 +.globl DynamicHelper_GenericDictionaryLookup_Method_3 +.type DynamicHelper_GenericDictionaryLookup_Method_3,@function +DynamicHelper_GenericDictionaryLookup_Method_3: + .functype DynamicHelper_GenericDictionaryLookup_Method_3 (i32, i32, i32) -> (i32) + local.get 1 // Load the GenericContext + i32.load OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo + i32.load 0xC // Load the last indirection (offset sizeof(TADDR) * 3) + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Class_UseHelper (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Class_UseHelper,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Class_UseHelper +.globl DynamicHelper_GenericDictionaryLookup_Class_UseHelper +.type DynamicHelper_GenericDictionaryLookup_Class_UseHelper,@function +DynamicHelper_GenericDictionaryLookup_Class_UseHelper: + .functype DynamicHelper_GenericDictionaryLookup_Class_UseHelper (i32, i32, i32) -> (i32) + local.get 0 // Load the stack pointer + local.get 1 // Load the GenericContext + local.get 2 // Load the GenericDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__HandleArgs + i32.const 0 + i32.load g_pClassWithSlotAndModule + local.tee 2 + local.get 2 + i32.load 0 + call_indirect __indirect_function_table, (i32, i32, i32, i32) -> (i32) + return + end_function + + +.functype DynamicHelper_GenericDictionaryLookup_Method_UseHelper (i32, i32, i32) -> (i32) +.section .text.DynamicHelper_GenericDictionaryLookup_Method_UseHelper,"",@ +.hidden DynamicHelper_GenericDictionaryLookup_Method_UseHelper +.globl DynamicHelper_GenericDictionaryLookup_Method_UseHelper +.type DynamicHelper_GenericDictionaryLookup_Method_UseHelper,@function +DynamicHelper_GenericDictionaryLookup_Method_UseHelper: + .functype DynamicHelper_GenericDictionaryLookup_Method_UseHelper (i32, i32, i32) -> (i32) + local.get 0 // Load the stack pointer + local.get 1 // Load the GenericContext + local.get 2 // Load the GenericDictionaryDynamicHelperStubData parameter + i32.load OFFSETOF__GenericDictionaryDynamicHelperStubData_PortableEntryPoint__HandleArgs + i32.const 0 + i32.load g_pMethodWithSlotAndModule + local.tee 2 + local.get 2 + i32.load 0 + call_indirect __indirect_function_table, (i32, i32, i32, i32) -> (i32) + return + end_function diff --git a/src/coreclr/vm/wasm/dynamichelpers.cpp b/src/coreclr/vm/wasm/dynamichelpers.cpp new file mode 100644 index 00000000000000..6e91656990954c --- /dev/null +++ b/src/coreclr/vm/wasm/dynamichelpers.cpp @@ -0,0 +1,237 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#include "callingconvention.h" +#include "cgensys.h" +#include "readytorun.h" +#include "readytoruninfo.h" +#include "jitinterface.h" +#include "loaderallocator.hpp" + +extern "C" SIZE_T STDCALL DynamicHelperWorker(TransitionBlock * pTransitionBlock, TADDR * pCell, DWORD sectionIndex, Module * pModule, INT frameFlags); + +extern "C" SIZE_T STDCALL DelayLoad_HelperImpl(TransitionBlock* pTransitionBlock, READYTORUN_IMPORT_THUNK_PORTABLE_ENTRYPOINT* pImportThunkEntry, uint8_t *moduleBase, int32_t rvaOfModuleFixup, INT frameFlags) +{ + Module** ppModule = (Module**)(moduleBase + rvaOfModuleFixup); + return DynamicHelperWorker(pTransitionBlock, (TADDR*)(moduleBase + pImportThunkEntry->RelocOffset), (DWORD)-1, *ppModule, frameFlags); +} + +extern "C" __attribute__((naked)) SIZE_T STDCALL DelayLoad_Helper(TransitionBlock* pTransitionBlock, READYTORUN_IMPORT_THUNK_PORTABLE_ENTRYPOINT* pImportThunkEntry, uint8_t *moduleBase, int32_t rvaOfModuleFixup) +{ + asm ("local.get 0\n" /* Capture pTransitionBlock onto the stack for calling DelayLoad_HelperImpl function. This also happens to be the callersFramePointer */ + "local.get 0\n" /* Capture callersFramePointer onto the stack for setting the __stack_pointer */ + "global.get __stack_pointer\n" /* Get current value of stack global */ + "local.set 0\n" /* Overwrite local 0 with the previous __stack_pointer value so it can be restored after the call */ + "global.set __stack_pointer\n" /* Set stack global to the initial value of callersFramePointer, which is the current stack pointer for the interpreter call */ + "local.get 1\n" /* Load pImportThunkEntry argument onto the stack for calling DelayLoad_HelperImpl function*/ + "local.get 2\n" /* Load moduleBase argument onto the stack for calling DelayLoad_HelperImpl function*/ + "local.get 3\n" /* Load rvaOfModuleFixup argument onto the stack for calling DelayLoad_HelperImpl function*/ + "i32.const 0\n" /* Load frameFlags argument onto the stack for calling DelayLoad_MethodCallImpl function. For this variant we want 0 as the flag */ + "call %0\n" /* Call the actual implementation function */ + "local.get 0\n" /* Reload the saved previous __stack_pointer value for restoration into the stack global */ + "global.set __stack_pointer\n" + "return" :: "i" (DelayLoad_HelperImpl)); +} + +extern "C" void STDCALL DelayLoad_Helper_Obj() +{ + PORTABILITY_ASSERT("DelayLoad_Helper_Obj is not implemented on wasm"); +} + +extern "C" void STDCALL DelayLoad_Helper_ObjObj() +{ + PORTABILITY_ASSERT("DelayLoad_Helper_ObjObj is not implemented on wasm"); +} + +extern "C" void DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Class_TestForNull(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Class(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Class_0_0(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Class_0_1(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Class_0_2(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Class_0_3(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Method_TestForNull(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Method(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Method_0(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Method_1(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Method_2(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Method_3(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Class_UseHelper(); +extern "C" void DynamicHelper_GenericDictionaryLookup_Method_UseHelper(); + +extern "C" PCODE g_pMethodWithSlotAndModule; +extern "C" PCODE g_pClassWithSlotAndModule; + +PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup, DWORD dictionaryIndexAndSlot, Module * pModule) +{ + STANDARD_VM_CONTRACT; + + AllocMemTracker amTracker; + + PCODE helperAddress = GetDictionaryLookupHelper(pLookup->helper); + + WORD slotOffset = (WORD)(dictionaryIndexAndSlot & 0xFFFF) * sizeof(Dictionary*); + + // It's available only via the run-time helper function + PCODE helper = (PCODE)NULL; + if (pLookup->indirections == CORINFO_USEHELPER) + { + GenericHandleArgs * pArgs = (GenericHandleArgs *)amTracker.Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(GenericHandleArgs)))); + pArgs->dictionaryIndexAndSlot = dictionaryIndexAndSlot; + pArgs->signature = pLookup->signature; + pArgs->module = (CORINFO_MODULE_HANDLE)pModule; + + PCODE helperFunc; + if (helperAddress == g_pClassWithSlotAndModule) + { + helperFunc = (PCODE)DynamicHelper_GenericDictionaryLookup_Class_UseHelper; + } + else + { + _ASSERTE(helperAddress == g_pMethodWithSlotAndModule); + helperFunc = (PCODE)DynamicHelper_GenericDictionaryLookup_Method_UseHelper; + } + + // The UseHelper stubs only ever read the HandleArgs field of the stub data, but the rest of the + // structure is zero-initialized for consistency with the other stubs. + GenericDictionaryDynamicHelperStubData dictLookupData = {0}; + dictLookupData.HandleArgs = pArgs; + + GenericDictionaryDynamicHelperStubData_PortableEntryPoint *pDictLookupData = (GenericDictionaryDynamicHelperStubData_PortableEntryPoint *)amTracker.Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(GenericDictionaryDynamicHelperStubData_PortableEntryPoint)))); + pDictLookupData->stubData = dictLookupData; + pDictLookupData->HelperFunctionTableIndex = helperFunc; + + PCODE result = (PCODE)pDictLookupData; + amTracker.SuppressRelease(); + return result; + } + else + { + PCODE result; + GenericDictionaryDynamicHelperStubData dictLookupData = {0}; + dictLookupData.SizeOffset = (UINT32)pLookup->sizeOffset; + dictLookupData.SlotOffset = slotOffset; + bool needsDictLookupData = false; + + if (pLookup->indirections == 3) + { + // Class! + _ASSERTE(helperAddress == g_pClassWithSlotAndModule); + _ASSERTE(pLookup->offsets[0] == offsetof(MethodTable, m_pPerInstInfo)); + dictLookupData.SecondIndir = (UINT32)pLookup->offsets[1]; + dictLookupData.LastIndir = (UINT32)pLookup->offsets[2]; + if (pLookup->testForNull && pLookup->sizeOffset != CORINFO_NO_SIZE_CHECK) + { + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Class_SizeCheck_TestForNull; + needsDictLookupData = true; + } + else if (pLookup->testForNull) + { + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Class_TestForNull; + needsDictLookupData = true; + } + else + { + _ASSERTE(pLookup->sizeOffset == CORINFO_NO_SIZE_CHECK); + if ((dictLookupData.SecondIndir == 0) && (dictLookupData.LastIndir <= sizeof(TADDR) * 3)) + { + needsDictLookupData = false; + switch (dictLookupData.LastIndir / sizeof(TADDR)) + { + case 0: + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Class_0_0; + break; + case 1: + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Class_0_1; + break; + case 2: + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Class_0_2; + break; + case 3: + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Class_0_3; + break; + } + } + else + { + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Class; + needsDictLookupData = true; + } + } + } + else if (pLookup->indirections == 2) + { + // Method! + _ASSERTE(helperAddress == g_pMethodWithSlotAndModule); + _ASSERTE(pLookup->offsets[0] == offsetof(InstantiatedMethodDesc, m_pPerInstInfo)); + dictLookupData.LastIndir = (UINT32)pLookup->offsets[1]; + if (pLookup->testForNull && pLookup->sizeOffset != CORINFO_NO_SIZE_CHECK) + { + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Method_SizeCheck_TestForNull; + needsDictLookupData = true; + } + else if (pLookup->testForNull) + { + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Method_TestForNull; + needsDictLookupData = true; + } + else + { + _ASSERTE(pLookup->sizeOffset == CORINFO_NO_SIZE_CHECK); + if ((dictLookupData.SecondIndir == 0) && (dictLookupData.LastIndir <= sizeof(TADDR) * 3)) + { + needsDictLookupData = false; + switch (dictLookupData.LastIndir / sizeof(TADDR)) + { + case 0: + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Method_0; + break; + case 1: + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Method_1; + break; + case 2: + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Method_2; + break; + case 3: + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Method_3; + break; + } + } + else + { + helper = (PCODE)DynamicHelper_GenericDictionaryLookup_Method; + needsDictLookupData = true; + } + } + } + + if (needsDictLookupData) + { + GenericHandleArgs * pArgs = (GenericHandleArgs *)amTracker.Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(GenericHandleArgs)))); + pArgs->dictionaryIndexAndSlot = dictionaryIndexAndSlot; + pArgs->signature = pLookup->signature; + pArgs->module = (CORINFO_MODULE_HANDLE)pModule; + + dictLookupData.HandleArgs = pArgs; + + GenericDictionaryDynamicHelperStubData_PortableEntryPoint *pDictLookupData = (GenericDictionaryDynamicHelperStubData_PortableEntryPoint *)amTracker.Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(GenericDictionaryDynamicHelperStubData_PortableEntryPoint)))); + + pDictLookupData->stubData = dictLookupData; + pDictLookupData->HelperFunctionTableIndex = helper; + result = (PCODE)pDictLookupData; + } + else + { + // The simple helpers do not need any stub data, but the portable entrypoint calling convention + // requires the result to point at a location whose first word is the helper's function table index. + PCODE *pHelperEntryPoint = (PCODE *)amTracker.Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(PCODE)))); + *pHelperEntryPoint = helper; + result = (PCODE)pHelperEntryPoint; + } + + amTracker.SuppressRelease(); + return result; + } +} diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp index 09825c48bc174f..8abf0c736818f2 100644 --- a/src/coreclr/vm/wasm/helpers.cpp +++ b/src/coreclr/vm/wasm/helpers.cpp @@ -140,6 +140,40 @@ namespace 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) { @@ -158,6 +192,24 @@ namespace 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) { @@ -304,6 +356,9 @@ const StringToWasmSigThunk g_wasmPortableEntryPointThunks[] = { { "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]); @@ -369,21 +424,6 @@ extern "C" __attribute__((naked)) PCODE STDCALL DelayLoad_MethodCall(TransitionB "return" :: "i" (DelayLoad_MethodCallImpl)); } -extern "C" void STDCALL DelayLoad_Helper() -{ - PORTABILITY_ASSERT("DelayLoad_Helper is not implemented on wasm"); -} - -extern "C" void STDCALL DelayLoad_Helper_Obj() -{ - PORTABILITY_ASSERT("DelayLoad_Helper_Obj is not implemented on wasm"); -} - -extern "C" void STDCALL DelayLoad_Helper_ObjObj() -{ - PORTABILITY_ASSERT("DelayLoad_Helper_ObjObj is not implemented on wasm"); -} - extern "C" void STDCALL PInvokeImportThunk() { PORTABILITY_ASSERT("PInvokeImportThunk is not implemented on wasm");