Skip to content

Commit

Permalink
Inline function execution with bytecode evaluation (#784)
Browse files Browse the repository at this point in the history
* Inline function execution with bytecode evaluation

* Apply same change to main.rs
  • Loading branch information
jeffcharles authored Oct 18, 2024
1 parent 5a1f1c0 commit f2faf17
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 42 deletions.
6 changes: 3 additions & 3 deletions crates/cli/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ fn test_exported_functions(builder: &mut Builder) -> Result<()> {
.build()?;
let (_, logs, fuel_consumed) = run_fn(&mut runner, "foo", &[]);
assert_eq!("Hello from top-level\nHello from foo\n", logs);
assert_fuel_consumed_within_threshold(80023, fuel_consumed);
assert_fuel_consumed_within_threshold(63_310, fuel_consumed);
let (_, logs, _) = run_fn(&mut runner, "foo-bar", &[]);
assert_eq!("Hello from top-level\nHello from fooBar\n", logs);
Ok(())
Expand Down Expand Up @@ -270,7 +270,7 @@ fn test_exported_default_arrow_fn(builder: &mut Builder) -> Result<()> {

let (_, logs, fuel_consumed) = run_fn(&mut runner, "default", &[]);
assert_eq!(logs, "42\n");
assert_fuel_consumed_within_threshold(76706, fuel_consumed);
assert_fuel_consumed_within_threshold(39_004, fuel_consumed);
Ok(())
}

Expand All @@ -283,7 +283,7 @@ fn test_exported_default_fn(builder: &mut Builder) -> Result<()> {
.build()?;
let (_, logs, fuel_consumed) = run_fn(&mut runner, "default", &[]);
assert_eq!(logs, "42\n");
assert_fuel_consumed_within_threshold(77909, fuel_consumed);
assert_fuel_consumed_within_threshold(39_951, fuel_consumed);
Ok(())
}

Expand Down
43 changes: 12 additions & 31 deletions crates/core/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::process;
use anyhow::{anyhow, bail, Error, Result};
use javy::{
from_js_error,
quickjs::{context::EvalOptions, Ctx, Error as JSError, Module, Value},
quickjs::{Ctx, Error as JSError, Function, Module, Value},
to_js_error, Runtime,
};

Expand All @@ -17,42 +17,23 @@ static EVENT_LOOP_ERR: &str = r#"
///
/// Evaluating also prepares (or "instantiates") the state of the JavaScript
/// engine given all the information encoded in the bytecode.
pub fn run_bytecode(runtime: &Runtime, bytecode: &[u8]) {
pub fn run_bytecode(runtime: &Runtime, bytecode: &[u8], fn_name: Option<&str>) {
runtime
.context()
.with(|this| {
let module = unsafe { Module::load(this.clone(), bytecode)? };
let (_, promise) = module.eval()?;
let (module, promise) = module.eval()?;

handle_maybe_promise(this.clone(), promise.into())
})
.map_err(|e| runtime.context().with(|cx| from_js_error(cx.clone(), e)))
.and_then(|_: ()| ensure_pending_jobs(runtime))
.unwrap_or_else(handle_error)
}
handle_maybe_promise(this.clone(), promise.into())?;

/// Entry point to invoke an exported JavaScript function.
///
/// This function will evaluate a JavaScript snippet that imports and invokes
/// the target function from a previously evaluated module. It's the caller's
/// reponsibility to ensure that the module containing the target function has
/// been previously evaluated.
pub fn invoke_function(runtime: &Runtime, fn_module: &str, fn_name: &str) {
let js = if fn_name == "default" {
format!("import {{ default as defaultFn }} from '{fn_module}'; defaultFn();")
} else {
format!("import {{ {fn_name} }} from '{fn_module}'; {fn_name}();")
};

runtime
.context()
.with(|this| {
let mut opts = EvalOptions::default();
opts.strict = false;
opts.global = false;
let value = this.eval_with_options::<Value<'_>, _>(js, opts)?;

handle_maybe_promise(this.clone(), value)
if let Some(fn_name) = fn_name {
let fun: Function = module.get(fn_name)?;
// Exported functions are guaranteed not to have arguments so
// we can safely pass an empty tuple for arguments.
let value = fun.call(())?;
handle_maybe_promise(this.clone(), value)?
}
Ok(())
})
.map_err(|e| runtime.context().with(|cx| from_js_error(cx.clone(), e)))
.and_then(|_: ()| ensure_pending_jobs(runtime))
Expand Down
16 changes: 10 additions & 6 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub unsafe extern "C" fn compile_src(js_src_ptr: *const u8, js_src_len: usize) -
pub unsafe extern "C" fn eval_bytecode(bytecode_ptr: *const u8, bytecode_len: usize) {
let runtime = RUNTIME.get().unwrap();
let bytecode = slice::from_raw_parts(bytecode_ptr, bytecode_len);
execution::run_bytecode(runtime, bytecode);
execution::run_bytecode(runtime, bytecode, None);
}

/// Evaluates QuickJS bytecode and optionally invokes exported JS function with
Expand All @@ -89,9 +89,13 @@ pub unsafe extern "C" fn invoke(
) {
let runtime = RUNTIME.get().unwrap();
let bytecode = slice::from_raw_parts(bytecode_ptr, bytecode_len);
execution::run_bytecode(runtime, bytecode);
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);
}
let fn_name = if !fn_name_ptr.is_null() && fn_name_len != 0 {
Some(str::from_utf8_unchecked(slice::from_raw_parts(
fn_name_ptr,
fn_name_len,
)))
} else {
None
};
execution::run_bytecode(runtime, bytecode, fn_name);
}
5 changes: 3 additions & 2 deletions crates/core/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub extern "C" fn initialize_runtime() {
fn main() {
let bytecode = unsafe { BYTECODE.take().unwrap() };
let runtime = unsafe { RUNTIME.take().unwrap() };
execution::run_bytecode(&runtime, &bytecode);
execution::run_bytecode(&runtime, &bytecode, None);
}

// Removed in post-processing.
Expand All @@ -65,8 +65,9 @@ pub unsafe extern "C" fn invoke(fn_name_ptr: *mut u8, fn_name_size: usize) {
let _wasm_ctx = WasmCtx::new();

let js_fn_name = str::from_utf8_unchecked(slice::from_raw_parts(fn_name_ptr, fn_name_size));
let bytecode = unsafe { BYTECODE.take().unwrap() };
let runtime = unsafe { RUNTIME.take().unwrap() };
execution::invoke_function(&runtime, FUNCTION_MODULE_NAME, js_fn_name);
execution::run_bytecode(&runtime, &bytecode, Some(js_fn_name));
}

// RAII abstraction for calling Wasm ctors and dtors for exported non-main functions.
Expand Down

0 comments on commit f2faf17

Please sign in to comment.