@@ -53,7 +53,7 @@ use std::cell::RefCell;
5353
5454thread_local ! {
5555 // max size is 32.max because we store id as prop
56- static BUFFERS : RefCell <AutoIdMap <Vec <u8 >>> = RefCell :: new( AutoIdMap :: new_with_max_size( i32 :: MAX as usize ) ) ;
56+ pub static BUFFERS : RefCell <AutoIdMap <Vec <u8 >>> = RefCell :: new( AutoIdMap :: new_with_max_size( i32 :: MAX as usize ) ) ;
5757}
5858
5959/// this method creates a new ArrayBuffer which is used as a basis for all typed arrays
@@ -73,6 +73,8 @@ pub unsafe fn new_array_buffer(
7373 ctx : * mut q:: JSContext ,
7474 buf : Vec < u8 > ,
7575) -> Result < QuickJsValueAdapter , JsError > {
76+ log:: trace!( "new_array_buffer" ) ;
77+
7678 #[ cfg( target_pointer_width = "64" ) ]
7779 let length = buf. len ( ) ;
7880 #[ cfg( target_pointer_width = "32" ) ]
@@ -156,6 +158,8 @@ pub unsafe fn new_array_buffer_copy(
156158 ctx : * mut q:: JSContext ,
157159 buf : & [ u8 ] ,
158160) -> Result < QuickJsValueAdapter , JsError > {
161+ log:: trace!( "new_array_buffer_copy" ) ;
162+
159163 #[ cfg( target_pointer_width = "64" ) ]
160164 let length = buf. len ( ) ;
161165 #[ cfg( target_pointer_width = "32" ) ]
@@ -190,6 +194,8 @@ pub unsafe fn detach_array_buffer_buffer(
190194 ctx : * mut q:: JSContext ,
191195 array_buffer : & QuickJsValueAdapter ,
192196) -> Result < Vec < u8 > , JsError > {
197+ log:: trace!( "detach_array_buffer_buffer" ) ;
198+
193199 debug_assert ! ( is_array_buffer( ctx, array_buffer) ) ;
194200
195201 // check if vec is one we buffered, if not we create a new one from the slice we got from quickjs
@@ -243,16 +249,33 @@ pub unsafe fn get_array_buffer_buffer_copy(
243249) -> Result < Vec < u8 > , JsError > {
244250 debug_assert ! ( is_array_buffer( ctx, array_buffer) ) ;
245251
246- #[ cfg( target_pointer_width = "64" ) ]
247- let mut len: usize = 0 ;
248- #[ cfg( target_pointer_width = "32" ) ]
249- let mut len: u32 = 0 ;
252+ log:: trace!( "get_array_buffer_buffer_copy" ) ;
253+
254+ let id_prop = get_property ( ctx, array_buffer, "__buffer_id" ) ?;
255+ let id_opt = if id_prop. is_i32 ( ) {
256+ Some ( id_prop. to_i32 ( ) as usize )
257+ } else {
258+ None
259+ } ;
260+
261+ if let Some ( id) = id_opt {
262+ let b = BUFFERS . with ( |rc| {
263+ let buffers = & mut * rc. borrow_mut ( ) ;
264+ buffers. get ( & id) . expect ( "invalid buffer state" ) . clone ( )
265+ } ) ;
266+ Ok ( b)
267+ } else {
268+ #[ cfg( target_pointer_width = "64" ) ]
269+ let mut len: usize = 0 ;
270+ #[ cfg( target_pointer_width = "32" ) ]
271+ let mut len: u32 = 0 ;
250272
251- let ptr = q:: JS_GetArrayBuffer ( ctx, & mut len, * array_buffer. borrow_value ( ) ) ;
273+ let ptr = q:: JS_GetArrayBuffer ( ctx, & mut len, * array_buffer. borrow_value ( ) ) ;
252274
253- let slice = std:: slice:: from_raw_parts ( ptr, len as _ ) ;
275+ let slice = std:: slice:: from_raw_parts ( ptr, len as _ ) ;
254276
255- Ok ( slice. to_vec ( ) )
277+ Ok ( slice. to_vec ( ) )
278+ }
256279}
257280
258281/// get the underlying ArrayBuffer of a TypedArray
@@ -276,6 +299,7 @@ pub unsafe fn get_array_buffer(
276299
277300 // todo!();
278301 // for our Uint8Array uses cases this works fine
302+ log:: trace!( "get_array_buffer" ) ;
279303 get_property ( ctx, typed_array, "buffer" )
280304}
281305
@@ -324,11 +348,13 @@ unsafe extern "C" fn free_func(
324348 opaque : * mut :: std:: os:: raw:: c_void ,
325349 ptr : * mut :: std:: os:: raw:: c_void ,
326350) {
351+ let id = opaque as usize ;
352+ log:: trace!( "typedarrays::free_func {}" , id) ;
353+
327354 if ptr. is_null ( ) {
328355 return ;
329356 }
330357
331- let id = opaque as usize ;
332358 BUFFERS . with ( |rc| {
333359 let buffers = & mut * rc. borrow_mut ( ) ;
334360 if buffers. contains_key ( & id) {
@@ -340,14 +366,23 @@ unsafe extern "C" fn free_func(
340366#[ cfg( test) ]
341367pub mod tests {
342368 use crate :: builder:: QuickJsRuntimeBuilder ;
343- use crate :: jsutils:: Script ;
369+ use crate :: jsutils:: { JsError , Script } ;
344370 use crate :: quickjs_utils:: typedarrays:: {
345- detach_array_buffer_buffer_q, get_array_buffer_q, is_array_buffer_q, is_typed_array_q,
346- new_array_buffer_q, new_uint8_array_q,
371+ detach_array_buffer_buffer_q, get_array_buffer_buffer_copy_q, get_array_buffer_q,
372+ is_array_buffer_q, is_typed_array_q, new_array_buffer_q, new_uint8_array_copy_q,
373+ new_uint8_array_q,
347374 } ;
375+ use crate :: values:: { JsValueFacade , TypedArrayType } ;
376+
377+ use crate :: quickjs_utils:: objects:: set_property_q;
378+ use crate :: quickjs_utils:: { get_global_q, new_undefined_ref} ;
379+ use std:: thread;
380+ use std:: time:: Duration ;
348381
349382 #[ test]
350383 fn test_typed ( ) {
384+ simple_logging:: log_to_stderr ( log:: LevelFilter :: max ( ) ) ;
385+
351386 std:: panic:: set_hook ( Box :: new ( |panic_info| {
352387 let backtrace = backtrace:: Backtrace :: new ( ) ;
353388 println ! ( "thread panic occurred: {panic_info}\n backtrace: {backtrace:?}" ) ;
@@ -358,7 +393,56 @@ pub mod tests {
358393 ) ;
359394 } ) ) ;
360395
361- //simple_logging::log_to_stderr(log::LevelFilter::max());
396+ let rt = QuickJsRuntimeBuilder :: new ( ) . build ( ) ;
397+
398+ let res: Result < ( ) , JsError > = rt. exe_rt_task_in_event_loop ( |rt| {
399+ let mut buffer: Vec < u8 > = vec ! [ ] ;
400+ for y in 0 ..( 10 * 1024 * 1024 ) {
401+ buffer. push ( y as u8 ) ;
402+ }
403+
404+ let realm = rt. get_main_realm ( ) ;
405+ let adapter = new_uint8_array_copy_q ( realm, & buffer) ?;
406+ drop ( buffer) ;
407+ let global = get_global_q ( realm) ;
408+ set_property_q ( realm, & global, "buf" , & adapter) ?;
409+
410+ drop ( adapter) ;
411+
412+ realm. eval ( Script :: new (
413+ "l.js" ,
414+ "console.log(`buf l=%s 1=%s`, globalThis.buf.length, globalThis.buf[1]);" ,
415+ ) ) ?;
416+
417+ set_property_q ( realm, & global, "buf" , & new_undefined_ref ( ) ) ?;
418+
419+ rt. gc ( ) ;
420+
421+ Ok ( ( ) )
422+ } ) ;
423+ match res {
424+ Ok ( _) => {
425+ log:: info!( "done ok" ) ;
426+ }
427+ Err ( err) => {
428+ panic ! ( "{err}" ) ;
429+ }
430+ }
431+ }
432+
433+ #[ test]
434+ fn test_typed2 ( ) {
435+ simple_logging:: log_to_stderr ( log:: LevelFilter :: max ( ) ) ;
436+
437+ std:: panic:: set_hook ( Box :: new ( |panic_info| {
438+ let backtrace = backtrace:: Backtrace :: new ( ) ;
439+ println ! ( "thread panic occurred: {panic_info}\n backtrace: {backtrace:?}" ) ;
440+ log:: error!(
441+ "thread panic occurred: {}\n backtrace: {:?}" ,
442+ panic_info,
443+ backtrace
444+ ) ;
445+ } ) ) ;
362446
363447 let rt = QuickJsRuntimeBuilder :: new ( ) . build ( ) ;
364448
@@ -379,7 +463,7 @@ pub mod tests {
379463 realm
380464 . eval ( Script :: new (
381465 "testu8" ,
382- "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;};" ,
466+ "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); };" ,
383467 ) )
384468 . expect ( "script failed" ) ;
385469 } ) ;
@@ -410,7 +494,7 @@ pub mod tests {
410494 match arr_res {
411495 Ok ( mut arr) => {
412496 arr. label ( "arr" ) ;
413- log:: debug!( "arr created" ) ;
497+ log:: debug!( "arr created, refcount={}" , arr . get_ref_count ( ) ) ;
414498
415499 assert ! ( is_typed_array_q( realm, & arr) ) ;
416500
@@ -420,6 +504,9 @@ pub mod tests {
420504
421505 let ab = get_array_buffer_q ( realm, & arr) . expect ( "did not get buffer" ) ;
422506
507+ let copy = get_array_buffer_buffer_copy_q ( realm, & ab) . expect ( "could not copy" ) ;
508+ log:: info!( "copy.len = {}" , copy. len( ) ) ;
509+
423510 log:: trace!( "reclaiming" ) ;
424511 let buf2_reclaimed =
425512 detach_array_buffer_buffer_q ( realm, & ab) . expect ( "detach failed" ) ;
@@ -452,5 +539,37 @@ pub mod tests {
452539 }
453540 }
454541 } ) ;
542+
543+ thread:: sleep ( Duration :: from_secs ( 1 ) ) ;
544+
545+ for x in 0 ..10 {
546+ let mut buffer2: Vec < u8 > = vec ! [ ] ;
547+ for y in 0 ..( 10 * 1024 * 1024 ) {
548+ buffer2. push ( y as u8 ) ;
549+ }
550+ let ta = JsValueFacade :: TypedArray {
551+ buffer : buffer2,
552+ array_type : TypedArrayType :: Uint8 ,
553+ } ;
554+ let res = rt. invoke_function_sync ( None , & [ ] , "testTyped" , vec ! [ ta] ) ;
555+ match res {
556+ Ok ( r) => {
557+ log:: info!( "from jsvf got {:?}" , r) ;
558+ }
559+ Err ( e) => {
560+ panic ! ( "{}" , e) ;
561+ }
562+ }
563+ log:: info!( "x={x}" ) ;
564+ }
565+
566+ drop ( rt) ;
567+
568+ crate :: quickjs_utils:: typedarrays:: BUFFERS . with ( |rc| {
569+ let buffers = & mut * rc. borrow_mut ( ) ;
570+ log:: info!( "BUFFERS.len = {}" , buffers. len( ) ) ;
571+ } ) ;
572+
573+ thread:: sleep ( Duration :: from_secs ( 1 ) ) ;
455574 }
456575}
0 commit comments