diff --git a/eng/Subsets.props b/eng/Subsets.props
index c43840784acef3..aa4da501a51acc 100644
--- a/eng/Subsets.props
+++ b/eng/Subsets.props
@@ -207,6 +207,7 @@
+
@@ -264,6 +265,11 @@
+
+
+
+
+
@@ -325,7 +331,7 @@
The cross tools are used as part of the build process with the downloaded build tools, so we need to build them for the host architecture and build them as unsanitized binaries.
-->
- <_BuildAnyCrossArch Condition="'$(CrossBuild)' == 'true' or '$(BuildArchitecture)' != '$(TargetArchitecture)' or '$(HostOS)' != '$(TargetOS)' or '$(EnableNativeSanitizers)' != ''">true
+ <_BuildAnyCrossArch Condition="('$(CrossBuild)' == 'true' or '$(BuildArchitecture)' != '$(TargetArchitecture)' or '$(HostOS)' != '$(TargetOS)' or '$(EnableNativeSanitizers)' != '') and '$(TargetArchitecture)' != 'wasm'">true
<_BuildCrossComponents Condition="$(_subset.Contains('+clr.crossarchtools+'))">true
<_BuildCrossComponents Condition="'$(ClrRuntimeBuildSubsets)' != '' and ('$(PrimaryRuntimeFlavor)' == 'CoreCLR' or '$(TargetsMobile)' == 'true')">true
<_CrossBitwidthBuild Condition="'$(BuildArchitecture)' == 'x64' and ('$(TargetArchitecture)' == 'x86' or '$(TargetArchitecture)' == 'arm')">true
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index f627b38bce8bf3..fe9c980fbb9354 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -117,6 +117,21 @@ extends:
eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true),
eq(variables['isRollingBuild'], true))
+ - template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ buildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
+ platforms:
+ - browser_wasm
+ jobParameters:
+ nameSuffix: AllSubsets_CoreCLR
+ buildArgs: -s mono.emsdk+clr.paltests -rc Release -c Release -lc $(_BuildConfig)
+ timeoutInMinutes: 120
+ condition: >-
+ or(
+ eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true),
+ eq(variables['isRollingBuild'], true))
+
#
# Build CoreCLR and Libraries with Libraries tests
# For running libraries tests and installer tests
diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt
index d1a5e3609c38a4..4a0c5a13c8a2d0 100644
--- a/src/coreclr/CMakeLists.txt
+++ b/src/coreclr/CMakeLists.txt
@@ -29,7 +29,7 @@ if(CORECLR_SET_RPATH)
set(MACOSX_RPATH ON)
endif(CORECLR_SET_RPATH)
-if(CLR_CMAKE_HOST_MACCATALYST OR CLR_CMAKE_HOST_IOS OR CLR_CMAKE_HOST_TVOS)
+if(CLR_CMAKE_HOST_MACCATALYST OR CLR_CMAKE_HOST_IOS OR CLR_CMAKE_HOST_TVOS OR CLR_CMAKE_HOST_BROWSER)
set(FEATURE_STANDALONE_GC 0)
endif()
@@ -148,8 +148,9 @@ endif()
include_directories("pal/prebuilt/inc")
include_directories(${CLR_ARTIFACTS_OBJ_DIR})
-add_subdirectory(tools/aot/jitinterface)
-
+if (NOT CLR_CMAKE_TARGET_BROWSER)
+ add_subdirectory(tools/aot/jitinterface)
+endif (NOT CLR_CMAKE_TARGET_BROWSER)
if(NOT CLR_CROSS_COMPONENTS_BUILD)
# NativeAOT only buildable for a subset of CoreCLR-supported configurations
@@ -262,7 +263,7 @@ if(CLR_CMAKE_HOST_UNIX)
add_subdirectory(nativeresources)
endif(CLR_CMAKE_HOST_UNIX)
-if(NOT CLR_CMAKE_HOST_TVOS)
+if(NOT CLR_CMAKE_HOST_TVOS AND NOT CLR_CMAKE_HOST_BROWSER)
add_subdirectory(utilcode)
add_subdirectory(inc)
@@ -280,7 +281,7 @@ if(NOT CLR_CMAKE_HOST_TVOS)
add_subdirectory(dlls)
add_subdirectory(unwinder)
add_subdirectory(interop)
-endif()
+endif(NOT CLR_CMAKE_HOST_TVOS AND NOT CLR_CMAKE_HOST_BROWSER)
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/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake
index 83cf4818add318..6bfb717125bbd2 100644
--- a/src/coreclr/clrfeatures.cmake
+++ b/src/coreclr/clrfeatures.cmake
@@ -3,8 +3,10 @@ if(CLR_CMAKE_TARGET_TIZEN_LINUX)
endif()
if(NOT DEFINED FEATURE_EVENT_TRACE)
- # To actually disable FEATURE_EVENT_TRACE, also change clr.featuredefines.props
- set(FEATURE_EVENT_TRACE 1)
+ if (NOT CLR_CMAKE_TARGET_BROWSER)
+ # To actually disable FEATURE_EVENT_TRACE, also change clr.featuredefines.props
+ set(FEATURE_EVENT_TRACE 1)
+ endif()
endif(NOT DEFINED FEATURE_EVENT_TRACE)
if(NOT DEFINED FEATURE_PERFTRACING AND FEATURE_EVENT_TRACE)
diff --git a/src/coreclr/inc/volatile.h b/src/coreclr/inc/volatile.h
index efcb25f8acd8a5..ce49c38ef7ac22 100644
--- a/src/coreclr/inc/volatile.h
+++ b/src/coreclr/inc/volatile.h
@@ -68,7 +68,7 @@
#error The Volatile type is currently only defined for Visual C++ and GNU C++
#endif
-#if defined(__GNUC__) && !defined(HOST_X86) && !defined(HOST_AMD64) && !defined(HOST_ARM) && !defined(HOST_ARM64) && !defined(HOST_LOONGARCH64) && !defined(HOST_RISCV64) && !defined(HOST_S390X) && !defined(HOST_POWERPC64)
+#if defined(__GNUC__) && !defined(HOST_X86) && !defined(HOST_AMD64) && !defined(HOST_ARM) && !defined(HOST_ARM64) && !defined(HOST_LOONGARCH64) && !defined(HOST_RISCV64) && !defined(HOST_S390X) && !defined(HOST_POWERPC64) && !defined(HOST_WASM)
#error The Volatile type is currently only defined for GCC when targeting x86, AMD64, ARM, ARM64, LOONGARCH64, RISCV64, PPC64LE, or S390X CPUs
#endif
diff --git a/src/coreclr/interpreter/CMakeLists.txt b/src/coreclr/interpreter/CMakeLists.txt
index 403079f50f9f41..2a62dd8778f510 100644
--- a/src/coreclr/interpreter/CMakeLists.txt
+++ b/src/coreclr/interpreter/CMakeLists.txt
@@ -28,7 +28,13 @@ else()
add_custom_target(interpreter_exports DEPENDS ${EXPORTS_FILE})
endif()
-add_library_clr(clrinterpreter SHARED ${INTERPRETER_SOURCES})
+if(CLR_CMAKE_TARGET_BROWSER)
+ set(LIBRARY_TYPE STATIC)
+else()
+ set(LIBRARY_TYPE SHARED)
+endif()
+
+add_library_clr(clrinterpreter ${LIBRARY_TYPE} ${INTERPRETER_SOURCES})
add_dependencies(clrinterpreter interpreter_exports)
diff --git a/src/coreclr/jit/CMakeLists.txt b/src/coreclr/jit/CMakeLists.txt
index 9b025f3180555f..288edf637a6dd4 100644
--- a/src/coreclr/jit/CMakeLists.txt
+++ b/src/coreclr/jit/CMakeLists.txt
@@ -495,6 +495,9 @@ elseif(CLR_CMAKE_TARGET_ARCH_LOONGARCH64)
elseif(CLR_CMAKE_TARGET_ARCH_RISCV64)
set(JIT_ARCH_SOURCES ${JIT_RISCV64_SOURCES})
set(JIT_ARCH_HEADERS ${JIT_RISCV64_HEADERS})
+elseif(CLR_CMAKE_TARGET_ARCH_WASM)
+ set(JIT_ARCH_SOURCES ${JIT_WASM32_SOURCES})
+ set(JIT_ARCH_HEADERS ${JIT_WASM32_HEADERS})
else()
clr_unknown_arch()
endif()
diff --git a/src/coreclr/pal/CMakeLists.txt b/src/coreclr/pal/CMakeLists.txt
index 9213941ba6da01..01ddee53d35d88 100644
--- a/src/coreclr/pal/CMakeLists.txt
+++ b/src/coreclr/pal/CMakeLists.txt
@@ -6,7 +6,12 @@ include_directories(${COREPAL_SOURCE_DIR}/inc)
include_directories(${COREPAL_SOURCE_DIR}/src)
include_directories(${COREPAL_SOURCE_DIR}/../inc)
-add_compile_options(-fexceptions)
+if (NOT CLR_CMAKE_TARGET_BROWSER)
+ add_compile_options(-fexceptions)
+else()
+ add_compile_options(-fwasm-exceptions)
+ add_link_options(-fwasm-exceptions -sEXIT_RUNTIME=1)
+endif()
add_subdirectory(src)
add_subdirectory(tests)
diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h
index 86459bc0a6c085..7c6384ee655729 100644
--- a/src/coreclr/pal/inc/pal.h
+++ b/src/coreclr/pal/inc/pal.h
@@ -2469,6 +2469,26 @@ typedef struct _KNONVOLATILE_CONTEXT_POINTERS {
//
} KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS;
+#elif defined(HOST_WASM)
+#define CONTEXT_CONTROL 0
+#define CONTEXT_INTEGER 0
+#define CONTEXT_FLOATING_POINT 0
+#define CONTEXT_FULL 0
+
+#define CONTEXT_XSTATE 0
+
+#define CONTEXT_EXCEPTION_ACTIVE 0x8000000L
+#define CONTEXT_SERVICE_ACTIVE 0x10000000L
+#define CONTEXT_EXCEPTION_REQUEST 0x40000000L
+#define CONTEXT_EXCEPTION_REPORTING 0x80000000L
+
+typedef struct _CONTEXT {
+ ULONG ContextFlags;
+} CONTEXT, *PCONTEXT, *LPCONTEXT;
+
+typedef struct _KNONVOLATILE_CONTEXT_POINTERS {
+ DWORD none;
+} KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS;
#else
#error Unknown architecture for defining CONTEXT.
@@ -2600,6 +2620,8 @@ PALIMPORT BOOL PALAPI PAL_GetUnwindInfoSize(SIZE_T baseAddress, ULONG64 ehFrameH
#define PAL_CS_NATIVE_DATA_SIZE 96
#elif defined(__HAIKU__) && defined(__x86_64__)
#define PAL_CS_NATIVE_DATA_SIZE 56
+#elif defined(HOST_WASM)
+#define PAL_CS_NATIVE_DATA_SIZE 76
#else
#error PAL_CS_NATIVE_DATA_SIZE is not defined for this architecture
#endif
diff --git a/src/coreclr/pal/inc/rt/palrt.h b/src/coreclr/pal/inc/rt/palrt.h
index 91cd688fdbe862..215290ce093439 100644
--- a/src/coreclr/pal/inc/rt/palrt.h
+++ b/src/coreclr/pal/inc/rt/palrt.h
@@ -1003,6 +1003,14 @@ typedef struct _DISPATCHER_CONTEXT {
DWORD Reserved;
} DISPATCHER_CONTEXT, *PDISPATCHER_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;
+} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
+
#else
#error Unknown architecture for defining DISPATCHER_CONTEXT.
diff --git a/src/coreclr/pal/src/CMakeLists.txt b/src/coreclr/pal/src/CMakeLists.txt
index e40b0fb02f09be..c6c498aa66d8bd 100644
--- a/src/coreclr/pal/src/CMakeLists.txt
+++ b/src/coreclr/pal/src/CMakeLists.txt
@@ -10,7 +10,7 @@ elseif (CLR_CMAKE_TARGET_FREEBSD)
include_directories(SYSTEM $ENV{ROOTFS_DIR}/usr/local/include)
endif()
-if(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND)
+if(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
include_directories(${CLR_SRC_NATIVE_DIR}/external/libunwind/include)
include_directories(${CLR_SRC_NATIVE_DIR}/external/libunwind/include/tdep)
include_directories(${CLR_ARTIFACTS_OBJ_DIR}/external/libunwind/include)
@@ -21,7 +21,7 @@ elseif(NOT CLR_CMAKE_TARGET_APPLE)
find_unwind_libs(UNWIND_LIBS)
else()
add_subdirectory(${CLR_SRC_NATIVE_DIR}/external/libunwind_extras ${CLR_ARTIFACTS_OBJ_DIR}/external/libunwind)
-endif(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND)
+endif(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
include(configure.cmake)
@@ -59,6 +59,8 @@ elseif(CLR_CMAKE_HOST_ARCH_S390X)
set(PAL_ARCH_SOURCES_DIR s390x)
elseif(CLR_CMAKE_HOST_ARCH_POWERPC64)
set(PAL_ARCH_SOURCES_DIR ppc64le)
+elseif(CLR_CMAKE_HOST_ARCH_WASM)
+ set(PAL_ARCH_SOURCES_DIR wasm)
endif()
if(CLR_CMAKE_USE_SYSTEM_LIBUNWIND)
@@ -113,18 +115,26 @@ endif(CLR_CMAKE_TARGET_HAIKU)
# turn off capability to remove unused functions (which was enabled in debug build with sanitizers)
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -Wl,--no-gc-sections")
-set(ARCH_SOURCES
- arch/${PAL_ARCH_SOURCES_DIR}/context2.S
- arch/${PAL_ARCH_SOURCES_DIR}/debugbreak.S
- arch/${PAL_ARCH_SOURCES_DIR}/exceptionhelper.S
-)
+if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+ set(ARCH_SOURCES
+ arch/${PAL_ARCH_SOURCES_DIR}/context2.S
+ arch/${PAL_ARCH_SOURCES_DIR}/debugbreak.S
+ arch/${PAL_ARCH_SOURCES_DIR}/exceptionhelper.S
+ )
+endif()
+
+if (CLR_CMAKE_TARGET_ARCH_WASM)
+ set(PLATFORM_SOURCES
+ arch/${PAL_ARCH_SOURCES_DIR}/stubs.cpp
+ )
+endif()
-if(NOT CLR_CMAKE_TARGET_APPLE)
+if(NOT CLR_CMAKE_TARGET_APPLE AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
list(APPEND PLATFORM_SOURCES
arch/${PAL_ARCH_SOURCES_DIR}/callsignalhandlerwrapper.S
arch/${PAL_ARCH_SOURCES_DIR}/signalhandlerhelper.cpp
)
-endif(NOT CLR_CMAKE_TARGET_APPLE)
+endif(NOT CLR_CMAKE_TARGET_APPLE AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
if(CLR_CMAKE_HOST_ARCH_ARM)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
@@ -210,9 +220,9 @@ set_source_files_properties(
INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/../inc/rt
)
-if(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND)
+if(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
set(LIBUNWIND_OBJECTS $)
-endif(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND)
+endif(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
add_library(coreclrpal
STATIC
diff --git a/src/coreclr/pal/src/arch/wasm/stubs.cpp b/src/coreclr/pal/src/arch/wasm/stubs.cpp
new file mode 100644
index 00000000000000..66b73f8badf17b
--- /dev/null
+++ b/src/coreclr/pal/src/arch/wasm/stubs.cpp
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "pal/dbgmsg.h"
+#include "pal/signal.hpp"
+
+SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first
+
+/* debugbreak */
+
+extern "C" void
+DBG_DebugBreak()
+{
+ asm volatile ("unreachable");
+}
+
+/* context */
+
+extern "C" void
+RtlCaptureContext(OUT PCONTEXT ContextRecord)
+{
+ _ASSERT("RtlCaptureContext not implemented on wasm");
+}
+
+extern "C" void
+CONTEXT_CaptureContext(LPCONTEXT lpContext)
+{
+ _ASSERT("CONTEXT_CaptureContext not implemented on wasm");
+}
+
+extern "C" void ThrowExceptionFromContextInternal(CONTEXT* context, PAL_SEHException* ex)
+{
+ _ASSERT("ThrowExceptionFromContextInternal not implemented on wasm");
+}
+
+/* unwind */
+
+void ExecuteHandlerOnCustomStack(int code, siginfo_t *siginfo, void *context, size_t sp, SignalHandlerWorkerReturnPoint* returnPoint)
+{
+ _ASSERT("ExecuteHandlerOnCustomStack not implemented on wasm");
+}
+
+extern "C" int unw_getcontext(int)
+{
+ _ASSERT("unw_getcontext not implemented on wasm");
+ return 0;
+}
+
+extern "C" int unw_init_local(int, int)
+{
+ _ASSERT("unw_init_local not implemented on wasm");
+ return 0;
+}
+
+extern "C" int unw_step(int)
+{
+ _ASSERT("unw_step not implemented on wasm");
+ return 0;
+}
+
+extern "C" int unw_is_signal_frame(int)
+{
+ _ASSERT("unw_is_signal_frame not implemented on wasm");
+ return 0;
+}
+
+/* threading */
+
+extern "C" int pthread_setschedparam(pthread_t, int, const struct sched_param *)
+{
+ _ASSERT("pthread_setschedparam not implemented on wasm");
+ return 0;
+}
diff --git a/src/coreclr/pal/src/configure.cmake b/src/coreclr/pal/src/configure.cmake
index 0dc8c6524d298c..55d3f47ff46748 100644
--- a/src/coreclr/pal/src/configure.cmake
+++ b/src/coreclr/pal/src/configure.cmake
@@ -937,6 +937,9 @@ elseif(CLR_CMAKE_TARGET_HAIKU)
# Haiku does not have ptrace.
set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0)
set(HAVE_SCHED_OTHER_ASSIGNABLE 1)
+elseif(CLR_CMAKE_TARGET_BROWSER)
+ set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0)
+ set(HAVE_SCHED_OTHER_ASSIGNABLE 0)
else() # Anything else is Linux
# LTTNG is not available on Android, so don't error out
if(NOT HAVE_LTTNG_TRACEPOINT_H AND NOT CLR_CMAKE_TARGET_ANDROID AND FEATURE_EVENT_TRACE)
diff --git a/src/coreclr/pal/src/debug/debug.cpp b/src/coreclr/pal/src/debug/debug.cpp
index 5f598a65494bb1..63a98aae178d60 100644
--- a/src/coreclr/pal/src/debug/debug.cpp
+++ b/src/coreclr/pal/src/debug/debug.cpp
@@ -111,6 +111,9 @@ This is a no-op for x86 architectures where the instruction and data
caches are coherent in hardware. For non-X86 architectures, this call
usually maps to a kernel API to flush the D-caches on all processors.
+It is also no-op on wasm. We don't have a way to flush the instruction
+cache and it is also not needed.
+
--*/
BOOL
PALAPI
@@ -422,7 +425,12 @@ DebugBreak(
BOOL
IsInDebugBreak(void *addr)
{
+#if defined (__wasm__)
+ _ASSERT("IsInDebugBreak not implemented on wasm");
+ return false;
+#else
return (addr >= (void *)DBG_DebugBreak) && (addr <= (void *)DBG_DebugBreak_End);
+#endif
}
/*++
diff --git a/src/coreclr/pal/src/exception/seh-unwind.cpp b/src/coreclr/pal/src/exception/seh-unwind.cpp
index 7f29df974b180c..8b6631a527d16a 100644
--- a/src/coreclr/pal/src/exception/seh-unwind.cpp
+++ b/src/coreclr/pal/src/exception/seh-unwind.cpp
@@ -497,6 +497,8 @@ void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext)
unw_get_reg(cursor, UNW_PPC64_R28, (unw_word_t *) &winContext->R28);
unw_get_reg(cursor, UNW_PPC64_R29, (unw_word_t *) &winContext->R29);
unw_get_reg(cursor, UNW_PPC64_R30, (unw_word_t *) &winContext->R30);
+#elif defined(HOST_WASM)
+ ASSERT("UnwindContextToWinContext not implemented for WASM");
#else
#error unsupported architecture
#endif
@@ -631,6 +633,8 @@ void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext, KNONVOL
GetContextPointer(cursor, unwContext, UNW_PPC64_R29, (SIZE_T **)&contextPointers->R29);
GetContextPointer(cursor, unwContext, UNW_PPC64_R30, (SIZE_T **)&contextPointers->R30);
GetContextPointer(cursor, unwContext, UNW_PPC64_R31, (SIZE_T **)&contextPointers->R31);
+#elif defined(HOST_WASM)
+ ASSERT("GetContextPointers not implemented for WASM");
#else
#error unsupported architecture
#endif
diff --git a/src/coreclr/pal/src/exception/seh.cpp b/src/coreclr/pal/src/exception/seh.cpp
index 02a540734001b0..bff76ad159f36d 100644
--- a/src/coreclr/pal/src/exception/seh.cpp
+++ b/src/coreclr/pal/src/exception/seh.cpp
@@ -304,7 +304,7 @@ PAL_ERROR SEHEnable(CPalThread *pthrCurrent)
{
#if HAVE_MACH_EXCEPTIONS
return pthrCurrent->EnableMachExceptions();
-#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined(__HAIKU__)
+#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined(__HAIKU__) || defined(__wasm__)
return NO_ERROR;
#else// HAVE_MACH_EXCEPTIONS
#error not yet implemented
@@ -329,7 +329,7 @@ PAL_ERROR SEHDisable(CPalThread *pthrCurrent)
{
#if HAVE_MACH_EXCEPTIONS
return pthrCurrent->DisableMachExceptions();
-#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined(__HAIKU__)
+#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined(__HAIKU__) || defined(__wasm__)
return NO_ERROR;
#else // HAVE_MACH_EXCEPTIONS
#error not yet implemented
diff --git a/src/coreclr/pal/src/file/file.cpp b/src/coreclr/pal/src/file/file.cpp
index 8eafaab2476bc9..1122fcbe580358 100644
--- a/src/coreclr/pal/src/file/file.cpp
+++ b/src/coreclr/pal/src/file/file.cpp
@@ -323,6 +323,15 @@ CorUnix::InternalCanonicalizeRealPath(LPCSTR lpUnixPath, PathCharString& lpBuffe
}
lpFilename = lpExistingPath;
}
+ else if (pchSeparator == lpExistingPath)
+ {
+ // This is a path in the root i.e. '/tmp'
+ // This scenario will probably only come up in WASM where it is normal to
+ // have a cwd of '/' and store files in the root of the virtual filesystem
+ lpBuffer.Clear();
+ lpBuffer.Append(lpExistingPath, strlen(lpExistingPath));
+ return NO_ERROR;
+ }
else
{
bool fSetFilename = true;
diff --git a/src/coreclr/pal/src/include/pal/context.h b/src/coreclr/pal/src/include/pal/context.h
index 40f0e9b88990df..4418f763f01f58 100644
--- a/src/coreclr/pal/src/include/pal/context.h
+++ b/src/coreclr/pal/src/include/pal/context.h
@@ -209,6 +209,11 @@ struct sve_context {
#define MCREG_Xer(mc) ((mc).gp_regs[37])
#define MCREG_Ccr(mc) ((mc).gp_regs[38])
+#elif defined(HOST_WASM)
+
+#define MCREG_Sp(mc) 0
+#define MCREG_Pc(mc) 0
+
#elif HAVE___GREGSET_T
#ifdef HOST_64BIT
@@ -1389,6 +1394,9 @@ inline static DWORD64 CONTEXTGetPC(LPCONTEXT pContext)
return pContext->PSWAddr;
#elif defined(HOST_POWERPC64)
return pContext->Nip;
+#elif defined(HOST_WASM) // wasm has no PC
+ _ASSERT(false);
+ return 0;
#else
return pContext->Pc;
#endif
@@ -1404,6 +1412,8 @@ inline static void CONTEXTSetPC(LPCONTEXT pContext, DWORD64 pc)
pContext->PSWAddr = pc;
#elif defined(HOST_POWERPC64)
pContext->Nip = pc;
+#elif defined(HOST_WASM) // wasm has no PC
+ _ASSERT(false);
#else
pContext->Pc = pc;
#endif
@@ -1421,6 +1431,9 @@ inline static DWORD64 CONTEXTGetFP(LPCONTEXT pContext)
return pContext->R11;
#elif defined(HOST_POWERPC64)
return pContext->R31;
+#elif defined(HOST_WASM) // wasm has no PC
+ _ASSERT(false);
+ return 0;
#else
return pContext->Fp;
#endif
diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp
index 8dcf3a1aee4830..7a74159cae60b8 100644
--- a/src/coreclr/pal/src/init/pal.cpp
+++ b/src/coreclr/pal/src/init/pal.cpp
@@ -607,6 +607,7 @@ Initialize(
}
}
+#ifndef __wasm__
if (flags & PAL_INITIALIZE_SYNC_THREAD)
{
//
@@ -619,7 +620,7 @@ Initialize(
goto CLEANUP13;
}
}
-
+#endif
/* initialize structured exception handling stuff (signals, etc) */
if (FALSE == SEHInitialize(pThread, flags))
{
@@ -949,6 +950,10 @@ Return value:
--*/
static BOOL INIT_IncreaseDescriptorLimit(void)
{
+#ifdef __wasm__
+ // WebAssembly cannot set limits
+ return TRUE;
+#endif
#ifndef DONT_SET_RLIMIT_NOFILE
struct rlimit rlp;
int result;
diff --git a/src/coreclr/pal/src/loader/module.cpp b/src/coreclr/pal/src/loader/module.cpp
index c8b07c6701750a..a81fa0664d631f 100644
--- a/src/coreclr/pal/src/loader/module.cpp
+++ b/src/coreclr/pal/src/loader/module.cpp
@@ -1017,11 +1017,13 @@ 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
if (exe_module.dl_handle == nullptr)
{
ERROR("Executable module will be broken : dlopen(nullptr) failed\n");
return FALSE;
}
+#endif
exe_module.lib_name = nullptr;
exe_module.refcount = -1;
exe_module.next = &exe_module;
diff --git a/src/coreclr/pal/src/map/virtual.cpp b/src/coreclr/pal/src/map/virtual.cpp
index aa02c81a1514b1..e5e67e18c3b4f6 100644
--- a/src/coreclr/pal/src/map/virtual.cpp
+++ b/src/coreclr/pal/src/map/virtual.cpp
@@ -1056,9 +1056,12 @@ VirtualFree(
goto VirtualFreeExit;
}
- TRACE( "Un-committing the following page(s) %d to %d.\n",
- StartBoundary, MemSize );
+ TRACE( "Un-committing the following page(s) %p to %p.\n",
+ StartBoundary, StartBoundary + MemSize );
+ // mmap support on emscripten/wasm is very limited and doesn't support location hints
+ // (when address is not null)
+#ifndef __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.
@@ -1089,6 +1092,13 @@ VirtualFree(
pthrCurrent->SetLastError( ERROR_INTERNAL_ERROR );
goto VirtualFreeExit;
}
+#else // __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__
}
if ( dwFreeType & MEM_RELEASE )
diff --git a/src/coreclr/pal/src/misc/sysinfo.cpp b/src/coreclr/pal/src/misc/sysinfo.cpp
index f4fef6977f3d62..2d6f9edb620a8f 100644
--- a/src/coreclr/pal/src/misc/sysinfo.cpp
+++ b/src/coreclr/pal/src/misc/sysinfo.cpp
@@ -221,6 +221,8 @@ GetSystemInfo(
lpSystemInfo->lpMaximumApplicationAddress = (PVOID) VM_MAX_PAGE_ADDRESS;
#elif defined(__HAIKU__)
lpSystemInfo->lpMaximumApplicationAddress = (PVOID) 0x7fffffe00000ul;
+#elif defined(__wasm__)
+ lpSystemInfo->lpMaximumApplicationAddress = (PVOID) (1ul << 31);
#elif defined(USERLIMIT)
lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USERLIMIT;
#elif defined(HOST_64BIT)
diff --git a/src/coreclr/pal/src/synchmgr/synchmanager.cpp b/src/coreclr/pal/src/synchmgr/synchmanager.cpp
index eaccd19e209b6e..0d1b0bc32ed1b7 100644
--- a/src/coreclr/pal/src/synchmgr/synchmanager.cpp
+++ b/src/coreclr/pal/src/synchmgr/synchmanager.cpp
@@ -1340,13 +1340,14 @@ namespace CorUnix
goto I_exit;
}
+#ifndef __wasm__
if (!pSynchManager->CreateProcessPipe())
{
ERROR("Unable to create process pipe \n");
palErr = ERROR_OPEN_FAILED;
goto I_exit;
}
-
+#endif
s_pObjSynchMgr = pSynchManager;
// Initialization was successful
diff --git a/src/coreclr/pal/src/thread/context.cpp b/src/coreclr/pal/src/thread/context.cpp
index 82be2fb000d69c..5b798be3a2f283 100644
--- a/src/coreclr/pal/src/thread/context.cpp
+++ b/src/coreclr/pal/src/thread/context.cpp
@@ -316,6 +316,11 @@ typedef int __ptrace_request;
ASSIGN_REG(R29) \
ASSIGN_REG(R30)
+#elif defined(HOST_WASM)
+#define ASSIGN_CONTROL_REGS \
+ ASSERT("WASM does not have registers");
+#define ASSIGN_INTEGER_REGS \
+ ASSERT("WASM does not have registers");
#else
#error "Don't know how to assign registers on this architecture"
#endif
@@ -2183,6 +2188,8 @@ DBG_FlushInstructionCache(
#endif
syscall(__NR_riscv_flush_icache, (char *)lpBaseAddress, (char *)((INT_PTR)lpBaseAddress + dwSize), 0 /* all harts */);
+#elif defined(HOST_WASM)
+ // do nothing, no instruction cache to flush
#elif defined(HOST_APPLE) && !defined(HOST_OSX)
sys_icache_invalidate((void *)lpBaseAddress, dwSize);
#else
diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp
index 20c09eb357dd2e..1688d3b16779bf 100644
--- a/src/coreclr/pal/src/thread/process.cpp
+++ b/src/coreclr/pal/src/thread/process.cpp
@@ -69,6 +69,9 @@ SET_DEFAULT_DEBUG_CHANNEL(PROCESS); // some headers have code with asserts, so d
#define membarrier(...) syscall(__NR_membarrier, __VA_ARGS__)
#elif HAVE_SYS_MEMBARRIER_H
#include
+#ifdef TARGET_BROWSER
+#define membarrier(cmd, flags, cpu_id) 0 // browser/wasm is currently single threaded
+#endif
#endif
#ifdef __APPLE__
diff --git a/src/coreclr/pal/tests/palsuite/CMakeLists.txt b/src/coreclr/pal/tests/palsuite/CMakeLists.txt
index cc0fec6d2aa70e..f651fde4e634aa 100644
--- a/src/coreclr/pal/tests/palsuite/CMakeLists.txt
+++ b/src/coreclr/pal/tests/palsuite/CMakeLists.txt
@@ -523,3 +523,7 @@ target_link_libraries(paltests
install (TARGETS paltests DESTINATION paltests COMPONENT paltests EXCLUDE_FROM_ALL)
add_dependencies(paltests_install paltests)
install (PROGRAMS runpaltests.sh runpaltestshelix.sh DESTINATION paltests COMPONENT paltests EXCLUDE_FROM_ALL)
+
+if(CLR_CMAKE_HOST_BROWSER)
+ install(FILES wasm/index.html paltestlist.txt DESTINATION ${CMAKE_CURRENT_BINARY_DIR} COMPONENT paltests EXCLUDE_FROM_ALL)
+endif(CLR_CMAKE_HOST_BROWSER)
diff --git a/src/coreclr/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt b/src/coreclr/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt
index ca5e4383d57ffb..cda9df41a65e09 100644
--- a/src/coreclr/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt
+++ b/src/coreclr/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt
@@ -1,3 +1,5 @@
+if(NOT CLR_CMAKE_HOST_BROWSER)
+
if(CLR_CMAKE_HOST_UNIX)
add_definitions(-DFEATURE_ENABLE_HARDWARE_EXCEPTIONS)
endif(CLR_CMAKE_HOST_UNIX)
@@ -95,3 +97,5 @@ install (TARGETS paltest_pal_sxs_test1 DESTINATION paltests/exception_handling/p
install (TARGETS paltest_pal_sxs_test1_dll1 DESTINATION paltests/exception_handling/pal_sxs/test1 COMPONENT paltests EXCLUDE_FROM_ALL)
install (TARGETS paltest_pal_sxs_test1_dll2 DESTINATION paltests/exception_handling/pal_sxs/test1 COMPONENT paltests EXCLUDE_FROM_ALL)
add_dependencies(paltests_install paltest_pal_sxs_test1 paltest_pal_sxs_test1_dll1 paltest_pal_sxs_test1_dll2)
+
+endif(NOT CLR_CMAKE_HOST_BROWSER)
\ No newline at end of file
diff --git a/src/coreclr/pal/tests/palsuite/wasm/index.html b/src/coreclr/pal/tests/palsuite/wasm/index.html
new file mode 100644
index 00000000000000..18b6931a4879a8
--- /dev/null
+++ b/src/coreclr/pal/tests/palsuite/wasm/index.html
@@ -0,0 +1,189 @@
+
+
+
+
+ PAL Tests WASM
+
+
+ PAL Tests WASM
+
+
+
+
diff --git a/src/coreclr/runtime.proj b/src/coreclr/runtime.proj
index b0bb03f3f0f662..7b440d5689c469 100644
--- a/src/coreclr/runtime.proj
+++ b/src/coreclr/runtime.proj
@@ -95,14 +95,20 @@
<_CoreClrBuildArg Include="-cmakeargs "-DCLR_CMAKE_ESRP_CLIENT=$(DotNetEsrpToolPath)"" />
+
+ <_CoreClrBuildArg Include="-keepnativesymbols" />
+
+
<_CoreClrBuildScript Condition="$([MSBuild]::IsOsPlatform(Windows))">build-runtime.cmd
<_CoreClrBuildScript Condition="!$([MSBuild]::IsOsPlatform(Windows))">build-runtime.sh
+ <_CoreClrBuildPreSource Condition="'$(TargetsBrowser)' == 'true' and $([MSBuild]::IsOsPlatform(Windows))">
+ <_CoreClrBuildPreSource Condition="'$(TargetsBrowser)' == 'true' and !$([MSBuild]::IsOsPlatform(Windows))">source "$(RepoRoot)src/mono/browser/emsdk/emsdk_env.sh" &&
-
-
+
diff --git a/src/coreclr/tools/CMakeLists.txt b/src/coreclr/tools/CMakeLists.txt
index 4e7f4368681d1d..23eba1bc3a878e 100644
--- a/src/coreclr/tools/CMakeLists.txt
+++ b/src/coreclr/tools/CMakeLists.txt
@@ -1,2 +1,5 @@
add_subdirectory(SOS)
-add_subdirectory(superpmi)
+
+if (NOT CLR_CMAKE_TARGET_BROWSER)
+ add_subdirectory(superpmi)
+endif()
diff --git a/src/mono/mono.proj b/src/mono/mono.proj
index 3ace486d3e9cfe..9dfdfe6f78e9ad 100644
--- a/src/mono/mono.proj
+++ b/src/mono/mono.proj
@@ -59,6 +59,7 @@
$(runtimelinuxx64MicrosoftNETCoreRuntimeMonoLLVMSdkVersion.Substring(0, $(runtimelinuxx64MicrosoftNETCoreRuntimeMonoLLVMSdkVersion.IndexOf('.'))))
$(runtimelinuxx64MicrosoftNETCoreRuntimeMonoLLVMLibclangVersion)
true
+ Build
@@ -175,6 +176,7 @@
@@ -1046,7 +1048,7 @@ JS_ENGINES = [NODE_JS]
-
+
diff --git a/src/native/corehost/apphost/static/CMakeLists.txt b/src/native/corehost/apphost/static/CMakeLists.txt
index 0ceebea335bc42..04e27826b08425 100644
--- a/src/native/corehost/apphost/static/CMakeLists.txt
+++ b/src/native/corehost/apphost/static/CMakeLists.txt
@@ -204,7 +204,7 @@ else()
include(${CLR_SRC_NATIVE_DIR}/libs/System.IO.Compression.Native/extra_libs.cmake)
append_extra_compression_libs(NATIVE_LIBS)
- if (NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID) # no gssapi on tvOS, see https://developer.apple.com/documentation/gss
+ if (NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER) # no gssapi on tvOS, see https://developer.apple.com/documentation/gss
# Additional requirements for System.Net.Security.Native
include(${CLR_SRC_NATIVE_DIR}/libs/System.Net.Security.Native/extra_libs.cmake)
append_extra_security_libs(NATIVE_LIBS)
@@ -214,7 +214,7 @@ else()
include(${CLR_SRC_NATIVE_DIR}/libs/System.Native/extra_libs.cmake)
append_extra_system_libs(NATIVE_LIBS)
- if(NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID)
+ if(NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER)
# Additional requirements for System.Security.Cryptography.Native.OpenSsl
include(${CLR_SRC_NATIVE_DIR}/libs/System.Security.Cryptography.Native/extra_libs.cmake)
append_extra_cryptography_libs(NATIVE_LIBS)
diff --git a/src/native/libs/CMakeLists.txt b/src/native/libs/CMakeLists.txt
index 7a7d94ee80842f..c90e9b8a45ddc5 100644
--- a/src/native/libs/CMakeLists.txt
+++ b/src/native/libs/CMakeLists.txt
@@ -119,6 +119,10 @@ if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI)
add_subdirectory(System.IO.Ports.Native)
endif ()
+ if (MONO_WASM_MT)
+ add_definitions(-DMONO_WASM_MT)
+ endif()
+
if (CMAKE_C_COMPILER_ID MATCHES "Clang")
add_compile_options(-Weverything)
add_compile_options(-Wno-format-nonliteral)
diff --git a/src/native/libs/System.Globalization.Native/CMakeLists.txt b/src/native/libs/System.Globalization.Native/CMakeLists.txt
index 035f85a257b97c..496bdb0d33e5cd 100644
--- a/src/native/libs/System.Globalization.Native/CMakeLists.txt
+++ b/src/native/libs/System.Globalization.Native/CMakeLists.txt
@@ -22,7 +22,7 @@ if(CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_WASI)
add_compile_options(-Wno-unknown-warning-option)
# The mobile configurations in particular bring their own ICU, so skip
- if (NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT DEFINED CMAKE_ICU_DIR)
+ if (NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT DEFINED CMAKE_ICU_DIR AND NOT CLR_CMAKE_TARGET_BROWSER)
if (CLR_CMAKE_TARGET_OSX)
execute_process(COMMAND brew --prefix OUTPUT_VARIABLE brew_prefix OUTPUT_STRIP_TRAILING_WHITESPACE)
set(ICU_HOMEBREW_INC_PATH "${brew_prefix}/opt/icu4c/include")
diff --git a/src/native/libs/System.Net.Security.Native/CMakeLists.txt b/src/native/libs/System.Net.Security.Native/CMakeLists.txt
index b0e02f41509b58..4a19c74dae73b8 100644
--- a/src/native/libs/System.Net.Security.Native/CMakeLists.txt
+++ b/src/native/libs/System.Net.Security.Native/CMakeLists.txt
@@ -5,7 +5,9 @@ add_compile_options(-Wno-incompatible-pointer-types-discards-qualifiers)
include(${CMAKE_CURRENT_LIST_DIR}/extra_libs.cmake)
set(NATIVE_LIBS_EXTRA)
-append_extra_security_libs(NATIVE_LIBS_EXTRA)
+if (NOT CLR_CMAKE_TARGET_BROWSER)
+ append_extra_security_libs(NATIVE_LIBS_EXTRA)
+endif()
set(NATIVEGSS_SOURCES
pal_gssapi.c
diff --git a/src/native/libs/build-native.cmd b/src/native/libs/build-native.cmd
index 5ccd7fe0a4230a..1ccb8814be1576 100644
--- a/src/native/libs/build-native.cmd
+++ b/src/native/libs/build-native.cmd
@@ -49,6 +49,7 @@ if /i [%1] == [icudir] ( set __icuDir=%2&&shift&&shift&goto Arg_Loop)
if /i [%1] == [usepthreads] ( set __usePThreads=1&&shift&goto Arg_Loop)
if /i [%1] == [-fsanitize] ( set __ExtraCmakeParams=%__ExtraCmakeParams% "-DCLR_CMAKE_ENABLE_SANITIZERS=$2"&&shift&&shift&goto Arg_Loop)
+if /i [%1] == [-cmakeargs] ( set __ExtraCmakeParams=%__ExtraCmakeParams% %2&&shift&&shift&goto Arg_Loop)
if /i [%1] == [-os] ( set __TargetOS=%2%&&shift&&shift&goto Arg_Loop)
shift
diff --git a/src/native/libs/build-native.proj b/src/native/libs/build-native.proj
index e3f9e73c3c0196..9351fc27427231 100644
--- a/src/native/libs/build-native.proj
+++ b/src/native/libs/build-native.proj
@@ -50,7 +50,8 @@
<_PortableBuildArg Condition="'$(PortableBuild)' != 'true'"> -portablebuild=false
<_CrossBuildArg Condition="'$(CrossBuild)' == 'true'"> -cross
<_KeepNativeSymbolsBuildArg Condition="'$(KeepNativeSymbols)' != 'false'"> -keepnativesymbols
- <_CMakeArgs Condition="'$(CMakeArgs)' != ''"> -cmakeargs "$(CMakeArgs)"
+ <_MonoWasmMTCMakeArgs Condition="'$(WasmEnableThreads)' == 'true'"> -DMONO_WASM_MT=1
+ <_CMakeArgs Condition="'$(CMakeArgs)' != '' or '$(_MonoWasmMTCMakeArgs)' != ''"> -cmakeargs "$(CMakeArgs)$(_MonoWasmMTCMakeArgs)"
diff --git a/src/native/minipal/thread.h b/src/native/minipal/thread.h
index 0ebd00415dbb19..7655f4bf2c7f88 100644
--- a/src/native/minipal/thread.h
+++ b/src/native/minipal/thread.h
@@ -43,7 +43,7 @@ extern "C" {
*/
static inline size_t minipal_get_current_thread_id(void)
{
-#ifdef __wasm
+#if defined(__wasm) && defined(MONO_WASM_MT)
return 0;
#else
#if defined(__GNUC__) && !defined(__clang__) && defined(__cplusplus)