diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index 7286f655004ca9..6e9519affb16d1 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -39,6 +39,10 @@ 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) +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..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 @@ -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 @@ -117,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 @@ -139,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_AdjustedControlPC = 0xd0; +#else public const int SIZEOF__StackFrameIterator = 0xc4; - public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0xb2; public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0xc0; +#endif + public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0xb2; #endif // TARGET_64BIT #endif // DEBUG @@ -167,7 +177,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/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake index e0c6b08ddf056f..801e40f2c8480d 100644 --- a/src/coreclr/clrfeatures.cmake +++ b/src/coreclr/clrfeatures.cmake @@ -32,13 +32,15 @@ endif(NOT DEFINED FEATURE_DBGIPC) if(NOT DEFINED FEATURE_INTERPRETER) if(CLR_CMAKE_TARGET_ANDROID) - set(FEATURE_INTERPRETER 0) + set(FEATURE_INTERPRETER 0) + elseif(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) + 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() endif(NOT DEFINED FEATURE_INTERPRETER) @@ -54,7 +56,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..5d063abe182de4 100644 --- a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt +++ b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt @@ -56,23 +56,28 @@ endif (CLR_CMAKE_HOST_WIN32) add_definitions(-DFX_VER_INTERNALNAME_STR=CoreCLR.dll) -add_library_clr(coreclr - SHARED - ${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}) + 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) +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) # 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 +85,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 +100,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) @@ -172,12 +177,25 @@ if(FEATURE_STATICALLY_LINKED) set(CLRJIT_STATIC clrjit_static) endif(FEATURE_STATICALLY_LINKED) +if(FEATURE_JIT) + set(CORECLR_STATIC_CLRJIT_STATIC clrjit_static) +endif(FEATURE_JIT) + +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 ${CORECLR_STATIC_CLRJIT_STATIC} ${CEE_WKS_STATIC} ${FOUNDATION}) target_compile_definitions(coreclr_static PUBLIC CORECLR_EMBEDDED) if (CLR_CMAKE_HOST_ANDROID) @@ -227,10 +245,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/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp index 720828b2565f85..33855147497c2b 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()) @@ -262,6 +262,7 @@ bool GCToOSInterface::Initialize() } } #endif // !TARGET_APPLE +#endif // !TARGET_WASM InitializeCGroup(); @@ -412,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) { @@ -490,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, @@ -576,7 +579,7 @@ static void* VirtualReserveInner(size_t size, size_t alignment, uint32_t flags, } pRetVal = pAlignedRetVal; -#ifdef MADV_DONTDUMP +#if defined(MADV_DONTDUMP) && !defined(TARGET_WASM) // Do not include reserved uncommitted memory in coredump. if (!committing) { @@ -624,9 +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_WASM bool success = mprotect(address, size, PROT_WRITE | PROT_READ) == 0; +#else + bool success = true; +#endif // !TARGET_WASM -#ifdef MADV_DODUMP +#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/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..01613dde60315a --- /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_INSTALL_PREFIX}/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 -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) + +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..2fff454fc0200b --- /dev/null +++ b/src/coreclr/hosts/corewasmrun/corewasmrun.cpp @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#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..f9b63c824e261e 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 PEXCEPTION_ROUTINE
 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
-    );
+    )
+{
+    PORTABILITY_ASSERT("The function RtlVirtualUnwind is not implemented on wasm");
+    return nullptr;
+}
 
 FORCEINLINE
 ULONG
@@ -529,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/inc/loaderheap.h b/src/coreclr/inc/loaderheap.h
index 9c0e8c82463711..79228c7eb5410d 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/inc/switches.h b/src/coreclr/inc/switches.h
index 5e8f90c0548a30..7915e0944f4175 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
+
+#ifdef TARGET_WASM
+#define PEIMAGE_FLAT_LAYOUT_ONLY
+#endif // !TARGET_WASM
diff --git a/src/coreclr/interpreter/compiler.h b/src/coreclr/interpreter/compiler.h
index 15d0050d074f09..24381d5ec529c7 100644
--- a/src/coreclr/interpreter/compiler.h
+++ b/src/coreclr/interpreter/compiler.h
@@ -478,7 +478,12 @@ class InterpCompiler
     CORINFO_CLASS_HANDLE m_classHnd;
     #ifdef DEBUG
     TArray m_methodName;
+#ifdef TARGET_WASM
+    // enable verbose output on wasm temporarily
+    bool m_verbose = true;
+#else
     bool m_verbose = false;
