diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake
index 274ab363bf7905..b04bfc9ca1397c 100644
--- a/eng/native/configureplatform.cmake
+++ b/eng/native/configureplatform.cmake
@@ -522,7 +522,7 @@ if (CLR_CMAKE_TARGET_ANDROID OR CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET
     set(CLR_CMAKE_USE_SYSTEM_ZLIB 1)
 endif()
 
-if (NOT CLR_CMAKE_TARGET_ANDROID)
+if (NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER)
     # opt into building tools like ildasm/ilasm
     set(CLR_CMAKE_BUILD_TOOLS 1)
 endif()
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index fe9c980fbb9354..1eac8b3924b036 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -125,7 +125,7 @@ extends:
           - browser_wasm
           jobParameters:
             nameSuffix: AllSubsets_CoreCLR
-            buildArgs: -s mono.emsdk+clr.paltests -rc Release -c Release -lc $(_BuildConfig)
+            buildArgs: -s mono.emsdk+clr.runtime -rc Release -c Release -lc $(_BuildConfig)
             timeoutInMinutes: 120
             condition: >-
               or(
diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt
index ad1cfcc279549f..ed016fad7214f1 100644
--- a/src/coreclr/CMakeLists.txt
+++ b/src/coreclr/CMakeLists.txt
@@ -35,6 +35,10 @@ endif()
 
 OPTION(CLR_CMAKE_ENABLE_CODE_COVERAGE "Enable code coverage" OFF)
 
+if (DEFINED CLR_CMAKE_ICU_DIR)
+  include_directories(${CLR_CMAKE_ICU_DIR}/include)
+endif(DEFINED CLR_CMAKE_ICU_DIR)
+
 #----------------------------------------------------
 # Cross target Component build specific configuration
 #----------------------------------------------------
@@ -59,7 +63,7 @@ include(components.cmake)
 #---------------------------
 # Build the single file host
 #---------------------------
-if(NOT CLR_CROSS_COMPONENTS_BUILD AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS)
+if(NOT CLR_CROSS_COMPONENTS_BUILD AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
   set(CLR_SINGLE_FILE_HOST_ONLY 1)
   add_subdirectory(${CLR_SRC_NATIVE_DIR}/corehost/apphost/static Corehost.Static)
   add_dependencies(runtime singlefilehost)
@@ -267,7 +271,7 @@ if(CLR_CMAKE_HOST_UNIX)
   add_subdirectory(nativeresources)
 endif(CLR_CMAKE_HOST_UNIX)
 
-if(NOT CLR_CMAKE_HOST_TVOS AND NOT CLR_CMAKE_HOST_BROWSER)
+if(NOT CLR_CMAKE_HOST_TVOS)
   add_subdirectory(utilcode)
   add_subdirectory(inc)
 
@@ -276,16 +280,27 @@ if(NOT CLR_CMAKE_HOST_TVOS AND NOT CLR_CMAKE_HOST_BROWSER)
     add_subdirectory(ildasm)
   endif(CLR_CMAKE_BUILD_TOOLS)
   add_subdirectory(gcinfo)
-  add_subdirectory(jit)
+
+  if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+    add_subdirectory(jit)
+  endif()
+
   add_subdirectory(vm)
   add_subdirectory(md)
-  add_subdirectory(debug)
+
+  if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+    add_subdirectory(debug)
+  endif()
+
   add_subdirectory(binder)
   add_subdirectory(classlibnative)
   add_subdirectory(dlls)
-  add_subdirectory(unwinder)
-  add_subdirectory(interop)
-endif(NOT CLR_CMAKE_HOST_TVOS AND NOT CLR_CMAKE_HOST_BROWSER)
+
+  if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+    add_subdirectory(unwinder)
+    add_subdirectory(interop)
+  endif()
+endif(NOT CLR_CMAKE_HOST_TVOS)
 
 if(NOT CLR_CMAKE_HOST_MACCATALYST AND NOT CLR_CMAKE_HOST_IOS AND NOT CLR_CMAKE_HOST_TVOS)
   add_subdirectory(tools)
diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake
index d5b2d29d2e5d5a..c37a4277e80b8d 100644
--- a/src/coreclr/clrdefinitions.cmake
+++ b/src/coreclr/clrdefinitions.cmake
@@ -58,7 +58,7 @@ if(CLR_CMAKE_HOST_WIN32)
   add_compile_definitions(NOMINMAX)
 endif(CLR_CMAKE_HOST_WIN32)
 
-if (NOT (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_UNIX))
+if (NOT ((CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_UNIX) OR CLR_CMAKE_TARGET_ARCH_WASM))
   add_compile_definitions(FEATURE_METADATA_UPDATER)
 endif()
 if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_WIN32))
@@ -119,9 +119,9 @@ if(CLR_CMAKE_TARGET_LINUX)
     add_definitions(-DFEATURE_EVENTSOURCE_XPLAT)
 endif(CLR_CMAKE_TARGET_LINUX)
 # NetBSD doesn't implement this feature
-if(NOT CLR_CMAKE_TARGET_NETBSD)
+if(NOT CLR_CMAKE_TARGET_NETBSD AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
     add_definitions(-DFEATURE_HIJACK)
-endif(NOT CLR_CMAKE_TARGET_NETBSD)
+endif(NOT CLR_CMAKE_TARGET_NETBSD AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
 if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM64))
     add_definitions(-DFEATURE_INTEROP_DEBUGGING)
 endif (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM64))
diff --git a/src/coreclr/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake
index d6a8965843e585..6bb761a8e0e2f8 100644
--- a/src/coreclr/clrfeatures.cmake
+++ b/src/coreclr/clrfeatures.cmake
@@ -52,7 +52,7 @@ if (CLR_CMAKE_TARGET_WIN32)
 endif(CLR_CMAKE_TARGET_WIN32)
 
 
-if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
+if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS OR CLR_CMAKE_TARGET_ARCH_WASM)
   set(FEATURE_CORECLR_CACHED_INTERFACE_DISPATCH 1)
   set(FEATURE_CORECLR_VIRTUAL_STUB_DISPATCH 0)
 else()
