Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
453 changes: 247 additions & 206 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ license = "Apache-2.0 WITH LLVM-exception"
[workspace.dependencies]
brotli = "8.0.2"
clap = { version = "4.5.53", features = ["derive"] }
wizer = "10.0.0"
wasmtime = "36"
wasmtime-wasi = "36"
wasmtime = "39"
wasmtime-wasi = "39"
wasmtime-wizer = "39"
wasm-opt = "0.116.1"
anyhow = "1.0"
javy = { path = "crates/javy", version = "6.0.1-alpha.1" }
tempfile = "3.23.0"
tokio = "1"
uuid = { version = "1.18", features = ["v4"] }
serde = { version = "1.0", default-features = false }
serde_json = "1.0"
Expand Down
2 changes: 2 additions & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ anyhow = { workspace = true }
wasmtime = { workspace = true }
walrus = { workspace = true }
tempfile = { workspace = true }
tokio = { workspace = true, features = ["macros"] }
clap = { workspace = true }
serde = { workspace = true, default-features = false }
serde_json = { workspace = true }
Expand All @@ -32,3 +33,4 @@ wit-component = "0.242.0"
anyhow = { workspace = true }
javy-plugin-processing = { path = "../plugin-processing" }
tempfile = { workspace = true }
tokio = { workspace = true, features = ["macros"] }
10 changes: 6 additions & 4 deletions crates/cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ use std::path::{Path, PathBuf};

use anyhow::Result;

