Skip to content

Commit

Permalink
Have provider invoke fn support not being given a function name (#776)
Browse files Browse the repository at this point in the history
* Make provider `invoke` fn support not being given a name

* PR feedback
  • Loading branch information
jeffcharles authored Oct 7, 2024
1 parent ef1e806 commit 7fa858f
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 23 deletions.
19 changes: 15 additions & 4 deletions crates/cli/tests/dylib_test.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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(())
Expand All @@ -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());

Expand All @@ -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(())
Expand Down
13 changes: 8 additions & 5 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
}
}
34 changes: 20 additions & 14 deletions crates/runner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ impl StoreContext {
}
}

pub enum UseExportedFn {
EvalBytecode,
Invoke(Option<&'static str>),
}

impl Runner {
#[allow(clippy::too_many_arguments)]
fn build(
Expand Down Expand Up @@ -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<u8>, Vec<u8>, 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)
Expand Down

0 comments on commit 7fa858f

Please sign in to comment.