From b32ad2550145d181241b8a5950aa18225545031b Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Fri, 6 Jun 2025 18:07:17 +0200 Subject: [PATCH 01/63] [wasm][coreclr] Get further in the runtime initialization Add corewasmhost binary to test runtime initialization Fix linking of the host binary with coreclr and interpreter Allow calling interpreter with arguments and handle return value Use fake precode stubs to pass the precode type and method desc Make alternate signal stack calls no-op on wasm Implement CallDescrWorkerInternal on wasm Fix PE image loading without RTR on wasm Do not use unsupported syscalls --- src/coreclr/CMakeLists.txt | 5 + .../Runtime/ExceptionServices/AsmOffsets.cs | 15 +- src/coreclr/clrdefinitions.cmake | 5 +- src/coreclr/clrfeatures.cmake | 8 +- .../dlls/mscoree/coreclr/CMakeLists.txt | 24 +- src/coreclr/gc/unix/gcenv.unix.cpp | 12 +- src/coreclr/hosts/CMakeLists.txt | 12 +- src/coreclr/hosts/corewasmrun/CMakeLists.txt | 28 ++ src/coreclr/hosts/corewasmrun/corewasmrun.cpp | 45 ++ src/coreclr/hosts/corewasmrun/index.html | 52 +++ src/coreclr/inc/clrnt.h | 8 +- src/coreclr/inc/loaderheap.h | 2 +- src/coreclr/interpreter/compiler.h | 7 +- src/coreclr/minipal/Unix/doublemapping.cpp | 3 + src/coreclr/pal/inc/rt/palrt.h | 6 +- src/coreclr/pal/src/exception/signal.cpp | 2 + src/coreclr/pal/src/init/pal.cpp | 2 + src/coreclr/pal/src/loader/module.cpp | 16 + src/coreclr/pal/src/map/map.cpp | 43 ++ src/coreclr/pal/src/map/virtual.cpp | 16 +- src/coreclr/pal/src/thread/process.cpp | 8 + src/coreclr/pal/src/thread/thread.cpp | 23 +- src/coreclr/utilcode/clrhost.cpp | 8 +- src/coreclr/vm/CMakeLists.txt | 8 + src/coreclr/vm/assembly.cpp | 2 +- src/coreclr/vm/callcounting.cpp | 2 + src/coreclr/vm/callhelpers.cpp | 4 + src/coreclr/vm/callhelpers.h | 4 + src/coreclr/vm/callingconvention.h | 10 + src/coreclr/vm/callstubgenerator.cpp | 4 +- src/coreclr/vm/ceemain.cpp | 6 +- src/coreclr/vm/codeversion.cpp | 2 + src/coreclr/vm/corhost.cpp | 2 +- src/coreclr/vm/gcinfodecoder.cpp | 9 + src/coreclr/vm/interpexec.cpp | 7 + src/coreclr/vm/metasig.h | 1 + src/coreclr/vm/precode.cpp | 15 + src/coreclr/vm/precode.h | 11 +- src/coreclr/vm/prestub.cpp | 19 +- src/coreclr/vm/threads.cpp | 2 + src/coreclr/vm/wasm/calldescrworkerwasm.cpp | 16 + src/coreclr/vm/wasm/cgencpu.h | 32 +- src/coreclr/vm/wasm/excepcpu.h | 5 +- src/coreclr/vm/wasm/helpers.cpp | 412 ++++++++++++++++++ src/coreclr/vm/wasm/profiler.cpp | 57 +++ src/native/libs/CMakeLists.txt | 4 + .../System.Globalization.Native/entrypoints.c | 4 + src/native/libs/build-native.proj | 3 +- src/native/minipal/random.c | 2 +- 49 files changed, 943 insertions(+), 50 deletions(-) create mode 100644 src/coreclr/hosts/corewasmrun/CMakeLists.txt create mode 100644 src/coreclr/hosts/corewasmrun/corewasmrun.cpp create mode 100644 src/coreclr/hosts/corewasmrun/index.html create mode 100644 src/coreclr/vm/wasm/calldescrworkerwasm.cpp create mode 100644 src/coreclr/vm/wasm/helpers.cpp create mode 100644 src/coreclr/vm/wasm/profiler.cpp diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index 7286f655004ca9..684a23b6f1b0b3 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -39,6 +39,11 @@ if (DEFINED CLR_CMAKE_ICU_DIR) include_directories(${CLR_CMAKE_ICU_DIR}/include) endif(DEFINED CLR_CMAKE_ICU_DIR) +if (CLR_CMAKE_TARGET_ARCH_WASM) + add_compile_options(-fwasm-exceptions) + add_link_options(-fwasm-exceptions -sEXIT_RUNTIME=1 -sUSE_OFFSET_CONVERTER=1) +endif() + #---------------------------------------------------- # Cross target Component build specific configuration #---------------------------------------------------- diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs index df3da7a876b787..5bafebd4cb140d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs @@ -51,9 +51,9 @@ class AsmOffsets public const int OFFSETOF__REGDISPLAY__SP = 0xba8; public const int OFFSETOF__REGDISPLAY__ControlPC = 0xbb0; #elif TARGET_WASM - public const int SIZEOF__REGDISPLAY = 0x3c; - public const int OFFSETOF__REGDISPLAY__SP = 0x34; - public const int OFFSETOF__REGDISPLAY__ControlPC = 0x38; + public const int SIZEOF__REGDISPLAY = 0x38; + public const int OFFSETOF__REGDISPLAY__SP = 0x30; + public const int OFFSETOF__REGDISPLAY__ControlPC = 0x34; #endif #if TARGET_64BIT @@ -73,9 +73,14 @@ class AsmOffsets public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x3d0; #else // TARGET_64BIT public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x4; +#if FEATURE_INTERPRETER + public const int SIZEOF__StackFrameIterator = 0xdc; + public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0xd8; +#else public const int SIZEOF__StackFrameIterator = 0xcc; - public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0xba; public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0xc8; +#endif + public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0xba; #endif // TARGET_64BIT #else // DEBUG @@ -167,7 +172,7 @@ class AsmOffsets #elif TARGET_LOONGARCH64 public const int SIZEOF__PAL_LIMITED_CONTEXT = 0x520; #elif TARGET_WASM - public const int SIZEOF__PAL_LIMITED_CONTEXT = 0x08; + public const int SIZEOF__PAL_LIMITED_CONTEXT = 0x04; #endif #if TARGET_AMD64 diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake index 133d30d41e615d..58d21f418f712f 100644 --- a/src/coreclr/clrdefinitions.cmake +++ b/src/coreclr/clrdefinitions.cmake @@ -35,7 +35,9 @@ if(CLR_CMAKE_TARGET_LINUX_MUSL) add_definitions(-DNO_FIXED_STACK_LIMIT) endif(CLR_CMAKE_TARGET_LINUX_MUSL) -add_definitions(-DDEBUGGING_SUPPORTED) +#if(NOT CLR_CMAKE_TARGET_ARCH_WASM) + add_definitions(-DDEBUGGING_SUPPORTED) +#endif() add_compile_definitions($<$>>:PROFILING_SUPPORTED>) add_compile_definitions($<$>:PROFILING_SUPPORTED_DATA>) @@ -270,4 +272,5 @@ function(set_target_definitions_to_custom_os_and_arch) if (TARGETDETAILS_ARCH STREQUAL "armel") target_compile_definitions(${TARGETDETAILS_TARGET} PRIVATE ARM_SOFTFP) endif() + endfunction() diff --git a/src/coreclr/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake index 93a32c3df576f5..f7ee1864daa8c4 100644 --- a/src/coreclr/clrfeatures.cmake +++ b/src/coreclr/clrfeatures.cmake @@ -31,11 +31,11 @@ if(NOT DEFINED FEATURE_DBGIPC) endif(NOT DEFINED FEATURE_DBGIPC) if(NOT DEFINED FEATURE_INTERPRETER) - if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64) + if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_WASM) set(FEATURE_INTERPRETER $,1,0>) - else(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64) + else(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_WASM) set(FEATURE_INTERPRETER 0) - endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64) + endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_WASM) endif(NOT DEFINED FEATURE_INTERPRETER) if(NOT DEFINED FEATURE_STANDALONE_GC) @@ -50,7 +50,7 @@ if(NOT DEFINED FEATURE_SINGLE_FILE_DIAGNOSTICS) set(FEATURE_SINGLE_FILE_DIAGNOSTICS 1) endif(NOT DEFINED FEATURE_SINGLE_FILE_DIAGNOSTICS) -if (CLR_CMAKE_TARGET_WIN32 OR CLR_CMAKE_TARGET_UNIX) +if ((CLR_CMAKE_TARGET_WIN32 OR CLR_CMAKE_TARGET_UNIX) AND NOT CLR_CMAKE_TARGET_ARCH_WASM) set(FEATURE_COMWRAPPERS 1) endif() diff --git a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt index 60f6a310451d90..5b5e471718f101 100644 --- a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt +++ b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt @@ -56,8 +56,14 @@ endif (CLR_CMAKE_HOST_WIN32) add_definitions(-DFX_VER_INTERNALNAME_STR=CoreCLR.dll) +if (CLR_CMAKE_TARGET_ARCH_WASM) + set(LINK_TYPE STATIC) +else() + set(LINK_TYPE SHARED) +endif() + add_library_clr(coreclr - SHARED + ${LINK_TYPE} ${CLR_SOURCES} ) @@ -70,9 +76,15 @@ add_dependencies(coreclr coreclr_exports) set_property(TARGET coreclr APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION}) set_property(TARGET coreclr APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE}) -if (CLR_CMAKE_HOST_UNIX) +if (CLR_CMAKE_HOST_UNIX AND NOT CLR_CMAKE_TARGET_ARCH_WASM) set(LIB_UNWINDER unwinder_wks) -endif (CLR_CMAKE_HOST_UNIX) +endif (CLR_CMAKE_HOST_UNIX AND NOT CLR_CMAKE_TARGET_ARCH_WASM) + +if (NOT CLR_CMAKE_TARGET_ARCH_WASM) + set(LIB_CORDBEE cordbee_wks) + set(LIB_INTEROP interop) + set(LIB_CDAC_CONTRACT_DESCRIPTOR cdac_contract_descriptor) +endif (NOT CLR_CMAKE_TARGET_ARCH_WASM) # IMPORTANT! Please do not rearrange the order of the libraries. The linker on Linux is # order dependent and changing the order can result in undefined symbols in the shared @@ -80,7 +92,7 @@ endif (CLR_CMAKE_HOST_UNIX) set(CORECLR_LIBRARIES utilcode ${START_LIBRARY_GROUP} # Start group of libraries that have circular references - cordbee_wks + ${LIB_CORDBEE} debug-pal ${LIB_UNWINDER} v3binder @@ -95,10 +107,10 @@ set(CORECLR_LIBRARIES utilcode v3binder System.Globalization.Native-Static - interop + ${LIB_INTEROP} coreclrminipal gc_pal - cdac_contract_descriptor + ${LIB_CDAC_CONTRACT_DESCRIPTOR} ) if(CLR_CMAKE_TARGET_ARCH_AMD64) diff --git a/src/coreclr/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp index 720828b2565f85..cb9b609721dbb1 100644 --- a/src/coreclr/gc/unix/gcenv.unix.cpp +++ b/src/coreclr/gc/unix/gcenv.unix.cpp @@ -244,6 +244,7 @@ bool GCToOSInterface::Initialize() // Verify that the s_helperPage is really aligned to the g_SystemInfo.dwPageSize assert((((size_t)g_helperPage) & (OS_PAGE_SIZE - 1)) == 0); +#ifndef TARGET_BROWSER // Locking the page ensures that it stays in memory during the two mprotect // calls in the FlushProcessWriteBuffers below. If the page was unmapped between // those calls, they would not have the expected effect of generating IPI. @@ -253,6 +254,9 @@ bool GCToOSInterface::Initialize() { return false; } +#else + int status; +#endif // !TARGET_BROWSER status = pthread_mutex_init(&g_flushProcessWriteBuffersMutex, NULL); if (status != 0) @@ -576,7 +580,7 @@ static void* VirtualReserveInner(size_t size, size_t alignment, uint32_t flags, } pRetVal = pAlignedRetVal; -#ifdef MADV_DONTDUMP +#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER) // Do not include reserved uncommitted memory in coredump. if (!committing) { @@ -624,9 +628,13 @@ bool GCToOSInterface::VirtualRelease(void* address, size_t size) // true if it has succeeded, false if it has failed static bool VirtualCommitInner(void* address, size_t size, uint16_t node, bool newMemory) { +#ifndef TARGET_BROWSER bool success = mprotect(address, size, PROT_WRITE | PROT_READ) == 0; +#else + bool success = true; +#endif // !TARGET_BROWSER -#ifdef MADV_DODUMP +#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER) if (success && !newMemory) { // Include committed memory in coredump. New memory is included by default. diff --git a/src/coreclr/hosts/CMakeLists.txt b/src/coreclr/hosts/CMakeLists.txt index dba881f7c6a3a7..4be3bbe8b95805 100644 --- a/src/coreclr/hosts/CMakeLists.txt +++ b/src/coreclr/hosts/CMakeLists.txt @@ -1,7 +1,11 @@ include_directories(inc) -if(CLR_CMAKE_HOST_WIN32) - add_subdirectory(coreshim) -endif(CLR_CMAKE_HOST_WIN32) +if (CLR_CMAKE_TARGET_ARCH_WASM) + add_subdirectory(corewasmrun) +else() + if(CLR_CMAKE_HOST_WIN32) + add_subdirectory(coreshim) + endif(CLR_CMAKE_HOST_WIN32) -add_subdirectory(corerun) + add_subdirectory(corerun) +endif() diff --git a/src/coreclr/hosts/corewasmrun/CMakeLists.txt b/src/coreclr/hosts/corewasmrun/CMakeLists.txt new file mode 100644 index 00000000000000..57eb957debfac3 --- /dev/null +++ b/src/coreclr/hosts/corewasmrun/CMakeLists.txt @@ -0,0 +1,28 @@ +project(corewasmrun) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +if (DEFINED CLR_CMAKE_ICU_DIR) + link_directories(${CLR_CMAKE_ICU_DIR}/lib) +endif(DEFINED CLR_CMAKE_ICU_DIR) + +add_executable_clr(corewasmrun + corewasmrun.cpp +) + +set(_WASM_PRELOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/../../../../../bin/coreclr/browser.wasm.Debug/IL") +if (EXISTS "${_WASM_PRELOAD_DIR}") + set(_WASM_PRELOAD_FILE --preload-file ${_WASM_PRELOAD_DIR}@/) +endif (EXISTS "${_WASM_PRELOAD_DIR}") + +target_compile_options(corewasmrun PRIVATE -fwasm-exceptions) +target_link_options(corewasmrun PRIVATE -fwasm-exceptions -sEXIT_RUNTIME=1 -sUSE_OFFSET_CONVERTER=1 -sINITIAL_MEMORY=134217728 -sFORCE_FILESYSTEM=1 ${_WASM_PRELOAD_FILE} -Wl,-error-limit=0) + +target_link_libraries(corewasmrun PRIVATE coreclr) +target_link_libraries(corewasmrun PRIVATE clrinterpreter) + +target_link_libraries(corewasmrun PRIVATE icuuc) +target_link_libraries(corewasmrun PRIVATE icui18n) +target_link_libraries(corewasmrun PRIVATE icudata) + +install_clr(TARGETS corewasmrun DESTINATIONS . COMPONENT hosts) diff --git a/src/coreclr/hosts/corewasmrun/corewasmrun.cpp b/src/coreclr/hosts/corewasmrun/corewasmrun.cpp new file mode 100644 index 00000000000000..dda735b72b521e --- /dev/null +++ b/src/coreclr/hosts/corewasmrun/corewasmrun.cpp @@ -0,0 +1,45 @@ +#include +#include + +static void log_error_info(const char* line) +{ + std::fprintf(stderr, "log error: %s\n", line); +} + +// The current CoreCLR instance details. +static void* CurrentClrInstance; +static unsigned int CurrentAppDomainId; + +static int run() +{ + const char* exe_path = ""; + const char* app_domain_name = "corewasmrun"; + const char* entry_assembly = "ManagedAssembly.dll"; + + coreclr_set_error_writer(log_error_info); + + printf("call coreclr_initialize\n"); + int retval = coreclr_initialize(exe_path, app_domain_name, 0, nullptr, nullptr, &CurrentClrInstance, &CurrentAppDomainId); + + if (retval < 0) + { + std::fprintf(stderr, "coreclr_initialize failed - Error: 0x%08x\n", retval); + return -1; + } + else + { + printf("coreclr_initialize succeeded - retval: 0x%08x\n", retval); + } + + // coreclr_execute_assembly(); + // coreclr_shutdown(); + + return retval; +} + +int main() +{ + int retval = run(); + + return retval; +} diff --git a/src/coreclr/hosts/corewasmrun/index.html b/src/coreclr/hosts/corewasmrun/index.html new file mode 100644 index 00000000000000..7fecf3afe85302 --- /dev/null +++ b/src/coreclr/hosts/corewasmrun/index.html @@ -0,0 +1,52 @@ + + + + + corewasmrun + + +

corewasmrun

+

