diff --git a/README.md b/README.md
index f149711..6e1ea6b 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ This is in the early stages of development. Don't use this for anything importan
UCE is a PHP-inspired server-side runtime that lets you build web pages and handlers in C++ using a small `.uce` preprocessor plus a FastCGI application server.
-- `.uce` pages compile to shared objects on demand
+- `.uce` pages compile to WebAssembly side modules on demand
- normal HTTP pages expose `RENDER(Request& context)`
- WebSocket pages can additionally expose `WS(Request& context)`
- local CLI/admin/test entrypoints can expose `CLI(Request& context)` and are invoked through the Unix CLI socket
@@ -103,7 +103,7 @@ Those are intended for sub-rendering through helpers such as `component("compone
Additional lifecycle hooks are also available on ordinary `.uce` units:
-- `INIT(Request& context)` runs once when a worker loads that unit's shared object into memory
+- `INIT(Request& context)` runs once when a worker instantiates that unit's wasm module
- `ONCE(Request& context)` runs once per request before the first `RENDER()`, `CLI()`, or `COMPONENT...` entrypoint from that file
CLI units can be invoked locally with the convenience wrapper or directly over HTTP-over-Unix:
@@ -330,7 +330,7 @@ Proactive compilation settings:
- `SITE_DIRECTORY=site` tells the runtime which tree to scan on startup for `.uce` files when `PRECOMPILE_FILES_IN` is left empty.
- `PRECOMPILE_FILES_IN=` can override that startup scan root with a different absolute or runtime-relative directory.
-- `PROACTIVE_COMPILE_CHECK_INTERVAL=60` controls how often the low-priority background compiler rechecks known `.uce` files for stale or missing shared objects.
+- `PROACTIVE_COMPILE_CHECK_INTERVAL=60` controls how often the low-priority background compiler rechecks known `.uce` files for stale or missing wasm modules.
The runtime keeps a shared known-file registry under `BIN_DIRECTORY` and updates it as request handling discovers new `.uce` files, so proactive recompiles are not limited to the initial startup scan.
diff --git a/scripts/compile b/scripts/compile
deleted file mode 100755
index 4000ce6..0000000
--- a/scripts/compile
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/bash
-cd "$(dirname "$0")"
-cd ..
-
-SRC_DIR="$1"
-DEST_DIR="$2"
-
-SRC_FN="$3"
-PP_FN="$4"
-SO_FN="$5"
-
-LINK_OBJECTS="$6"
-
-#echo "Source Dir: $SRC_DIR"
-#echo "Dest Dir: $DEST_DIR"
-#echo "Source File: $SRC_FN"
-#echo "Preprocessed File: $PP_FN"
-#echo "Dest File: $SO_FN"
-
-mkdir -p "$DEST_DIR" > /dev/null 2>&1
-
-export CPLUS_INCLUDE_PATH="${CPLUS_INCLUDE_PATH:+${CPLUS_INCLUDE_PATH}:}$SRC_DIR"
-
-BUILDMODE="debug"
-OPT_FLAG="O0"
-
-COMPILER="clang++"
-#COMPILER="g++"
-FLAGS="-shared -g -rdynamic -w -Wall -$OPT_FLAG -std=c++20 -fpermissive -ffast-math -fPIC -Isrc/lib"
-
-LIBS="-ldl -lm -lpthread"
-SRCFLAGS="-D PLATFORM_NAME=\"linux\""
-
-# echo "Compliling executable..."
-$COMPILER "$DEST_DIR/$PP_FN" $SRCFLAGS $FLAGS $LIBS -o "$DEST_DIR/$SO_FN"
-
-# separate .o file
-#$COMPILER -c "$DEST_DIR/$PP_FN" $SRCFLAGS $FLAGS $LIBS -o "$DEST_DIR/$PP_FN.o"
-#$COMPILER "$DEST_DIR/$PP_FN.o" "$LINK_OBJECTS" $SRCFLAGS $FLAGS $LIBS -o "$DEST_DIR/$SO_FN"
-
-if [ $? -eq 0 ]
-then
- # ls -lh "$DEST_DIR"
- exit 0
-else
- exit 1
-fi
diff --git a/scripts/compile_wasm_unit b/scripts/compile_wasm_unit
index 007bd00..6d6a783 100755
--- a/scripts/compile_wasm_unit
+++ b/scripts/compile_wasm_unit
@@ -21,9 +21,9 @@ COMMON_FLAGS=(
--target=wasm32-wasip1
-fPIC -fvisibility=default -fvisibility-inlines-hidden
-O1 -g -std=c++20
- # -w as in scripts/compile: warnings are not failures. The server captures
- # this script's output and treats any non-empty result as a compile failure
- # (then drops the .wasm), so a successful build must be silent.
+ # The server captures this script's output and treats any non-empty result as
+ # a compile failure (then drops the .wasm), so a successful build must be
+ # silent; warnings are intentionally suppressed.
-w
# must match the core build ABI: units with RTTI/EH enabled import
# typeinfo/unwind symbols the -fno-rtti/-fno-exceptions core cannot provide
diff --git a/scripts/wasm/build_w2_units.sh b/scripts/wasm/build_w2_units.sh
index 20a3955..2117195 100755
--- a/scripts/wasm/build_w2_units.sh
+++ b/scripts/wasm/build_w2_units.sh
@@ -20,21 +20,12 @@ fi
count=0
checked=0
skipped=0
-# Native-only units that cannot be wasm side modules (yet).
-# - error-reporting.uce deliberately throws to exercise the native exception
-# path; the wasm backend replaces that machinery with traps (§11.1).
-# - tests/zip.uce uses try/catch around the zip library, which is carved out
-# of the wasm core until it moves behind a hostcall (W4+ membrane work).
-SKIP_PATTERN=${UCE_W2_SKIP:-(error-reporting|tests/zip)\.uce$}
for unit in "${UNITS[@]}"; do
case "$unit" in
*.uce|*.ws.uce) ;;
*) continue ;;
esac
- if [[ "$unit" =~ $SKIP_PATTERN ]]; then
- continue
- fi
src_dir=$(dirname "$unit")
base=$(basename "$unit")
dest_dir="$BIN_DIR$src_dir"
diff --git a/site/demo/unit-browser.uce b/site/demo/unit-browser.uce
index 9641ee4..243c0ac 100644
--- a/site/demo/unit-browser.uce
+++ b/site/demo/unit-browser.uce
@@ -157,16 +157,16 @@ RENDER(Request& context)
Runtime Flags
- loaded = unit_flag_label(selected_info["loaded"]) ?>, stale = unit_flag_label(selected_info["stale"]) ?>, current = unit_flag_label(selected_info["current_unit"]) ?>
+ wasm = unit_flag_label(selected_info["wasm_available"]) ?>, stale = unit_flag_label(selected_info["stale"]) ?>, current = unit_flag_label(selected_info["current_unit"]) ?>
Artifacts
- = selected_info["so_name"].to_string() ?>
+ = selected_info["wasm_name"].to_string() ?>
Timestamps
Source file: = time_format_relative(selected_info["source_mtime"].to_u64()) ?>
- Binary: = time_format_relative(selected_info["compiled_mtime"].to_u64()) ?>
+ Wasm: = time_format_relative(selected_info["compiled_mtime"].to_u64()) ?>
Meta info: = time_format_relative(selected_info["metadata_mtime"].to_u64()) ?>
diff --git a/site/doc/pages/1_INIT.txt b/site/doc/pages/1_INIT.txt
index 89f21a5..568f76d 100644
--- a/site/doc/pages/1_INIT.txt
+++ b/site/doc/pages/1_INIT.txt
@@ -15,7 +15,7 @@ INIT(Request& context)
:content
Defines a worker-load hook for the current `.uce` unit.
-When a worker loads the unit's compiled shared object into memory, the runtime checks whether the unit exposes `INIT(Request& context)`. If it does, the hook runs once for that load before the unit begins serving later requests from that in-memory copy.
+When a worker instantiates the unit's compiled wasm module, the runtime checks whether the unit exposes `INIT(Request& context)`. If it does, the hook runs once for that instance before the unit begins serving requests from that worker-local copy.
Because UCE usually loads units on demand during a request, `INIT()` still receives a valid `Request& context`. Use it for worker-local initialization, not for request-local state that should reset each request.
diff --git a/site/doc/pages/3_C++ Preprocessor.txt b/site/doc/pages/3_C++ Preprocessor.txt
index bb0d8e9..746e2ff 100644
--- a/site/doc/pages/3_C++ Preprocessor.txt
+++ b/site/doc/pages/3_C++ Preprocessor.txt
@@ -14,7 +14,7 @@ unit_call
:content
UCE runs a small custom source-to-source preprocessor before Clang sees a `.uce` or `.ws.uce` file.
-The template rewriting implementation lives in `src/lib/compiler-parser.cpp`, with orchestration in `src/lib/compiler.cpp`. It does not try to parse all of C++. Instead, it performs a narrow character-wise rewrite that understands literal output, inline code islands, `#load`, and `EXPORT` harvesting, then writes a generated `.cpp` file and compiles that file into a shared object.
+The template rewriting implementation lives in `src/lib/compiler-parser.cpp`, with orchestration in `src/lib/compiler.cpp`. It does not try to parse all of C++. Instead, it performs a narrow character-wise rewrite that understands literal output, inline code islands, `#load`, and `EXPORT` harvesting, then writes a generated `.cpp` file and compiles that file into a WebAssembly side module.
## Syntax
@@ -32,7 +32,7 @@ The template rewriting implementation lives in `src/lib/compiler-parser.cpp`, wi
## Pipeline
-- The generated file starts by including the logical runtime header `uce_lib.h`; native and WASM compile scripts provide the include path.
+- The generated file starts by including the logical runtime header `uce_lib.h`; the wasm unit compile script provides the include path.
- It then inlines the configured setup template from `SETUP_TEMPLATE` (by default `scripts/setup.h.template`), which defines the internal hook `__uce_set_current_request(Request*)`.
- It inserts `#line 1` before page code so compiler diagnostics point back to the original `.uce` file.
- Each literal region is rewritten into one or more `print(R"...( ... )...");` calls using a safe raw-string delimiter selected for that literal content.
@@ -47,8 +47,8 @@ The template rewriting implementation lives in `src/lib/compiler-parser.cpp`, wi
- Lines beginning with `RENDER:NAME(...)` are rewritten into exported `__uce_render_NAME(...)` functions.
- Lines beginning with `COMPONENT:NAME(...)` are rewritten into exported `__uce_component_NAME(...)` functions for the component helpers.
- The final generated source is written to `BIN_DIRECTORY + src_path + "/" + source_file + ".cpp"`.
-- `scripts/compile` then compiles that generated `.cpp` into `source_file + ".so"` with `clang++ -shared -std=c++20 ...`.
-- When a worker loads the compiled unit into memory, the runtime checks for `INIT(Request& context)` and calls it once for that worker-side load.
+- `scripts/compile_wasm_unit` then compiles that generated `.cpp` into `source_file + ".wasm"` as a PIC WebAssembly side module.
+- When a worker instantiates the compiled unit, the runtime checks for `INIT(Request& context)` and calls it once for that worker-side instance.
- On each request, the first time a given unit is entered through `RENDER()`, `CLI()`, or any `COMPONENT...` handler, the runtime checks for `ONCE(Request& context)` and calls it before the selected handler.
## Generated Files
@@ -56,7 +56,7 @@ The template rewriting implementation lives in `src/lib/compiler-parser.cpp`, wi
For a source file like `/some/path/page.uce`, the preprocessor produces:
- generated C++: `BIN_DIRECTORY/some/path/page.uce.cpp`
-- shared object: `BIN_DIRECTORY/some/path/page.uce.so`
+- wasm side module: `BIN_DIRECTORY/some/path/page.uce.wasm`
- export list: `BIN_DIRECTORY/some/path/page.uce.exports.txt`
## Examples
@@ -153,7 +153,7 @@ The page template can then render `context.call["fragments"]["head"]` inside `Make dynamic websites like it's 2006.
UCE is a deliberately direct web runtime: files are pages, templates live next to control flow,
- nginx fronts the whole thing, and a request can compile into a shared object on first hit.
+ nginx fronts the whole thing, and a request can compile into a wasm module on first hit.
It is built in the image of PHP's non-architecture, but with an explicit request object,
component rendering, and a built-in WebSocket broker.
@@ -177,7 +177,7 @@ RENDER(Request& context)
render_signal("Files are routes", "A .uce page is the thing you edit and the thing nginx serves."); ?>
- render_signal("Compile on demand", "First request builds a shared object, later requests reuse it."); ?>
+ render_signal("Compile on demand", "First request builds a wasm module, later requests reuse it."); ?>
render_signal("WebSockets included", "Same runtime, same page path, broker-managed connection state."); ?>
@@ -314,7 +314,7 @@ RENDER(Request& context)
What makes it different from old PHP?
- The request object is explicit, components and named handlers are native, markdown support is built in, and WebSockets use a broker-owned connection model inside the runtime.
+ The request object is explicit, components and named handlers are first-class, markdown support is built in, and WebSockets use a broker-owned connection model inside the runtime.
diff --git a/src/lib/compiler-parser.cpp b/src/lib/compiler-parser.cpp
index e80650f..8949f0c 100644
--- a/src/lib/compiler-parser.cpp
+++ b/src/lib/compiler-parser.cpp
@@ -567,7 +567,7 @@ String compiler_preprocess_shared_unit_char_wise(Request* context, SharedUnit* s
String resolved_unit = unit_name;
if(resolved_unit != "" && resolved_unit[0] != '/')
resolved_unit = expand_path(resolved_unit, su->src_path);
- SharedUnit* sub_su = (resolved_unit == "" ? 0 : get_shared_unit(context, resolved_unit, true));
+ SharedUnit* sub_su = (resolved_unit == "" ? 0 : get_shared_unit(context, resolved_unit));
if(sub_su)
parsed_content.append("#include \"" + sub_su->bin_path + "/" + sub_su->pre_file_name + "\"\n");
}
diff --git a/src/lib/compiler.cpp b/src/lib/compiler.cpp
index 426dd29..0974dcd 100644
--- a/src/lib/compiler.cpp
+++ b/src/lib/compiler.cpp
@@ -386,34 +386,29 @@ SharedUnit* compiler_cached_unit(Request* context, String file_name)
return(it->second);
}
-bool compiler_cache_mode_matches(SharedUnit* su, bool opt_so_optional)
-{
- return(su && su->opt_so_optional == opt_so_optional);
-}
-
-bool compiler_cached_unit_is_reusable(Request* context, SharedUnit* su, bool opt_so_optional, bool force_recompile)
+bool compiler_cached_unit_is_reusable(Request* context, SharedUnit* su, bool force_recompile)
{
return(
!force_recompile &&
- compiler_cache_mode_matches(su, opt_so_optional) &&
+ su &&
!shared_unit_cache_is_stale(context, su)
);
}
-SharedUnit* compiler_reusable_cached_unit(Request* context, String file_name, bool opt_so_optional, bool force_recompile)
+SharedUnit* compiler_reusable_cached_unit(Request* context, String file_name, bool force_recompile)
{
auto su = compiler_cached_unit(context, file_name);
- if(compiler_cached_unit_is_reusable(context, su, opt_so_optional, force_recompile))
+ if(compiler_cached_unit_is_reusable(context, su, force_recompile))
return(su);
return(0);
}
-void compiler_release_cached_unit_if_needed(Request* context, String file_name, bool opt_so_optional, bool force_recompile)
+void compiler_release_cached_unit_if_needed(Request* context, String file_name, bool force_recompile)
{
auto su = compiler_cached_unit(context, file_name);
if(!su)
return;
- if(force_recompile || !compiler_cache_mode_matches(su, opt_so_optional) || shared_unit_cache_is_stale(context, su))
+ if(force_recompile || shared_unit_cache_is_stale(context, su))
release_shared_unit_cache_entry(context, file_name);
}
@@ -632,11 +627,9 @@ void setup_unit_paths(Request* context, SharedUnit* su, String file_name)
su->pre_path = context->server->config["BIN_DIRECTORY"] + su->src_path;
su->src_file_name = basename(file_name);
- su->bin_file_name = su->src_file_name + ".so";
su->wasm_file_name = su->src_file_name + ".wasm";
su->pre_file_name = su->src_file_name + ".cpp";
- su->so_name = su->bin_path + "/" + su->bin_file_name;
su->wasm_name = su->bin_path + "/" + su->wasm_file_name;
su->wasm_check_file_name = su->bin_path + "/" + su->src_file_name + ".wasm-check.txt";
su->api_file_name = su->bin_path + "/" + su->src_file_name + ".exports.txt";
@@ -779,21 +772,20 @@ void compile_shared_unit(Request* context, SharedUnit* su)
}
}
-SharedUnit* compiler_get_shared_unit_internal(Request* context, String file_name, bool opt_so_optional, bool force_recompile)
+SharedUnit* compiler_get_shared_unit_internal(Request* context, String file_name, bool force_recompile)
{
file_name = compiler_normalize_unit_path(context, file_name);
- auto cached = compiler_reusable_cached_unit(context, file_name, opt_so_optional, force_recompile);
+ auto cached = compiler_reusable_cached_unit(context, file_name, force_recompile);
if(cached)
return(cached);
- compiler_release_cached_unit_if_needed(context, file_name, opt_so_optional, force_recompile);
+ compiler_release_cached_unit_if_needed(context, file_name, force_recompile);
SharedUnit* su = new SharedUnit();
setup_unit_paths(context, su, file_name);
- su->opt_so_optional = opt_so_optional;
- int fdlock = compiler_open_lock_file(su->so_name + ".lock", "shared-unit:" + file_name);
+ int fdlock = compiler_open_lock_file(su->wasm_name + ".lock", "shared-unit:" + file_name);
if(fdlock == -1)
{
su->compiler_messages = "could not open compile lock";
@@ -804,7 +796,7 @@ SharedUnit* compiler_get_shared_unit_internal(Request* context, String file_name
return(su);
}
- cached = compiler_reusable_cached_unit(context, file_name, opt_so_optional, force_recompile);
+ cached = compiler_reusable_cached_unit(context, file_name, force_recompile);
if(cached)
{
compiler_close_lock_file(fdlock);
@@ -812,7 +804,7 @@ SharedUnit* compiler_get_shared_unit_internal(Request* context, String file_name
return(cached);
}
- compiler_release_cached_unit_if_needed(context, file_name, opt_so_optional, force_recompile);
+ compiler_release_cached_unit_if_needed(context, file_name, force_recompile);
auto state = inspect_shared_unit_filesystem(context, su);
auto compile_check = shared_unit_compile_check(state);
@@ -852,9 +844,9 @@ SharedUnit* compiler_get_shared_unit_internal(Request* context, String file_name
return(su);
}
-SharedUnit* get_shared_unit(Request* context, String file_name, bool opt_so_optional)
+SharedUnit* get_shared_unit(Request* context, String file_name)
{
- return(compiler_get_shared_unit_internal(context, file_name, opt_so_optional, false));
+ return(compiler_get_shared_unit_internal(context, file_name, false));
}
String compiler_error_page_unit(Request* context, String config_key)
@@ -880,7 +872,7 @@ bool compiler_unit_compile_pending(Request* context, String file_name)
String normalized = compiler_normalize_unit_path(context, file_name);
if(normalized == "" || !file_exists(normalized))
return(false);
- if(compiler_reusable_cached_unit(context, normalized, false, false))
+ if(compiler_reusable_cached_unit(context, normalized, false))
return(false);
SharedUnit probe;
@@ -972,7 +964,7 @@ String component(String name, DValue props, Request& context)
SharedUnit* unit_load(String file_name)
{
String resolved = compiler_resolve_unit_path(context, file_name);
- return(resolved == "" ? 0 : get_shared_unit(context, resolved, true));
+ return(resolved == "" ? 0 : get_shared_unit(context, resolved));
}
DValue* unit_call(String file_name, String function_name, DValue* call_param)
@@ -1120,9 +1112,8 @@ DValue unit_info(String path)
info["bin_path"] = su->bin_path;
info["pre_path"] = su->pre_path;
info["src_file_name"] = su->src_file_name;
- info["bin_file_name"] = su->bin_file_name;
info["pre_file_name"] = su->pre_file_name;
- info["so_name"] = su->so_name;
+ info["wasm_file_name"] = su->wasm_file_name;
info["wasm_name"] = su->wasm_name;
info["wasm_exists"].set_bool(file_exists(su->wasm_name));
info["api_file_name"] = su->api_file_name;
@@ -1134,7 +1125,6 @@ DValue unit_info(String path)
info["error_status"] = compiler_error_status(su);
info["compiler_messages"] = su->compiler_messages;
info["last_compiled"] = (f64)su->last_compiled;
- info["last_loaded"] = (f64)su->last_loaded;
info["last_rendered"] = (f64)su->last_rendered;
info["last_error"] = (f64)su->last_error;
info["request_count"] = (f64)su->request_count;
@@ -1164,7 +1154,7 @@ DValue unit_info(String path)
info["metadata_build_token"] = fs_state.metadata_build_token;
compiler_tree_set_bool(info, "known", compiler_has_known_unit_cached(context, resolved_path));
compiler_tree_set_bool(info, "current_unit", resolved_path == compiler_current_unit_path(context));
- compiler_tree_set_bool(info, "loaded", file_exists(su->wasm_name));
+ compiler_tree_set_bool(info, "wasm_available", file_exists(su->wasm_name));
compiler_tree_set_bool(info, "source_exists", fs_state.source_exists);
compiler_tree_set_bool(info, "compiled_exists", fs_state.compiled_time != 0);
compiler_tree_set_bool(info, "metadata_exists", fs_state.metadata_exists);
@@ -1202,6 +1192,6 @@ bool unit_compile(String path)
if(resolved_path == "")
return(false);
compiler_track_known_unit(context, resolved_path);
- auto su = compiler_get_shared_unit_internal(context, resolved_path, false, true);
+ auto su = compiler_get_shared_unit_internal(context, resolved_path, true);
return(su && trim(su->compiler_messages) == "" && file_exists(su->wasm_name));
}
diff --git a/src/lib/compiler.h b/src/lib/compiler.h
index b72dbcc..16c6972 100644
--- a/src/lib/compiler.h
+++ b/src/lib/compiler.h
@@ -14,7 +14,7 @@ String compiler_generated_cpp_path(Request* context, String source_file);
String compiler_generated_cpp_path(SharedUnit* su);
void setup_unit_paths(Request* context, SharedUnit* su, String file_name);
void compile_shared_unit(Request* context, SharedUnit* su);
-SharedUnit* get_shared_unit(Request* context, String file_name, bool opt_so_optional = false);
+SharedUnit* get_shared_unit(Request* context, String file_name);
String compiler_error_page_unit(Request* context, String config_key);
bool compiler_unit_compile_pending(Request* context, String file_name);
String compiler_site_directory(Request* context);
diff --git a/src/lib/functionlib.h b/src/lib/functionlib.h
index a05a732..629a6f2 100644
--- a/src/lib/functionlib.h
+++ b/src/lib/functionlib.h
@@ -48,7 +48,7 @@ inline String to_string(SharedUnit* u) {
result += String("SharedUnit( \n")+
"Source:"+(u->file_name)+"\n"+
- "SharedObject:"+(u->so_name)+"\n"+
+ "Wasm:"+(u->wasm_name)+"\n"+
"API:"+(u->api_file_name)+"\n"+
to_string(u->api_declarations);
diff --git a/src/lib/types.h b/src/lib/types.h
index 6a03405..23e4a25 100644
--- a/src/lib/types.h
+++ b/src/lib/types.h
@@ -57,16 +57,14 @@ typedef std::ostringstream ByteStream;
struct Request;
struct DValue;
-typedef void (*request_ref_handler)(Request& request);
-typedef DValue* (*dv_call_handler)(DValue* call_param);
-typedef void (*request_handler)(Request* request);
+typedef void (*WasmRequestHandler)(Request& request);
+typedef DValue* (*WasmDValueCallHandler)(DValue* call_param);
inline String to_string(s64 v) { return(std::to_string(v)); }
struct SharedUnit {
String file_name;
- String so_name;
String wasm_name;
String wasm_check_file_name;
String api_file_name;
@@ -79,7 +77,6 @@ struct SharedUnit {
String bin_path;
String pre_path;
String src_file_name;
- String bin_file_name;
String wasm_file_name;
String pre_file_name;
@@ -89,7 +86,6 @@ struct SharedUnit {
String runtime_error_status = "";
time_t last_compiled = 0;
time_t observed_compiled_time = 0;
- time_t last_loaded = 0;
time_t last_rendered = 0;
time_t last_error = 0;
String observed_metadata_content = "";
@@ -112,8 +108,6 @@ struct SharedUnit {
f64 best_render_duration = 0;
f64 worst_render_duration = 0;
- bool opt_so_optional = false;
-
~SharedUnit();
};
diff --git a/src/linux_fastcgi.cpp b/src/linux_fastcgi.cpp
index cf14321..a5309d6 100644
--- a/src/linux_fastcgi.cpp
+++ b/src/linux_fastcgi.cpp
@@ -86,7 +86,7 @@ bool render_wasm_error_page(Request& request, String config_key, s32 status_code
String unit = compiler_normalize_unit_path(&request, unit_file);
if(!wasm_backend_should_handle(request, unit))
- get_shared_unit(&request, unit, true);
+ get_shared_unit(&request, unit);
ob_start();
String wasm_error = "";
@@ -417,7 +417,7 @@ int handle_cli_complete(FastCGIRequest& request)
// been removed, so a unit that still cannot be served by wasm is a
// request failure instead of a fallback path.
if(!wasm_backend_should_handle(request, cli_unit))
- get_shared_unit(&request, cli_unit, true);
+ get_shared_unit(&request, cli_unit);
if(wasm_backend_should_handle(request, cli_unit))
{
String wasm_error = wasm_backend_serve(request, cli_unit, "cli");
@@ -537,7 +537,7 @@ int handle_complete(FastCGIRequest& request) {
// be served by wasm becomes a clean 500 request failure.
auto wasm_ready = [&](const String& unit) -> bool {
if(!wasm_backend_should_handle(request, unit))
- get_shared_unit(&request, unit, true);
+ get_shared_unit(&request, unit);
return(wasm_backend_should_handle(request, unit));
};
auto fail_wasm_unavailable = [&](const String& handler) {
@@ -1218,7 +1218,7 @@ void run_proactive_compiler()
if(compiler_unit_needs_recompile(&background_context, file_name, &source_missing))
{
printf("(i) proactive compile %s\n", file_name.c_str());
- auto su = get_shared_unit(&background_context, file_name, false);
+ auto su = get_shared_unit(&background_context, file_name);
if(su && su->compiler_messages == "")
retry_after.erase(file_name);
else
diff --git a/src/wasm/backend.h b/src/wasm/backend.h
index 0c9e516..0f1e440 100644
--- a/src/wasm/backend.h
+++ b/src/wasm/backend.h
@@ -6,8 +6,8 @@
// backend.cpp — so it does not have to compile worker.cpp + wasmtime.hh on
// every build. Include only after uce_lib.h (needs Request / String).
-// True if this request should be served by the wasm backend (config + artifact
-// + fallback-token gate); handler-agnostic, the caller names the handler.
+// True if this request can be served by the wasm backend for the named unit
+// artifact; handler-agnostic, the caller names the handler.
bool wasm_backend_should_handle(Request& request, const String& entry_unit);
// Serve a request through a wasm workspace by invoking a named unit handler —
diff --git a/src/wasm/core.cpp b/src/wasm/core.cpp
index d7d99b8..adcc117 100644
--- a/src/wasm/core.cpp
+++ b/src/wasm/core.cpp
@@ -564,7 +564,7 @@ static void wasm_run_once(const String& resolved, Request& request)
return;
String previous_unit = request.resources.current_unit_file;
request.resources.current_unit_file = resolved;
- request_ref_handler once_handler = (request_ref_handler)(uintptr_t)once_slot;
+ WasmRequestHandler once_handler = (WasmRequestHandler)(uintptr_t)once_slot;
once_handler(request);
request.resources.current_unit_file = previous_unit;
}
@@ -597,7 +597,7 @@ DValue* unit_call(String file_name, String function_name, DValue* call_param)
String previous_unit = context->resources.current_unit_file;
if(resolved != "")
context->resources.current_unit_file = resolved;
- request_ref_handler handler_fn = (request_ref_handler)(uintptr_t)slot;
+ WasmRequestHandler handler_fn = (WasmRequestHandler)(uintptr_t)slot;
handler_fn(*context);
context->resources.current_unit_file = previous_unit;
return(0);
@@ -614,7 +614,7 @@ DValue* unit_call(String file_name, String function_name, DValue* call_param)
String previous_unit = context->resources.current_unit_file;
if(resolved != "")
context->resources.current_unit_file = resolved;
- dv_call_handler handler_fn = (dv_call_handler)(uintptr_t)slot;
+ WasmDValueCallHandler handler_fn = (WasmDValueCallHandler)(uintptr_t)slot;
DValue* result = handler_fn(call_param);
context->resources.current_unit_file = previous_unit;
if(result)
@@ -644,7 +644,7 @@ void component_render(String name, DValue props, Request& request)
request.resources.current_unit_file = resolved;
// a wasm function pointer is its index in the shared funcref table; the
// host returned the handler's slot, so this is a plain call_indirect
- request_ref_handler handler_fn = (request_ref_handler)(uintptr_t)slot;
+ WasmRequestHandler handler_fn = (WasmRequestHandler)(uintptr_t)slot;
handler_fn(request);
request.resources.current_unit_file = previous_unit;
}
@@ -680,7 +680,7 @@ void unit_render(String file_name, Request& request)
String previous_unit = request.resources.current_unit_file;
if(resolved != "")
request.resources.current_unit_file = resolved;
- request_ref_handler handler_fn = (request_ref_handler)(uintptr_t)slot;
+ WasmRequestHandler handler_fn = (WasmRequestHandler)(uintptr_t)slot;
handler_fn(request);
request.resources.current_unit_file = previous_unit;
}
@@ -706,7 +706,7 @@ void uce_wasm_invoke_entry(const char* path, size_t path_len, const char* handle
String previous_unit = context->resources.current_unit_file;
if(resolved != "")
context->resources.current_unit_file = resolved;
- request_ref_handler handler_fn = (request_ref_handler)(uintptr_t)slot;
+ WasmRequestHandler handler_fn = (WasmRequestHandler)(uintptr_t)slot;
handler_fn(*context);
context->resources.current_unit_file = previous_unit;
}
diff --git a/src/wasm/worker.cpp b/src/wasm/worker.cpp
index 46f564f..35ec87e 100644
--- a/src/wasm/worker.cpp
+++ b/src/wasm/worker.cpp
@@ -1090,7 +1090,7 @@ private:
}
if(!file_exists_host(worker.unit_wasm_path(resolved)) || compiler_unit_needs_recompile(context, resolved, 0))
- get_shared_unit(context, resolved, true);
+ get_shared_unit(context, resolved);
size_t unit_index = 0;
String error = load_unit(resolved, unit_index);
diff --git a/tests/README.md b/tests/README.md
index ed1564d..64238e9 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -10,7 +10,7 @@ scripts/run_cli_tests.sh --include-wasm-kill
scripts/run_cli_tests.sh --list
```
-`--include-wasm-kill` adds the wasm trap/loop/recurse kill cases and should be used when `WASM_BACKEND_ENABLED=1`.
+`--include-wasm-kill` adds the wasm trap/loop/recurse kill cases and should be used for the normal wasm-only runtime gate.
The script reads `CLI_SOCKET_PATH` from `/etc/uce/settings.cfg` unless `UCE_CLI_SOCKET` is set.
diff --git a/tests/wasm_benchmark.py b/tests/wasm_benchmark.py
index d2fbe3a..93b5128 100755
--- a/tests/wasm_benchmark.py
+++ b/tests/wasm_benchmark.py
@@ -1,9 +1,10 @@
#!/usr/bin/env python3
-"""Phase 5 native/WASM benchmark harness.
+"""Current wasm-runtime HTTP benchmark harness.
-This runner intentionally has no third-party dependencies. It records a warmed
-native HTTP baseline now and can compare against a future wasm worker by passing
---wasm-base-url. Results are written as JSON plus a small Markdown table.
+This runner intentionally has no third-party dependencies. It measures one or
+more HTTP endpoints served by the wasm-only UCE runtime. Optionally pass a prior
+benchmark JSON as a baseline; old native baselines are treated as historical
+reference data only, not as a runnable backend mode.
"""
from __future__ import annotations
@@ -95,14 +96,14 @@ def measure_backend(backend: str, base_url: str, host_header: str, targets: list
return results
-def compare(results: list[Measurement]) -> list[str]:
- native = {r.target: r for r in results if r.backend == "native"}
+def compare(results: list[Measurement], baseline_label: str) -> list[str]:
+ baseline = {r.target: r for r in results if r.backend == baseline_label}
lines = ["| target | backend | median ms | mean ms | budget | status |", "|---|---:|---:|---:|---|---|"]
for result in results:
- budget = "baseline"
+ budget = "baseline" if result.backend == baseline_label else "n/a"
status = "PASS" if result.ok else "FAIL"
- if result.backend != "native" and result.target in native:
- limit = native[result.target].median_ms * 2.0
+ if result.backend != baseline_label and result.target in baseline:
+ limit = baseline[result.target].median_ms * 2.0
budget = f"≤ {limit:.1f} ms"
if result.median_ms > limit:
status = "FAIL"
@@ -119,33 +120,30 @@ def build_targets() -> list[Target]:
def main() -> int:
- parser = argparse.ArgumentParser(description="Phase 5 native/wasm benchmark harness")
- parser.add_argument("--native-base-url", default="http://localhost:80")
- parser.add_argument("--wasm-base-url", default="", help="optional wasm worker URL; omitted until worker exists")
- parser.add_argument("--backend-label", default="native", help="label for --native-base-url measurements when running one backend at a time")
- parser.add_argument("--compare-native-json", default="", help="optional prior native benchmark.json for budget comparison")
+ parser = argparse.ArgumentParser(description="UCE wasm-runtime HTTP benchmark harness")
+ parser.add_argument("--base-url", "--native-base-url", dest="base_url", default="http://localhost:80", help="runtime base URL (legacy alias --native-base-url is accepted)")
+ parser.add_argument("--backend-label", default="wasm", help="label for this run's measurements")
+ parser.add_argument("--compare-baseline-json", "--compare-native-json", dest="compare_baseline_json", default="", help="optional prior benchmark.json for budget comparison")
+ parser.add_argument("--baseline-label", default="native", help="backend label in the prior JSON to use as the budget baseline")
parser.add_argument("--host-header", default="uce.openfu.com")
parser.add_argument("--warmups", type=int, default=2)
parser.add_argument("--samples", type=int, default=20)
parser.add_argument("--timeout", type=float, default=10.0)
- parser.add_argument("--out-dir", default="/tmp/uce/wasm-phase5")
+ parser.add_argument("--out-dir", default="/tmp/uce/wasm-benchmark")
args = parser.parse_args()
targets = build_targets()
results: list[Measurement] = []
- if args.compare_native_json:
- for row in json.loads(Path(args.compare_native_json).read_text()):
+ if args.compare_baseline_json:
+ for row in json.loads(Path(args.compare_baseline_json).read_text()):
+ row.setdefault("backend", args.baseline_label)
results.append(Measurement(**row))
- results.extend(measure_backend(args.backend_label, args.native_base_url, args.host_header, targets, args.warmups, args.samples, args.timeout))
- if args.wasm_base_url:
- results.extend(measure_backend("wasm", args.wasm_base_url, args.host_header, targets, args.warmups, args.samples, args.timeout))
+ results.extend(measure_backend(args.backend_label, args.base_url, args.host_header, targets, args.warmups, args.samples, args.timeout))
out_dir = Path(args.out_dir)
out_dir.mkdir(parents=True, exist_ok=True)
(out_dir / "benchmark.json").write_text(json.dumps([asdict(r) for r in results], indent=2) + "\n")
- md_lines = ["# Phase 5 benchmark report", "", *compare(results), ""]
- if not args.wasm_base_url and args.backend_label == "native" and not args.compare_native_json:
- md_lines.append("WASM worker URL was not provided; this report is the native baseline that future wasm runs compare against.")
+ md_lines = ["# UCE wasm benchmark report", "", *compare(results, args.baseline_label), ""]
(out_dir / "benchmark.md").write_text("\n".join(md_lines) + "\n")
print("\n".join(md_lines))
print(f"wrote {out_dir / 'benchmark.json'} and {out_dir / 'benchmark.md'}")