Skip to content

Commit 8f58910

Browse files
hansltheoparisjedel1043
committed
Allow dead code for code that is newly detected as unused (#3984)
* Allow dead code for code that is newly detected as unused * Fix compile errors with nightly rust * Add missing SAFETY section * Increase safety of `FutexWaiters` --------- Co-authored-by: Theo Paris <[email protected]> Co-authored-by: José Julián Espina <[email protected]>
1 parent 19ae8ed commit 8f58910

File tree

2 files changed

+115
-98
lines changed

2 files changed

+115
-98
lines changed

core/engine/src/builtins/atomics/futex.rs

Lines changed: 111 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -139,120 +139,139 @@
139139
#![allow(clippy::expl_impl_clone_on_copy)]
140140
#![allow(unstable_name_collisions)]
141141

142-
use std::{
143-
cell::UnsafeCell,
144-
sync::{atomic::Ordering, Condvar, Mutex},
145-
};
142+
use std::{cell::UnsafeCell, sync::atomic::Ordering};
146143

147-
use intrusive_collections::{intrusive_adapter, LinkedList, LinkedListLink, UnsafeRef};
148144
use sptr::Strict;
149145

150146
use crate::{
151147
builtins::{
152148
array_buffer::{utils::SliceRef, SharedArrayBuffer},
153149
typed_array::Element,
154150
},
155-
small_map::{Entry, SmallMap},
156151
sys::time::{Duration, Instant},
157152
JsNativeError, JsResult,
158153
};
159154

160-
/// Map of shared data addresses and its corresponding list of agents waiting on that location.
161-
pub(crate) static CRITICAL_SECTION: Mutex<FutexWaiters> = Mutex::new(FutexWaiters {
162-
waiters: SmallMap::new(),
163-
});
164-
165-
/// A waiter of a memory address.
166-
#[derive(Debug, Default)]
167-
pub(crate) struct FutexWaiter {
168-
pub(super) link: LinkedListLink,
169-
pub(super) cond_var: Condvar,
170-
pub(super) waiting: bool,
171-
addr: usize,
172-
}
155+
mod sync {
156+
use std::sync::{Condvar, Mutex, MutexGuard};
173157

174-
intrusive_adapter!(FutexWaiterAdapter = UnsafeRef<FutexWaiter>: FutexWaiter { link: LinkedListLink });
158+
use intrusive_collections::{intrusive_adapter, LinkedList, LinkedListLink, UnsafeRef};
175159

176-
/// List of memory addresses and its corresponding list of waiters for that address.
177-
#[derive(Debug)]
178-
pub(crate) struct FutexWaiters {
179-
waiters: SmallMap<usize, LinkedList<FutexWaiterAdapter>, 16>,
180-
}
160+
use crate::{
161+
small_map::{Entry, SmallMap},
162+
JsNativeError, JsResult,
163+
};
181164

182-
impl FutexWaiters {
183-
/// Notifies at most `max_count` waiters that are waiting on the address `addr`, and
184-
/// returns the number of waiters that were notified.
185-
///
186-
/// Equivalent to [`RemoveWaiters`][remove] and [`NotifyWaiter`][notify], but in a single operation.
187-
///
188-
/// [remove]: https://tc39.es/ecma262/#sec-removewaiters
189-
/// [notify]: https://tc39.es/ecma262/#sec-notifywaiter
190-
pub(crate) fn notify_many(&mut self, addr: usize, max_count: u64) -> u64 {
191-
let Entry::Occupied(mut wl) = self.waiters.entry(addr) else {
192-
return 0;
193-
};
194-
195-
for i in 0..max_count {
196-
let Some(elem) = wl.get_mut().pop_front() else {
197-
wl.remove();
198-
return i;
165+
/// A waiter of a memory address.
166+
#[derive(Debug, Default)]
167+
pub(crate) struct FutexWaiter {
168+
pub(super) link: LinkedListLink,
169+
pub(super) cond_var: Condvar,
170+
pub(super) waiting: bool,
171+
addr: usize,
172+
}
173+
174+
intrusive_adapter!(FutexWaiterAdapter = UnsafeRef<FutexWaiter>: FutexWaiter { link: LinkedListLink });
175+
176+
/// List of memory addresses and its corresponding list of waiters for that address.
177+
#[derive(Debug)]
178+
pub(super) struct FutexWaiters {
179+
waiters: SmallMap<usize, LinkedList<FutexWaiterAdapter>, 16>,
180+
}
181+
182+
// SAFETY: `FutexWaiters` is not constructable outside its `get` method, and it's only exposed by
183+
// a global lock, meaning the inner data of `FutexWaiters` (which includes non-Send pointers)
184+
// can only be accessed by a single thread at once.
185+
unsafe impl Send for FutexWaiters {}
186+
187+
impl FutexWaiters {
188+
/// Gets the map of all shared data addresses and its corresponding list of agents waiting on that location.
189+
pub(super) fn get() -> JsResult<MutexGuard<'static, Self>> {
190+
static CRITICAL_SECTION: Mutex<FutexWaiters> = Mutex::new(FutexWaiters {
191+
waiters: SmallMap::new(),
192+
});
193+
194+
CRITICAL_SECTION.lock().map_err(|_| {
195+
JsNativeError::typ()
196+
.with_message("failed to synchronize with the agent cluster")
197+
.into()
198+
})
199+
}
200+
201+
/// Notifies at most `max_count` waiters that are waiting on the address `addr`, and
202+
/// returns the number of waiters that were notified.
203+
///
204+
/// Equivalent to [`RemoveWaiters`][remove] and [`NotifyWaiter`][notify], but in a single operation.
205+
///
206+
/// [remove]: https://tc39.es/ecma262/#sec-removewaiters
207+
/// [notify]: https://tc39.es/ecma262/#sec-notifywaiter
208+
pub(super) fn notify_many(&mut self, addr: usize, max_count: u64) -> u64 {
209+
let Entry::Occupied(mut wl) = self.waiters.entry(addr) else {
210+
return 0;
199211
};
200212

201-
elem.cond_var.notify_one();
213+
for i in 0..max_count {
214+
let Some(elem) = wl.get_mut().pop_front() else {
215+
wl.remove();
216+
return i;
217+
};
202218

203-
// SAFETY: all elements of the waiters list are guaranteed to be valid.
204-
unsafe {
205-
(*UnsafeRef::into_raw(elem)).waiting = false;
219+
elem.cond_var.notify_one();
220+
221+
// SAFETY: all elements of the waiters list are guaranteed to be valid.
222+
unsafe {
223+
(*UnsafeRef::into_raw(elem)).waiting = false;
224+
}
206225
}
207-
}
208226

209-
if wl.get().is_empty() {
210-
wl.remove();
211-
}
227+
if wl.get().is_empty() {
228+
wl.remove();
229+
}
212230

213-
max_count
214-
}
231+
max_count
232+
}
215233

216-
/// # Safety
217-
///
218-
/// - `node` must NOT be linked to an existing waiter list.
219-
/// - `node` must always point to a valid instance of `FutexWaiter` until `node` is
220-
/// removed from its linked list. This can happen by either `remove_waiter` or `notify_many`.
221-
pub(crate) unsafe fn add_waiter(&mut self, node: *mut FutexWaiter, addr: usize) {
222-
// SAFETY: `node` must point to a valid instance.
223-
let node = unsafe {
224-
debug_assert!(!(*node).link.is_linked());
225-
(*node).waiting = true;
226-
(*node).addr = addr;
227-
UnsafeRef::from_raw(node)
228-
};
229-
230-
self.waiters
231-
.entry(addr)
232-
.or_insert_with(|| LinkedList::new(FutexWaiterAdapter::new()))
233-
.push_back(node);
234-
}
234+
/// # Safety
235+
///
236+
/// - `node` must NOT be linked to an existing waiter list.
237+
/// - `node` must always point to a valid instance of `FutexWaiter` until `node` is
238+
/// removed from its linked list. This can happen by either `remove_waiter` or `notify_many`.
239+
pub(super) unsafe fn add_waiter(&mut self, node: *mut FutexWaiter, addr: usize) {
240+
// SAFETY: `node` must point to a valid instance.
241+
let node = unsafe {
242+
debug_assert!(!(*node).link.is_linked());
243+
(*node).waiting = true;
244+
(*node).addr = addr;
245+
UnsafeRef::from_raw(node)
246+
};
235247

236-
/// # Safety
237-
///
238-
/// - `node` must point to a valid instance of `FutexWaiter`.
239-
/// - `node` must be inside the wait list associated with `node.addr`.
240-
pub(crate) unsafe fn remove_waiter(&mut self, node: *mut FutexWaiter) {
241-
// SAFETY: `node` must point to a valid instance.
242-
let addr = unsafe { (*node).addr };
243-
244-
let mut wl = match self.waiters.entry(addr) {
245-
Entry::Occupied(wl) => wl,
246-
Entry::Vacant(_) => return,
247-
};
248-
249-
// SAFETY: `node` must be inside the wait list associated with `node.addr`.
250-
unsafe {
251-
wl.get_mut().cursor_mut_from_ptr(node).remove();
248+
self.waiters
249+
.entry(addr)
250+
.or_insert_with(|| LinkedList::new(FutexWaiterAdapter::new()))
251+
.push_back(node);
252252
}
253253

254-
if wl.get().is_empty() {
255-
wl.remove();
254+
/// # Safety
255+
///
256+
/// - `node` must point to a valid instance of `FutexWaiter`.
257+
/// - `node` must be inside the wait list associated with `node.addr`.
258+
pub(super) unsafe fn remove_waiter(&mut self, node: *mut FutexWaiter) {
259+
// SAFETY: `node` must point to a valid instance.
260+
let addr = unsafe { (*node).addr };
261+
262+
let mut wl = match self.waiters.entry(addr) {
263+
Entry::Occupied(wl) => wl,
264+
Entry::Vacant(_) => return,
265+
};
266+
267+
// SAFETY: `node` must be inside the wait list associated with `node.addr`.
268+
unsafe {
269+
wl.get_mut().cursor_mut_from_ptr(node).remove();
270+
}
271+
272+
if wl.get().is_empty() {
273+
wl.remove();
274+
}
256275
}
257276
}
258277
}
@@ -281,10 +300,7 @@ pub(super) unsafe fn wait<E: Element + PartialEq>(
281300
// 10. Let block be buffer.[[ArrayBufferData]].
282301
// 11. Let WL be GetWaiterList(block, indexedPosition).
283302
// 12. Perform EnterCriticalSection(WL).
284-
let mut waiters = CRITICAL_SECTION.lock().map_err(|_| {
285-
// avoids exposing internals of our implementation.
286-
JsNativeError::typ().with_message("failed to synchronize with the agent cluster")
287-
})?;
303+
let mut waiters = sync::FutexWaiters::get()?;
288304

289305
let time_info = timeout.map(|timeout| (Instant::now(), timeout));
290306

@@ -307,7 +323,7 @@ pub(super) unsafe fn wait<E: Element + PartialEq>(
307323
// 17. Perform AddWaiter(WL, W).
308324

309325
// ensure we can have aliased pointers to the waiter in a sound way.
310-
let waiter = UnsafeCell::new(FutexWaiter::default());
326+
let waiter = UnsafeCell::new(sync::FutexWaiter::default());
311327
let waiter_ptr = waiter.get();
312328

313329
// SAFETY: waiter is valid and we call `remove_node` below.
@@ -385,10 +401,7 @@ pub(super) fn notify(buffer: &SharedArrayBuffer, offset: usize, count: u64) -> J
385401

386402
// 7. Let WL be GetWaiterList(block, indexedPosition).
387403
// 8. Perform EnterCriticalSection(WL).
388-
let mut waiters = CRITICAL_SECTION.lock().map_err(|_| {
389-
// avoids exposing internals of our implementation.
390-
JsNativeError::typ().with_message("failed to synchronize with the agent cluster")
391-
})?;
404+
let mut waiters = sync::FutexWaiters::get()?;
392405

393406
// 9. Let S be RemoveWaiters(WL, c).
394407
// 10. For each element W of S, do

core/engine/src/builtins/builder.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@ use crate::{
1616
use super::{function::ConstructorKind, BuiltInConstructor, IntrinsicObject};
1717

1818
/// Marker for a constructor function.
19+
// TODO: Remove this marker and use `Constructor` directly.
20+
#[allow(dead_code)]
1921
pub(crate) struct Constructor {
2022
prototype: JsObject,
2123
inherits: JsPrototype,
2224
attributes: Attribute,
2325
}
2426

2527
/// Marker for a constructor function without a custom prototype for its instances.
28+
// TODO: Remove this marker and use `ConstructorNoProto` directly.
29+
#[allow(dead_code)]
2630
pub(crate) struct ConstructorNoProto;
2731

2832
/// Marker for an ordinary function.

0 commit comments

Comments
 (0)