WebIDL: Use ArrayBuffer instead of raw JSObject in bindings (#31202)

* WebIDL: Use ArrayBuffer instead of raw JSObject in bindings

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

* Convert GPUBufferMapInfo mapping to Arc<Mutex>

* Remove #[allow(unsafe_code)] from GPUBuffer

* Add doc comments

* Implement trace for Arc<Mutex<Vec<T>>>

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

* Use #[no_trace] for GPUBufferMapInfo.mapping

* Make create_new_external_array_buffer generic

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

* Address review comments

* Remove HeapTypedArray::new and avoid cloning Arc

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

* Use expect for GetMappedRange and ReadAsArrayBuffer

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

* Use doc comments for FileReaderSyncMethods

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

* Return for Error::JsFailed GetMappedRange and ReadAsArrayBuffer

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

* Fix detached_internal implementation and comments

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

* format code

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

* Update expectations

---------

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
Co-authored-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
Taym Haddadi 2024-02-13 08:58:48 +01:00 committed by GitHub
parent e6baa26ff8
commit 9be989146d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 121 additions and 75 deletions

View file

@ -128,6 +128,7 @@ builtinNames = {
IDLType.Tags.uint32array: 'Uint32Array',
IDLType.Tags.float32array: 'Float32Array',
IDLType.Tags.float64array: 'Float64Array',
IDLType.Tags.arrayBuffer: 'ArrayBuffer',
}
numericTags = [
@ -1481,7 +1482,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
return CGGeneric("()")
if returnType.isPrimitive() and returnType.tag() in builtinNames:
return builtin_return_type(returnType)
if returnType.isTypedArray() and returnType.tag() in builtinNames:
if is_typed_array(returnType) and returnType.tag() in builtinNames:
return builtin_return_type(returnType)
if returnType.isDOMString():
result = CGGeneric("DOMString")
@ -6516,6 +6517,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::typedarray::Uint32Array',
'js::typedarray::Float32Array',
'js::typedarray::Float64Array',
'js::typedarray::ArrayBuffer',
'crate::dom',
'crate::dom::bindings',
'crate::dom::bindings::codegen::InterfaceObjectMap',

View file

@ -4,12 +4,17 @@
#![allow(unsafe_code)]
use std::borrow::BorrowMut;
use std::ffi::c_void;
use std::marker::PhantomData;
use std::ptr;
use std::sync::{Arc, Mutex};
use js::jsapi::{Heap, JSObject, JS_GetArrayBufferViewBuffer};
use js::jsapi::{
Heap, JSObject, JS_GetArrayBufferViewBuffer, JS_IsArrayBufferViewObject, NewExternalArrayBuffer,
};
use js::rust::wrappers::DetachArrayBuffer;
use js::rust::{CustomAutoRooterGuard, MutableHandleObject};
use js::rust::{CustomAutoRooterGuard, Handle, MutableHandleObject};
use js::typedarray::{CreateWith, TypedArray, TypedArrayElement, TypedArrayElementCreator};
use crate::script_runtime::JSContext;
@ -52,14 +57,7 @@ where
array as Result<CustomAutoRooterGuard<'_, TypedArray<T, *mut JSObject>>, &mut ()>
{
let data = array.to_vec();
let mut is_shared = false;
unsafe {
rooted!(in (*cx) let view_buffer =
JS_GetArrayBufferViewBuffer(*cx, self.internal.handle(), &mut is_shared));
// This buffer is always created unshared
debug_assert!(!is_shared);
let _ = DetachArrayBuffer(*cx, view_buffer.handle());
}
let _ = self.detach_internal(cx);
Ok(data)
} else {
Err(())
@ -68,6 +66,26 @@ where
data
}
/// <https://tc39.es/ecma262/#sec-detacharraybuffer>
pub fn detach_internal(&self, cx: JSContext) -> bool {
assert!(self.is_initialized());
let mut is_shared = false;
unsafe {
if JS_IsArrayBufferViewObject(*self.internal.handle()) {
// If it is an ArrayBuffer view, get the buffer using JS_GetArrayBufferViewBuffer
rooted!(in (*cx) let view_buffer =
JS_GetArrayBufferViewBuffer(*cx, self.internal.handle(), &mut is_shared));
// This buffer is always created unshared
debug_assert!(!is_shared);
// Detach the ArrayBuffer
DetachArrayBuffer(*cx, view_buffer.handle())
} else {
// If it's not an ArrayBuffer view, Detach the internal buffer directly
DetachArrayBuffer(*cx, Handle::from_raw(self.internal.handle()))
}
}
}
pub fn copy_data_to(
&self,
cx: JSContext,
@ -142,3 +160,40 @@ where
TypedArray::from(dest.get())
}
}
pub fn create_new_external_array_buffer<T>(
cx: JSContext,
mapping: Arc<Mutex<Vec<T::Element>>>,
offset: usize,
range_size: usize,
m_end: usize,
) -> HeapTypedArray<T>
where
T: TypedArrayElement + TypedArrayElementCreator,
T::Element: Clone + Copy,
{
/// `freeFunc()` must be threadsafe, should be safely callable from any thread
/// without causing conflicts or unexpected behavior.
/// <https://github.com/servo/mozjs/blob/main/mozjs-sys/mozjs/js/public/ArrayBuffer.h#L89>
unsafe extern "C" fn free_func(_contents: *mut c_void, free_user_data: *mut c_void) {
let _ = Arc::from_raw(free_user_data as _);
}
unsafe {
let mapping_slice_ptr =
mapping.lock().unwrap().borrow_mut()[offset as usize..m_end as usize].as_mut_ptr();
let array_buffer = NewExternalArrayBuffer(
*cx,
range_size as usize,
mapping_slice_ptr as _,
Some(free_func),
Arc::into_raw(mapping) as _,
);
HeapTypedArray {
internal: Heap::boxed(array_buffer),
phantom: PhantomData::default(),
}
}
}