diff --git a/README.md b/README.md
index b115294b7ad1..9652429fb132 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# .NET Runtime - Native AOT
-This branch contains experimental fork of CoreCLR [.NET runtime](http://github.com/dotnet/runtime) optimized for the [Native AOT Form factor](https://github.com/dotnet/designs/blob/main/accepted/2020/form-factors.md#native-aot-form-factors). The ahead-of-time (AOT) toolchain can compile .NET application into a native (architecture specific) single-file executable. It can also produce standalone dynamic or static libraries that can be consumed by applications written in other programming languages.
+This branch contains experimental fork of CoreCLR [.NET runtime](http://github.com/dotnet/runtime) optimized for the [Native AOT Form factor](https://github.com/dotnet/designs/blob/main/accepted/2020/form-factors.md#native-aot-form-factors). The ahead-of-time (AOT) toolchain can compile .NET application into a native (architecture specific) single-file executable. It can also produce standalone dynamic or static libraries that can be consumed by applications written in other programming languages. This branch contains the experimental feature of compiling to LLVM to target Web Assembly at present and other LLVM targets in the future.
## Samples
diff --git a/docs/workflow/building/coreclr/nativeaot.md b/docs/workflow/building/coreclr/nativeaot.md
index 7cba07269c39..3e8f53ae1322 100644
--- a/docs/workflow/building/coreclr/nativeaot.md
+++ b/docs/workflow/building/coreclr/nativeaot.md
@@ -10,6 +10,12 @@ The Native AOT toolchain can be currently built for Linux, macOS and Windows x64
- Add the package directory to your `nuget.config` file. For example, replace `dotnet-experimental` line in `samples\HelloWorld\nuget.config` with ``
- Run `dotnet publish --packages pkg -r [win-x64|linux-x64|osx-64] -c [Debug|Release]` to publish your project. `--packages pkg` option restores the package into a local directory that is easy to cleanup once you are done. It avoids polluting the global nuget cache with your locally built dev package.
+## Building for Web Assembly
+- Currently only tested on Windows
+- Run `build nativeaot+libs+nativeaot.packages -rc [Debug|Release] -lc [Debug|Release] -a wasm -os Browser -runtimeFlavor CoreCLR`
+- Add the package directory to your `nuget.config` as above.
+- Run `dotnet publish -r browser-wasm -c [Debug|Release] /p:Platform=wasm` to publish.
+
## Visual Studio Solutions
The repository has a number of Visual Studio Solutions files (`*.sln`) that are useful for editing parts of the repository. Build the repo from command line first before building using the solution files. Remember to select the appropriate configuration that you built. By default, `build.cmd` builds Debug x64 and so `Debug` and `x64` must be selected in the solution build configuration drop downs.
diff --git a/eng/Configurations.props b/eng/Configurations.props
index 09814ae0c05e..23b85837df79 100644
--- a/eng/Configurations.props
+++ b/eng/Configurations.props
@@ -123,9 +123,9 @@
<_toolRuntimeRID Condition="'$(_runtimeOS)' == 'linux-musl' and $(TargetArchitecture.StartsWith('arm')) and !$(_hostArch.StartsWith('arm'))">linux-x64
- <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'browser' and '$(TargetOS)' == 'windows'">win-x64
- <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'browser' and '$(TargetOS)' != 'windows' and $(_buildingInOSX)">osx-x64
- <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'browser' and '$(TargetOS)' != 'windows' and !$(_buildingInOSX)">linux-x64
+ <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'browser'">linux-x64
+ <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'browser' and $([MSBuild]::IsOSPlatform('WINDOWS'))">win-x64
+ <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'browser' and $([MSBuild]::IsOSPlatform('OSX'))">osx-x64
<_toolRuntimeRID Condition="'$(_runtimeOS)' == 'android' and '$(TargetOS)' == 'windows'">win-x64
diff --git a/eng/Subsets.props b/eng/Subsets.props
index 6423a04c0938..0fc111ff877d 100644
--- a/eng/Subsets.props
+++ b/eng/Subsets.props
@@ -237,7 +237,7 @@
-
+
diff --git a/eng/build.ps1 b/eng/build.ps1
index 4faea7ff30c3..658f35ac48bc 100644
--- a/eng/build.ps1
+++ b/eng/build.ps1
@@ -243,7 +243,11 @@ foreach ($config in $configuration) {
$argumentsWithConfig = $arguments + " -configuration $((Get-Culture).TextInfo.ToTitleCase($config))";
foreach ($singleArch in $arch) {
$argumentsWithArch = "/p:TargetArchitecture=$singleArch " + $argumentsWithConfig
- $env:__DistroRid="win-$singleArch"
+ if ($singleArch -eq "wasm") {
+ $env:__DistroRid="browser-wasm"
+ } else {
+ $env:__DistroRid="win-$singleArch"
+ }
Invoke-Expression "& `"$PSScriptRoot/common/build.ps1`" $argumentsWithArch"
if ($lastExitCode -ne 0) {
$failedBuilds += "Configuration: $config, Architecture: $singleArch"
diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets
index 5cb3c220feea..214d68d51c75 100644
--- a/eng/liveBuilds.targets
+++ b/eng/liveBuilds.targets
@@ -159,14 +159,14 @@
$(LibrariesNativeArtifactsPath)*.pdb"
IsNative="true"
Exclude="@(ExcludeNativeLibrariesRuntimeFiles)" />
-
-
- >>:TARGET_X86>)
+elseif (CLR_CMAKE_TARGET_ARCH_WASM)
+ set(ARCH_TARGET_NAME wasm)
+ set(ARCH_SOURCES_DIR wasm)
+ add_compile_definitions($<$>>:TARGET_WASM>)
else ()
clr_unknown_arch()
endif ()
@@ -294,15 +302,26 @@ endif ()
#--------------------------------------
# Compile Options
#--------------------------------------
-if (CLR_CMAKE_HOST_UNIX)
- # Disable frame pointer optimizations so profilers can get better call stacks
- add_compile_options(-fno-omit-frame-pointer)
-
+if (NOT(MSVC))
# The -fms-extensions enable the stuff like __if_exists, __declspec(uuid()), etc.
add_compile_options(-fms-extensions)
#-fms-compatibility Enable full Microsoft Visual C++ compatibility
#-fms-extensions Accept some non-standard constructs supported by the Microsoft compiler
+ # Disabled common warnings
+ add_compile_options(-Wno-unused-variable)
+ add_compile_options(-Wno-unused-value)
+ add_compile_options(-Wno-unused-function)
+ add_compile_options(-Wno-tautological-compare)
+
+ #These seem to indicate real issues
+ add_compile_options($<$:-Wno-invalid-offsetof>)
+endif (NOT(MSVC))
+
+if (CLR_CMAKE_HOST_UNIX)
+ # Disable frame pointer optimizations so profilers can get better call stacks
+ add_compile_options(-fno-omit-frame-pointer)
+
# Make signed arithmetic overflow of addition, subtraction, and multiplication wrap around
# using twos-complement representation (this is normally undefined according to the C++ spec).
add_compile_options(-fwrapv)
@@ -322,20 +341,11 @@ if (CLR_CMAKE_HOST_UNIX)
add_compile_options(-Werror)
endif(PRERELEASE)
- # Disabled common warnings
- add_compile_options(-Wno-unused-variable)
- add_compile_options(-Wno-unused-value)
- add_compile_options(-Wno-unused-function)
- add_compile_options(-Wno-tautological-compare)
-
check_cxx_compiler_flag(-Wimplicit-fallthrough COMPILER_SUPPORTS_W_IMPLICIT_FALLTHROUGH)
if (COMPILER_SUPPORTS_W_IMPLICIT_FALLTHROUGH)
add_compile_options(-Wimplicit-fallthrough)
endif()
- #These seem to indicate real issues
- add_compile_options($<$:-Wno-invalid-offsetof>)
-
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# The -ferror-limit is helpful during the porting, it makes sure the compiler doesn't stop
# after hitting just about 20 errors.
@@ -639,6 +649,8 @@ if (CLR_CMAKE_HOST_WIN32)
message(FATAL_ERROR "MC not found")
endif()
+elseif(CLR_CMAKE_TARGET_ARCH_WASM)
+ # No other tools required, emcmake is already running this script
else (CLR_CMAKE_HOST_WIN32)
enable_language(ASM)
diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake
index f8b1a10c0e8f..c659c0c6594c 100644
--- a/eng/native/configureplatform.cmake
+++ b/eng/native/configureplatform.cmake
@@ -183,7 +183,8 @@ if(CLR_CMAKE_HOST_OS STREQUAL Windows)
endif(CLR_CMAKE_HOST_OS STREQUAL Windows)
if(CLR_CMAKE_HOST_OS STREQUAL Emscripten)
- #set(CLR_CMAKE_HOST_UNIX 1) # TODO: this should be reenabled but it activates a bunch of additional compiler flags in configurecompiler.cmake
+ set(CLR_CMAKE_HOST_WIN32 0)
+ set(CLR_CMAKE_HOST_UNIX 0)
set(CLR_CMAKE_HOST_UNIX_WASM 1)
set(CLR_CMAKE_HOST_BROWSER 1)
endif(CLR_CMAKE_HOST_OS STREQUAL Emscripten)
@@ -337,8 +338,10 @@ endif(CLR_CMAKE_TARGET_OS STREQUAL SunOS)
if(CLR_CMAKE_TARGET_OS STREQUAL Emscripten)
set(CLR_CMAKE_TARGET_UNIX 1)
- set(CLR_CMAKE_TARGET_LINUX 1)
set(CLR_CMAKE_TARGET_BROWSER 1)
+ if(NOT(RUNTIME_FLAVOR STREQUAL CoreClr))
+ set(CLR_CMAKE_TARGET_LINUX 1)
+ endif(NOT(RUNTIME_FLAVOR STREQUAL CoreClr))
endif(CLR_CMAKE_TARGET_OS STREQUAL Emscripten)
if(CLR_CMAKE_TARGET_UNIX)
@@ -364,7 +367,7 @@ endif(CLR_CMAKE_TARGET_UNIX)
# check if host & target os/arch combination are valid
if (CLR_CMAKE_TARGET_OS STREQUAL CLR_CMAKE_HOST_OS)
if(NOT(CLR_CMAKE_TARGET_ARCH STREQUAL CLR_CMAKE_HOST_ARCH))
- if(NOT((CLR_CMAKE_HOST_ARCH_AMD64 AND CLR_CMAKE_TARGET_ARCH_ARM64) OR (CLR_CMAKE_HOST_ARCH_I386 AND CLR_CMAKE_TARGET_ARCH_ARM) OR (CLR_CMAKE_HOST_ARCH_AMD64 AND CLR_CMAKE_TARGET_ARCH_ARM) OR (CLR_CMAKE_HOST_ARCH_AMD64 AND CLR_CMAKE_TARGET_ARCH_I386)))
+ if(NOT((CLR_CMAKE_HOST_ARCH_AMD64 AND CLR_CMAKE_TARGET_ARCH_ARM64) OR (CLR_CMAKE_HOST_ARCH_I386 AND CLR_CMAKE_TARGET_ARCH_ARM) OR (CLR_CMAKE_HOST_ARCH_AMD64 AND CLR_CMAKE_TARGET_ARCH_ARM) OR (CLR_CMAKE_HOST_ARCH_AMD64 AND CLR_CMAKE_TARGET_ARCH_I386) OR (CLR_CMAKE_TARGET_UNIX_WASM AND CLR_CMAKE_HOST_ARCH STREQUAL Windows_NT)))
message(FATAL_ERROR "Invalid platform and target arch combination TARGET_ARCH=${CLR_CMAKE_TARGET_ARCH} HOST_ARCH=${CLR_CMAKE_HOST_ARCH}")
endif()
endif()
diff --git a/eng/native/gen-buildsys.cmd b/eng/native/gen-buildsys.cmd
index c340ec2f9fad..52674a3c73ba 100644
--- a/eng/native/gen-buildsys.cmd
+++ b/eng/native/gen-buildsys.cmd
@@ -29,7 +29,7 @@ if /i "%__Ninja%" == "1" (
if /i NOT "%__Arch%" == "wasm" (
if /i "%__VSVersion%" == "vs2019" (set __CmakeGenerator=%__CmakeGenerator% 16 2019)
if /i "%__VSVersion%" == "vs2017" (set __CmakeGenerator=%__CmakeGenerator% 15 2017)
-
+
if /i "%__Arch%" == "x64" (set __ExtraCmakeParams=%__ExtraCmakeParams% -A x64)
if /i "%__Arch%" == "arm" (set __ExtraCmakeParams=%__ExtraCmakeParams% -A ARM)
if /i "%__Arch%" == "arm64" (set __ExtraCmakeParams=%__ExtraCmakeParams% -A ARM64)
@@ -38,17 +38,17 @@ if /i "%__Ninja%" == "1" (
set __CmakeGenerator=NMake Makefiles
)
)
-
+echo gen-buildsys %__Arch%
if /i "%__Arch%" == "wasm" (
- if "%EMSDK_PATH%" == "" (
- echo Error: Should set EMSDK_PATH environment variable pointing to emsdk root.
+ if "%EMSDK%" == "" (
+ echo Error: Should set EMSDK environment variable pointing to emsdk root.
exit /B 1
)
- if "%EMSCRIPTEN_ROOT%" == "" (
- set EMSCRIPTEN_ROOT="%EMSDK_PATH/upstream/emscripten%"
+ if /i "%CMAKE_BUILD_TYPE%" == "debug" (
+ set __ExtraCmakeParams=%__ExtraCmakeParams% -g -O0
)
- set __ExtraCmakeParams=%__ExtraCmakeParams% "-DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=1" "-DCMAKE_TOOLCHAIN_FILE=%EMSCRIPTEN%/cmake/Modules/Platform/Emscripten.cmake"
+ set __ExtraCmakeParams=%__ExtraCmakeParams% "-DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%" "-DCMAKE_TOOLCHAIN_FILE=%EMSDK%/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" -DCLR_CMAKE_TARGET_ARCH=wasm -DCLR_CMAKE_TARGET_ARCH_WASM=1 -DCLR_CMAKE_HOST_ARCH=Windows_NT -DCLR_CMAKE_HOST_OS=Emscripten -DRUNTIME_FLAVOR=CoreClr -DCLR_CMAKE_HOST_UNIX_WASM=1 "-DCLR_ENG_NATIVE_DIR=%__repoRoot%\eng\native" "-DCMAKE_REPO_ROOT=%__repoRoot%" -DCLR_CMAKE_KEEP_NATIVE_SYMBOLS=1
set __UseEmcmake=1
) else (
set __ExtraCmakeParams=%__ExtraCmakeParams% "-DCMAKE_SYSTEM_VERSION=10.0"
diff --git a/samples/HelloWorld/HelloWorld.csproj b/samples/HelloWorld/HelloWorld.csproj
index 0dd37c7c03c4..fc110f34ca6e 100644
--- a/samples/HelloWorld/HelloWorld.csproj
+++ b/samples/HelloWorld/HelloWorld.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/samples/HelloWorld/README.md b/samples/HelloWorld/README.md
index ad2bca14daf6..f97770d08ff0 100644
--- a/samples/HelloWorld/README.md
+++ b/samples/HelloWorld/README.md
@@ -33,7 +33,7 @@ This will add a nuget.config file to your application. Open the file and in the
Once you've added the package source, add a reference to the compiler by running the following command:
```bash
-> dotnet add package Microsoft.DotNet.ILCompiler -v 6.0.0-*
+> dotnet add package Microsoft.DotNet.ILCompiler.LLVM -v 6.0.0-*
```
## Restore and Publish your app
diff --git a/samples/HelloWorld/nuget.config b/samples/HelloWorld/nuget.config
index 689c575ce22e..2c2fd2f313ed 100644
--- a/samples/HelloWorld/nuget.config
+++ b/samples/HelloWorld/nuget.config
@@ -3,7 +3,7 @@
-
+
diff --git a/samples/NativeLibrary/NativeLibrary.csproj b/samples/NativeLibrary/NativeLibrary.csproj
index c13e259a1bec..e06e6ac40238 100644
--- a/samples/NativeLibrary/NativeLibrary.csproj
+++ b/samples/NativeLibrary/NativeLibrary.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt
index 98a9aa8ea507..11c9485ae293 100644
--- a/src/coreclr/CMakeLists.txt
+++ b/src/coreclr/CMakeLists.txt
@@ -75,21 +75,23 @@ if(CLR_CMAKE_HOST_UNIX)
add_subdirectory(src/pal)
add_subdirectory(src/hosts)
else(CLR_CMAKE_HOST_UNIX)
- if(CLR_CMAKE_TARGET_UNIX)
+ if(CLR_CMAKE_TARGET_UNIX AND NOT CLR_CMAKE_HOST_UNIX_WASM)
add_subdirectory(src/pal/src/libunwind)
- endif(CLR_CMAKE_TARGET_UNIX)
+ endif(CLR_CMAKE_TARGET_UNIX AND NOT CLR_CMAKE_HOST_UNIX_WASM)
endif(CLR_CMAKE_HOST_UNIX)
# Add this subdir. We install the headers for the jit.
add_subdirectory(src/pal/prebuilt/inc)
-add_subdirectory(src/debug/debug-pal)
+if(NOT CLR_CMAKE_HOST_UNIX_WASM)
+ add_subdirectory(src/debug/debug-pal)
+ add_subdirectory(src/tools/aot/jitinterface)
+endif(NOT CLR_CMAKE_HOST_UNIX_WASM)
if(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_BUILD_SUBSET_RUNTIME)
add_subdirectory(src/gc/sample)
endif()
-add_subdirectory(src/tools/aot/jitinterface)
if(NOT CLR_CROSS_COMPONENTS_BUILD)
add_subdirectory(src/nativeaot)
diff --git a/src/coreclr/build-runtime.cmd b/src/coreclr/build-runtime.cmd
index ca32712554db..72f983cf169e 100644
--- a/src/coreclr/build-runtime.cmd
+++ b/src/coreclr/build-runtime.cmd
@@ -58,6 +58,7 @@ set __BuildArchX64=0
set __BuildArchX86=0
set __BuildArchArm=0
set __BuildArchArm64=0
+set __BuildArchWasm=0
set __BuildTypeDebug=0
set __BuildTypeChecked=0
@@ -117,6 +118,7 @@ if /i "%1" == "-x64" (set __BuildArchX64=1&set processedArgs=!pr
if /i "%1" == "-x86" (set __BuildArchX86=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
if /i "%1" == "-arm" (set __BuildArchArm=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
if /i "%1" == "-arm64" (set __BuildArchArm64=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "-wasm" (set __BuildArchWasm=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
if /i "%1" == "-debug" (set __BuildTypeDebug=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
if /i "%1" == "-checked" (set __BuildTypeChecked=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
@@ -233,6 +235,11 @@ if %__BuildArchArm64%==1 (
set __BuildArch=arm64
set __CrossArch=x64
)
+if %__BuildArchWasm%==1 (
+ set __TargetOS=browser
+ set __BuildArch=wasm
+ set __BuildJit=0
+)
set /A __TotalSpecifiedBuildType=__BuildTypeDebug + __BuildTypeChecked + __BuildTypeRelease
if %__TotalSpecifiedBuildType% GTR 1 (
@@ -622,6 +629,9 @@ if %__BuildNative% EQU 1 (
if %__Ninja% EQU 1 (
set __ExtraCmakeArgs="-DCMAKE_BUILD_TYPE=!__BuildType!"
)
+ if "%__BuildArch%" == "wasm" (
+ set __ExtraCmakeArgs="-DCMAKE_BUILD_TYPE=!__BuildType!"
+ )
set __ExtraCmakeArgs=!__ExtraCmakeArgs! !___CrossBuildDefine! %__CMakeClrBuildSubsetArgs% "-DCLR_CMAKE_PGO_INSTRUMENT=%__PgoInstrument%" "-DCLR_CMAKE_OPTDATA_PATH=%__PgoOptDataPath%" "-DCLR_CMAKE_PGO_OPTIMIZE=%__PgoOptimize%" "-DCLR_ENG_NATIVE_DIR=%__RepoRootDir%/eng/native" "-DCLR_REPO_ROOT_DIR=%__RepoRootDir%" %__CMakeArgs%
call "%__RepoRootDir%\eng\native\gen-buildsys.cmd" "%__ProjectDir%" "%__IntermediatesDir%" %__VSVersion% %__BuildArch% !__ExtraCmakeArgs!
@@ -656,7 +666,10 @@ if %__BuildNative% EQU 1 (
set __CmakeBuildToolArgs=
) else (
REM We pass the /m flag directly to MSBuild so that we can get both MSBuild and CL parallelism, which is fastest for our builds.
- set __CmakeBuildToolArgs=/nologo /m !__Logging!
+ REM wasm uses nmake which does not support /m
+ if not "%__BuildArch%" == "wasm" (
+ set __CmakeBuildToolArgs=/nologo /m !__Logging!
+ )
)
"%CMakePath%" --build %__IntermediatesDir% --target install --config %__BuildType% -- !__CmakeBuildToolArgs!
@@ -671,6 +684,7 @@ if %__BuildNative% EQU 1 (
)
if /i "%__BuildArch%" == "arm64" goto SkipCopyUcrt
+ if /i "%__BuildArch%" == "wasm" goto SkipCopyUcrt
if not defined UCRTVersion (
echo %__ErrMsgPrefix%%__MsgPrefix%Error: Please install Windows 10 SDK.
diff --git a/src/coreclr/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake
index 1687bc50568f..ab91230e3700 100644
--- a/src/coreclr/clrfeatures.cmake
+++ b/src/coreclr/clrfeatures.cmake
@@ -2,6 +2,10 @@ if(CLR_CMAKE_TARGET_TIZEN_LINUX)
set(FEATURE_GDBJIT_LANGID_CS 1)
endif()
+if(CLR_CMAKE_TARGET_UNIX_WASM)
+ set(FEATURE_EVENT_TRACE 0)
+endif()
+
if(NOT DEFINED FEATURE_EVENT_TRACE)
set(FEATURE_EVENT_TRACE 1)
endif(NOT DEFINED FEATURE_EVENT_TRACE)
diff --git a/src/coreclr/src/CMakeLists.txt b/src/coreclr/src/CMakeLists.txt
index 5f74a587d849..46be64cf4ba9 100644
--- a/src/coreclr/src/CMakeLists.txt
+++ b/src/coreclr/src/CMakeLists.txt
@@ -12,7 +12,9 @@ if(CLR_CMAKE_TARGET_WIN32 AND FEATURE_EVENT_TRACE)
include_directories("${GENERATED_INCLUDE_DIR}/etw")
endif(CLR_CMAKE_TARGET_WIN32 AND FEATURE_EVENT_TRACE)
-add_subdirectory(debug/dbgutil)
+if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+ add_subdirectory(debug/dbgutil)
+endif(NOT CLR_CMAKE_TARGET_ARCH_WASM)
if(CLR_CMAKE_HOST_UNIX)
if(CLR_CMAKE_BUILD_SUBSET_RUNTIME)
@@ -64,28 +66,34 @@ if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSI
add_compile_options(-Wno-error=stringop-overflow=)
endif()
-add_subdirectory(utilcode)
-add_subdirectory(gcinfo)
-add_subdirectory(jit)
-add_subdirectory(inc)
+if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+ add_subdirectory(utilcode)
+ add_subdirectory(gcinfo)
+ add_subdirectory(jit)
+ add_subdirectory(inc)
+endif(NOT CLR_CMAKE_TARGET_ARCH_WASM)
if(CLR_CMAKE_HOST_UNIX)
add_subdirectory(palrt)
endif(CLR_CMAKE_HOST_UNIX)
-add_subdirectory(vm)
+if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+ add_subdirectory(vm)
+endif(NOT CLR_CMAKE_TARGET_ARCH_WASM)
if (CLR_CMAKE_BUILD_SUBSET_RUNTIME)
- add_subdirectory(md)
- add_subdirectory(debug)
- add_subdirectory(binder)
- add_subdirectory(classlibnative)
- add_subdirectory(dlls)
- add_subdirectory(ToolBox)
- add_subdirectory(tools)
- add_subdirectory(unwinder)
- add_subdirectory(ildasm)
- add_subdirectory(ilasm)
- add_subdirectory(interop)
+ if (NOT CLR_CMAKE_TARGET_ARCH_WASM)
+ add_subdirectory(md)
+ add_subdirectory(debug)
+ add_subdirectory(binder)
+ add_subdirectory(classlibnative)
+ add_subdirectory(dlls)
+ add_subdirectory(ToolBox)
+ add_subdirectory(tools)
+ add_subdirectory(unwinder)
+ add_subdirectory(ildasm)
+ add_subdirectory(ilasm)
+ add_subdirectory(interop)
+ endif(NOT CLR_CMAKE_TARGET_ARCH_WASM)
if(CLR_CMAKE_HOST_WIN32)
add_subdirectory(hosts)
diff --git a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj
index 3073cec10bdc..9a1f2f25d5b6 100644
--- a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -132,12 +132,14 @@
+
+
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Exception.CoreCLR.LLVM.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Exception.CoreCLR.LLVM.cs
new file mode 100644
index 000000000000..345c91a44e55
--- /dev/null
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/Exception.CoreCLR.LLVM.cs
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace System
+{
+ public partial class Exception
+ {
+ [DllImport("*")]
+ internal static extern void RhpThrowEx(object exception);
+
+ private static void DispatchExLLVM(object exception)
+ {
+ AppendExceptionStackFrameLLVM(exception, new StackTrace(1).ToString());
+ //RhpThrowEx(exception); can't as not handling the transition unmanaged->managed in the landing pads.
+ }
+
+ private static void AppendExceptionStackFrameLLVM(object exceptionObj, string stackTraceString)
+ {
+ // This method is called by the runtime's EH dispatch code and is not allowed to leak exceptions
+ // back into the dispatcher.
+ try
+ {
+ Exception ex = exceptionObj as Exception;
+ if (ex == null)
+ Environment.FailFast("Exceptions must derive from the System.Exception class");
+
+ if (!RuntimeExceptionHelpers.SafeToPerformRichExceptionSupport)
+ return;
+
+ ex._stackTraceString = stackTraceString.Replace("__", ".").Replace("_", ".");
+ }
+ catch
+ {
+ // We may end up with a confusing stack trace or a confusing ETW trace log, but at least we
+ // can continue to dispatch this exception.
+ }
+ }
+ }
+}
diff --git a/src/coreclr/src/gc/CMakeLists.txt b/src/coreclr/src/gc/CMakeLists.txt
index c68bbcefc347..64cc19ba66b7 100644
--- a/src/coreclr/src/gc/CMakeLists.txt
+++ b/src/coreclr/src/gc/CMakeLists.txt
@@ -26,7 +26,7 @@ set( GC_SOURCES
gcload.cpp
handletablecache.cpp)
-if(CLR_CMAKE_HOST_UNIX)
+if(CLR_CMAKE_HOST_UNIX OR CLR_CMAKE_TARGET_ARCH_WASM)
include(unix/configure.cmake)
set ( GC_SOURCES
${GC_SOURCES}
@@ -37,7 +37,7 @@ else()
set ( GC_SOURCES
${GC_SOURCES}
windows/gcenv.windows.cpp)
-endif(CLR_CMAKE_HOST_UNIX)
+endif(CLR_CMAKE_HOST_UNIX OR CLR_CMAKE_TARGET_ARCH_WASM)
if (CLR_CMAKE_TARGET_ARCH_AMD64 AND CLR_CMAKE_TARGET_WIN32)
set ( GC_SOURCES
diff --git a/src/coreclr/src/gc/env/gcenv.base.h b/src/coreclr/src/gc/env/gcenv.base.h
index 7132efae407c..e1b3fbd6b523 100644
--- a/src/coreclr/src/gc/env/gcenv.base.h
+++ b/src/coreclr/src/gc/env/gcenv.base.h
@@ -231,10 +231,10 @@ typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(void* lpThreadParameter);
#define MemoryBarrier __sync_synchronize
#endif // __aarch64__
-#ifdef __arm__
+#if defined(__arm__) || TARGET_WASM
#define YieldProcessor()
#define MemoryBarrier __sync_synchronize
-#endif // __arm__
+#endif // __arm__ || TARGET_WASM
#endif // _MSC_VER
diff --git a/src/coreclr/src/gc/unix/config.gc.h.in b/src/coreclr/src/gc/unix/config.gc.h.in
index dbcf506f91d2..9a12a23b24f2 100644
--- a/src/coreclr/src/gc/unix/config.gc.h.in
+++ b/src/coreclr/src/gc/unix/config.gc.h.in
@@ -30,6 +30,7 @@
#cmakedefine01 HAVE_SYSINFO_WITH_MEM_UNIT
#cmakedefine01 HAVE_XSW_USAGE
#cmakedefine01 HAVE_XSWDEV
-#cmakedefine01 HAVE_NON_LEGACY_STATFS
-
+#if !TARGET_WASM // emscripten configure test passes for this, but the f_type on the statfs is not recognized and fails https://github.com/dotnet/runtimelab/blob/e5c4d674afdf758adf12052d64c120ce9030048b/src/coreclr/src/gc/unix/cgroup.cpp#L152
+#cmakedefine01 HAVE_NON_LEGACY_STATFS
+#endif
#endif // __CONFIG_H__
diff --git a/src/coreclr/src/gc/unix/configure.cmake b/src/coreclr/src/gc/unix/configure.cmake
index 02c4725e538b..e7f7ee1f1201 100644
--- a/src/coreclr/src/gc/unix/configure.cmake
+++ b/src/coreclr/src/gc/unix/configure.cmake
@@ -1,3 +1,10 @@
+# Emscripten cmake requires these includes
+include(CheckCXXSourceRuns)
+include(CheckCXXSymbolExists)
+include(CheckStructHasMember)
+include(CheckFunctionExists)
+include(CheckPrototypeDefinition)
+
check_include_files(sys/time.h HAVE_SYS_TIME_H)
check_include_files(sys/mman.h HAVE_SYS_MMAN_H)
check_include_files(numa.h HAVE_NUMA_H)
diff --git a/src/coreclr/src/nativeaot/Bootstrap/main.cpp b/src/coreclr/src/nativeaot/Bootstrap/main.cpp
index 7fda9a47b622..9cd13ed33d19 100644
--- a/src/coreclr/src/nativeaot/Bootstrap/main.cpp
+++ b/src/coreclr/src/nativeaot/Bootstrap/main.cpp
@@ -3,6 +3,10 @@
#include
+#if defined HOST_WASM
+#include
+#endif // HOST_WASM
+
//
// This is the mechanism whereby multiple linked modules contribute their global data for initialization at
// startup of the application.
@@ -143,13 +147,58 @@ extern "C" int __managed__Main(int argc, char* argv[]);
extern "C" void __managed__Startup();
#endif // !CORERT_DLL
+#if defined HOST_WASM
+// Exception wrapper type that allows us to differentiate managed and native exceptions
+class ManagedExceptionWrapper : std::exception
+{
+public:
+ ManagedExceptionWrapper(void* pManagedException)
+ {
+ m_pManagedException = pManagedException;
+ }
+
+public:
+ void* m_pManagedException;
+};
+
+extern "C" void RhpThrowEx(void * pEx)
+{
+ throw ManagedExceptionWrapper(pEx);
+}
+
+extern "C" void RhpThrowHwEx()
+{
+ throw "RhpThrowHwEx";
+}
+
+// returns the Leave target
+extern "C" uint32_t LlvmCatchFunclet(void* pHandlerIP, void* pvRegDisplay);
+extern "C" uint32_t RhpCallCatchFunclet(void * exceptionObj, void* pHandlerIP, void* pvRegDisplay, void *exInfo)
+{
+ return LlvmCatchFunclet(pHandlerIP, pvRegDisplay);
+}
+
+extern "C" uint32_t LlvmFilterFunclet(void* pHandlerIP, void* pvRegDisplay);
+extern "C" uint32_t RhpCallFilterFunclet(void* exceptionObj, void * pHandlerIP, void* shadowStack)
+{
+ return LlvmFilterFunclet(pHandlerIP, shadowStack);
+}
+extern "C" void LlvmFinallyFunclet(void *finallyHandler, void *shadowStack);
+extern "C" void RhpCallFinallyFunclet(void *finallyHandler, void *shadowStack)
+{
+ LlvmFinallyFunclet(finallyHandler, shadowStack);
+}
+extern "C" void* RtRHeaderWrapper();
+#endif // HOST_WASM
+
static int InitializeRuntime()
{
if (!RhInitialize())
return -1;
- // RhpEnableConservativeStackReporting();
-
+#if defined HOST_WASM
+ RhpEnableConservativeStackReporting();
+#else
void * osModule = PalGetModuleHandleFromPointer((void*)&CORERT_ENTRYPOINT);
// TODO: pass struct with parameters instead of the large signature of RhRegisterOSModule
@@ -161,8 +210,13 @@ static int InitializeRuntime()
{
return -1;
}
+#endif // HOST_WASM
+#if defined HOST_WASM
+ InitializeModules(nullptr, (void**)RtRHeaderWrapper(), 1, (void **)&c_classlibFunctions, _countof(c_classlibFunctions));
+#else // !HOST_WASM
InitializeModules(osModule, __modules_a, (int)((__modules_z - __modules_a)), (void **)&c_classlibFunctions, _countof(c_classlibFunctions));
+#endif
#ifdef CORERT_DLL
// Run startup method immediately for a native library
diff --git a/src/coreclr/src/nativeaot/BuildIntegration/BuildFrameworkNativeObjects.proj b/src/coreclr/src/nativeaot/BuildIntegration/BuildFrameworkNativeObjects.proj
index 49c4b2f75751..dd71595be86b 100644
--- a/src/coreclr/src/nativeaot/BuildIntegration/BuildFrameworkNativeObjects.proj
+++ b/src/coreclr/src/nativeaot/BuildIntegration/BuildFrameworkNativeObjects.proj
@@ -11,7 +11,7 @@
-
+
win
osx
linux-musl
+ browser-wasm
linux
- $(PortableRuntimeIdentifier)-$(PlatformTarget)
- runtime.$(PortableRuntimeIdentifier).Microsoft.DotNet.ILCompiler
+ $(PortableRuntimeIdentifier)-$(PlatformTarget)
+ runtime.$(PortableRuntimeIdentifier).Microsoft.DotNet.ILCompiler.LLVM
true
diff --git a/src/coreclr/src/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets b/src/coreclr/src/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
index e520ffa4352d..9cf6b66744ad 100644
--- a/src/coreclr/src/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
+++ b/src/coreclr/src/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
@@ -53,9 +53,9 @@
-
-
-
+
+
+
@@ -74,6 +74,13 @@
+
+
+
+
+
+
+
diff --git a/src/coreclr/src/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/src/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
index da2ea40a4605..59c37a337873 100644
--- a/src/coreclr/src/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
+++ b/src/coreclr/src/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
@@ -14,14 +14,20 @@ The .NET Foundation licenses this file to you under the MIT license.
-->
+
+
+ browser
+ wasm
+
+
$(IntermediateOutputPath)native\
$(OutputPath)native\
true
$(MSBuildThisFileDirectory)..\tools\netstandard\ILCompiler.Build.Tasks.dll
- windows
- OSX
+ windows
+ OSX
$(OS)
true
@@ -55,6 +61,7 @@ The .NET Foundation licenses this file to you under the MIT license.
.so
.lib
.a
+ .html
.def
.exports
@@ -73,6 +80,7 @@ The .NET Foundation licenses this file to you under the MIT license.
$(FrameworkLibPath)\Framework$(LibFileExt)
$(FrameworkLibPath)\libframework$(LibFileExt)
SetupProperties
+ true
@@ -172,7 +180,7 @@ The .NET Foundation licenses this file to you under the MIT license.
-->
-
+
IntermediateOutputPath=$(IntermediateOutputPath);
@@ -204,6 +212,8 @@ The .NET Foundation licenses this file to you under the MIT license.
+
+
@@ -294,15 +304,34 @@ The .NET Foundation licenses this file to you under the MIT license.
-
-
+
+
+
+
+
+
+
+
+ "$(NativeObject)" -o "$(NativeBinary)" -s ALLOW_MEMORY_GROWTH=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_EXCEPTION_CATCHING=0 --emrun
+ $(EmccArgs) "$(IlcPath)/sdk/libPortableRuntime.a" "$(IlcPath)/sdk/libbootstrapper.a" "$(IlcPath)/framework/libSystem.Native.a" $(EmccExtraArgs)
+ $(EmccArgs) -O2 -flto
+ $(EmccArgs) -g3
+
+
+
+
+
+
+
+
= _tryStartOffset) &&
+ (idxTryLandingStart < _tryEndOffset));
+ }
+ }
+
+ // TODO: temporary to try things out, when working look to see how to refactor with FindFirstPassHandler
+ private static bool FindFirstPassHandlerWasm(object exception, uint idxStart, uint idxCurrentBlockStart /* the start IL idx of the current block for the landing pad, will use in place of PC */,
+ void* shadowStack, ref EHClauseIterator clauseIter, out uint tryRegionIdx, out byte* pHandler)
+ {
+ pHandler = (byte*)0;
+ tryRegionIdx = MaxTryRegionIdx;
+ uint lastTryStart = 0, lastTryEnd = 0;
+ RhEHClauseWasm ehClause = new RhEHClauseWasm();
+ for (uint curIdx = 0; clauseIter.Next(ref ehClause); curIdx++)
+ {
+ //
+ // Skip to the starting try region. This is used by collided unwinds and rethrows to pickup where
+ // the previous dispatch left off.
+ //
+ if (idxStart != MaxTryRegionIdx)
+ {
+ if (curIdx <= idxStart)
+ {
+ lastTryStart = ehClause._tryStartOffset;
+ lastTryEnd = ehClause._tryEndOffset;
+ continue;
+ }
+
+ // Now, we continue skipping while the try region is identical to the one that invoked the
+ // previous dispatch.
+ if ((ehClause._tryStartOffset == lastTryStart) && (ehClause._tryEndOffset == lastTryEnd))
+ {
+ continue;
+ }
+
+ // We are done skipping. This is required to handle empty finally block markers that are used
+ // to separate runs of different try blocks with same native code offsets.
+ idxStart = MaxTryRegionIdx;
+ }
+
+ EHClauseIterator.RhEHClauseKindWasm clauseKind = ehClause._clauseKind;
+ if (((clauseKind != EHClauseIterator.RhEHClauseKindWasm.RH_EH_CLAUSE_TYPED) &&
+ (clauseKind != EHClauseIterator.RhEHClauseKindWasm.RH_EH_CLAUSE_FILTER))
+ || !ehClause.ContainsCodeOffset(idxCurrentBlockStart))
+ {
+ continue;
+ }
+
+ // Found a containing clause. Because of the order of the clauses, we know this is the
+ // most containing.
+ if (clauseKind == EHClauseIterator.RhEHClauseKindWasm.RH_EH_CLAUSE_TYPED)
+ {
+ if (ShouldTypedClauseCatchThisException(exception, (EEType*)ehClause._typeSymbol))
+ {
+ pHandler = ehClause._handlerAddress;
+ tryRegionIdx = curIdx;
+ return true;
+ }
+ }
+ else
+ {
+ tryRegionIdx = 0;
+ bool shouldInvokeHandler = InternalCalls.RhpCallFilterFunclet(exception, ehClause._filterAddress, shadowStack);
+ if (shouldInvokeHandler)
+ {
+ pHandler = ehClause._handlerAddress;
+ tryRegionIdx = curIdx;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static void InvokeSecondPassWasm(uint idxStart, uint idxTryLandingStart, ref EHClauseIterator clauseIter, uint idxLimit, void* shadowStack)
+ {
+ uint lastTryStart = 0, lastTryEnd = 0;
+ // Search the clauses for one that contains the current offset.
+ RhEHClauseWasm ehClause = new RhEHClauseWasm();
+ for (uint curIdx = 0; clauseIter.Next(ref ehClause) && curIdx < idxLimit; curIdx++)
+ {
+ //
+ // Skip to the starting try region. This is used by collided unwinds and rethrows to pickup where
+ // the previous dispatch left off.
+ //
+ if (idxStart != MaxTryRegionIdx)
+ {
+ if (curIdx <= idxStart)
+ {
+ lastTryStart = ehClause._tryStartOffset;
+ lastTryEnd = ehClause._tryEndOffset;
+ continue;
+ }
+
+ // Now, we continue skipping while the try region is identical to the one that invoked the
+ // previous dispatch.
+ if ((ehClause._tryStartOffset == lastTryStart) && (ehClause._tryEndOffset == lastTryEnd))
+ continue;
+
+ // We are done skipping. This is required to handle empty finally block markers that are used
+ // to separate runs of different try blocks with same native code offsets.
+ idxStart = MaxTryRegionIdx;
+ }
+
+ EHClauseIterator.RhEHClauseKindWasm clauseKind = ehClause._clauseKind;
+
+ if ((clauseKind != EHClauseIterator.RhEHClauseKindWasm.RH_EH_CLAUSE_FAULT)
+ || !ehClause.TryStartsAt(idxTryLandingStart))
+ {
+ continue;
+ }
+
+ // Found a containing clause. Because of the order of the clauses, we know this is the
+ // most containing.
+
+ // N.B. -- We need to suppress GC "in-between" calls to finallys in this loop because we do
+ // not have the correct next-execution point live on the stack and, therefore, may cause a GC
+ // hole if we allow a GC between invocation of finally funclets (i.e. after one has returned
+ // here to the dispatcher, but before the next one is invoked). Once they are running, it's
+ // fine for them to trigger a GC, obviously.
+ //
+ // As a result, RhpCallFinallyFunclet will set this state in the runtime upon return from the
+ // funclet, and we need to reset it if/when we fall out of the loop and we know that the
+ // method will no longer get any more GC callbacks.
+
+ byte* pFinallyHandler = ehClause._handlerAddress;
+
+ InternalCalls.RhpCallFinallyFunclet(pFinallyHandler, shadowStack);
+ }
+ }
+ } // static class EH
+}
diff --git a/src/coreclr/src/nativeaot/Runtime.Base/src/System/Runtime/StackFrameIterator.wasm.cs b/src/coreclr/src/nativeaot/Runtime.Base/src/System/Runtime/StackFrameIterator.wasm.cs
new file mode 100644
index 000000000000..96e4fffdcdb5
--- /dev/null
+++ b/src/coreclr/src/nativeaot/Runtime.Base/src/System/Runtime/StackFrameIterator.wasm.cs
@@ -0,0 +1,120 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.InteropServices;
+
+namespace System.Runtime
+{
+ internal unsafe struct EHClauseIterator
+ {
+ private uint _totalClauses;
+ private byte *_currentPtr;
+ private int _currentClause;
+
+ private static uint DecodeUnsigned(ref byte* stream)
+ {
+ uint value = 0;
+
+ uint val = *stream;
+ if ((val & 1) == 0)
+ {
+ value = (val >> 1);
+ stream += 1;
+ }
+ else if ((val & 2) == 0)
+ {
+ value = (val >> 2) |
+ (((uint)*(stream + 1)) << 6);
+ stream += 2;
+ }
+ else if ((val & 4) == 0)
+ {
+ value = (val >> 3) |
+ (((uint)*(stream + 1)) << 5) |
+ (((uint)*(stream + 2)) << 13);
+ stream += 3;
+ }
+ else if ((val & 8) == 0)
+ {
+ value = (val >> 4) |
+ (((uint)*(stream + 1)) << 4) |
+ (((uint)*(stream + 2)) << 12) |
+ (((uint)*(stream + 3)) << 20);
+ stream += 4;
+ }
+ else if ((val & 16) == 0)
+ {
+ stream += 1;
+ value = ReadUInt32(ref stream);
+ }
+
+ // TODO : deleted all the error handling
+ return value;
+ }
+
+ private static uint ReadUInt32(ref byte* stream)
+ {
+ uint result = *(uint*)(stream); // Assumes little endian and unaligned access
+ stream += 4;
+ return result;
+ }
+
+ uint GetUnsigned()
+ {
+ uint value;
+ value = DecodeUnsigned(ref _currentPtr);
+ return value;
+ }
+
+ internal void InitFromEhInfo(byte* ehInfoStart, byte* ehInfoEnd, int idxStart)
+ {
+ _currentPtr = ehInfoStart;
+ _currentClause = 0;
+ _totalClauses = GetUnsigned();
+ }
+
+ // TODO : copied from EH
+ internal enum RhEHClauseKindWasm
+ {
+ RH_EH_CLAUSE_TYPED = 0,
+ RH_EH_CLAUSE_FAULT = 1,
+ RH_EH_CLAUSE_FILTER = 2,
+ RH_EH_CLAUSE_UNUSED = 3,
+ }
+
+ internal bool Next(ref EH.RhEHClauseWasm pEHClause)
+ {
+ if (_currentClause >= _totalClauses) return false;
+
+ _currentClause++;
+ pEHClause._tryStartOffset = GetUnsigned();
+ uint tryLengthAndKind = GetUnsigned();
+ pEHClause._clauseKind = (RhEHClauseKindWasm)(tryLengthAndKind & 3);
+ pEHClause._tryEndOffset = (tryLengthAndKind >> 2) + pEHClause._tryStartOffset;
+ switch (pEHClause._clauseKind)
+ {
+ case RhEHClauseKindWasm.RH_EH_CLAUSE_TYPED:
+
+ AlignToSymbol();
+ pEHClause._typeSymbol = ReadUInt32(ref _currentPtr);
+ pEHClause._handlerAddress = (byte *)ReadUInt32(ref _currentPtr);
+ break;
+ case RhEHClauseKindWasm.RH_EH_CLAUSE_FAULT:
+ AlignToSymbol();
+ pEHClause._handlerAddress = (byte*)ReadUInt32(ref _currentPtr);
+ break;
+ case RhEHClauseKindWasm.RH_EH_CLAUSE_FILTER:
+ AlignToSymbol();
+ pEHClause._handlerAddress = (byte*)ReadUInt32(ref _currentPtr);
+ pEHClause._filterAddress = (byte*)ReadUInt32(ref _currentPtr);
+ break;
+ }
+ return true;
+ }
+
+ private void AlignToSymbol()
+ {
+ _currentPtr = (byte *)(((uint)_currentPtr + 3) & ~(3));
+ }
+ }
+}
diff --git a/src/coreclr/src/nativeaot/Runtime/Portable/CMakeLists.txt b/src/coreclr/src/nativeaot/Runtime/Portable/CMakeLists.txt
index e1f09ed4127c..d7883ff4b961 100644
--- a/src/coreclr/src/nativeaot/Runtime/Portable/CMakeLists.txt
+++ b/src/coreclr/src/nativeaot/Runtime/Portable/CMakeLists.txt
@@ -17,7 +17,7 @@ if(WIN32)
set(ASM_OFFSETS_CPP ${RUNTIME_DIR}/windows/AsmOffsets.cpp)
else()
set(COMPILER_LANGUAGE -x c++)
- set(PREPROCESSOR_FLAGS -E -P)
+ set(PREPROCESSOR_FLAGS -E -P -C) # include license for code cop
set(ASM_OFFSETS_CPP ${RUNTIME_DIR}/unix/AsmOffsets.cpp)
endif()
diff --git a/src/coreclr/src/nativeaot/Runtime/wasm/AsmOffsetsCpu.h b/src/coreclr/src/nativeaot/Runtime/wasm/AsmOffsetsCpu.h
new file mode 100644
index 000000000000..23976f026fed
--- /dev/null
+++ b/src/coreclr/src/nativeaot/Runtime/wasm/AsmOffsetsCpu.h
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//
+// This file is used by AsmOffsets.h to validate that our
+// assembly-code offsets always match their C++ counterparts.
+//
+// NOTE: the offsets MUST be in hex notation WITHOUT the 0x prefix
+
+PLAT_ASM_SIZEOF(a4, ExInfo)
+PLAT_ASM_OFFSET(0, ExInfo, m_pPrevExInfo)
+PLAT_ASM_OFFSET(4, ExInfo, m_pExContext)
+PLAT_ASM_OFFSET(8, ExInfo, m_exception)
+PLAT_ASM_OFFSET(0c, ExInfo, m_kind)
+PLAT_ASM_OFFSET(0d, ExInfo, m_passNumber)
+PLAT_ASM_OFFSET(10, ExInfo, m_idxCurClause)
+PLAT_ASM_OFFSET(14, ExInfo, m_frameIter)
+PLAT_ASM_OFFSET(a0, ExInfo, m_notifyDebuggerSP)
+
+PLAT_ASM_SIZEOF(8c, StackFrameIterator)
+PLAT_ASM_OFFSET(08, StackFrameIterator, m_FramePointer)
+PLAT_ASM_OFFSET(0c, StackFrameIterator, m_ControlPC)
+PLAT_ASM_OFFSET(10, StackFrameIterator, m_RegDisplay)
+PLAT_ASM_OFFSET(88, StackFrameIterator, m_OriginalControlPC)
+
+PLAT_ASM_SIZEOF(4, PAL_LIMITED_CONTEXT)
+PLAT_ASM_OFFSET(0, PAL_LIMITED_CONTEXT, IP)
+
+PLAT_ASM_SIZEOF(0c, REGDISPLAY)
+PLAT_ASM_OFFSET(0, REGDISPLAY, SP)
diff --git a/src/coreclr/src/nativeaot/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/src/nativeaot/System.Private.CoreLib/System.Private.CoreLib.csproj
index 42024ce857b1..14379be924c6 100644
--- a/src/coreclr/src/nativeaot/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/src/nativeaot/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -26,16 +26,20 @@
false
- true
+ true
false
- true
+ true
true
true
+
+ TARGET_UNIX;TARGET_WASM;TARGET_32BIT;FEATURE_64BIT_ALIGNMENT;$(DefineConstants)
+ llvm
+
@@ -168,7 +172,7 @@
-
+
@@ -181,6 +185,7 @@
+
@@ -224,6 +229,7 @@
+
@@ -323,7 +329,7 @@
Interop\Windows\Kernel32\Interop.GetLastError.cs
-
+
@@ -469,9 +475,17 @@
Common\TransitionBlock.cs
+
+ Runtime.Base\src\System\Runtime\ExceptionHandling.wasm.cs
+
+
+ Runtime.Base\src\System\Runtime\StackFrameIterator.wasm.cs
+
-
+
+
+
diff --git a/src/coreclr/src/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackTrace.CoreRT.Wasm.cs b/src/coreclr/src/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackTrace.CoreRT.Wasm.cs
new file mode 100644
index 000000000000..1537709b6d91
--- /dev/null
+++ b/src/coreclr/src/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackTrace.CoreRT.Wasm.cs
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace System.Diagnostics
+{
+ public partial class StackTrace
+ {
+ private readonly StringBuilder _builder = new StringBuilder();
+
+ [DllImport("*")]
+ static unsafe extern int emscripten_get_callstack(int flags, byte* outBuf, int maxBytes);
+
+ private unsafe void InitializeForCurrentThread(int skipFrames, bool needFileInfo)
+ {
+ var backtraceBuffer = new byte[8192];
+ int callstackLen;
+ // skip these 2:
+ // at S_P_CoreLib_System_Diagnostics_StackTrace__InitializeForCurrentThread (wasm-function[12314]:275)
+ // at S_P_CoreLib_System_Diagnostics_StackTrace___ctor_0(wasm-function[12724]:118)
+ skipFrames += 2; // METHODS_TO_SKIP is a constant so just change here
+
+ fixed (byte* curChar = backtraceBuffer)
+ {
+ callstackLen = emscripten_get_callstack(8 /* original source stack if source maps available, not tested */, curChar, backtraceBuffer.Length);
+ }
+ int _numOfFrames = 1;
+ int lineStartIx = 0;
+ int ix = 0;
+ for (; ix < callstackLen; ix++)
+ {
+ if (backtraceBuffer[ix] == '\n')
+ {
+ if (_numOfFrames > skipFrames)
+ {
+ _builder.Append(Encoding.Default.GetString(backtraceBuffer, lineStartIx, ix - lineStartIx + 1));
+ }
+ _numOfFrames++;
+ lineStartIx = ix + 1;
+ }
+ }
+ if (lineStartIx < ix)
+ {
+ _builder.AppendLine(Encoding.Default.GetString(backtraceBuffer, lineStartIx, ix - lineStartIx));
+ }
+ _methodsToSkip = 0;
+ }
+
+
+ internal string ToString(TraceFormat traceFormat)
+ {
+ var stackTraceString = _builder.ToString();
+ if (traceFormat == TraceFormat.Normal && stackTraceString.EndsWith(Environment.NewLine))
+ return stackTraceString.Substring(0, stackTraceString.Length - Environment.NewLine.Length);
+
+ return stackTraceString;
+ }
+ }
+}
diff --git a/src/coreclr/src/nativeaot/System.Private.CoreLib/src/System/Exception.CoreRT.LLVM.cs b/src/coreclr/src/nativeaot/System.Private.CoreLib/src/System/Exception.CoreRT.LLVM.cs
new file mode 100644
index 000000000000..345c91a44e55
--- /dev/null
+++ b/src/coreclr/src/nativeaot/System.Private.CoreLib/src/System/Exception.CoreRT.LLVM.cs
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace System
+{
+ public partial class Exception
+ {
+ [DllImport("*")]
+ internal static extern void RhpThrowEx(object exception);
+
+ private static void DispatchExLLVM(object exception)
+ {
+ AppendExceptionStackFrameLLVM(exception, new StackTrace(1).ToString());
+ //RhpThrowEx(exception); can't as not handling the transition unmanaged->managed in the landing pads.
+ }
+
+ private static void AppendExceptionStackFrameLLVM(object exceptionObj, string stackTraceString)
+ {
+ // This method is called by the runtime's EH dispatch code and is not allowed to leak exceptions
+ // back into the dispatcher.
+ try
+ {
+ Exception ex = exceptionObj as Exception;
+ if (ex == null)
+ Environment.FailFast("Exceptions must derive from the System.Exception class");
+
+ if (!RuntimeExceptionHelpers.SafeToPerformRichExceptionSupport)
+ return;
+
+ ex._stackTraceString = stackTraceString.Replace("__", ".").Replace("_", ".");
+ }
+ catch
+ {
+ // We may end up with a confusing stack trace or a confusing ETW trace log, but at least we
+ // can continue to dispatch this exception.
+ }
+ }
+ }
+}
diff --git a/src/coreclr/src/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/CallConverterThunk.cs b/src/coreclr/src/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/CallConverterThunk.cs
index 093c764aaf2f..8817da165012 100644
--- a/src/coreclr/src/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/CallConverterThunk.cs
+++ b/src/coreclr/src/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/CallConverterThunk.cs
@@ -102,7 +102,9 @@ private static extern unsafe void CallingConventionConverter_GetStubs(out IntPtr
out IntPtr commonStub
#if CALLDESCR_FPARGREGSARERETURNREGS
#else
+#pragma warning disable SA1001,SA1115,SA1113
, out IntPtr returnFloatingPointReturn4Thunk,
+#pragma warning restore SA10011,SA1115,SA1113
out IntPtr returnFloatingPointReturn8Thunk
#endif
);
diff --git a/src/coreclr/src/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj b/src/coreclr/src/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj
index c8badf6365bd..7324dfcd6d69 100644
--- a/src/coreclr/src/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj
+++ b/src/coreclr/src/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj
@@ -19,6 +19,9 @@
$(CompilerCommonPath)\Internal\NativeFormat
+
+ TARGET_UNIX;TARGET_WASM;TARGET_32BIT;$(DefineConstants)
+
diff --git a/src/coreclr/src/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj b/src/coreclr/src/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj
index ffb31c08312b..6e315e602c6c 100644
--- a/src/coreclr/src/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj
+++ b/src/coreclr/src/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj
@@ -12,9 +12,11 @@
FEATURE_64BIT_ALIGNMENT;$(DefineConstants)
-
- FEATURE_64BIT_ALIGNMENT;$(DefineConstants)
+
+ TARGET_WASM;TARGET_32BIT;FEATURE_64BIT_ALIGNMENT;$(DefineConstants)
+ llvm
+
true
@@ -72,7 +74,8 @@
-
+
+
diff --git a/src/coreclr/src/tools/aot/ILCompiler.LLVM/CodeGen/DebugMetadata.cs b/src/coreclr/src/tools/aot/ILCompiler.LLVM/CodeGen/DebugMetadata.cs
new file mode 100644
index 000000000000..29b66e8a0484
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.LLVM/CodeGen/DebugMetadata.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using LLVMSharp.Interop;
+
+namespace ILCompiler.LLVM
+{
+ class DebugMetadata
+ {
+ public DebugMetadata(LLVMMetadataRef file, LLVMMetadataRef compileUnit)
+ {
+ File = file;
+ CompileUnit = compileUnit;
+ }
+
+ public LLVMMetadataRef CompileUnit { get; }
+ public LLVMMetadataRef File { get; }
+ }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.LLVM/CodeGen/EvaluationStack.cs b/src/coreclr/src/tools/aot/ILCompiler.LLVM/CodeGen/EvaluationStack.cs
new file mode 100644
index 000000000000..685622d2fcb7
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.LLVM/CodeGen/EvaluationStack.cs
@@ -0,0 +1,596 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Diagnostics;
+using Internal.TypeSystem;
+using LLVMSharp.Interop;
+
+namespace Internal.IL
+{
+ ///
+ /// Abstraction of a variable size last-in-first-out (LIFO) collection of instances of the same specified type
+ /// implemented via an array.
+ ///
+ /// Type of elements in the stack.
+ internal class EvaluationStack
+ {
+ ///
+ /// Initializes a new instance of the stack that is empty and has the specified initial capacity .
+ ///
+ /// Initial number of elements that the stack can contain.
+ public EvaluationStack(int n)
+ {
+ Debug.Assert(n >= 0, "Count should be non-negative");
+
+ _stack = n > 0 ? new T[n] : s_emptyStack;
+ _top = 0;
+
+ Debug.Assert(n == _stack.Length, "Stack length does not match requested capacity");
+ Debug.Assert(_top == 0, "Top of stack is at bottom");
+ }
+
+ ///
+ /// Value for all stacks of length 0.
+ ///
+ private static readonly T[] s_emptyStack = new T[0];
+
+ ///
+ /// Storage for current stack.
+ ///
+ private T[] _stack;
+
+ ///
+ /// Position in where next element will be pushed.
+ ///
+ private int _top;
+
+ ///
+ /// Position in stack where next element will be pushed.
+ ///
+ public int Top
+ {
+ get { return _top; }
+ }
+
+ ///
+ /// Number of elements contained in the stack.
+ ///
+ public int Length
+ {
+ get { return _top; }
+ }
+
+ ///
+ /// Push at the top of the stack.
+ ///
+ /// Element to push onto the stack.
+ public void Push(T value)
+ {
+ if (_top >= _stack.Length)
+ {
+ Array.Resize(ref _stack, 2 * _top + 3);
+ }
+ _stack[_top++] = value;
+ }
+
+ ///
+ /// Insert at position in current stack, shifting all
+ /// elements after or at by one.
+ ///
+ /// Element to insert
+ /// Position where to insert
+ public void InsertAt(T v, int pos)
+ {
+ Debug.Assert(pos <= _top, "Invalid insertion point");
+
+ if (_top >= _stack.Length)
+ {
+ Array.Resize(ref _stack, 2 * _top + 3);
+ }
+ for (int i = _top - 1; i >= pos; i--)
+ {
+ _stack[i + 1] = _stack[i];
+ }
+ _top++;
+ _stack[pos] = v;
+ }
+
+ ///
+ /// Access and set
+ ///
+ ///
+ ///
+ public T this[int index]
+ {
+ get
+ {
+ Debug.Assert(index >= 0 && index < _top, "Index not in range");
+ return _stack[index];
+ }
+ set
+ {
+ Debug.Assert(index >= 0 && index < _top, "Index not in range");
+ _stack[index] = value;
+ }
+ }
+
+ ///
+ /// Return element of the top of the stack.
+ ///
+ /// Element at the top of the stack
+ public T Peek()
+ {
+ if (_top <= 0)
+ {
+ ThrowHelper.ThrowInvalidProgramException();
+ }
+
+ return _stack[_top - 1];
+ }
+
+ ///
+ /// Remove top element from stack and return it.
+ ///
+ /// Element formerly at the top of the stack
+ public T Pop()
+ {
+ if (_top <= 0)
+ {
+ ThrowHelper.ThrowInvalidProgramException();
+ }
+
+ return _stack[--_top];
+ }
+
+ ///
+ /// Remove elements from the stack.
+ ///
+ /// Number of elements to remove from the stack
+ public void PopN(int n)
+ {
+ Debug.Assert(n <= _top, "Too many elements to remove");
+ _top -= n;
+ }
+
+ ///
+ /// Remove all elements from the stack.
+ ///
+ public void Clear()
+ {
+ _top = 0;
+ }
+ }
+
+ ///
+ /// Abstract representation of a stack entry
+ ///
+ internal abstract class StackEntry
+ {
+ ///
+ /// Evaluation stack kind of the entry.
+ ///
+ public StackValueKind Kind { get; }
+
+ ///
+ /// Managed type if any of the entry.
+ ///
+ public TypeDesc Type { get; }
+
+ public LLVMValueRef ValueAsType(LLVMTypeRef type, LLVMBuilderRef builder)
+ {
+ return ValueAsTypeInternal(type, builder, Type != null && (Type.IsWellKnownType(WellKnownType.SByte) || Type.IsWellKnownType(WellKnownType.Int16)));
+ }
+
+ public LLVMValueRef ValueAsType(TypeDesc type, LLVMBuilderRef builder)
+ {
+ return ValueAsType(ILImporter.GetLLVMTypeForTypeDesc(type), builder);
+ }
+
+ public LLVMValueRef ValueForStackKind(StackValueKind kind, LLVMBuilderRef builder, bool signExtend)
+ {
+ if (kind == StackValueKind.Int32)
+ return ValueAsInt32(builder, signExtend);
+ else if (kind == StackValueKind.Int64)
+ return ValueAsInt64(builder, signExtend);
+ else if (kind == StackValueKind.Float)
+ return ValueAsType(Type.IsWellKnownType(WellKnownType.Single) ? ILImporter.Context.FloatType : ILImporter.Context.DoubleType, builder);
+ else if (kind == StackValueKind.NativeInt || kind == StackValueKind.ByRef || kind == StackValueKind.ObjRef)
+ return ValueAsInt32(builder, false);
+ else
+ throw new NotImplementedException();
+ }
+
+ public LLVMValueRef ValueAsInt32(LLVMBuilderRef builder, bool signExtend)
+ {
+ return ValueAsTypeInternal(ILImporter.Context.Int32Type, builder, signExtend);
+ }
+
+ public LLVMValueRef ValueAsInt64(LLVMBuilderRef builder, bool signExtend)
+ {
+ return ValueAsTypeInternal(ILImporter.Context.Int64Type, builder, signExtend);
+ }
+
+ protected abstract LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend);
+
+ ///
+ /// Initializes a new instance of StackEntry.
+ ///
+ /// Kind of entry.
+ /// Type if any of entry.
+ protected StackEntry(StackValueKind kind, TypeDesc type = null)
+ {
+ Kind = kind;
+ Type = type;
+ }
+
+ ///
+ /// Add representation of current entry in .
+ ///
+ /// Generation buffer used for appending new content.
+ //public abstract void Append(CppGenerationBuffer builder);
+
+ ///
+ /// Create a new copy of current entry.
+ ///
+ /// A new instance of the same type as the current entry.
+ public abstract StackEntry Duplicate(LLVMBuilderRef builder);
+ }
+
+ ///
+ /// Abstract entry for all constant values.
+ ///
+ internal abstract class ConstantEntry : StackEntry
+ {
+ protected ConstantEntry(StackValueKind kind, TypeDesc type = null) : base(kind, type)
+ {
+ }
+
+ ///
+ /// Does current entry require a cast to be assigned to ?
+ ///
+ /// Type of destination
+ /// True if a cast is required
+ public virtual bool IsCastNecessary(TypeDesc destType)
+ {
+ return false;
+ }
+ }
+
+ internal abstract class ConstantEntry : ConstantEntry where T : IConvertible
+ {
+ public T Value { get; }
+
+ protected ConstantEntry(StackValueKind kind, T value, TypeDesc type = null) : base(kind, type)
+ {
+ Value = value;
+ }
+ }
+
+ internal class Int32ConstantEntry : ConstantEntry
+ {
+ public Int32ConstantEntry(int value, TypeDesc type = null) : base(StackValueKind.Int32, value, type)
+ {
+ }
+
+ protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
+ {
+ if (type.Kind == LLVMTypeKind.LLVMPointerTypeKind && Value == 0)
+ {
+ return LLVMValueRef.CreateConstPointerNull(type);
+ }
+ else if (type.Kind == LLVMTypeKind.LLVMPointerTypeKind && Value != 0)
+ {
+ return LLVMValueRef.CreateConstIntToPtr(LLVMValueRef.CreateConstInt(ILImporter.Context.Int32Type, (ulong)Value), type);
+ }
+ else if (type.Kind != LLVMTypeKind.LLVMIntegerTypeKind)
+ {
+ throw new NotImplementedException();
+ }
+ else
+ {
+ return LLVMValueRef.CreateConstInt(type, (ulong)Value);
+ }
+ }
+
+ public override StackEntry Duplicate(LLVMBuilderRef builder)
+ {
+ return new Int32ConstantEntry(Value, Type);
+ }
+
+ public override bool IsCastNecessary(TypeDesc destType)
+ {
+ switch (destType.UnderlyingType.Category)
+ {
+ case TypeFlags.SByte:
+ return Value >= sbyte.MaxValue || Value <= sbyte.MinValue;
+ case TypeFlags.Byte:
+ case TypeFlags.Boolean:
+ return Value >= byte.MaxValue || Value < 0;
+ case TypeFlags.Int16:
+ return Value >= short.MaxValue || Value <= short.MinValue;
+ case TypeFlags.UInt16:
+ case TypeFlags.Char:
+ return Value >= ushort.MaxValue || Value < 0;
+ case TypeFlags.Int32:
+ return false;
+ case TypeFlags.UInt32:
+ return Value < 0;
+ default:
+ return true;
+ }
+ }
+ }
+
+ internal class Int64ConstantEntry : ConstantEntry
+ {
+ public Int64ConstantEntry(long value, TypeDesc type = null) : base(StackValueKind.Int64, value, type)
+ {
+ }
+
+ public override StackEntry Duplicate(LLVMBuilderRef builder)
+ {
+ return new Int64ConstantEntry(Value, Type);
+ }
+
+ protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
+ {
+ if (type.Kind == LLVMTypeKind.LLVMPointerTypeKind && Value == 0)
+ {
+ return LLVMValueRef.CreateConstPointerNull(type);
+ }
+ else if (type.Kind == LLVMTypeKind.LLVMPointerTypeKind && Value != 0)
+ {
+ return LLVMValueRef.CreateConstIntToPtr(LLVMValueRef.CreateConstInt(ILImporter.Context.Int64Type, (ulong)Value), type);
+ }
+ else if (type.Kind != LLVMTypeKind.LLVMIntegerTypeKind)
+ {
+ throw new NotImplementedException();
+ }
+ else
+ {
+ return LLVMValueRef.CreateConstInt(type, (ulong)Value);
+ }
+ }
+
+ public override bool IsCastNecessary(TypeDesc destType)
+ {
+ switch (destType.UnderlyingType.Category)
+ {
+ case TypeFlags.SByte:
+ return Value >= sbyte.MaxValue || Value <= sbyte.MinValue;
+ case TypeFlags.Byte:
+ case TypeFlags.Boolean:
+ return Value >= byte.MaxValue || Value < 0;
+ case TypeFlags.Int16:
+ return Value >= short.MaxValue || Value <= short.MinValue;
+ case TypeFlags.UInt16:
+ case TypeFlags.Char:
+ return Value >= ushort.MaxValue || Value < 0;
+ case TypeFlags.Int32:
+ return Value >= int.MaxValue || Value <= int.MinValue;
+ case TypeFlags.UInt32:
+ return Value >= uint.MaxValue || Value < 0;
+ case TypeFlags.Int64:
+ return false;
+ case TypeFlags.UInt64:
+ return Value < 0;
+ default:
+ return true;
+ }
+ }
+ }
+
+ internal class FloatConstantEntry : ConstantEntry
+ {
+ public FloatConstantEntry(double value, TypeDesc type = null) : base(StackValueKind.Float, value, type)
+ {
+ }
+
+ protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
+ {
+ return LLVMValueRef.CreateConstReal(type, Value);
+ }
+
+ public override StackEntry Duplicate(LLVMBuilderRef builder)
+ {
+ return new FloatConstantEntry(Value, Type);
+ }
+ }
+
+ ///
+ /// Entry representing some expression
+ ///
+ internal class ExpressionEntry : StackEntry
+ {
+ ///
+ /// String representation of current expression
+ ///
+ public string Name { get; set; }
+ public LLVMValueRef RawLLVMValue { get; set; }
+ ///
+ /// Initializes new instance of ExpressionEntry
+ ///
+ /// Kind of entry
+ /// String representation of entry
+ /// Type if any of entry
+ public ExpressionEntry(StackValueKind kind, string name, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, type)
+ {
+ Name = name;
+ RawLLVMValue = llvmValue;
+ }
+
+ public override StackEntry Duplicate(LLVMBuilderRef builder)
+ {
+ return new ExpressionEntry(Kind, Name, RawLLVMValue, Type);
+ }
+
+ protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
+ {
+ if (type.IsPackedStruct && type.Handle != RawLLVMValue.TypeOf.Handle)
+ {
+ var destStruct = type.Undef;
+ for (uint elemNo = 0; elemNo < RawLLVMValue.TypeOf.StructElementTypesCount; elemNo++)
+ {
+ var elemValRef = builder.BuildExtractValue(RawLLVMValue, 0, "ex" + elemNo);
+ destStruct = builder.BuildInsertValue(destStruct, elemValRef, elemNo, "st" + elemNo);
+ }
+ return destStruct;
+ }
+ return ILImporter.CastIfNecessary(builder, RawLLVMValue, type, Name, !signExtend);
+ }
+ }
+
+ internal class LoadExpressionEntry : ExpressionEntry
+ {
+ ///
+ /// Initializes new instance of ExpressionEntry
+ ///
+ /// Kind of entry
+ /// String representation of entry
+ /// Type if any of entry
+ public LoadExpressionEntry(StackValueKind kind, string name, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, name, llvmValue, type)
+ {
+ }
+
+ public override StackEntry Duplicate(LLVMBuilderRef builder)
+ {
+ return new ExpressionEntry(Kind, "duplicate_" + Name, ILImporter.LoadValue(builder, RawLLVMValue, Type, ILImporter.GetLLVMTypeForTypeDesc(Type), false, "load_duplicate_" + Name), Type);
+ }
+
+ protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
+ {
+ return ILImporter.LoadValue(builder, RawLLVMValue, Type, type, signExtend, $"Load{Name}");
+ }
+ }
+
+ internal class AddressExpressionEntry : ExpressionEntry
+ {
+ ///
+ /// Initializes new instance of ExpressionEntry
+ ///
+ /// Kind of entry
+ /// String representation of entry
+ /// Type if any of entry
+ public AddressExpressionEntry(StackValueKind kind, string name, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, name, llvmValue, type)
+ {
+ }
+
+ public override StackEntry Duplicate(LLVMBuilderRef builder)
+ {
+ return new AddressExpressionEntry(Kind, Name, RawLLVMValue, Type);
+ }
+
+ protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
+ {
+ return ILImporter.CastIfNecessary(builder, RawLLVMValue, type, Name);
+ }
+ }
+
+ ///
+ /// Represents the result of a ldftn or ldvirtftn
+ ///
+ internal class FunctionPointerEntry : ExpressionEntry
+ {
+ ///
+ /// True if the function pointer was loaded as a virtual function pointer
+ ///
+ public bool IsVirtual { get; }
+
+ public MethodDesc Method { get; }
+
+ public FunctionPointerEntry(string name, MethodDesc method, LLVMValueRef llvmValue, TypeDesc type, bool isVirtual) : base(StackValueKind.NativeInt, name, llvmValue, type)
+ {
+ Method = method;
+ IsVirtual = isVirtual;
+ }
+
+ public override StackEntry Duplicate(LLVMBuilderRef builder)
+ {
+ return new FunctionPointerEntry(Name, Method, RawLLVMValue, Type, IsVirtual);
+ }
+ }
+
+ ///
+ /// Entry representing some token (either of TypeDesc, MethodDesc or FieldDesc) along with its string representation
+ ///
+ internal class LdTokenEntry : ExpressionEntry
+ {
+ public T LdToken { get; }
+
+ public LdTokenEntry(StackValueKind kind, string name, T token, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, name, llvmValue, type)
+ {
+ LdToken = token;
+ }
+
+ public override StackEntry Duplicate(LLVMBuilderRef builder)
+ {
+ return new LdTokenEntry(Kind, Name, LdToken, RawLLVMValue, Type);
+ }
+
+ protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
+ {
+ if (RawLLVMValue.Handle == IntPtr.Zero)
+ throw new NullReferenceException();
+
+ return ILImporter.CastIfNecessary(builder, RawLLVMValue, type, Name);
+ }
+ }
+
+ internal class InvalidEntry : StackEntry
+ {
+ ///
+ /// Entry to use to get an instance of InvalidEntry.
+ ///
+ public static InvalidEntry Entry = new InvalidEntry();
+
+ protected InvalidEntry() : base(StackValueKind.Unknown, null)
+ {
+ }
+
+ public override StackEntry Duplicate(LLVMBuilderRef builder)
+ {
+ return this;
+ }
+
+ protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
+ {
+ throw new InvalidOperationException();
+ }
+ }
+
+ ///
+ /// Entry representing a writable sharable stack entry that can survive from one basic block to another
+ ///
+ internal class SpilledExpressionEntry : ExpressionEntry
+ {
+ public int LocalIndex;
+ private ILImporter _importer;
+ public SpilledExpressionEntry(StackValueKind kind, string name, TypeDesc type, int localIndex, ILImporter importer) : base(kind, name, new LLVMValueRef(IntPtr.Zero), type)
+ {
+ LocalIndex = localIndex;
+ _importer = importer;
+ }
+
+ protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
+ {
+ LLVMTypeRef origLLVMType = ILImporter.GetLLVMTypeForTypeDesc(Type);
+ LLVMValueRef value = _importer.LoadTemp(LocalIndex, origLLVMType);
+
+ return ILImporter.CastIfNecessary(builder, value, type, unsigned: !signExtend);
+ }
+
+ public override StackEntry Duplicate(LLVMBuilderRef builder)
+ {
+ return new SpilledExpressionEntry(Kind, Name, Type, LocalIndex, _importer);
+ }
+ }
+
+ internal static class StackEntryExtensions
+ {
+ public static string Name(this StackEntry entry)
+ {
+ return (entry as ExpressionEntry)?.Name;
+ }
+ }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.LLVM/CodeGen/ILToLLVMImporter.cs b/src/coreclr/src/tools/aot/ILCompiler.LLVM/CodeGen/ILToLLVMImporter.cs
new file mode 100644
index 000000000000..816b800622b3
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.LLVM/CodeGen/ILToLLVMImporter.cs
@@ -0,0 +1,5648 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using Internal.TypeSystem;
+using ILCompiler;
+using LLVMSharp.Interop;
+using ILCompiler.Compiler.DependencyAnalysis;
+using ILCompiler.DependencyAnalysis;
+using ILCompiler.LLVM;
+using Internal.IL.Stubs;
+using Internal.TypeSystem.Ecma;
+
+namespace Internal.IL
+{
+ // Implements an IL scanner that scans method bodies to be compiled by the code generation
+ // backend before the actual compilation happens to gain insights into the code.
+ partial class ILImporter
+ {
+ public enum LocalVarKind
+ {
+ Argument,
+ Local,
+ Temp
+ }
+
+ private class ExceptionRegion
+ {
+ public ILExceptionRegion ILRegion;
+ }
+
+ ArrayBuilder
diff --git a/src/libraries/Native/Unix/System.Globalization.Native/CMakeLists.txt b/src/libraries/Native/Unix/System.Globalization.Native/CMakeLists.txt
index 834a86ec1cca..b124f49f7975 100644
--- a/src/libraries/Native/Unix/System.Globalization.Native/CMakeLists.txt
+++ b/src/libraries/Native/Unix/System.Globalization.Native/CMakeLists.txt
@@ -13,7 +13,11 @@ if(CLR_CMAKE_TARGET_UNIX)
add_compile_options(-Wno-extra-semi-stmt)
add_compile_options(-Wno-unknown-warning-option)
- if (NOT CLR_CMAKE_TARGET_ANDROID)
+ if (CLR_CMAKE_TARGET_UNIX_WASM)
+ message("including ICU")
+ # add ICU support to emscripten and workaround https://github.com/emscripten-core/emscripten/issues/9302
+ add_compile_options(-s USE_ICU=1 -I$ENV{EMSDK}/upstream/emscripten/cache/ports/icu/icu/source/i18n)
+ elseif (NOT CLR_CMAKE_TARGET_ANDROID)
set(ICU_HOMEBREW_INC_PATH "/usr/local/opt/icu4c/include")
find_path(UTYPES_H "unicode/utypes.h" PATHS ${ICU_HOMEBREW_INC_PATH})
diff --git a/src/libraries/Native/build-native.cmd b/src/libraries/Native/build-native.cmd
index e96af68eb5a1..8568899162a3 100644
--- a/src/libraries/Native/build-native.cmd
+++ b/src/libraries/Native/build-native.cmd
@@ -97,7 +97,7 @@ goto :SetupDirs
echo Commencing build of native components
echo.
-if /i "%__BuildArch%" == "wasm" set __sourceDir=%~dp0..\Unix
+if /i "%__BuildArch%" == "wasm" set __sourceDir=%~dp0\Unix
if [%__outConfig%] == [] set __outConfig=%__TargetOS%-%__BuildArch%-%CMAKE_BUILD_TYPE%
@@ -158,7 +158,7 @@ set __generatorArgs=
if [%__Ninja%] == [1] (
set __generatorArgs=
) else if [%__BuildArch%] == [wasm] (
- set __generatorArgs=-j
+ set __generatorArgs=
) else (
set __generatorArgs=/p:Platform=%__BuildArch% /p:PlatformToolset="%__PlatformToolset%" -noWarn:MSB8065
)
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 5d9e31260a20..8b7c80c27910 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -52,7 +52,6 @@
-