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:
+67
-29
@@ -65,6 +65,51 @@ void clear_request_output(Request& request)
|
||||
request.ob_start();
|
||||
}
|
||||
|
||||
bool render_wasm_error_page(Request& request, String config_key, s32 status_code, String status_reason, DValue error_info)
|
||||
{
|
||||
if(!(request.params["REQUEST_METHOD"] != "" && request.ob && request.ob_stack.size() > 0))
|
||||
return(false);
|
||||
if(!request.server || request.resources.error_page_active)
|
||||
return(false);
|
||||
String unit_file = compiler_error_page_unit(&request, config_key);
|
||||
if(unit_file == "")
|
||||
return(false);
|
||||
|
||||
String previous_response_code = request.response_code;
|
||||
s32 previous_status = request.flags.status;
|
||||
String previous_content_type = request.header["Content-Type"];
|
||||
|
||||
request.resources.error_page_active = true;
|
||||
request.call["error"] = error_info;
|
||||
request.set_status(status_code, status_reason);
|
||||
request.header["Content-Type"] = first(request.server->config["CONTENT_TYPE"], "text/html; charset=utf-8");
|
||||
|
||||
String unit = compiler_normalize_unit_path(&request, unit_file);
|
||||
if(!wasm_backend_should_handle(request, unit))
|
||||
get_shared_unit(&request, unit, true);
|
||||
|
||||
ob_start();
|
||||
String wasm_error = "";
|
||||
if(wasm_backend_should_handle(request, unit))
|
||||
wasm_error = wasm_backend_serve(request, unit, "render");
|
||||
else
|
||||
wasm_error = "error page wasm unit unavailable after compile: " + unit_file;
|
||||
String html = ob_get_close();
|
||||
request.resources.error_page_active = false;
|
||||
|
||||
if(wasm_error != "")
|
||||
{
|
||||
printf("(!) configured %s page %s failed to render: %s\n", config_key.c_str(), unit_file.c_str(), trim(wasm_error).c_str());
|
||||
request.response_code = previous_response_code;
|
||||
request.flags.status = previous_status;
|
||||
request.header["Content-Type"] = previous_content_type;
|
||||
request.call.remove("error");
|
||||
return(false);
|
||||
}
|
||||
print(html);
|
||||
return(true);
|
||||
}
|
||||
|
||||
void render_request_failure(Request& request, String title, String details, String trace, int status_code = 500)
|
||||
{
|
||||
request.response_code = request_status_line(request, status_code, "Internal Server Error");
|
||||
@@ -92,7 +137,7 @@ void render_request_failure(Request& request, String title, String details, Stri
|
||||
error_info["signal_name"] = signal_name((int)request_fault_signal);
|
||||
}
|
||||
error_info["trace"] = trace;
|
||||
if(compiler_render_error_page(&request, "page_runtime_error", status_code, "Internal Server Error", error_info))
|
||||
if(render_wasm_error_page(request, "page_runtime_error", status_code, "Internal Server Error", error_info))
|
||||
{
|
||||
request.err = "UCE runtime error: " + title + (details != "" ? " (" + details + ")" : "");
|
||||
restore_active_request(previous_context);
|
||||
@@ -368,10 +413,9 @@ int handle_cli_complete(FastCGIRequest& request)
|
||||
// The CLI socket path installs no native fault handler, so the
|
||||
// wasm worker (whose traps are signal-based) can run directly.
|
||||
String cli_unit = compiler_normalize_unit_path(&request, script_filename);
|
||||
// W7e: compile a cold/stale unit on demand instead of executing
|
||||
// native. force_recompile: the compile-needed check ignores the
|
||||
// .wasm (keys off .so mtime), so a missing/stale .wasm with a
|
||||
// current .so must be forced to rebuild — see wasm_ready note.
|
||||
// W7e: compile a cold/stale unit on demand; native execution has
|
||||
// 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);
|
||||
if(wasm_backend_should_handle(request, cli_unit))
|
||||
@@ -384,7 +428,10 @@ int handle_cli_complete(FastCGIRequest& request)
|
||||
}
|
||||
}
|
||||
else
|
||||
compiler_invoke_cli(&request, script_filename);
|
||||
{
|
||||
request.set_status(500, "Internal Server Error");
|
||||
print("UCE CLI wasm unit unavailable after compile: ", script_filename, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -484,27 +531,21 @@ int handle_complete(FastCGIRequest& request) {
|
||||
|
||||
String entry_unit = compiler_normalize_unit_path(&request, request.params["SCRIPT_FILENAME"]);
|
||||
// W7e: every unit runs on wasm. When the artifact is missing or stale
|
||||
// (cold worker, or source edited since the last compile),
|
||||
// wasm_backend_should_handle() returns false; rather than fall back to
|
||||
// native execution we compile the unit on demand — get_shared_unit()
|
||||
// builds the .wasm side-module — and recheck. Native execution remains
|
||||
// only as a safety net for a genuine wasm-compile failure (or the wasm
|
||||
// backend being disabled), both of which leave should_handle() false.
|
||||
// Only reached on the cold/stale path (should_handle false); warm
|
||||
// requests short-circuit before this, so there is no steady-state
|
||||
// recompile cost. force_recompile is needed because the compile-needed
|
||||
// check keys off the .so mtime only (shared_unit_compile_check /
|
||||
// compiled_time ignores the .wasm), so an uncached unit with a current
|
||||
// .so but missing .wasm would otherwise not rebuild. NOTE: this does not
|
||||
// cover a unit already cached in-process whose .wasm later vanished
|
||||
// (compiler_reusable_cached_unit short-circuits before the recompile) —
|
||||
// that synthetic case still uses native fallback and is closed properly
|
||||
// in W7e stage B (make the .wasm part of the compile-freshness check).
|
||||
// (cold worker, or source edited since the last compile), compile the
|
||||
// unit on demand — get_shared_unit() builds the .wasm side-module — and
|
||||
// recheck. Native execution has been removed, so a unit that still cannot
|
||||
// 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);
|
||||
return(wasm_backend_should_handle(request, unit));
|
||||
};
|
||||
auto fail_wasm_unavailable = [&](const String& handler) {
|
||||
failure_title = "wasm unit unavailable after compile";
|
||||
failure_details = handler + " handler could not be served by wasm";
|
||||
failure_trace = "source: " + request.params["SCRIPT_FILENAME"];
|
||||
};
|
||||
|
||||
if(request.params["UCE_WS"] == "1")
|
||||
{
|
||||
// A WS message the broker forwarded here: rebuild the connection
|
||||
@@ -529,14 +570,14 @@ int handle_complete(FastCGIRequest& request) {
|
||||
if(wasm_ready(entry_unit))
|
||||
serve_via_wasm(entry_unit, "websocket");
|
||||
else
|
||||
compiler_invoke_websocket(&request, request.params["SCRIPT_FILENAME"]);
|
||||
fail_wasm_unavailable("websocket");
|
||||
}
|
||||
else if(request.resources.is_cli)
|
||||
{
|
||||
if(wasm_ready(entry_unit))
|
||||
serve_via_wasm(entry_unit, "cli");
|
||||
else
|
||||
compiler_invoke_cli(&request, request.params["SCRIPT_FILENAME"]);
|
||||
fail_wasm_unavailable("cli");
|
||||
}
|
||||
else if(request.params["UCE_SERVE_HTTP"] == "1")
|
||||
{
|
||||
@@ -549,12 +590,12 @@ int handle_complete(FastCGIRequest& request) {
|
||||
serve_via_wasm(entry_unit, fn == "" ? String("serve_http") : "serve_http:" + fn);
|
||||
}
|
||||
else
|
||||
compiler_invoke_serve_http(&request, request.params["SCRIPT_FILENAME"], request.params["UCE_SERVE_HTTP_FUNCTION"]);
|
||||
fail_wasm_unavailable("serve_http");
|
||||
}
|
||||
else if(wasm_ready(entry_unit))
|
||||
serve_via_wasm(entry_unit, "render");
|
||||
else
|
||||
compiler_invoke(&request, request.params["SCRIPT_FILENAME"]);
|
||||
fail_wasm_unavailable("render");
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
@@ -1270,9 +1311,6 @@ void init_base_process()
|
||||
server_state.config["COMPILER_SYS_PATH"] = cwd_get();
|
||||
printf("Compiler base path: %s\n", server_state.config["COMPILER_SYS_PATH"].c_str());
|
||||
|
||||
server_state.config["COMPILE_SCRIPT"] =
|
||||
server_state.config["COMPILER_SYS_PATH"] + "/" + server_state.config["COMPILE_SCRIPT"];
|
||||
|
||||
if(server_state.config["FCGI_PORT"] != "")
|
||||
server.listen(int_val(server_state.config["FCGI_PORT"]));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user