+    
+    
+
diff --git a/src/coreclr/inc/clrnt.h b/src/coreclr/inc/clrnt.h
index 8040117a28b8f6..30cb7eacdff957 100644
--- a/src/coreclr/inc/clrnt.h
+++ b/src/coreclr/inc/clrnt.h
@@ -510,7 +510,7 @@ RtlVirtualUnwind(
 #define UNW_FLAG_EHANDLER               0x1             /* filter handler */
 #define UNW_FLAG_UHANDLER               0x2             /* unwind handler */
 
-PEXCEPTION_ROUTINE
+PEXCEPTION_ROUTINE inline
 RtlVirtualUnwind (
     _In_ DWORD HandlerType,
     _In_ DWORD ImageBase,
@@ -520,7 +520,11 @@ RtlVirtualUnwind (
     _Out_ PVOID *HandlerData,
     _Out_ PDWORD EstablisherFrame,
     __inout_opt PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers
-    );
+    )
+{
+    _ASSERTE("The function RtlVirtualUnwind is not implemented on wasm");
+    return nullptr;
+}
 
 FORCEINLINE
 ULONG
diff --git a/src/coreclr/inc/loaderheap.h b/src/coreclr/inc/loaderheap.h
index d3040e0b4aa448..49e9e4727bcba9 100644
--- a/src/coreclr/inc/loaderheap.h
+++ b/src/coreclr/inc/loaderheap.h
@@ -158,7 +158,7 @@ struct LoaderHeapEvent;
 // When an interleaved LoaderHeap is constructed, this is the interleaving size
 inline UINT32 GetStubCodePageSize()
 {
-#if defined(TARGET_ARM64) && defined(TARGET_UNIX)
+#if (defined(TARGET_ARM64) && defined(TARGET_UNIX)) || defined(TARGET_WASM)
     return max(16*1024u, GetOsPageSize());
 #elif defined(TARGET_ARM)
     return 4096; // ARM is special as the 32bit instruction set does not easily permit a 16KB offset
diff --git a/src/coreclr/interpreter/compiler.h b/src/coreclr/interpreter/compiler.h
index fa48efcecef67b..23f628dc8e4d81 100644
--- a/src/coreclr/interpreter/compiler.h
+++ b/src/coreclr/interpreter/compiler.h
@@ -331,8 +331,13 @@ class InterpCompiler
 #ifdef DEBUG
     CORINFO_CLASS_HANDLE m_classHnd;
     TArray m_methodName;
+#ifdef __wasm__
+    // enable verbose output on wasm temporarily
+    bool m_verbose = true;
+#else
     bool m_verbose = false;
-#endif
+#endif // __wasm__
+#endif // DEBUG
 
     static int32_t InterpGetMovForType(InterpType interpType, bool signExtend);
 
diff --git a/src/coreclr/minipal/Unix/doublemapping.cpp b/src/coreclr/minipal/Unix/doublemapping.cpp
index 4a2516bea58484..61359029418ce2 100644
--- a/src/coreclr/minipal/Unix/doublemapping.cpp
+++ b/src/coreclr/minipal/Unix/doublemapping.cpp
@@ -47,6 +47,9 @@ static const off_t MaxDoubleMappedSize = UINT_MAX;
 
 bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecutableCodeSize)
 {
+#ifdef __wasm__
+    return false;
+#endif
     if (minipal_detect_rosetta())
     {
         // Rosetta doesn't support double mapping correctly
diff --git a/src/coreclr/pal/inc/rt/palrt.h b/src/coreclr/pal/inc/rt/palrt.h
index 215290ce093439..67697a63e656e5 100644
--- a/src/coreclr/pal/inc/rt/palrt.h
+++ b/src/coreclr/pal/inc/rt/palrt.h
@@ -1008,7 +1008,11 @@ typedef struct _DISPATCHER_CONTEXT {
 typedef struct _DISPATCHER_CONTEXT {
     // WASM does not build the VM or JIT at this point,
     // so we only provide a dummy definition.
-    DWORD Reserved;
+    UINT32 ControlPc;
+    UINT32 ImageBase;
+    PRUNTIME_FUNCTION FunctionEntry;
+    UINT32 EstablisherFrame;
+    PCONTEXT ContextRecord;
 } DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
 
 #else
diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp
index 444bad7e5c072c..b0501bc993f5cb 100644
--- a/src/coreclr/pal/src/exception/signal.cpp
+++ b/src/coreclr/pal/src/exception/signal.cpp
@@ -219,6 +219,7 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
             return FALSE;
         }
 
+#ifndef TARGET_BROWSER
         // create a guard page for the alternate stack
         int st = mprotect((void*)g_stackOverflowHandlerStack, GetVirtualPageSize(), PROT_NONE);
         if (st != 0)
@@ -226,6 +227,7 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
             munmap((void*)g_stackOverflowHandlerStack, stackOverflowStackSize);
             return FALSE;
         }
+#endif // TARGET_BROWSER
 
         g_stackOverflowHandlerStack = (void*)((size_t)g_stackOverflowHandlerStack + stackOverflowStackSize);
 #endif // HAVE_MACH_EXCEPTIONS
diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp
index 6811690132daed..aa0e1a5592ba4b 100644
--- a/src/coreclr/pal/src/init/pal.cpp
+++ b/src/coreclr/pal/src/init/pal.cpp
@@ -719,6 +719,7 @@ PAL_InitializeCoreCLR(const char *szExePath, BOOL runningInExe)
         return ERROR_SUCCESS;
     }
 
+#ifndef __wasm__ // we don't use shared libraries on wasm
     // Now that the PAL is initialized it's safe to call the initialization methods for the code that used to
     // be dynamically loaded libraries but is now statically linked into CoreCLR just like the PAL, i.e. the
     // PAL RT and mscorwks.
@@ -726,6 +727,7 @@ PAL_InitializeCoreCLR(const char *szExePath, BOOL runningInExe)
     {
         return ERROR_DLL_INIT_FAILED;
     }
+#endif // !__wasm__
 
     if (!PROCAbortInitialize())
     {
diff --git a/src/coreclr/pal/src/loader/module.cpp b/src/coreclr/pal/src/loader/module.cpp
index d7cff970a0b02e..4c16bb98164b00 100644
--- a/src/coreclr/pal/src/loader/module.cpp
+++ b/src/coreclr/pal/src/loader/module.cpp
@@ -926,6 +926,22 @@ PAL_CopyModuleData(PVOID moduleBase, PVOID destinationBufferStart, PVOID destina
     }
     return param.result;
 }
+#elif defined(__wasm__)
+// TODO: get rid of whole module loading on wasm
+static int CopyModuleDataCallback(struct dl_phdr_info *info, size_t size, void *data)
+{
+    _ASSERTE("CopyModuleDataCallback not implemented for wasm");
+    return 0;
+}
+
+PALIMPORT
+int
+PALAPI
+PAL_CopyModuleData(PVOID moduleBase, PVOID destinationBufferStart, PVOID destinationBufferEnd)
+{
+    _ASSERTE("PAL_CopyModuleData not implemented for wasm");
+    return 0;
+}
 #else
 static int CopyModuleDataCallback(struct dl_phdr_info *info, size_t size, void *data)
 {
diff --git a/src/coreclr/pal/src/map/map.cpp b/src/coreclr/pal/src/map/map.cpp
index 8900ccd1058c01..6f33f4ad4dc399 100644
--- a/src/coreclr/pal/src/map/map.cpp
+++ b/src/coreclr/pal/src/map/map.cpp
@@ -1928,7 +1928,9 @@ MAPmmapAndRecord(
 
     // Ensure address and offset arguments mmap() are page-aligned.
     _ASSERTE(OffsetWithinPage(offset - adjust) == 0);
+#ifndef __wasm__
     _ASSERTE(OffsetWithinPage((off_t)pvBaseAddress) == 0);
+#endif
 
 #ifdef __APPLE__
     if ((prot & PROT_EXEC) != 0 && IsRunningOnMojaveHardenedRuntime())
@@ -1980,6 +1982,30 @@ MAPmmapAndRecord(
 
     }
     else
+#elif defined(__wasm__)
+    // WebAssembly doesn't support mmap() with location hints
+    if (pvBaseAddress != nullptr)
+    {
+        LPVOID pvMappedFile = mmap(NULL, len + adjust, prot, flags, fd, offset - adjust);
+        if (MAP_FAILED == pvMappedFile)
+        {
+            ERROR_(LOADER)("mmap failed with code %d: %s.\n", errno, strerror(errno));
+            palError = FILEGetLastErrorFromErrno();
+            return palError;
+        }
+        else
+        {
+            memcpy(pvBaseAddress, pvMappedFile, len + adjust);
+            if (-1 == munmap(pvMappedFile, len + adjust))
+            {
+                ERROR_(LOADER)("Unable to unmap the file. Expect trouble.\n");
+                if (NO_ERROR == palError)
+                    palError = FILEGetLastErrorFromErrno();
+                return palError;
+            }
+        }
+    }
+    else
 #endif
     {
         pvBaseAddress = mmap(pvBaseAddress, len + adjust, prot, flags, fd, offset - adjust);
@@ -2238,6 +2264,13 @@ void * MAPMapPEFile(HANDLE hFile, off_t offset)
     size_t headerSize;
     headerSize = GetVirtualPageSize(); // if there are lots of sections, this could be wrong
 
+#ifdef __wasm__
+    if (headerSize > ntHeader.OptionalHeader.SectionAlignment)
+    {
+        headerSize = ntHeader.OptionalHeader.SectionAlignment;
+    }
+#endif // __wasm__
+
     if (forceOveralign)
     {
         loadedBase = ALIGN_UP(loadedBase, ntHeader.OptionalHeader.SectionAlignment);
@@ -2297,7 +2330,11 @@ void * MAPMapPEFile(HANDLE hFile, off_t offset)
 
     void* prevSectionEndAligned;
     // the first "section" for our purposes is the header
+#ifndef __wasm__
     prevSectionEndAligned = ALIGN_UP((char*)loadedHeader + headerSize, GetVirtualPageSize());
+#else
+    prevSectionEndAligned = ALIGN_UP((char*)loadedHeader + headerSize, ntHeader.OptionalHeader.SectionAlignment);
+#endif // __wasm__
 
     for (unsigned i = 0; i < numSections; ++i)
     {
@@ -2329,12 +2366,14 @@ void * MAPMapPEFile(HANDLE hFile, off_t offset)
             goto doneReleaseMappingCriticalSection;
         }
 
+#ifndef __wasm__
         if (OffsetWithinPage((off_t)sectionBase) != OffsetWithinPage(offset + currentHeader.PointerToRawData))
         {
             ERROR_(LOADER)("can't map section if data and VA hint have different page alignment %d\n", i);
             palError = ERROR_INVALID_PARAMETER;
             goto doneReleaseMappingCriticalSection;
         }
+#endif // !__wasm__
 
         // Is there space between the previous section and this one? If so, add a PROT_NONE mapping to cover it.
         if (prevSectionEndAligned < sectionBaseAligned)
@@ -2390,7 +2429,11 @@ void * MAPMapPEFile(HANDLE hFile, off_t offset)
         }
 #endif // _DEBUG
 
+#ifndef __wasm__
         prevSectionEndAligned = ALIGN_UP((char*)sectionBase + currentHeader.SizeOfRawData, GetVirtualPageSize()); // round up to page boundary
+#else
+        prevSectionEndAligned = ALIGN_UP((char*)sectionBase + currentHeader.SizeOfRawData, ntHeader.OptionalHeader.SectionAlignment); // round up to page boundary
+#endif // __wasm__
     }
 
     // Is there space after the last section and before the end of the mapped image? If so, add a PROT_NONE mapping to cover it.
diff --git a/src/coreclr/pal/src/map/virtual.cpp b/src/coreclr/pal/src/map/virtual.cpp
index dcf3fd5c51c852..7936c968c1664e 100644
--- a/src/coreclr/pal/src/map/virtual.cpp
+++ b/src/coreclr/pal/src/map/virtual.cpp
@@ -641,7 +641,7 @@ static LPVOID ReserveVirtualMemory(
     }
 #endif  // MMAP_ANON_IGNORES_PROTECTION
 
-#ifdef MADV_DONTDUMP
+#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER)
     // Do not include reserved uncommitted memory in coredump.
     if (!(fAllocationType & MEM_COMMIT))
     {
@@ -730,14 +730,16 @@ VIRTUALCommitMemory(
 
     nProtect = W32toUnixAccessControl(flProtect);
 
+#ifndef TARGET_BROWSER
     // Commit the pages
     if (mprotect((void *) StartBoundary, MemSize, nProtect) != 0)
     {
         ERROR("mprotect() failed! Error(%d)=%s\n", errno, strerror(errno));
         goto error;
     }
+#endif
 
-#ifdef MADV_DODUMP
+#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER)
     // Include committed memory in coredump. Any newly allocated memory included by default.
     if (!IsNewMemory)
     {
@@ -748,7 +750,9 @@ VIRTUALCommitMemory(
     pRetVal = (void *) StartBoundary;
     goto done;
 
+#ifndef TARGET_BROWSER
 error:
+#endif
     if ( flAllocationType & MEM_RESERVE || IsLocallyReserved )
     {
         munmap( pRetVal, MemSize );
@@ -1073,7 +1077,7 @@ VirtualFree(
             }
 #endif  // MMAP_ANON_IGNORES_PROTECTION
 
-#ifdef MADV_DONTDUMP
+#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER)
             // Do not include freed memory in coredump.
             madvise((LPVOID) StartBoundary, MemSize, MADV_DONTDUMP);
 #endif
@@ -1207,9 +1211,11 @@ VirtualProtect(
     }
 
     pEntry = VIRTUALFindRegionInformation( StartBoundary );
+#ifndef TARGET_BROWSER
     if ( 0 == mprotect( (LPVOID)StartBoundary, MemSize,
                    W32toUnixAccessControl( flNewProtect ) ) )
     {
+#endif // !TARGET_BROWSER
         /* Reset the access protection. */
         TRACE( "Number of pages to change %d, starting page %d \n",
                NumberOfPagesToChange, OffSet );
@@ -1220,13 +1226,14 @@ VirtualProtect(
          */
         *lpflOldProtect = PAGE_EXECUTE_READWRITE;
 
-#ifdef MADV_DONTDUMP
+#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER)
         // Include or exclude memory from coredump based on the protection.
         int advise = flNewProtect == PAGE_NOACCESS ? MADV_DONTDUMP : MADV_DODUMP;
         madvise((LPVOID)StartBoundary, MemSize, advise);
 #endif
 
         bRetVal = TRUE;
+#ifndef TARGET_BROWSER
     }
     else
     {
@@ -1240,6 +1247,7 @@ VirtualProtect(
             SetLastError( ERROR_INVALID_ACCESS );
         }
     }
+#endif // !TARGET_BROWSER
 ExitVirtualProtect:
     minipal_mutex_leave(&virtual_critsec);
 
diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp
index c56cc0637dcd2f..bc7e08acd502be 100644
--- a/src/coreclr/pal/src/thread/process.cpp
+++ b/src/coreclr/pal/src/thread/process.cpp
@@ -2610,6 +2610,7 @@ InitializeFlushProcessWriteBuffers()
     // Verify that the s_helperPage is really aligned to the GetVirtualPageSize()
     _ASSERTE((((SIZE_T)s_helperPage) & (GetVirtualPageSize() - 1)) == 0);
 
+#ifndef TARGET_BROWSER
     // Locking the page ensures that it stays in memory during the two mprotect
     // calls in the FlushProcessWriteBuffers below. If the page was unmapped between
     // those calls, they would not have the expected effect of generating IPI.
@@ -2619,6 +2620,9 @@ InitializeFlushProcessWriteBuffers()
     {
         return FALSE;
     }
+#else
+    int status;
+#endif // !TARGET_BROWSER
 
     status = pthread_mutex_init(&flushProcessWriteBuffersMutex, NULL);
     if (status != 0)
@@ -2664,18 +2668,22 @@ FlushProcessWriteBuffers()
         int status = pthread_mutex_lock(&flushProcessWriteBuffersMutex);
         FATAL_ASSERT(status == 0, "Failed to lock the flushProcessWriteBuffersMutex lock");
 
+#ifndef TARGET_BROWSER
         // Changing a helper memory page protection from read / write to no access
         // causes the OS to issue IPI to flush TLBs on all processors. This also
         // results in flushing the processor buffers.
         status = mprotect(s_helperPage, GetVirtualPageSize(), PROT_READ | PROT_WRITE);
         FATAL_ASSERT(status == 0, "Failed to change helper page protection to read / write");
+#endif // !TARGET_BROWSER
 
         // Ensure that the page is dirty before we change the protection so that
         // we prevent the OS from skipping the global TLB flush.
         InterlockedIncrement(s_helperPage);
 
+#ifndef TARGET_BROWSER
         status = mprotect(s_helperPage, GetVirtualPageSize(), PROT_NONE);
         FATAL_ASSERT(status == 0, "Failed to change helper page protection to no access");
+#endif // !TARGET_BROWSER
 
         status = pthread_mutex_unlock(&flushProcessWriteBuffersMutex);
         FATAL_ASSERT(status == 0, "Failed to unlock the flushProcessWriteBuffersMutex lock");
diff --git a/src/coreclr/pal/src/thread/thread.cpp b/src/coreclr/pal/src/thread/thread.cpp
index fe48f04dfe639b..9b53b9dcdeeafd 100644
--- a/src/coreclr/pal/src/thread/thread.cpp
+++ b/src/coreclr/pal/src/thread/thread.cpp
@@ -42,6 +42,10 @@ SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do
 #include 
 #endif
 
+#if defined(TARGET_BROWSER)
+#include 
+#endif
+
 #include 
 #include 
 #if HAVE_PTHREAD_NP_H
@@ -2281,6 +2285,10 @@ Return :
 BOOL
 CPalThread::EnsureSignalAlternateStack()
 {
+#ifdef __wasm__
+    // WebAssembly does not support alternate signal stacks.
+    return TRUE;
+#else // !__wasm__
     int st = 0;
 
     if (g_registered_signal_handlers)
@@ -2334,6 +2342,7 @@ CPalThread::EnsureSignalAlternateStack()
     }
 
     return (st == 0);
+#endif // !__wasm__
 }
 
 /*++
@@ -2351,6 +2360,7 @@ Return :
 void
 CPalThread::FreeSignalAlternateStack()
 {
+#ifndef __wasm__ // WebAssembly does not support alternate signal stacks.
     void *altstack = m_alternateStack;
     m_alternateStack = nullptr;
 
@@ -2374,6 +2384,7 @@ CPalThread::FreeSignalAlternateStack()
             }
         }
     }
+#endif // !__wasm__
 }
 
 #endif // !HAVE_MACH_EXCEPTIONS
@@ -2444,6 +2455,7 @@ CPalThread::GetStackBase()
     status = pthread_attr_init(&attr);
     _ASSERT_MSG(status == 0, "pthread_attr_init call failed");
 
+#ifndef TARGET_BROWSER
 #if HAVE_PTHREAD_ATTR_GET_NP
     status = pthread_attr_get_np(thread, &attr);
 #elif HAVE_PTHREAD_GETATTR_NP
@@ -2460,7 +2472,10 @@ CPalThread::GetStackBase()
     _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed");
 
     stackBase = (void*)((size_t)stackAddr + stackSize);
-#endif
+#else // TARGET_BROWSER
+    stackBase = (void*)emscripten_stack_get_base();
+#endif // TARGET_BROWSER
+#endif // !TARGET_APPLE
 
     return stackBase;
 }
@@ -2484,6 +2499,7 @@ CPalThread::GetStackLimit()
     status = pthread_attr_init(&attr);
     _ASSERT_MSG(status == 0, "pthread_attr_init call failed");
 
+#ifndef TARGET_BROWSER
 #if HAVE_PTHREAD_ATTR_GET_NP
     status = pthread_attr_get_np(thread, &attr);
 #elif HAVE_PTHREAD_GETATTR_NP
@@ -2498,7 +2514,10 @@ CPalThread::GetStackLimit()
 
     status = pthread_attr_destroy(&attr);
     _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed");
-#endif
+#else // TARGET_BROWSER
+    stackLimit = (void*)emscripten_stack_get_end();
+#endif // TARGET_BROWSER
+#endif // !TARGET_APPLE
 
     return stackLimit;
 }
diff --git a/src/coreclr/utilcode/clrhost.cpp b/src/coreclr/utilcode/clrhost.cpp
index a57b115fbfc780..41e8b2dc348b2a 100644
--- a/src/coreclr/utilcode/clrhost.cpp
+++ b/src/coreclr/utilcode/clrhost.cpp
@@ -62,7 +62,13 @@ DWORD GetClrModulePathName(SString& buffer)
 #ifdef HOST_WINDOWS
     return WszGetModuleFileName((HINSTANCE)GetClrModuleBase(), buffer);
 #else
-    return WszGetModuleFileName(PAL_GetPalHostModule(), buffer);
+#ifndef __wasm__
+    HMODULE hModule = PAL_GetPalHostModule();
+#else
+    // on wasm the PAL library is statically linked
+    HMODULE hModule = nullptr;
+#endif
+    return WszGetModuleFileName(hModule, buffer);
 #endif
 }
 
diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt
index b9a272765a8090..f5a29c0634293a 100644
--- a/src/coreclr/vm/CMakeLists.txt
+++ b/src/coreclr/vm/CMakeLists.txt
@@ -918,6 +918,14 @@ elseif(CLR_CMAKE_TARGET_ARCH_RISCV64)
         ${ARCH_SOURCES_DIR}/singlestepper.cpp
         gcinfodecoder.cpp
     )
+elseif(CLR_CMAKE_TARGET_ARCH_WASM)
+    set(VM_SOURCES_WKS_ARCH
+        ${ARCH_SOURCES_DIR}/calldescrworkerwasm.cpp
+        ${ARCH_SOURCES_DIR}/profiler.cpp
+        ${ARCH_SOURCES_DIR}/helpers.cpp
+        exceptionhandling.cpp
+        gcinfodecoder.cpp
+    )
 endif()
 
 set(VM_SOURCES_DAC_ARCH
diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp
index 091a061ba5a863..e1605c6acff3b4 100644
--- a/src/coreclr/vm/assembly.cpp
+++ b/src/coreclr/vm/assembly.cpp
@@ -2392,7 +2392,7 @@ DebuggerAssemblyControlFlags Assembly::ComputeDebuggingConfig()
     IfFailThrow(GetDebuggingCustomAttributes(&dacfFlags));
     return (DebuggerAssemblyControlFlags)dacfFlags;
 #else // !DEBUGGING_SUPPORTED
-    return 0;
+    return (DebuggerAssemblyControlFlags)0;
 #endif // DEBUGGING_SUPPORTED
 }
 
diff --git a/src/coreclr/vm/callcounting.cpp b/src/coreclr/vm/callcounting.cpp
index f5168fc0f799b1..7d9e533b9465d1 100644
--- a/src/coreclr/vm/callcounting.cpp
+++ b/src/coreclr/vm/callcounting.cpp
@@ -324,6 +324,8 @@ void CallCountingStub::StaticInitialize()
         // This should fail if the template is used on a platform which doesn't support the supported page size for templates
         ThrowHR(COR_E_EXECUTIONENGINE);
     }
+#elif defined(TARGET_WASM)
+    // CallCountingStub is not implemented on WASM
 #else
     _ASSERTE((SIZE_T)((BYTE*)CallCountingStubCode_End - (BYTE*)CallCountingStubCode) <= CallCountingStub::CodeSize);
 #endif
diff --git a/src/coreclr/vm/callhelpers.cpp b/src/coreclr/vm/callhelpers.cpp
index 24389bc4e75420..95884af8c6ea3e 100644
--- a/src/coreclr/vm/callhelpers.cpp
+++ b/src/coreclr/vm/callhelpers.cpp
@@ -532,6 +532,10 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *
 #endif
     callDescrData.fpReturnSize = fpReturnSize;
     callDescrData.pTarget = m_pCallTarget;
+#ifdef TARGET_WASM
+    callDescrData.pMD = m_pMD;
+    callDescrData.nArgsSize = m_argIt.GetArgSize();
+#endif
 
     CallDescrWorkerWithHandler(&callDescrData);
 
diff --git a/src/coreclr/vm/callhelpers.h b/src/coreclr/vm/callhelpers.h
index 767ce238ac14fb..6454b580f96ccc 100644
--- a/src/coreclr/vm/callhelpers.h
+++ b/src/coreclr/vm/callhelpers.h
@@ -28,6 +28,10 @@ struct CallDescrData
 #endif
     UINT32                      fpReturnSize;
     PCODE                       pTarget;
+#ifdef TARGET_WASM
+    MethodDesc*                 pMD;
+    size_t                      nArgsSize;
+#endif
 
 #ifdef CALLDESCR_RETBUFFARGREG
     // Pointer to return buffer arg location
diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h
index 98e6eee147fcd6..1de315880bcca6 100644
--- a/src/coreclr/vm/callingconvention.h
+++ b/src/coreclr/vm/callingconvention.h
@@ -1223,6 +1223,9 @@ int ArgIteratorTemplate::GetNextOffset()
         m_idxGenReg = numRegistersUsed;
         m_ofsStack = 0;
         m_idxFPReg = 0;
+#elif defined(TARGET_WASM)
+        // we put everything on the stack, we don't have registers
+        m_ofsStack = 0;
 #else
         PORTABILITY_ASSERT("ArgIteratorTemplate::GetNextOffset");
 #endif
@@ -1794,6 +1797,13 @@ int ArgIteratorTemplate::GetNextOffset()
     int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
     m_ofsStack += ALIGN_UP(cbArg, TARGET_POINTER_SIZE);
 
+    return argOfs;
+#elif defined(TARGET_WASM)
+    int cbArg = ALIGN_UP(StackElemSize(argSize), TARGET_POINTER_SIZE);
+    int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
+    
+    m_ofsStack += cbArg;
+    
     return argOfs;
 #else
     PORTABILITY_ASSERT("ArgIteratorTemplate::GetNextOffset");
diff --git a/src/coreclr/vm/callstubgenerator.cpp b/src/coreclr/vm/callstubgenerator.cpp
index 30a70af7ace201..d6200bdb333524 100644
--- a/src/coreclr/vm/callstubgenerator.cpp
+++ b/src/coreclr/vm/callstubgenerator.cpp
@@ -1,7 +1,7 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-#ifdef FEATURE_INTERPRETER
+#if defined(FEATURE_INTERPRETER) && defined(FEATURE_JIT)
 
 #include "callstubgenerator.h"
 
@@ -997,4 +997,4 @@ void CallStubGenerator::ProcessArgument(ArgIterator& argIt, ArgLocDesc& argLocDe
 #endif // UNIX_AMD64_ABI
 }
 
-#endif // FEATURE_INTERPRETER
+#endif // FEATURE_INTERPRETER && FEATURE_JIT
diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp
index 9f6cc475e4f1e8..cf711a60dec941 100644
--- a/src/coreclr/vm/ceemain.cpp
+++ b/src/coreclr/vm/ceemain.cpp
@@ -835,7 +835,9 @@ void EEStartupHelper()
         // Initialize the debugging services. This must be done before any
         // EE thread objects are created, and before any classes or
         // modules are loaded.
+#ifndef __wasm__
         InitializeDebugger(); // throws on error
+#endif
 #endif // DEBUGGING_SUPPORTED
 
 #ifdef PROFILING_SUPPORTED
@@ -913,7 +915,9 @@ void EEStartupHelper()
         }
 #endif
 
-#ifndef TARGET_WINDOWS
+        // on wasm we need to run finalizers on main thread as we are single threaded
+        // active issue: https://github.com/dotnet/runtime/issues/114096
+#if !defined(TARGET_WINDOWS) && !defined(__wasm__)
         // This isn't done as part of InitializeGarbageCollector() above because
         // debugger must be initialized before creating EE thread objects
         FinalizerThread::FinalizerThreadCreate();
diff --git a/src/coreclr/vm/codeversion.cpp b/src/coreclr/vm/codeversion.cpp
index 9b95ef12f9de83..1704eeb1362418 100644
--- a/src/coreclr/vm/codeversion.cpp
+++ b/src/coreclr/vm/codeversion.cpp
@@ -12,9 +12,11 @@
 #ifdef FEATURE_CODE_VERSIONING
 #include "threadsuspend.h"
 #include "methoditer.h"
+#ifdef DDEBUGGING_SUPPORTED
 #include "../debug/ee/debugger.h"
 #include "../debug/ee/walker.h"
 #include "../debug/ee/controller.h"
+#endif // DDEBUGGING_SUPPORTED
 #endif // FEATURE_CODE_VERSIONING
 
 #ifndef FEATURE_CODE_VERSIONING
diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp
index 9b485ab803df19..578179d2e590e3 100644
--- a/src/coreclr/vm/corhost.cpp
+++ b/src/coreclr/vm/corhost.cpp
@@ -636,7 +636,7 @@ HRESULT CorHost2::CreateAppDomainWithManager(
             sAppPaths));
     }
 
-#if defined(TARGET_UNIX)
+#if defined(TARGET_UNIX) and !defined(TARGET_WASM)
     if (!g_coreclr_embedded)
     {
         // Check if the current code is executing in the single file host or in libcoreclr.so. The libSystem.Native is linked
diff --git a/src/coreclr/vm/gcinfodecoder.cpp b/src/coreclr/vm/gcinfodecoder.cpp
index 00bfa6b96f6d63..48e8eddf25498f 100644
--- a/src/coreclr/vm/gcinfodecoder.cpp
+++ b/src/coreclr/vm/gcinfodecoder.cpp
@@ -2183,6 +2183,15 @@ template  void TGcInfoDecoder::ReportRe
     _ASSERTE( !"NYI" );
 }
 
+template  OBJECTREF* TGcInfoDecoder::GetCapturedRegister(
+    int             regNum,
+    PREGDISPLAY     pRD
+    )
+{
+    _ASSERTE( !"NYI" );
+    return nullptr;
+}
+
 #endif // Unknown platform
 
 #ifdef FEATURE_INTERPRETER
diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp
index a8d4b2207e317c..90306c365cd026 100644
--- a/src/coreclr/vm/interpexec.cpp
+++ b/src/coreclr/vm/interpexec.cpp
@@ -6,6 +6,8 @@
 #include "threads.h"
 #include "gcenv.h"
 #include "interpexec.h"
+
+#ifdef FEATURE_JIT
 #include "callstubgenerator.h"
 
 FCDECL1(uint64_t, JIT_Dbl2ULng, double);
@@ -54,6 +56,7 @@ void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet)
 
     pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
 }
+#endif // FEATURE_JIT
 
 typedef void* (*HELPER_FTN_PP)(void*);
 typedef void* (*HELPER_FTN_BOX_UNBOX)(MethodTable*, void*);
@@ -1206,8 +1209,12 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
                     }
                     else if (codeInfo.GetCodeManager() != ExecutionManager::GetInterpreterCodeManager())
                     {
+#ifdef FEATURE_JIT
                         MethodDesc *pMD = codeInfo.GetMethodDesc();
                         InvokeCompiledMethod(pMD, stack + callArgsOffset, stack + returnOffset);
+#else
+                        EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Attempted to execute non-interpreter code from interpreter on a non-JIT build"));
+#endif // FEATURE_JIT
                         break;
                     }
 
diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h
index 1dcfce6a42ba39..37dd885542fb75 100644
--- a/src/coreclr/vm/metasig.h
+++ b/src/coreclr/vm/metasig.h
@@ -201,6 +201,7 @@ DEFINE_METASIG_T(SM(Exception_Obj_RefIntPtr_RetVoidPtr, C(EXCEPTION) j r(I), P(v
 #endif // FEATURE_OBJCMARSHAL
 DEFINE_METASIG(SM(Int_RetVoid, i, v))
 DEFINE_METASIG(SM(Int_RetObj, i, j))
+DEFINE_METASIG(SM(Int_RetInt, i, i))
 DEFINE_METASIG(SM(Int_Int_RetVoid, i i, v))
 DEFINE_METASIG(SM(Str_RetIntPtr, s, I))
 DEFINE_METASIG(SM(Str_RetBool, s, F))
diff --git a/src/coreclr/vm/precode.cpp b/src/coreclr/vm/precode.cpp
index 798e9849de3a6a..6e845484cd73e5 100644
--- a/src/coreclr/vm/precode.cpp
+++ b/src/coreclr/vm/precode.cpp
@@ -133,6 +133,9 @@ MethodDesc* Precode::GetMethodDesc(BOOL fSpeculative /*= FALSE*/)
     TADDR pMD = (TADDR)NULL;
 
     PrecodeType precodeType = GetType();
+#ifdef __wasm__
+    pMD = *(TADDR*)(m_data + OFFSETOF_PRECODE_TYPE + 4);
+#else
     switch (precodeType)
     {
     case PRECODE_STUB:
@@ -165,6 +168,7 @@ MethodDesc* Precode::GetMethodDesc(BOOL fSpeculative /*= FALSE*/)
     default:
         break;
     }
+#endif // __wasm__
 
     if (pMD == (TADDR)NULL)
     {
@@ -287,6 +291,10 @@ void Precode::Init(Precode* pPrecodeRX, PrecodeType t, MethodDesc* pMD, LoaderAl
 {
     LIMITED_METHOD_CONTRACT;
 
+#ifdef __wasm__  
+    m_data[OFFSETOF_PRECODE_TYPE] = t;
+    *(TADDR*)(m_data + OFFSETOF_PRECODE_TYPE + 4) = (TADDR)pMD;
+#else
     switch (t) {
     case PRECODE_STUB:
         ((StubPrecode*)this)->Init((StubPrecode*)pPrecodeRX, (TADDR)pMD, pLoaderAllocator);
@@ -310,6 +318,7 @@ void Precode::Init(Precode* pPrecodeRX, PrecodeType t, MethodDesc* pMD, LoaderAl
         UnexpectedPrecodeType("Precode::Init", t);
         break;
     }
+#endif
 
     _ASSERTE(IsValidType(GetType()));
 }
@@ -531,6 +540,8 @@ void StubPrecode::StaticInitialize()
     }
 
     #undef ENUM_PAGE_SIZE
+#elif defined(TARGET_WASM)
+    // StubPrecode is not implemented on WASM
 #else
     _ASSERTE((SIZE_T)((BYTE*)StubPrecodeCode_End - (BYTE*)StubPrecodeCode) <= StubPrecode::CodeSize);
 #endif
@@ -676,6 +687,8 @@ void FixupPrecode::StaticInitialize()
         // This should fail if the template is used on a platform which doesn't support the supported page size for templates
         ThrowHR(COR_E_EXECUTIONENGINE);
     }
+#elif defined(TARGET_WASM)
+    // FixupPrecode is not implemented on WASM
 #else
     _ASSERTE((SIZE_T)((BYTE*)FixupPrecodeCode_End - (BYTE*)FixupPrecodeCode) <= FixupPrecode::CodeSize);
 #endif
@@ -683,6 +696,8 @@ void FixupPrecode::StaticInitialize()
     _ASSERTE(((*((short*)PCODEToPINSTR((PCODE)StubPrecodeCode) + OFFSETOF_PRECODE_TYPE)) >> 5) == StubPrecode::Type);
 #elif TARGET_RISCV64
     _ASSERTE((*((BYTE*)PCODEToPINSTR((PCODE)FixupPrecodeCode) + OFFSETOF_PRECODE_TYPE)) == FixupPrecode::Type);
+#elif defined(TARGET_WASM)
+    // FixupPrecode is not implemented on WASM
 #else
     _ASSERTE(*((BYTE*)PCODEToPINSTR((PCODE)FixupPrecodeCode) + OFFSETOF_PRECODE_TYPE) == FixupPrecode::Type);
 #endif
diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h
index 64394d259e91a4..bff78896df4033 100644
--- a/src/coreclr/vm/precode.h
+++ b/src/coreclr/vm/precode.h
@@ -52,7 +52,7 @@ EXTERN_C VOID STDCALL PrecodeRemotingThunk();
 
 #elif defined(TARGET_WASM)
 
-#define SIZEOF_PRECODE_BASE         0
+#define SIZEOF_PRECODE_BASE         8 // 2*pointer size
 #define OFFSETOF_PRECODE_TYPE       0
 
 #endif // TARGET_AMD64
@@ -77,7 +77,6 @@ struct InvalidPrecode
 #elif defined(TARGET_RISCV64)
     static const int Type = 0xff;
 #elif defined(TARGET_WASM)
-    // unreachable instruction
     static const int Type = 0;
 #endif
 };
@@ -131,7 +130,7 @@ struct StubPrecode
     static const SIZE_T CodeSize = 24;
 #elif defined(TARGET_WASM)
     static const int Type = 0;
-    static const SIZE_T CodeSize = 0;
+    static const SIZE_T CodeSize = 8;
 #endif // TARGET_AMD64
 
     BYTE m_code[CodeSize];
@@ -413,7 +412,7 @@ struct FixupPrecode
     static const int FixupCodeOffset = 10;
 #elif defined(TARGET_WASM)
     static const int Type = 2;
-    static const SIZE_T CodeSize = 0;
+    static const SIZE_T CodeSize = 8;
     static const int FixupCodeOffset = 0;
 #endif // TARGET_AMD64
 
@@ -563,6 +562,10 @@ inline BYTE StubPrecode::GetType()
     LIMITED_METHOD_DAC_CONTRACT;
     TADDR type = GetData()->Type;
 
+#ifdef __wasm__
+    return (BYTE)type;
+#endif
+
     // There are a limited number of valid bit patterns here. Restrict to those, so that the
     // speculative variant of GetPrecodeFromEntryPoint is more robust. Type is stored as a TADDR
     // so that a single byte matching is not enough to cause a false match.
diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp
index 2f5c506ccb6000..d7c79143cb5093 100644
--- a/src/coreclr/vm/prestub.cpp
+++ b/src/coreclr/vm/prestub.cpp
@@ -1990,7 +1990,7 @@ extern "C" PCODE STDCALL PreStubWorker(TransitionBlock* pTransitionBlock, Method
 }
 
 #ifdef FEATURE_INTERPRETER
-extern "C" void STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr)
+extern "C" void STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, int8_t *pReturnValue, size_t returnValueSize)
 {
     // Argument registers are in the TransitionBlock
     // The stack arguments are right after the pTransitionBlock
@@ -2002,6 +2002,12 @@ extern "C" void STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBlo
     }
     int8_t *sp = threadContext->pStackPointer;
 
+    // copy the arguments to the stack
+    if (size > 0 && pArgs != nullptr)
+    {
+        memcpy(sp, pArgs, size);
+    }
+
     // This construct ensures that the InterpreterFrame is always stored at a higher address than the
     // InterpMethodContextFrame. This is important for the stack walking code.
     struct Frames
@@ -2024,8 +2030,19 @@ extern "C" void STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBlo
 
     InterpExecMethod(&frames.interpreterFrame, &frames.interpMethodContextFrame, threadContext);
 
+    if (pReturnValue != nullptr && returnValueSize > 0)
+    {
+        // Copy the return value from the stack to the returnValue pointer
+        memcpy(pReturnValue, &retVal, returnValueSize);
+    }
+
     frames.interpreterFrame.Pop();
 }
+
+extern "C" void STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr)
+{
+    ExecuteInterpretedMethodWithArgs(pTransitionBlock, byteCodeAddr, nullptr, 0, nullptr, 0);
+}
 #endif // FEATURE_INTERPRETER
 
 #ifdef _DEBUG
diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp
index ee16db9fec5398..844949264fb3f4 100644
--- a/src/coreclr/vm/threads.cpp
+++ b/src/coreclr/vm/threads.cpp
@@ -6055,11 +6055,13 @@ BOOL Thread::SetStackLimits(SetStackLimitScope scope)
     {
         m_CacheStackBase  = GetStackUpperBound();
         m_CacheStackLimit = GetStackLowerBound();
+#ifndef __wasm__ // stack can start at address 0 on wasm/emscripten and usually does
         if (m_CacheStackLimit == NULL)
         {
             _ASSERTE(!"Failed to set stack limits");
             return FALSE;
         }
+#endif
 
         // Compute the limit used by TryEnsureSufficientExecutionStack and cache it on the thread. This minimum stack size should
         // be sufficient to allow a typical non-recursive call chain to execute, including potential exception handling and
diff --git a/src/coreclr/vm/wasm/calldescrworkerwasm.cpp b/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
new file mode 100644
index 00000000000000..8e8811f0df095d
--- /dev/null
+++ b/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
@@ -0,0 +1,16 @@
+#include 
+
+extern "C" void STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, int8_t* pReturnValue, size_t returnValueSize);
+
+extern "C" void STDCALL CallDescrWorkerInternal(CallDescrData * pCallDescrData)
+{
+    PCODE code = pCallDescrData->pMD->GetNativeCode();
+    if (!code)
+    {
+        GCX_PREEMP();
+        pCallDescrData->pMD->PrepareInitialCode(CallerGCMode::Coop);
+        code = pCallDescrData->pMD->GetNativeCode();
+    }
+
+    ExecuteInterpretedMethodWithArgs(((TransitionBlock*)pCallDescrData->pSrc) - 1, code, (int8_t*)pCallDescrData->pSrc, pCallDescrData->nArgsSize, (int8_t*)pCallDescrData->returnValue, sizeof(pCallDescrData->returnValue));
+}
diff --git a/src/coreclr/vm/wasm/cgencpu.h b/src/coreclr/vm/wasm/cgencpu.h
index 2093a7a80a5499..ca996b269a1859 100644
--- a/src/coreclr/vm/wasm/cgencpu.h
+++ b/src/coreclr/vm/wasm/cgencpu.h
@@ -85,9 +85,13 @@ struct ArgumentRegisters {
 class StubLinkerCPU : public StubLinker
 {
 public:
-    static void Init();
-    void EmitShuffleThunk(struct ShuffleEntry *pShuffleEntryArray);
-    VOID EmitComputedInstantiatingMethodStub(MethodDesc* pSharedMD, struct ShuffleEntry *pShuffleEntryArray, void* extraArg);
+    static void Init() { /* no-op on wasm */ }
+    inline void EmitShuffleThunk(struct ShuffleEntry *pShuffleEntryArray) {
+        _ASSERTE("The EmitShuffleThunk is not implemented on wasm");
+    }
+    inline VOID EmitComputedInstantiatingMethodStub(MethodDesc* pSharedMD, struct ShuffleEntry *pShuffleEntryArray, void* extraArg) {
+        _ASSERTE("The EmitComputedInstantiatingMethodStub is not implemented on wasm");
+    }
 };
 
 //**********************************************************************
@@ -162,4 +166,26 @@ FORCEINLINE int64_t PalInterlockedCompareExchange64(_Inout_ int64_t volatile *pD
     return result;
 }
 
+inline void SetFirstArgReg(T_CONTEXT *context, TADDR value)
+{
+    PORTABILITY_ASSERT("SetFirstArgReg is not implemented on wasm");
+}
+
+inline TADDR GetFirstArgReg(T_CONTEXT *context)
+{
+    PORTABILITY_ASSERT("GetFirstArgReg is not implemented on wasm");
+    return 0;
+}
+
+inline void SetSecondArgReg(T_CONTEXT *context, TADDR value)
+{
+    PORTABILITY_ASSERT("SetSecondArgReg is not implemented on wasm");
+}
+
+inline TADDR GetSecondArgReg(T_CONTEXT *context)
+{
+    PORTABILITY_ASSERT("GetSecondArgReg is not implemented on wasm");
+    return 0;
+}
+
 #endif // __cgenwasm_h__
diff --git a/src/coreclr/vm/wasm/excepcpu.h b/src/coreclr/vm/wasm/excepcpu.h
index 7ca5a994a60760..bb819cae090f5d 100644
--- a/src/coreclr/vm/wasm/excepcpu.h
+++ b/src/coreclr/vm/wasm/excepcpu.h
@@ -29,6 +29,9 @@ PCODE GetAdjustedCallAddress(PCODE returnAddress)
     return returnAddress;
 }
 
-BOOL AdjustContextForVirtualStub(EXCEPTION_RECORD *pExceptionRecord, T_CONTEXT *pContext);
+inline BOOL AdjustContextForVirtualStub(EXCEPTION_RECORD *pExceptionRecord, T_CONTEXT *pContext) {
+    _ASSERTE("AdjustContextForVirtualStub is not implemented on wasm");
+    return FALSE;
+}
 
 #endif // __excepcpu_h__
diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp
new file mode 100644
index 00000000000000..0af3f891355f86
--- /dev/null
+++ b/src/coreclr/vm/wasm/helpers.cpp
@@ -0,0 +1,412 @@
+extern "C" void STDCALL CallCountingStubCode()
+{
+    PORTABILITY_ASSERT("CallCountingStubCode is not implemented on wasm");
+}
+
+extern "C" void CallCountingStubCode_End()
+{
+    PORTABILITY_ASSERT("CallCountingStubCode_End is not implemented on wasm");
+}
+
+extern "C" void STDCALL OnCallCountThresholdReachedStub()
+{
+    PORTABILITY_ASSERT("OnCallCountThresholdReachedStub is not implemented on wasm");
+}
+
+extern "C" void STDCALL ThePreStub()
+{
+    PORTABILITY_ASSERT("ThePreStub is not implemented on wasm");
+}
+
+extern "C" void InterpreterStub()
+{
+    PORTABILITY_ASSERT("InterpreterStub is not implemented on wasm");
+}
+
+extern "C" UINT_PTR STDCALL GetCurrentIP(void)
+{
+    PORTABILITY_ASSERT("GetCurrentIP is not implemented on wasm");
+    return 0;
+}
+
+extern "C" void STDMETHODCALLTYPE JIT_ProfilerEnterLeaveTailcallStub(UINT_PTR ProfilerHandle)
+{
+    PORTABILITY_ASSERT("JIT_ProfilerEnterLeaveTailcallStub is not implemented on wasm");
+}
+
+extern "C" void STDCALL DelayLoad_MethodCall()
+{
+    PORTABILITY_ASSERT("DelayLoad_MethodCall is not implemented on wasm");
+}
+
+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 NDirectImportThunk()
+{
+    PORTABILITY_ASSERT("NDirectImportThunk is not implemented on wasm");
+}
+
+extern "C" void STDCALL StubPrecodeCode()
+{
+    PORTABILITY_ASSERT("StubPrecodeCode is not implemented on wasm");
+}
+
+extern "C" void STDCALL StubPrecodeCode_End()
+{
+    PORTABILITY_ASSERT("StubPrecodeCode_End is not implemented on wasm");
+}
+
+extern "C" void STDCALL FixupPrecodeCode()
+{
+    PORTABILITY_ASSERT("FixupPrecodeCode is not implemented on wasm");
+}
+
+extern "C" void STDCALL FixupPrecodeCode_End()
+{
+    PORTABILITY_ASSERT("FixupPrecodeCode_End is not implemented on wasm");
+}
+
+extern "C" void STDCALL JIT_PatchedCodeLast()
+{
+    PORTABILITY_ASSERT("JIT_PatchedCodeLast is not implemented on wasm");
+}
+
+extern "C" void STDCALL JIT_PatchedCodeStart()
+{
+    PORTABILITY_ASSERT("JIT_PatchedCodeStart is not implemented on wasm");
+}
+
+extern "C" void RhpInitialInterfaceDispatch()
+{
+    PORTABILITY_ASSERT("RhpInitialInterfaceDispatch is not implemented on wasm");
+}
+
+unsigned FuncEvalFrame::GetFrameAttribs_Impl(void)
+{
+    PORTABILITY_ASSERT("FuncEvalFrame::GetFrameAttribs_Impl is not implemented on wasm");
+    return 0;
+}
+
+TADDR FuncEvalFrame::GetReturnAddressPtr_Impl()
+{
+    PORTABILITY_ASSERT("FuncEvalFrame::GetReturnAddressPtr_Impl is not implemented on wasm");
+    return 0;
+}
+
+void FuncEvalFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
+{
+    PORTABILITY_ASSERT("FuncEvalFrame::UpdateRegDisplay_Impl is not implemented on wasm");
+}
+
+void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
+{
+    PORTABILITY_ASSERT("InlinedCallFrame::UpdateRegDisplay_Impl is not implemented on wasm");
+}
+
+void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
+{
+    PORTABILITY_ASSERT("FaultingExceptionFrame::UpdateRegDisplay_Impl is not implemented on wasm");
+}
+
+void HelperMethodFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
+{
+    PORTABILITY_ASSERT("HelperMethodFrame::UpdateRegDisplay_Impl is not implemented on wasm");
+}
+
+void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
+{
+    PORTABILITY_ASSERT("TransitionFrame::UpdateRegDisplay_Impl is not implemented on wasm");
+}
+
+size_t CallDescrWorkerInternalReturnAddressOffset;
+
+VOID PALAPI RtlRestoreContext(IN PCONTEXT ContextRecord, IN PEXCEPTION_RECORD ExceptionRecord)
+{
+    PORTABILITY_ASSERT("RtlRestoreContext is not implemented on wasm");
+}
+
+extern "C" void TheUMEntryPrestub(void)
+{
+    PORTABILITY_ASSERT("TheUMEntryPrestub is not implemented on wasm");
+}
+
+extern "C" void STDCALL VarargPInvokeStub(void)
+{
+    PORTABILITY_ASSERT("VarargPInvokeStub is not implemented on wasm");
+}
+
+extern "C" void STDCALL VarargPInvokeStub_RetBuffArg(void)
+{
+    PORTABILITY_ASSERT("VarargPInvokeStub_RetBuffArg is not implemented on wasm");
+}
+
+extern "C" PCODE CID_VirtualOpenDelegateDispatch(TransitionBlock * pTransitionBlock)
+{
+    PORTABILITY_ASSERT("CID_VirtualOpenDelegateDispatch is not implemented on wasm");
+    return 0;
+}
+
+extern "C" FCDECL2(VOID, JIT_WriteBarrier_Callable, Object **dst, Object *ref)
+{
+    PORTABILITY_ASSERT("JIT_WriteBarrier_Callable is not implemented on wasm");
+}
+
+EXTERN_C void JIT_WriteBarrier_End()
+{
+    PORTABILITY_ASSERT("JIT_WriteBarrier_End is not implemented on wasm");
+}
+
+EXTERN_C void JIT_CheckedWriteBarrier_End()
+{
+    PORTABILITY_ASSERT("JIT_CheckedWriteBarrier_End is not implemented on wasm");
+}
+
+EXTERN_C void JIT_ByRefWriteBarrier_End()
+{
+    PORTABILITY_ASSERT("JIT_ByRefWriteBarrier_End is not implemented on wasm");
+}
+
+EXTERN_C void JIT_StackProbe_End()
+{
+    PORTABILITY_ASSERT("JIT_StackProbe_End is not implemented on wasm");
+}
+
+EXTERN_C int __fastcall HelperMethodFrameRestoreState(
+    INDEBUG_COMMA(HelperMethodFrame *pFrame)
+    MachState *pState
+)
+{
+    PORTABILITY_ASSERT("HelperMethodFrameRestoreState is not implemented on wasm");
+    return 0;
+}
+
+EXTERN_C VOID STDCALL ResetCurrentContext()
+{
+    PORTABILITY_ASSERT("ResetCurrentContext is not implemented on wasm");
+}
+
+extern "C" void STDCALL GenericPInvokeCalliHelper(void)
+{
+    PORTABILITY_ASSERT("GenericPInvokeCalliHelper is not implemented on wasm");
+}
+
+EXTERN_C void JIT_PInvokeBegin(InlinedCallFrame* pFrame)
+{
+    PORTABILITY_ASSERT("JIT_PInvokeBegin is not implemented on wasm");
+}
+
+EXTERN_C void JIT_PInvokeEnd(InlinedCallFrame* pFrame)
+{
+    PORTABILITY_ASSERT("JIT_PInvokeEnd is not implemented on wasm");
+}
+
+extern "C" void STDCALL JIT_StackProbe()
+{
+    PORTABILITY_ASSERT("JIT_StackProbe is not implemented on wasm");
+}
+
+EXTERN_C FCDECL0(void, JIT_PollGC)
+{
+    PORTABILITY_ASSERT("JIT_PollGC is not implemented on wasm");
+}
+
+extern "C" FCDECL2(VOID, JIT_WriteBarrier, Object **dst, Object *ref)
+{
+    PORTABILITY_ASSERT("JIT_WriteBarrier is not implemented on wasm");
+}
+
+extern "C" FCDECL2(VOID, JIT_CheckedWriteBarrier, Object **dst, Object *ref)
+{
+    PORTABILITY_ASSERT("JIT_CheckedWriteBarrier is not implemented on wasm");
+}
+
+extern "C" void STDCALL JIT_ByRefWriteBarrier()
+{
+    PORTABILITY_ASSERT("JIT_ByRefWriteBarrier is not implemented on wasm");
+}
+
+void InitJITHelpers1()
+{
+    /* no-op TODO do we need to do anything for the interpreter? */
+}
+
+extern "C" HRESULT __cdecl CorDBGetInterface(DebugInterface** rcInterface)
+{
+    PORTABILITY_ASSERT("CorDBGetInterface is not implemented on wasm");
+    return 0;
+}
+
+extern "C" void RhpInterfaceDispatch1()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatch1 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatch2()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatch2 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatch4()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatch4 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatch8()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatch8 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatch16()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatch16 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatch32()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatch32 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatch64()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatch64 is not implemented on wasm");
+}
+
+extern "C" void RhpVTableOffsetDispatch()
+{
+    PORTABILITY_ASSERT("RhpVTableOffsetDispatch is not implemented on wasm");
+}
+
+typedef uint8_t CODE_LOCATION;
+CODE_LOCATION RhpAssignRefAVLocation;
+CODE_LOCATION RhpCheckedAssignRefAVLocation;
+CODE_LOCATION RhpByRefAssignRefAVLocation1;
+CODE_LOCATION RhpByRefAssignRefAVLocation2;
+
+extern "C" void ThisPtrRetBufPrecodeWorker()
+{
+    PORTABILITY_ASSERT("ThisPtrRetBufPrecodeWorker is not implemented on wasm");
+}
+
+extern "C" FCDECL2(VOID, RhpAssignRef, Object **dst, Object *ref)
+{
+    PORTABILITY_ASSERT("RhpAssignRef is not implemented on wasm");
+}
+
+extern "C" FCDECL2(VOID, RhpCheckedAssignRef, Object **dst, Object *ref)
+{
+    PORTABILITY_ASSERT("RhpCheckedAssignRef is not implemented on wasm");
+}
+
+extern "C" FCDECL2(VOID, RhpByRefAssignRef, Object **dst, Object *ref)
+{
+    PORTABILITY_ASSERT("RhpByRefAssignRef is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatchAVLocation1()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatchAVLocation1 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatchAVLocation2()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatchAVLocation2 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatchAVLocation4()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatchAVLocation4 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatchAVLocation8()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatchAVLocation8 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatchAVLocation16()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatchAVLocation16 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatchAVLocation32()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatchAVLocation32 is not implemented on wasm");
+}
+
+extern "C" void RhpInterfaceDispatchAVLocation64()
+{
+    PORTABILITY_ASSERT("RhpInterfaceDispatchAVLocation64 is not implemented on wasm");
+}
+
+extern "C" void RhpVTableOffsetDispatchAVLocation()
+{
+    PORTABILITY_ASSERT("RhpVTableOffsetDispatchAVLocation is not implemented on wasm");
+}
+
+extern "C" void STDCALL ThePreStubPatchLabel(void)
+{
+    PORTABILITY_ASSERT("ThePreStubPatchLabel is not implemented on wasm");
+}
+
+LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv)
+{
+    PORTABILITY_ASSERT("CLRNoCatchHandler is not implemented on wasm");
+    return EXCEPTION_CONTINUE_SEARCH;
+}
+
+EXTERN_C void STDMETHODCALLTYPE ProfileEnterNaked(FunctionIDOrClientID functionIDOrClientID)
+{
+    PORTABILITY_ASSERT("ProfileEnterNaked is not implemented on wasm");
+}
+
+EXTERN_C void STDMETHODCALLTYPE ProfileLeaveNaked(UINT_PTR clientData)
+{
+    PORTABILITY_ASSERT("ProfileLeaveNaked is not implemented on wasm");
+}
+
+EXTERN_C void STDMETHODCALLTYPE ProfileTailcallNaked(UINT_PTR clientData)
+{
+    PORTABILITY_ASSERT("ProfileTailcallNaked is not implemented on wasm");
+}
+
+int StompWriteBarrierEphemeral(bool isRuntimeSuspended)
+{
+    _ASSERTE("StompWriteBarrierEphemeral is not implemented on wasm");
+    return 0;
+}
+
+int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
+{
+    _ASSERTE("StompWriteBarrierResize is not implemented on wasm");
+    return 0;
+}
+
+void FlushWriteBarrierInstructionCache()
+{
+    PORTABILITY_ASSERT("FlushWriteBarrierInstructionCache is not implemented on wasm");
+}
+
+EXTERN_C Thread * JIT_InitPInvokeFrame(InlinedCallFrame *pFrame)
+{
+    PORTABILITY_ASSERT("JIT_InitPInvokeFrame is not implemented on wasm");
+    return nullptr;
+}
+
+void _DacGlobals::Initialize()
+{
+    /* no-op on wasm */
+}
+
+int g_pDebugger;
diff --git a/src/coreclr/vm/wasm/profiler.cpp b/src/coreclr/vm/wasm/profiler.cpp
new file mode 100644
index 00000000000000..b4004f1c4c4347
--- /dev/null
+++ b/src/coreclr/vm/wasm/profiler.cpp
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "common.h"
+
+#ifdef PROFILING_SUPPORTED
+#include "asmconstants.h"
+#include "proftoeeinterfaceimpl.h"
+
+UINT_PTR ProfileGetIPFromPlatformSpecificHandle(void* pPlatformSpecificHandle)
+{
+    _ASSERTE(!"ProfileGetIPFromPlatformSpecificHandle is not implemented on wasm");
+    return 0;
+}
+
+void ProfileSetFunctionIDInPlatformSpecificHandle(void* pPlatformSpecificHandle, FunctionID functionId)
+{
+    _ASSERTE(!"ProfileSetFunctionIDInPlatformSpecificHandle is not implemented on wasm");
+}
+
+ProfileArgIterator::ProfileArgIterator(MetaSig* pSig, void* pPlatformSpecificHandle)
+    : m_argIterator(pSig)
+{
+    _ASSERTE(!"ProfileArgIterator constructor is not implemented on wasm");
+}
+
+ProfileArgIterator::~ProfileArgIterator()
+{
+    _ASSERTE(!"ProfileArgIterator destructor is not implemented on wasm");
+}
+
+LPVOID ProfileArgIterator::GetNextArgAddr()
+{
+    _ASSERTE(!"GetNextArgAddr is not implemented on wasm");
+    return nullptr;
+}
+
+LPVOID ProfileArgIterator::GetHiddenArgValue(void)
+{
+    _ASSERTE(!"GetHiddenArgValue is not implemented on wasm");
+    return nullptr;
+}
+
+LPVOID ProfileArgIterator::GetThis(void)
+{
+    _ASSERTE(!"GetThis is not implemented on wasm");
+    return nullptr;
+}
+
+LPVOID ProfileArgIterator::GetReturnBufferAddr(void)
+{
+    _ASSERTE(!"GetReturnBufferAddr is not implemented on wasm");
+    return nullptr;
+}
+
+
+#endif // PROFILING_SUPPORTED
diff --git a/src/native/libs/CMakeLists.txt b/src/native/libs/CMakeLists.txt
index c90e9b8a45ddc5..a54fa43ed3f902 100644
--- a/src/native/libs/CMakeLists.txt
+++ b/src/native/libs/CMakeLists.txt
@@ -4,6 +4,10 @@ include(CheckCCompilerFlag)
 
 project(LibsNative C)
 
+if (MONO_RUNTIME)
+    add_definitions(-DMONO_RUNTIME)
+endif()
+
 if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
     # This is our root CMakeList.txt, so we need to set up some global settings and include the minipal here.
     include(../../../eng/native/configurepaths.cmake)
diff --git a/src/native/libs/System.Globalization.Native/entrypoints.c b/src/native/libs/System.Globalization.Native/entrypoints.c
index f2db315ec5452e..9adb279383b8ad 100644
--- a/src/native/libs/System.Globalization.Native/entrypoints.c
+++ b/src/native/libs/System.Globalization.Native/entrypoints.c
@@ -41,8 +41,10 @@ static const Entry s_globalizationNative[] =
     DllImportEntry(GlobalizationNative_GetSortHandle)
     DllImportEntry(GlobalizationNative_GetSortKey)
     DllImportEntry(GlobalizationNative_GetSortVersion)
+#ifndef __wasm__
     DllImportEntry(GlobalizationNative_GetTimeZoneDisplayName)
     DllImportEntry(GlobalizationNative_IanaIdToWindowsId)
+#endif
     DllImportEntry(GlobalizationNative_IndexOf)
     DllImportEntry(GlobalizationNative_InitICUFunctions)
     DllImportEntry(GlobalizationNative_IsNormalized)
@@ -54,7 +56,9 @@ static const Entry s_globalizationNative[] =
 #endif
     DllImportEntry(GlobalizationNative_NormalizeString)
     DllImportEntry(GlobalizationNative_StartsWith)
+#ifndef __wasm__
     DllImportEntry(GlobalizationNative_WindowsIdToIanaId)
+#endif
 #if defined(APPLE_HYBRID_GLOBALIZATION)
     DllImportEntry(GlobalizationNative_ChangeCaseInvariantNative)
     DllImportEntry(GlobalizationNative_ChangeCaseNative)
diff --git a/src/native/libs/build-native.proj b/src/native/libs/build-native.proj
index 2b5dcac9ae4a41..7380913b8ed279 100644
--- a/src/native/libs/build-native.proj
+++ b/src/native/libs/build-native.proj
@@ -98,9 +98,10 @@
           Condition="$([MSBuild]::IsOsPlatform(Windows))">
     
         <_BuildNativeArgs Condition="'$(Ninja)' == 'false'">$(_BuildNativeArgs) msbuild
+        <_MonoCMakeArgs Condition="'$(RuntimeFlavor)' == 'Mono'">-DMONO_RUNTIME=1
         <_MonoWasmMTCMakeArgs Condition="'$(WasmEnableThreads)' == 'true'">-DMONO_WASM_MT=1
         <_MonoWasmMTCMakeArgs Condition="'$(CMakeArgs)' != ''"> $(_MonoWasmMTCMakeArgs)
-        <_BuildNativeArgs Condition="'$(CMakeArgs)' != '' or '$(_MonoWasmMTCMakeArgs)' != ''">$(_BuildNativeArgs) -cmakeargs "$(CMakeArgs)$(_MonoWasmMTCMakeArgs)"
+        <_BuildNativeArgs Condition="'$(CMakeArgs)' != '' or '$(_MonoWasmMTCMakeArgs)' != '' or '$(_MonoCMakeArgs)' != ''">$(_BuildNativeArgs) -cmakeargs "$(CMakeArgs)$(_MonoCMakeArgs)$(_MonoWasmMTCMakeArgs)"
     
     
     
diff --git a/src/native/minipal/random.c b/src/native/minipal/random.c
index 3c2b33ac7463b0..e26ce66d6660c2 100644
--- a/src/native/minipal/random.c
+++ b/src/native/minipal/random.c
@@ -77,7 +77,7 @@ int32_t minipal_get_cryptographically_secure_random_bytes(uint8_t* buffer, int32
 {
     assert(buffer != NULL);
 
-#ifdef __EMSCRIPTEN__
+#if defined(__EMSCRIPTEN__) && defined(MONO_RUNTIME)
     extern int32_t mono_wasm_browser_entropy(uint8_t* buffer, int32_t bufferLength);
     static bool sMissingBrowserCrypto;
     if (!sMissingBrowserCrypto)

From 790712a8ad0cbf753fc53346a3e0d4303b5a33a3 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 9 Jun 2025 11:38:18 +0200
Subject: [PATCH 02/63] Fix condition

Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com>
---
 src/coreclr/vm/corhost.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp
index 578179d2e590e3..c62748f85bf934 100644
--- a/src/coreclr/vm/corhost.cpp
+++ b/src/coreclr/vm/corhost.cpp
@@ -636,7 +636,7 @@ HRESULT CorHost2::CreateAppDomainWithManager(
             sAppPaths));
     }
 
-#if defined(TARGET_UNIX) and !defined(TARGET_WASM)
+#if defined(TARGET_UNIX) && !defined(TARGET_WASM)
     if (!g_coreclr_embedded)
     {
         // Check if the current code is executing in the single file host or in libcoreclr.so. The libSystem.Native is linked

From 0036748bb4e992709582b6ed1aa0e1b8bdd711bb Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 9 Jun 2025 17:42:50 +0200
Subject: [PATCH 03/63] Fix build

The jit helpers are used later unconditionally
---
 src/coreclr/vm/interpexec.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp
index 90306c365cd026..fcc26ac62ef7ed 100644
--- a/src/coreclr/vm/interpexec.cpp
+++ b/src/coreclr/vm/interpexec.cpp
@@ -7,9 +7,6 @@
 #include "gcenv.h"
 #include "interpexec.h"
 
-#ifdef FEATURE_JIT
-#include "callstubgenerator.h"
-
 FCDECL1(uint64_t, JIT_Dbl2ULng, double);
 FCDECL1(int64_t, JIT_Dbl2Lng, double);
 FCDECL1(uint32_t, JIT_Dbl2UInt, double);
@@ -19,6 +16,9 @@ FCDECL1(double, JIT_ULng2Dbl, uint64_t val);
 FCDECL1(float, JIT_Lng2Flt, int64_t val);
 FCDECL1(double, JIT_Lng2Dbl, int64_t val);
 
+#ifdef FEATURE_JIT
+#include "callstubgenerator.h"
+
 void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet)
 {
     CONTRACTL

From 788fecf43c780258cafbea9b832dc51abdf0dad4 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 9 Jun 2025 22:04:42 +0200
Subject: [PATCH 04/63] Update after merge

---
 src/coreclr/vm/wasm/helpers.cpp | 89 +++++++++++++++++++++++++++------
 1 file changed, 73 insertions(+), 16 deletions(-)

diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp
index 0af3f891355f86..e073b2714a7100 100644
--- a/src/coreclr/vm/wasm/helpers.cpp
+++ b/src/coreclr/vm/wasm/helpers.cpp
@@ -121,11 +121,6 @@ void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool u
     PORTABILITY_ASSERT("FaultingExceptionFrame::UpdateRegDisplay_Impl is not implemented on wasm");
 }
 
-void HelperMethodFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
-{
-    PORTABILITY_ASSERT("HelperMethodFrame::UpdateRegDisplay_Impl is not implemented on wasm");
-}
-
 void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
 {
     PORTABILITY_ASSERT("TransitionFrame::UpdateRegDisplay_Impl is not implemented on wasm");
@@ -184,15 +179,6 @@ EXTERN_C void JIT_StackProbe_End()
     PORTABILITY_ASSERT("JIT_StackProbe_End is not implemented on wasm");
 }
 
-EXTERN_C int __fastcall HelperMethodFrameRestoreState(
-    INDEBUG_COMMA(HelperMethodFrame *pFrame)
-    MachState *pState
-)
-{
-    PORTABILITY_ASSERT("HelperMethodFrameRestoreState is not implemented on wasm");
-    return 0;
-}
-
 EXTERN_C VOID STDCALL ResetCurrentContext()
 {
     PORTABILITY_ASSERT("ResetCurrentContext is not implemented on wasm");
@@ -355,6 +341,72 @@ extern "C" void RhpVTableOffsetDispatchAVLocation()
     PORTABILITY_ASSERT("RhpVTableOffsetDispatchAVLocation is not implemented on wasm");
 }
 
+EXTERN_C FCDECL2(Object*, RhpNewVariableSizeObject, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size)
+{
+    PORTABILITY_ASSERT("RhpNewVariableSizeObject is not implemented on wasm");
+    return nullptr;
+}
+
+EXTERN_C FCDECL1(Object*, RhpNewMaybeFrozen, CORINFO_CLASS_HANDLE typeHnd_)
+{
+    PORTABILITY_ASSERT("RhpNewMaybeFrozen is not implemented on wasm");
+    return nullptr;
+}
+
+EXTERN_C FCDECL2(Object*, RhpNewArrayFast, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size)
+{
+    PORTABILITY_ASSERT("RhpNewArrayFast is not implemented on wasm");
+    return nullptr;
+}
+
+EXTERN_C FCDECL2(Object*, RhpNewPtrArrayFast, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size)
+{
+    PORTABILITY_ASSERT("RhpNewPtrArrayFast is not implemented on wasm");
+    return nullptr;
+}
+
+EXTERN_C FCDECL2(Object*, RhpNewArrayFastAlign8, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size)
+{
+    PORTABILITY_ASSERT("RhpNewArrayFastAlign8 is not implemented on wasm");
+    return nullptr;
+}
+
+EXTERN_C FCDECL1(Object*, RhpNewFastAlign8, CORINFO_CLASS_HANDLE typeHnd_)
+{
+    PORTABILITY_ASSERT("RhpNewFastAlign8 is not implemented on wasm");
+    return nullptr;
+}
+
+EXTERN_C FCDECL1(Object*, RhpNewFastMisalign, CORINFO_CLASS_HANDLE typeHnd_)
+{
+    PORTABILITY_ASSERT("RhpNewFastMisalign is not implemented on wasm");
+    return nullptr;
+}
+
+EXTERN_C FCDECL1(Object*, RhpNewFast, CORINFO_CLASS_HANDLE typeHnd_)
+{
+    PORTABILITY_ASSERT("RhpNewFast is not implemented on wasm");
+    return nullptr;
+}
+
+EXTERN_C FCDECL1(Object*, RhpNew, CORINFO_CLASS_HANDLE typeHnd_)
+{
+    PORTABILITY_ASSERT("RhpNew is not implemented on wasm");
+    return nullptr;
+}
+
+EXTERN_C FCDECL2(Object*, RhpNewArrayMaybeFrozen, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size)
+{
+    PORTABILITY_ASSERT("RhpNewArrayMaybeFrozen is not implemented on wasm");
+    return nullptr;
+}
+
+EXTERN_C FCDECL2(Object*, RhNewString, CORINFO_CLASS_HANDLE typeHnd_, DWORD stringLength)
+{
+    PORTABILITY_ASSERT("RhNewString is not implemented on wasm");
+    return nullptr;
+}
+
 extern "C" void STDCALL ThePreStubPatchLabel(void)
 {
     PORTABILITY_ASSERT("ThePreStubPatchLabel is not implemented on wasm");
@@ -381,15 +433,20 @@ EXTERN_C void STDMETHODCALLTYPE ProfileTailcallNaked(UINT_PTR clientData)
     PORTABILITY_ASSERT("ProfileTailcallNaked is not implemented on wasm");
 }
 
+void InitJITWriteBarrierHelpers()
+{
+    // TODO: implement me
+}
+
 int StompWriteBarrierEphemeral(bool isRuntimeSuspended)
 {
-    _ASSERTE("StompWriteBarrierEphemeral is not implemented on wasm");
+    // TODO: implement me
     return 0;
 }
 
 int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
 {
-    _ASSERTE("StompWriteBarrierResize is not implemented on wasm");
+    // TODO: implement me
     return 0;
 }
 

From 01198766c0d80f95a25c7f881e89f428b40857dd Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 9 Jun 2025 22:11:43 +0200
Subject: [PATCH 05/63] Feedback

---
 src/coreclr/hosts/corewasmrun/corewasmrun.cpp | 4 ++++
 src/coreclr/vm/wasm/calldescrworkerwasm.cpp   | 4 ++++
 src/coreclr/vm/wasm/helpers.cpp               | 4 ++++
 3 files changed, 12 insertions(+)

diff --git a/src/coreclr/hosts/corewasmrun/corewasmrun.cpp b/src/coreclr/hosts/corewasmrun/corewasmrun.cpp
index dda735b72b521e..2fff454fc0200b 100644
--- a/src/coreclr/hosts/corewasmrun/corewasmrun.cpp
+++ b/src/coreclr/hosts/corewasmrun/corewasmrun.cpp
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
 #include 
 #include 
 
diff --git a/src/coreclr/vm/wasm/calldescrworkerwasm.cpp b/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
index 8e8811f0df095d..90c005370556be 100644
--- a/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
+++ b/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
 #include 
 
 extern "C" void STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, int8_t* pReturnValue, size_t returnValueSize);
diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp
index e073b2714a7100..d9fdf89a572d62 100644
--- a/src/coreclr/vm/wasm/helpers.cpp
+++ b/src/coreclr/vm/wasm/helpers.cpp
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
 extern "C" void STDCALL CallCountingStubCode()
 {
     PORTABILITY_ASSERT("CallCountingStubCode is not implemented on wasm");

From 43c83fdcb7006612dc383cf87a0c4468b9ad3489 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 10 Jun 2025 13:31:40 +0200
Subject: [PATCH 06/63] Update after merge

---
 src/coreclr/vm/interpexec.cpp               |  8 ++++++--
 src/coreclr/vm/prestub.cpp                  | 11 +++++------
 src/coreclr/vm/wasm/calldescrworkerwasm.cpp |  4 ++--
 3 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp
index 9a5bdc82046474..162539985243af 100644
--- a/src/coreclr/vm/interpexec.cpp
+++ b/src/coreclr/vm/interpexec.cpp
@@ -60,7 +60,6 @@ void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet)
 
     pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
 }
-#endif // FEATURE_JIT
 
 // Create call stub for calling interpreted methods from JITted/AOTed code.
 CallStubHeader *CreateNativeToInterpreterCallStub(InterpMethod* pInterpMethod)
@@ -97,6 +96,8 @@ CallStubHeader *CreateNativeToInterpreterCallStub(InterpMethod* pInterpMethod)
     return pHeader;
 }
 
