feat(runtime): gate the wasm tier ladder behind tools builds (#13882) 314202c0f2 * feat(runtime): gate the wasm tier ladder and transplant behind tools builds * refactor(runtime): inline the disabled ladder so tier paths compile away * fix(runtime): honor the tests workspace tools global for wamr internals * fix(runtime): stub ladder keeps the singleton contract * fix(scripting_workspace): handles import survives windows separators Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
diff --git a/.rive_head b/.rive_head index 358d82e..c68f2c2 100644 --- a/.rive_head +++ b/.rive_head
@@ -1 +1 @@ -9fe2b415a70bb2d6460a9df2c2e4a6caf8589c30 +314202c0f2271da5100892d0fd430114107cf8da
diff --git a/include/rive/wasm/module_tier_ladder.hpp b/include/rive/wasm/module_tier_ladder.hpp index d353edb..161b0bc 100644 --- a/include/rive/wasm/module_tier_ladder.hpp +++ b/include/rive/wasm/module_tier_ladder.hpp
@@ -3,16 +3,28 @@ #ifdef WITH_RIVE_SCRIPTING_WASM +// An editor/tools feature: the ladder spawns wamrc subprocesses. Runtime +// builds stub it out and stay on interp (prelinked artifacts load by +// registry instead); windows tools builds stay stubbed pending a +// CreateProcess port. +#if defined(WITH_RIVE_TOOLS) && !defined(_WIN32) +#define RIVE_WASM_TIER_LADDER 1 +#endif + #include "rive/span.hpp" -#include <condition_variable> #include <cstdint> -#include <deque> #include <functional> -#include <mutex> #include <string> + +#ifdef RIVE_WASM_TIER_LADDER +#include <condition_variable> +#include <deque> +#include <mutex> +#include <sys/types.h> #include <thread> #include <unordered_map> #include <vector> +#endif namespace rive { @@ -28,6 +40,8 @@ hw = 2, }; +#ifdef RIVE_WASM_TIER_LADDER + // Drives wamrc subprocesses that turn wasm modules into AOT artifacts and // reports arrivals for frame-boundary hot swap. File-in/file-out, no IPC: // compile crashes and LLVM's RSS stay in the child. Process-wide like the @@ -88,12 +102,7 @@ TierSpecies species = TierSpecies::o0; std::string wasmPath; uint64_t generation = 0; -#ifdef _WIN32 - // The ladder compiles out on Windows; only the layout survives. - intptr_t pid = -1; -#else pid_t pid = -1; -#endif bool cancelled = false; }; @@ -126,6 +135,49 @@ static constexpr unsigned kWorkerCount = 2; }; +#else // RIVE_WASM_TIER_LADDER + +// Same surface, all inline: the ladder reports disabled, so the tier +// paths behind enabled() checks compile away. +class ModuleTierLadder +{ +public: + static ModuleTierLadder& instance() + { + static ModuleTierLadder ladder; + return ladder; + } + + void configure(const std::string&, const std::string&) {} + bool enabled() { return false; } + + struct Artifact + { + uint64_t moduleKey = 0; + TierSpecies species = TierSpecies::o0; + std::string path; + }; + using ArrivalCallback = std::function<void(const Artifact&)>; + void onArrival(ArrivalCallback) {} + + void schedule(const std::string&, uint64_t, Span<const uint8_t>) {} + void stagePristine(uint64_t, Span<const uint8_t>) {} + std::string artifactPath(uint64_t, TierSpecies) { return std::string(); } + void drain() {} + + static constexpr size_t kStraightToO3Bytes = 50 * 1024; + +private: + // Singleton in both configurations, so code cannot compile against one + // and break against the other. + ModuleTierLadder() = default; + ~ModuleTierLadder() = default; + ModuleTierLadder(const ModuleTierLadder&) = delete; + ModuleTierLadder& operator=(const ModuleTierLadder&) = delete; +}; + +#endif // RIVE_WASM_TIER_LADDER + } // namespace rive #endif // WITH_RIVE_SCRIPTING_WASM
diff --git a/include/rive/wasm/wamr_state_transplant.hpp b/include/rive/wasm/wamr_state_transplant.hpp index 7046371..76fc5fe 100644 --- a/include/rive/wasm/wamr_state_transplant.hpp +++ b/include/rive/wasm/wamr_state_transplant.hpp
@@ -3,12 +3,18 @@ #ifdef WITH_RIVE_SCRIPTING_WASM +// The transplant is the tier ladder's frame-boundary half; it rides the +// same gate. +#include "rive/wasm/module_tier_ladder.hpp" + #include "wasm_export.h" #include <string> namespace rive { +#ifdef RIVE_WASM_TIER_LADDER + // Copies live mutable state (memories, globals, table entries) from one // instance of a module onto a fresh instance of the same module content in // a different representation - the frame-boundary half of a tier swap. @@ -20,6 +26,19 @@ wasm_module_inst_t destination, std::string& error); +#else // RIVE_WASM_TIER_LADDER + +// Only reachable through the disabled ladder's upgrade path. +inline bool wamrTransplantState(wasm_module_inst_t, + wasm_module_inst_t, + std::string& error) +{ + error = "tier transplant not built"; + return false; +} + +#endif // RIVE_WASM_TIER_LADDER + } // namespace rive #endif // WITH_RIVE_SCRIPTING_WASM
diff --git a/premake5_v2.lua b/premake5_v2.lua index bdb1cf3..4c87f57 100644 --- a/premake5_v2.lua +++ b/premake5_v2.lua
@@ -258,10 +258,20 @@ filter({ 'options:with_rive_scripting' }) do includedirs({ wamr .. '/core/iwasm/include' }) - -- The tier transplant reads instance internals; layout hinges - -- on the same config defines the wamr lib builds with. - includedirs(wamrInternalIncludes) defines(wamrConfigDefines) + -- The tier transplant is the one TU reading instance internals + -- (layout hinges on the config defines above); runtime builds + -- compile its stub without them. The tests workspace forces + -- tools on without the option, so honor both signals. + if WITH_RIVE_TOOLS == true then + includedirs(wamrInternalIncludes) + else + filter({ + 'options:with_rive_scripting', + 'options:with_rive_tools', + }) + includedirs(wamrInternalIncludes) + end filter({ 'options:with_rive_scripting', 'system:macosx' }) defines({ 'BH_PLATFORM_DARWIN' }) filter({ 'options:with_rive_scripting', 'system:linux' })
diff --git a/src/wasm/module_tier_ladder.cpp b/src/wasm/module_tier_ladder.cpp index 5318d0f..98c0c25 100644 --- a/src/wasm/module_tier_ladder.cpp +++ b/src/wasm/module_tier_ladder.cpp
@@ -2,7 +2,7 @@ #include "rive/wasm/module_tier_ladder.hpp" -#ifndef _WIN32 +#ifdef RIVE_WASM_TIER_LADDER #include <algorithm> #include <cerrno> @@ -472,32 +472,5 @@ } // namespace rive -#else // _WIN32 - -namespace rive -{ -// Windows editor execution is a deferred decision; the ladder reports -// disabled and every module stays on interp. -ModuleTierLadder& ModuleTierLadder::instance() -{ - static ModuleTierLadder* ladder = new ModuleTierLadder(); - return *ladder; -} -ModuleTierLadder::~ModuleTierLadder() {} -void ModuleTierLadder::configure(const std::string&, const std::string&) {} -bool ModuleTierLadder::enabled() { return false; } -void ModuleTierLadder::onArrival(ArrivalCallback) {} -void ModuleTierLadder::schedule(const std::string&, - uint64_t, - Span<const uint8_t>) -{} -void ModuleTierLadder::stagePristine(uint64_t, Span<const uint8_t>) {} -std::string ModuleTierLadder::artifactPath(uint64_t, TierSpecies) -{ - return std::string(); -} -void ModuleTierLadder::drain() {} -} // namespace rive - -#endif // _WIN32 +#endif // RIVE_WASM_TIER_LADDER #endif // WITH_RIVE_SCRIPTING_WASM
diff --git a/src/wasm/wamr_state_transplant.cpp b/src/wasm/wamr_state_transplant.cpp index d5862de..c3691f6 100644 --- a/src/wasm/wamr_state_transplant.cpp +++ b/src/wasm/wamr_state_transplant.cpp
@@ -2,6 +2,10 @@ #include "rive/wasm/wamr_state_transplant.hpp" +// The one TU reading wamr instance internals; runtime builds compile it +// empty and use the header's inline stub. +#ifdef RIVE_WASM_TIER_LADDER + #include "aot_runtime.h" #include "wasm_runtime.h" @@ -175,4 +179,5 @@ } // namespace rive +#endif // RIVE_WASM_TIER_LADDER #endif // WITH_RIVE_SCRIPTING_WASM