diff --git a/src/coreclr/debug/inc/dbgipcevents.h b/src/coreclr/debug/inc/dbgipcevents.h
index 6c39939f00307e..9ff25d86edf185 100644
--- a/src/coreclr/debug/inc/dbgipcevents.h
+++ b/src/coreclr/debug/inc/dbgipcevents.h
@@ -1938,6 +1938,9 @@ C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
 C_ASSERT(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
 C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
 #endif
+#elif defined(TARGET_WASM)
+#define DBG_TARGET_REGNUM_SP 0
+#define DBG_TARGET_REGNUM_AMBIENT_SP 0
 #else
 #error Target registers are not defined for this platform
 #endif
diff --git a/src/coreclr/debug/inc/dbgtargetcontext.h b/src/coreclr/debug/inc/dbgtargetcontext.h
index dab7ca29c7db33..ea374cf8b6def6 100644
--- a/src/coreclr/debug/inc/dbgtargetcontext.h
+++ b/src/coreclr/debug/inc/dbgtargetcontext.h
@@ -58,6 +58,8 @@
 #define DTCONTEXT_IS_LOONGARCH64
 #elif defined (TARGET_RISCV64)
 #define DTCONTEXT_IS_RISCV64
+#elif defined (TARGET_WASM)
+#define DTCONTEXT_IS_WASM
 #endif
 
 #define CONTEXT_AREA_MASK 0xffff
@@ -614,6 +616,10 @@ typedef struct DECLSPEC_ALIGN(16) {
 
 static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size");
 
+#elif defined(DTCONTEXT_IS_WASM)
+// no context for wasm
+typedef struct {
+} DT_CONTEXT;
 #else
 #error Unsupported platform
 #endif
diff --git a/src/coreclr/debug/inc/wasm/primitives.h b/src/coreclr/debug/inc/wasm/primitives.h
new file mode 100644
index 00000000000000..5c428fe76ceb62
--- /dev/null
+++ b/src/coreclr/debug/inc/wasm/primitives.h
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//*****************************************************************************
+// File: primitives.h
+//
+
+//
+// Platform-specific debugger primitives
+//
+//*****************************************************************************
+
+#ifndef PRIMITIVES_H_
+#define PRIMITIVES_H_
+
+inline CORDB_ADDRESS GetPatchEndAddr(CORDB_ADDRESS patchAddr)
+{
+    _ASSERTE("The function is not implemented on wasm");
+    return patchAddr;
+}
+
+typedef const BYTE                  CORDB_ADDRESS_TYPE;
+typedef DPTR(CORDB_ADDRESS_TYPE)    PTR_CORDB_ADDRESS_TYPE;
+
+//This is an abstraction to keep x86/ia64 patch data separate
+#define PRD_TYPE                               USHORT
+
+#define MAX_INSTRUCTION_LENGTH 2 // update once we have codegen
+
+#define CORDbg_BREAK_INSTRUCTION_SIZE 1
+#define CORDbg_BREAK_INSTRUCTION 0 // unreachable intruction
+
+inline bool PRDIsEmpty(PRD_TYPE p1)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return p1 == 0;
+}
+
+#endif
diff --git a/src/coreclr/dlls/CMakeLists.txt b/src/coreclr/dlls/CMakeLists.txt
index 9bd79f94d6fd91..0a2ab14d8db82f 100644
--- a/src/coreclr/dlls/CMakeLists.txt
+++ b/src/coreclr/dlls/CMakeLists.txt
@@ -2,9 +2,13 @@ if(CLR_CMAKE_TARGET_WIN32 AND FEATURE_EVENT_TRACE)
     add_subdirectory(clretwrc)
 endif(CLR_CMAKE_TARGET_WIN32 AND FEATURE_EVENT_TRACE)
 if (NOT (CLR_CMAKE_TARGET_WIN32 AND FEATURE_CROSSBITNESS))
-    add_subdirectory(mscordbi)
-    add_subdirectory(mscordac)
+    if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+        add_subdirectory(mscordbi)
+        add_subdirectory(mscordac)
+    endif()
     add_subdirectory(mscoree)
 endif()
-add_subdirectory(mscorpe)
+if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+    add_subdirectory(mscorpe)
+endif()
 add_subdirectory(mscorrc)
diff --git a/src/coreclr/gc/env/gcenv.base.h b/src/coreclr/gc/env/gcenv.base.h
index 1603448ae2a4f8..94d88e46466940 100644
--- a/src/coreclr/gc/env/gcenv.base.h
+++ b/src/coreclr/gc/env/gcenv.base.h
@@ -143,7 +143,10 @@ typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(void* lpThreadParameter);
   #pragma intrinsic(__dmb)
   #define MemoryBarrier() { __dmb(_ARM64_BARRIER_SY); }
 
- #elif defined(HOST_AMD64)
+ #elif defined(HOST_BROWSER)
+  #define YieldProcessor()
+  #define MemoryBarrier __sync_synchronize
+#elif defined(HOST_AMD64)
 
   extern "C" void
   _mm_pause (
diff --git a/src/coreclr/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp
index 43588c66eb015a..5a199f4b7db69e 100644
--- a/src/coreclr/gc/unix/gcenv.unix.cpp
+++ b/src/coreclr/gc/unix/gcenv.unix.cpp
@@ -35,6 +35,9 @@
 #define membarrier(...) syscall(__NR_membarrier, __VA_ARGS__)
 #elif HAVE_SYS_MEMBARRIER_H
 #include <sys/membarrier.h>
+#ifdef TARGET_BROWSER
+#define membarrier(cmd, flags, cpu_id) 0 // browser/wasm is currently single threaded
+#endif
 #endif
 
 #include <sys/resource.h>
diff --git a/src/coreclr/inc/check.h b/src/coreclr/inc/check.h
index 21d717c13e6bb7..5a7218cc652d77 100644
--- a/src/coreclr/inc/check.h
+++ b/src/coreclr/inc/check.h
@@ -723,7 +723,9 @@ CHECK CheckOverflow(UINT64 value1, UINT64 value2);
 #ifdef __APPLE__
 CHECK CheckOverflow(SIZE_T value1, SIZE_T value2);
 #endif
+#ifndef __wasm__
 CHECK CheckOverflow(PTR_CVOID address, UINT offset);
+#endif
 #if defined(_MSC_VER)
 CHECK CheckOverflow(const void *address, ULONG offset);
 #endif
diff --git a/src/coreclr/inc/check.inl b/src/coreclr/inc/check.inl
index 34a2956d1be6e2..b0f65c5d218bbd 100644
--- a/src/coreclr/inc/check.inl
+++ b/src/coreclr/inc/check.inl
@@ -156,7 +156,7 @@ inline CHECK CheckAligned(UINT64 value, UINT alignment)
     CHECK_OK;
 }
 
-#ifdef __APPLE__
+#if defined(__APPLE__) || defined(__wasm__)
 inline CHECK CheckAligned(SIZE_T value, UINT alignment)
 {
     STATIC_CONTRACT_WRAPPER;
@@ -237,7 +237,7 @@ inline CHECK CheckOverflow(const void *address, UINT64 offset)
     CHECK_OK;
 }
 
-#ifdef __APPLE__
+#if defined(__APPLE__) || defined(__wasm__)
 inline CHECK CheckOverflow(const void *address, SIZE_T offset)
 {
     CHECK((UINT64) address + offset >= (UINT64) address);
@@ -316,10 +316,11 @@ inline CHECK CheckUnderflow(const void *address, UINT64 offset)
     CHECK_OK;
 }
 
-#ifdef __APPLE__
+#if defined(__APPLE__) || defined(__wasm__)
 inline CHECK CheckUnderflow(const void *address, SIZE_T offset)
 {
-#if POINTER_BITS == 32
+    // SIZE_T is 32bit on wasm32
+#if !defined(__wasm__) && POINTER_BITS == 32
     CHECK(offset >> 32 == 0);
     CHECK((UINT) (SIZE_T) address - (UINT) offset <= (UINT) (SIZE_T) address);
 #else
diff --git a/src/coreclr/inc/clrnt.h b/src/coreclr/inc/clrnt.h
index 2d935a95317e69..bcd4427538babe 100644
--- a/src/coreclr/inc/clrnt.h
+++ b/src/coreclr/inc/clrnt.h
@@ -501,4 +501,48 @@ RtlVirtualUnwind(
 
 #endif // TARGET_RISCV64
 
+#ifdef TARGET_WASM
+//
+// Define unwind information flags.
+//
+
+#define UNW_FLAG_NHANDLER               0x0             /* any handler */
+#define UNW_FLAG_EHANDLER               0x1             /* filter handler */
+#define UNW_FLAG_UHANDLER               0x2             /* unwind handler */
+
+PEXCEPTION_ROUTINE
+RtlVirtualUnwind (
+    _In_ DWORD HandlerType,
+    _In_ DWORD ImageBase,
+    _In_ DWORD ControlPc,
+    _In_ PRUNTIME_FUNCTION FunctionEntry,
+    __inout PT_CONTEXT ContextRecord,
+    _Out_ PVOID *HandlerData,
+    _Out_ PDWORD EstablisherFrame,
+    __inout_opt PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers
+    );
+
+FORCEINLINE
+ULONG
+RtlpGetFunctionEndAddress (
+    _In_ PT_RUNTIME_FUNCTION FunctionEntry,
+    _In_ TADDR ImageBase
+    )
+{
+    _ASSERTE("The function RtlpGetFunctionEndAddress is not implemented on wasm");
+    return 0;
+}
+
+#define RUNTIME_FUNCTION__BeginAddress(FunctionEntry)               ((FunctionEntry)->BeginAddress)
+#define RUNTIME_FUNCTION__SetBeginAddress(FunctionEntry,address)    ((FunctionEntry)->BeginAddress = (address))
+
+#define RUNTIME_FUNCTION__EndAddress(FunctionEntry, ImageBase)      (RtlpGetFunctionEndAddress(FunctionEntry, (ULONG64)(ImageBase)))
+
+#define RUNTIME_FUNCTION__SetUnwindInfoAddress(prf,address)         do { (prf)->UnwindData = (address); } while (0)
+
+typedef struct _UNWIND_INFO {
+    // dummy
+} UNWIND_INFO, *PUNWIND_INFO;
+#endif
+
 #endif  // CLRNT_H_
diff --git a/src/coreclr/inc/clrtypes.h b/src/coreclr/inc/clrtypes.h
index 9094e4932a2527..b1990054c48738 100644
--- a/src/coreclr/inc/clrtypes.h
+++ b/src/coreclr/inc/clrtypes.h
@@ -338,7 +338,7 @@ inline UINT64 AlignUp(UINT64 value, UINT alignment)
     return (value+alignment-1)&~(UINT64)(alignment-1);
 }
 
-#ifdef __APPLE__
+#if defined(__APPLE__) || defined(__wasm__)
 inline SIZE_T AlignUp(SIZE_T value, UINT alignment)
 {
     STATIC_CONTRACT_LEAF;
@@ -399,13 +399,13 @@ inline UINT AlignmentPad(UINT64 value, UINT alignment)
     return (UINT) (AlignUp(value, alignment) - value);
 }
 
-#ifdef __APPLE__
+#if defined(__APPLE__) || defined(__wasm__)
 inline UINT AlignmentPad(SIZE_T value, UINT alignment)
 {
     STATIC_CONTRACT_WRAPPER;
     return (UINT) (AlignUp(value, alignment) - value);
 }
-#endif // __APPLE__
+#endif // __APPLE__ || __wasm__
 
 inline UINT AlignmentTrim(UINT value, UINT alignment)
 {
@@ -432,7 +432,7 @@ inline UINT AlignmentTrim(UINT64 value, UINT alignment)
     return ((UINT)value)&(alignment-1);
 }
 
-#ifdef __APPLE__
+#if defined(__APPLE__) || defined(__wasm__)
 inline UINT AlignmentTrim(SIZE_T value, UINT alignment)
 {
     STATIC_CONTRACT_LEAF;
diff --git a/src/coreclr/inc/corcompile.h b/src/coreclr/inc/corcompile.h
index 845b72465c3439..57ca94832e6be7 100644
--- a/src/coreclr/inc/corcompile.h
+++ b/src/coreclr/inc/corcompile.h
@@ -56,6 +56,11 @@ inline ReadyToRunCrossModuleInlineFlags operator &( const ReadyToRunCrossModuleI
     return static_cast<ReadyToRunCrossModuleInlineFlags>(static_cast<uint32_t>(left) & static_cast<uint32_t>(right));
 }
 
+#ifdef TARGET_WASM
+// why was it defined only for x86 before?
+typedef DPTR(RUNTIME_FUNCTION) PTR_RUNTIME_FUNCTION;
+#endif
+
 #ifdef TARGET_X86
 
 typedef DPTR(RUNTIME_FUNCTION) PTR_RUNTIME_FUNCTION;
diff --git a/src/coreclr/inc/cordebuginfo.h b/src/coreclr/inc/cordebuginfo.h
index b3125060f308eb..b6979c52f3ac5c 100644
--- a/src/coreclr/inc/cordebuginfo.h
+++ b/src/coreclr/inc/cordebuginfo.h
@@ -213,6 +213,8 @@ class ICorDebugInfo
         REGNUM_T5,
         REGNUM_T6,
         REGNUM_PC,
+#elif TARGET_WASM
+        REGNUM_PC, // wasm doesn't have registers
 #else
         PORTABILITY_WARNING("Register numbers not defined on this platform")
 #endif
diff --git a/src/coreclr/inc/crosscomp.h b/src/coreclr/inc/crosscomp.h
index c3c1f97ddeedea..36081dee778ab4 100644
--- a/src/coreclr/inc/crosscomp.h
+++ b/src/coreclr/inc/crosscomp.h
@@ -721,6 +721,8 @@ typedef struct _T_KNONVOLATILE_CONTEXT_POINTERS {
 #define DAC_CS_NATIVE_DATA_SIZE 48
 #elif defined(TARGET_HAIKU) && defined(TARGET_AMD64)
 #define DAC_CS_NATIVE_DATA_SIZE 56
+#elif defined(TARGET_WASM)
+#define DAC_CS_NATIVE_DATA_SIZE 76
 #else
 #warning
 #error  DAC_CS_NATIVE_DATA_SIZE is not defined for this architecture. This should be same value as PAL_CS_NATIVE_DATA_SIZE (aka sizeof(PAL_CS_NATIVE_DATA)).
diff --git a/src/coreclr/inc/pedecoder.h b/src/coreclr/inc/pedecoder.h
index 057dfa9a25de61..6b13de957bfb93 100644
--- a/src/coreclr/inc/pedecoder.h
+++ b/src/coreclr/inc/pedecoder.h
@@ -89,6 +89,8 @@ inline CHECK CheckOverflow(RVA value1, COUNT_T value2)
 #define IMAGE_FILE_MACHINE_NATIVE   IMAGE_FILE_MACHINE_UNKNOWN
 #elif defined(TARGET_RISCV64)
 #define IMAGE_FILE_MACHINE_NATIVE   IMAGE_FILE_MACHINE_RISCV64
+#elif defined(TARGET_WASM)
+#define IMAGE_FILE_MACHINE_NATIVE   IMAGE_FILE_MACHINE_UNKNOWN
 #else
 #error "port me"
 #endif
diff --git a/src/coreclr/inc/regdisp.h b/src/coreclr/inc/regdisp.h
index 07d3f1f6d5e057..3aa4be6fd9e60c 100644
--- a/src/coreclr/inc/regdisp.h
+++ b/src/coreclr/inc/regdisp.h
@@ -345,6 +345,25 @@ inline TADDR GetRegdisplayStackMark(REGDISPLAY *display) {
     return GetSP(display->pCallerContext);
 }
 
+#elif defined(TARGET_WASM)
+struct REGDISPLAY : public REGDISPLAY_BASE {
+    REGDISPLAY()
+    {
+        // Initialize
+        memset(this, 0, sizeof(REGDISPLAY));
+    }
+};
+
+inline void SyncRegDisplayToCurrentContext(REGDISPLAY* pRD)
+{
+}
+
+// This function tells us if the given stack pointer is in one of the frames of the functions called by the given frame
+inline BOOL IsInCalleesFrames(REGDISPLAY *display, LPVOID stackPointer) {
+    _ASSERTE("IsInCalleesFrames is not implemented on wasm");
+    return FALSE;
+}
+
 #else // none of the above processors
 #error "RegDisplay functions are not implemented on this platform."
 #endif
diff --git a/src/coreclr/inc/switches.h b/src/coreclr/inc/switches.h
index 06fdaa5f397510..9534511ef2a99d 100644
--- a/src/coreclr/inc/switches.h
+++ b/src/coreclr/inc/switches.h
@@ -43,7 +43,7 @@
 #define GC_STATS
 #endif
 
-#if defined(TARGET_X86) || defined(TARGET_ARM)
+#if defined(TARGET_X86) || defined(TARGET_ARM) || defined(TARGET_BROWSER)
     #define USE_LAZY_PREFERRED_RANGE       0
 
 #elif defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_S390X) || defined(TARGET_LOONGARCH64) || defined(TARGET_POWERPC64) || defined(TARGET_RISCV64)
diff --git a/src/coreclr/inc/targetosarch.h b/src/coreclr/inc/targetosarch.h
index 00fe5b70647e7d..217db1de7b6fa3 100644
--- a/src/coreclr/inc/targetosarch.h
+++ b/src/coreclr/inc/targetosarch.h
@@ -95,6 +95,14 @@ class TargetArchitecture
     static const bool IsArmArch = false;
     static const bool IsLoongArch64 = false;
     static const bool IsRiscV64 = true;
+#elif defined(TARGET_WASM)
+    static const bool IsX86 = false;
+    static const bool IsX64 = false;
+    static const bool IsArm64 = false;
+    static const bool IsArm32 = false;
+    static const bool IsArmArch = false;
+    static const bool IsLoongArch64 = false;
+    static const bool IsRiscV64 = false;
 #else
 #error Unknown architecture
 #endif
diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h
index c065859ce757c1..da749d1a19f71c 100644
--- a/src/coreclr/pal/inc/pal.h
+++ b/src/coreclr/pal/inc/pal.h
@@ -2475,7 +2475,9 @@ typedef struct _KNONVOLATILE_CONTEXT_POINTERS {
 #define CONTEXT_CONTROL 0
 #define CONTEXT_INTEGER 0
 #define CONTEXT_FLOATING_POINT 0
+#define CONTEXT_DEBUG_REGISTERS 0
 #define CONTEXT_FULL 0
+#define CONTEXT_ALL 0
 
 #define CONTEXT_XSTATE 0
 
diff --git a/src/coreclr/runtime.proj b/src/coreclr/runtime.proj
index 7b440d5689c469..1a887cbb41e9c3 100644
--- a/src/coreclr/runtime.proj
+++ b/src/coreclr/runtime.proj
@@ -4,11 +4,13 @@
     <_BuildNativeTargetOS>$(TargetOS)</_BuildNativeTargetOS>
     <_BuildNativeTargetOS Condition="'$(TargetsLinuxBionic)' == 'true'">linux-bionic</_BuildNativeTargetOS>
     <HasCdacBuildTool Condition="'$(ClrFullNativeBuild)' == 'true' or '$(ClrRuntimeSubset)' == 'true' or '$(ClrDebugSubset)' == 'true' or '$(ClrCrossComponentsSubset)' == 'true'">true</HasCdacBuildTool>
+    <_IcuDir Condition="'$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)' != '' and '$(TargetsBrowser)' == 'true'">$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)/runtimes/$(TargetOS)-$(TargetArchitecture)$(_RuntimeVariant)/native</_IcuDir>
   </PropertyGroup>
 
   <ItemGroup>
     <ProjectReference Include="runtime-prereqs.proj" GlobalPropertiesToRemove="$(NativeBuildPartitionPropertiesToRemove)" />
     <ProjectReference Condition="'$(HasCdacBuildTool)' == 'true'" Include="tools\cdac-build-tool\cdac-build-tool.csproj" ReferenceOutputAssembly="false" GlobalPropertiesToRemove="$(NativeBuildPartitionPropertiesToRemove)" />
+    <PackageReference Condition="'$(TargetsBrowser)' == 'true'" Include="Microsoft.NETCore.Runtime.ICU.Transport" PrivateAssets="all" Version="$(MicrosoftNETCoreRuntimeICUTransportVersion)" GeneratePathProperty="true" />
   </ItemGroup>
 
   <Import Project="$(RepositoryEngineeringDir)nativepgo.targets" />
@@ -48,6 +50,7 @@
       <_CoreClrBuildArg Condition="'$(BuildSubdirectory)' != ''" Include="-subdir $(BuildSubdirectory)" />
       <_CoreClrBuildArg Include="-cmakeargs &quot;-DCLR_DOTNET_HOST_PATH=$(DOTNET_HOST_PATH)&quot;" />
       <_CoreClrBuildArg Condition="'$(HasCdacBuildTool)' == 'true'" Include="-cmakeargs &quot;-DCDAC_BUILD_TOOL_BINARY_PATH=$(RuntimeBinDir)cdac-build-tool\cdac-build-tool.dll&quot;" />
+      <_CoreClrBuildArg Condition="'$(_IcuDir)' != ''" Include="-cmakeargs &quot;-DCLR_CMAKE_ICU_DIR=$(_IcuDir)&quot;" />
     </ItemGroup>
 
     <ItemGroup Condition="'$(CxxStandardLibrary)' != ''">
diff --git a/src/coreclr/utilcode/CMakeLists.txt b/src/coreclr/utilcode/CMakeLists.txt
index 06282d39189e56..78ae6b2b365632 100644
--- a/src/coreclr/utilcode/CMakeLists.txt
+++ b/src/coreclr/utilcode/CMakeLists.txt
@@ -84,7 +84,9 @@ convert_to_absolute_path(UTILCODE_SOURCES ${UTILCODE_SOURCES})
 convert_to_absolute_path(UTILCODE_DAC_SOURCES ${UTILCODE_DAC_SOURCES})
 convert_to_absolute_path(UTILCODE_STATICNOHOST_SOURCES ${UTILCODE_STATICNOHOST_SOURCES})
 
+if(NOT CLR_CMAKE_TARGET_ARCH_WASM)
 add_library_clr(utilcode_dac STATIC ${UTILCODE_DAC_SOURCES})
+endif()
 add_library_clr(utilcode OBJECT ${UTILCODE_SOURCES})
 add_library_clr(utilcodestaticnohost STATIC ${UTILCODE_STATICNOHOST_SOURCES})
 
@@ -92,9 +94,11 @@ target_link_libraries(utilcodestaticnohost PUBLIC coreclrminipal)
 
 if(CLR_CMAKE_HOST_UNIX)
   target_link_libraries(utilcodestaticnohost PUBLIC nativeresourcestring)
-  target_link_libraries(utilcode_dac PUBLIC nativeresourcestring)
+  if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+    target_link_libraries(utilcode_dac PUBLIC nativeresourcestring)
+    add_dependencies(utilcode_dac coreclrpal)
+  endif()
   target_link_libraries(utilcode INTERFACE nativeresourcestring)
-  add_dependencies(utilcode_dac coreclrpal)
   add_dependencies(utilcode coreclrpal)
 endif(CLR_CMAKE_HOST_UNIX)
 
@@ -107,12 +111,14 @@ if(CLR_CMAKE_HOST_WIN32)
     link_natvis_sources_for_target(utilcode INTERFACE utilcode.natvis)
 endif(CLR_CMAKE_HOST_WIN32)
 
-set_target_properties(utilcode_dac PROPERTIES DAC_COMPONENT TRUE)
-target_compile_definitions(utilcode_dac PRIVATE SELF_NO_HOST)
+if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+  set_target_properties(utilcode_dac PROPERTIES DAC_COMPONENT TRUE)
+  target_compile_definitions(utilcode_dac PRIVATE SELF_NO_HOST)
+  add_dependencies(utilcode_dac ${UTILCODE_DEPENDENCIES})
+  target_precompile_headers(utilcode_dac PRIVATE [["stdafx.h"]])
+  endif()
 target_compile_definitions(utilcodestaticnohost PRIVATE SELF_NO_HOST)
-add_dependencies(utilcode_dac ${UTILCODE_DEPENDENCIES})
 add_dependencies(utilcode ${UTILCODE_DEPENDENCIES})
 add_dependencies(utilcodestaticnohost ${UTILCODE_DEPENDENCIES})
-target_precompile_headers(utilcode_dac PRIVATE [["stdafx.h"]])
 target_precompile_headers(utilcode PRIVATE [["stdafx.h"]])
 target_precompile_headers(utilcodestaticnohost PRIVATE [["stdafx.h"]])
diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt
index 61a210eb37ef36..df3636832dd5b3 100644
--- a/src/coreclr/vm/CMakeLists.txt
+++ b/src/coreclr/vm/CMakeLists.txt
@@ -955,10 +955,12 @@ convert_to_absolute_path(VM_SOURCES_WKS_ARCH_ASM ${VM_SOURCES_WKS_ARCH_ASM})
 convert_to_absolute_path(VM_SOURCES_DAC ${VM_SOURCES_DAC})
 convert_to_absolute_path(VM_SOURCES_WKS_SPECIAL ${VM_SOURCES_WKS_SPECIAL})
 
-add_library_clr(cee_dac ${VM_SOURCES_DAC})
-add_dependencies(cee_dac eventing_headers)
-set_target_properties(cee_dac PROPERTIES DAC_COMPONENT TRUE)
-target_precompile_headers(cee_dac PRIVATE [["common.h"]])
+if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+    add_library_clr(cee_dac ${VM_SOURCES_DAC})
+    add_dependencies(cee_dac eventing_headers)
+    set_target_properties(cee_dac PROPERTIES DAC_COMPONENT TRUE)
+    target_precompile_headers(cee_dac PRIVATE [["common.h"]])
+endif()
 
 add_subdirectory(wks)
 
diff --git a/src/coreclr/vm/callcounting.h b/src/coreclr/vm/callcounting.h
index 34bbf526225fc0..8073e860f5e88c 100644
--- a/src/coreclr/vm/callcounting.h
+++ b/src/coreclr/vm/callcounting.h
@@ -101,6 +101,8 @@ class CallCountingStub
     static const SIZE_T CodeSize = 40;
 #elif defined(TARGET_RISCV64)
     static const SIZE_T CodeSize = 40;
+#elif defined(TARGET_WASM)
+    static const SIZE_T CodeSize = 0;
 #endif
 
 private:
diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h
index 63a92f9b1fbcf5..5b167300ec856d 100644
--- a/src/coreclr/vm/callingconvention.h
+++ b/src/coreclr/vm/callingconvention.h
@@ -186,6 +186,16 @@ struct TransitionBlock
     };
     TADDR padding; // Keep size of TransitionBlock as multiple of 16-byte. Simplifies code in PROLOG_WITH_TRANSITION_BLOCK
     ArgumentRegisters       m_argumentRegisters;
+#elif defined(TARGET_WASM)
+    // No transition block on WASM yet
+    union {
+        CalleeSavedRegisters m_calleeSavedRegisters;
+        // alias saved link register as m_ReturnAddress
+        struct {
+            TADDR m_ReturnAddress;
+        };
+    };
+    ArgumentRegisters       m_argumentRegisters;
 #else
     PORTABILITY_ASSERT("TransitionBlock");
 #endif
@@ -924,6 +934,16 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
     }
 
 #endif // TARGET_LOONGARCH64 || TARGET_RISCV64
+
+#ifdef TARGET_WASM
+
+    // Get layout information for the argument that the ArgIterator is currently visiting.
+    void GetArgLoc(int argOffset, ArgLocDesc *pLoc)
+    {
+        _ASSERTE(!"GetArgLoc not implemented for WASM");
+    }
+#endif // TARGET_WASM
+
 protected:
     DWORD               m_dwFlags;              // Cached flags
     int                 m_nSizeOfArgStack;      // Cached value of SizeOfArgStack
diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h
index 9ff3492a399b9c..fd52513be864c1 100644
--- a/src/coreclr/vm/codeman.h
+++ b/src/coreclr/vm/codeman.h
@@ -2565,6 +2565,10 @@ class EECodeInfo
     }
 #endif // TARGET_X86
 
+#if defined(TARGET_WASM)
+ULONG       GetFixedStackSize();
+#endif
+
 #if defined(TARGET_AMD64)
     BOOL        HasFrameRegister();
     ULONG       GetFixedStackSize();
diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h
index be519af3b9b239..b96598c516f818 100644
--- a/src/coreclr/vm/frames.h
+++ b/src/coreclr/vm/frames.h
@@ -729,6 +729,9 @@ class ResumableFrame : public Frame
 #elif defined(TARGET_RISCV64)
             Object** firstIntReg = (Object**)&this->GetContext()->Gp;
             Object** lastIntReg  = (Object**)&this->GetContext()->T6;
+#elif defined(TARGET_WASM)
+            Object** firstIntReg = nullptr;
+            Object** lastIntReg  = nullptr;
 #else
             _ASSERTE(!"nyi for platform");
 #endif
diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp
index 0f3c65c12981b6..16186cb5b08f1a 100644
--- a/src/coreclr/vm/methodtablebuilder.cpp
+++ b/src/coreclr/vm/methodtablebuilder.cpp
@@ -10181,6 +10181,8 @@ void MethodTableBuilder::CheckForSystemTypes()
             // although applying 16 byte alignment is consistent with treatment of 128 bit SSE types
             // even on X86
             pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; // sizeof(__int128)
+#elif defined(TARGET_WASM)
+            pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; // sizeof(v128)
 #else
 #error Unknown architecture
 #endif // TARGET_64BIT
diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h
index c9a07e8751b217..f7a1bc336d02bb 100644
--- a/src/coreclr/vm/precode.h
+++ b/src/coreclr/vm/precode.h
@@ -50,6 +50,11 @@ EXTERN_C VOID STDCALL PrecodeRemotingThunk();
 #define SIZEOF_PRECODE_BASE         CODE_SIZE_ALIGN
 #define OFFSETOF_PRECODE_TYPE       0
 
+#elif defined(TARGET_WASM)
+
+#define SIZEOF_PRECODE_BASE         0
+#define OFFSETOF_PRECODE_TYPE       0
+
 #endif // TARGET_AMD64
 
 #ifndef DACCESS_COMPILE
@@ -71,6 +76,9 @@ struct InvalidPrecode
     static const int Type = 0xff;
 #elif defined(TARGET_RISCV64)
     static const int Type = 0xff;
+#elif defined(TARGET_WASM)
+    // unreachable instruction
+    static const int Type = 0;
 #endif
 };
 