+#endif // FEATURE_JIT
+
 typedef void* (*HELPER_FTN_PP)(void*);
 typedef void* (*HELPER_FTN_BOX_UNBOX)(MethodTable*, void*);
 typedef Object* (*HELPER_FTN_NEWARR)(CORINFO_CLASS_HANDLE, intptr_t);
@@ -1486,9 +1487,12 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
                         }
                         if (targetIp == NULL)
                         {
+#ifdef FEATURE_JIT
                             // If we didn't get the interpreter code pointer setup, then this is a method we need to invoke as a compiled method.
                             InvokeCompiledMethod(targetMethod, stack + callArgsOffset, stack + returnOffset);
-                            break;
+#else
+                        EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Attempted to execute non-interpreter code from interpreter on a non-JIT build"));
+#endif // FEATURE_JIT                            break;
                         }
                     }
 
diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp
index d212ecfd9f0e55..0c6cdce552a57f 100644
--- a/src/coreclr/vm/prestub.cpp
+++ b/src/coreclr/vm/prestub.cpp
@@ -1991,8 +1991,7 @@ extern "C" PCODE STDCALL PreStubWorker(TransitionBlock* pTransitionBlock, Method
 }
 
 #ifdef FEATURE_INTERPRETER
-extern "C" void STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, void* retBuff)
-extern "C" void* STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, )
+extern "C" void* STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, void* retBuff)
 {
     // Argument registers are in the TransitionBlock
     // The stack arguments are right after the pTransitionBlock
@@ -2035,9 +2034,9 @@ extern "C" void* STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBl
     return frames.interpMethodContextFrame.pRetVal;
 }
 
-extern "C" void STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr)
+extern "C" void* STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, void* retBuff)
 {
-    ExecuteInterpretedMethodWithArgs(pTransitionBlock, byteCodeAddr, nullptr, 0, nullptr, 0);
+    return ExecuteInterpretedMethodWithArgs(pTransitionBlock, byteCodeAddr, nullptr, 0, retBuff);
 }
 #endif // FEATURE_INTERPRETER
 
@@ -2340,13 +2339,13 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo
     pCode = DoBackpatch(pMT, pDispatchingMT, FALSE);
 
 Return:
-#ifdef FEATURE_INTERPRETER
+#if defined(FEATURE_INTERPRETER) && defined(FEATURE_JIT)
     InterpByteCodeStart *pInterpreterCode = GetInterpreterCode();
     if (pInterpreterCode != NULL)
     {
         CreateNativeToInterpreterCallStub(pInterpreterCode->Method);
     }
-#endif // FEATURE_INTERPRETER
+#endif // FEATURE_INTERPRETER && FEATURE_JIT
 
     RETURN pCode;
 }
diff --git a/src/coreclr/vm/wasm/calldescrworkerwasm.cpp b/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
index 90c005370556be..baf171b5df7554 100644
--- a/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
+++ b/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
@@ -4,7 +4,7 @@
 
 #include 
 
-extern "C" void STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, int8_t* pReturnValue, size_t returnValueSize);
+extern "C" void* STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, void* retBuff);
 
 extern "C" void STDCALL CallDescrWorkerInternal(CallDescrData * pCallDescrData)
 {
@@ -16,5 +16,5 @@ extern "C" void STDCALL CallDescrWorkerInternal(CallDescrData * pCallDescrData)
         code = pCallDescrData->pMD->GetNativeCode();
     }
 
-    ExecuteInterpretedMethodWithArgs(((TransitionBlock*)pCallDescrData->pSrc) - 1, code, (int8_t*)pCallDescrData->pSrc, pCallDescrData->nArgsSize, (int8_t*)pCallDescrData->returnValue, sizeof(pCallDescrData->returnValue));
+    ExecuteInterpretedMethodWithArgs(((TransitionBlock*)pCallDescrData->pSrc) - 1, code, (int8_t*)pCallDescrData->pSrc, pCallDescrData->nArgsSize, pCallDescrData->returnValue);
 }

From 70b06c5f0fa776f13e021f75d5f8aa5bdcf51063 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 10 Jun 2025 15:44:47 +0200
Subject: [PATCH 07/63] Fix release build offsets

---
 .../src/System/Runtime/ExceptionServices/AsmOffsets.cs      | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs
index 5bafebd4cb140d..37be5fd2e093db 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs
@@ -122,9 +122,9 @@ class AsmOffsets
     public const int OFFSETOF__REGDISPLAY__SP = 0xba0;
     public const int OFFSETOF__REGDISPLAY__ControlPC = 0xba8;
 #elif TARGET_WASM
-    public const int SIZEOF__REGDISPLAY = 0x3c;
-    public const int OFFSETOF__REGDISPLAY__SP = 0x34;
-    public const int OFFSETOF__REGDISPLAY__ControlPC = 0x38;
+    public const int SIZEOF__REGDISPLAY = 0x34;
+    public const int OFFSETOF__REGDISPLAY__SP = 0x2c;
+    public const int OFFSETOF__REGDISPLAY__ControlPC = 0x30;
 #endif
 
 #if TARGET_64BIT

From 51f0214330e984b019bc91c2beee710b705544ce Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 10 Jun 2025 15:58:23 +0200
Subject: [PATCH 08/63] Build Debug runtime configuration on CI, so that
 interpreter is enabled

---
 eng/pipelines/runtime.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index 9fa0492f75c8e9..e5c8c02147c618 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -126,7 +126,7 @@ extends:
           - browser_wasm_win
           jobParameters:
             nameSuffix: AllSubsets_CoreCLR
-            buildArgs: -s clr.runtime+libs -rc Release -c Release -lc $(_BuildConfig)
+            buildArgs: -s clr.runtime+libs -rc Debug -c Release -lc $(_BuildConfig)
             timeoutInMinutes: 120
             condition: >-
               or(

From c667e6c7b39f3121553f47e882fce4b1fbf561f0 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 10 Jun 2025 18:19:17 +0200
Subject: [PATCH 09/63] Fix build

---
 src/native/libs/build-native.proj | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/native/libs/build-native.proj b/src/native/libs/build-native.proj
index 7380913b8ed279..12421841d8dcda 100644
--- a/src/native/libs/build-native.proj
+++ b/src/native/libs/build-native.proj
@@ -99,8 +99,9 @@
     
         <_BuildNativeArgs Condition="'$(Ninja)' == 'false'">$(_BuildNativeArgs) msbuild
         <_MonoCMakeArgs Condition="'$(RuntimeFlavor)' == 'Mono'">-DMONO_RUNTIME=1
+        <_MonoCMakeArgs Condition="'$(CMakeArgs)' != ''"> $(_MonoCMakeArgs)
         <_MonoWasmMTCMakeArgs Condition="'$(WasmEnableThreads)' == 'true'">-DMONO_WASM_MT=1
-        <_MonoWasmMTCMakeArgs Condition="'$(CMakeArgs)' != ''"> $(_MonoWasmMTCMakeArgs)
+        <_MonoWasmMTCMakeArgs Condition="'$(CMakeArgs)' != '' or '$(_MonoCMakeArgs)' != ''"> $(_MonoWasmMTCMakeArgs)
         <_BuildNativeArgs Condition="'$(CMakeArgs)' != '' or '$(_MonoWasmMTCMakeArgs)' != '' or '$(_MonoCMakeArgs)' != ''">$(_BuildNativeArgs) -cmakeargs "$(CMakeArgs)$(_MonoCMakeArgs)$(_MonoWasmMTCMakeArgs)"
     
     

From e45f726010101ec5017f9b344358978aa564b89b Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 10 Jun 2025 18:30:37 +0200
Subject: [PATCH 10/63] Enable interpreter in all configuration on wasm

Fix build
---
 .../System/Runtime/ExceptionServices/AsmOffsets.cs |  4 ++--
 src/coreclr/clrfeatures.cmake                      | 14 +++++++++-----
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs
index 37be5fd2e093db..2544e0222b704b 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs
@@ -144,9 +144,9 @@ class AsmOffsets
     public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x3c8;
 #else // TARGET_64BIT
     public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x4;
-    public const int SIZEOF__StackFrameIterator = 0xc4;
+    public const int SIZEOF__StackFrameIterator = 0xd4;
     public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0xb2;
-    public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0xc0;
+    public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0xd0;
 #endif // TARGET_64BIT
 
 #endif // DEBUG
diff --git a/src/coreclr/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake
index f7ee1864daa8c4..bdc10b6aa719e7 100644
--- a/src/coreclr/clrfeatures.cmake
+++ b/src/coreclr/clrfeatures.cmake
@@ -31,11 +31,15 @@ if(NOT DEFINED FEATURE_DBGIPC)
 endif(NOT DEFINED FEATURE_DBGIPC)
 
 if(NOT DEFINED FEATURE_INTERPRETER)
-  if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_WASM)
-    set(FEATURE_INTERPRETER $,1,0>)
-  else(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_WASM)
-    set(FEATURE_INTERPRETER 0)
-  endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_WASM)
+  if(CLR_CMAKE_TARGET_ARCH_WASM)
+    set(FEATURE_INTERPRETER 1)
+  else()
+    if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64)
+      set(FEATURE_INTERPRETER $,1,0>)
+    else(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64)
+      set(FEATURE_INTERPRETER 0)
+    endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64)
+  endif(CLR_CMAKE_TARGET_ARCH_WASM)
 endif(NOT DEFINED FEATURE_INTERPRETER)
 
 if(NOT DEFINED FEATURE_STANDALONE_GC)

From 91f336cffcc70e832ed00d95e4388481167692cf Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 10 Jun 2025 18:56:45 +0200
Subject: [PATCH 11/63] Build in Release again as we are missing debug packages

---
 eng/pipelines/runtime.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index e5c8c02147c618..9fa0492f75c8e9 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -126,7 +126,7 @@ extends:
           - browser_wasm_win
           jobParameters:
             nameSuffix: AllSubsets_CoreCLR
-            buildArgs: -s clr.runtime+libs -rc Debug -c Release -lc $(_BuildConfig)
+            buildArgs: -s clr.runtime+libs -rc Release -c Release -lc $(_BuildConfig)
             timeoutInMinutes: 120
             condition: >-
               or(

From f9a033901c605991d01a369347795f1808cfd2d0 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 11 Jun 2025 17:31:40 +0200
Subject: [PATCH 12/63] Move inline keyword

Co-authored-by: Jan Kotas 
---
 src/coreclr/inc/clrnt.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/inc/clrnt.h b/src/coreclr/inc/clrnt.h
index 30cb7eacdff957..c5b56ec644e378 100644
--- a/src/coreclr/inc/clrnt.h
+++ b/src/coreclr/inc/clrnt.h
@@ -510,7 +510,7 @@ RtlVirtualUnwind(
 #define UNW_FLAG_EHANDLER               0x1             /* filter handler */
 #define UNW_FLAG_UHANDLER               0x2             /* unwind handler */
 
-PEXCEPTION_ROUTINE inline
+inline PEXCEPTION_ROUTINE
 RtlVirtualUnwind (
     _In_ DWORD HandlerType,
     _In_ DWORD ImageBase,

From 2df11b1e5cbd95d718a8e254fc918de45b6dfc29 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 11 Jun 2025 17:02:07 +0200
Subject: [PATCH 13/63] Feedback

---
 src/native/libs/System.Globalization.Native/entrypoints.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/native/libs/System.Globalization.Native/entrypoints.c b/src/native/libs/System.Globalization.Native/entrypoints.c
index 9adb279383b8ad..b687ea837daac6 100644
--- a/src/native/libs/System.Globalization.Native/entrypoints.c
+++ b/src/native/libs/System.Globalization.Native/entrypoints.c
@@ -41,10 +41,6 @@ static const Entry s_globalizationNative[] =
     DllImportEntry(GlobalizationNative_GetSortHandle)
     DllImportEntry(GlobalizationNative_GetSortKey)
     DllImportEntry(GlobalizationNative_GetSortVersion)
-#ifndef __wasm__
-    DllImportEntry(GlobalizationNative_GetTimeZoneDisplayName)
-    DllImportEntry(GlobalizationNative_IanaIdToWindowsId)
-#endif
     DllImportEntry(GlobalizationNative_IndexOf)
     DllImportEntry(GlobalizationNative_InitICUFunctions)
     DllImportEntry(GlobalizationNative_IsNormalized)
@@ -57,6 +53,8 @@ static const Entry s_globalizationNative[] =
     DllImportEntry(GlobalizationNative_NormalizeString)
     DllImportEntry(GlobalizationNative_StartsWith)
 #ifndef __wasm__
+    DllImportEntry(GlobalizationNative_GetTimeZoneDisplayName)
+    DllImportEntry(GlobalizationNative_IanaIdToWindowsId)
     DllImportEntry(GlobalizationNative_WindowsIdToIanaId)
 #endif
 #if defined(APPLE_HYBRID_GLOBALIZATION)

From 556e5fae89be845fea660a7b8dbdcad34baf8eb0 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Fri, 13 Jun 2025 13:48:43 +0200
Subject: [PATCH 14/63] Feedback

---
 src/coreclr/clrdefinitions.cmake | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake
index 58d21f418f712f..846f9a7830794b 100644
--- a/src/coreclr/clrdefinitions.cmake
+++ b/src/coreclr/clrdefinitions.cmake
@@ -35,9 +35,7 @@ if(CLR_CMAKE_TARGET_LINUX_MUSL)
   add_definitions(-DNO_FIXED_STACK_LIMIT)
 endif(CLR_CMAKE_TARGET_LINUX_MUSL)
 
-#if(NOT CLR_CMAKE_TARGET_ARCH_WASM)
-  add_definitions(-DDEBUGGING_SUPPORTED)
-#endif()
+add_definitions(-DDEBUGGING_SUPPORTED)
 add_compile_definitions($<$>>:PROFILING_SUPPORTED>)
 add_compile_definitions($<$>:PROFILING_SUPPORTED_DATA>)
 

From 5032d3706d4a42c53b40e91bac52e4e22dd7758f Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Fri, 13 Jun 2025 13:49:06 +0200
Subject: [PATCH 15/63] Fix release build

---
 .../src/System/Runtime/ExceptionServices/AsmOffsets.cs     | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs
index 2544e0222b704b..86cb928e36e89d 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs
@@ -144,9 +144,14 @@ class AsmOffsets
     public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x3c8;
 #else // TARGET_64BIT
     public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x4;
+#if FEATURE_INTERPRETER
     public const int SIZEOF__StackFrameIterator = 0xd4;
-    public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0xb2;
     public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0xd0;
+#else
+    public const int SIZEOF__StackFrameIterator = 0xc4;
+    public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0xc0;
+#endif
+    public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0xb2;
 #endif // TARGET_64BIT
 
 #endif // DEBUG

From c61d5a327f0cb79defdacce35bcc4e0d20f01963 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Fri, 13 Jun 2025 16:56:12 +0200
Subject: [PATCH 16/63] Feedback

Do not special case missing mono_wasm_browser_entropy and just add it
to helpers with an assert
---
 src/coreclr/vm/wasm/helpers.cpp   | 6 ++++++
 src/native/libs/CMakeLists.txt    | 4 ----
 src/native/libs/build-native.proj | 6 ++----
 src/native/minipal/random.c       | 2 +-
 4 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp
index d9fdf89a572d62..67a542d030756a 100644
--- a/src/coreclr/vm/wasm/helpers.cpp
+++ b/src/coreclr/vm/wasm/helpers.cpp
@@ -471,3 +471,9 @@ void _DacGlobals::Initialize()
 }
 
 int g_pDebugger;
+
+extern "C" int32_t mono_wasm_browser_entropy(uint8_t* buffer, int32_t bufferLength)
+{
+    PORTABILITY_ASSERT("mono_wasm_browser_entropy is not implemented");
+    return -1;
+}
diff --git a/src/native/libs/CMakeLists.txt b/src/native/libs/CMakeLists.txt
index a54fa43ed3f902..c90e9b8a45ddc5 100644
--- a/src/native/libs/CMakeLists.txt
+++ b/src/native/libs/CMakeLists.txt
@@ -4,10 +4,6 @@ include(CheckCCompilerFlag)
 
 project(LibsNative C)
 
-if (MONO_RUNTIME)
-    add_definitions(-DMONO_RUNTIME)
-endif()
-
 if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
     # This is our root CMakeList.txt, so we need to set up some global settings and include the minipal here.
     include(../../../eng/native/configurepaths.cmake)
diff --git a/src/native/libs/build-native.proj b/src/native/libs/build-native.proj
index 12421841d8dcda..2b5dcac9ae4a41 100644
--- a/src/native/libs/build-native.proj
+++ b/src/native/libs/build-native.proj
@@ -98,11 +98,9 @@
           Condition="$([MSBuild]::IsOsPlatform(Windows))">
     
         <_BuildNativeArgs Condition="'$(Ninja)' == 'false'">$(_BuildNativeArgs) msbuild
-        <_MonoCMakeArgs Condition="'$(RuntimeFlavor)' == 'Mono'">-DMONO_RUNTIME=1
-        <_MonoCMakeArgs Condition="'$(CMakeArgs)' != ''"> $(_MonoCMakeArgs)
         <_MonoWasmMTCMakeArgs Condition="'$(WasmEnableThreads)' == 'true'">-DMONO_WASM_MT=1
-        <_MonoWasmMTCMakeArgs Condition="'$(CMakeArgs)' != '' or '$(_MonoCMakeArgs)' != ''"> $(_MonoWasmMTCMakeArgs)
-        <_BuildNativeArgs Condition="'$(CMakeArgs)' != '' or '$(_MonoWasmMTCMakeArgs)' != '' or '$(_MonoCMakeArgs)' != ''">$(_BuildNativeArgs) -cmakeargs "$(CMakeArgs)$(_MonoCMakeArgs)$(_MonoWasmMTCMakeArgs)"
+        <_MonoWasmMTCMakeArgs Condition="'$(CMakeArgs)' != ''"> $(_MonoWasmMTCMakeArgs)
+        <_BuildNativeArgs Condition="'$(CMakeArgs)' != '' or '$(_MonoWasmMTCMakeArgs)' != ''">$(_BuildNativeArgs) -cmakeargs "$(CMakeArgs)$(_MonoWasmMTCMakeArgs)"
     
     
     
diff --git a/src/native/minipal/random.c b/src/native/minipal/random.c
index e26ce66d6660c2..3c2b33ac7463b0 100644
--- a/src/native/minipal/random.c
+++ b/src/native/minipal/random.c
@@ -77,7 +77,7 @@ int32_t minipal_get_cryptographically_secure_random_bytes(uint8_t* buffer, int32
 {
     assert(buffer != NULL);
 
-#if defined(__EMSCRIPTEN__) && defined(MONO_RUNTIME)
+#ifdef __EMSCRIPTEN__
     extern int32_t mono_wasm_browser_entropy(uint8_t* buffer, int32_t bufferLength);
     static bool sMissingBrowserCrypto;
     if (!sMissingBrowserCrypto)

From 15e1d83302cccc759be700d666aeb539bafa6777 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Fri, 13 Jun 2025 17:12:56 +0200
Subject: [PATCH 17/63] Feedback

---
 src/coreclr/vm/assembly.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp
index e9f6d3140ab378..a78ad9d913ed1f 100644
--- a/src/coreclr/vm/assembly.cpp
+++ b/src/coreclr/vm/assembly.cpp
@@ -2388,7 +2388,7 @@ DebuggerAssemblyControlFlags Assembly::ComputeDebuggingConfig()
     IfFailThrow(GetDebuggingCustomAttributes(&dacfFlags));
     return (DebuggerAssemblyControlFlags)dacfFlags;
 #else // !DEBUGGING_SUPPORTED
-    return (DebuggerAssemblyControlFlags)0;
+    return DACF_NONE;
 #endif // DEBUGGING_SUPPORTED
 }
 

From 86efb1c602cfcd1824840be4938f8dd7795984cd Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Fri, 13 Jun 2025 22:39:18 +0200
Subject: [PATCH 18/63] Feedback

Use MethodDesc's GetInterpreterCode() instead of GetNativeCode()
---
 src/coreclr/vm/wasm/calldescrworkerwasm.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/coreclr/vm/wasm/calldescrworkerwasm.cpp b/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
index baf171b5df7554..e11ecf799f707a 100644
--- a/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
+++ b/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
@@ -8,13 +8,14 @@ extern "C" void* STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTran
 
 extern "C" void STDCALL CallDescrWorkerInternal(CallDescrData * pCallDescrData)
 {
-    PCODE code = pCallDescrData->pMD->GetNativeCode();
-    if (!code)
+    MethodDesc* pMethod = pCallDescrData->pMD;
+    InterpByteCodeStart* targetIp = pMethod->GetInterpreterCode();
+    if (targetIp == NULL)
     {
         GCX_PREEMP();
-        pCallDescrData->pMD->PrepareInitialCode(CallerGCMode::Coop);
-        code = pCallDescrData->pMD->GetNativeCode();
+        pMethod->PrepareInitialCode(CallerGCMode::Coop);
+        targetIp = pMethod->GetInterpreterCode();
     }
 
-    ExecuteInterpretedMethodWithArgs(((TransitionBlock*)pCallDescrData->pSrc) - 1, code, (int8_t*)pCallDescrData->pSrc, pCallDescrData->nArgsSize, pCallDescrData->returnValue);
+    ExecuteInterpretedMethodWithArgs(((TransitionBlock*)pCallDescrData->pSrc) - 1, (TADDR)targetIp, (int8_t*)pCallDescrData->pSrc, pCallDescrData->nArgsSize, pCallDescrData->returnValue);
 }

From c6da89ea1b012689ee61e19e5c0e0e2efaa912d1 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Fri, 13 Jun 2025 22:55:29 +0200
Subject: [PATCH 19/63] Feedback

Do not use FEATURE_JIT for callstub exclusion, until we support it on wasm, use TARGET_WASM instead.

Also update build after merge
---
 src/coreclr/vm/callstubgenerator.cpp |  4 ++--
 src/coreclr/vm/ceemain.cpp           |  2 +-
 src/coreclr/vm/interpexec.cpp        | 15 ++++++++++-----
 src/coreclr/vm/jitinterface.cpp      |  6 +++++-
 4 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/src/coreclr/vm/callstubgenerator.cpp b/src/coreclr/vm/callstubgenerator.cpp
index 5b5a0e905993e8..75db73b1cfaef5 100644
--- a/src/coreclr/vm/callstubgenerator.cpp
+++ b/src/coreclr/vm/callstubgenerator.cpp
@@ -1,7 +1,7 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-#if defined(FEATURE_INTERPRETER) && defined(FEATURE_JIT)
+#if defined(FEATURE_INTERPRETER) && !defined(TARGET_WASM)
 
 #include "callstubgenerator.h"
 #include "ecall.h"
@@ -1780,4 +1780,4 @@ CallStubGenerator::ReturnType CallStubGenerator::GetReturnType(ArgIterator *pArg
     return ReturnTypeVoid;
 }
 
-#endif // FEATURE_INTERPRETER && FEATURE_JIT
+#endif // FEATURE_INTERPRETER && !TARGET_WASM
diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp
index 602a54fc02b5ac..ab9ad9c5581d23 100644
--- a/src/coreclr/vm/ceemain.cpp
+++ b/src/coreclr/vm/ceemain.cpp
@@ -663,7 +663,7 @@ void EEStartupHelper()
 
         Thread::StaticInitialize();
 
-#ifdef FEATURE_INTERPRETER
+#if defined(FEATURE_INTERPRETER) && !defined(TARGET_WASM)
         InitCallStubGenerator();
 #endif // FEATURE_INTERPRETER
 
diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp
index 00297afbb5dcd6..1fb79b463cfe86 100644
--- a/src/coreclr/vm/interpexec.cpp
+++ b/src/coreclr/vm/interpexec.cpp
@@ -20,7 +20,7 @@ FCDECL1(double, JIT_ULng2Dbl, uint64_t val);
 FCDECL1(float, JIT_Lng2Flt, int64_t val);
 FCDECL1(double, JIT_Lng2Dbl, int64_t val);
 
-#ifdef FEATURE_JIT
+#ifndef TARGET_WASM
 #include "callstubgenerator.h"
 
 void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet)
@@ -116,7 +116,7 @@ CallStubHeader *CreateNativeToInterpreterCallStub(InterpMethod* pInterpMethod)
     return pHeader;
 }
 
-#endif // FEATURE_JIT
+#endif // !TARGET_WASM
 
 typedef void* (*HELPER_FTN_PP)(void*);
 typedef void* (*HELPER_FTN_BOX_UNBOX)(MethodTable*, void*);
@@ -1481,6 +1481,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
 
                 case INTOP_CALLI:
                 {
+#ifndef TARGET_WASM
                     returnOffset = ip[1];
                     callArgsOffset = ip[2];
                     int32_t calliFunctionPointerVar = ip[3];
@@ -1490,6 +1491,9 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
                     ip += 5;
 
                     InvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), pCallStub, stack + callArgsOffset, stack + returnOffset);
