W7e: delete the native unit pipeline (.so compile + dlopen execution)

Units now run exclusively on wasm; the native generated-C++ -> clang -> .so ->
dlopen path and its request-time fallback are removed.

- Dispatch (linux_fastcgi.cpp): the 4 handle_complete branches + the CLI-socket
  path route every request through wasm (wasm_ready compiles cold/stale on
  demand); a wasm-unavailable unit now yields a clean error page
  (fail_wasm_unavailable / render_request_failure) instead of native execution.
  compiler_invoke / _cli / _websocket / _serve_http deleted.
- compiler.cpp (-1274): removed the native .so compile (COMPILE_SCRIPT),
  load_shared_unit, dlopen/dlsym/dlclose, compiler_load_shared_unit, and the
  SharedUnit .so function-pointer fields (on_setup/on_render/on_component/
  on_websocket/on_cli/on_once/on_init) in types.h/types.cpp. compile_shared_unit
  now builds only the .wasm side-module; the .uce preprocessor/parser front-end
  is kept (it emits the C++ the wasm compile consumes).
- unit_call()/component()/once/init now resolve across units through the wasm
  host component resolver (uce_host_component_resolve) instead of native dlsym;
  configured runtime error pages render through the wasm backend.
- Dropped the WASM_BACKEND_ENABLED feature flag and dead COMPILE_SCRIPT /
  COMPILE_WASM_UNITS config; unit ABI freshness tied to UCE_UNIT_ABI_VERSION;
  guard against serving a stale .wasm for a deleted source; retired the obsolete
  W5 native-vs-wasm toggle script. Docs updated.

Implemented via the pi agent (with 3 delegated sub-reviews); independently
re-verified on the build host: run_cli_tests --include-wasm-kill => 87 passed,
0 failed, 0 skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
root
2026-06-14 23:20:50 +00:00
co-authored by Claude Opus 4.8
parent fb728d63bc
commit cf51336873
16 changed files with 352 additions and 1344 deletions
+59 -29
View File
@@ -139,32 +139,6 @@ bool unit_compile(String path)
}
static DValue wasm_unit_call_result;
DValue* unit_call(String file_name, String function_name, DValue* call_param)
{
DValue request;
request["op"] = "call";
request["file"] = file_name;
request["function"] = function_name;
if(call_param)
request["param"] = *call_param;
DValue response = wasm_units_call(request);
String output = response["output"].to_string();
if(output != "")
print(output);
DValue* result = response.key("result");
if(result)
{
wasm_unit_call_result = *result;
return(&wasm_unit_call_result);
}
return(0);
}
SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String current_path, bool opt_so_optional)
{
(void)context; (void)file_name; (void)current_path; (void)opt_so_optional;
return(0);
}
static DValue wasm_mysql_call(DValue request)
{
@@ -484,9 +458,9 @@ extern "C" int32_t uce_host_component_resolve(
// but a single workspace can render the same component many times)
static std::map<String, s32> wasm_component_slots;
// These mirror small page-runtime pieces of compiler.cpp, which is carved
// out of the wasm core wholesale (it is the native toolchain: parser, clang
// driver, dlopen). Kept byte-identical where possible.
// These mirror small page-runtime pieces that cannot include compiler.cpp in
// the wasm core (compiler.cpp owns parser/clang/cache bookkeeping for the host
// build). Kept byte-identical where possible.
String component_normalize_path(String name)
{
name = trim(name);
@@ -595,6 +569,62 @@ static void wasm_run_once(const String& resolved, Request& request)
request.resources.current_unit_file = previous_unit;
}
DValue* unit_call(String file_name, String function_name, DValue* call_param)
{
String macro = to_upper(trim(function_name));
String handler = "";
if(macro == "RENDER" || macro.rfind("RENDER:", 0) == 0)
handler = "render" + (macro.length() > 7 ? ":" + trim(function_name.substr(function_name.find(":") + 1)) : String(""));
else if(macro == "COMPONENT" || macro.rfind("COMPONENT:", 0) == 0)
handler = "component" + (macro.length() > 10 ? ":" + trim(function_name.substr(function_name.find(":") + 1)) : String(""));
else if(macro == "ONCE")
handler = "once";
else if(macro == "INIT")
handler = "init";
if(handler != "")
{
String resolved;
s32 slot = wasm_resolve_target(file_name, handler, &resolved);
if(!slot)
{
print("Error: unit_call() function '", function_name, "' not found");
return(0);
}
RequestPropsScope props_scope(context, (call_param ? *call_param : DValue()));
if((handler == "render" || handler.rfind("render:", 0) == 0 || handler == "component" || handler.rfind("component:", 0) == 0) && resolved != "")
wasm_run_once(resolved, *context);
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;
handler_fn(*context);
context->resources.current_unit_file = previous_unit;
return(0);
}
String resolved;
s32 slot = wasm_resolve_target(file_name, "export:" + function_name, &resolved);
if(!slot)
{
print("Error: unit_call() function '", function_name, "' not found");
return(0);
}
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;
DValue* result = handler_fn(call_param);
context->resources.current_unit_file = previous_unit;
if(result)
{
wasm_unit_call_result = *result;
return(&wasm_unit_call_result);
}
return(0);
}
void component_render(String name, DValue props, Request& request)
{
String file_name, render_name;