@@ -118,6 +126,9 @@ struct StubPrecode
 #elif defined(TARGET_RISCV64)
     static const int Type = 0x17;
     static const SIZE_T CodeSize = 24;
+#elif defined(TARGET_WASM)
+    static const int Type = 0;
+    static const SIZE_T CodeSize = 0;
 #endif // TARGET_AMD64
 
     BYTE m_code[CodeSize];
@@ -311,6 +322,10 @@ struct FixupPrecode
     static const int Type = 0x97;
     static const SIZE_T CodeSize = 32;
     static const int FixupCodeOffset = 10;
+#elif defined(TARGET_WASM)
+    static const int Type = 2;
+    static const SIZE_T CodeSize = 0;
+    static const int FixupCodeOffset = 0;
 #endif // TARGET_AMD64
 
     BYTE m_code[CodeSize];
diff --git a/src/coreclr/vm/stackwalk.cpp b/src/coreclr/vm/stackwalk.cpp
index c84c6105fcff30..817cbb65514628 100644
--- a/src/coreclr/vm/stackwalk.cpp
+++ b/src/coreclr/vm/stackwalk.cpp
@@ -440,6 +440,10 @@ PCODE Thread::VirtualUnwindCallFrame(T_CONTEXT* pContext,
                                         T_KNONVOLATILE_CONTEXT_POINTERS* pContextPointers /*= NULL*/,
                                         EECodeInfo * pCodeInfo /*= NULL*/)
 {
+#ifdef TARGET_WASM
+    _ASSERTE("VirtualUnwindCallFrame is not supported on WebAssembly");
+    return 0;
+#else
     CONTRACTL
     {
         NOTHROW;
@@ -542,6 +546,7 @@ PCODE Thread::VirtualUnwindCallFrame(T_CONTEXT* pContext,
 #endif // !DACCESS_COMPILE
 
     return uControlPc;
+#endif // TARGET_WASM
 }
 
 #ifndef DACCESS_COMPILE
diff --git a/src/coreclr/vm/wasm/asmconstants.h b/src/coreclr/vm/wasm/asmconstants.h
new file mode 100644
index 00000000000000..c43f599357ea26
--- /dev/null
+++ b/src/coreclr/vm/wasm/asmconstants.h
@@ -0,0 +1,10 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// asmconstants.h -
+//
+// This header defines field offsets and constants used by assembly code
+// Be sure to rebuild clr/src/vm/ceemain.cpp after changing this file, to
+// ensure that the constants match the expected C/C++ values
+
+#define DynamicHelperFrameFlags_ObjectArg   1
+#define DynamicHelperFrameFlags_ObjectArg2  2
diff --git a/src/coreclr/vm/wasm/cgencpu.h b/src/coreclr/vm/wasm/cgencpu.h
new file mode 100644
index 00000000000000..f77b2608fbb1be
--- /dev/null
+++ b/src/coreclr/vm/wasm/cgencpu.h
@@ -0,0 +1,194 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
+#ifndef __cgenwasm_h__
+#define __cgenwasm_h__
+
+#include "stublink.h"
+#include "utilcode.h"
+
+// preferred alignment for data
+#define DATA_ALIGNMENT 4
+
+#define CODE_SIZE_ALIGN                         4
+#define LOG2SLOT                                LOG2_PTRSIZE
+
+// looks like this is mandatory for now
+#define HAS_NDIRECT_IMPORT_PRECODE              1
+#define HAS_FIXUP_PRECODE                       1
+// ThisPtrRetBufPrecode one is necessary for closed delegates over static methods with return buffer
+#define HAS_THISPTR_RETBUF_PRECODE              1
+
+#define BACK_TO_BACK_JUMP_ALLOCATE_SIZE         8   // # bytes to allocate for a back to back jump instruction
+
+//**********************************************************************
+// Parameter size
+//**********************************************************************
+
+inline unsigned StackElemSize(unsigned parmSize, bool isValueType = false /* unused */, bool isFloatHfa = false /* unused */)
+{
+    _ASSERTE("The function is not implemented on wasm");
+    return 0;
+}
+
+inline TADDR GetSP(const T_CONTEXT * context)
+{
+    _ASSERTE("The function is not implemented on wasm, it lacks registers");
+    return 0;
+}
+
+struct HijackArgs
+{
+};
+
+inline LPVOID STDCALL GetCurrentSP()
+{
+    _ASSERTE("The function is not implemented on wasm, it lacks registers");
+    return nullptr;
+}
+
+extern PCODE GetPreStubEntryPoint();
+
+struct ThisPtrRetBufPrecode {
+    static const int Type = 0x01;
+
+    void Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator)
+    {
+        _ASSERTE("The ThisPtrRetBufPrecode::Init is not implemented on wasm");
+    }
+
+    TADDR GetMethodDesc()
+    {
+        _ASSERTE("The ThisPtrRetBufPrecode::GetMethodDesc is not implemented on wasm");
+        return 0;
+    }
+
+    PCODE GetTarget()
+    {
+        _ASSERTE("The ThisPtrRetBufPrecode::GetTarget is not implemented on wasm");
+        return 0;
+    }
+
+    BOOL SetTargetInterlocked(TADDR target, TADDR expected)
+    {
+        _ASSERTE("The ThisPtrRetBufPrecode::SetTargetInterlocked is not implemented on wasm");
+        return FALSE;
+    }
+};
+
+typedef DPTR(ThisPtrRetBufPrecode) PTR_ThisPtrRetBufPrecode;
+
+#define GetEEFuncEntryPoint(pfn) GFN_TADDR(pfn)
+
+//**********************************************************************
+// Frames
+//**********************************************************************
+
+//--------------------------------------------------------------------
+// This represents the callee saved (non-volatile) registers saved as
+// of a FramedMethodFrame.
+//--------------------------------------------------------------------
+typedef DPTR(struct CalleeSavedRegisters) PTR_CalleeSavedRegisters;
+struct CalleeSavedRegisters {
+};
+
+//--------------------------------------------------------------------
+// This represents the arguments that are stored in volatile registers.
+// This should not overlap the CalleeSavedRegisters since those are already
+// saved separately and it would be wasteful to save the same register twice.
+// If we do use a non-volatile register as an argument, then the ArgIterator
+// will probably have to communicate this back to the PromoteCallerStack
+// routine to avoid a double promotion.
+//--------------------------------------------------------------------
+typedef DPTR(struct ArgumentRegisters) PTR_ArgumentRegisters;
+struct ArgumentRegisters {
+};
+#define NUM_ARGUMENT_REGISTERS 0
+#define ARGUMENTREGISTERS_SIZE sizeof(ArgumentRegisters)
+
+#define ENREGISTERED_RETURNTYPE_MAXSIZE         16  // not sure here, 16 bytes is v128
+
+#define STACKWALK_CONTROLPC_ADJUST_OFFSET 0
+
+class StubLinkerCPU : public StubLinker
+{
+public:
+    static void Init();
+    void EmitShuffleThunk(struct ShuffleEntry *pShuffleEntryArray);
+    VOID EmitComputedInstantiatingMethodStub(MethodDesc* pSharedMD, struct ShuffleEntry *pShuffleEntryArray, void* extraArg);
+};
+
+//**********************************************************************
+// Exception handling
+//**********************************************************************
+
+inline PCODE GetIP(const T_CONTEXT * context) {
+    _ASSERT("GetIP is not implemented on wasm, it lacks registers");
+    return 0;
+}
+
+inline void SetIP(T_CONTEXT *context, PCODE eip) {
+    _ASSERT("SetIP is not implemented on wasm, it lacks registers");
+}
+
+inline void SetSP(T_CONTEXT *context, TADDR esp) {
+    _ASSERT("SetSP is not implemented on wasm, it lacks registers");
+}
+
+inline void SetFP(T_CONTEXT *context, TADDR ebp) {
+    _ASSERT("SetFP is not implemented on wasm, it lacks registers");
+}
+
+inline TADDR GetFP(const T_CONTEXT * context)
+{
+    _ASSERT("GetFP is not implemented on wasm, it lacks registers");
+    return 0;
+}
+
+#define ENUM_CALLEE_SAVED_REGISTERS()
+
+#define ENUM_FP_CALLEE_SAVED_REGISTERS()
+
+// ClrFlushInstructionCache is used when we want to call FlushInstructionCache
+// for a specific architecture in the common code, but not for other architectures.
+// On IA64 ClrFlushInstructionCache calls the Kernel FlushInstructionCache function
+// to flush the instruction cache.
+// We call ClrFlushInstructionCache whenever we create or modify code in the heap.
+// Currently ClrFlushInstructionCache has no effect on X86
+//
+
+inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode, bool hasCodeExecutedBefore = false)
+{
+    // no-op on wasm
+    return true;
+}
+
+//
+// On IA64 back to back jumps should be separated by a nop bundle to get
+// the best performance from the hardware's branch prediction logic.
+// For all other platforms back to back jumps don't require anything special
+// That is why we have these two wrapper functions that call emitJump and decodeJump
+//
+
+//------------------------------------------------------------------------
+inline void emitBackToBackJump(LPBYTE pBufferRX, LPBYTE pBufferRW, LPVOID target)
+{
+    _ASSERTE("emitBackToBackJump is not implemented on wasm");
+}
+
+//------------------------------------------------------------------------
+inline PCODE decodeBackToBackJump(PCODE pBuffer)
+{
+    _ASSERTE("decodeBackToBackJump is not implemented on wasm");
+    return 0;
+}
+
+FORCEINLINE int64_t PalInterlockedCompareExchange64(_Inout_ int64_t volatile *pDst, int64_t iValue, int64_t iComparand)
+{
+    int64_t result = __sync_val_compare_and_swap(pDst, iComparand, iValue);
+    __sync_synchronize();
+    return result;
+}
+
+#endif // __cgenwasm_h__
diff --git a/src/coreclr/vm/wasm/excepcpu.h b/src/coreclr/vm/wasm/excepcpu.h
new file mode 100644
index 00000000000000..7ca5a994a60760
--- /dev/null
+++ b/src/coreclr/vm/wasm/excepcpu.h
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// copied from arm and left empty. wasm cannot do most of it
+
+#ifndef __excepcpu_h__
+#define __excepcpu_h__
+
+#define THROW_CONTROL_FOR_THREAD_FUNCTION  ThrowControlForThread
+
+#define STATUS_CLR_GCCOVER_CODE         STATUS_ILLEGAL_INSTRUCTION
+
+class Thread;
+class FaultingExceptionFrame;
+
+#define INSTALL_EXCEPTION_HANDLING_RECORD(record)
+#define UNINSTALL_EXCEPTION_HANDLING_RECORD(record)
+#define DECLARE_CPFH_EH_RECORD(pCurThread)
+
+//
+// Retrieves the redirected CONTEXT* from the stack frame of one of the
+// RedirectedHandledJITCaseForXXX_Stub's.
+//
+PTR_CONTEXT GetCONTEXTFromRedirectedStubStackFrame(T_CONTEXT * pContext);
+
+inline
+PCODE GetAdjustedCallAddress(PCODE returnAddress)
+{
+    return returnAddress;
+}
+
+BOOL AdjustContextForVirtualStub(EXCEPTION_RECORD *pExceptionRecord, T_CONTEXT *pContext);
+
+#endif // __excepcpu_h__
diff --git a/src/coreclr/vm/wasm/gmscpu.h b/src/coreclr/vm/wasm/gmscpu.h
new file mode 100644
index 00000000000000..5355cfbc546ee6
--- /dev/null
+++ b/src/coreclr/vm/wasm/gmscpu.h
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef __gmscpu_h__
+#define __gmscpu_h__
+
+#define __gmscpu_h__
+
+    // A MachState indicates the register state of the processor at some point in time (usually
+    // just before or after a call is made).  It can be made one of two ways.  Either explicitly
+    // (when you for some reason know the values of all the registers), or implicitly using the
+    // GET_STATE macros.
+
+    typedef DPTR(struct MachState) PTR_MachState;
+    struct MachState {
+    
+        BOOL   isValid()    { LIMITED_METHOD_DAC_CONTRACT; return TRUE; }
+        TADDR  GetRetAddr() { LIMITED_METHOD_DAC_CONTRACT; return 0; }
+    
+        friend class HelperMethodFrame;
+        friend class CheckAsmOffsets;
+        friend struct LazyMachState;
+    };
+    
+    /********************************************************************/
+    /* This allows you to defer the computation of the Machine state
+       until later.  Note that we don't reuse slots, because we want
+       this to be threadsafe without locks */
+    
+    struct LazyMachState : public MachState {
+        // compute the machine state of the processor as it will exist just
+        // after the return after at most'funCallDepth' number of functions.
+        // if 'testFtn' is non-NULL, the return address is tested at each
+        // return instruction encountered.  If this test returns non-NULL,
+        // then stack walking stops (thus you can walk up to the point that the
+        // return address matches some criteria
+    
+        // Normally this is called with funCallDepth=1 and testFtn = 0 so that
+        // it returns the state of the processor after the function that called 'captureState()'
+        void setLazyStateFromUnwind(MachState* copy);
+        static void unwindLazyState(LazyMachState* baseState,
+                                    MachState* lazyState,
+                                    DWORD threadId,
+                                    int funCallDepth = 1);
+    
+        friend class HelperMethodFrame;
+        friend class CheckAsmOffsets;
+    };
+    
+    // R4 - R11
+    #define NUM_NONVOLATILE_CONTEXT_POINTERS 8
+    
+    inline void LazyMachState::setLazyStateFromUnwind(MachState* copy)
+    {
+        _ASSERTE("LazyMachState::setLazyStateFromUnwind is not implemented");
+    }
+    typedef DPTR(LazyMachState) PTR_LazyMachState;
+    
+    // Do the initial capture of the machine state.  This is meant to be
+    // as light weight as possible, as we may never need the state that
+    // we capture.  Thus to complete the process you need to call
+    // 'getMachState()', which finishes the process
+    EXTERN_C void LazyMachStateCaptureState(struct LazyMachState *pState);
+    
+    // CAPTURE_STATE captures just enough register state so that the state of the
+    // processor can be deterined just after the routine that has CAPTURE_STATE in
+    // it returns.
+    
+    #define CAPTURE_STATE(machState, ret)                       \
+        LazyMachStateCaptureState(machState)
+    
+    #endif
