about summary refs log tree commit diff
path: root/library/alloc/src
diff options
context:
space:
mode:
authorGuillaume Boisseau <Nadrieril@users.noreply.github.com>2024-03-02 20:13:22 +0100
committerGitHub <noreply@github.com>2024-03-02 20:13:22 +0100
commitb0ca9b5d445ea049f447c9fa03878922311f3c4a (patch)
tree76014a6aca32960a73a6e0c50094036b2935879a /library/alloc/src
parent8653c09087989489873a10054aeab43e5f9a5c87 (diff)
parentdb535bad791fcab1e802728fe7e0ca95804192af (diff)
downloadrust-b0ca9b5d445ea049f447c9fa03878922311f3c4a.tar.gz
rust-b0ca9b5d445ea049f447c9fa03878922311f3c4a.zip
Rollup merge of #121622 - dtolnay:wake, r=cuviper
Preserve same vtable pointer when cloning raw waker, to fix Waker::will_wake

Fixes #121600.

As `@jkarneges` identified in https://github.com/rust-lang/rust/issues/121600#issuecomment-1963041051, the issue is two different const promotions produce two statics at different addresses, which may or may not later be deduplicated by the linker (in this case not).

Prior to #119863, the content of the statics was compared, and they were equal. After, the address of the statics are compared and they are not equal.

It is documented that `will_wake` _"works on a best-effort basis, and may return false even when the Wakers would awaken the same task"_ so this PR fixes a quality-of-implementation issue, not a correctness issue.
Diffstat (limited to 'library/alloc/src')
-rw-r--r--library/alloc/src/task.rs13
1 files changed, 13 insertions, 0 deletions
diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs
index b214f4946b1..b40768a52b6 100644
--- a/library/alloc/src/task.rs
+++ b/library/alloc/src/task.rs
@@ -136,6 +136,15 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
 #[inline(always)]
 fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
     // Increment the reference count of the arc to clone it.
+    //
+    // The #[inline(always)] is to ensure that raw_waker and clone_waker are
+    // always generated in the same code generation unit as one another, and
+    // therefore that the structurally identical const-promoted RawWakerVTable
+    // within both functions is deduplicated at LLVM IR code generation time.
+    // This allows optimizing Waker::will_wake to a single pointer comparison of
+    // the vtable pointers, rather than comparing all four function pointers
+    // within the vtables.
+    #[inline(always)]
     unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
         unsafe { Arc::increment_strong_count(waker as *const W) };
         RawWaker::new(
@@ -304,6 +313,10 @@ impl<W: LocalWake + 'static> From<Rc<W>> for RawWaker {
 #[inline(always)]
 fn local_raw_waker<W: LocalWake + 'static>(waker: Rc<W>) -> RawWaker {
     // Increment the reference count of the Rc to clone it.
+    //
+    // Refer to the comment on raw_waker's clone_waker regarding why this is
+    // always inline.
+    #[inline(always)]
     unsafe fn clone_waker<W: LocalWake + 'static>(waker: *const ()) -> RawWaker {
         unsafe { Rc::increment_strong_count(waker as *const W) };
         RawWaker::new(