Skip to content

Commit a752895

Browse files
committed
compensate for regression in 1.78 (rust-lang/rust#123281)
1 parent aa7afbe commit a752895

File tree

4 files changed

+171
-22
lines changed

4 files changed

+171
-22
lines changed

stabby-abi/src/alloc/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,13 @@ impl<T, Alloc> AllocPtr<T, Alloc> {
264264
marker: PhantomData,
265265
}
266266
}
267+
/// Casts an allocated pointer.
268+
pub const fn cast<U>(self) -> AllocPtr<U, Alloc> {
269+
AllocPtr {
270+
ptr: self.ptr.cast(),
271+
marker: PhantomData,
272+
}
273+
}
267274
/// The offset between `self.ptr` and the prefix.
268275
pub const fn prefix_skip() -> usize {
269276
AllocPrefix::<Alloc>::skip_to::<T>()

stabby-abi/src/fatptr.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl<'a, Vt: Copy + 'a> DynRef<'a, Vt> {
140140
where
141141
Vt: PartialEq + IConstConstructor<'a, T>,
142142
{
143-
(self.vtable == Vt::VTABLE).then(|| unsafe { self.ptr.as_ref() })
143+
(self.vtable == Vt::vtable()).then(|| unsafe { self.ptr.as_ref() })
144144
}
145145
/// Downcasts the reference based on its reflection report.
146146
pub fn stable_downcast<T: crate::IStable, Path>(&self) -> Option<&T>
@@ -286,8 +286,7 @@ impl<'a, P: IPtrOwned + IPtr, Vt: HasDropVt + 'a> Dyn<'a, P, Vt> {
286286
where
287287
Vt: PartialEq + Copy + IConstConstructor<'a, T>,
288288
{
289-
eprintln!("{:p} vs {:p}", self.vtable(), Vt::VTABLE);
290-
(self.vtable == Vt::VTABLE).then(|| unsafe { self.ptr.as_ref() })
289+
(self.vtable == Vt::vtable()).then(|| unsafe { self.ptr.as_ref() })
291290
}
292291
/// Downcasts the reference based on its reflection report.
293292
pub fn stable_downcast_ref<T: crate::IStable, Path>(&self) -> Option<&T>
@@ -321,7 +320,7 @@ impl<'a, P: IPtrOwned + IPtr, Vt: HasDropVt + 'a> Dyn<'a, P, Vt> {
321320
Vt: PartialEq + Copy + IConstConstructor<'a, T>,
322321
P: IPtrMut,
323322
{
324-
(self.vtable == Vt::VTABLE).then(|| unsafe { self.ptr.as_mut() })
323+
(self.vtable == Vt::vtable()).then(|| unsafe { self.ptr.as_mut() })
325324
}
326325
/// Downcasts the mutable reference based on its reflection report.
327326
pub fn stable_downcast_mut<T: crate::IStable, Path>(&mut self) -> Option<&mut T>
@@ -344,7 +343,7 @@ where
344343
fn from(value: P) -> Self {
345344
Self {
346345
ptr: core::mem::ManuallyDrop::new(value.anonimize()),
347-
vtable: Vt::VTABLE,
346+
vtable: Vt::vtable(),
348347
unsend: core::marker::PhantomData,
349348
}
350349
}
@@ -363,7 +362,7 @@ impl<'a, T, Vt: Copy + IConstConstructor<'a, T>> From<&'a T> for DynRef<'a, Vt>
363362
unsafe {
364363
DynRef {
365364
ptr: core::mem::transmute(value),
366-
vtable: Vt::VTABLE,
365+
vtable: Vt::vtable(),
367366
unsend: core::marker::PhantomData,
368367
}
369368
}

stabby-abi/src/vtable.rs

Lines changed: 144 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,140 @@
1212
// Pierre Avital, <[email protected]>
1313
//
1414

15-
use crate as stabby;
15+
use crate::{self as stabby};
16+
use core::{
17+
hash::{Hash, Hasher},
18+
marker::PhantomData,
19+
ptr::NonNull,
20+
};
1621

1722
#[rustversion::nightly]
1823
/// Implementation detail for stabby's version of dyn traits.
1924
/// Any type that implements a trait `ITrait` must implement `IConstConstructor<VtITrait>` for `stabby::dyn!(Ptr<ITrait>)::from(value)` to work.
2025
pub trait IConstConstructor<'a, Source>: 'a + Copy + core::marker::Freeze {
2126
/// The vtable.
22-
const VTABLE: &'a Self;
27+
const VTABLE: Self;
28+
/// A reference to the vtable
29+
const VTABLE_REF: &'a Self = &Self::VTABLE;
30+
/// Returns the reference to the vtable
31+
fn vtable() -> &'a Self {
32+
Self::VTABLE_REF
33+
}
2334
}
24-
#[rustversion::not(nightly)]
35+
36+
#[rustversion::before(1.78.0)]
2537
/// Implementation detail for stabby's version of dyn traits.
2638
/// Any type that implements a trait `ITrait` must implement `IConstConstructor<VtITrait>` for `stabby::dyn!(Ptr<ITrait>)::from(value)` to work.
2739
pub trait IConstConstructor<'a, Source>: 'a + Copy {
2840
/// The vtable.
29-
const VTABLE: &'a Self;
41+
const VTABLE: Self;
42+
/// A reference to the vtable
43+
const VTABLE_REF: &'a Self = &Self::VTABLE;
44+
/// Returns the reference to the vtable
45+
fn vtable() -> &'a Self {
46+
Self::VTABLE_REF
47+
}
48+
}
49+
50+
#[cfg(feature = "libc")]
51+
#[rustversion::all(since(1.78.0), not(nightly))]
52+
static VTABLES: core::sync::atomic::AtomicPtr<
53+
crate::alloc::vec::Vec<(
54+
u64,
55+
crate::alloc::AllocPtr<*const (), crate::alloc::DefaultAllocator>,
56+
)>,
57+
> = core::sync::atomic::AtomicPtr::new(core::ptr::null_mut());
58+
#[cfg(feature = "libc")]
59+
#[rustversion::all(since(1.78.0), not(nightly))]
60+
/// Implementation detail for stabby's version of dyn traits.
61+
/// Any type that implements a trait `ITrait` must implement `IConstConstructor<VtITrait>` for `stabby::dyn!(Ptr<ITrait>)::from(value)` to work.
62+
pub trait IConstConstructor<'a, Source>: 'a + Copy + core::hash::Hash + core::fmt::Debug {
63+
/// The vtable.
64+
const VTABLE: Self;
65+
/// Returns the reference to the vtable
66+
fn vtable() -> &'a Self {
67+
use crate::alloc::{boxed::Box, vec::Vec, AllocPtr, DefaultAllocator};
68+
let vtable = Self::VTABLE;
69+
#[allow(deprecated)]
70+
let hash = {
71+
let mut hasher = core::hash::SipHasher::new();
72+
vtable.hash(&mut hasher);
73+
hasher.finish()
74+
};
75+
fn insert_vtable(hash: u64, vtable: &[*const ()]) -> AllocPtr<*const (), DefaultAllocator> {
76+
let mut search_start = 0;
77+
let mut allocated_vt = None;
78+
let mut vtables = VTABLES.load(core::sync::atomic::Ordering::SeqCst);
79+
loop {
80+
let vts = match unsafe { vtables.as_ref() } {
81+
None => [].as_slice(),
82+
Some(vts) => match vts[search_start..]
83+
.iter()
84+
.find_map(|e| (e.0 == hash).then_some(e.1))
85+
{
86+
Some(vt) => return vt,
87+
None => vts,
88+
},
89+
};
90+
let vt = allocated_vt.unwrap_or_else(|| {
91+
let mut ptr =
92+
AllocPtr::alloc_array(&mut DefaultAllocator::new(), vtable.len()).unwrap();
93+
unsafe {
94+
core::ptr::copy_nonoverlapping(vtable.as_ptr(), ptr.as_mut(), vtable.len())
95+
};
96+
ptr
97+
});
98+
allocated_vt = Some(vt);
99+
let updated = VTABLES.load(core::sync::atomic::Ordering::SeqCst);
100+
if !core::ptr::eq(vtables, updated) {
101+
vtables = updated;
102+
continue;
103+
}
104+
let mut vec = Vec::with_capacity(vts.len() + 1);
105+
vec.copy_extend(vts);
106+
vec.push((hash, vt));
107+
let mut vec = Box::into_raw(Box::new(vec));
108+
match VTABLES.compare_exchange(
109+
updated,
110+
unsafe { vec.as_mut() },
111+
core::sync::atomic::Ordering::SeqCst,
112+
core::sync::atomic::Ordering::SeqCst,
113+
) {
114+
Ok(updated) => {
115+
if let Some(updated) = NonNull::new(updated) {
116+
unsafe {
117+
Box::from_raw(AllocPtr {
118+
ptr: updated,
119+
marker: PhantomData::<DefaultAllocator>,
120+
})
121+
};
122+
}
123+
return vt;
124+
}
125+
Err(new_vtables) => {
126+
search_start = vts.len();
127+
vtables = new_vtables;
128+
unsafe { Box::from_raw(vec) };
129+
}
130+
}
131+
}
132+
}
133+
unsafe {
134+
let vtable = core::slice::from_raw_parts(
135+
(&vtable as *const Self).cast(),
136+
core::mem::size_of::<Self>() / core::mem::size_of::<*const ()>(),
137+
);
138+
let vt = insert_vtable(hash, vtable).cast().as_ref();
139+
debug_assert_eq!(
140+
core::slice::from_raw_parts(
141+
(vt as *const Self).cast::<*const ()>(),
142+
core::mem::size_of::<Self>() / core::mem::size_of::<*const ()>(),
143+
),
144+
vtable
145+
);
146+
vt
147+
}
148+
}
30149
}
31150

