diff --git a/components/script/dom/audiobuffer.rs b/components/script/dom/audiobuffer.rs index 9bb797cba09..7f2545f3934 100644 --- a/components/script/dom/audiobuffer.rs +++ b/components/script/dom/audiobuffer.rs @@ -9,7 +9,7 @@ use js::rust::{CustomAutoRooterGuard, HandleObject}; use js::typedarray::{Float32, Float32Array}; use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer; -use super::bindings::typedarrays::HeapTypedArray; +use super::bindings::buffer_source::HeapBufferSource; use crate::dom::audionode::MAX_CHANNEL_COUNT; use crate::dom::bindings::cell::{DomRefCell, Ref}; use crate::dom::bindings::codegen::Bindings::AudioBufferBinding::{ @@ -42,7 +42,7 @@ pub struct AudioBuffer { reflector_: Reflector, /// Float32Arrays returned by calls to GetChannelData. #[ignore_malloc_size_of = "mozjs"] - js_channels: DomRefCell>>, + js_channels: DomRefCell>>, /// Aggregates the data from js_channels. /// This is Some iff the buffers in js_channels are detached. #[ignore_malloc_size_of = "servo_media"] @@ -60,10 +60,9 @@ pub struct AudioBuffer { impl AudioBuffer { #[allow(crown::unrooted_must_root)] - #[allow(unsafe_code)] pub fn new_inherited(number_of_channels: u32, length: u32, sample_rate: f32) -> AudioBuffer { let vec = (0..number_of_channels) - .map(|_| HeapTypedArray::default()) + .map(|_| HeapBufferSource::default()) .collect(); AudioBuffer { reflector_: Reflector::new(), @@ -238,7 +237,7 @@ impl AudioBufferMethods for AudioBuffer { } self.js_channels.borrow()[channel as usize] - .get_internal() + .get_buffer() .map_err(|_| Error::JSFailed) } diff --git a/components/script/dom/bindings/buffer_source.rs b/components/script/dom/bindings/buffer_source.rs new file mode 100644 index 00000000000..2e7073356b5 --- /dev/null +++ b/components/script/dom/bindings/buffer_source.rs @@ -0,0 +1,441 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#![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, JS_IsArrayBufferViewObject, NewExternalArrayBuffer, +}; +use js::rust::wrappers::DetachArrayBuffer; +use js::rust::{CustomAutoRooterGuard, Handle, MutableHandleObject}; +use js::typedarray::{CreateWith, TypedArray, TypedArrayElement, TypedArrayElementCreator}; + +use crate::script_runtime::JSContext; + +/// +#[allow(dead_code)] +pub enum BufferSource { + Int8Array(Box>), + Int16Array(Box>), + Int32Array(Box>), + Uint8Array(Box>), + Uint16Array(Box>), + Uint32Array(Box>), + Uint8ClampedArray(Box>), + BigInt64Array(Box>), + BigUint64Array(Box>), + Float32Array(Box>), + Float64Array(Box>), + DataView(Box>), + ArrayBuffer(Box>), + Default(Box>), +} + +pub struct HeapBufferSource { + buffer_source: BufferSource, + phantom: PhantomData, +} + +unsafe impl crate::dom::bindings::trace::JSTraceable for HeapBufferSource { + #[inline] + unsafe fn trace(&self, tracer: *mut js::jsapi::JSTracer) { + match &self.buffer_source { + BufferSource::Int8Array(buffer) | + BufferSource::Int16Array(buffer) | + BufferSource::Int32Array(buffer) | + BufferSource::Uint8Array(buffer) | + BufferSource::Uint16Array(buffer) | + BufferSource::Uint32Array(buffer) | + BufferSource::Uint8ClampedArray(buffer) | + BufferSource::BigInt64Array(buffer) | + BufferSource::BigUint64Array(buffer) | + BufferSource::Float32Array(buffer) | + BufferSource::Float64Array(buffer) | + BufferSource::DataView(buffer) | + BufferSource::ArrayBuffer(buffer) | + BufferSource::Default(buffer) => { + buffer.trace(tracer); + }, + } + } +} + +pub fn new_initialized_heap_buffer_source_types( + init: HeapTypedArrayInit, +) -> Result, ()> +where + T: TypedArrayElement + TypedArrayElementCreator, + T::Element: Clone + Copy, +{ + let heap_buffer_source_types = match init { + HeapTypedArrayInit::Buffer(buffer_source) => HeapBufferSource { + buffer_source: buffer_source, + phantom: PhantomData::default(), + }, + HeapTypedArrayInit::Info { len, cx } => { + rooted!(in (*cx) let mut array = ptr::null_mut::()); + let typed_array_result = + create_buffer_source_types_with_length::(cx, len as usize, array.handle_mut()); + if typed_array_result.is_err() { + return Err(()); + } + let heap_buffer_source_types = HeapBufferSource::::default(); + + match &heap_buffer_source_types.buffer_source { + BufferSource::Int8Array(buffer) | + BufferSource::Int16Array(buffer) | + BufferSource::Int32Array(buffer) | + BufferSource::Uint8Array(buffer) | + BufferSource::Uint16Array(buffer) | + BufferSource::Uint32Array(buffer) | + BufferSource::Uint8ClampedArray(buffer) | + BufferSource::BigInt64Array(buffer) | + BufferSource::BigUint64Array(buffer) | + BufferSource::Float32Array(buffer) | + BufferSource::Float64Array(buffer) | + BufferSource::DataView(buffer) | + BufferSource::ArrayBuffer(buffer) | + BufferSource::Default(buffer) => { + buffer.set(*array); + }, + } + heap_buffer_source_types + }, + }; + Ok(heap_buffer_source_types) +} + +pub enum HeapTypedArrayInit { + Buffer(BufferSource), + Info { len: u32, cx: JSContext }, +} + +impl HeapBufferSource +where + T: TypedArrayElement + TypedArrayElementCreator, + T::Element: Clone + Copy, +{ + pub fn default() -> HeapBufferSource { + HeapBufferSource { + buffer_source: BufferSource::Default(Box::new(Heap::default())), + phantom: PhantomData::default(), + } + } + + pub fn set_data(&self, cx: JSContext, data: &[T::Element]) -> Result<(), ()> { + rooted!(in (*cx) let mut array = ptr::null_mut::()); + let _: TypedArray = + create_buffer_source_types(cx, data, array.handle_mut())?; + + match &self.buffer_source { + BufferSource::Int8Array(buffer) | + BufferSource::Int16Array(buffer) | + BufferSource::Int32Array(buffer) | + BufferSource::Uint8Array(buffer) | + BufferSource::Uint16Array(buffer) | + BufferSource::Uint32Array(buffer) | + BufferSource::Uint8ClampedArray(buffer) | + BufferSource::BigInt64Array(buffer) | + BufferSource::BigUint64Array(buffer) | + BufferSource::Float32Array(buffer) | + BufferSource::Float64Array(buffer) | + BufferSource::DataView(buffer) | + BufferSource::ArrayBuffer(buffer) | + BufferSource::Default(buffer) => { + buffer.set(*array); + }, + } + Ok(()) + } + + pub fn acquire_data(&self, cx: JSContext) -> Result, ()> { + assert!(self.is_initialized()); + + typedarray!(in(*cx) let array: TypedArray = match &self.buffer_source { + BufferSource::Int8Array(buffer) | + BufferSource::Int16Array(buffer) | + BufferSource::Int32Array(buffer) | + BufferSource::Uint8Array(buffer) | + BufferSource::Uint16Array(buffer) | + BufferSource::Uint32Array(buffer) | + BufferSource::Uint8ClampedArray(buffer) | + BufferSource::BigInt64Array(buffer) | + BufferSource::BigUint64Array(buffer) | + BufferSource::Float32Array(buffer) | + BufferSource::Float64Array(buffer) | + BufferSource::DataView(buffer) | + BufferSource::ArrayBuffer(buffer) | + BufferSource::Default(buffer) => { + buffer.get() + }, + }); + let data = if let Ok(array) = + array as Result>, &mut ()> + { + let data = array.to_vec(); + let _ = self.detach_buffer(cx); + Ok(data) + } else { + Err(()) + }; + + match &self.buffer_source { + BufferSource::Int8Array(buffer) | + BufferSource::Int16Array(buffer) | + BufferSource::Int32Array(buffer) | + BufferSource::Uint8Array(buffer) | + BufferSource::Uint16Array(buffer) | + BufferSource::Uint32Array(buffer) | + BufferSource::Uint8ClampedArray(buffer) | + BufferSource::BigInt64Array(buffer) | + BufferSource::BigUint64Array(buffer) | + BufferSource::Float32Array(buffer) | + BufferSource::Float64Array(buffer) | + BufferSource::DataView(buffer) | + BufferSource::ArrayBuffer(buffer) | + BufferSource::Default(buffer) => { + buffer.set(ptr::null_mut()); + }, + } + data + } + + /// + pub fn detach_buffer(&self, cx: JSContext) -> bool { + match &self.buffer_source { + BufferSource::Int8Array(buffer) | + BufferSource::Int16Array(buffer) | + BufferSource::Int32Array(buffer) | + BufferSource::Uint8Array(buffer) | + BufferSource::Uint16Array(buffer) | + BufferSource::Uint32Array(buffer) | + BufferSource::Uint8ClampedArray(buffer) | + BufferSource::BigInt64Array(buffer) | + BufferSource::BigUint64Array(buffer) | + BufferSource::Float32Array(buffer) | + BufferSource::Float64Array(buffer) | + BufferSource::DataView(buffer) | + BufferSource::ArrayBuffer(buffer) | + BufferSource::Default(buffer) => { + assert!(self.is_initialized()); + let mut is_shared = false; + unsafe { + if JS_IsArrayBufferViewObject(*buffer.handle()) { + // If it is an ArrayBuffer view, get the buffer using JS_GetArrayBufferViewBuffer + rooted!(in (*cx) let view_buffer = + JS_GetArrayBufferViewBuffer(*cx, buffer.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 buffer directly + DetachArrayBuffer(*cx, Handle::from_raw(buffer.handle())) + } + } + }, + } + } + + pub fn copy_data_to( + &self, + cx: JSContext, + dest: &mut [T::Element], + source_start: usize, + length: usize, + ) -> Result<(), ()> { + assert!(self.is_initialized()); + typedarray!(in(*cx) let array: TypedArray = match &self.buffer_source { + BufferSource::Int8Array(buffer) | + BufferSource::Int16Array(buffer) | + BufferSource::Int32Array(buffer) | + BufferSource::Uint8Array(buffer) | + BufferSource::Uint16Array(buffer) | + BufferSource::Uint32Array(buffer) | + BufferSource::Uint8ClampedArray(buffer) | + BufferSource::BigInt64Array(buffer) | + BufferSource::BigUint64Array(buffer) | + BufferSource::Float32Array(buffer) | + BufferSource::Float64Array(buffer) | + BufferSource::DataView(buffer) | + BufferSource::ArrayBuffer(buffer) | + BufferSource::Default(buffer) => { + buffer.get() + }, + }); + let Ok(array) = array as Result>, &mut ()> else{ + return Err(()) + }; + unsafe { + let slice = (*array).as_slice(); + dest.copy_from_slice(&slice[source_start..length]); + } + Ok(()) + } + + pub fn copy_data_from( + &self, + cx: JSContext, + source: CustomAutoRooterGuard>, + dest_start: usize, + length: usize, + ) -> Result<(), ()> { + assert!(self.is_initialized()); + typedarray!(in(*cx) let mut array: TypedArray = match &self.buffer_source { + BufferSource::Int8Array(buffer) | + BufferSource::Int16Array(buffer) | + BufferSource::Int32Array(buffer) | + BufferSource::Uint8Array(buffer) | + BufferSource::Uint16Array(buffer) | + BufferSource::Uint32Array(buffer) | + BufferSource::Uint8ClampedArray(buffer) | + BufferSource::BigInt64Array(buffer) | + BufferSource::BigUint64Array(buffer) | + BufferSource::Float32Array(buffer) | + BufferSource::Float64Array(buffer) | + BufferSource::DataView(buffer) | + BufferSource::ArrayBuffer(buffer) | + BufferSource::Default(buffer) => { + buffer.get() + }, + }); + let Ok(mut array) = array as Result>, &mut ()> else + { + return Err(()) + }; + unsafe { + let slice = (*array).as_mut_slice(); + let (_, dest) = slice.split_at_mut(dest_start); + dest[0..length].copy_from_slice(&source.as_slice()[0..length]) + } + Ok(()) + } + + pub fn is_initialized(&self) -> bool { + match &self.buffer_source { + BufferSource::Int8Array(buffer) | + BufferSource::Int16Array(buffer) | + BufferSource::Int32Array(buffer) | + BufferSource::Uint8Array(buffer) | + BufferSource::Uint16Array(buffer) | + BufferSource::Uint32Array(buffer) | + BufferSource::Uint8ClampedArray(buffer) | + BufferSource::BigInt64Array(buffer) | + BufferSource::BigUint64Array(buffer) | + BufferSource::Float32Array(buffer) | + BufferSource::Float64Array(buffer) | + BufferSource::DataView(buffer) | + BufferSource::ArrayBuffer(buffer) | + BufferSource::Default(buffer) => !buffer.get().is_null(), + } + } + + pub fn get_buffer(&self) -> Result, ()> { + TypedArray::from(match &self.buffer_source { + BufferSource::Int8Array(buffer) | + BufferSource::Int16Array(buffer) | + BufferSource::Int32Array(buffer) | + BufferSource::Uint8Array(buffer) | + BufferSource::Uint16Array(buffer) | + BufferSource::Uint32Array(buffer) | + BufferSource::Uint8ClampedArray(buffer) | + BufferSource::BigInt64Array(buffer) | + BufferSource::BigUint64Array(buffer) | + BufferSource::Float32Array(buffer) | + BufferSource::Float64Array(buffer) | + BufferSource::DataView(buffer) | + BufferSource::ArrayBuffer(buffer) | + BufferSource::Default(buffer) => buffer.get(), + }) + } + + pub fn buffer_to_option(&self) -> Option> { + if self.is_initialized() { + Some(self.get_buffer().expect("Failed to get buffer.")) + } else { + warn!("Buffer not initialized."); + None + } + } +} + +/// +pub fn create_buffer_source_types( + cx: JSContext, + data: &[T::Element], + dest: MutableHandleObject, +) -> Result, ()> +where + T: TypedArrayElement + TypedArrayElementCreator, +{ + let res = unsafe { TypedArray::::create(*cx, CreateWith::Slice(data), dest) }; + + if res.is_err() { + Err(()) + } else { + TypedArray::from(dest.get()) + } +} + +fn create_buffer_source_types_with_length( + cx: JSContext, + len: usize, + dest: MutableHandleObject, +) -> Result, ()> +where + T: TypedArrayElement + TypedArrayElementCreator, +{ + let res = unsafe { TypedArray::::create(*cx, CreateWith::Length(len), dest) }; + + if res.is_err() { + Err(()) + } else { + TypedArray::from(dest.get()) + } +} + +pub fn create_new_external_array_buffer( + cx: JSContext, + mapping: Arc>>, + offset: usize, + range_size: usize, + m_end: usize, +) -> HeapBufferSource +where + T: TypedArrayElement + TypedArrayElementCreator, + T::Element: Clone + Copy, +{ + /// `freeFunc()` must be threadsafe, should be safely callable from any thread + /// without causing conflicts , unexpected behavior. + /// + 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(); + + // rooted! is needed to ensure memory safety and prevent potential garbage collection issues. + // https://github.com/mozilla-spidermonkey/spidermonkey-embedding-examples/blob/esr78/docs/GC%20Rooting%20Guide.md#performance-tweaking + rooted!(in(*cx) let array_buffer = NewExternalArrayBuffer( + *cx, + range_size as usize, + mapping_slice_ptr as _, + Some(free_func), + Arc::into_raw(mapping) as _, + )); + + HeapBufferSource { + buffer_source: BufferSource::ArrayBuffer(Heap::boxed(*array_buffer)), + phantom: PhantomData::default(), + } + } +} diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs index 485cf8b3079..9733cabc73e 100644 --- a/components/script/dom/bindings/mod.rs +++ b/components/script/dom/bindings/mod.rs @@ -134,6 +134,7 @@ #![deny(missing_docs)] #![deny(non_snake_case)] +pub mod buffer_source; pub mod callback; pub mod cell; pub mod constant; @@ -159,7 +160,6 @@ pub mod str; pub mod structuredclone; pub mod trace; pub mod transferable; -pub mod typedarrays; pub mod utils; pub mod weakref; pub mod xmlname; diff --git a/components/script/dom/bindings/typedarrays.rs b/components/script/dom/bindings/typedarrays.rs deleted file mode 100644 index 5fb12c9c00d..00000000000 --- a/components/script/dom/bindings/typedarrays.rs +++ /dev/null @@ -1,250 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -#![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, JS_IsArrayBufferViewObject, NewExternalArrayBuffer, -}; -use js::rust::wrappers::DetachArrayBuffer; -use js::rust::{CustomAutoRooterGuard, Handle, MutableHandleObject}; -use js::typedarray::{CreateWith, TypedArray, TypedArrayElement, TypedArrayElementCreator}; - -use crate::script_runtime::JSContext; - -pub struct HeapTypedArray { - internal: Box>, - phantom: PhantomData, -} - -unsafe impl crate::dom::bindings::trace::JSTraceable for HeapTypedArray { - #[inline] - unsafe fn trace(&self, tracer: *mut js::jsapi::JSTracer) { - self.internal.trace(tracer); - } -} - -pub fn new_initialized_heap_typed_array( - init: HeapTypedArrayInit, -) -> Result, ()> -where - T: TypedArrayElement + TypedArrayElementCreator, - T::Element: Clone + Copy, -{ - let heap_typed_array = match init { - HeapTypedArrayInit::Object(js_object) => HeapTypedArray { - internal: Heap::boxed(js_object), - phantom: PhantomData::default(), - }, - HeapTypedArrayInit::Info { len, cx } => { - rooted!(in (*cx) let mut array = ptr::null_mut::()); - let typed_array_result = - create_typed_array_with_length::(cx, len as usize, array.handle_mut()); - if typed_array_result.is_err() { - return Err(()); - } - let heap_typed_array = HeapTypedArray::::default(); - heap_typed_array.internal.set(*array); - heap_typed_array - }, - }; - Ok(heap_typed_array) -} - -pub enum HeapTypedArrayInit { - Object(*mut JSObject), - Info { len: u32, cx: JSContext }, -} - -impl HeapTypedArray -where - T: TypedArrayElement + TypedArrayElementCreator, - T::Element: Clone + Copy, -{ - pub fn default() -> HeapTypedArray { - HeapTypedArray { - internal: Box::new(Heap::default()), - phantom: PhantomData::default(), - } - } - - pub fn set_data(&self, cx: JSContext, data: &[T::Element]) -> Result<(), ()> { - rooted!(in (*cx) let mut array = ptr::null_mut::()); - let _: TypedArray = create_typed_array(cx, data, array.handle_mut())?; - self.internal.set(*array); - Ok(()) - } - - pub fn acquire_data(&self, cx: JSContext) -> Result, ()> { - assert!(self.is_initialized()); - typedarray!(in(*cx) let array: TypedArray = self.internal.get()); - let data = if let Ok(array) = - array as Result>, &mut ()> - { - let data = array.to_vec(); - let _ = self.detach_internal(cx); - Ok(data) - } else { - Err(()) - }; - self.internal.set(ptr::null_mut()); - data - } - - /// - 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, - dest: &mut [T::Element], - source_start: usize, - length: usize, - ) -> Result<(), ()> { - assert!(self.is_initialized()); - typedarray!(in(*cx) let array: TypedArray = self.internal.get()); - let Ok(array) = array as Result>, &mut ()> else{ - return Err(()) - }; - unsafe { - let slice = (*array).as_slice(); - dest.copy_from_slice(&slice[source_start..length]); - } - Ok(()) - } - - pub fn copy_data_from( - &self, - cx: JSContext, - source: CustomAutoRooterGuard>, - dest_start: usize, - length: usize, - ) -> Result<(), ()> { - assert!(self.is_initialized()); - typedarray!(in(*cx) let mut array: TypedArray = self.internal.get()); - let Ok(mut array) = array as Result>, &mut ()> else - { - return Err(()) - }; - unsafe { - let slice = (*array).as_mut_slice(); - let (_, dest) = slice.split_at_mut(dest_start); - dest[0..length].copy_from_slice(&source.as_slice()[0..length]) - } - Ok(()) - } - - pub fn is_initialized(&self) -> bool { - !self.internal.get().is_null() - } - - pub fn get_internal(&self) -> Result, ()> { - TypedArray::from(self.internal.get()) - } - - pub fn internal_to_option(&self) -> Option> { - if self.is_initialized() { - Some(self.get_internal().expect("Failed to get internal.")) - } else { - warn!("Internal not initialized."); - None - } - } -} - -pub fn create_typed_array( - cx: JSContext, - data: &[T::Element], - dest: MutableHandleObject, -) -> Result, ()> -where - T: TypedArrayElement + TypedArrayElementCreator, -{ - let res = unsafe { TypedArray::::create(*cx, CreateWith::Slice(data), dest) }; - - if res.is_err() { - Err(()) - } else { - TypedArray::from(dest.get()) - } -} - -fn create_typed_array_with_length( - cx: JSContext, - len: usize, - dest: MutableHandleObject, -) -> Result, ()> -where - T: TypedArrayElement + TypedArrayElementCreator, -{ - let res = unsafe { TypedArray::::create(*cx, CreateWith::Length(len), dest) }; - - if res.is_err() { - Err(()) - } else { - TypedArray::from(dest.get()) - } -} - -pub fn create_new_external_array_buffer( - cx: JSContext, - mapping: Arc>>, - offset: usize, - range_size: usize, - m_end: usize, -) -> HeapTypedArray -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. - /// - 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(); - - // rooted! is needed to ensure memory safety and prevent potential garbage collection issues. - // https://github.com/mozilla-spidermonkey/spidermonkey-embedding-examples/blob/esr78/docs/GC%20Rooting%20Guide.md#performance-tweaking - rooted!(in(*cx) 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(), - } - } -} diff --git a/components/script/dom/dommatrixreadonly.rs b/components/script/dom/dommatrixreadonly.rs index 12e4e8c8acd..496e4e972c7 100644 --- a/components/script/dom/dommatrixreadonly.rs +++ b/components/script/dom/dommatrixreadonly.rs @@ -15,6 +15,7 @@ use js::typedarray::{Float32Array, Float64Array}; use style::parser::ParserContext; use url::Url; +use crate::dom::bindings::buffer_source::create_buffer_source_types; use crate::dom::bindings::cell::{DomRefCell, Ref}; use crate::dom::bindings::codegen::Bindings::DOMMatrixBinding::{DOMMatrixInit, DOMMatrixMethods}; use crate::dom::bindings::codegen::Bindings::DOMMatrixReadOnlyBinding::DOMMatrixReadOnlyMethods; @@ -25,7 +26,6 @@ use crate::dom::bindings::error::Fallible; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomObject, Reflector}; use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::typedarrays::create_typed_array; use crate::dom::dommatrix::DOMMatrix; use crate::dom::dompoint::DOMPoint; use crate::dom::globalscope::GlobalScope; @@ -686,14 +686,14 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly { .map(|&x| x as f32) .collect(); rooted!(in (*cx) let mut array = ptr::null_mut::()); - create_typed_array(cx, &vec, array.handle_mut()) + create_buffer_source_types(cx, &vec, array.handle_mut()) .expect("Converting matrix to float32 array should never fail") } // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-tofloat64array fn ToFloat64Array(&self, cx: JSContext) -> Float64Array { rooted!(in (*cx) let mut array = ptr::null_mut::()); - create_typed_array(cx, &self.matrix.borrow().to_array(), array.handle_mut()) + create_buffer_source_types(cx, &self.matrix.borrow().to_array(), array.handle_mut()) .expect("Converting matrix to float64 array should never fail") } } diff --git a/components/script/dom/filereadersync.rs b/components/script/dom/filereadersync.rs index 81590ffc9b6..ef47648d460 100644 --- a/components/script/dom/filereadersync.rs +++ b/components/script/dom/filereadersync.rs @@ -9,13 +9,13 @@ use js::jsapi::JSObject; use js::rust::HandleObject; use js::typedarray::{ArrayBuffer, ArrayBufferU8}; +use crate::dom::bindings::buffer_source::create_buffer_source_types; use crate::dom::bindings::codegen::Bindings::BlobBinding::BlobMethods; use crate::dom::bindings::codegen::Bindings::FileReaderSyncBinding::FileReaderSyncMethods; use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; -use crate::dom::bindings::typedarrays::create_typed_array; use crate::dom::blob::Blob; use crate::dom::filereader::FileReaderSharedFunctionality; use crate::dom::globalscope::GlobalScope; @@ -95,7 +95,7 @@ impl FileReaderSyncMethods for FileReaderSync { // step 2 rooted!(in(*cx) let mut array_buffer = ptr::null_mut::()); - create_typed_array::(cx, &blob_contents, array_buffer.handle_mut()) + create_buffer_source_types::(cx, &blob_contents, array_buffer.handle_mut()) .map_err(|_| Error::JSFailed) } } diff --git a/components/script/dom/gamepad.rs b/components/script/dom/gamepad.rs index c25db0747ca..2cf327cd06e 100644 --- a/components/script/dom/gamepad.rs +++ b/components/script/dom/gamepad.rs @@ -7,7 +7,7 @@ use std::cell::Cell; use dom_struct::dom_struct; use js::typedarray::{Float64, Float64Array}; -use super::bindings::typedarrays::HeapTypedArray; +use super::bindings::buffer_source::HeapBufferSource; use crate::dom::bindings::codegen::Bindings::GamepadBinding::{GamepadHand, GamepadMethods}; use crate::dom::bindings::codegen::Bindings::GamepadButtonListBinding::GamepadButtonListMethods; use crate::dom::bindings::inheritance::Castable; @@ -37,7 +37,7 @@ pub struct Gamepad { timestamp: Cell, mapping_type: String, #[ignore_malloc_size_of = "mozjs"] - axes: HeapTypedArray, + axes: HeapBufferSource, buttons: Dom, pose: Option>, #[ignore_malloc_size_of = "Defined in rust-webvr"] @@ -68,7 +68,7 @@ impl Gamepad { connected: Cell::new(connected), timestamp: Cell::new(timestamp), mapping_type: mapping_type, - axes: HeapTypedArray::default(), + axes: HeapBufferSource::default(), buttons: Dom::from_ref(buttons), pose: pose.map(Dom::from_ref), hand: hand, @@ -150,9 +150,7 @@ impl GamepadMethods for Gamepad { // https://w3c.github.io/gamepad/#dom-gamepad-axes fn Axes(&self, _cx: JSContext) -> Float64Array { - self.axes - .get_internal() - .expect("Failed to get gamepad axes.") + self.axes.get_buffer().expect("Failed to get gamepad axes.") } // https://w3c.github.io/gamepad/#dom-gamepad-buttons @@ -232,7 +230,7 @@ impl Gamepad { if normalized_value.is_finite() { let mut axis_vec = self .axes - .internal_to_option() + .buffer_to_option() .expect("Axes have not been initialized!"); unsafe { axis_vec.as_mut_slice()[axis_index] = normalized_value; diff --git a/components/script/dom/gamepadpose.rs b/components/script/dom/gamepadpose.rs index 709c6fd7648..d17681b3a0a 100644 --- a/components/script/dom/gamepadpose.rs +++ b/components/script/dom/gamepadpose.rs @@ -5,7 +5,7 @@ use dom_struct::dom_struct; use js::typedarray::{Float32, Float32Array}; -use super::bindings::typedarrays::HeapTypedArray; +use super::bindings::buffer_source::HeapBufferSource; use crate::dom::bindings::codegen::Bindings::GamepadPoseBinding::GamepadPoseMethods; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; @@ -16,17 +16,17 @@ use crate::script_runtime::JSContext; pub struct GamepadPose { reflector_: Reflector, #[ignore_malloc_size_of = "mozjs"] - position: HeapTypedArray, + position: HeapBufferSource, #[ignore_malloc_size_of = "mozjs"] - orientation: HeapTypedArray, + orientation: HeapBufferSource, #[ignore_malloc_size_of = "mozjs"] - linear_vel: HeapTypedArray, + linear_vel: HeapBufferSource, #[ignore_malloc_size_of = "mozjs"] - angular_vel: HeapTypedArray, + angular_vel: HeapBufferSource, #[ignore_malloc_size_of = "mozjs"] - linear_acc: HeapTypedArray, + linear_acc: HeapBufferSource, #[ignore_malloc_size_of = "mozjs"] - angular_acc: HeapTypedArray, + angular_acc: HeapBufferSource, } // TODO: support gamepad discovery @@ -35,12 +35,12 @@ impl GamepadPose { fn new_inherited() -> GamepadPose { GamepadPose { reflector_: Reflector::new(), - position: HeapTypedArray::default(), - orientation: HeapTypedArray::default(), - linear_vel: HeapTypedArray::default(), - angular_vel: HeapTypedArray::default(), - linear_acc: HeapTypedArray::default(), - angular_acc: HeapTypedArray::default(), + position: HeapBufferSource::default(), + orientation: HeapBufferSource::default(), + linear_vel: HeapBufferSource::default(), + angular_vel: HeapBufferSource::default(), + linear_acc: HeapBufferSource::default(), + angular_acc: HeapBufferSource::default(), } } @@ -52,7 +52,7 @@ impl GamepadPose { impl GamepadPoseMethods for GamepadPose { // https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-position fn GetPosition(&self, _cx: JSContext) -> Option { - self.position.internal_to_option() + self.position.buffer_to_option() } // https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-hasposition @@ -62,17 +62,17 @@ impl GamepadPoseMethods for GamepadPose { // https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-linearvelocity fn GetLinearVelocity(&self, _cx: JSContext) -> Option { - self.linear_vel.internal_to_option() + self.linear_vel.buffer_to_option() } // https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-linearacceleration fn GetLinearAcceleration(&self, _cx: JSContext) -> Option { - self.linear_acc.internal_to_option() + self.linear_acc.buffer_to_option() } // https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-orientation fn GetOrientation(&self, _cx: JSContext) -> Option { - self.orientation.internal_to_option() + self.orientation.buffer_to_option() } // https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-orientation @@ -82,11 +82,11 @@ impl GamepadPoseMethods for GamepadPose { // https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-angularvelocity fn GetAngularVelocity(&self, _cx: JSContext) -> Option { - self.angular_vel.internal_to_option() + self.angular_vel.buffer_to_option() } // https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-angularacceleration fn GetAngularAcceleration(&self, _cx: JSContext) -> Option { - self.angular_acc.internal_to_option() + self.angular_acc.buffer_to_option() } } diff --git a/components/script/dom/gpubuffer.rs b/components/script/dom/gpubuffer.rs index 6031778179c..10ced4a654e 100644 --- a/components/script/dom/gpubuffer.rs +++ b/components/script/dom/gpubuffer.rs @@ -15,7 +15,7 @@ use webgpu::identity::WebGPUOpResult; use webgpu::wgpu::device::HostMap; use webgpu::{WebGPU, WebGPUBuffer, WebGPURequest, WebGPUResponse, WebGPUResponseResult}; -use super::bindings::typedarrays::{create_new_external_array_buffer, HeapTypedArray}; +use super::bindings::buffer_source::{create_new_external_array_buffer, HeapBufferSource}; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ GPUBufferMethods, GPUMapModeConstants, GPUSize64, @@ -54,7 +54,7 @@ pub struct GPUBufferMapInfo { pub mapping_range: Range, pub mapped_ranges: Vec>, #[ignore_malloc_size_of = "defined in mozjs"] - pub js_buffers: Vec>, + pub js_buffers: Vec>, pub map_mode: Option, } @@ -169,7 +169,7 @@ impl GPUBufferMethods for GPUBuffer { } // Step 3.3 m_info.js_buffers.drain(..).for_each(|obj| { - obj.detach_internal(cx); + obj.detach_buffer(cx); }); }, // Step 2 @@ -325,7 +325,7 @@ impl GPUBufferMethods for GPUBuffer { m_end as usize, ); - let result = heap_typed_array.get_internal().map_err(|_| Error::JSFailed); + let result = heap_typed_array.get_buffer().map_err(|_| Error::JSFailed); m_info.mapped_ranges.push(offset..m_end); m_info.js_buffers.push(heap_typed_array); diff --git a/components/script/dom/imagedata.rs b/components/script/dom/imagedata.rs index a2907a98b3f..ba11fcd05c5 100644 --- a/components/script/dom/imagedata.rs +++ b/components/script/dom/imagedata.rs @@ -9,12 +9,12 @@ use std::vec::Vec; use dom_struct::dom_struct; use euclid::default::{Rect, Size2D}; use ipc_channel::ipc::IpcSharedMemory; -use js::jsapi::JSObject; +use js::jsapi::{Heap, JSObject}; use js::rust::HandleObject; use js::typedarray::{ClampedU8, CreateWith, Uint8ClampedArray}; -use super::bindings::typedarrays::{ - new_initialized_heap_typed_array, HeapTypedArray, HeapTypedArrayInit, +use super::bindings::buffer_source::{ + new_initialized_heap_buffer_source_types, BufferSource, HeapBufferSource, HeapTypedArrayInit, }; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::ImageDataMethods; use crate::dom::bindings::error::{Error, Fallible}; @@ -29,7 +29,7 @@ pub struct ImageData { width: u32, height: u32, #[ignore_malloc_size_of = "mozjs"] - data: HeapTypedArray, + data: HeapBufferSource, } impl ImageData { @@ -63,14 +63,14 @@ impl ImageData { opt_height: Option, jsobject: *mut JSObject, ) -> Fallible> { - let heap_typed_array = match new_initialized_heap_typed_array::( - HeapTypedArrayInit::Object(jsobject), + let heap_typed_array = match new_initialized_heap_buffer_source_types::( + HeapTypedArrayInit::Buffer(BufferSource::Uint8ClampedArray(Heap::boxed(jsobject))), ) { Ok(heap_typed_array) => heap_typed_array, Err(_) => return Err(Error::JSFailed), }; - let typed_array = match heap_typed_array.get_internal() { + let typed_array = match heap_typed_array.get_buffer() { Ok(array) => array, Err(_) => { return Err(Error::Type( @@ -117,7 +117,7 @@ impl ImageData { let len = width * height * 4; let heap_typed_array = - match new_initialized_heap_typed_array::(HeapTypedArrayInit::Info { + match new_initialized_heap_buffer_source_types::(HeapTypedArrayInit::Info { len, cx, }) { @@ -163,7 +163,7 @@ impl ImageData { assert!(self.data.is_initialized()); let internal_data = self .data - .get_internal() + .get_buffer() .expect("Failed to get Data from ImageData."); // NOTE(nox): This is just as unsafe as `as_slice` itself even though we // are extending the lifetime of the slice, because the data in @@ -202,6 +202,6 @@ impl ImageDataMethods for ImageData { /// fn GetData(&self, _: JSContext) -> Fallible { - self.data.get_internal().map_err(|_| Error::JSFailed) + self.data.get_buffer().map_err(|_| Error::JSFailed) } } diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index bd7fd7c4fa3..464ca0220dd 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -17,6 +17,7 @@ use script_traits::serializable::BlobImpl; use script_traits::MsDuration; use servo_config::prefs; +use crate::dom::bindings::buffer_source::create_buffer_source_types; use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::codegen::Bindings::EventListenerBinding::EventListener; use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function; @@ -41,7 +42,6 @@ use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomObject, use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::{ByteString, DOMString, USVString}; use crate::dom::bindings::trace::RootedTraceableBox; -use crate::dom::bindings::typedarrays::create_typed_array; use crate::dom::bindings::weakref::MutableWeakRef; use crate::dom::blob::Blob; use crate::dom::globalscope::GlobalScope; @@ -214,7 +214,7 @@ impl TestBindingMethods for TestBinding { let data: [u8; 16] = [0; 16]; rooted!(in (*cx) let mut array = ptr::null_mut::()); - create_typed_array(cx, &data, array.handle_mut()) + create_buffer_source_types(cx, &data, array.handle_mut()) .expect("Creating ClampedU8 array should never fail") } fn AnyAttribute(&self, _: SafeJSContext) -> JSVal { diff --git a/components/script/dom/textencoder.rs b/components/script/dom/textencoder.rs index 20c9116f04b..f237dca3903 100644 --- a/components/script/dom/textencoder.rs +++ b/components/script/dom/textencoder.rs @@ -9,12 +9,12 @@ use js::jsapi::JSObject; use js::rust::HandleObject; use js::typedarray::Uint8Array; +use crate::dom::bindings::buffer_source::create_buffer_source_types; use crate::dom::bindings::codegen::Bindings::TextEncoderBinding::TextEncoderMethods; use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::{DOMString, USVString}; -use crate::dom::bindings::typedarrays::create_typed_array; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::JSContext; @@ -55,7 +55,7 @@ impl TextEncoderMethods for TextEncoder { let encoded = input.0.as_bytes(); rooted!(in(*cx) let mut js_object = ptr::null_mut::()); - create_typed_array(cx, &encoded, js_object.handle_mut()) + create_buffer_source_types(cx, &encoded, js_object.handle_mut()) .expect("Converting input to uint8 array should never fail") } } diff --git a/components/script/dom/xrray.rs b/components/script/dom/xrray.rs index a91395acb8a..b1d699761bd 100644 --- a/components/script/dom/xrray.rs +++ b/components/script/dom/xrray.rs @@ -8,7 +8,7 @@ use js::rust::HandleObject; use js::typedarray::{Float32, Float32Array}; use webxr_api::{ApiSpace, Ray}; -use super::bindings::typedarrays::HeapTypedArray; +use super::bindings::buffer_source::HeapBufferSource; use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit; use crate::dom::bindings::codegen::Bindings::XRRayBinding::{XRRayDirectionInit, XRRayMethods}; use crate::dom::bindings::error::{Error, Fallible}; @@ -27,7 +27,7 @@ pub struct XRRay { #[no_trace] ray: Ray, #[ignore_malloc_size_of = "defined in mozjs"] - matrix: HeapTypedArray, + matrix: HeapBufferSource, } impl XRRay { @@ -35,7 +35,7 @@ impl XRRay { XRRay { reflector_: Reflector::new(), ray, - matrix: HeapTypedArray::default(), + matrix: HeapBufferSource::default(), } } @@ -163,7 +163,7 @@ impl XRRayMethods for XRRay { } self.matrix - .get_internal() + .get_buffer() .expect("Failed to get matrix from XRRay.") } } diff --git a/components/script/dom/xrrigidtransform.rs b/components/script/dom/xrrigidtransform.rs index b5677cd48ba..2f44b23b44e 100644 --- a/components/script/dom/xrrigidtransform.rs +++ b/components/script/dom/xrrigidtransform.rs @@ -7,7 +7,7 @@ use euclid::{RigidTransform3D, Rotation3D, Vector3D}; use js::rust::HandleObject; use js::typedarray::{Float32, Float32Array}; -use super::bindings::typedarrays::HeapTypedArray; +use super::bindings::buffer_source::HeapBufferSource; use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit; use crate::dom::bindings::codegen::Bindings::XRRigidTransformBinding::XRRigidTransformMethods; use crate::dom::bindings::error::{Error, Fallible}; @@ -29,7 +29,7 @@ pub struct XRRigidTransform { transform: ApiRigidTransform, inverse: MutNullableDom, #[ignore_malloc_size_of = "defined in mozjs"] - matrix: HeapTypedArray, + matrix: HeapBufferSource, } impl XRRigidTransform { @@ -40,7 +40,7 @@ impl XRRigidTransform { orientation: MutNullableDom::default(), transform, inverse: MutNullableDom::default(), - matrix: HeapTypedArray::default(), + matrix: HeapBufferSource::default(), } } @@ -140,7 +140,7 @@ impl XRRigidTransformMethods for XRRigidTransform { } self.matrix - .get_internal() + .get_buffer() .expect("Failed to get transform's internal matrix.") } } diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs index 6c8c7ab2f7d..ef566111b69 100644 --- a/components/script/dom/xrview.rs +++ b/components/script/dom/xrview.rs @@ -7,7 +7,7 @@ use euclid::RigidTransform3D; use js::typedarray::{Float32, Float32Array}; use webxr_api::{ApiSpace, View}; -use super::bindings::typedarrays::HeapTypedArray; +use super::bindings::buffer_source::HeapBufferSource; use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods}; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; @@ -23,7 +23,7 @@ pub struct XRView { eye: XREye, viewport_index: usize, #[ignore_malloc_size_of = "mozjs"] - proj: HeapTypedArray, + proj: HeapBufferSource, #[ignore_malloc_size_of = "defined in rust-webxr"] #[no_trace] view: View, @@ -43,7 +43,7 @@ impl XRView { session: Dom::from_ref(session), eye, viewport_index, - proj: HeapTypedArray::default(), + proj: HeapBufferSource::default(), view, transform: Dom::from_ref(transform), } @@ -98,7 +98,7 @@ impl XRViewMethods for XRView { .expect("Failed to set projection matrix.") } self.proj - .get_internal() + .get_buffer() .expect("Failed to get projection matrix.") }