From 32dcc62c24264edb7072a9d627c07b097a5c5acc Mon Sep 17 00:00:00 2001 From: Demetrius Kanios Date: Wed, 24 Jun 2026 13:54:25 -0700 Subject: [PATCH] Add LDC-specific DRuntime changes. --- runtime/CMakeLists.txt | 5 ++- runtime/druntime/src/core/thread/osthread.d | 26 +++++++++++++++ runtime/druntime/src/ldc/eh_wasm.d | 35 +++++++++++++++++++++ runtime/druntime/src/ldc/intrinsics.di | 5 +++ runtime/druntime/src/rt/sections_ldc.d | 1 + 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 runtime/druntime/src/ldc/eh_wasm.d diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index a203e1c56b0..ba5fe6b759f 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -181,11 +181,12 @@ file(GLOB_RECURSE DRUNTIME_D_OPENBSD ${RUNTIME_DIR}/src/core/sys/openbsd/*.d) file(GLOB_RECURSE DRUNTIME_D_POSIX ${RUNTIME_DIR}/src/core/sys/posix/*.d) file(GLOB_RECURSE DRUNTIME_D_SOLARIS ${RUNTIME_DIR}/src/core/sys/solaris/*.d) file(GLOB_RECURSE DRUNTIME_D_WINDOWS ${RUNTIME_DIR}/src/core/sys/windows/*.d) +file(GLOB_RECURSE DRUNTIME_D_WASI ${RUNTIME_DIR}/src/core/sys/wasi/*.d) list(REMOVE_ITEM DRUNTIME_D ${DRUNTIME_D_BIONIC} ${DRUNTIME_D_DARWIN} ${DRUNTIME_D_DRAGONFLYBSD} ${DRUNTIME_D_FREEBSD} ${DRUNTIME_D_LINUX} ${DRUNTIME_D_NETBSD} ${DRUNTIME_D_OPENBSD} ${DRUNTIME_D_POSIX} ${DRUNTIME_D_SOLARIS} - ${DRUNTIME_D_WINDOWS} + ${DRUNTIME_D_WINDOWS} ${DRUNTIME_D_WASI} ) if("${TARGET_SYSTEM}" MATCHES "Windows") list(APPEND DRUNTIME_D ${DRUNTIME_D_WINDOWS}) @@ -206,6 +207,8 @@ elseif("${TARGET_SYSTEM}" MATCHES "UNIX") list(APPEND DRUNTIME_D ${DRUNTIME_D_OPENBSD}) elseif("${TARGET_SYSTEM}" MATCHES "SunOS") list(APPEND DRUNTIME_D ${DRUNTIME_D_SOLARIS}) + elseif("${TARGET_SYSTEM}" MATCHES "WASI") + list(APPEND DRUNTIME_D ${DRUNTIME_D_WASI}) endif() endif() diff --git a/runtime/druntime/src/core/thread/osthread.d b/runtime/druntime/src/core/thread/osthread.d index 73e5adb4d9b..493ff22ccb2 100644 --- a/runtime/druntime/src/core/thread/osthread.d +++ b/runtime/druntime/src/core/thread/osthread.d @@ -1831,6 +1831,24 @@ version (LDC) static assert(0); } } + else version (WebAssembly) + { + /* Must NOT be naked, but is safe to inline. + * + * The function prologue is what loads the `__stack_pointer` global + * into a fake "physical" register (which becomes a Wasm local). + * Manipulation of the stack is done with the local, and only synced + * back out to `__stack_pointer` across function boundaries. + * + * `llvm_stackaddress` gives us access to this fake register + * and allows for better optimization than inline asm would. + */ + private extern(D) void* getStackTop() nothrow @nogc + { + import ldc.intrinsics; + return llvm_stackaddress(); + } + } else { /* The use of intrinsic llvm_frameaddress is a reasonable default for @@ -1874,6 +1892,14 @@ version (LDC_Windows) static assert(false, "Architecture not supported."); } } +else version (WebAssembly) +{ + private extern(C) extern void* __stack_low; + private extern(D) void* getStackBottom() nothrow @nogc + { + return __stack_low; + } +} else private extern(D) void* getStackBottom() nothrow @nogc { diff --git a/runtime/druntime/src/ldc/eh_wasm.d b/runtime/druntime/src/ldc/eh_wasm.d new file mode 100644 index 00000000000..59dd74f4ee8 --- /dev/null +++ b/runtime/druntime/src/ldc/eh_wasm.d @@ -0,0 +1,35 @@ +/** + * This module implements the runtime-part of LDC exceptions + * on WebAssembly (Wasm EH) + */ + +module ldc.eh_wasm; + +version (WebAssembly): + +extern (C) void _d_throw_exception(Throwable t) { + import core.stdc.stdio : fwrite, stdout, putc; + import ldc.intrinsics : llvm_trap; + + auto msg = t.toString(); + fwrite(msg.ptr, msg.length, 1, stdout); + putc('\n', stdout); + + llvm_trap(); +} + +extern (C) void _Unwind_Resume(void*) { + import core.stdc.stdio : puts; + import ldc.intrinsics : llvm_trap; + + puts("Cannot EH unwind on Wasm (yet)."); + llvm_trap(); +} + +extern (C) void _d_eh_enter_catch(void*) { + import core.stdc.stdio : puts; + import ldc.intrinsics : llvm_trap; + + puts("Cannot EH catch on Wasm (yet)."); + llvm_trap(); +} diff --git a/runtime/druntime/src/ldc/intrinsics.di b/runtime/druntime/src/ldc/intrinsics.di index 96256e5e871..5bac20af473 100644 --- a/runtime/druntime/src/ldc/intrinsics.di +++ b/runtime/druntime/src/ldc/intrinsics.di @@ -54,6 +54,11 @@ pragma(LDC_intrinsic, "llvm.returnaddress") pragma(LDC_intrinsic, "llvm.frameaddress.p0") void* llvm_frameaddress(uint level); +/// The 'llvm.stackaddress' intrinsic returns the starting address of the stack +// region that may be used by called functions. +pragma(LDC_intrinsic, "llvm.stackaddress.p0") + void* llvm_stackaddress(); + /// The 'llvm.stacksave' intrinsic is used to remember the current state of the /// function stack, for use with llvm.stackrestore. This is useful for /// implementing language features like scoped automatic variable sized arrays diff --git a/runtime/druntime/src/rt/sections_ldc.d b/runtime/druntime/src/rt/sections_ldc.d index 8d42a109527..828cceb046c 100644 --- a/runtime/druntime/src/rt/sections_ldc.d +++ b/runtime/druntime/src/rt/sections_ldc.d @@ -32,6 +32,7 @@ else version (DragonFlyBSD) {} else version (NetBSD) {} else version (OpenBSD) {} else version (Windows) {} +else version (WebAssembly) {} else version (LDC): import rt.minfo;