Skip to content

Commit

Permalink
feature: use the stdout as the output of console.log .
Browse files Browse the repository at this point in the history
  • Loading branch information
Joinhack committed Aug 23, 2024
1 parent 71cac08 commit f96beef
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 32 deletions.
1 change: 1 addition & 0 deletions crates/cli/benches/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl FunctionCase {
Ok(function_case)
}

#[allow(clippy::needless_borrows_for_generic_args)]
pub fn run(&self, linker: &mut Linker<WasiCtx>, mut store: &mut Store<WasiCtx>) -> Result<()> {
let js_module = match &self.precompiled_elf_bytes {
Some(bytes) => unsafe { Module::deserialize(&self.engine, bytes) }?,
Expand Down
3 changes: 3 additions & 0 deletions crates/cli/src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fn create_wasm_env() -> Result<(Store<WasiCtx>, Instance, Memory)> {
Ok((store, instance, memory))
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn copy_source_code_into_instance(
js_source_code: &[u8],
mut store: &mut Store<WasiCtx>,
Expand All @@ -48,6 +49,7 @@ fn copy_source_code_into_instance(
Ok((js_source_ptr, js_src_len))
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn call_compile(
js_src_ptr: u32,
js_src_len: u32,
Expand All @@ -61,6 +63,7 @@ fn call_compile(
Ok(ret_ptr)
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn copy_bytecode_from_instance(
ret_ptr: u32,
mut store: &mut Store<WasiCtx>,
Expand Down
38 changes: 26 additions & 12 deletions crates/cli/tests/dylib_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod common;
fn test_dylib() -> Result<()> {
let js_src = "console.log(42);";
let stderr = WritePipe::new_in_memory();
run_js_src(js_src, &stderr)?;
run_js_src(js_src, &stderr, false)?;

let output = stderr.try_into_inner().unwrap().into_inner();
assert_eq!("42\n", str::from_utf8(&output)?);
Expand All @@ -23,7 +23,7 @@ fn test_dylib() -> Result<()> {
fn test_dylib_with_error() -> Result<()> {
let js_src = "function foo() { throw new Error('foo error'); } foo();";
let stderr = WritePipe::new_in_memory();
let result = run_js_src(js_src, &stderr);
let result = run_js_src(js_src, &stderr, true);

assert!(result.is_err());
let output = stderr.try_into_inner().unwrap().into_inner();
Expand All @@ -37,17 +37,21 @@ fn test_dylib_with_error() -> Result<()> {
#[test]
fn test_dylib_with_exported_func() -> Result<()> {
let js_src = "export function foo() { console.log('In foo'); }; console.log('Toplevel');";
let stderr = WritePipe::new_in_memory();
run_invoke(js_src, "foo", &stderr)?;
let stdout = WritePipe::new_in_memory();
run_invoke(js_src, "foo", &stdout)?;

let output = stderr.try_into_inner().unwrap().into_inner();
let output = stdout.try_into_inner().unwrap().into_inner();
assert_eq!("Toplevel\nIn foo\n", str::from_utf8(&output)?);

Ok(())
}

fn run_js_src<T: WasiFile + Clone + 'static>(js_src: &str, stderr: &T) -> Result<()> {
let (instance, mut store) = create_wasm_env(stderr)?;
fn run_js_src<T: WasiFile + Clone + 'static>(
js_src: &str,
stderr: &T,
is_stderr: bool,
) -> Result<()> {
let (instance, mut store) = create_wasm_env(stderr, is_stderr)?;

let eval_bytecode_func =
instance.get_typed_func::<(u32, u32), ()>(&mut store, "eval_bytecode")?;
Expand All @@ -59,9 +63,9 @@ fn run_js_src<T: WasiFile + Clone + 'static>(js_src: &str, stderr: &T) -> Result
fn run_invoke<T: WasiFile + Clone + 'static>(
js_src: &str,
fn_to_invoke: &str,
stderr: &T,
stdout: &T,
) -> Result<()> {
let (instance, mut store) = create_wasm_env(stderr)?;
let (instance, mut store) = create_wasm_env(stdout, false)?;

let invoke_func = instance.get_typed_func::<(u32, u32, u32, u32), ()>(&mut store, "invoke")?;
let (bytecode_ptr, bytecode_len) = compile_src(js_src.as_bytes(), &instance, &mut store)?;
Expand All @@ -75,13 +79,20 @@ fn run_invoke<T: WasiFile + Clone + 'static>(

fn create_wasm_env<T: WasiFile + Clone + 'static>(
stderr: &T,
is_stderr: bool,
) -> Result<(Instance, Store<WasiCtx>)> {
let engine = Engine::default();
let mut linker = Linker::new(&engine);
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
let wasi = WasiCtxBuilder::new()
.stderr(Box::new(stderr.clone()))
.build();
let wasi = if is_stderr {
WasiCtxBuilder::new()
.stderr(Box::new(stderr.clone()))
.build()
} else {
WasiCtxBuilder::new()
.stdout(Box::new(stderr.clone()))
.build()
};
let module = common::create_quickjs_provider_module(&engine)?;

let mut store = Store::new(&engine, wasi);
Expand All @@ -90,6 +101,7 @@ fn create_wasm_env<T: WasiFile + Clone + 'static>(
Ok((instance, store))
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn compile_src(
js_src: &[u8],
instance: &Instance,
Expand All @@ -110,6 +122,7 @@ fn compile_src(
Ok((bytecode_ptr, bytecode_len))
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn copy_func_name(
fn_name: &str,
instance: &Instance,
Expand All @@ -123,6 +136,7 @@ fn copy_func_name(
Ok((fn_name_ptr, fn_name_bytes.len().try_into()?))
}

#[allow(clippy::needless_borrows_for_generic_args)]
fn allocate_memory(
instance: &Instance,
mut store: &mut Store<WasiCtx>,
Expand Down
23 changes: 15 additions & 8 deletions crates/cli/tests/dynamic_linking_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod common;
#[test]
pub fn test_dynamic_linking() -> Result<()> {
let js_src = "console.log(42);";
let log_output = invoke_fn_on_generated_module(js_src, "_start", None)?;
let log_output = invoke_fn_on_generated_module(js_src, "_start", None, false)?;
assert_eq!("42\n", &log_output);
Ok(())
}
Expand All @@ -28,15 +28,16 @@ pub fn test_dynamic_linking_with_func() -> Result<()> {
export foo-bar: func()
}
";
let log_output = invoke_fn_on_generated_module(js_src, "foo-bar", Some((wit, "foo-test")))?;
let log_output =
invoke_fn_on_generated_module(js_src, "foo-bar", Some((wit, "foo-test")), false)?;
assert_eq!("Toplevel\nIn foo\n", &log_output);
Ok(())
}

#[test]
pub fn test_dynamic_linking_with_func_without_flag() -> Result<()> {
let js_src = "export function foo() { console.log('In foo'); }; console.log('Toplevel');";
let res = invoke_fn_on_generated_module(js_src, "foo", None);
let res = invoke_fn_on_generated_module(js_src, "foo", None, true);
assert_eq!(
"failed to find function export `foo`",
res.err().unwrap().to_string()
Expand All @@ -49,7 +50,7 @@ pub fn check_for_new_imports() -> Result<()> {
// If you need to change this test, then you've likely made a breaking change.
let js_src = "console.log(42);";
let wasm = create_dynamically_linked_wasm_module(js_src, None)?;
let (engine, _linker, _store) = create_wasm_env(WritePipe::new_in_memory())?;
let (engine, _linker, _store) = create_wasm_env(WritePipe::new_in_memory(), false)?;
let module = Module::from_binary(&engine, &wasm)?;
for import in module.imports() {
match (import.module(), import.name(), import.ty()) {
Expand Down Expand Up @@ -78,7 +79,7 @@ pub fn check_for_new_imports_for_exports() -> Result<()> {
}
";
let wasm = create_dynamically_linked_wasm_module(js_src, Some((wit, "foo-test")))?;
let (engine, _linker, _store) = create_wasm_env(WritePipe::new_in_memory())?;
let (engine, _linker, _store) = create_wasm_env(WritePipe::new_in_memory(), false)?;
let module = Module::from_binary(&engine, &wasm)?;
for import in module.imports() {
match (import.module(), import.name(), import.ty()) {
Expand Down Expand Up @@ -110,7 +111,7 @@ pub fn test_dynamic_linking_with_arrow_fn() -> Result<()> {
}
";
let log_output =
invoke_fn_on_generated_module(js_src, "default", Some((wit, "exported-arrow")))?;
invoke_fn_on_generated_module(js_src, "default", Some((wit, "exported-arrow")), false)?;
assert_eq!("42\n", log_output);
Ok(())
}
Expand Down Expand Up @@ -166,11 +167,12 @@ fn invoke_fn_on_generated_module(
js_src: &str,
func: &str,
wit: Option<(&str, &str)>,
is_stderr: bool,
) -> Result<String> {
let js_wasm = create_dynamically_linked_wasm_module(js_src, wit)?;

let stderr = WritePipe::new_in_memory();
let (engine, mut linker, mut store) = create_wasm_env(stderr.clone())?;
let (engine, mut linker, mut store) = create_wasm_env(stderr.clone(), is_stderr)?;
let quickjs_provider_module = common::create_quickjs_provider_module(&engine)?;
let js_module = Module::from_binary(&engine, &js_wasm)?;

Expand All @@ -192,11 +194,16 @@ fn invoke_fn_on_generated_module(

fn create_wasm_env(
stderr: WritePipe<Cursor<Vec<u8>>>,
is_stderr: bool,
) -> Result<(Engine, Linker<WasiCtx>, Store<WasiCtx>)> {
let engine = Engine::new(Config::new().wasm_multi_memory(true))?;
let mut linker = Linker::new(&engine);
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
let wasi = WasiCtxBuilder::new().stderr(Box::new(stderr)).build();
let wasi = if is_stderr {
WasiCtxBuilder::new().stderr(Box::new(stderr)).build()
} else {
WasiCtxBuilder::new().stdout(Box::new(stderr)).build()
};
let store = Store::new(&engine, wasi);
Ok((engine, linker, store))
}
20 changes: 14 additions & 6 deletions crates/cli/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ fn test_encoding() {
fn test_logging() {
let mut runner = Runner::new("logging.js");

let (_output, logs, fuel_consumed) = run(&mut runner, &[]);
let (output, logs, fuel_consumed) = run_fn(&mut runner, "_start", &[]);
let mut output = String::from_utf8(output).unwrap();
output.push_str(&logs);
assert_eq!(
"hello world from console.log\nhello world from console.error\n",
logs.as_str(),
output.as_str(),
);
assert_fuel_consumed_within_threshold(22_296, fuel_consumed);
}
Expand Down Expand Up @@ -104,10 +106,10 @@ fn test_promises() {
#[test]
fn test_exported_functions() {
let mut runner = Runner::new_with_exports("exported-fn.js", "exported-fn.wit", "exported-fn");
let (_, logs, fuel_consumed) = run_fn(&mut runner, "foo", &[]);
let (logs, _, fuel_consumed) = run_fn_stdout(&mut runner, "foo", &[]);
assert_eq!("Hello from top-level\nHello from foo\n", logs);
assert_fuel_consumed_within_threshold(54610, fuel_consumed);
let (_, logs, _) = run_fn(&mut runner, "foo-bar", &[]);
let (logs, _, _) = run_fn_stdout(&mut runner, "foo-bar", &[]);
assert_eq!("Hello from top-level\nHello from fooBar\n", logs);
}

Expand Down Expand Up @@ -178,7 +180,7 @@ fn test_exported_default_arrow_fn() {
"exported-default-arrow-fn.wit",
"exported-arrow",
);
let (_, logs, fuel_consumed) = run_fn(&mut runner, "default", &[]);
let (logs, _, fuel_consumed) = run_fn_stdout(&mut runner, "default", &[]);
assert_eq!(logs, "42\n");
assert_fuel_consumed_within_threshold(48_628, fuel_consumed);
}
Expand All @@ -190,7 +192,7 @@ fn test_exported_default_fn() {
"exported-default-fn.wit",
"exported-default",
);
let (_, logs, fuel_consumed) = run_fn(&mut runner, "default", &[]);
let (logs, _, fuel_consumed) = run_fn_stdout(&mut runner, "default", &[]);
assert_eq!(logs, "42\n");
assert_fuel_consumed_within_threshold(49_748, fuel_consumed);
}
Expand All @@ -211,6 +213,12 @@ fn run_fn(r: &mut Runner, func: &str, stdin: &[u8]) -> (Vec<u8>, String, u64) {
(output, logs, fuel_consumed)
}

fn run_fn_stdout(r: &mut Runner, func: &str, stdin: &[u8]) -> (String, Vec<u8>, u64) {
let (output, logs, fuel_consumed) = r.exec_func(func, stdin).unwrap();
let output = String::from_utf8(output).unwrap();
(output, logs, fuel_consumed)
}

/// Used to detect any significant changes in the fuel consumption when making changes in Javy.
///
/// A threshold is used here so that we can decide how much of a change is acceptable. The threshold value needs to be sufficiently large enough to account for fuel differences between different operating systems.
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ use javy_apis::{APIConfig, LogStream, RuntimeExt};

pub(crate) fn new_runtime() -> Result<Runtime> {
let mut api_config = APIConfig::default();
api_config.log_stream(LogStream::StdErr);
api_config.log_stream(LogStream::StdOut);
Runtime::new_with_apis(Config::default(), api_config)
}
4 changes: 2 additions & 2 deletions crates/javy/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ const ZERO_SIZE_ALLOCATION_PTR: *mut u8 = 1 as _;
///
/// 1. Allocate memory of new_size with alignment.
/// 2. If original_ptr != 0.
/// a. copy min(new_size, original_size) bytes from original_ptr to new memory.
/// b. de-allocate original_ptr.
/// a. copy min(new_size, original_size) bytes from original_ptr to new memory.
/// b. de-allocate original_ptr.
/// 3. Return new memory ptr.
///
/// # Safety
Expand Down
6 changes: 3 additions & 3 deletions crates/quickjs-wasm-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@
//! serialization formats and `JSValueRef`:
//! - `messagepack` provides `quickjs_wasm_rs::messagepack` for msgpack, using `rmp_serde`.
//! - `json` provides `quickjs_wasm_rs::json` for JSON, using `serde_json`.
//! msgpack example:
//!
//! msgpack example:
//!
//! ```rust
//! use quickjs_wasm_rs::{messagepack, JSContextRef, JSValueRef};
Expand Down

0 comments on commit f96beef

Please sign in to comment.