32151
/// Implementation detail for stabby's version of dyn traits.
@@ -42,7 +161,7 @@ pub struct T<T>(T);
42161
/// You should _always_ use `stabby::vtable!(Trait1 + Trait2 + ...)` to generate this type,
43162
/// as this macro will ensure that traits are ordered consistently in the vtable.
44163
#[stabby::stabby]
45-
#[derive(Clone, Copy, PartialEq, Eq)]
164+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
46165
pub struct VTable<Head, Tail = VtDrop> {
47166
/// The rest of the vtable.
48167
///
@@ -63,13 +182,13 @@ where
63182
Head: IConstConstructor<'a, T>,
64183
Tail: IConstConstructor<'a, T>,
65184
{
66-
const VTABLE: &'a VTable<Head, Tail> = &VTable {
67-
head: *Head::VTABLE,
68-
tail: *Tail::VTABLE,
185+
const VTABLE: VTable<Head, Tail> = VTable {
186+
head: Head::VTABLE,
187+
tail: Tail::VTABLE,
69188
};
70189
}
71190
impl<'a, T> IConstConstructor<'a, T> for () {
72-
const VTABLE: &'a () = &();
191+
const VTABLE: () = ();
73192
}
74193
impl<Head, Tail> TransitiveDeref<Head, H> for VTable<Head, Tail> {
75194
fn tderef(&self) -> &Head {
@@ -122,11 +241,21 @@ impl<Head, Tail: HasSyncVt> HasSyncVt for VTable<Head, Tail> {}
122241
// DROP
123242
/// The vtable to drop a value in place
124243
#[stabby::stabby]
125-
#[derive(Clone, Copy)]
244+
#[derive(Clone, Copy, Eq)]
126245
pub struct VtDrop {
127246
/// The [`Drop::drop`] function, shimmed with the C calling convention.
128247
pub drop: crate::StableLike<unsafe extern "C" fn(&mut ()), core::num::NonZeroUsize>,
129248
}
249+
impl core::fmt::Debug for VtDrop {
250+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
251+
write!(f, "VtDrop({:p})", unsafe { self.drop.as_ref_unchecked() })
252+
}
253+
}
254+
impl Hash for VtDrop {
255+
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
256+
self.drop.hash(state)
257+
}
258+
}
130259
impl PartialEq for VtDrop {
131260
fn eq(&self, other: &Self) -> bool {
132261
core::ptr::eq(
@@ -136,7 +265,7 @@ impl PartialEq for VtDrop {
136265
}
137266
}
138267
impl<'a, T> IConstConstructor<'a, T> for VtDrop {
139-
const VTABLE: &'a VtDrop = &VtDrop {
268+
const VTABLE: VtDrop = VtDrop {
140269
drop: unsafe {
141270
core::mem::transmute({
142271
unsafe extern "C" fn drop<T>(this: &mut T) {
@@ -150,7 +279,7 @@ impl<'a, T> IConstConstructor<'a, T> for VtDrop {
150279

151280
/// A marker for vtables for types that are `Send`
152281
#[stabby::stabby]
153-
#[derive(Clone, Copy, PartialEq, Eq)]
282+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
154283
pub struct VtSend<T>(pub T);
155284
impl CompoundVt for dyn Send {
156285
type Vt<T> = VtSend<T>;
@@ -166,18 +295,18 @@ impl<Head, Tail> From<crate::vtable::VtSend<VTable<Head, Tail>>> for VTable<Head
166295
}
167296
}
168297
impl<'a, T: Send, Vt: IConstConstructor<'a, T>> IConstConstructor<'a, T> for VtSend<Vt> {
169-
const VTABLE: &'a VtSend<Vt> = &VtSend(*Vt::VTABLE);
298+
const VTABLE: VtSend<Vt> = VtSend(Vt::VTABLE);
170299
}
171300

172301
/// A marker for vtables for types that are `Sync`
173302
#[stabby::stabby]
174-
#[derive(Clone, Copy, PartialEq, Eq)]
303+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
175304
pub struct VtSync<T>(pub T);
176305
impl CompoundVt for dyn Sync {
177306
type Vt<T> = VtSync<T>;
178307
}
179308
impl<'a, T: Sync, Vt: IConstConstructor<'a, T>> IConstConstructor<'a, T> for VtSync<Vt> {
180-
const VTABLE: &'a VtSync<Vt> = &VtSync(*Vt::VTABLE);
309+
const VTABLE: VtSync<Vt> = VtSync(Vt::VTABLE);
181310
}
182311
impl<Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, N> for VtSync<Tail> {
183312
fn tderef(&self) -> &Vt {

stabby-macros/src/traits.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,8 @@ impl<'a> DynTraitDescription<'a> {
654654
)*
655655
}
656656
};
657+
let vtid_str = vtid.to_string();
658+
let all_fn_ids_str = all_fn_ids.iter().map(|id| id.to_string());
657659
vtable_decl = crate::stabby(proc_macro::TokenStream::new(), vtable_decl.into()).into();
658660
quote! {
659661
#[doc = #vt_doc]
@@ -669,6 +671,18 @@ impl<'a> DynTraitDescription<'a> {
669671
#(core::ptr::eq((*unsafe{self.#all_fn_ids.as_ref_unchecked()}) as *const (), (*unsafe{other.#all_fn_ids.as_ref_unchecked()}) as *const _) &&)* true
670672
}
671673
}
674+
impl< #vt_generics > core::hash::Hash for #vtid < #nbvt_generics > where #(#vt_bounds)*{
675+
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
676+
#(self.#all_fn_ids.hash(state);)*
677+
}
678+
}
679+
impl< #vt_generics > core::fmt::Debug for #vtid < #nbvt_generics > where #(#vt_bounds)*{
680+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
681+
let mut s = f.debug_struct(#vtid_str);
682+
#(s.field(#all_fn_ids_str, &core::format_args!("{:p}", unsafe{self.#all_fn_ids.as_ref_unchecked()}));)*
683+
s.finish()
684+
}
685+
}
672686

673687
impl<
674688
'stabby_vt_lt, #(#trait_lts,)*
@@ -683,7 +697,7 @@ impl<'a> DynTraitDescription<'a> {
683697
#(#unbound_trait_types: 'stabby_vt_lt,)*
684698
#(#dyntrait_types: 'stabby_vt_lt,)* {
685699
#[doc = #vt_doc]
686-
const VTABLE: &'stabby_vt_lt #vt_signature = & #vtid {
700+
const VTABLE: #vt_signature = #vtid {
687701
#(#all_fn_ids: unsafe {core::mem::transmute(#self_as_trait::#all_fn_ids as #fn_ptrs)},)*
688702
};
689703
}

0 commit comments

Comments
 (0)