Pre-instantiate WASM core workers
This commit is contained in:
+79
-28
@@ -8,8 +8,7 @@
|
||||
//
|
||||
// Designed for amalgamation-include (like uce_lib.cpp): the including TU must
|
||||
// provide String/DValue/ucb_encode/ucb_decode (types.cpp + dvalue.cpp) and
|
||||
// wasm_trace.h. W4 includes this from the FastCGI worker build; the W3 CLI
|
||||
// driver (w3_driver.cpp) is the first consumer.
|
||||
// wasm_trace.h. The production FastCGI worker includes this through backend.cpp.
|
||||
//
|
||||
// Loader rules carried from the spike phases, now enforced as policy:
|
||||
// - import discipline: units may import only env / GOT.mem / GOT.func
|
||||
@@ -117,6 +116,14 @@ struct WasmUnitModuleLoadProfile
|
||||
u64 classify_us = 0;
|
||||
};
|
||||
|
||||
struct WasmInstancePreDeleter
|
||||
{
|
||||
void operator()(wasmtime_instance_pre_t* instance_pre) const
|
||||
{
|
||||
wasmtime_instance_pre_delete(instance_pre);
|
||||
}
|
||||
};
|
||||
|
||||
struct WasmWorkerConfig
|
||||
{
|
||||
String core_wasm_path = "bin/wasm/core.wasm";
|
||||
@@ -602,8 +609,8 @@ static bool uce_job_cancel_value(u64 id)
|
||||
|
||||
// ---- module byte parsing (hardened; carried from the phase 3 spike) -------
|
||||
|
||||
// included into both w3_driver.cpp and the native server TU (via backend.cpp);
|
||||
// file-scope helpers are static so each TU gets its own copy with no clash
|
||||
// Included into the native server TU through backend.cpp. File-scope helpers
|
||||
// remain static to keep their linkage local to the wasm backend object.
|
||||
static bool wasm_read_uleb(const std::vector<u8>& buf, size_t& pos, size_t end, u64& out)
|
||||
{
|
||||
out = 0;
|
||||
@@ -965,6 +972,7 @@ public:
|
||||
wasmtime::Engine engine;
|
||||
std::optional<wasmtime::Module> core_module;
|
||||
std::optional<wasmtime::Linker> core_linker;
|
||||
std::unique_ptr<wasmtime_instance_pre_t, WasmInstancePreDeleter> core_instance_pre;
|
||||
struct CoreImport
|
||||
{
|
||||
String module;
|
||||
@@ -1411,38 +1419,75 @@ public:
|
||||
return(error);
|
||||
worker.core_imports.push_back({ mod, name, false });
|
||||
}
|
||||
}
|
||||
if(!worker.core_table_imported)
|
||||
return("core does not import __indirect_function_table — rebuild core with --import-table");
|
||||
std::vector<wasmtime::Extern> imports;
|
||||
u32 total = worker.core_table_min + worker.cfg.table_headroom;
|
||||
wasmtime::TableType table_type(wasmtime::ValType::funcref(), total, total);
|
||||
auto table_created = wasmtime::Table::create(cx, table_type, wasmtime::Val(std::optional<wasmtime::Func>()));
|
||||
if(!table_created)
|
||||
return("table create failed: " + String(table_created.err().message()));
|
||||
table.emplace(table_created.ok());
|
||||
table_next_free = worker.core_table_min;
|
||||
for(auto& import : worker.core_imports)
|
||||
{
|
||||
if(import.table)
|
||||
if(!worker.core_table_imported)
|
||||
{
|
||||
imports.push_back(*table);
|
||||
continue;
|
||||
wasmtime_instance_pre_t* instance_pre = 0;
|
||||
wasmtime_error_t* pre_error = wasmtime_linker_instantiate_pre(
|
||||
worker.core_linker->capi(), module.capi(), &instance_pre);
|
||||
if(pre_error)
|
||||
return("core pre-instantiation failed: " + String(wasmtime::Error(pre_error).message()));
|
||||
worker.core_instance_pre.reset(instance_pre);
|
||||
}
|
||||
}
|
||||
std::vector<wasmtime::Extern> imports;
|
||||
if(worker.core_table_imported)
|
||||
{
|
||||
u32 total = worker.core_table_min + worker.cfg.table_headroom;
|
||||
wasmtime::TableType table_type(wasmtime::ValType::funcref(), total, total);
|
||||
auto table_created = wasmtime::Table::create(cx, table_type, wasmtime::Val(std::optional<wasmtime::Func>()));
|
||||
if(!table_created)
|
||||
return("table create failed: " + String(table_created.err().message()));
|
||||
table.emplace(table_created.ok());
|
||||
table_next_free = worker.core_table_min;
|
||||
for(auto& import : worker.core_imports)
|
||||
{
|
||||
if(import.table)
|
||||
{
|
||||
imports.push_back(*table);
|
||||
continue;
|
||||
}
|
||||
auto host_import = worker.core_linker->get(cx, import.module, import.name);
|
||||
if(!host_import)
|
||||
return("core host import unavailable: " + import.module + "." + import.name);
|
||||
imports.push_back(*host_import);
|
||||
}
|
||||
auto host_import = worker.core_linker->get(cx, import.module, import.name);
|
||||
if(!host_import)
|
||||
return("core host import unavailable: " + import.module + "." + import.name);
|
||||
imports.push_back(*host_import);
|
||||
}
|
||||
hostcall_operation_slots = worker.hostcall_operation_names.size();
|
||||
birth_import_us = phase_us();
|
||||
|
||||
auto created = wasmtime::Instance::create(cx, module, imports);
|
||||
if(!created)
|
||||
return("core instantiation failed: " + trap_text(created.err()));
|
||||
core.emplace(created.ok());
|
||||
if(worker.core_instance_pre)
|
||||
{
|
||||
wasmtime_instance_t instance;
|
||||
wasm_trap_t* trap = 0;
|
||||
wasmtime_error_t* instantiate_error = wasmtime_instance_pre_instantiate(
|
||||
worker.core_instance_pre.get(), cx.capi(), &instance, &trap);
|
||||
if(instantiate_error)
|
||||
return("core instantiation failed: " + String(wasmtime::Error(instantiate_error).message()));
|
||||
if(trap)
|
||||
return("core instantiation trapped: " + String(wasmtime::Trap(trap).message()));
|
||||
core.emplace(instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto created = wasmtime::Instance::create(cx, module, imports);
|
||||
if(!created)
|
||||
return("core instantiation failed: " + trap_text(created.err()));
|
||||
core.emplace(created.ok());
|
||||
}
|
||||
birth_instantiate_us = phase_us();
|
||||
|
||||
if(!table)
|
||||
{
|
||||
auto exported_table = core->get(cx, "__indirect_function_table");
|
||||
if(!exported_table || !std::get_if<wasmtime::Table>(&*exported_table))
|
||||
return("core does not export __indirect_function_table");
|
||||
table.emplace(std::get<wasmtime::Table>(*exported_table));
|
||||
auto grown = table->grow(cx, worker.cfg.table_headroom, wasmtime::Val(std::optional<wasmtime::Func>()));
|
||||
if(!grown)
|
||||
return("table grow failed: " + String(grown.err().message()));
|
||||
table_next_free = (u32)grown.ok();
|
||||
}
|
||||
|
||||
auto exported_memory = core->get(cx, "memory");
|
||||
if(!exported_memory || !std::get_if<wasmtime::Memory>(&*exported_memory))
|
||||
return("core does not export memory");
|
||||
@@ -3706,6 +3751,12 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
inline String wasm_worker_prepare(WasmWorker& worker)
|
||||
{
|
||||
WasmWorkspace workspace(worker);
|
||||
return(workspace.birth());
|
||||
}
|
||||
|
||||
// ---- public entry: one request through one workspace -----------------------
|
||||
|
||||
inline WasmResponse wasm_worker_serve(WasmWorker& worker, const DValue& context_tree, const String& entry_source_path,
|
||||
|
||||
Reference in New Issue
Block a user