script_webgpu/
datablock.rs1use std::ffi::c_void;
6use std::ops::Range;
7use std::sync::Arc;
8
9use js::context::JSContext;
10use js::rooted;
11use js::rust::wrappers2::{DetachArrayBuffer, NewExternalArrayBuffer};
12use js::typedarray::HeapArrayBuffer;
13use jstraceable_derive::JSTraceable;
14use malloc_size_of_derive::MallocSizeOf;
15use script_bindings::trace::RootedTraceableBox;
16
17#[derive(JSTraceable, MallocSizeOf)]
18#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
19pub(crate) struct DataBlock {
20 #[conditional_malloc_size_of]
21 data: Arc<Box<[u8]>>,
22 data_views: Vec<DataView>,
24}
25
26fn range_overlap<T: std::cmp::PartialOrd>(range1: &Range<T>, range2: &Range<T>) -> bool {
29 range1.start < range2.end && range2.start < range1.end
30}
31
32impl DataBlock {
33 pub(crate) fn new_zeroed(size: usize) -> Self {
34 let data = vec![0; size];
35 Self {
36 data: Arc::new(data.into_boxed_slice()),
37 data_views: Vec::new(),
38 }
39 }
40
41 pub(crate) fn load(&mut self, src: &[u8]) {
43 Arc::get_mut(&mut self.data).unwrap().clone_from_slice(src)
45 }
46
47 pub(crate) fn data(&mut self) -> &mut [u8] {
49 Arc::get_mut(&mut self.data).unwrap()
51 }
52
53 #[cfg_attr(
54 crown,
55 expect(
56 crown::unrooted_must_root,
57 reason = "Underlying content is rooted when GC can happen"
58 )
59 )]
60 pub(crate) fn clear_views(&mut self, cx: &mut JSContext) {
61 while let Some(DataView { buffer, .. }) = self.data_views.pop() {
63 rooted!(&in(cx) let b = unsafe { buffer.underlying_object().get() });
64 assert!(unsafe { DetachArrayBuffer(cx, b.handle()) })
65 }
66 }
67
68 pub(crate) fn view(
70 &mut self,
71 cx: &mut JSContext,
72 range: Range<usize>,
73 ) -> Result<&DataView, ()> {
74 if self
75 .data_views
76 .iter()
77 .any(|view| range_overlap(&view.range, &range))
78 {
79 return Err(());
80 }
81 let range_len = range
82 .end
83 .checked_sub(range.start)
84 .expect("range end must be >= range start");
85 assert!(range.end <= self.data.len());
86
87 unsafe extern "C" fn free_func(_contents: *mut c_void, free_user_data: *mut c_void) {
90 let raw: *const Box<[u8]> = free_user_data.cast();
91 drop(unsafe { Arc::from_raw(raw) });
95 }
96 let raw: *const Box<[u8]> = Arc::into_raw(Arc::clone(&self.data));
97 let data_ptr = unsafe { (**raw).as_ptr().add(range.start) };
101 rooted!(&in(cx) let object = unsafe {
102 NewExternalArrayBuffer(
103 cx,
104 range_len,
105 data_ptr.cast_mut().cast(),
108 Some(free_func),
109 raw as _,
110 )
111 });
112 self.data_views.push(DataView {
113 range,
114 buffer: HeapArrayBuffer::from(*object).unwrap(),
115 });
116 Ok(self.data_views.last().unwrap())
117 }
118}
119
120#[derive(JSTraceable, MallocSizeOf)]
123#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
124pub(crate) struct DataView {
125 #[no_trace]
126 range: Range<usize>,
127 #[ignore_malloc_size_of = "defined in mozjs"]
128 buffer: HeapArrayBuffer,
129}
130
131impl DataView {
132 pub(crate) fn array_buffer(&self) -> RootedTraceableBox<HeapArrayBuffer> {
133 RootedTraceableBox::new(unsafe {
134 HeapArrayBuffer::from(self.buffer.underlying_object().get()).unwrap()
135 })
136 }
137}