+#endif // TARGET_WASM
 
     const char* PointerIsClassHandle = (const char*)0x1;
     const char* PointerIsMethodHandle = (const char*)0x2;
@@ -494,7 +499,7 @@ class InterpCompiler
         checkNoError(dn_simdhash_ptr_ptr_try_add(m_pointerToNameMap.GetValue(), ptr, (void*)name));
     }
     void PrintNameInPointerMap(void* ptr);
-#endif
+#endif // DEBUG
 
     static int32_t InterpGetMovForType(InterpType interpType, bool signExtend);
 
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/palrt.h b/src/coreclr/pal/inc/rt/palrt.h
index 215290ce093439..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
 
-#define _ReturnAddress() __builtin_return_address(0)
-
 #define DIRECTORY_SEPARATOR_CHAR_A '/'
 #define DIRECTORY_SEPARATOR_CHAR_W W('/')
 #define DIRECTORY_SEPARATOR_STR_A "/"
@@ -1006,9 +1004,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.
-    DWORD Reserved;
+    // WASM does not build the JIT at this point,
+    // so we only add necessary fields.
+    UINT32 ControlPc;
 } DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
 
 #else
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/seh.cpp b/src/coreclr/pal/src/exception/seh.cpp
index c2f28cff936c96..26c963ff3b1110 100644
--- a/src/coreclr/pal/src/exception/seh.cpp
+++ b/src/coreclr/pal/src/exception/seh.cpp
@@ -248,7 +248,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 444bad7e5c072c..732d1d5db05933 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_WASM
         // 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_WASM
 
         g_stackOverflowHandlerStack = (void*)((size_t)g_stackOverflowHandlerStack + stackOverflowStackSize);
 #endif // HAVE_MACH_EXCEPTIONS
@@ -876,7 +878,7 @@ Parameters :
 __attribute__((noinline))
 static void InvokeActivationHandler(CONTEXT *pWinContext)
 {
-    g_InvokeActivationHandlerReturnAddress = __builtin_return_address(0);
+    g_InvokeActivationHandlerReturnAddress = _ReturnAddress();
     g_activationFunction(pWinContext);
 }
 
diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp
index 6811690132daed..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))
         {
@@ -719,6 +719,7 @@ PAL_InitializeCoreCLR(const char *szExePath, BOOL runningInExe)
         return ERROR_SUCCESS;
     }
 
+#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.
@@ -726,6 +727,7 @@ PAL_InitializeCoreCLR(const char *szExePath, BOOL runningInExe)
     {
         return ERROR_DLL_INIT_FAILED;
     }
+#endif // !TARGET_WASM
 
     if (!PROCAbortInitialize())
     {
@@ -916,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 d7cff970a0b02e..76fdb966afb6ac 100644
--- a/src/coreclr/pal/src/loader/module.cpp
+++ b/src/coreclr/pal/src/loader/module.cpp
@@ -926,6 +926,16 @@ PAL_CopyModuleData(PVOID moduleBase, PVOID destinationBufferStart, PVOID destina
     }
     return param.result;
 }
