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::NewExternalArrayBuffer;
12use js::typedarray::{ArrayBufferU8, HeapArrayBuffer};
13use jstraceable_derive::JSTraceable;
14use malloc_size_of_derive::MallocSizeOf;
15use script_bindings::buffer_source::HeapBufferSource;
16use script_bindings::trace::RootedTraceableBox;
17use servo_base::generic_channel::GenericSharedMemory;
18
19#[derive(JSTraceable, MallocSizeOf)]
20#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
21pub(crate) struct DataBlock {
22 #[conditional_malloc_size_of]
23 data: Arc<GenericSharedMemory>,
24 data_views: Vec<DataView>,
26}
27
28fn range_overlap<T: std::cmp::PartialOrd>(range1: &Range<T>, range2: &Range<T>) -> bool {
31 range1.start < range2.end && range2.start < range1.end
32}
33
34impl DataBlock {
35 pub(crate) fn new_zeroed(size: usize) -> Self {
36 Self {
37 data: Arc::new(GenericSharedMemory::from_byte(0, size)),
38 data_views: Vec::new(),
39 }
40 }
41
42 pub(crate) fn new_from_shared_memory(data: GenericSharedMemory) -> Self {
43 Self {
44 data: Arc::new(data),
45 data_views: Vec::new(),
46 }
47 }
48
49 #[cfg_attr(
50 crown,
51 expect(
52 crown::unrooted_must_root,
53 reason = "Underlying content is rooted when GC can happen"
54 )
55 )]
56 pub(crate) fn clear_views(&mut self, cx: &mut JSContext) {
57 while let Some(DataView { buffer, .. }) = self.data_views.pop() {
59 let buffer = RootedTraceableBox::new(buffer);
60 assert!(buffer.detach_buffer(cx))
61 }
62 }
63
64 pub(crate) fn view(
66 &mut self,
67 cx: &mut JSContext,
68 range: Range<usize>,
69 ) -> Result<&DataView, ()> {
70 if self
71 .data_views
72 .iter()
73 .any(|view| range_overlap(&view.range, &range))
74 {
75 return Err(());
76 }
77 let range_len = range
78 .end
79 .checked_sub(range.start)
80 .expect("range end must be >= range start");
81 assert!(range.end <= self.data.as_ref().len());
82
83 unsafe extern "C" fn free_func(_contents: *mut c_void, free_user_data: *mut c_void) {
86 let raw: *const GenericSharedMemory = free_user_data.cast();
87 drop(unsafe { Arc::from_raw(raw) });
91 }
92 let raw: *const GenericSharedMemory = Arc::into_raw(Arc::clone(&self.data));
93 let data_ptr = unsafe { (*raw).as_ptr().add(range.start) };
97 rooted!(&in(cx) let object = unsafe {
98 NewExternalArrayBuffer(
99 cx,
100 range_len,
101 data_ptr.cast_mut().cast(),
104 Some(free_func),
105 raw as _,
106 )
107 });
108 self.data_views.push(DataView {
109 range,
110 buffer: HeapBufferSource::new(object.handle()),
111 });
112 Ok(self.data_views.last().unwrap())
113 }
114
115 #[cfg_attr(
116 crown,
117 expect(
118 crown::unrooted_must_root,
119 reason = "No GC can happen when this is called"
120 )
121 )]
122 pub(crate) fn consume(self) -> GenericSharedMemory {
123 Arc::into_inner(self.data).expect("No view should be alive")
124 }
125}
126
127#[derive(JSTraceable, MallocSizeOf)]
130#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
131pub(crate) struct DataView {
132 #[no_trace]
133 range: Range<usize>,
134 #[ignore_malloc_size_of = "HeapBufferSource"]
135 buffer: HeapBufferSource<ArrayBufferU8>,
136}
137
138impl DataView {
139 pub(crate) fn array_buffer(&self) -> RootedTraceableBox<HeapArrayBuffer> {
140 self.buffer.get_typed_array().unwrap()
141 }
142}