Skip to content

Commit

Permalink
Add experimental NativeAOT-LLVM support
Browse files Browse the repository at this point in the history
  • Loading branch information
RReverser committed Jan 10, 2024
1 parent 4b6fc68 commit c915a9f
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 24 deletions.
31 changes: 24 additions & 7 deletions crates/bindings-csharp/Codegen/Module.cs
Expand Up @@ -286,26 +286,43 @@ class {r.Name}: IReducer {{
// <auto-generated />
#nullable enable
using static SpacetimeDB.RawBindings;
using SpacetimeDB.Module;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static SpacetimeDB.Runtime;
using System.Diagnostics.CodeAnalysis;
static class ModuleRegistration {{
{string.Join("\n", addReducers.Select(r => r.Class))}
#pragma warning disable CA2255
// [ModuleInitializer] - doesn't work because assemblies are loaded lazily;
// might make use of it later down the line, but for now assume there is only one
// module so we can use `Main` instead.
#if EXPERIMENTAL_WASM_AOT
// In AOT mode we're building a library.
// Main method won't be called automatically, so we need to export it as a preinit function.
[UnmanagedCallersOnly(EntryPoint = ""__preinit__10_init_csharp"")]
#else
// Prevent trimming of FFI exports that are invoked from C and not visible to C# trimmer.
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(SpacetimeDB.Module.FFI))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(FFI))]
#endif
public static void Main() {{
{string.Join("\n", addReducers.Select(r => $"FFI.RegisterReducer(new {r.Name}());"))}
{string.Join("\n", tableNames.Select(t => $"FFI.RegisterTable({t}.MakeTableDesc());"))}
}}
#pragma warning restore CA2255
// Exports only work from the main assembly, so we need to generate forwarding methods.
#if EXPERIMENTAL_WASM_AOT
[UnmanagedCallersOnly(EntryPoint = ""__describe_module__"")]
public static Buffer __describe_module__() => FFI.__describe_module__();
[UnmanagedCallersOnly(EntryPoint = ""__call_reducer__"")]
public static Buffer __call_reducer__(
uint id,
Buffer caller_identity,
Buffer caller_address,
ulong timestamp,
Buffer args
) => FFI.__call_reducer__(id, caller_identity, caller_address, timestamp, args);
#endif
}}
"
);
Expand Down
2 changes: 0 additions & 2 deletions crates/bindings-csharp/Runtime/Module.cs
Expand Up @@ -276,7 +276,6 @@ public static void RegisterReducer(IReducer reducer)
bool anonymous = false
) => module.SetTypeRef<T>(typeRef, type, anonymous);

// [UnmanagedCallersOnly(EntryPoint = "__describe_module__")]
public static RawBindings.Buffer __describe_module__()
{
// replace `module` with a temporary internal module that will register ModuleDef, AlgebraicType and other internal types
Expand Down Expand Up @@ -308,7 +307,6 @@ private static byte[] Consume(this RawBindings.Buffer buffer)
return result;
}