+#elif defined(TARGET_WASM)
+// 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");
+    return 0;
+}
 #else
 static int CopyModuleDataCallback(struct dl_phdr_info *info, size_t size, void *data)
 {
@@ -1016,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 dcf3fd5c51c852..9143917af4c2bb 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_WASM)
     // Do not include reserved uncommitted memory in coredump.
     if (!(fAllocationType & MEM_COMMIT))
     {
@@ -730,14 +730,16 @@ VIRTUALCommitMemory(
 
     nProtect = W32toUnixAccessControl(flProtect);
 
+#ifndef TARGET_WASM
     // 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_WASM)
     // 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_WASM
 error:
+#endif
     if ( flAllocationType & MEM_RESERVE || IsLocallyReserved )
     {
         munmap( pRetVal, MemSize );
@@ -1055,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.
@@ -1073,7 +1077,7 @@ VirtualFree(
             }
 #endif  // MMAP_ANON_IGNORES_PROTECTION
 
-#ifdef MADV_DONTDUMP
+#if defined(MADV_DONTDUMP) && !defined(TARGET_WASM)
             // Do not include freed memory in coredump.
             madvise((LPVOID) StartBoundary, MemSize, MADV_DONTDUMP);
 #endif
@@ -1086,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 )
@@ -1207,9 +1211,11 @@ VirtualProtect(
     }
 
     pEntry = VIRTUALFindRegionInformation( StartBoundary );
+#ifndef TARGET_WASM
     if ( 0 == mprotect( (LPVOID)StartBoundary, MemSize,
                    W32toUnixAccessControl( flNewProtect ) ) )
     {
+#endif // !TARGET_WASM
         /* 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_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_WASM
     }
     else
     {
@@ -1240,6 +1247,7 @@ VirtualProtect(
             SetLastError( ERROR_INVALID_ACCESS );
         }
     }
+#endif // !TARGET_WASM
 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 f29bded4cb860c..cb00d493be4fb6 100644
--- a/src/coreclr/pal/src/thread/process.cpp
+++ b/src/coreclr/pal/src/thread/process.cpp
@@ -2603,7 +2603,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));
@@ -2633,7 +2633,7 @@ InitializeFlushProcessWriteBuffers()
     }
 
     return status == 0;
-#endif // TARGET_APPLE
+#endif // TARGET_APPLE || TARGET_WASM
 }
 
 #define FATAL_ASSERT(e, msg) \
@@ -2657,6 +2657,7 @@ VOID
 PALAPI
 FlushProcessWriteBuffers()
 {
+#ifndef TARGET_WASM
 #if defined(__linux__) || HAVE_SYS_MEMBARRIER_H
     if (s_flushUsingMemBarrier)
     {
@@ -2716,6 +2717,7 @@ FlushProcessWriteBuffers()
         CHECK_MACH("vm_deallocate()", machret);
     }
 #endif // TARGET_APPLE
+#endif // !TARGET_WASM
 }
 
 /*++
diff --git a/src/coreclr/pal/src/thread/thread.cpp b/src/coreclr/pal/src/thread/thread.cpp
index 31ccdabef28d55..ec6920f922cade 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
@@ -2280,6 +2284,10 @@ Return :
 BOOL
 CPalThread::EnsureSignalAlternateStack()
 {
+#ifdef TARGET_WASM
+    // WebAssembly does not support alternate signal stacks.
+    return TRUE;
+#else // !TARGET_WASM
     int st = 0;
 
     if (g_registered_signal_handlers)
@@ -2333,6 +2341,7 @@ CPalThread::EnsureSignalAlternateStack()
     }
 
     return (st == 0);
+#endif // !TARGET_WASM
 }
 
 /*++
@@ -2350,6 +2359,7 @@ Return :
 void
 CPalThread::FreeSignalAlternateStack()
 {
+#ifndef TARGET_WASM // WebAssembly does not support alternate signal stacks.
     void *altstack = m_alternateStack;
     m_alternateStack = nullptr;
 
@@ -2373,6 +2383,7 @@ CPalThread::FreeSignalAlternateStack()
             }
         }
     }
+#endif // !TARGET_WASM
 }
 
 #endif // !HAVE_MACH_EXCEPTIONS
@@ -2443,6 +2454,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
@@ -2459,7 +2471,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;
 }
@@ -2483,6 +2498,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
@@ -2497,7 +2513,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..2c6915c3fdfad5 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 HOST_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/utilcode/executableallocator.cpp b/src/coreclr/utilcode/executableallocator.cpp
index 4cacac8526b187..565ecfaba617b9 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;
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;
diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt
index 0a37c998ba581f..a31e5f75e53124 100644
--- a/src/coreclr/vm/CMakeLists.txt
+++ b/src/coreclr/vm/CMakeLists.txt
@@ -914,6 +914,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 cf6e0834dcb180..21f9b00f6da872 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 0;
+    return DACF_NONE;
 #endif // DEBUGGING_SUPPORTED
 }
 
diff --git a/src/coreclr/vm/callcounting.cpp b/src/coreclr/vm/callcounting.cpp
index 4dd2aea86bf33f..f654cc34b0aed0 100644
--- a/src/coreclr/vm/callcounting.cpp
+++ b/src/coreclr/vm/callcounting.cpp
@@ -326,6 +326,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 00f7f1110d4756..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(
@@ -515,6 +519,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
@@ -531,6 +538,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..12b4a8da1af464 100644
--- a/src/coreclr/vm/callhelpers.h
+++ b/src/coreclr/vm/callhelpers.h
@@ -28,6 +28,13 @@ struct CallDescrData
 #endif
     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
 
 #ifdef CALLDESCR_RETBUFFARGREG
     // Pointer to return buffer arg location
diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h
index 5fbff84b36523d..9ae7d10df0c9c5 100644
--- a/src/coreclr/vm/callingconvention.h
+++ b/src/coreclr/vm/callingconvention.h
@@ -1296,6 +1296,10 @@ 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
+        // WASM_TODO find out whether we can use implicit stack here
+        m_ofsStack = 0;
 #else
         PORTABILITY_ASSERT("ArgIteratorTemplate::GetNextOffset");
 #endif
@@ -1867,6 +1871,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 901c102b33dd77..10855af6bc402f 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(TARGET_WASM)
 
 #include "callstubgenerator.h"
 #include "ecall.h"
@@ -1895,4 +1895,4 @@ CallStubGenerator::ReturnType CallStubGenerator::GetReturnType(ArgIterator *pArg
     return ReturnTypeVoid;
 }
 
-#endif // FEATURE_INTERPRETER
+#endif // FEATURE_INTERPRETER && !TARGET_WASM
diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp
index 7c24437a5a444c..4ad3ae3cc78925 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
 
@@ -842,7 +842,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 TARGET_WASM
         InitializeDebugger(); // throws on error
+#endif
 #endif // DEBUGGING_SUPPORTED
 
 #ifdef PROFILING_SUPPORTED
@@ -920,7 +922,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(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/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 028534a932b8a9..2537e0bf3d5a33 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) && !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
diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp
index 653117ba3ecc29..8a34fbe57be54e 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 PEIMAGE_FLAT_LAYOUT_ONLY
     // Creating the Assembly should have ensured the PEAssembly is loaded
     _ASSERT(GetPEAssembly()->IsLoaded());
+#endif
 }
 
 DomainAssembly::~DomainAssembly()
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 ea0a3509320bc3..38a1fb0a616a6b 100644
--- a/src/coreclr/vm/interpexec.cpp
+++ b/src/coreclr/vm/interpexec.cpp
@@ -6,12 +6,17 @@
 #include "threads.h"
 #include "gcenv.h"
 #include "interpexec.h"
-#include "callstubgenerator.h"
 #include "frames.h"
 
 // for numeric_limits
 #include 
 
+#ifdef TARGET_WASM
+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"
+
 void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE target)
 {
     CONTRACTL
@@ -107,6 +112,8 @@ CallStubHeader *CreateNativeToInterpreterCallStub(InterpMethod* pInterpMethod)
     return pHeader;
 }
 
+#endif // !TARGET_WASM
+
 typedef void* (*HELPER_FTN_P_P)(void*);
 typedef void* (*HELPER_FTN_BOX_UNBOX)(MethodTable*, void*);
 typedef Object* (*HELPER_FTN_NEWARR)(MethodTable*, intptr_t);
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 0cf8e884af4405..77098664687ca3 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -11200,9 +11200,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);
@@ -11216,7 +11218,9 @@ LPVOID CInterpreterJitInfo::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* sz
     result = callStubGenerator.GenerateCallStubForSig(sig);
 
     EE_TO_JIT_TRANSITION();
-
+#else
+    PORTABILITY_ASSERT("GetCookieForInterpreterCalliSig is not supported on wasm yet");
+#endif // !TARGET_WASM
     return result;
 }
 
diff --git a/src/coreclr/vm/peassembly.cpp b/src/coreclr/vm/peassembly.cpp
index adc08d6fc020b6..0ab24368e027c1 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 PEIMAGE_FLAT_LAYOUT_ONLY
+        PEImageLayout::LAYOUT_FLAT
+#else
+        PEImageLayout::LAYOUT_LOADED
+#endif
+        );
     if (pLayout == NULL)
     {
         EEFileLoadException::Throw(this, COR_E_BADIMAGEFORMAT, NULL);
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..4362b3b571d28e 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 PEIMAGE_FLAT_LAYOUT_ONLY
         if (bIsLoadedLayoutPreferred)
         {
             _ASSERTE(bIsLoadedLayoutSuitable);
             pRetVal = PEImage::CreateLoadedLayout(!bIsFlatLayoutSuitable);
         }
+#endif
 
         if (pRetVal == NULL)
         {
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;
 
diff --git a/src/coreclr/vm/precode.cpp b/src/coreclr/vm/precode.cpp
index bb5f2491a7e0e6..44efd650c96cc2 100644
--- a/src/coreclr/vm/precode.cpp
+++ b/src/coreclr/vm/precode.cpp
@@ -134,6 +134,9 @@ MethodDesc* Precode::GetMethodDesc(BOOL fSpeculative /*= FALSE*/)
     TADDR pMD = (TADDR)NULL;
 
     PrecodeType precodeType = GetType();
+#ifdef TARGET_WASM
+    pMD = *(TADDR*)(m_data + OFFSETOF_PRECODE_MD);
+#else
     switch (precodeType)
     {
     case PRECODE_STUB:
@@ -166,6 +169,7 @@ MethodDesc* Precode::GetMethodDesc(BOOL fSpeculative /*= FALSE*/)
     default:
         break;
     }
+#endif // TARGET_WASM
 
     if (pMD == (TADDR)NULL)
     {
@@ -318,6 +322,10 @@ void Precode::Init(Precode* pPrecodeRX, PrecodeType t, MethodDesc* pMD, LoaderAl
 {
     LIMITED_METHOD_CONTRACT;
 
+#ifdef TARGET_WASM
+    m_data[OFFSETOF_PRECODE_TYPE] = t;
+    *(TADDR*)(m_data + OFFSETOF_PRECODE_MD) = (TADDR)pMD;
+#else
     switch (t) {
     case PRECODE_STUB:
         ((StubPrecode*)this)->Init((StubPrecode*)pPrecodeRX, (TADDR)pMD, pLoaderAllocator);
@@ -341,6 +349,7 @@ void Precode::Init(Precode* pPrecodeRX, PrecodeType t, MethodDesc* pMD, LoaderAl
         UnexpectedPrecodeType("Precode::Init", t);
         break;
     }
+#endif
 
     _ASSERTE(IsValidType(GetType()));
 }
@@ -562,6 +571,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
@@ -714,6 +725,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
diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h
index 21df63fcab6af8..5d9bf8c98fdd21 100644
--- a/src/coreclr/vm/precode.h
+++ b/src/coreclr/vm/precode.h
@@ -40,8 +40,10 @@ EXTERN_C VOID STDCALL PrecodeRemotingThunk();
 
 #elif defined(TARGET_WASM)
 
-#define SIZEOF_PRECODE_BASE         0
-
+// 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
 
 #ifndef DACCESS_COMPILE
@@ -100,7 +102,7 @@ struct StubPrecode
 #elif defined(TARGET_RISCV64)
     static const SIZE_T CodeSize = 24;
 #elif defined(TARGET_WASM)
-    static const SIZE_T CodeSize = 0;
+    static const SIZE_T CodeSize = 3*sizeof(void*);
 #endif // TARGET_AMD64
 
     BYTE m_code[CodeSize];
@@ -383,7 +385,7 @@ struct FixupPrecode
     static const SIZE_T CodeSize = 32;
     static const int FixupCodeOffset = 10;
 #elif defined(TARGET_WASM)
-    static const SIZE_T CodeSize = 0;
+    static const SIZE_T CodeSize = 2*sizeof(void*);
     static const int FixupCodeOffset = 0;
 #endif // TARGET_AMD64
 
@@ -530,6 +532,10 @@ inline BYTE StubPrecode::GetType()
     LIMITED_METHOD_DAC_CONTRACT;
     TADDR type = GetData()->Type;
 
+#ifdef TARGET_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.
@@ -631,7 +637,9 @@ class Precode {
     {
         LIMITED_METHOD_CONTRACT;
         SUPPORTS_DAC;
-
+#ifdef TARGET_WASM // WASM-TODO: we will not need this once we have real precode on Wasm
+        return (PrecodeType)m_data[OFFSETOF_PRECODE_TYPE];
+#endif
         PrecodeType basicPrecodeType = PRECODE_INVALID;
         if (StubPrecode::IsStubPrecodeByASM(PINSTRToPCODE(dac_cast(this))))
         {
@@ -748,6 +756,10 @@ class Precode {
         fSpeculative = TRUE;
 #endif
 
+#ifdef TARGET_WASM // WASM-TODO: we will not need this once we have real precode on Wasm
+        return (PTR_Precode)addr;
+#endif
+
         TADDR pInstr = PCODEToPINSTR(addr);
 
         // Always do consistency check in debug
@@ -805,6 +817,13 @@ 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
+// 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
+
 // A summary of the precode layout for diagnostic purposes
 struct PrecodeMachineDescriptor
 {
diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp
index e13b5143facd46..a6478d1a8a0cca 100644
--- a/src/coreclr/vm/prestub.cpp
+++ b/src/coreclr/vm/prestub.cpp
@@ -1984,16 +1984,23 @@ extern "C" PCODE STDCALL PreStubWorker(TransitionBlock* pTransitionBlock, Method
 }
 
 #ifdef FEATURE_INTERPRETER
-extern "C" void* STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, 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);
     }
+
+    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
@@ -2020,6 +2027,20 @@ extern "C" void* STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBl
 
     return frames.interpMethodContextFrame.pRetVal;
 }
+
+extern "C" void* STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, void* 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
 
 #ifdef _DEBUG
@@ -2314,13 +2335,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/threads.cpp b/src/coreclr/vm/threads.cpp
index b550748b70647b..76f48455a33f7c 100644
--- a/src/coreclr/vm/threads.cpp
+++ b/src/coreclr/vm/threads.cpp
@@ -6044,11 +6044,13 @@ BOOL Thread::SetStackLimits(SetStackLimitScope scope)
     {
         m_CacheStackBase  = GetStackUpperBound();
         m_CacheStackLimit = GetStackLowerBound();
+#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");
             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..afbf3e07ff7913
--- /dev/null
+++ b/src/coreclr/vm/wasm/calldescrworkerwasm.cpp
@@ -0,0 +1,21 @@
+// 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, void* retBuff);
+
+extern "C" void STDCALL CallDescrWorkerInternal(CallDescrData * pCallDescrData)
+{
+    MethodDesc* pMethod = pCallDescrData->pMD;
+    InterpByteCodeStart* targetIp = pMethod->GetInterpreterCode();
+    if (targetIp == NULL)
+    {
+        GCX_PREEMP();
+        pMethod->PrepareInitialCode(CallerGCMode::Coop);
+        targetIp = pMethod->GetInterpreterCode();
+    }
+
+    ExecuteInterpretedMethodWithArgs(pCallDescrData->pTransitionBlock, (TADDR)targetIp, (int8_t*)pCallDescrData->pSrc, pCallDescrData->nArgsSize, 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..d16676c4408524
--- /dev/null
+++ b/src/coreclr/vm/wasm/helpers.cpp
@@ -0,0 +1,489 @@
+// 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");
+}
+
+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 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 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 WASM-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 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_, INT_PTR 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");
+}
+
+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");
+}
+
+void InitJITWriteBarrierHelpers()
+{
+    // Nothing to do - wasm has static write barriers
+}
+
+int StompWriteBarrierEphemeral(bool isRuntimeSuspended)
+{
+    // WASM-TODO: implement me
+    return 0;
+}
+
+int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
+{
+    // Nothing to do - wasm has static write barriers
+    return SWB_PASS;
+}
+
+void FlushWriteBarrierInstructionCache()
+{
+    // Nothing to do - wasm has static write barriers
+}
+
+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;
+
+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;
+}
+
+void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet)
+{
+    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");
+}
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/System.Globalization.Native/entrypoints.c b/src/native/libs/System.Globalization.Native/entrypoints.c
index f2db315ec5452e..b687ea837daac6 100644
--- a/src/native/libs/System.Globalization.Native/entrypoints.c
+++ b/src/native/libs/System.Globalization.Native/entrypoints.c
@@ -41,8 +41,6 @@ static const Entry s_globalizationNative[] =
     DllImportEntry(GlobalizationNative_GetSortHandle)
     DllImportEntry(GlobalizationNative_GetSortKey)
     DllImportEntry(GlobalizationNative_GetSortVersion)
-    DllImportEntry(GlobalizationNative_GetTimeZoneDisplayName)
-    DllImportEntry(GlobalizationNative_IanaIdToWindowsId)
     DllImportEntry(GlobalizationNative_IndexOf)
     DllImportEntry(GlobalizationNative_InitICUFunctions)
     DllImportEntry(GlobalizationNative_IsNormalized)
@@ -54,7 +52,11 @@ static const Entry s_globalizationNative[] =
 #endif
     DllImportEntry(GlobalizationNative_NormalizeString)
     DllImportEntry(GlobalizationNative_StartsWith)
+#ifndef __wasm__
+    DllImportEntry(GlobalizationNative_GetTimeZoneDisplayName)
+    DllImportEntry(GlobalizationNative_IanaIdToWindowsId)
     DllImportEntry(GlobalizationNative_WindowsIdToIanaId)
+#endif
 #if defined(APPLE_HYBRID_GLOBALIZATION)
     DllImportEntry(GlobalizationNative_ChangeCaseInvariantNative)
     DllImportEntry(GlobalizationNative_ChangeCaseNative)