diff --git a/src/wasm/worker.cpp b/src/wasm/worker.cpp index 9bbcdb4..0478472 100644 --- a/src/wasm/worker.cpp +++ b/src/wasm/worker.cpp @@ -249,53 +249,12 @@ public: if(!wasm_parse_sections(bytes, core_dylink, abi_ignored, parse_error)) return("core module: " + parse_error); - String core_cached_path = cfg.core_wasm_path; - if(core_cached_path.size() >= 5 && core_cached_path.rfind(".wasm", core_cached_path.size() - 5) == core_cached_path.size() - 5) - core_cached_path = core_cached_path.substr(0, core_cached_path.size() - 5) + ".cwasm"; - else - core_cached_path += ".cwasm"; - struct stat core_stat; - struct stat cached_stat; - if(stat(core_cached_path.c_str(), &cached_stat) == 0 && stat(cfg.core_wasm_path.c_str(), &core_stat) == 0) - { - if(cached_stat.st_mtime > core_stat.st_mtime) - { - auto deserialized = wasmtime::Module::deserialize_file(engine, core_cached_path); - if(deserialized) - { - core_module.emplace(deserialized.ok()); - return(""); - } - } - } - - auto compiled = wasmtime::Module::compile(engine, bytes); - if(!compiled) - return("core module compile failed: " + String(compiled.err().message())); - core_module.emplace(compiled.ok()); - - auto serialized = core_module->serialize(); - if(serialized) - { - String tmp = core_cached_path + "." + std::to_string((long long)getpid()) + ".tmp"; - auto data = serialized.ok(); - { - std::ofstream out(tmp, std::ios::binary | std::ios::trunc); - if(out) - { - out.write((const char*)data.data(), (std::streamsize)data.size()); - if(out) - { - out.flush(); - out.close(); - if(std::rename(tmp.c_str(), core_cached_path.c_str()) != 0) - (void)std::remove(tmp.c_str()); - } - } - else - (void)std::remove(tmp.c_str()); - } - } + String core_cached_path = cached_wasm_path(cfg.core_wasm_path); + String compile_error; + auto compiled_or_cached = load_or_compile_cached_module(engine, core_cached_path, cfg.core_wasm_path, bytes, compile_error); + if(!compiled_or_cached) + return("core module compile failed: " + compile_error); + core_module.emplace(std::move(*compiled_or_cached)); return(""); } @@ -347,18 +306,74 @@ public: error = wasm_path + ": missing uce.abi stamp"; return(nullptr); } - auto compiled = wasmtime::Module::compile(engine, bytes); - if(!compiled) + String unit_cached_path = cached_wasm_path(wasm_path); + String compile_error; + auto compiled_or_cached = load_or_compile_cached_module(engine, unit_cached_path, wasm_path, bytes, compile_error); + if(!compiled_or_cached) { - error = wasm_path + ": compile failed: " + String(compiled.err().message()); + error = wasm_path + ": compile failed: " + compile_error; return(nullptr); } - unit->module.emplace(compiled.ok()); + unit->module.emplace(std::move(*compiled_or_cached)); module_cache[wasm_path] = unit; return(unit); } private: + static String cached_wasm_path(const String& wasm_path) + { + if(wasm_path.size() >= 5 && wasm_path.rfind(".wasm", wasm_path.size() - 5) == wasm_path.size() - 5) + return(wasm_path.substr(0, wasm_path.size() - 5) + ".cwasm"); + return(wasm_path + ".cwasm"); + } + + static std::optional load_or_compile_cached_module(wasmtime::Engine& engine, const String& cached_path, const String& wasm_path, + std::vector& bytes, String& compile_error) + { + struct stat wasm_stat; + struct stat cached_stat; + if(stat(cached_path.c_str(), &cached_stat) == 0 && stat(wasm_path.c_str(), &wasm_stat) == 0) + { + if(cached_stat.st_mtime > wasm_stat.st_mtime) + { + auto deserialized = wasmtime::Module::deserialize_file(engine, cached_path); + if(deserialized) + return(deserialized.ok()); + } + } + + auto compiled = wasmtime::Module::compile(engine, bytes); + if(!compiled) + { + compile_error = String(compiled.err().message()); + return(std::nullopt); + } + auto result = compiled.ok(); + auto serialized = result.serialize(); + if(serialized) + { + String tmp = cached_path + "." + std::to_string((long long)getpid()) + ".tmp"; + auto data = serialized.ok(); + { + std::ofstream out(tmp, std::ios::binary | std::ios::trunc); + if(out) + { + out.write((const char*)data.data(), (std::streamsize)data.size()); + if(out) + { + out.flush(); + out.close(); + if(std::rename(tmp.c_str(), cached_path.c_str()) != 0) + (void)std::remove(tmp.c_str()); + } + } + else + (void)std::remove(tmp.c_str()); + } + } + return(result); + } + static wasmtime::Engine make_engine() { wasmtime::Config config;