diff --git a/crates/plugin_runtime/Cargo.toml b/crates/plugin_runtime/Cargo.toml index a145b12a19..87a93fb1f4 100644 --- a/crates/plugin_runtime/Cargo.toml +++ b/crates/plugin_runtime/Cargo.toml @@ -13,3 +13,6 @@ serde_json = "1.0" bincode = "1.3" pollster = "0.2.5" smol = "1.2.5" + +[build-dependencies] +wasmtime = "0.38.1" diff --git a/crates/plugin_runtime/build.rs b/crates/plugin_runtime/build.rs index a6f0db38ac..05bb65b2d8 100644 --- a/crates/plugin_runtime/build.rs +++ b/crates/plugin_runtime/build.rs @@ -1,4 +1,5 @@ -use std::path::Path; +use std::{io::Write, path::Path}; +use wasmtime::{Config, Engine}; fn main() { let base = Path::new("../../plugins"); @@ -28,6 +29,8 @@ fn main() { .expect("Could not find compiled plugins in target"); println!("cargo:warning={:?}", binaries); + let engine = create_engine(); + for file in binaries { let is_wasm = || { let path = file.ok()?.path(); @@ -39,11 +42,30 @@ fn main() { }; if let Some(path) = is_wasm() { - std::fs::copy(&path, base.join("bin").join(path.file_name().unwrap())) - .expect("Could not copy compiled plugin to bin"); + let out_path = base.join("bin").join(path.file_name().unwrap()); + std::fs::copy(&path, &out_path).expect("Could not copy compiled plugin to bin"); + precompile(&out_path, &engine); } } - - // TODO: create .wat versions - // TODO: optimize with wasm-opt +} + +fn create_engine() -> Engine { + let mut config = Config::default(); + config.async_support(true); + // config.epoch_interruption(true); + Engine::new(&config).expect("Could not create engine") +} + +fn precompile(path: &Path, engine: &Engine) { + let bytes = std::fs::read(path).expect("Could not read wasm module"); + let compiled = engine + .precompile_module(&bytes) + .expect("Could not precompile module"); + let out_path = path.parent().unwrap().join(&format!( + "{}.pre", + path.file_name().unwrap().to_string_lossy() + )); + let mut out_file = std::fs::File::create(out_path) + .expect("Could not create output file for precompiled module"); + out_file.write_all(&compiled).unwrap(); } diff --git a/crates/plugin_runtime/src/lib.rs b/crates/plugin_runtime/src/lib.rs index 12b1c3b4f4..c12b8e525a 100644 --- a/crates/plugin_runtime/src/lib.rs +++ b/crates/plugin_runtime/src/lib.rs @@ -51,7 +51,10 @@ mod tests { }) }) .unwrap() - .init(include_bytes!("../../../plugins/bin/test_plugin.wasm")) + .init( + false, + include_bytes!("../../../plugins/bin/test_plugin.wasm"), + ) .await .unwrap(); diff --git a/crates/plugin_runtime/src/plugin.rs b/crates/plugin_runtime/src/plugin.rs index 2d2cab35f1..ac97569a50 100644 --- a/crates/plugin_runtime/src/plugin.rs +++ b/crates/plugin_runtime/src/plugin.rs @@ -231,9 +231,9 @@ impl PluginBuilder { /// Initializes a [`Plugin`] from a given compiled Wasm module. /// Both binary (`.wasm`) and text (`.wat`) module formats are supported. - pub async fn init>(self, module: T) -> Result { + pub async fn init>(self, precompiled: bool, module: T) -> Result { dbg!("initializing plugin"); - Plugin::init(module.as_ref().to_vec(), self).await + Plugin::init(precompiled, module.as_ref().to_vec(), self).await } } @@ -297,7 +297,11 @@ impl Plugin { } impl Plugin { - async fn init(module: Vec, plugin: PluginBuilder) -> Result { + async fn init( + precompiled: bool, + module: Vec, + plugin: PluginBuilder, + ) -> Result { dbg!("Initializing new plugin"); // initialize the WebAssembly System Interface context let engine = plugin.engine; @@ -314,7 +318,11 @@ impl Plugin { }, ); // store.epoch_deadline_async_yield_and_update(todo!()); - let module = Module::new(&engine, module)?; + let module = if precompiled { + unsafe { Module::deserialize(&engine, module)? } + } else { + Module::new(&engine, module)? + }; // load the provided module into the asynchronous runtime linker.module_async(&mut store, "", &module).await?; diff --git a/crates/zed/src/languages/language_plugin.rs b/crates/zed/src/languages/language_plugin.rs index 6c07fc7042..fe74d7d9eb 100644 --- a/crates/zed/src/languages/language_plugin.rs +++ b/crates/zed/src/languages/language_plugin.rs @@ -21,7 +21,10 @@ pub async fn new_json(executor: Arc) -> Result { .log_err() .map(|output| output.stdout) })? - .init(include_bytes!("../../../../plugins/bin/json_language.wasm")) + .init( + true, + include_bytes!("../../../../plugins/bin/json_language.wasm.pre"), + ) .await?; PluginLspAdapter::new(plugin, executor).await }