+#else
+                    EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Attempted to execute calli instruction on a non-JIT build"));
+#endif // TARGET_WASM
                     break;
                 }
 
@@ -1525,12 +1529,13 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
                         }
                         if (targetIp == NULL)
                         {
-#ifdef FEATURE_JIT
+#ifndef TARGET_WASM
                             // If we didn't get the interpreter code pointer setup, then this is a method we need to invoke as a compiled method.
                             InvokeCompiledMethod(targetMethod, stack + callArgsOffset, stack + returnOffset);
 #else
-                        EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Attempted to execute non-interpreter code from interpreter on a non-JIT build"));
-#endif // FEATURE_JIT                            break;
+                            EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Attempted to execute non-interpreter code from interpreter on a non-JIT build"));
+#endif // !TARGET_WASM
+                            break;
                         }
                     }
 
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index d55f2969a1fe24..dc7f38f036c821 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11297,9 +11297,11 @@ LPVOID CEEInfo::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig)
 
 #ifdef FEATURE_INTERPRETER
 
+
 LPVOID CInterpreterJitInfo::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig)
 {
     void* result = NULL;
+#ifndef TARGET_WASM
     JIT_TO_EE_TRANSITION();
 
     Module* module = GetModule(szMetaSig->scope);
@@ -11313,7 +11315,9 @@ LPVOID CInterpreterJitInfo::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* sz
     result = callStubGenerator.GenerateCallStubForSig(sig);
 
     EE_TO_JIT_TRANSITION();
-
+#else
+    PLATFORM_UNSUPPORTED("GetCookieForInterpreterCalliSig is not supported on WebAssembly");
+#endif // !TARGET_WASM
     return result;
 }
 

From d1eb90a34b4a2307635729a40dfb6153120626cc Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Sat, 14 Jun 2025 11:25:03 +0200
Subject: [PATCH 20/63] Feedback

Use PORTABILITY_ASSERT
---
 src/coreclr/vm/interpexec.cpp   | 4 ++--
 src/coreclr/vm/jitinterface.cpp | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp
index 1fb79b463cfe86..9989e44dfc1361 100644
--- a/src/coreclr/vm/interpexec.cpp
+++ b/src/coreclr/vm/interpexec.cpp
@@ -1492,7 +1492,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
 
                     InvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), pCallStub, stack + callArgsOffset, stack + returnOffset);
 #else
-                    EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Attempted to execute calli instruction on a non-JIT build"));
+                    PORTABILITY_ASSERT("Attempted to execute calli instruction on wasm, this is not yet implemented");
 #endif // TARGET_WASM
                     break;
                 }
@@ -1533,7 +1533,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
                             // If we didn't get the interpreter code pointer setup, then this is a method we need to invoke as a compiled method.
                             InvokeCompiledMethod(targetMethod, stack + callArgsOffset, stack + returnOffset);
 #else
-                            EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Attempted to execute non-interpreter code from interpreter on a non-JIT build"));
+                            PORTABILITY_ASSERT("Attempted to execute non-interpreter code from interpreter on wasm, this is not yet implemented");
 #endif // !TARGET_WASM
                             break;
                         }
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index dc7f38f036c821..b6b7fd86646861 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11316,7 +11316,7 @@ LPVOID CInterpreterJitInfo::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* sz
 
     EE_TO_JIT_TRANSITION();
 #else
-    PLATFORM_UNSUPPORTED("GetCookieForInterpreterCalliSig is not supported on WebAssembly");
+    PORTABILITY_ASSERT("GetCookieForInterpreterCalliSig is not supported on wasm yet");
 #endif // !TARGET_WASM
     return result;
 }

From 063fc3b59fbc5cf9de5a71358bbeab12b853dcd9 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 16 Jun 2025 17:12:10 +0200
Subject: [PATCH 21/63] Feedback, add FEATURE_PEIMAGE_FLAT_LAYOUT

---
 src/coreclr/clrdefinitions.cmake  |  4 ++++
 src/coreclr/clrfeatures.cmake     |  1 +
 src/coreclr/vm/domainassembly.cpp |  2 ++
 src/coreclr/vm/peassembly.cpp     | 12 +++++++++++-
 src/coreclr/vm/peassembly.h       |  9 +++++++++
 src/coreclr/vm/peassembly.inl     |  2 +-
 src/coreclr/vm/peimage.cpp        |  2 ++
 7 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake
index 846f9a7830794b..3ea9afff9c0a5d 100644
--- a/src/coreclr/clrdefinitions.cmake
+++ b/src/coreclr/clrdefinitions.cmake
@@ -4,6 +4,10 @@ if(FEATURE_JIT)
   add_compile_definitions(FEATURE_JIT)
 endif(FEATURE_JIT)
 
+if(FEATURE_PEIMAGE_FLAT_LAYOUT)
+  add_compile_definitions(FEATURE_PEIMAGE_FLAT_LAYOUT)
+endif(FEATURE_PEIMAGE_FLAT_LAYOUT)
+
 add_compile_definitions($<$>:DACCESS_COMPILE>)
 
 if (CLR_CMAKE_TARGET_UNIX)
diff --git a/src/coreclr/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake
index bdc10b6aa719e7..4740667e9f28b8 100644
--- a/src/coreclr/clrfeatures.cmake
+++ b/src/coreclr/clrfeatures.cmake
@@ -1,5 +1,6 @@
 if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
   set(FEATURE_JIT 1)
+  set(FEATURE_PEIMAGE_FLAT_LAYOUT 1)
 endif()
 
 if(CLR_CMAKE_TARGET_TIZEN_LINUX)
diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp
index 653117ba3ecc29..7fd463d4a0c179 100644
--- a/src/coreclr/vm/domainassembly.cpp
+++ b/src/coreclr/vm/domainassembly.cpp
@@ -38,8 +38,10 @@ DomainAssembly::DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoader
 
     m_pAssembly->SetDomainAssembly(this);
 
+#ifndef FEATURE_PEIMAGE_FLAT_LAYOUT
     // Creating the Assembly should have ensured the PEAssembly is loaded
     _ASSERT(GetPEAssembly()->IsLoaded());
+#endif
 }
 
 DomainAssembly::~DomainAssembly()
diff --git a/src/coreclr/vm/peassembly.cpp b/src/coreclr/vm/peassembly.cpp
index adc08d6fc020b6..bacf0300e2fd10 100644
--- a/src/coreclr/vm/peassembly.cpp
+++ b/src/coreclr/vm/peassembly.cpp
@@ -68,7 +68,13 @@ void PEAssembly::EnsureLoaded()
         RETURN;
 
     // Ensure that loaded layout is available.
-    PEImageLayout* pLayout = GetPEImage()->GetOrCreateLayout(PEImageLayout::LAYOUT_LOADED);
+    PEImageLayout* pLayout = GetPEImage()->GetOrCreateLayout(
+#ifdef FEATURE_PEIMAGE_FLAT_LAYOUT
+        PEImageLayout::LAYOUT_FLAT
+#else
+        PEImageLayout::LAYOUT_LOADED
+#endif
+        );
     if (pLayout == NULL)
     {
         EEFileLoadException::Throw(this, COR_E_BADIMAGEFORMAT, NULL);
@@ -260,7 +266,11 @@ TADDR PEAssembly::GetIL(RVA il)
     CONTRACT_END;
 
     PEImageLayout *image = NULL;
+#ifdef FEATURE_PEIMAGE_FLAT_LAYOUT
+    image = GetFlatLayout();
+#else
     image = GetLoadedLayout();
+#endif
 
 #ifndef DACCESS_COMPILE
     // Verify that the IL blob is valid before giving it out
diff --git a/src/coreclr/vm/peassembly.h b/src/coreclr/vm/peassembly.h
index 43b14abe9fe41d..6b58a0f4248e21 100644
--- a/src/coreclr/vm/peassembly.h
+++ b/src/coreclr/vm/peassembly.h
@@ -258,6 +258,15 @@ class PEAssembly final
         return GetPEImage()->GetLoadedLayout();
     };
 
+    PTR_PEImageLayout GetFlatLayout()
+    {
+        LIMITED_METHOD_CONTRACT;
+        SUPPORTS_DAC;
+
+        _ASSERTE(HasPEImage());
+        return GetPEImage()->GetFlatLayout();
+    };
+
     BOOL IsLoaded()
     {
         return IsReflectionEmit() || HasLoadedPEImage();
diff --git a/src/coreclr/vm/peassembly.inl b/src/coreclr/vm/peassembly.inl
index eb485215f14cf2..3153136eecd897 100644
--- a/src/coreclr/vm/peassembly.inl
+++ b/src/coreclr/vm/peassembly.inl
@@ -329,7 +329,7 @@ inline BOOL PEAssembly::IsReadyToRun()
     }
     CONTRACTL_END;
 
-    if (HasPEImage())
+    if (HasPEImage() && HasLoadedPEImage())
     {
         return GetLoadedLayout()->HasReadyToRunHeader();
     }
diff --git a/src/coreclr/vm/peimage.cpp b/src/coreclr/vm/peimage.cpp
index 090c2ed5b864ed..4614ccafda658a 100644
--- a/src/coreclr/vm/peimage.cpp
+++ b/src/coreclr/vm/peimage.cpp
@@ -636,11 +636,13 @@ PTR_PEImageLayout PEImage::GetOrCreateLayoutInternal(DWORD imageLayoutMask)
 
         _ASSERTE(bIsLoadedLayoutSuitable || bIsFlatLayoutSuitable);
 
+#ifndef FEATURE_PEIMAGE_FLAT_LAYOUT
         if (bIsLoadedLayoutPreferred)
         {
             _ASSERTE(bIsLoadedLayoutSuitable);
             pRetVal = PEImage::CreateLoadedLayout(!bIsFlatLayoutSuitable);
         }
+#endif
 
         if (pRetVal == NULL)
         {

From 22acc25e1b6a7fc0edbff9cfa6b37f0125948ebd Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 16 Jun 2025 17:19:56 +0200
Subject: [PATCH 22/63] Revert mapping changes for PE loaded layout

We use the flat layout now
---
 src/coreclr/pal/src/map/map.cpp | 43 ---------------------------------
 1 file changed, 43 deletions(-)

diff --git a/src/coreclr/pal/src/map/map.cpp b/src/coreclr/pal/src/map/map.cpp
index 6f33f4ad4dc399..8900ccd1058c01 100644
--- a/src/coreclr/pal/src/map/map.cpp
+++ b/src/coreclr/pal/src/map/map.cpp
@@ -1928,9 +1928,7 @@ MAPmmapAndRecord(
 
     // Ensure address and offset arguments mmap() are page-aligned.
     _ASSERTE(OffsetWithinPage(offset - adjust) == 0);
-#ifndef __wasm__
     _ASSERTE(OffsetWithinPage((off_t)pvBaseAddress) == 0);
-#endif
 
 #ifdef __APPLE__
     if ((prot & PROT_EXEC) != 0 && IsRunningOnMojaveHardenedRuntime())
@@ -1982,30 +1980,6 @@ MAPmmapAndRecord(
 
     }
     else
-#elif defined(__wasm__)
-    // WebAssembly doesn't support mmap() with location hints
-    if (pvBaseAddress != nullptr)
-    {
-        LPVOID pvMappedFile = mmap(NULL, len + adjust, prot, flags, fd, offset - adjust);
-        if (MAP_FAILED == pvMappedFile)
-        {
-            ERROR_(LOADER)("mmap failed with code %d: %s.\n", errno, strerror(errno));
-            palError = FILEGetLastErrorFromErrno();
-            return palError;
-        }
-        else
-        {
-            memcpy(pvBaseAddress, pvMappedFile, len + adjust);
-            if (-1 == munmap(pvMappedFile, len + adjust))
-            {
-                ERROR_(LOADER)("Unable to unmap the file. Expect trouble.\n");
-                if (NO_ERROR == palError)
-                    palError = FILEGetLastErrorFromErrno();
-                return palError;
-            }
-        }
-    }
-    else
 #endif
     {
         pvBaseAddress = mmap(pvBaseAddress, len + adjust, prot, flags, fd, offset - adjust);
@@ -2264,13 +2238,6 @@ void * MAPMapPEFile(HANDLE hFile, off_t offset)
     size_t headerSize;
     headerSize = GetVirtualPageSize(); // if there are lots of sections, this could be wrong
 
-#ifdef __wasm__
-    if (headerSize > ntHeader.OptionalHeader.SectionAlignment)
-    {
-        headerSize = ntHeader.OptionalHeader.SectionAlignment;
-    }
-#endif // __wasm__
-
     if (forceOveralign)
     {
         loadedBase = ALIGN_UP(loadedBase, ntHeader.OptionalHeader.SectionAlignment);
@@ -2330,11 +2297,7 @@ void * MAPMapPEFile(HANDLE hFile, off_t offset)
 
     void* prevSectionEndAligned;
     // the first "section" for our purposes is the header
-#ifndef __wasm__
     prevSectionEndAligned = ALIGN_UP((char*)loadedHeader + headerSize, GetVirtualPageSize());
-#else
-    prevSectionEndAligned = ALIGN_UP((char*)loadedHeader + headerSize, ntHeader.OptionalHeader.SectionAlignment);
-#endif // __wasm__
 
     for (unsigned i = 0; i < numSections; ++i)
     {
@@ -2366,14 +2329,12 @@ void * MAPMapPEFile(HANDLE hFile, off_t offset)
             goto doneReleaseMappingCriticalSection;
         }
 
-#ifndef __wasm__
         if (OffsetWithinPage((off_t)sectionBase) != OffsetWithinPage(offset + currentHeader.PointerToRawData))
         {
             ERROR_(LOADER)("can't map section if data and VA hint have different page alignment %d\n", i);
             palError = ERROR_INVALID_PARAMETER;
             goto doneReleaseMappingCriticalSection;
         }
-#endif // !__wasm__
 
         // Is there space between the previous section and this one? If so, add a PROT_NONE mapping to cover it.
         if (prevSectionEndAligned < sectionBaseAligned)
@@ -2429,11 +2390,7 @@ void * MAPMapPEFile(HANDLE hFile, off_t offset)
         }
 #endif // _DEBUG
 
-#ifndef __wasm__
         prevSectionEndAligned = ALIGN_UP((char*)sectionBase + currentHeader.SizeOfRawData, GetVirtualPageSize()); // round up to page boundary
-#else
-        prevSectionEndAligned = ALIGN_UP((char*)sectionBase + currentHeader.SizeOfRawData, ntHeader.OptionalHeader.SectionAlignment); // round up to page boundary
-#endif // __wasm__
     }
 
     // Is there space after the last section and before the end of the mapped image? If so, add a PROT_NONE mapping to cover it.

From c93a61b139592a291c922e445f506c1013c1bac5 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 16 Jun 2025 17:31:32 +0200
Subject: [PATCH 23/63] Feedback, change call order of execute interp method

---
 src/coreclr/vm/prestub.cpp | 32 +++++++++++++++++++++-----------
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp
index 0c6cdce552a57f..abf28dc874f82c 100644
--- a/src/coreclr/vm/prestub.cpp
+++ b/src/coreclr/vm/prestub.cpp
@@ -1991,23 +1991,24 @@ extern "C" PCODE STDCALL PreStubWorker(TransitionBlock* pTransitionBlock, Method
 }
 
 #ifdef FEATURE_INTERPRETER
-extern "C" void* STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, void* retBuff)
+static InterpThreadContext* GetInterpThreadContext()
 {
-    // Argument registers are in the TransitionBlock
-    // The stack arguments are right after the pTransitionBlock
     Thread *pThread = GetThread();
     InterpThreadContext *threadContext = pThread->GetInterpThreadContext();
     if (threadContext == nullptr || threadContext->pStackStart == nullptr)
     {
         COMPlusThrow(kOutOfMemoryException);
     }
-    int8_t *sp = threadContext->pStackPointer;
 
-    // copy the arguments to the stack
-    if (size > 0 && pArgs != nullptr)
-    {
-        memcpy(sp, pArgs, size);
-    }
+    return threadContext;
+}
+
+extern "C" void* STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, void* retBuff)
+{
+    // Argument registers are in the TransitionBlock
+    // The stack arguments are right after the pTransitionBlock
+    InterpThreadContext *threadContext = GetInterpThreadContext();
+    int8_t *sp = threadContext->pStackPointer;
 
     // This construct ensures that the InterpreterFrame is always stored at a higher address than the
     // InterpMethodContextFrame. This is important for the stack walking code.
@@ -2034,9 +2035,18 @@ extern "C" void* STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTran
     return frames.interpMethodContextFrame.pRetVal;
 }
 
-extern "C" void* STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, void* retBuff)
+extern "C" void* STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, void* retBuff)
 {
-    return ExecuteInterpretedMethodWithArgs(pTransitionBlock, byteCodeAddr, nullptr, 0, retBuff);
+    // copy the arguments to the stack
+    if (size > 0 && pArgs != nullptr)
+    {
+        InterpThreadContext *threadContext = GetInterpThreadContext();
+        int8_t *sp = threadContext->pStackPointer;
+
+        memcpy(sp, pArgs, size);
+    }
+
+    return ExecuteInterpretedMethod(pTransitionBlock, byteCodeAddr, retBuff);
 }
 #endif // FEATURE_INTERPRETER
 

From 406594a6c05e80f928efc4c27d561f2b20836c6c Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 16 Jun 2025 17:34:48 +0200
Subject: [PATCH 24/63] Feedback, change condition to avoid dynamic loads in
 corhost

---
 src/coreclr/vm/corhost.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp
index c62748f85bf934..28d290bdbe0311 100644
--- a/src/coreclr/vm/corhost.cpp
+++ b/src/coreclr/vm/corhost.cpp
@@ -636,7 +636,7 @@ HRESULT CorHost2::CreateAppDomainWithManager(
             sAppPaths));
     }
 
