From 7fa858f6ec947b55ed06eadf0e07379bf623b266 Mon Sep 17 00:00:00 2001 From: Jeffrey Charles Date: Mon, 7 Oct 2024 17:24:14 -0400 Subject: [PATCH] Have provider `invoke` fn support not being given a function name (#776) * Make provider `invoke` fn support not being given a name * PR feedback --- crates/cli/tests/dylib_test.rs | 19 +++++++++++++++---- crates/core/src/lib.rs | 13 ++++++++----- crates/runner/src/lib.rs | 34 ++++++++++++++++++++-------------- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/crates/cli/tests/dylib_test.rs b/crates/cli/tests/dylib_test.rs index a1ed9f99..7fb0415c 100644 --- a/crates/cli/tests/dylib_test.rs +++ b/crates/cli/tests/dylib_test.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use javy_runner::{Runner, RunnerError}; +use javy_runner::{Runner, RunnerError, UseExportedFn}; use std::path::{Path, PathBuf}; use std::str; @@ -10,7 +10,18 @@ fn test_dylib() -> Result<()> { let js_src = "console.log(42);"; let mut runner = Runner::with_dylib(provider_module()?)?; - let (_, logs, _) = runner.exec_through_dylib(js_src, None)?; + let (_, logs, _) = runner.exec_through_dylib(js_src, UseExportedFn::EvalBytecode)?; + assert_eq!("42\n", str::from_utf8(&logs)?); + + Ok(()) +} + +#[test] +fn test_dylib_with_invoke_with_no_fn_name() -> Result<()> { + let js_src = "console.log(42);"; + let mut runner = Runner::with_dylib(provider_module()?)?; + + let (_, logs, _) = runner.exec_through_dylib(js_src, UseExportedFn::Invoke(None))?; assert_eq!("42\n", str::from_utf8(&logs)?); Ok(()) @@ -22,7 +33,7 @@ fn test_dylib_with_error() -> Result<()> { let mut runner = Runner::with_dylib(provider_module()?)?; - let res = runner.exec_through_dylib(js_src, None); + let res = runner.exec_through_dylib(js_src, UseExportedFn::EvalBytecode); assert!(res.is_err()); @@ -42,7 +53,7 @@ fn test_dylib_with_exported_func() -> Result<()> { let mut runner = Runner::with_dylib(provider_module()?)?; - let (_, logs, _) = runner.exec_through_dylib(js_src, Some("foo"))?; + let (_, logs, _) = runner.exec_through_dylib(js_src, UseExportedFn::Invoke(Some("foo")))?; assert_eq!("Toplevel\nIn foo\n", str::from_utf8(&logs)?); Ok(()) diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 0685731d..38a98779 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -71,14 +71,15 @@ pub unsafe extern "C" fn eval_bytecode(bytecode_ptr: *const u8, bytecode_len: us execution::run_bytecode(runtime, bytecode); } -/// Evaluates QuickJS bytecode and invokes the exported JS function name. +/// Evaluates QuickJS bytecode and optionally invokes exported JS function with +/// name. /// /// # Safety /// /// * `bytecode_ptr` must reference a valid array of bytes of `bytecode_len` /// length. -/// * `fn_name_ptr` must reference a UTF-8 string with `fn_name_len` byte -/// length. +/// * If `fn_name_ptr` is not 0, it must reference a UTF-8 string with +/// `fn_name_len` byte length. #[export_name = "invoke"] pub unsafe extern "C" fn invoke( bytecode_ptr: *const u8, @@ -88,7 +89,9 @@ pub unsafe extern "C" fn invoke( ) { let runtime = RUNTIME.get().unwrap(); let bytecode = slice::from_raw_parts(bytecode_ptr, bytecode_len); - let fn_name = str::from_utf8_unchecked(slice::from_raw_parts(fn_name_ptr, fn_name_len)); execution::run_bytecode(runtime, bytecode); - execution::invoke_function(runtime, FUNCTION_MODULE_NAME, fn_name); + if !fn_name_ptr.is_null() && fn_name_len != 0 { + let fn_name = str::from_utf8_unchecked(slice::from_raw_parts(fn_name_ptr, fn_name_len)); + execution::invoke_function(runtime, FUNCTION_MODULE_NAME, fn_name); + } } diff --git a/crates/runner/src/lib.rs b/crates/runner/src/lib.rs index 805a15d2..f3cda8b3 100644 --- a/crates/runner/src/lib.rs +++ b/crates/runner/src/lib.rs @@ -251,6 +251,11 @@ impl StoreContext { } } +pub enum UseExportedFn { + EvalBytecode, + Invoke(Option<&'static str>), +} + impl Runner { #[allow(clippy::too_many_arguments)] fn build( @@ -659,26 +664,27 @@ impl Runner { pub fn exec_through_dylib( &mut self, src: &str, - named: Option<&'static str>, + use_exported_fn: UseExportedFn, ) -> Result<(Vec, Vec, u64)> { let mut store = Self::setup_store(self.linker.engine(), &[])?; let module = Module::from_binary(self.linker.engine(), &self.wasm)?; let instance = self.linker.instantiate(store.as_context_mut(), &module)?; - let res = if let Some(invoke) = named { - let invoke_fn = instance - .get_typed_func::<(u32, u32, u32, u32), ()>(store.as_context_mut(), "invoke")?; - let (bc_ptr, bc_len) = - Self::compile(src.as_bytes(), store.as_context_mut(), &instance)?; - let (ptr, len) = Self::copy_func_name(invoke, &instance, store.as_context_mut())?; - - invoke_fn.call(store.as_context_mut(), (bc_ptr, bc_len, ptr, len)) - } else { - let eval = instance - .get_typed_func::<(u32, u32), ()>(store.as_context_mut(), "eval_bytecode")?; - let (ptr, len) = Self::compile(src.as_bytes(), store.as_context_mut(), &instance)?; - eval.call(store.as_context_mut(), (ptr, len)) + let (bc_ptr, bc_len) = Self::compile(src.as_bytes(), store.as_context_mut(), &instance)?; + let res = match use_exported_fn { + UseExportedFn::EvalBytecode => instance + .get_typed_func::<(u32, u32), ()>(store.as_context_mut(), "eval_bytecode")? + .call(store.as_context_mut(), (bc_ptr, bc_len)), + UseExportedFn::Invoke(func) => { + let (fn_ptr, fn_len) = match func { + Some(func) => Self::copy_func_name(func, &instance, store.as_context_mut())?, + None => (0, 0), + }; + instance + .get_typed_func::<(u32, u32, u32, u32), ()>(store.as_context_mut(), "invoke")? + .call(store.as_context_mut(), (bc_ptr, bc_len, fn_ptr, fn_len)) + } }; self.extract_store_data(res, store)