Skip to content

Commit

Permalink
Inline function execution with bytecode evaluation
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffcharles committed Oct 17, 2024
1 parent 89afb6c commit 3395c6b
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 11 deletions.
18 changes: 14 additions & 4 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::{context::EvalOptions, Ctx, Error as JSError, Function, Module, Value},
to_js_error, Runtime,
};

Expand All @@ -17,14 +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())
handle_maybe_promise(this.clone(), promise.into())?;

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 All @@ -37,6 +46,7 @@ pub fn run_bytecode(runtime: &Runtime, bytecode: &[u8]) {
/// 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.
#[allow(dead_code)] // Used by `main.rs` but not by `lib.rs`.
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();")
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);
}
2 changes: 1 addition & 1 deletion 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 Down

0 comments on commit 3395c6b

Please sign in to comment.