-#if defined(TARGET_UNIX) && !defined(TARGET_WASM)
+#if defined(TARGET_UNIX) && !defined(FEATURE_STATICALLY_LINKED)
     if (!g_coreclr_embedded)
     {
         // Check if the current code is executing in the single file host or in libcoreclr.so. The libSystem.Native is linked

From 3c58f83c8a2c6ff2aa60a8b66d28ab22bc814c79 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 17 Jun 2025 16:43:03 +0200
Subject: [PATCH 25/63] Increase stub size to fit interpreter stub data

This way we get further in the initialization

    log: stdout: Interpreter compile method System.AppContext:Setup(ptr,ptr,int)
    log: stdout: Interpreter compile method System.Diagnostics.Debug:Assert(bool,System.String)
    log: stdout: Interpreter compile method System.Collections.Generic.Dictionary`2[System.__Canon,System.__Canon]:.ctor(int,System.Collections.Generic.IEqualityComparer`1[System.__Canon])
    log: stdout: Interpreter compile method System.Diagnostics.Debug:Assert(bool,System.String,System.String)
    log: stdout: Interpreter compile method System.Collections.Generic.Dictionary`2[System.__Canon,System.__Canon]:.ctor(int)
---
 src/coreclr/vm/precode.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h
index bff78896df4033..23f569ab1737ba 100644
--- a/src/coreclr/vm/precode.h
+++ b/src/coreclr/vm/precode.h
@@ -52,7 +52,7 @@ EXTERN_C VOID STDCALL PrecodeRemotingThunk();
 
 #elif defined(TARGET_WASM)
 
-#define SIZEOF_PRECODE_BASE         8 // 2*pointer size
+#define SIZEOF_PRECODE_BASE         12 // 3*pointer size
 #define OFFSETOF_PRECODE_TYPE       0
 
 #endif // TARGET_AMD64
@@ -130,7 +130,7 @@ struct StubPrecode
     static const SIZE_T CodeSize = 24;
 #elif defined(TARGET_WASM)
     static const int Type = 0;
-    static const SIZE_T CodeSize = 8;
+    static const SIZE_T CodeSize = 12;
 #endif // TARGET_AMD64
 
     BYTE m_code[CodeSize];
@@ -412,7 +412,7 @@ struct FixupPrecode
     static const int FixupCodeOffset = 10;
 #elif defined(TARGET_WASM)
     static const int Type = 2;
-    static const SIZE_T CodeSize = 8;
+    static const SIZE_T CodeSize = 12;
     static const int FixupCodeOffset = 0;
 #endif // TARGET_AMD64
 

From caec18218f064dd41230a39e37304ce00c7ae8c9 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 17 Jun 2025 22:46:08 +0200
Subject: [PATCH 26/63] Update precode sizes, feedback and size check

---
 src/coreclr/vm/precode.h | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h
index 23f569ab1737ba..2ca9c648d3fea5 100644
--- a/src/coreclr/vm/precode.h
+++ b/src/coreclr/vm/precode.h
@@ -52,7 +52,7 @@ EXTERN_C VOID STDCALL PrecodeRemotingThunk();
 
 #elif defined(TARGET_WASM)
 
-#define SIZEOF_PRECODE_BASE         12 // 3*pointer size
+#define SIZEOF_PRECODE_BASE         2*sizeof(void*)
 #define OFFSETOF_PRECODE_TYPE       0
 
 #endif // TARGET_AMD64
@@ -130,7 +130,7 @@ struct StubPrecode
     static const SIZE_T CodeSize = 24;
 #elif defined(TARGET_WASM)
     static const int Type = 0;
-    static const SIZE_T CodeSize = 12;
+    static const SIZE_T CodeSize = 3*sizeof(void*);
 #endif // TARGET_AMD64
 
     BYTE m_code[CodeSize];
@@ -412,7 +412,7 @@ struct FixupPrecode
     static const int FixupCodeOffset = 10;
 #elif defined(TARGET_WASM)
     static const int Type = 2;
-    static const SIZE_T CodeSize = 12;
+    static const SIZE_T CodeSize = 2*sizeof(void*);
     static const int FixupCodeOffset = 0;
 #endif // TARGET_AMD64
 
@@ -562,7 +562,7 @@ inline BYTE StubPrecode::GetType()
     LIMITED_METHOD_DAC_CONTRACT;
     TADDR type = GetData()->Type;
 
-#ifdef __wasm__
+#ifdef TARGET_WASM
     return (BYTE)type;
 #endif
 
@@ -828,6 +828,9 @@ static_assert_no_msg(sizeof(Precode) <= sizeof(NDirectImportPrecode));
 static_assert_no_msg(sizeof(Precode) <= sizeof(FixupPrecode));
 static_assert_no_msg(sizeof(Precode) <= sizeof(ThisPtrRetBufPrecode));
 
+// check that the InterpreterPrecodeData fits into the StubPrecode
+static_assert_no_msg(sizeof(InterpreterPrecodeData) <= sizeof(StubPrecode));
+
 #ifndef DACCESS_COMPILE
 // A summary of the precode layout for diagnostic purposes
 struct PrecodeMachineDescriptor

From 9a761d7d084a578477b87f7de390086ff1231fa7 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 18 Jun 2025 15:58:12 +0200
Subject: [PATCH 27/63] Feedback, TODO, transition block

---
 src/coreclr/vm/callhelpers.cpp              | 3 +++
 src/coreclr/vm/callhelpers.h                | 1 +
 src/coreclr/vm/wasm/calldescrworkerwasm.cpp | 2 +-
 src/coreclr/vm/wasm/helpers.cpp             | 8 ++++----
 4 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/src/coreclr/vm/callhelpers.cpp b/src/coreclr/vm/callhelpers.cpp
index c99644c1ff5d33..92a9a60b84ec63 100644
--- a/src/coreclr/vm/callhelpers.cpp
+++ b/src/coreclr/vm/callhelpers.cpp
@@ -515,6 +515,9 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *
     CallDescrData callDescrData;
 
     callDescrData.pSrc = pTransitionBlock + sizeof(TransitionBlock);
+#ifdef TARGET_WASM
+    callDescrData.pTransitionBlock = (TransitionBlock*)pTransitionBlock;
+#endif
     _ASSERTE((nStackBytes % TARGET_POINTER_SIZE) == 0);
     callDescrData.numStackSlots = nStackBytes / TARGET_POINTER_SIZE;
 #ifdef CALLDESCR_ARGREGS
diff --git a/src/coreclr/vm/callhelpers.h b/src/coreclr/vm/callhelpers.h
index 6454b580f96ccc..aa6af8bdbe9875 100644
--- a/src/coreclr/vm/callhelpers.h
+++ b/src/coreclr/vm/callhelpers.h
@@ -31,6 +31,7 @@ struct CallDescrData
 #ifdef TARGET_WASM
     MethodDesc*                 pMD;
     size_t                      nArgsSize;
+    TransitionBlock*            pTransitionBlock;
 #endif
 
 #ifdef CALLDESCR_RETBUFFARGREG
diff --git a/src/coreclr/vm/wasm/calldescrworkerwasm.cpp b/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
index e11ecf799f707a..afbf3e07ff7913 100644
--- a/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
+++ b/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
@@ -17,5 +17,5 @@ extern "C" void STDCALL CallDescrWorkerInternal(CallDescrData * pCallDescrData)
         targetIp = pMethod->GetInterpreterCode();
     }
 
-    ExecuteInterpretedMethodWithArgs(((TransitionBlock*)pCallDescrData->pSrc) - 1, (TADDR)targetIp, (int8_t*)pCallDescrData->pSrc, pCallDescrData->nArgsSize, pCallDescrData->returnValue);
+    ExecuteInterpretedMethodWithArgs(pCallDescrData->pTransitionBlock, (TADDR)targetIp, (int8_t*)pCallDescrData->pSrc, pCallDescrData->nArgsSize, pCallDescrData->returnValue);
 }
diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp
index 67a542d030756a..b4d2691299f401 100644
--- a/src/coreclr/vm/wasm/helpers.cpp
+++ b/src/coreclr/vm/wasm/helpers.cpp
@@ -230,7 +230,7 @@ extern "C" void STDCALL JIT_ByRefWriteBarrier()
 
 void InitJITHelpers1()
 {
-    /* no-op TODO do we need to do anything for the interpreter? */
+    /* no-op WASM-TODO do we need to do anything for the interpreter? */
 }
 
 extern "C" HRESULT __cdecl CorDBGetInterface(DebugInterface** rcInterface)
@@ -439,18 +439,18 @@ EXTERN_C void STDMETHODCALLTYPE ProfileTailcallNaked(UINT_PTR clientData)
 
 void InitJITWriteBarrierHelpers()
 {
-    // TODO: implement me
+    // WASM-TODO: implement me
 }
 
 int StompWriteBarrierEphemeral(bool isRuntimeSuspended)
 {
-    // TODO: implement me
+    // WASM-TODO: implement me
     return 0;
 }
 
 int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
 {
-    // TODO: implement me
+    // WASM-TODO: implement me
     return 0;
 }
 

From dda8b41aebc48b8ac297ed6a74ca31ece1e17a8e Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 18 Jun 2025 16:46:22 +0200
Subject: [PATCH 28/63] Feedback

---
 src/coreclr/vm/precode.cpp | 10 +++++-----
 src/coreclr/vm/precode.h   |  2 ++
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/coreclr/vm/precode.cpp b/src/coreclr/vm/precode.cpp
index 6e845484cd73e5..f0206e206b2e9f 100644
--- a/src/coreclr/vm/precode.cpp
+++ b/src/coreclr/vm/precode.cpp
@@ -133,8 +133,8 @@ MethodDesc* Precode::GetMethodDesc(BOOL fSpeculative /*= FALSE*/)
     TADDR pMD = (TADDR)NULL;
 
     PrecodeType precodeType = GetType();
-#ifdef __wasm__
-    pMD = *(TADDR*)(m_data + OFFSETOF_PRECODE_TYPE + 4);
+#ifdef TARGET_WASM
+    pMD = *(TADDR*)(m_data + OFFSETOF_PRECODE_MD);
 #else
     switch (precodeType)
     {
@@ -168,7 +168,7 @@ MethodDesc* Precode::GetMethodDesc(BOOL fSpeculative /*= FALSE*/)
     default:
         break;
     }
-#endif // __wasm__
+#endif // TARGET_WASM
 
     if (pMD == (TADDR)NULL)
     {
@@ -291,9 +291,9 @@ void Precode::Init(Precode* pPrecodeRX, PrecodeType t, MethodDesc* pMD, LoaderAl
 {
     LIMITED_METHOD_CONTRACT;
 
-#ifdef __wasm__  
+#ifdef TARGET_WASM
     m_data[OFFSETOF_PRECODE_TYPE] = t;
-    *(TADDR*)(m_data + OFFSETOF_PRECODE_TYPE + 4) = (TADDR)pMD;
+    *(TADDR*)(m_data + OFFSETOF_PRECODE_MD) = (TADDR)pMD;
 #else
     switch (t) {
     case PRECODE_STUB:
diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h
index 2ca9c648d3fea5..6890ff884e6ba7 100644
--- a/src/coreclr/vm/precode.h
+++ b/src/coreclr/vm/precode.h
@@ -52,8 +52,10 @@ EXTERN_C VOID STDCALL PrecodeRemotingThunk();
 
 #elif defined(TARGET_WASM)
 
+// on wasm we have "fake" precode, with precode type and MethodDesc information stored
 #define SIZEOF_PRECODE_BASE         2*sizeof(void*)
 #define OFFSETOF_PRECODE_TYPE       0
+#define OFFSETOF_PRECODE_MD         4
 
 #endif // TARGET_AMD64
 

From ee635033b8f636fb98e6f02f0498accb0ce7162f Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Fri, 20 Jun 2025 07:29:00 +0200
Subject: [PATCH 29/63] Use coreclr_static library for wasm

And do not build coreclr
---
 .../dlls/mscoree/coreclr/CMakeLists.txt       | 54 +++++++++++--------
 src/coreclr/hosts/corewasmrun/CMakeLists.txt  |  2 +-
 2 files changed, 32 insertions(+), 24 deletions(-)

diff --git a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
index 5b5e471718f101..67b7d6ce6e77bb 100644
--- a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
+++ b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
@@ -56,25 +56,21 @@ endif (CLR_CMAKE_HOST_WIN32)
 
 add_definitions(-DFX_VER_INTERNALNAME_STR=CoreCLR.dll)
 
-if (CLR_CMAKE_TARGET_ARCH_WASM)
-    set(LINK_TYPE STATIC)
-else()
-    set(LINK_TYPE SHARED)
-endif()
-
-add_library_clr(coreclr
-    ${LINK_TYPE}
-    ${CLR_SOURCES}
-)
+if (NOT CLR_CMAKE_HOST_ARCH_WASM)
+    add_library_clr(coreclr
+        SHARED
+        ${CLR_SOURCES}
+    )
 
-add_custom_target(coreclr_exports DEPENDS ${EXPORTS_FILE})
-add_custom_target(coreclr_def DEPENDS ${DEF_FILE})
+    add_custom_target(coreclr_exports DEPENDS ${EXPORTS_FILE})
+    add_custom_target(coreclr_def DEPENDS ${DEF_FILE})
 
-add_dependencies(coreclr coreclr_def)
-add_dependencies(coreclr coreclr_exports)
+    add_dependencies(coreclr coreclr_def)
+    add_dependencies(coreclr coreclr_exports)
 
-set_property(TARGET coreclr APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION})
-set_property(TARGET coreclr APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE})
+    set_property(TARGET coreclr APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION})
+    set_property(TARGET coreclr APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE})
+endif(NOT CLR_CMAKE_HOST_ARCH_WASM)
 
 if (CLR_CMAKE_HOST_UNIX AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
     set(LIB_UNWINDER unwinder_wks)
@@ -180,16 +176,25 @@ if(FEATURE_PERFTRACING)
     endif(CLR_CMAKE_TARGET_LINUX)
 endif(FEATURE_PERFTRACING)
 
-if(FEATURE_STATICALLY_LINKED)
+if(FEATURE_STATICALLY_LINKED AND NOT CLR_CMAKE_HOST_ARCH_WASM)
     set(CLRJIT_STATIC clrjit_static)
-endif(FEATURE_STATICALLY_LINKED)
+endif(FEATURE_STATICALLY_LINKED AND NOT CLR_CMAKE_HOST_ARCH_WASM)
+
+if(NOT CLR_CMAKE_HOST_ARCH_WASM)
+    set(CEE_WKS_STATIC cee_wks_mergeable)
+else()
+    set(CEE_WKS_STATIC cee_wks)
+endif(NOT CLR_CMAKE_HOST_ARCH_WASM)
 
 if (CLR_CMAKE_TARGET_OSX)
     find_library(FOUNDATION Foundation REQUIRED)
 endif()
 
-target_link_libraries(coreclr PUBLIC ${CORECLR_LIBRARIES} ${CLRJIT_STATIC} cee_wks_core cee_wks ${FOUNDATION})
-target_link_libraries(coreclr_static PUBLIC ${CORECLR_LIBRARIES} cee_wks_core clrjit_static cee_wks_mergeable ${FOUNDATION})
+if(NOT CLR_CMAKE_HOST_ARCH_WASM)
+    target_link_libraries(coreclr PUBLIC ${CORECLR_LIBRARIES} ${CLRJIT_STATIC} cee_wks_core cee_wks ${FOUNDATION})
+endif(NOT CLR_CMAKE_HOST_ARCH_WASM)
+
+target_link_libraries(coreclr_static PUBLIC ${CORECLR_LIBRARIES} cee_wks_core ${CLRJIT_STATIC} ${CEE_WKS_STATIC} ${FOUNDATION})
 target_compile_definitions(coreclr_static PUBLIC CORECLR_EMBEDDED)
 
 if (CLR_CMAKE_HOST_ANDROID)
@@ -239,10 +244,13 @@ if(CLR_CMAKE_TARGET_WIN32)
 endif(CLR_CMAKE_TARGET_WIN32)
 
 # add the install targets
-install_clr(TARGETS coreclr DESTINATIONS . sharedFramework COMPONENT runtime)
-if(CLR_CMAKE_HOST_MACCATALYST OR CLR_CMAKE_HOST_IOS OR CLR_CMAKE_HOST_TVOS OR CLR_CMAKE_HOST_ANDROID)
+if(NOT CLR_CMAKE_HOST_ARCH_WASM)
+    install_clr(TARGETS coreclr DESTINATIONS . sharedFramework COMPONENT runtime)
+endif(NOT CLR_CMAKE_HOST_ARCH_WASM)
+
+if(CLR_CMAKE_HOST_MACCATALYST OR CLR_CMAKE_HOST_IOS OR CLR_CMAKE_HOST_TVOS OR CLR_CMAKE_HOST_ANDROID OR CLR_CMAKE_HOST_ARCH_WASM)
     install_clr(TARGETS coreclr_static DESTINATIONS . sharedFramework COMPONENT runtime)
-endif(CLR_CMAKE_HOST_MACCATALYST OR CLR_CMAKE_HOST_IOS OR CLR_CMAKE_HOST_TVOS OR CLR_CMAKE_HOST_ANDROID)
+endif(CLR_CMAKE_HOST_MACCATALYST OR CLR_CMAKE_HOST_IOS OR CLR_CMAKE_HOST_TVOS OR CLR_CMAKE_HOST_ANDROID OR CLR_CMAKE_HOST_ARCH_WASM)
 
 # Enable profile guided optimization
 add_pgo(coreclr)
diff --git a/src/coreclr/hosts/corewasmrun/CMakeLists.txt b/src/coreclr/hosts/corewasmrun/CMakeLists.txt
index 57eb957debfac3..6bf835a9d8a5b2 100644
--- a/src/coreclr/hosts/corewasmrun/CMakeLists.txt
+++ b/src/coreclr/hosts/corewasmrun/CMakeLists.txt
@@ -18,7 +18,7 @@ endif (EXISTS "${_WASM_PRELOAD_DIR}")
 target_compile_options(corewasmrun PRIVATE -fwasm-exceptions)
 target_link_options(corewasmrun PRIVATE -fwasm-exceptions -sEXIT_RUNTIME=1 -sUSE_OFFSET_CONVERTER=1 -sINITIAL_MEMORY=134217728 -sFORCE_FILESYSTEM=1 ${_WASM_PRELOAD_FILE} -Wl,-error-limit=0)
 
-target_link_libraries(corewasmrun PRIVATE coreclr)
+target_link_libraries(corewasmrun PRIVATE coreclr_static)
 target_link_libraries(corewasmrun PRIVATE clrinterpreter)
 
 target_link_libraries(corewasmrun PRIVATE icuuc)

From ebc8f45094394a03050fed5fe760f93a45dfcf39 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Sun, 22 Jun 2025 21:34:48 +0200
Subject: [PATCH 30/63] Feedback

Disable larger part of GCToOSInterface::Initialize than before
---
 src/coreclr/gc/unix/gcenv.unix.cpp | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/src/coreclr/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp
index cb9b609721dbb1..4a44be49c233bf 100644
--- a/src/coreclr/gc/unix/gcenv.unix.cpp
+++ b/src/coreclr/gc/unix/gcenv.unix.cpp
@@ -222,7 +222,7 @@ bool GCToOSInterface::Initialize()
     //
     // support for FlusProcessWriteBuffers
     //
-
+#ifndef TARGET_WASM
     assert(s_flushUsingMemBarrier == 0);
 
     if (CanFlushUsingMembarrier())
@@ -244,7 +244,6 @@ bool GCToOSInterface::Initialize()
         // Verify that the s_helperPage is really aligned to the g_SystemInfo.dwPageSize
         assert((((size_t)g_helperPage) & (OS_PAGE_SIZE - 1)) == 0);
 
-#ifndef TARGET_BROWSER
         // Locking the page ensures that it stays in memory during the two mprotect
         // calls in the FlushProcessWriteBuffers below. If the page was unmapped between
         // those calls, they would not have the expected effect of generating IPI.
@@ -254,9 +253,6 @@ bool GCToOSInterface::Initialize()
         {
             return false;
         }
-#else
-        int status;
-#endif // !TARGET_BROWSER
 
         status = pthread_mutex_init(&g_flushProcessWriteBuffersMutex, NULL);
         if (status != 0)
@@ -266,6 +262,7 @@ bool GCToOSInterface::Initialize()
         }
     }
 #endif // !TARGET_APPLE
+#endif // !TARGET_WASM
 
     InitializeCGroup();
 

From 18e25e45705e2c44d84792c65139043bc90fa16c Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Sun, 22 Jun 2025 21:40:14 +0200
Subject: [PATCH 31/63] Feedback

Make InitializeFlushProcessWriteBuffers no-op on wasm
---
 src/coreclr/pal/src/thread/process.cpp | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp
index bc7e08acd502be..a39258112ee48f 100644
--- a/src/coreclr/pal/src/thread/process.cpp
+++ b/src/coreclr/pal/src/thread/process.cpp
@@ -2597,7 +2597,7 @@ InitializeFlushProcessWriteBuffers()
     }
 #endif
 
-#ifdef TARGET_APPLE
+#if defined(TARGET_APPLE) || defined(TARGET_WASM)
     return TRUE;
 #else
     s_helperPage = static_cast(mmap(0, GetVirtualPageSize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
@@ -2610,7 +2610,6 @@ InitializeFlushProcessWriteBuffers()
     // Verify that the s_helperPage is really aligned to the GetVirtualPageSize()
     _ASSERTE((((SIZE_T)s_helperPage) & (GetVirtualPageSize() - 1)) == 0);
 
-#ifndef TARGET_BROWSER
     // Locking the page ensures that it stays in memory during the two mprotect
     // calls in the FlushProcessWriteBuffers below. If the page was unmapped between
     // those calls, they would not have the expected effect of generating IPI.
@@ -2620,9 +2619,6 @@ InitializeFlushProcessWriteBuffers()
     {
         return FALSE;
     }
-#else
-    int status;
-#endif // !TARGET_BROWSER
 
     status = pthread_mutex_init(&flushProcessWriteBuffersMutex, NULL);
     if (status != 0)
@@ -2631,7 +2627,7 @@ InitializeFlushProcessWriteBuffers()
     }
 
     return status == 0;
-#endif // TARGET_APPLE
+#endif // TARGET_APPLE || TARGET_WASM
 }
 
 #define FATAL_ASSERT(e, msg) \

From 6ca105cadba752f6dc6ab2723a5240142b82e456 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Sun, 22 Jun 2025 21:49:11 +0200
Subject: [PATCH 32/63] Write barriers helper updated

Co-authored-by: Jan Kotas 
---
 src/coreclr/vm/wasm/helpers.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp
index b4d2691299f401..2fba6f14141319 100644
--- a/src/coreclr/vm/wasm/helpers.cpp
+++ b/src/coreclr/vm/wasm/helpers.cpp
@@ -450,8 +450,8 @@ int StompWriteBarrierEphemeral(bool isRuntimeSuspended)
 
 int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
 {
-    // WASM-TODO: implement me
-    return 0;
+    // Nothing to do - wasm has static write barriers
+    return SWB_PASS;
 }
 
 void FlushWriteBarrierInstructionCache()

From 542d7321f23381d366c8fae423851dd5b8aaf0ca Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Sun, 22 Jun 2025 21:49:26 +0200
Subject: [PATCH 33/63] Write barriers helper updated

Co-authored-by: Jan Kotas 
---
 src/coreclr/vm/wasm/helpers.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp
index 2fba6f14141319..12f22fb57b36ed 100644
--- a/src/coreclr/vm/wasm/helpers.cpp
+++ b/src/coreclr/vm/wasm/helpers.cpp
@@ -456,7 +456,7 @@ int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
 
 void FlushWriteBarrierInstructionCache()
 {
-    PORTABILITY_ASSERT("FlushWriteBarrierInstructionCache is not implemented on wasm");
+    // Nothing to do - wasm has static write barriers
 }
 
 EXTERN_C Thread * JIT_InitPInvokeFrame(InlinedCallFrame *pFrame)

From f907a4dfac592cc9e8be1e39a90113aa0e9bf5aa Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Sun, 22 Jun 2025 21:53:09 +0200
Subject: [PATCH 34/63] Feedback

Return false from ExecutableAllocator::IsDoubleMappingEnabled instead
of making the double mapping init no-op on wasm
---
 src/coreclr/minipal/Unix/doublemapping.cpp   | 3 ---
 src/coreclr/utilcode/executableallocator.cpp | 2 +-
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/coreclr/minipal/Unix/doublemapping.cpp b/src/coreclr/minipal/Unix/doublemapping.cpp
index 61359029418ce2..4a2516bea58484 100644
--- a/src/coreclr/minipal/Unix/doublemapping.cpp
+++ b/src/coreclr/minipal/Unix/doublemapping.cpp
@@ -47,9 +47,6 @@ static const off_t MaxDoubleMappedSize = UINT_MAX;
 
 bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecutableCodeSize)
 {
-#ifdef __wasm__
-    return false;
-#endif
     if (minipal_detect_rosetta())
     {
         // Rosetta doesn't support double mapping correctly
diff --git a/src/coreclr/utilcode/executableallocator.cpp b/src/coreclr/utilcode/executableallocator.cpp
index 0242377072238c..39dc111e3d736f 100644
--- a/src/coreclr/utilcode/executableallocator.cpp
+++ b/src/coreclr/utilcode/executableallocator.cpp
@@ -124,7 +124,7 @@ bool ExecutableAllocator::IsDoubleMappingEnabled()
 {
     LIMITED_METHOD_CONTRACT;
 
-#if defined(HOST_APPLE) && defined(HOST_ARM64)
+#if defined(HOST_APPLE) && defined(HOST_ARM64) || defined(HOST_WASM)
     return false;
 #else
     return g_isWXorXEnabled;

From f5c3500f5994a909f7b9c8fea43654314ab6277d Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Sun, 22 Jun 2025 21:55:54 +0200
Subject: [PATCH 35/63] Make InitJITWriteBarrierHelpers no-op on wasm

Co-authored-by: Jan Kotas 
---
 src/coreclr/vm/wasm/helpers.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp
index 12f22fb57b36ed..7e54216608dc14 100644
--- a/src/coreclr/vm/wasm/helpers.cpp
+++ b/src/coreclr/vm/wasm/helpers.cpp
@@ -439,7 +439,7 @@ EXTERN_C void STDMETHODCALLTYPE ProfileTailcallNaked(UINT_PTR clientData)
 
 void InitJITWriteBarrierHelpers()
 {
-    // WASM-TODO: implement me
+    // Nothing to do - wasm has static write barriers
 }
 
 int StompWriteBarrierEphemeral(bool isRuntimeSuspended)

From 2bdc376a9f5b94b7d491650075216b596ec98044 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Sun, 22 Jun 2025 22:00:27 +0200
Subject: [PATCH 36/63] Feedback

Fix few asserts
---
 src/coreclr/inc/clrnt.h               |  4 ++--
 src/coreclr/pal/src/loader/module.cpp | 10 ++--------
 src/coreclr/utilcode/stresslog.cpp    |  3 +++
 3 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/src/coreclr/inc/clrnt.h b/src/coreclr/inc/clrnt.h
index c5b56ec644e378..f9b63c824e261e 100644
--- a/src/coreclr/inc/clrnt.h
+++ b/src/coreclr/inc/clrnt.h
@@ -522,7 +522,7 @@ RtlVirtualUnwind (
     __inout_opt PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers
     )
 {
-    _ASSERTE("The function RtlVirtualUnwind is not implemented on wasm");
+    PORTABILITY_ASSERT("The function RtlVirtualUnwind is not implemented on wasm");
     return nullptr;
 }
 
@@ -533,7 +533,7 @@ RtlpGetFunctionEndAddress (
     _In_ TADDR ImageBase
     )
 {
-    _ASSERTE("The function RtlpGetFunctionEndAddress is not implemented on wasm");
+    PORTABILITY_ASSERT("The function RtlpGetFunctionEndAddress is not implemented on wasm");
     return 0;
 }
 
diff --git a/src/coreclr/pal/src/loader/module.cpp b/src/coreclr/pal/src/loader/module.cpp
index 4c16bb98164b00..6cb95277f142e5 100644
--- a/src/coreclr/pal/src/loader/module.cpp
+++ b/src/coreclr/pal/src/loader/module.cpp
@@ -927,19 +927,13 @@ PAL_CopyModuleData(PVOID moduleBase, PVOID destinationBufferStart, PVOID destina
     return param.result;
 }
 #elif defined(__wasm__)
-// TODO: get rid of whole module loading on wasm
-static int CopyModuleDataCallback(struct dl_phdr_info *info, size_t size, void *data)
-{
-    _ASSERTE("CopyModuleDataCallback not implemented for wasm");
-    return 0;
-}
-
+// WASM-TODO: get rid of whole module loading on wasm
 PALIMPORT
 int
 PALAPI
 PAL_CopyModuleData(PVOID moduleBase, PVOID destinationBufferStart, PVOID destinationBufferEnd)
 {
-    _ASSERTE("PAL_CopyModuleData not implemented for wasm");
+    _ASSERTE(!"PAL_CopyModuleData not implemented for wasm");
     return 0;
 }
 #else
diff --git a/src/coreclr/utilcode/stresslog.cpp b/src/coreclr/utilcode/stresslog.cpp
index e837e86712d789..3fd772c41e92b5 100644
--- a/src/coreclr/utilcode/stresslog.cpp
+++ b/src/coreclr/utilcode/stresslog.cpp
@@ -305,6 +305,9 @@ void StressLog::Initialize(unsigned facilities, unsigned level, unsigned maxByte
 
 void StressLog::AddModule(uint8_t* moduleBase)
 {
+#ifdef TARGET_WASM
+    return; // no modules on wasm
+#endif
     unsigned moduleIndex = 0;
 #ifdef MEMORY_MAPPED_STRESSLOG
     StressLogHeader* hdr = theLog.stressLogHeader;

From c3ca64a077be30d8c62abb279e1038845f4718d0 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 23 Jun 2025 22:03:19 +0200
Subject: [PATCH 37/63] Feedback

Define PEIMAGE_FLAT_LAYOUT_ONLY in inc\switches.h
---
 src/coreclr/clrdefinitions.cmake  | 4 ----
 src/coreclr/clrfeatures.cmake     | 1 -
 src/coreclr/inc/switches.h        | 4 ++++
 src/coreclr/vm/domainassembly.cpp | 2 +-
 src/coreclr/vm/peassembly.cpp     | 4 ++--
 src/coreclr/vm/peimage.cpp        | 2 +-
 6 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake
index 3ea9afff9c0a5d..846f9a7830794b 100644
--- a/src/coreclr/clrdefinitions.cmake
+++ b/src/coreclr/clrdefinitions.cmake
@@ -4,10 +4,6 @@ if(FEATURE_JIT)
   add_compile_definitions(FEATURE_JIT)
 endif(FEATURE_JIT)
 
-if(FEATURE_PEIMAGE_FLAT_LAYOUT)
-  add_compile_definitions(FEATURE_PEIMAGE_FLAT_LAYOUT)
-endif(FEATURE_PEIMAGE_FLAT_LAYOUT)
-
 add_compile_definitions($<$>:DACCESS_COMPILE>)
 
 if (CLR_CMAKE_TARGET_UNIX)
diff --git a/src/coreclr/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake
index 4740667e9f28b8..bdc10b6aa719e7 100644
--- a/src/coreclr/clrfeatures.cmake
+++ b/src/coreclr/clrfeatures.cmake
@@ -1,6 +1,5 @@
 if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
   set(FEATURE_JIT 1)
-  set(FEATURE_PEIMAGE_FLAT_LAYOUT 1)
 endif()
 
 if(CLR_CMAKE_TARGET_TIZEN_LINUX)
diff --git a/src/coreclr/inc/switches.h b/src/coreclr/inc/switches.h
index 5e8f90c0548a30..cd63d7ddbaaf99 100644
--- a/src/coreclr/inc/switches.h
+++ b/src/coreclr/inc/switches.h
@@ -165,3 +165,7 @@
 // If this is uncommented, leaves a file "StubLog_.log" with statistics on the behavior
 // of stub-based interface dispatch.
 //#define STUB_LOGGING
+
+#ifndef TARGET_WASM
+#define PEIMAGE_FLAT_LAYOUT_ONLY
+#endif // !TARGET_WASM
diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp
index 7fd463d4a0c179..8a34fbe57be54e 100644
--- a/src/coreclr/vm/domainassembly.cpp
+++ b/src/coreclr/vm/domainassembly.cpp
@@ -38,7 +38,7 @@ DomainAssembly::DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoader
 
     m_pAssembly->SetDomainAssembly(this);
 
-#ifndef FEATURE_PEIMAGE_FLAT_LAYOUT
+#ifndef PEIMAGE_FLAT_LAYOUT_ONLY
     // Creating the Assembly should have ensured the PEAssembly is loaded
     _ASSERT(GetPEAssembly()->IsLoaded());
 #endif
diff --git a/src/coreclr/vm/peassembly.cpp b/src/coreclr/vm/peassembly.cpp
index bacf0300e2fd10..b031044af19fab 100644
--- a/src/coreclr/vm/peassembly.cpp
+++ b/src/coreclr/vm/peassembly.cpp
@@ -69,7 +69,7 @@ void PEAssembly::EnsureLoaded()
 
     // Ensure that loaded layout is available.
     PEImageLayout* pLayout = GetPEImage()->GetOrCreateLayout(
-#ifdef FEATURE_PEIMAGE_FLAT_LAYOUT
+#ifdef PEIMAGE_FLAT_LAYOUT_ONLY
         PEImageLayout::LAYOUT_FLAT
 #else
         PEImageLayout::LAYOUT_LOADED
@@ -266,7 +266,7 @@ TADDR PEAssembly::GetIL(RVA il)
     CONTRACT_END;
 
     PEImageLayout *image = NULL;
-#ifdef FEATURE_PEIMAGE_FLAT_LAYOUT
+#ifdef PEIMAGE_FLAT_LAYOUT_ONLY
     image = GetFlatLayout();
 #else
     image = GetLoadedLayout();
diff --git a/src/coreclr/vm/peimage.cpp b/src/coreclr/vm/peimage.cpp
index 4614ccafda658a..4362b3b571d28e 100644
--- a/src/coreclr/vm/peimage.cpp
+++ b/src/coreclr/vm/peimage.cpp
@@ -636,7 +636,7 @@ PTR_PEImageLayout PEImage::GetOrCreateLayoutInternal(DWORD imageLayoutMask)
 
         _ASSERTE(bIsLoadedLayoutSuitable || bIsFlatLayoutSuitable);
 
-#ifndef FEATURE_PEIMAGE_FLAT_LAYOUT
+#ifndef PEIMAGE_FLAT_LAYOUT_ONLY
         if (bIsLoadedLayoutPreferred)
         {
             _ASSERTE(bIsLoadedLayoutSuitable);

From efd8722e302a0b6ffff9f84e52e3b0ae4e59702e Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 23 Jun 2025 22:15:03 +0200
Subject: [PATCH 38/63] Feedback

Replace __wasm__ where appropriate
---
 src/coreclr/interpreter/compiler.h | 4 ++--
 src/coreclr/utilcode/clrhost.cpp   | 2 +-
 src/coreclr/vm/ceemain.cpp         | 4 ++--
 src/coreclr/vm/threads.cpp         | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/coreclr/interpreter/compiler.h b/src/coreclr/interpreter/compiler.h
index 26b666c0e8e2e9..b5b3b27e7e2c0a 100644
--- a/src/coreclr/interpreter/compiler.h
+++ b/src/coreclr/interpreter/compiler.h
@@ -334,12 +334,12 @@ class InterpCompiler
 #ifdef DEBUG
     CORINFO_CLASS_HANDLE m_classHnd;
     TArray m_methodName;
-#ifdef __wasm__
+#ifdef TARGET_WASM
     // enable verbose output on wasm temporarily
     bool m_verbose = true;
 #else
     bool m_verbose = false;
-#endif // __wasm__
+#endif // TARGET_WASM
 #endif // DEBUG
 
     static int32_t InterpGetMovForType(InterpType interpType, bool signExtend);
diff --git a/src/coreclr/utilcode/clrhost.cpp b/src/coreclr/utilcode/clrhost.cpp
index 41e8b2dc348b2a..2c6915c3fdfad5 100644
--- a/src/coreclr/utilcode/clrhost.cpp
+++ b/src/coreclr/utilcode/clrhost.cpp
@@ -62,7 +62,7 @@ DWORD GetClrModulePathName(SString& buffer)
 #ifdef HOST_WINDOWS
     return WszGetModuleFileName((HINSTANCE)GetClrModuleBase(), buffer);
 #else
-#ifndef __wasm__
+#ifndef HOST_WASM
     HMODULE hModule = PAL_GetPalHostModule();
 #else
     // on wasm the PAL library is statically linked
diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp
index ab9ad9c5581d23..a30f9663124473 100644
--- a/src/coreclr/vm/ceemain.cpp
+++ b/src/coreclr/vm/ceemain.cpp
@@ -842,7 +842,7 @@ void EEStartupHelper()
         // Initialize the debugging services. This must be done before any
         // EE thread objects are created, and before any classes or
         // modules are loaded.
-#ifndef __wasm__
+#ifndef TARGET_WASM
         InitializeDebugger(); // throws on error
 #endif
 #endif // DEBUGGING_SUPPORTED
@@ -924,7 +924,7 @@ void EEStartupHelper()
 
         // on wasm we need to run finalizers on main thread as we are single threaded
         // active issue: https://github.com/dotnet/runtime/issues/114096
-#if !defined(TARGET_WINDOWS) && !defined(__wasm__)
+#if !defined(TARGET_WINDOWS) && !defined(TARGET_WASM)
         // This isn't done as part of InitializeGarbageCollector() above because
         // debugger must be initialized before creating EE thread objects
         FinalizerThread::FinalizerThreadCreate();
diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp
index 0ccc832bebfb78..eddb940c33193b 100644
--- a/src/coreclr/vm/threads.cpp
+++ b/src/coreclr/vm/threads.cpp
@@ -6049,7 +6049,7 @@ BOOL Thread::SetStackLimits(SetStackLimitScope scope)
     {
         m_CacheStackBase  = GetStackUpperBound();
         m_CacheStackLimit = GetStackLowerBound();
-#ifndef __wasm__ // stack can start at address 0 on wasm/emscripten and usually does
+#ifndef TARGET_WASM // stack can start at address 0 on wasm/emscripten and usually does
         if (m_CacheStackLimit == NULL)
         {
             _ASSERTE(!"Failed to set stack limits");

From fb6f747ecd2137e80a5e4a9fd9c5f2446d6b80f0 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 23 Jun 2025 22:46:06 +0200
Subject: [PATCH 39/63] Feedback

Do not use __builtin_return_address on wasm
---
 src/coreclr/CMakeLists.txt                   |  2 +-
 src/coreclr/hosts/corewasmrun/CMakeLists.txt |  2 +-
 src/coreclr/pal/inc/rt/palrt.h               |  2 +-
 src/coreclr/pal/inc/rt/retaddr.h             | 14 ++++++++++++++
 src/coreclr/pal/src/CMakeLists.txt           |  1 +
 src/coreclr/pal/src/exception/seh.cpp        |  4 +++-
 src/coreclr/pal/src/exception/signal.cpp     |  4 +++-
 7 files changed, 24 insertions(+), 5 deletions(-)
 create mode 100644 src/coreclr/pal/inc/rt/retaddr.h

diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt
index 684a23b6f1b0b3..4d6f844a0aa526 100644
--- a/src/coreclr/CMakeLists.txt
+++ b/src/coreclr/CMakeLists.txt
@@ -41,7 +41,7 @@ endif(DEFINED CLR_CMAKE_ICU_DIR)
 
 if (CLR_CMAKE_TARGET_ARCH_WASM)
     add_compile_options(-fwasm-exceptions)
-    add_link_options(-fwasm-exceptions -sEXIT_RUNTIME=1 -sUSE_OFFSET_CONVERTER=1)
+    add_link_options(-fwasm-exceptions -sEXIT_RUNTIME=1)
 endif()
 
 #----------------------------------------------------
diff --git a/src/coreclr/hosts/corewasmrun/CMakeLists.txt b/src/coreclr/hosts/corewasmrun/CMakeLists.txt
index 6bf835a9d8a5b2..e64702d9f1830c 100644
--- a/src/coreclr/hosts/corewasmrun/CMakeLists.txt
+++ b/src/coreclr/hosts/corewasmrun/CMakeLists.txt
@@ -16,7 +16,7 @@ if (EXISTS "${_WASM_PRELOAD_DIR}")
 endif (EXISTS "${_WASM_PRELOAD_DIR}")
 
 target_compile_options(corewasmrun PRIVATE -fwasm-exceptions)
-target_link_options(corewasmrun PRIVATE -fwasm-exceptions -sEXIT_RUNTIME=1 -sUSE_OFFSET_CONVERTER=1 -sINITIAL_MEMORY=134217728 -sFORCE_FILESYSTEM=1 ${_WASM_PRELOAD_FILE} -Wl,-error-limit=0)
+target_link_options(corewasmrun PRIVATE -fwasm-exceptions -sEXIT_RUNTIME=1 -sINITIAL_MEMORY=134217728 -sFORCE_FILESYSTEM=1 ${_WASM_PRELOAD_FILE} -Wl,-error-limit=0)
 
 target_link_libraries(corewasmrun PRIVATE coreclr_static)
 target_link_libraries(corewasmrun PRIVATE clrinterpreter)
diff --git a/src/coreclr/pal/inc/rt/palrt.h b/src/coreclr/pal/inc/rt/palrt.h
index 67697a63e656e5..c493362ba2bf88 100644
--- a/src/coreclr/pal/inc/rt/palrt.h
+++ b/src/coreclr/pal/inc/rt/palrt.h
@@ -751,7 +751,7 @@ typedef struct _LIST_ENTRY {
 #define RUNTIME_FUNCTION_INDIRECT 0x1
 #endif
 
-#define _ReturnAddress() __builtin_return_address(0)
+#include "retaddr.h"
 
 #define DIRECTORY_SEPARATOR_CHAR_A '/'
 #define DIRECTORY_SEPARATOR_CHAR_W W('/')
diff --git a/src/coreclr/pal/inc/rt/retaddr.h b/src/coreclr/pal/inc/rt/retaddr.h
new file mode 100644
index 00000000000000..703b46802bea60
--- /dev/null
+++ b/src/coreclr/pal/inc/rt/retaddr.h
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
+#ifndef __PALRETADDR_H__
+#define __PALRETADDR_H__
+
+#ifndef TARGET_WASM
+#define _ReturnAddress() __builtin_return_address(0)
+#else
+#define _ReturnAddress() 0
+#endif
+
+#endif // __PALRETADDR_H__
diff --git a/src/coreclr/pal/src/CMakeLists.txt b/src/coreclr/pal/src/CMakeLists.txt
index a850607a20c359..204d51fbd9b5fa 100644
--- a/src/coreclr/pal/src/CMakeLists.txt
+++ b/src/coreclr/pal/src/CMakeLists.txt
@@ -37,6 +37,7 @@ endif(CORECLR_SET_RPATH)
 # Include directories
 
 include_directories(include)
+include_directories(${COREPAL_SOURCE_DIR}/inc/rt)
 
 # Compile options
 
diff --git a/src/coreclr/pal/src/exception/seh.cpp b/src/coreclr/pal/src/exception/seh.cpp
index c2f28cff936c96..6c9fdfdaca0ae9 100644
--- a/src/coreclr/pal/src/exception/seh.cpp
+++ b/src/coreclr/pal/src/exception/seh.cpp
@@ -27,6 +27,8 @@ Module Name:
 #include "pal/signal.hpp"
 #include "pal/virtual.h"
 
+#include "retaddr.h"
+
 #if HAVE_MACH_EXCEPTIONS
 #include "machexception.h"
 #else
@@ -248,7 +250,7 @@ Return value:
 BOOL
 SEHProcessException(PAL_SEHException* exception)
 {
-    g_SEHProcessExceptionReturnAddress = __builtin_return_address(0);
+    g_SEHProcessExceptionReturnAddress = _ReturnAddress();
 
     CONTEXT* contextRecord = exception->GetContextRecord();
     EXCEPTION_RECORD* exceptionRecord = exception->GetExceptionRecord();
diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp
index b0501bc993f5cb..5f2f0bc2036a49 100644
--- a/src/coreclr/pal/src/exception/signal.cpp
+++ b/src/coreclr/pal/src/exception/signal.cpp
@@ -31,6 +31,8 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do
 
 #include "pal/palinternal.h"
 
+#include "retaddr.h"
+
 #include 
 
 #include 
@@ -878,7 +880,7 @@ Parameters :
 __attribute__((noinline))
 static void InvokeActivationHandler(CONTEXT *pWinContext)
 {
-    g_InvokeActivationHandlerReturnAddress = __builtin_return_address(0);
+    g_InvokeActivationHandlerReturnAddress = _ReturnAddress();
     g_activationFunction(pWinContext);
 }
 

From 13b945ac0cc8991891e3722a7e2769a558aa113c Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 24 Jun 2025 11:34:52 +0200
Subject: [PATCH 40/63] Feedback

Add InvokeCalliStub to helpers
---
 src/coreclr/vm/interpexec.cpp   | 8 +++-----
 src/coreclr/vm/wasm/helpers.cpp | 5 +++++
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp
index 91cb77e8f4fa00..8a3e2d8e22a12f 100644
--- a/src/coreclr/vm/interpexec.cpp
+++ b/src/coreclr/vm/interpexec.cpp
@@ -20,7 +20,9 @@ FCDECL1(double, JIT_ULng2Dbl, uint64_t val);
 FCDECL1(float, JIT_Lng2Flt, int64_t val);
 FCDECL1(double, JIT_Lng2Dbl, int64_t val);
 
-#ifndef TARGET_WASM
+#ifdef TARGET_WASM
+void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet);
+#else
 #include "callstubgenerator.h"
 
 void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet)
@@ -1481,7 +1483,6 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
 
                 case INTOP_CALLI:
                 {
-#ifndef TARGET_WASM
                     returnOffset = ip[1];
                     callArgsOffset = ip[2];
                     int32_t calliFunctionPointerVar = ip[3];
@@ -1491,9 +1492,6 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
                     ip += 5;
 
                     InvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), pCallStub, stack + callArgsOffset, stack + returnOffset);
-#else
-                    PORTABILITY_ASSERT("Attempted to execute calli instruction on wasm, this is not yet implemented");
-#endif // TARGET_WASM
                     break;
                 }
 
diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp
index 7e54216608dc14..10dad3e8be02c4 100644
--- a/src/coreclr/vm/wasm/helpers.cpp
+++ b/src/coreclr/vm/wasm/helpers.cpp
@@ -477,3 +477,8 @@ extern "C" int32_t mono_wasm_browser_entropy(uint8_t* buffer, int32_t bufferLeng
     PORTABILITY_ASSERT("mono_wasm_browser_entropy is not implemented");
     return -1;
 }
+
+void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet)
+{
+    PORTABILITY_ASSERT("InvokeCalliStub is not implemented on wasm");
+}

From da2b4050a801b0d8e507435a10bb24cdd805901a Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 24 Jun 2025 13:38:17 +0200
Subject: [PATCH 41/63] Feedback

Update comments and remove unwanted fields
---
 src/coreclr/pal/inc/rt/palrt.h     | 8 ++------
 src/coreclr/vm/callingconvention.h | 1 +
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/src/coreclr/pal/inc/rt/palrt.h b/src/coreclr/pal/inc/rt/palrt.h
index c493362ba2bf88..5488668b1e6ea7 100644
--- a/src/coreclr/pal/inc/rt/palrt.h
+++ b/src/coreclr/pal/inc/rt/palrt.h
@@ -1006,13 +1006,9 @@ typedef struct _DISPATCHER_CONTEXT {
 #elif defined(HOST_WASM)
 
 typedef struct _DISPATCHER_CONTEXT {
-    // WASM does not build the VM or JIT at this point,
-    // so we only provide a dummy definition.
+    // WASM does not build the JIT at this point,
+    // so we only add necessary fields.
     UINT32 ControlPc;
-    UINT32 ImageBase;
-    PRUNTIME_FUNCTION FunctionEntry;
-    UINT32 EstablisherFrame;
-    PCONTEXT ContextRecord;
 } DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
 
 #else
diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h
index 1de315880bcca6..6d509d80d4ae0b 100644
--- a/src/coreclr/vm/callingconvention.h
+++ b/src/coreclr/vm/callingconvention.h
@@ -1225,6 +1225,7 @@ int ArgIteratorTemplate::GetNextOffset()
         m_idxFPReg = 0;
 #elif defined(TARGET_WASM)
         // we put everything on the stack, we don't have registers
+        // WASM_TODO find out whether we can use implicit stack here
         m_ofsStack = 0;
 #else
         PORTABILITY_ASSERT("ArgIteratorTemplate::GetNextOffset");

From 7c912c55184150da8b8b0bb269edfcb15b04a1df Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 24 Jun 2025 17:51:57 +0200
Subject: [PATCH 42/63] Feedback

Add comment to the wasm specific call description data fields
---
 src/coreclr/vm/callhelpers.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/coreclr/vm/callhelpers.h b/src/coreclr/vm/callhelpers.h
index aa6af8bdbe9875..12b4a8da1af464 100644
--- a/src/coreclr/vm/callhelpers.h
+++ b/src/coreclr/vm/callhelpers.h
@@ -29,7 +29,9 @@ struct CallDescrData
     UINT32                      fpReturnSize;
     PCODE                       pTarget;
 #ifdef TARGET_WASM
+    // method description is used to compile the method with the interpreter
     MethodDesc*                 pMD;
+    // size of the arguments and the transition block are used to execute the method with the interpreter
     size_t                      nArgsSize;
     TransitionBlock*            pTransitionBlock;
 #endif

From bd16e774e9573362a75f16397c30833ba21a032a Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 24 Jun 2025 17:58:19 +0200
Subject: [PATCH 43/63] Feedback

Add portability assert in DispatchCallSimple to light up if we get
called through this path
---
 src/coreclr/vm/callhelpers.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/coreclr/vm/callhelpers.cpp b/src/coreclr/vm/callhelpers.cpp
index 92a9a60b84ec63..4bf742d5078440 100644
--- a/src/coreclr/vm/callhelpers.cpp
+++ b/src/coreclr/vm/callhelpers.cpp
@@ -224,6 +224,10 @@ void * DispatchCallSimple(
     callDescrData.fpReturnSize = 0;
     callDescrData.pTarget = pTargetAddress;
 
+#ifdef TARGET_WASM
+    PORTABILITY_ASSERT("wasm need to fill call description data");
+#endif
+
     if ((dwDispatchCallSimpleFlags & DispatchCallSimple_CatchHandlerFoundNotification) != 0)
     {
         DispatchCallDebuggerWrapper(

From defe297e67b6e844672dd5722ef0afa5a18a4927 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 24 Jun 2025 19:12:14 +0200
Subject: [PATCH 44/63] Fix build

---
 src/coreclr/vm/precode.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h
index 7d69b2df22d87f..d68ca727a1b631 100644
--- a/src/coreclr/vm/precode.h
+++ b/src/coreclr/vm/precode.h
@@ -836,8 +836,10 @@ static_assert_no_msg(sizeof(Precode) <= sizeof(NDirectImportPrecode));
 static_assert_no_msg(sizeof(Precode) <= sizeof(FixupPrecode));
 static_assert_no_msg(sizeof(Precode) <= sizeof(ThisPtrRetBufPrecode));
 
+#ifdef FEATURE_INTERPRETER
 // check that the InterpreterPrecodeData fits into the StubPrecode
 static_assert_no_msg(sizeof(InterpreterPrecodeData) <= sizeof(StubPrecode));
+#endif // FEATURE_INTERPRETER
 
 #ifndef DACCESS_COMPILE
 // A summary of the precode layout for diagnostic purposes

From ef5b327f121d5d7d0694bf7ea6eef33eb08bd3d3 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 25 Jun 2025 14:51:20 +0200
Subject: [PATCH 45/63] Fix non-wasm build

---
 src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
index 67b7d6ce6e77bb..a52f0fc252fcb0 100644
--- a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
+++ b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
@@ -176,9 +176,13 @@ if(FEATURE_PERFTRACING)
     endif(CLR_CMAKE_TARGET_LINUX)
 endif(FEATURE_PERFTRACING)
 
-if(FEATURE_STATICALLY_LINKED AND NOT CLR_CMAKE_HOST_ARCH_WASM)
+if(FEATURE_STATICALLY_LINKED)
     set(CLRJIT_STATIC clrjit_static)
-endif(FEATURE_STATICALLY_LINKED AND NOT CLR_CMAKE_HOST_ARCH_WASM)
+endif(FEATURE_STATICALLY_LINKED)
+
+if(NOT CLR_CMAKE_HOST_ARCH_WASM)
+    set(CORECLR_STATIC_CLRJIT_STATIC clrjit_static)
+endif(NOT CLR_CMAKE_HOST_ARCH_WASM)
 
 if(NOT CLR_CMAKE_HOST_ARCH_WASM)
     set(CEE_WKS_STATIC cee_wks_mergeable)
@@ -194,7 +198,7 @@ if(NOT CLR_CMAKE_HOST_ARCH_WASM)
     target_link_libraries(coreclr PUBLIC ${CORECLR_LIBRARIES} ${CLRJIT_STATIC} cee_wks_core cee_wks ${FOUNDATION})
 endif(NOT CLR_CMAKE_HOST_ARCH_WASM)
 
-target_link_libraries(coreclr_static PUBLIC ${CORECLR_LIBRARIES} cee_wks_core ${CLRJIT_STATIC} ${CEE_WKS_STATIC} ${FOUNDATION})
+target_link_libraries(coreclr_static PUBLIC ${CORECLR_LIBRARIES} cee_wks_core ${CORECLR_STATIC_CLRJIT_STATIC} ${CEE_WKS_STATIC} ${FOUNDATION})
 target_compile_definitions(coreclr_static PUBLIC CORECLR_EMBEDDED)
 
 if (CLR_CMAKE_HOST_ANDROID)

From 71643ecb3254788adf1db0764eab1640a361bc89 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 25 Jun 2025 16:08:48 +0200
Subject: [PATCH 46/63] Feedback

Use FEATURE_JIT instead of not WASM check
---
 src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
index a52f0fc252fcb0..e31376bd3eac79 100644
--- a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
+++ b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
@@ -180,9 +180,9 @@ if(FEATURE_STATICALLY_LINKED)
     set(CLRJIT_STATIC clrjit_static)
 endif(FEATURE_STATICALLY_LINKED)
 
-if(NOT CLR_CMAKE_HOST_ARCH_WASM)
+if(FEATURE_JIT)
     set(CORECLR_STATIC_CLRJIT_STATIC clrjit_static)
-endif(NOT CLR_CMAKE_HOST_ARCH_WASM)
+endif(FEATURE_JIT)
 
 if(NOT CLR_CMAKE_HOST_ARCH_WASM)
     set(CEE_WKS_STATIC cee_wks_mergeable)

From 2aa639f7d24b5ca497765b839ba2070e172a04b4 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 7 Jul 2025 14:20:12 +0200
Subject: [PATCH 47/63] Feedback

Co-authored-by: Jan Kotas 
---
 src/coreclr/CMakeLists.txt                      | 1 -
 src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt | 9 +++------
 src/coreclr/inc/switches.h                      | 2 +-
 3 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt
index 4d6f844a0aa526..6e9519affb16d1 100644
--- a/src/coreclr/CMakeLists.txt
+++ b/src/coreclr/CMakeLists.txt
@@ -41,7 +41,6 @@ endif(DEFINED CLR_CMAKE_ICU_DIR)
 
 if (CLR_CMAKE_TARGET_ARCH_WASM)
     add_compile_options(-fwasm-exceptions)
-    add_link_options(-fwasm-exceptions -sEXIT_RUNTIME=1)
 endif()
 
 #----------------------------------------------------
diff --git a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
index e31376bd3eac79..5d063abe182de4 100644
--- a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
+++ b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
@@ -70,18 +70,15 @@ if (NOT CLR_CMAKE_HOST_ARCH_WASM)
 
     set_property(TARGET coreclr APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION})
     set_property(TARGET coreclr APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE})
+    set(LIB_CORDBEE cordbee_wks)
+    set(LIB_INTEROP interop)
+    set(LIB_CDAC_CONTRACT_DESCRIPTOR cdac_contract_descriptor)
 endif(NOT CLR_CMAKE_HOST_ARCH_WASM)
 
 if (CLR_CMAKE_HOST_UNIX AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
     set(LIB_UNWINDER unwinder_wks)
 endif (CLR_CMAKE_HOST_UNIX AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
 
-if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
-    set(LIB_CORDBEE cordbee_wks)
-    set(LIB_INTEROP interop)
-    set(LIB_CDAC_CONTRACT_DESCRIPTOR cdac_contract_descriptor)
-endif (NOT CLR_CMAKE_TARGET_ARCH_WASM)
-
 # IMPORTANT! Please do not rearrange the order of the libraries. The linker on Linux is
 # order dependent and changing the order can result in undefined symbols in the shared
 # library.
diff --git a/src/coreclr/inc/switches.h b/src/coreclr/inc/switches.h
index cd63d7ddbaaf99..7915e0944f4175 100644
--- a/src/coreclr/inc/switches.h
+++ b/src/coreclr/inc/switches.h
@@ -166,6 +166,6 @@
 // of stub-based interface dispatch.
 //#define STUB_LOGGING
 
-#ifndef TARGET_WASM
+#ifdef TARGET_WASM
 #define PEIMAGE_FLAT_LAYOUT_ONLY
 #endif // !TARGET_WASM

From bcc8051a19fd242268b4017d35f895485d913cf5 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 8 Jul 2025 14:00:58 +0200
Subject: [PATCH 48/63] Feedback

---
 src/coreclr/vm/interpexec.cpp | 5 -----
 src/coreclr/vm/metasig.h      | 1 -
 2 files changed, 6 deletions(-)

diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp
index 31e1b4c1394a20..4ff45f91139442 100644
--- a/src/coreclr/vm/interpexec.cpp
+++ b/src/coreclr/vm/interpexec.cpp
@@ -10,11 +10,6 @@
 // for numeric_limits
 #include 
 
-FCDECL1(float, JIT_ULng2Flt, uint64_t val);
-FCDECL1(double, JIT_ULng2Dbl, uint64_t val);
-FCDECL1(float, JIT_Lng2Flt, int64_t val);
-FCDECL1(double, JIT_Lng2Dbl, int64_t val);
-
 #ifdef TARGET_WASM
 void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet);
 #else
diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h
index 37dd885542fb75..1dcfce6a42ba39 100644
--- a/src/coreclr/vm/metasig.h
+++ b/src/coreclr/vm/metasig.h
@@ -201,7 +201,6 @@ DEFINE_METASIG_T(SM(Exception_Obj_RefIntPtr_RetVoidPtr, C(EXCEPTION) j r(I), P(v
 #endif // FEATURE_OBJCMARSHAL
 DEFINE_METASIG(SM(Int_RetVoid, i, v))
 DEFINE_METASIG(SM(Int_RetObj, i, j))
-DEFINE_METASIG(SM(Int_RetInt, i, i))
 DEFINE_METASIG(SM(Int_Int_RetVoid, i i, v))
 DEFINE_METASIG(SM(Str_RetIntPtr, s, I))
 DEFINE_METASIG(SM(Str_RetBool, s, F))

From 19d1e78e2e269eeb06bf48677f03d5559cf4d8be Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Tue, 8 Jul 2025 14:01:31 +0200
Subject: [PATCH 49/63] Feedback

Disable stack limit assert only in Debug configuration
---
 src/coreclr/vm/threads.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp
index 078acc604627b4..782831f8e45b24 100644
--- a/src/coreclr/vm/threads.cpp
+++ b/src/coreclr/vm/threads.cpp
@@ -6047,7 +6047,7 @@ BOOL Thread::SetStackLimits(SetStackLimitScope scope)
     {
         m_CacheStackBase  = GetStackUpperBound();
         m_CacheStackLimit = GetStackLowerBound();
-#ifndef TARGET_WASM // stack can start at address 0 on wasm/emscripten and usually does
+#if !defined(TARGET_WASM) || !defined(_DEBUG) // stack can start at address 0 on wasm/emscripten and usually does in Debug builds
         if (m_CacheStackLimit == NULL)
         {
             _ASSERTE(!"Failed to set stack limits");

From a5d3c97dc97c18d2148a32f8ca46eca05b822b03 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Thu, 10 Jul 2025 14:25:06 +0200
Subject: [PATCH 50/63] Feedback

Return flat layout from GetLoadedLayout when PEIMAGE_FLAT_LAYOUT_ONLY
switch is enabled
---
 src/coreclr/vm/peassembly.cpp | 4 ----
 src/coreclr/vm/peassembly.h   | 9 ---------
 src/coreclr/vm/peimage.inl    | 3 +++
 3 files changed, 3 insertions(+), 13 deletions(-)

diff --git a/src/coreclr/vm/peassembly.cpp b/src/coreclr/vm/peassembly.cpp
index b031044af19fab..0ab24368e027c1 100644
--- a/src/coreclr/vm/peassembly.cpp
+++ b/src/coreclr/vm/peassembly.cpp
@@ -266,11 +266,7 @@ TADDR PEAssembly::GetIL(RVA il)
     CONTRACT_END;
 
     PEImageLayout *image = NULL;
-#ifdef PEIMAGE_FLAT_LAYOUT_ONLY
-    image = GetFlatLayout();
-#else
     image = GetLoadedLayout();
-#endif
 
 #ifndef DACCESS_COMPILE
     // Verify that the IL blob is valid before giving it out
diff --git a/src/coreclr/vm/peassembly.h b/src/coreclr/vm/peassembly.h
index 6b58a0f4248e21..43b14abe9fe41d 100644
--- a/src/coreclr/vm/peassembly.h
+++ b/src/coreclr/vm/peassembly.h
@@ -258,15 +258,6 @@ class PEAssembly final
         return GetPEImage()->GetLoadedLayout();
     };
 
-    PTR_PEImageLayout GetFlatLayout()
-    {
-        LIMITED_METHOD_CONTRACT;
-        SUPPORTS_DAC;
-
-        _ASSERTE(HasPEImage());
-        return GetPEImage()->GetFlatLayout();
-    };
-
     BOOL IsLoaded()
     {
         return IsReflectionEmit() || HasLoadedPEImage();
diff --git a/src/coreclr/vm/peimage.inl b/src/coreclr/vm/peimage.inl
index 3c12013030e82b..592a84792646be 100644
--- a/src/coreclr/vm/peimage.inl
+++ b/src/coreclr/vm/peimage.inl
@@ -170,6 +170,9 @@ inline BOOL PEImage::HasLoadedLayout()
 
 inline PTR_PEImageLayout PEImage::GetLoadedLayout()
 {
+#ifdef PEIMAGE_FLAT_LAYOUT_ONLY
+    return GetFlatLayout();
+#endif
     LIMITED_METHOD_CONTRACT;
     SUPPORTS_DAC;
 

From 9f26f89a16b6ce006c198cf6cdc05f23dfbdb980 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Thu, 10 Jul 2025 15:28:13 +0200
Subject: [PATCH 51/63] Feedback

Add more explanation in the comment and use the CodeSize in the assert
---
 src/coreclr/vm/precode.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h
index d68ca727a1b631..aa1c70b56c7225 100644
--- a/src/coreclr/vm/precode.h
+++ b/src/coreclr/vm/precode.h
@@ -837,8 +837,10 @@ static_assert_no_msg(sizeof(Precode) <= sizeof(FixupPrecode));
 static_assert_no_msg(sizeof(Precode) <= sizeof(ThisPtrRetBufPrecode));
 
 #ifdef FEATURE_INTERPRETER
-// check that the InterpreterPrecodeData fits into the StubPrecode
-static_assert_no_msg(sizeof(InterpreterPrecodeData) <= sizeof(StubPrecode));
+// we are allocating InterpreterPrecode in the interleaved StubPrecodeHeap
+// (in Precode::AllocateInterpreterPrecode)
+// and so we need it to fit the data into the StubPrecode::CodeSize
+static_assert_no_msg(sizeof(InterpreterPrecodeData) <= StubPrecode::CodeSize);
 #endif // FEATURE_INTERPRETER
 
 #ifndef DACCESS_COMPILE

From 9f26ea7bdc38fdec6c3d5f465b14174f9bc80edd Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Mon, 14 Jul 2025 11:06:15 +0200
Subject: [PATCH 52/63] Add comment

Co-authored-by: Jan Kotas 
---
 src/coreclr/vm/threads.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp
index 782831f8e45b24..61781ad697f0ad 100644
--- a/src/coreclr/vm/threads.cpp
+++ b/src/coreclr/vm/threads.cpp
@@ -6047,7 +6047,7 @@ BOOL Thread::SetStackLimits(SetStackLimitScope scope)
     {
         m_CacheStackBase  = GetStackUpperBound();
         m_CacheStackLimit = GetStackLowerBound();
-#if !defined(TARGET_WASM) || !defined(_DEBUG) // stack can start at address 0 on wasm/emscripten and usually does in Debug builds
+#if !defined(TARGET_WASM) // WASM-TODO: stack can start at address 0 on wasm/emscripten and usually does in Debug builds
         if (m_CacheStackLimit == NULL)
         {
             _ASSERTE(!"Failed to set stack limits");

From fdb56bc7dda05ec8463f7cf37f7419f6f21bd57c Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Fri, 18 Jul 2025 16:26:37 +0200
Subject: [PATCH 53/63] Feedback

Move _ReturnAddress macro ro pal.h
---
 src/coreclr/pal/inc/pal.h                |  6 ++++++
 src/coreclr/pal/inc/rt/retaddr.h         | 14 --------------
 src/coreclr/pal/src/CMakeLists.txt       |  1 -
 src/coreclr/pal/src/exception/seh.cpp    |  2 --
 src/coreclr/pal/src/exception/signal.cpp |  2 --
 5 files changed, 6 insertions(+), 19 deletions(-)
 delete mode 100644 src/coreclr/pal/inc/rt/retaddr.h

diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h
index 8da66ba362488a..0adb251a54b68c 100644
--- a/src/coreclr/pal/inc/pal.h
+++ b/src/coreclr/pal/inc/pal.h
@@ -4334,4 +4334,10 @@ class NativeExceptionHolderFactory
 }
 #endif
 
+#ifndef TARGET_WASM
+#define _ReturnAddress() __builtin_return_address(0)
+#else
+#define _ReturnAddress() 0
+#endif
+
 #endif // __PAL_H__
diff --git a/src/coreclr/pal/inc/rt/retaddr.h b/src/coreclr/pal/inc/rt/retaddr.h
deleted file mode 100644
index 703b46802bea60..00000000000000
--- a/src/coreclr/pal/inc/rt/retaddr.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-//
-
-#ifndef __PALRETADDR_H__
-#define __PALRETADDR_H__
-
-#ifndef TARGET_WASM
-#define _ReturnAddress() __builtin_return_address(0)
-#else
-#define _ReturnAddress() 0
-#endif
-
-#endif // __PALRETADDR_H__
diff --git a/src/coreclr/pal/src/CMakeLists.txt b/src/coreclr/pal/src/CMakeLists.txt
index 204d51fbd9b5fa..a850607a20c359 100644
--- a/src/coreclr/pal/src/CMakeLists.txt
+++ b/src/coreclr/pal/src/CMakeLists.txt
@@ -37,7 +37,6 @@ endif(CORECLR_SET_RPATH)
 # Include directories
 
 include_directories(include)
-include_directories(${COREPAL_SOURCE_DIR}/inc/rt)
 
 # Compile options
 
diff --git a/src/coreclr/pal/src/exception/seh.cpp b/src/coreclr/pal/src/exception/seh.cpp
index 6c9fdfdaca0ae9..26c963ff3b1110 100644
--- a/src/coreclr/pal/src/exception/seh.cpp
+++ b/src/coreclr/pal/src/exception/seh.cpp
@@ -27,8 +27,6 @@ Module Name:
 #include "pal/signal.hpp"
 #include "pal/virtual.h"
 
-#include "retaddr.h"
-
 #if HAVE_MACH_EXCEPTIONS
 #include "machexception.h"
 #else
diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp
index 5f2f0bc2036a49..f9c9b2a74eb0ff 100644
--- a/src/coreclr/pal/src/exception/signal.cpp
+++ b/src/coreclr/pal/src/exception/signal.cpp
@@ -31,8 +31,6 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do
 
 #include "pal/palinternal.h"
 
-#include "retaddr.h"
-
 #include 
 
 #include 

From 7c279158249ae1cb71be44f84c44cad0fa12bc58 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Fri, 18 Jul 2025 16:36:57 +0200
Subject: [PATCH 54/63] Fix build

---
 src/coreclr/pal/inc/rt/palrt.h  | 2 --
 src/coreclr/vm/interpexec.cpp   | 7 ++-----
 src/coreclr/vm/wasm/helpers.cpp | 7 ++++++-
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/coreclr/pal/inc/rt/palrt.h b/src/coreclr/pal/inc/rt/palrt.h
index 5488668b1e6ea7..45ed97d670f7ee 100644
--- a/src/coreclr/pal/inc/rt/palrt.h
+++ b/src/coreclr/pal/inc/rt/palrt.h
@@ -751,8 +751,6 @@ typedef struct _LIST_ENTRY {
 #define RUNTIME_FUNCTION_INDIRECT 0x1
 #endif
 
-#include "retaddr.h"
-
 #define DIRECTORY_SEPARATOR_CHAR_A '/'
 #define DIRECTORY_SEPARATOR_CHAR_W W('/')
 #define DIRECTORY_SEPARATOR_STR_A "/"
diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp
index ed53344445d90a..38a1fb0a616a6b 100644
--- a/src/coreclr/vm/interpexec.cpp
+++ b/src/coreclr/vm/interpexec.cpp
@@ -12,7 +12,8 @@
 #include 
 
 #ifdef TARGET_WASM
-void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet, PCODE target);
+void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet);
+void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE target);
 #else
 #include "callstubgenerator.h"
 
@@ -1912,12 +1913,8 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
                         }
                         if (targetIp == NULL)
                         {
-#ifndef TARGET_WASM
                             // If we didn't get the interpreter code pointer setup, then this is a method we need to invoke as a compiled method.
                             InvokeCompiledMethod(targetMethod, stack + callArgsOffset, stack + returnOffset, targetMethod->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY));
-#else
-                            PORTABILITY_ASSERT("Attempted to execute non-interpreter code from interpreter on wasm, this is not yet implemented");
-#endif // !TARGET_WASM
                             break;
                         }
                     }
diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp
index 10dad3e8be02c4..d16676c4408524 100644
--- a/src/coreclr/vm/wasm/helpers.cpp
+++ b/src/coreclr/vm/wasm/helpers.cpp
@@ -405,7 +405,7 @@ EXTERN_C FCDECL2(Object*, RhpNewArrayMaybeFrozen, CORINFO_CLASS_HANDLE typeHnd_,
     return nullptr;
 }
 
-EXTERN_C FCDECL2(Object*, RhNewString, CORINFO_CLASS_HANDLE typeHnd_, DWORD stringLength)
+EXTERN_C FCDECL2(Object*, RhNewString, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR stringLength)
 {
     PORTABILITY_ASSERT("RhNewString is not implemented on wasm");
     return nullptr;
@@ -482,3 +482,8 @@ void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArg
 {
     PORTABILITY_ASSERT("InvokeCalliStub is not implemented on wasm");
 }
+
+void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE target)
+{
+    PORTABILITY_ASSERT("Attempted to execute non-interpreter code from interpreter on wasm, this is not yet implemented");
+}

From 4a2f57ad3c4d8b11a26999ea284119472a03d301 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 23 Jul 2025 12:59:23 +0200
Subject: [PATCH 55/63] Feedback

Make FlushProcessWriteBuffers no-op on wasm
---
 src/coreclr/gc/unix/gcenv.unix.cpp     | 2 ++
 src/coreclr/pal/src/thread/process.cpp | 6 ++----
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/coreclr/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp
index 4a44be49c233bf..f86368654d8744 100644
--- a/src/coreclr/gc/unix/gcenv.unix.cpp
+++ b/src/coreclr/gc/unix/gcenv.unix.cpp
@@ -413,6 +413,7 @@ bool GCToOSInterface::CanGetCurrentProcessorNumber()
 // Flush write buffers of processors that are executing threads of the current process
 void GCToOSInterface::FlushProcessWriteBuffers()
 {
+#ifndef TARGET_WASM
 #if defined(__linux__) || HAVE_SYS_MEMBARRIER_H
     if (s_flushUsingMemBarrier)
     {
@@ -491,6 +492,7 @@ void GCToOSInterface::FlushProcessWriteBuffers()
         CHECK_MACH("vm_deallocate()", machret);
     }
 #endif // TARGET_APPLE
+#endif // !TARGET_WASM
 }
 
 // Break into a debugger. Uses a compiler intrinsic if one is available,
diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp
index 5c688fe8009b8b..e03b776ac28295 100644
--- a/src/coreclr/pal/src/thread/process.cpp
+++ b/src/coreclr/pal/src/thread/process.cpp
@@ -2657,6 +2657,7 @@ VOID
 PALAPI
 FlushProcessWriteBuffers()
 {
+#ifndef TARGET_BROWSER
 #if defined(__linux__) || HAVE_SYS_MEMBARRIER_H
     if (s_flushUsingMemBarrier)
     {
@@ -2670,22 +2671,18 @@ FlushProcessWriteBuffers()
         int status = pthread_mutex_lock(&flushProcessWriteBuffersMutex);
         FATAL_ASSERT(status == 0, "Failed to lock the flushProcessWriteBuffersMutex lock");
 
-#ifndef TARGET_BROWSER
         // Changing a helper memory page protection from read / write to no access
         // causes the OS to issue IPI to flush TLBs on all processors. This also
         // results in flushing the processor buffers.
         status = mprotect(s_helperPage, GetVirtualPageSize(), PROT_READ | PROT_WRITE);
         FATAL_ASSERT(status == 0, "Failed to change helper page protection to read / write");
-#endif // !TARGET_BROWSER
 
         // Ensure that the page is dirty before we change the protection so that
         // we prevent the OS from skipping the global TLB flush.
         InterlockedIncrement(s_helperPage);
 
-#ifndef TARGET_BROWSER
         status = mprotect(s_helperPage, GetVirtualPageSize(), PROT_NONE);
         FATAL_ASSERT(status == 0, "Failed to change helper page protection to no access");
-#endif // !TARGET_BROWSER
 
         status = pthread_mutex_unlock(&flushProcessWriteBuffersMutex);
         FATAL_ASSERT(status == 0, "Failed to unlock the flushProcessWriteBuffersMutex lock");
@@ -2720,6 +2717,7 @@ FlushProcessWriteBuffers()
         CHECK_MACH("vm_deallocate()", machret);
     }
 #endif // TARGET_APPLE
+#endif // !TARGET_BROWSER
 }
 
 /*++

From 3eae3d7cc26c71ca12510c9081166188c5f0f66a Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 23 Jul 2025 16:00:10 +0200
Subject: [PATCH 56/63] Feedback

Fix path
---
 src/coreclr/hosts/corewasmrun/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/hosts/corewasmrun/CMakeLists.txt b/src/coreclr/hosts/corewasmrun/CMakeLists.txt
index e64702d9f1830c..01613dde60315a 100644
--- a/src/coreclr/hosts/corewasmrun/CMakeLists.txt
+++ b/src/coreclr/hosts/corewasmrun/CMakeLists.txt
@@ -10,7 +10,7 @@ add_executable_clr(corewasmrun
   corewasmrun.cpp
 )
 
-set(_WASM_PRELOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/../../../../../bin/coreclr/browser.wasm.Debug/IL")
+set(_WASM_PRELOAD_DIR "${CMAKE_INSTALL_PREFIX}/IL")
 if (EXISTS "${_WASM_PRELOAD_DIR}")
   set(_WASM_PRELOAD_FILE --preload-file ${_WASM_PRELOAD_DIR}@/)
 endif (EXISTS "${_WASM_PRELOAD_DIR}")

From c2ecb4787ac72f9e80da0950dea4aadabe65d11d Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 23 Jul 2025 16:02:47 +0200
Subject: [PATCH 57/63] Fix whitespace

Co-authored-by: Jan Kotas 
---
 src/coreclr/clrdefinitions.cmake | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake
index 69c6812c279261..18b6c457977877 100644
--- a/src/coreclr/clrdefinitions.cmake
+++ b/src/coreclr/clrdefinitions.cmake
@@ -276,5 +276,4 @@ function(set_target_definitions_to_custom_os_and_arch)
   if (TARGETDETAILS_ARCH STREQUAL "armel")
     target_compile_definitions(${TARGETDETAILS_TARGET} PRIVATE ARM_SOFTFP)
   endif()
-
 endfunction()

From a9df6391a40db56fe8c487f3ccea61e2f71dfc3d Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 23 Jul 2025 16:03:31 +0200
Subject: [PATCH 58/63] Prefer TARGET_WASM

Co-authored-by: Jan Kotas 
---
 src/coreclr/pal/src/exception/signal.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp
index f9c9b2a74eb0ff..37f8eb18049b8a 100644
--- a/src/coreclr/pal/src/exception/signal.cpp
+++ b/src/coreclr/pal/src/exception/signal.cpp
@@ -219,7 +219,7 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
             return FALSE;
         }
 
-#ifndef TARGET_BROWSER
+#ifndef TARGET_WASM
         // create a guard page for the alternate stack
         int st = mprotect((void*)g_stackOverflowHandlerStack, GetVirtualPageSize(), PROT_NONE);
         if (st != 0)

From ca1ce4756604fccb6f0b6f4a4ed97e485a6fdb07 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 23 Jul 2025 16:04:31 +0200
Subject: [PATCH 59/63] Update src/coreclr/pal/src/init/pal.cpp

Co-authored-by: Jan Kotas 
---
 src/coreclr/pal/src/init/pal.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp
index aa0e1a5592ba4b..6c4a47445d2fec 100644
--- a/src/coreclr/pal/src/init/pal.cpp
+++ b/src/coreclr/pal/src/init/pal.cpp
@@ -727,7 +727,7 @@ PAL_InitializeCoreCLR(const char *szExePath, BOOL runningInExe)
     {
         return ERROR_DLL_INIT_FAILED;
     }
-#endif // !__wasm__
+#endif // !TARGET_WASM
 
     if (!PROCAbortInitialize())
     {

From 17d9952d9f8f70928971f12786408165a92ab2ae Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 23 Jul 2025 16:06:57 +0200
Subject: [PATCH 60/63] Prefer TARGET_WASM

Co-authored-by: Jan Kotas 
---
 src/coreclr/pal/src/init/pal.cpp      | 2 +-
 src/coreclr/pal/src/loader/module.cpp | 2 +-
 src/coreclr/pal/src/map/virtual.cpp   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp
index 6c4a47445d2fec..38139058dd108a 100644
--- a/src/coreclr/pal/src/init/pal.cpp
+++ b/src/coreclr/pal/src/init/pal.cpp
@@ -719,7 +719,7 @@ PAL_InitializeCoreCLR(const char *szExePath, BOOL runningInExe)
         return ERROR_SUCCESS;
     }
 
-#ifndef __wasm__ // we don't use shared libraries on wasm
+#ifndef TARGET_WASM // we don't use shared libraries on wasm
     // Now that the PAL is initialized it's safe to call the initialization methods for the code that used to
     // be dynamically loaded libraries but is now statically linked into CoreCLR just like the PAL, i.e. the
     // PAL RT and mscorwks.
diff --git a/src/coreclr/pal/src/loader/module.cpp b/src/coreclr/pal/src/loader/module.cpp
index 6cb95277f142e5..fd59c76bcda9ce 100644
--- a/src/coreclr/pal/src/loader/module.cpp
+++ b/src/coreclr/pal/src/loader/module.cpp
@@ -926,7 +926,7 @@ PAL_CopyModuleData(PVOID moduleBase, PVOID destinationBufferStart, PVOID destina
     }
     return param.result;
 }
-#elif defined(__wasm__)
+#elif defined(TARGET_WASM)
 // WASM-TODO: get rid of whole module loading on wasm
 PALIMPORT
 int
diff --git a/src/coreclr/pal/src/map/virtual.cpp b/src/coreclr/pal/src/map/virtual.cpp
index 7936c968c1664e..bd5945e6919411 100644
--- a/src/coreclr/pal/src/map/virtual.cpp
+++ b/src/coreclr/pal/src/map/virtual.cpp
@@ -641,7 +641,7 @@ static LPVOID ReserveVirtualMemory(
     }
 #endif  // MMAP_ANON_IGNORES_PROTECTION
 
-#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER)
+#if defined(MADV_DONTDUMP) && !defined(TARGET_WASM)
     // Do not include reserved uncommitted memory in coredump.
     if (!(fAllocationType & MEM_COMMIT))
     {

From 1e2246f6bcfbace1efbe0ad62acd72ade4123645 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 23 Jul 2025 16:15:15 +0200
Subject: [PATCH 61/63] Prefer TARGET_WASM

---
 src/coreclr/pal/src/debug/debug.cpp      |  2 +-
 src/coreclr/pal/src/exception/signal.cpp |  2 +-
 src/coreclr/pal/src/init/pal.cpp         |  6 +++---
 src/coreclr/pal/src/loader/module.cpp    |  2 +-
 src/coreclr/pal/src/map/virtual.cpp      |  6 +++---
 src/coreclr/pal/src/thread/thread.cpp    | 10 +++++-----
 6 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/src/coreclr/pal/src/debug/debug.cpp b/src/coreclr/pal/src/debug/debug.cpp
index b248de3533d7a9..64dd8b7e0caadd 100644
--- a/src/coreclr/pal/src/debug/debug.cpp
+++ b/src/coreclr/pal/src/debug/debug.cpp
@@ -425,7 +425,7 @@ DebugBreak(
 BOOL
 IsInDebugBreak(void *addr)
 {
-#if defined (__wasm__)
+#ifdef TARGET_WASM
     _ASSERT("IsInDebugBreak not implemented on wasm");
     return false;
 #else
diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp
index 37f8eb18049b8a..732d1d5db05933 100644
--- a/src/coreclr/pal/src/exception/signal.cpp
+++ b/src/coreclr/pal/src/exception/signal.cpp
@@ -227,7 +227,7 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
             munmap((void*)g_stackOverflowHandlerStack, stackOverflowStackSize);
             return FALSE;
         }
-#endif // TARGET_BROWSER
+#endif // TARGET_WASM
 
         g_stackOverflowHandlerStack = (void*)((size_t)g_stackOverflowHandlerStack + stackOverflowStackSize);
 #endif // HAVE_MACH_EXCEPTIONS
diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp
index 38139058dd108a..f7a0cef45a5db9 100644
--- a/src/coreclr/pal/src/init/pal.cpp
+++ b/src/coreclr/pal/src/init/pal.cpp
@@ -588,7 +588,7 @@ Initialize(
             }
         }
 
-#ifndef __wasm__
+#ifndef TARGET_WASM
         if (flags & PAL_INITIALIZE_SYNC_THREAD)
         {
             //
@@ -601,7 +601,7 @@ Initialize(
                 goto CLEANUP13;
             }
         }
-#endif
+#endif // !TARGET_WASM
         /* initialize structured exception handling stuff (signals, etc) */
         if (FALSE == SEHInitialize(pThread, flags))
         {
@@ -918,7 +918,7 @@ Return value:
 --*/
 static BOOL INIT_IncreaseDescriptorLimit(void)
 {
-#ifdef __wasm__
+#ifdef TARGET_WASM
     // WebAssembly cannot set limits
     return TRUE;
 #endif
diff --git a/src/coreclr/pal/src/loader/module.cpp b/src/coreclr/pal/src/loader/module.cpp
index fd59c76bcda9ce..76fdb966afb6ac 100644
--- a/src/coreclr/pal/src/loader/module.cpp
+++ b/src/coreclr/pal/src/loader/module.cpp
@@ -1026,7 +1026,7 @@ BOOL LOADInitializeModules()
 
     exe_module.self = (HMODULE)&exe_module;
     exe_module.dl_handle = dlopen(nullptr, RTLD_LAZY);
-#if not defined(__wasm__) // wasm does not support shared libraries
+#ifndef TARGET_WASM // wasm does not support shared libraries
     if (exe_module.dl_handle == nullptr)
     {
         ERROR("Executable module will be broken : dlopen(nullptr) failed\n");
diff --git a/src/coreclr/pal/src/map/virtual.cpp b/src/coreclr/pal/src/map/virtual.cpp
index bd5945e6919411..edb56e3fa3e7d3 100644
--- a/src/coreclr/pal/src/map/virtual.cpp
+++ b/src/coreclr/pal/src/map/virtual.cpp
@@ -1059,7 +1059,7 @@ VirtualFree(
 
         // mmap support on emscripten/wasm is very limited and doesn't support location hints
         // (when address is not null)
-#ifndef __wasm__
+#ifndef TARGET_WASM
         // Explicitly calling mmap instead of mprotect here makes it
         // that much more clear to the operating system that we no
         // longer need these pages.
@@ -1090,13 +1090,13 @@ VirtualFree(
             pthrCurrent->SetLastError( ERROR_INTERNAL_ERROR );
             goto VirtualFreeExit;
         }
-#else // __wasm__
+#else // TARGET_WASM
         // We can't decommit the mapping (MAP_FIXED doesn't work in emscripten), and we can't
         //  MADV_DONTNEED it (madvise doesn't work in emscripten), but we can at least zero
         //  the memory so that if an attempt is made to reuse it later, the memory will be
         //  empty as PAL tests expect it to be.
         ZeroMemory((LPVOID) StartBoundary, MemSize);
-#endif // __wasm__
+#endif // TARGET_WASM
     }
 
     if ( dwFreeType & MEM_RELEASE )
diff --git a/src/coreclr/pal/src/thread/thread.cpp b/src/coreclr/pal/src/thread/thread.cpp
index 429c7c27a2e9f0..ec6920f922cade 100644
--- a/src/coreclr/pal/src/thread/thread.cpp
+++ b/src/coreclr/pal/src/thread/thread.cpp
@@ -2284,10 +2284,10 @@ Return :
 BOOL
 CPalThread::EnsureSignalAlternateStack()
 {
-#ifdef __wasm__
+#ifdef TARGET_WASM
     // WebAssembly does not support alternate signal stacks.
     return TRUE;
-#else // !__wasm__
+#else // !TARGET_WASM
     int st = 0;
 
     if (g_registered_signal_handlers)
@@ -2341,7 +2341,7 @@ CPalThread::EnsureSignalAlternateStack()
     }
 
     return (st == 0);
-#endif // !__wasm__
+#endif // !TARGET_WASM
 }
 
 /*++
@@ -2359,7 +2359,7 @@ Return :
 void
 CPalThread::FreeSignalAlternateStack()
 {
-#ifndef __wasm__ // WebAssembly does not support alternate signal stacks.
+#ifndef TARGET_WASM // WebAssembly does not support alternate signal stacks.
     void *altstack = m_alternateStack;
     m_alternateStack = nullptr;
 
@@ -2383,7 +2383,7 @@ CPalThread::FreeSignalAlternateStack()
             }
         }
     }
-#endif // !__wasm__
+#endif // !TARGET_WASM
 }
 
 #endif // !HAVE_MACH_EXCEPTIONS

From 52dd3d20820638b26cc09d858b0b8949d04700c8 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 23 Jul 2025 16:20:18 +0200
Subject: [PATCH 62/63] Few more places to use more general TARGET_WASM

---
 src/coreclr/pal/src/map/virtual.cpp | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/coreclr/pal/src/map/virtual.cpp b/src/coreclr/pal/src/map/virtual.cpp
index edb56e3fa3e7d3..9143917af4c2bb 100644
--- a/src/coreclr/pal/src/map/virtual.cpp
+++ b/src/coreclr/pal/src/map/virtual.cpp
@@ -730,7 +730,7 @@ VIRTUALCommitMemory(
 
     nProtect = W32toUnixAccessControl(flProtect);
 
-#ifndef TARGET_BROWSER
+#ifndef TARGET_WASM
     // Commit the pages
     if (mprotect((void *) StartBoundary, MemSize, nProtect) != 0)
     {
@@ -739,7 +739,7 @@ VIRTUALCommitMemory(
     }
 #endif
 
-#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER)
+#if defined(MADV_DONTDUMP) && !defined(TARGET_WASM)
     // Include committed memory in coredump. Any newly allocated memory included by default.
     if (!IsNewMemory)
     {
@@ -750,7 +750,7 @@ VIRTUALCommitMemory(
     pRetVal = (void *) StartBoundary;
     goto done;
 
-#ifndef TARGET_BROWSER
+#ifndef TARGET_WASM
 error:
 #endif
     if ( flAllocationType & MEM_RESERVE || IsLocallyReserved )
@@ -1077,7 +1077,7 @@ VirtualFree(
             }
 #endif  // MMAP_ANON_IGNORES_PROTECTION
 
-#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER)
+#if defined(MADV_DONTDUMP) && !defined(TARGET_WASM)
             // Do not include freed memory in coredump.
             madvise((LPVOID) StartBoundary, MemSize, MADV_DONTDUMP);
 #endif
@@ -1211,11 +1211,11 @@ VirtualProtect(
     }
 
     pEntry = VIRTUALFindRegionInformation( StartBoundary );
-#ifndef TARGET_BROWSER
+#ifndef TARGET_WASM
     if ( 0 == mprotect( (LPVOID)StartBoundary, MemSize,
                    W32toUnixAccessControl( flNewProtect ) ) )
     {
-#endif // !TARGET_BROWSER
+#endif // !TARGET_WASM
         /* Reset the access protection. */
         TRACE( "Number of pages to change %d, starting page %d \n",
                NumberOfPagesToChange, OffSet );
@@ -1226,14 +1226,14 @@ VirtualProtect(
          */
         *lpflOldProtect = PAGE_EXECUTE_READWRITE;
 
-#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER)
+#if defined(MADV_DONTDUMP) && !defined(TARGET_WASM)
         // Include or exclude memory from coredump based on the protection.
         int advise = flNewProtect == PAGE_NOACCESS ? MADV_DONTDUMP : MADV_DODUMP;
         madvise((LPVOID)StartBoundary, MemSize, advise);
 #endif
 
         bRetVal = TRUE;
-#ifndef TARGET_BROWSER
+#ifndef TARGET_WASM
     }
     else
     {
@@ -1247,7 +1247,7 @@ VirtualProtect(
             SetLastError( ERROR_INVALID_ACCESS );
         }
     }
-#endif // !TARGET_BROWSER
+#endif // !TARGET_WASM
 ExitVirtualProtect:
     minipal_mutex_leave(&virtual_critsec);
 

From 4f6f578bd57608e584203343b2df78ecf2821a50 Mon Sep 17 00:00:00 2001
From: Radek Doulik 
Date: Wed, 23 Jul 2025 16:40:41 +0200
Subject: [PATCH 63/63] Prefer TARGET_WASM

Co-authored-by: Jan Kotas 
---
 src/coreclr/gc/unix/gcenv.unix.cpp     | 8 ++++----
 src/coreclr/pal/src/thread/process.cpp | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/coreclr/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp
index f86368654d8744..33855147497c2b 100644
--- a/src/coreclr/gc/unix/gcenv.unix.cpp
+++ b/src/coreclr/gc/unix/gcenv.unix.cpp
@@ -579,7 +579,7 @@ static void* VirtualReserveInner(size_t size, size_t alignment, uint32_t flags,
         }
 
         pRetVal = pAlignedRetVal;
-#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER)
+#if defined(MADV_DONTDUMP) && !defined(TARGET_WASM)
         // Do not include reserved uncommitted memory in coredump.
         if (!committing)
         {
@@ -627,13 +627,13 @@ bool GCToOSInterface::VirtualRelease(void* address, size_t size)
 //  true if it has succeeded, false if it has failed
 static bool VirtualCommitInner(void* address, size_t size, uint16_t node, bool newMemory)
 {
-#ifndef TARGET_BROWSER
+#ifndef TARGET_WASM
     bool success = mprotect(address, size, PROT_WRITE | PROT_READ) == 0;
 #else
     bool success = true;
-#endif // !TARGET_BROWSER
+#endif // !TARGET_WASM
 
-#if defined(MADV_DONTDUMP) && !defined(TARGET_BROWSER)
+#if defined(MADV_DONTDUMP) && !defined(TARGET_WASM)
     if (success && !newMemory)
     {
         // Include committed memory in coredump. New memory is included by default.
diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp
index e03b776ac28295..cb00d493be4fb6 100644
--- a/src/coreclr/pal/src/thread/process.cpp
+++ b/src/coreclr/pal/src/thread/process.cpp
@@ -2657,7 +2657,7 @@ VOID
 PALAPI
 FlushProcessWriteBuffers()
 {
-#ifndef TARGET_BROWSER
+#ifndef TARGET_WASM
 #if defined(__linux__) || HAVE_SYS_MEMBARRIER_H
     if (s_flushUsingMemBarrier)
     {
@@ -2717,7 +2717,7 @@ FlushProcessWriteBuffers()
         CHECK_MACH("vm_deallocate()", machret);
     }
 #endif // TARGET_APPLE
-#endif // !TARGET_BROWSER
+#endif // !TARGET_WASM
 }
 
 /*++