Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
andrieshiemstra committed Jan 13, 2024
1 parent 9dc5ad4 commit 4584c11
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 27 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 0.12.0

* uses hirofa-quickjs-sys 0.10.0 and ['bellard'] feature and thus the 2023-12-09 version of the original quickjs by Fabrice Bellard
* uses hirofa-quickjs-sys 0.2.0 and ['bellard'] feature and thus the 2024-01-13 version of the original quickjs by Fabrice Bellard
* added get_proxy_instance_id for getting instance id without looking up the proxy
* console functions output source filename

Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ hirofa_utils = "0.7"
#hirofa_utils = {git="https://github.com/HiRoFa/utils"}
backtrace = "0.3.67"

libquickjs-sys = {package="hirofa-quickjs-sys", git='https://github.com/HiRoFa/quickjs-sys', features=["bellard"]}
#libquickjs-sys = {package="hirofa-quickjs-sys", git='https://github.com/HiRoFa/quickjs-sys', features=["bellard"]}
#libquickjs-sys = {package="hirofa-quickjs-sys", path='../quickjs-sys', features=["bellard"]}
libquickjs-sys = {package="hirofa-quickjs-sys", version="0.2.0", features=["bellard"]}
lazy_static = "1.4.0"
log = "0.4"
num_cpus = "1"
Expand Down
6 changes: 3 additions & 3 deletions src/facades.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ impl QuickJsRuntimeFacade {
std::thread::spawn(move || loop {
std::thread::sleep(interval);
if let Some(el) = rti_ref.upgrade() {
log::trace!("running gc from gc interval thread");
log::debug!("running gc from gc interval thread");
el.event_loop.add_void(|| {
QJS_RT
.try_with(|rc| {
Expand Down Expand Up @@ -1079,12 +1079,12 @@ pub mod tests {
fn test_func() {
let rt = init_test_rt();
let res = rt.set_function(&["nl", "my", "utils"], "methodA", |_q_ctx, args| {
if args.len() != 2 || !args.get(0).unwrap().is_i32() || !args.get(1).unwrap().is_i32() {
if args.len() != 2 || !args.first().unwrap().is_i32() || !args.get(1).unwrap().is_i32() {
Err(JsError::new_str(
"i'd really like 2 args of the int32 kind please",
))
} else {
let a = args.get(0).unwrap().get_i32();
let a = args.first().unwrap().get_i32();
let b = args.get(1).unwrap().get_i32();
Ok((a * b).to_js_value_facade())
}
Expand Down
8 changes: 4 additions & 4 deletions src/quickjs_utils/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ pub unsafe fn call_to_string(
obj_ref: &QuickJsValueAdapter,
) -> Result<String, JsError> {
if obj_ref.is_string() {
crate::quickjs_utils::primitives::to_string(context, obj_ref)
primitives::to_string(context, obj_ref)
} else if obj_ref.is_null() {
Ok("null".to_string())
} else if obj_ref.is_undefined() {
Expand Down Expand Up @@ -264,7 +264,7 @@ pub unsafe fn call_to_string(
if !res_ref.is_string() {
return Err(JsError::new_str("Could not convert value to string"));
}
crate::quickjs_utils::primitives::to_string(context, &res_ref)
primitives::to_string(context, &res_ref)
}
}

Expand Down Expand Up @@ -529,11 +529,11 @@ thread_local! {
RefCell::new(class_id)
};

static CALLBACK_REGISTRY: RefCell<AutoIdMap<(String, Rc<Callback>)>> = {
pub static CALLBACK_REGISTRY: RefCell<AutoIdMap<(String, Rc<Callback>)>> = {
RefCell::new(AutoIdMap::new_with_max_size(i32::MAX as usize))
};

static CALLBACK_IDS: RefCell<HashSet<Box<i32>>> = RefCell::new(HashSet::new());
pub static CALLBACK_IDS: RefCell<HashSet<Box<i32>>> = RefCell::new(HashSet::new());
}

pub(crate) fn init_statics() {
Expand Down
2 changes: 1 addition & 1 deletion src/quickjs_utils/promises.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ pub mod tests {
q_ctx,
"testThen",
|_q_ctx, _this, args| {
let res = primitives::to_i32(args.get(0).unwrap()).ok().unwrap();
let res = primitives::to_i32(args.first().unwrap()).ok().unwrap();
log::trace!("prom resolved with: {}", res);
Ok(new_null_ref())
},
Expand Down
149 changes: 134 additions & 15 deletions src/quickjs_utils/typedarrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use std::cell::RefCell;

thread_local! {
// max size is 32.max because we store id as prop
static BUFFERS: RefCell<AutoIdMap<Vec<u8>>> = RefCell::new(AutoIdMap::new_with_max_size(i32::MAX as usize));
pub static BUFFERS: RefCell<AutoIdMap<Vec<u8>>> = RefCell::new(AutoIdMap::new_with_max_size(i32::MAX as usize));
}

/// this method creates a new ArrayBuffer which is used as a basis for all typed arrays
Expand All @@ -73,6 +73,8 @@ pub unsafe fn new_array_buffer(
ctx: *mut q::JSContext,
buf: Vec<u8>,
) -> Result<QuickJsValueAdapter, JsError> {
log::trace!("new_array_buffer");

#[cfg(target_pointer_width = "64")]
let length = buf.len();
#[cfg(target_pointer_width = "32")]
Expand Down Expand Up @@ -156,6 +158,8 @@ pub unsafe fn new_array_buffer_copy(
ctx: *mut q::JSContext,
buf: &[u8],
) -> Result<QuickJsValueAdapter, JsError> {
log::trace!("new_array_buffer_copy");

#[cfg(target_pointer_width = "64")]
let length = buf.len();
#[cfg(target_pointer_width = "32")]
Expand Down Expand Up @@ -190,6 +194,8 @@ pub unsafe fn detach_array_buffer_buffer(
ctx: *mut q::JSContext,
array_buffer: &QuickJsValueAdapter,
) -> Result<Vec<u8>, JsError> {
log::trace!("detach_array_buffer_buffer");

debug_assert!(is_array_buffer(ctx, array_buffer));

// check if vec is one we buffered, if not we create a new one from the slice we got from quickjs
Expand Down Expand Up @@ -243,16 +249,33 @@ pub unsafe fn get_array_buffer_buffer_copy(
) -> Result<Vec<u8>, JsError> {
debug_assert!(is_array_buffer(ctx, array_buffer));

#[cfg(target_pointer_width = "64")]
let mut len: usize = 0;
#[cfg(target_pointer_width = "32")]
let mut len: u32 = 0;
log::trace!("get_array_buffer_buffer_copy");

let id_prop = get_property(ctx, array_buffer, "__buffer_id")?;
let id_opt = if id_prop.is_i32() {
Some(id_prop.to_i32() as usize)
} else {
None
};

if let Some(id) = id_opt {
let b = BUFFERS.with(|rc| {
let buffers = &mut *rc.borrow_mut();
buffers.get(&id).expect("invalid buffer state").clone()
});
Ok(b)
} else {
#[cfg(target_pointer_width = "64")]
let mut len: usize = 0;
#[cfg(target_pointer_width = "32")]
let mut len: u32 = 0;

let ptr = q::JS_GetArrayBuffer(ctx, &mut len, *array_buffer.borrow_value());
let ptr = q::JS_GetArrayBuffer(ctx, &mut len, *array_buffer.borrow_value());

let slice = std::slice::from_raw_parts(ptr, len as _);
let slice = std::slice::from_raw_parts(ptr, len as _);

Ok(slice.to_vec())
Ok(slice.to_vec())
}
}

/// get the underlying ArrayBuffer of a TypedArray
Expand All @@ -276,6 +299,7 @@ pub unsafe fn get_array_buffer(

// todo!();
// for our Uint8Array uses cases this works fine
log::trace!("get_array_buffer");
get_property(ctx, typed_array, "buffer")
}

Expand Down Expand Up @@ -324,11 +348,13 @@ unsafe extern "C" fn free_func(
opaque: *mut ::std::os::raw::c_void,
ptr: *mut ::std::os::raw::c_void,
) {
let id = opaque as usize;
log::trace!("typedarrays::free_func {}", id);

if ptr.is_null() {
return;
}

let id = opaque as usize;
BUFFERS.with(|rc| {
let buffers = &mut *rc.borrow_mut();
if buffers.contains_key(&id) {
Expand All @@ -340,14 +366,23 @@ unsafe extern "C" fn free_func(
#[cfg(test)]
pub mod tests {
use crate::builder::QuickJsRuntimeBuilder;
use crate::jsutils::Script;
use crate::jsutils::{JsError, Script};
use crate::quickjs_utils::typedarrays::{
detach_array_buffer_buffer_q, get_array_buffer_q, is_array_buffer_q, is_typed_array_q,
new_array_buffer_q, new_uint8_array_q,
detach_array_buffer_buffer_q, get_array_buffer_buffer_copy_q, get_array_buffer_q,
is_array_buffer_q, is_typed_array_q, new_array_buffer_q, new_uint8_array_copy_q,
new_uint8_array_q,
};
use crate::values::{JsValueFacade, TypedArrayType};

use crate::quickjs_utils::objects::set_property_q;
use crate::quickjs_utils::{get_global_q, new_undefined_ref};
use std::thread;
use std::time::Duration;

#[test]
fn test_typed() {
simple_logging::log_to_stderr(log::LevelFilter::max());

std::panic::set_hook(Box::new(|panic_info| {
let backtrace = backtrace::Backtrace::new();
println!("thread panic occurred: {panic_info}\nbacktrace: {backtrace:?}");
Expand All @@ -358,7 +393,56 @@ pub mod tests {
);
}));

//simple_logging::log_to_stderr(log::LevelFilter::max());
let rt = QuickJsRuntimeBuilder::new().build();

let res: Result<(), JsError> = rt.exe_rt_task_in_event_loop(|rt| {
let mut buffer: Vec<u8> = vec![];
for y in 0..(10 * 1024 * 1024) {
buffer.push(y as u8);
}

let realm = rt.get_main_realm();
let adapter = new_uint8_array_copy_q(realm, &buffer)?;
drop(buffer);
let global = get_global_q(realm);
set_property_q(realm, &global, "buf", &adapter)?;

drop(adapter);

realm.eval(Script::new(
"l.js",
"console.log(`buf l=%s 1=%s`, globalThis.buf.length, globalThis.buf[1]);",
))?;

set_property_q(realm, &global, "buf", &new_undefined_ref())?;

rt.gc();

Ok(())
});
match res {
Ok(_) => {
log::info!("done ok");
}
Err(err) => {
panic!("{err}");
}
}
}

#[test]
fn test_typed2() {
simple_logging::log_to_stderr(log::LevelFilter::max());

std::panic::set_hook(Box::new(|panic_info| {
let backtrace = backtrace::Backtrace::new();
println!("thread panic occurred: {panic_info}\nbacktrace: {backtrace:?}");
log::error!(
"thread panic occurred: {}\nbacktrace: {:?}",
panic_info,
backtrace
);
}));

let rt = QuickJsRuntimeBuilder::new().build();

Expand All @@ -379,7 +463,7 @@ pub mod tests {
realm
.eval(Script::new(
"testu8",
"globalThis.testTyped = function(typedArray) {console.log('t=%s len=%s 0=%s 1=%s 2=%s', typedArray.constructor.name, typedArray.length, typedArray[0], typedArray[1], typedArray[2]); typedArray[0] = 34;};",
"globalThis.testTyped = function(typedArray) {console.log('t=%s len=%s 0=%s 1=%s 2=%s', typedArray.constructor.name, typedArray.length, typedArray[0], typedArray[1], typedArray[2]); typedArray[0] = 34; const ret = []; for (let x = 0; x < 1024; x++) {ret.push(x);}; return new Uint8Array(ret);};",
))
.expect("script failed");
});
Expand Down Expand Up @@ -410,7 +494,7 @@ pub mod tests {
match arr_res {
Ok(mut arr) => {
arr.label("arr");
log::debug!("arr created");
log::debug!("arr created, refcount={}", arr.get_ref_count());

assert!(is_typed_array_q(realm, &arr));

Expand All @@ -420,6 +504,9 @@ pub mod tests {

let ab = get_array_buffer_q(realm, &arr).expect("did not get buffer");

let copy = get_array_buffer_buffer_copy_q(realm, &ab).expect("could not copy");
log::info!("copy.len = {}", copy.len());

log::trace!("reclaiming");
let buf2_reclaimed =
detach_array_buffer_buffer_q(realm, &ab).expect("detach failed");
Expand Down Expand Up @@ -452,5 +539,37 @@ pub mod tests {
}
}
});

thread::sleep(Duration::from_secs(1));

for x in 0..10 {
let mut buffer2: Vec<u8> = vec![];
for y in 0..(10 * 1024 * 1024) {
buffer2.push(y as u8);
}
let ta = JsValueFacade::TypedArray {
buffer: buffer2,
array_type: TypedArrayType::Uint8,
};
let res = rt.invoke_function_sync(None, &[], "testTyped", vec![ta]);
match res {
Ok(r) => {
log::info!("from jsvf got {:?}", r);
}
Err(e) => {
panic!("{}", e);
}
}
log::info!("x={x}");
}

drop(rt);

crate::quickjs_utils::typedarrays::BUFFERS.with(|rc| {
let buffers = &mut *rc.borrow_mut();
log::info!("BUFFERS.len = {}", buffers.len());
});

thread::sleep(Duration::from_secs(1));
}
}
Loading

0 comments on commit 4584c11

Please sign in to comment.