// [UnmanagedCallersOnly(EntryPoint = "__call_reducer__")]
public static RawBindings.Buffer __call_reducer__(
uint id,
RawBindings.Buffer caller_identity,
Expand Down
8 changes: 7 additions & 1 deletion crates/bindings-csharp/Runtime/RawBindings.cs
Expand Up @@ -12,7 +12,13 @@ public static partial class RawBindings
// For now this must match the name of the `.c` file (`bindings.c`).
// In the future C# will allow to specify Wasm import namespace in
// `LibraryImport` directly.
const string StdbNamespace = "bindings";
const string StdbNamespace =
#if EXPERIMENTAL_WASM_AOT
"spacetime_7.0"
#else
"bindings"
#endif
;

// This custom marshaller takes care of checking the status code
// returned from the host and throwing an exception if it's not 0.
Expand Down
9 changes: 6 additions & 3 deletions crates/bindings-csharp/Runtime/bindings.c
@@ -1,3 +1,4 @@
#ifndef EXPERIMENTAL_WASM_AOT
#include <assert.h>
// #include <mono/metadata/appdomain.h>
// #include <mono/metadata/object.h>
Expand Down Expand Up @@ -111,6 +112,7 @@ EXPORT(Buffer, __call_reducer__,
(uint32_t id, Buffer caller_identity, Buffer caller_address,
uint64_t timestamp, Buffer args),
&id, &caller_identity, &caller_address, &timestamp, &args);
#endif

// Shims to avoid dependency on WASI in the generated Wasm file.

Expand Down Expand Up @@ -208,9 +210,10 @@ int32_t WASI_NAME(fd_write)(__wasi_fd_t fd, const __wasi_ciovec_t* iovs,
// Note: this will produce ugly broken output, but there's not much we can
// do about it until we have proper line-buffered WASI writer in the core.
// It's better than nothing though.
_console_log_imp((LogLevel){fd == STDERR_FILENO ? /*WARN*/ 1 : /*INFO*/ 2},
CSTR("wasi"), CSTR(__FILE__), __LINE__, iovs[i].buf,
iovs[i].buf_len);
// _console_log_imp((LogLevel){fd == STDERR_FILENO ? /*WARN*/ 1 : /*INFO*/
// 2},
// CSTR("wasi"), CSTR(__FILE__), __LINE__, iovs[i].buf,
// iovs[i].buf_len);
*retptr0 += iovs[i].buf_len;
}
return 0;
Expand Down
18 changes: 17 additions & 1 deletion crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.props
Expand Up @@ -4,10 +4,26 @@
<WasmSingleFileBundle>true</WasmSingleFileBundle>
<TrimMode>full</TrimMode>
<InvariantGlobalization>true</InvariantGlobalization>
<DebuggerSupport>false</DebuggerSupport>
<EventSourceSupport>false</EventSourceSupport>
<UseSystemResourceKeys>true</UseSystemResourceKeys>
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup>

<PropertyGroup Condition="'$(EXPERIMENTAL_WASM_AOT)' == '1'">
<OutputType>Library</OutputType>
<NativeLib>Shared</NativeLib>
<DefineConstants>$(DefineConstants);EXPERIMENTAL_WASM_AOT</DefineConstants>
<MSBuildEnableWorkloadResolver>false</MSBuildEnableWorkloadResolver>
<UseAppHost>false</UseAppHost>
<SpacetimeNamespace>spacetime_7.0</SpacetimeNamespace>
<RestoreAdditionalProjectSources>https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json</RestoreAdditionalProjectSources>
</PropertyGroup>

<PropertyGroup Condition="'$(EXPERIMENTAL_WASM_AOT)' != '1'">
<!-- needs to be exe for initializers to be embedded correctly -->
<OutputType>Exe</OutputType>
<!-- conditional due to https://github.com/dotnet/runtime/issues/86186 which is not fixed in NAOT-LLVM -->
<DebuggerSupport>false</DebuggerSupport>
</PropertyGroup>

</Project>
32 changes: 30 additions & 2 deletions crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets
@@ -1,6 +1,33 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<ItemGroup>
<ItemGroup Condition="'$(EXPERIMENTAL_WASM_AOT)' == '1'">
<NativeLibrary Include="$(MSBuildThisFileDirectory)..\bindings.c" />
<UnmanagedEntryPointsAssembly Include="SpacetimeDB.Runtime" />
<WasmImport Include="$(SpacetimeNamespace)!_console_log" />
<WasmImport Include="$(SpacetimeNamespace)!_get_table_id" />
<WasmImport Include="$(SpacetimeNamespace)!_create_index" />
<WasmImport Include="$(SpacetimeNamespace)!_iter_by_col_eq" />
<WasmImport Include="$(SpacetimeNamespace)!_insert" />
<WasmImport Include="$(SpacetimeNamespace)!_delete_by_col_eq" />
<WasmImport Include="$(SpacetimeNamespace)!_delete_by_rel" />
<WasmImport Include="$(SpacetimeNamespace)!_iter_start" />
<WasmImport Include="$(SpacetimeNamespace)!_iter_start_filtered" />
<WasmImport Include="$(SpacetimeNamespace)!_iter_next" />
<WasmImport Include="$(SpacetimeNamespace)!_iter_drop" />
<WasmImport Include="$(SpacetimeNamespace)!_schedule_reducer" />
<WasmImport Include="$(SpacetimeNamespace)!_cancel_reducer" />
<WasmImport Include="$(SpacetimeNamespace)!_buffer_len" />
<WasmImport Include="$(SpacetimeNamespace)!_buffer_consume" />
<WasmImport Include="$(SpacetimeNamespace)!_buffer_alloc" />

<PackageReference Include="Microsoft.DotNet.ILCompiler.LLVM" Version="8.0.0-*" />
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="8.0.0-*" />
<PackageReference Include="Microsoft.NET.ILLink.Tasks" Version="8.0.0-*" Condition="'$(ILLinkTargetsPath)' == ''" />

<CustomLinkerArg Include="-DEXPERIMENTAL_WASM_AOT" />
</ItemGroup>

<ItemGroup Condition="'$(EXPERIMENTAL_WASM_AOT)' != '1'">
<NativeFileReference Include="$(MSBuildThisFileDirectory)..\bindings.c" />
<_WasmNativeFileForLinking Include="@(NativeFileReference)" />
</ItemGroup>
Expand All @@ -9,7 +36,7 @@
<!-- Adapted from https://github.com/dotnet/dotnet-wasi-sdk/blob/2dbb00c779180873d3ed985e59e431f56404d8da/src/Wasi.Sdk/build/Wasi.Sdk.targets#L245-L262 -->
<!-- Executes before the errors in https://github.com/dotnet/runtime/blob/57fd56a99d4c97ac2f95fe84640f2a3f653f4dd7/src/mono/wasi/build/WasiApp.Native.targets#L41-L50. -->
<!-- TODO: remove when https://github.com/dotnet/runtime/issues/82788 is resolved. -->
<Target Name="ObtainWasiSdk" BeforeTargets="_SetupWasiSdk">
<Target Name="ObtainWasiSdk" BeforeTargets="_SetupWasiSdk;CheckWasmSdks">
<PropertyGroup>
<WasiSdkVersion>20</WasiSdkVersion>

Expand All @@ -22,6 +49,7 @@
<WasiSdkUrl>https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WasiSdkVersion)/wasi-sdk-$(WasiSdkVersion).0$(WasiSdkFilenameSuffix).tar.gz</WasiSdkUrl>