fn main() -> Result<()> {
#[tokio::main]
async fn main() -> Result<()> {
if let Ok("cargo-clippy") = env::var("CARGO_CFG_FEATURE").as_ref().map(String::as_str) {
stub_plugin_for_clippy()
} else {
copy_plugin()
copy_plugin().await
}
}

Expand All @@ -27,7 +28,7 @@ fn stub_plugin_for_clippy() -> Result<()> {
}

// Copy the plugin binary build from the `plugin` crate
fn copy_plugin() -> Result<()> {
async fn copy_plugin() -> Result<()> {
let cargo_manifest_dir = env::var("CARGO_MANIFEST_DIR")?;
let module_path = PathBuf::from(&cargo_manifest_dir)
.parent()
Expand All @@ -38,7 +39,8 @@ fn copy_plugin() -> Result<()> {
let plugin_path = module_path.join("plugin.wasm");
let plugin_wizened_path = module_path.join("plugin_wizened.wasm");

let initialized_plugin = javy_plugin_processing::initialize_plugin(&fs::read(&plugin_path)?)?;
let initialized_plugin =
javy_plugin_processing::initialize_plugin(&fs::read(&plugin_path)?).await?;
fs::write(&plugin_wizened_path, &initialized_plugin)?;

println!("cargo:rerun-if-changed={}", plugin_path.to_str().unwrap());
Expand Down
7 changes: 4 additions & 3 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use std::fs;
use std::fs::File;
use std::io::Write;

fn main() -> Result<()> {
#[tokio::main]
async fn main() -> Result<()> {
let args = Cli::parse();

match &args.command {
Expand Down Expand Up @@ -54,7 +55,7 @@ fn main() -> Result<()> {
generator.linking(LinkingKind::Static);
};

let wasm = generator.generate(&js)?;
let wasm = generator.generate(&js).await?;

fs::write(&opts.output, wasm)?;
Ok(())
Expand All @@ -63,7 +64,7 @@ fn main() -> Result<()> {
let plugin_bytes = fs::read(&opts.plugin)?;

let uninitialized_plugin = UninitializedPlugin::new(&plugin_bytes)?;
let initialized_plugin_bytes = uninitialized_plugin.initialize()?;
let initialized_plugin_bytes = uninitialized_plugin.initialize().await?;

let mut out: Box<dyn Write> = match opts.out.as_ref() {
Some(path) => Box::new(File::create(path)?),
Expand Down
4 changes: 2 additions & 2 deletions crates/cli/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ impl<'a> UninitializedPlugin<'a> {
}

/// Initializes the plugin.
pub(crate) fn initialize(&self) -> Result<Vec<u8>> {
javy_plugin_processing::initialize_plugin(self.bytes)
pub(crate) async fn initialize(&self) -> Result<Vec<u8>> {
javy_plugin_processing::initialize_plugin(self.bytes).await
}

fn validate(plugin_bytes: &'a [u8]) -> Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ fn test_source_code_omitted(builder: &mut Builder) -> Result<()> {
fn test_init_plugin() -> Result<()> {
let engine = Engine::default();
let mut linker = Linker::new(&engine);
wasmtime_wasi::preview1::add_to_linker_sync(&mut linker, |s| s)?;
wasmtime_wasi::p1::add_to_linker_sync(&mut linker, |s| s)?;
let wasi = WasiCtxBuilder::new().build_p1();
let mut store = Store::new(&engine, wasi);

Expand Down
4 changes: 4 additions & 0 deletions crates/codegen/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed

- The `generate` method on `Generator` is now async.

## [3.0.0] - 2025-11-12

### Changed
Expand Down
5 changes: 3 additions & 2 deletions crates/codegen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "javy-codegen"
version = "3.0.1-alpha.1"
version = "4.0.0-alpha.1"
authors.workspace = true
edition.workspace = true
license.workspace = true
Expand All @@ -13,11 +13,11 @@ categories = ["wasm"]
plugin_internal = []

[dependencies]
wizer = { workspace = true }
anyhow = { workspace = true }
brotli = { workspace = true }
wasmtime = { workspace = true }
wasmtime-wasi = { workspace = true }
wasmtime-wizer = { workspace = true, features = ["wasmtime"] }
walrus = { workspace = true }
swc_core = { version = "49.0.0", features = [
"common_sourcemap",
Expand All @@ -32,4 +32,5 @@ wasmparser = { workspace = true }

[dev-dependencies]
insta = "1.44.3"
tokio = { workspace = true, features = ["macros"] }
wasmprinter = "0.242.0"
5 changes: 3 additions & 2 deletions crates/codegen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ Example usage:
use std::path::Path;
use javy_codegen::{Generator, LinkingKind, Plugin, JS};

fn main() {
#[tokio::main]
async fn main() {
// Load your target Javascript.
let js = JS::from_file(Path::new("example.js"));

Expand All @@ -30,6 +31,6 @@ fn main() {
generator.linking(LinkingKind::Static);

// Generate your Wasm module.
let wasm = generator.generate(&js)?;
let wasm = generator.generate(&js).await?;
}
```
59 changes: 26 additions & 33 deletions crates/codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
//! use std::path::Path;
//! use javy_codegen::{Generator, LinkingKind, Plugin, JS};
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Load your target Javascript.
//! let js = JS::from_file(Path::new("example.js"))?;
//!
Expand All @@ -52,7 +53,7 @@
//! generator.linking(LinkingKind::Static);
//!
//! // Generate your Wasm module.
//! let wasm = generator.generate(&js);
//! let wasm = generator.generate(&js).await?;
//!
//! Ok(())
//! }
Expand All @@ -70,7 +71,7 @@
//! unstable API's exposed by this future may break in the future without
//! notice.

use std::{fs, rc::Rc, sync::OnceLock};
use std::fs;

pub(crate) mod bytecode;
pub(crate) mod exports;
Expand All @@ -90,12 +91,11 @@ use walrus::{
DataId, DataKind, ExportItem, FunctionBuilder, FunctionId, LocalId, MemoryId, Module, ValType,
};
use wasm_opt::{OptimizationOptions, ShrinkLevel};
use wasmtime::{Config, Engine, Linker, Store};
use wasmtime_wasi::{WasiCtxBuilder, p2::pipe::MemoryInputPipe};
use wizer::{Linker, Wizer};

use anyhow::Result;

static STDIN_PIPE: OnceLock<MemoryInputPipe> = OnceLock::new();
use wasmtime_wizer::Wizer;

/// The kind of linking to use.
#[derive(Debug, Clone, Default)]
Expand Down Expand Up @@ -219,37 +219,30 @@ impl Generator {

impl Generator {
/// Generate the starting module.
fn generate_initial_module(&self) -> Result<Module> {
async fn generate_initial_module(&self) -> Result<Module> {
let config = transform::module_config();
let module = match &self.linking {
LinkingKind::Static => {
// Copy config JSON into stdin for `initialize-runtime` function.
STDIN_PIPE
.set(MemoryInputPipe::new(self.js_runtime_config.clone()))
.unwrap();
let mut cfg = Config::new();
cfg.async_support(true);
let engine = Engine::new(&cfg)?;
let wasi = WasiCtxBuilder::new()
.stdin(MemoryInputPipe::new(self.js_runtime_config.clone()))
.inherit_stdout()
.inherit_stderr()
.build_p1();
let mut store = Store::new(&engine, wasi);
let wasm = Wizer::new()
.init_func("initialize-runtime")
.make_linker(Some(Rc::new(move |engine| {
.run(&mut store, self.plugin.as_bytes(), async |store, module| {
let engine = store.engine();
let mut linker = Linker::new(engine);
wasmtime_wasi::preview1::add_to_linker_sync(&mut linker, move |cx| {
if cx.wasi_ctx.is_none() {
// The underlying buffer backing the pipe is an Arc
// so the cloning should be fast.
let config = STDIN_PIPE.get().unwrap().clone();
cx.wasi_ctx = Some(
WasiCtxBuilder::new()
.stdin(config)
.inherit_stdout()
.inherit_stderr()
.build_p1(),
);
}
cx.wasi_ctx.as_mut().unwrap()
})?;
Ok(linker)
})))?
.wasm_bulk_memory(true)
.run(self.plugin.as_bytes())?;
wasmtime_wasi::p1::add_to_linker_async(&mut linker, |cx| cx)?;
linker.define_unknown_imports_as_traps(module)?;
let instance = linker.instantiate_async(store, module).await?;
Ok(instance)
})
.await?;
config.parse(&wasm)?
}
LinkingKind::Dynamic => Module::with_config(config),
Expand Down Expand Up @@ -442,7 +435,7 @@ impl Generator {
}

/// Generate a Wasm module which will run the provided JS source code.
pub fn generate(&mut self, js: &js::JS) -> Result<Vec<u8>> {
pub async fn generate(&mut self, js: &js::JS) -> Result<Vec<u8>> {
if self.wit_opts.defined() {
self.function_exports = exports::process_exports(
js,
Expand All @@ -451,7 +444,7 @@ impl Generator {
)?;
}

let mut module = self.generate_initial_module()?;
let mut module = self.generate_initial_module().await?;
let identifiers = self.resolve_identifiers(&mut module)?;
let bc_metadata = self.generate_main(&mut module, js, &identifiers)?;
self.generate_exports(&mut module, &identifiers, &bc_metadata)?;
Expand Down
13 changes: 7 additions & 6 deletions crates/codegen/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::path::PathBuf;
use anyhow::Result;
use javy_codegen::{Generator, JS, LinkingKind, Plugin, WitOptions};

#[test]
fn test_empty() -> Result<()> {
#[tokio::test]
async fn test_empty() -> Result<()> {
// Load valid JS from file.
let js = JS::from_file(
&cargo_manifest_dir()
Expand All @@ -18,16 +18,16 @@ fn test_empty() -> Result<()> {
generator.linking(LinkingKind::Static);

// Generate valid Wasm module.
let wasm = generator.generate(&js)?;
let wasm = generator.generate(&js).await?;

// Verify generated bytes are valid Wasm.
walrus::Module::from_buffer(wasm.as_slice())?;

Ok(())
}

#[test]
fn test_snapshot_for_dynamically_linked_module() -> Result<()> {
#[tokio::test]
async fn test_snapshot_for_dynamically_linked_module() -> Result<()> {
let sample_scripts = sample_scripts_dir();
let js = JS::from_file(&sample_scripts.join("exported-functions.js"))?;
let wasm = Generator::new(default_plugin()?)
Expand All @@ -37,7 +37,8 @@ fn test_snapshot_for_dynamically_linked_module() -> Result<()> {
Some("exported-logs".into()),
))?)
.producer_version("snapshot".into())
.generate(&js)?;
.generate(&js)
.await?;
let wat = wasmprinter::print_bytes(wasm)?;
insta::assert_snapshot!("default_dynamic", wat);
Ok(())
Expand Down
4 changes: 3 additions & 1 deletion crates/plugin-processing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ categories = ["wasm"]
anyhow = { workspace = true }
clap = { workspace = true }
tempfile = { workspace = true }
tokio = { workspace = true, features = ["macros"] }
walrus = { workspace = true }
wasmparser = { workspace = true }
wasm-opt = { workspace = true }
wasmtime = { workspace = true }
wasmtime-wasi = { workspace = true }
wizer = { workspace = true }
wasmtime-wizer = { workspace = true, features = ["wasmtime"] }
Loading