<WasiSdkRoot>$([System.IO.Path]::Combine($([System.Environment]::GetFolderPath(SpecialFolder.UserProfile)), '.wasi-sdk', "wasi-sdk-$(WasiSdkVersion)"))</WasiSdkRoot>
<WASI_SDK_PATH>$(WasiSdkRoot)</WASI_SDK_PATH>
<WasiSysRoot>$([System.IO.Path]::Combine($(WasiSdkRoot), 'share', 'wasi-sysroot'))</WasiSysRoot>
<WasiClang>$([System.IO.Path]::Combine($(WasiSdkRoot), 'bin', 'clang'))</WasiClang>
<WasiClang Condition="$([MSBuild]::IsOSPlatform('Windows'))">$(WasiClang).exe</WasiClang>
Expand Down
2 changes: 0 additions & 2 deletions crates/cli/src/subcommands/project/csharp/StdbModule._csproj
@@ -1,8 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<!-- needs to be exe for initializers to be embedded correctly -->
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>wasi-wasm</RuntimeIdentifier>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
7 changes: 6 additions & 1 deletion crates/cli/src/tasks/csharp.rs
Expand Up @@ -60,7 +60,12 @@ pub(crate) fn build_csharp(project_path: &Path, build_debug: bool) -> anyhow::Re
cmd!("dotnet", "publish", "-c", config_name).dir(project_path).run()?;

// check if file exists
let mut output_path = project_path.join(format!("bin/{config_name}/net8.0/wasi-wasm/AppBundle/StdbModule.wasm"));
let subdir = if std::env::var_os("EXPERIMENTAL_WASM_AOT").map_or(false, |v| v == "1") {
"publish"
} else {
"AppBundle"
};
let mut output_path = project_path.join(format!("bin/{config_name}/net8.0/wasi-wasm/{subdir}/StdbModule.wasm"));
if !output_path.exists() {
// check for the old .NET 7 path for projects that haven't migrated yet
output_path = project_path.join(format!("bin/{config_name}/net7.0/StdbModule.wasm"));
Expand Down
2 changes: 0 additions & 2 deletions modules/sdk-test-connect-disconnect-cs/StdbModule.csproj
@@ -1,8 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<!-- needs to be exe for initializers to be embedded correctly -->
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>wasi-wasm</RuntimeIdentifier>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
2 changes: 0 additions & 2 deletions modules/sdk-test-cs/StdbModule.csproj
@@ -1,8 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<!-- needs to be exe for initializers to be embedded correctly -->
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>wasi-wasm</RuntimeIdentifier>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
1 change: 0 additions & 1 deletion modules/spacetimedb-quickstart-cs/StdbModule.csproj
Expand Up @@ -2,7 +2,6 @@

<PropertyGroup>
<!-- needs to be exe for initializers to be embedded correctly -->
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>wasi-wasm</RuntimeIdentifier>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down

0 comments on commit c915a9f

Please sign in to comment.