Skip to content

Commit 88c84b2

Browse files
committed
add intrinsic to access vtable size and align
1 parent 332f61e commit 88c84b2

File tree

6 files changed

+66
-2
lines changed

6 files changed

+66
-2
lines changed

Diff for: compiler/rustc_codegen_llvm/src/intrinsic.rs

+14
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,20 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
363363
return;
364364
}
365365

366+
sym::vtable_size | sym::vtable_align => {
367+
let ptr = args[0].immediate();
368+
let layout = self.layout_of(self.tcx.types.usize);
369+
let type_ = self.backend_type(layout);
370+
let offset = match name {
371+
sym::vtable_size => 1,
372+
sym::vtable_align => 2,
373+
_ => bug!(),
374+
};
375+
let offset = self.const_int(type_, offset);
376+
let vtable_field_ptr = self.inbounds_gep(type_, ptr, &[offset]);
377+
self.load(type_, vtable_field_ptr, layout.align.abi)
378+
}
379+
366380
_ if name.as_str().starts_with("simd_") => {
367381
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
368382
Ok(llval) => llval,

Diff for: compiler/rustc_const_eval/src/interpret/intrinsics.rs

+12
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
491491
let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
492492
self.write_scalar(result, dest)?;
493493
}
494+
495+
sym::vtable_size => {
496+
let ptr = self.read_pointer(&args[0])?;
497+
let (size, _align) = self.get_vtable_size_and_align(ptr)?;
498+
self.write_scalar(Scalar::from_machine_usize(size.bytes(), self), dest)?;
499+
}
500+
sym::vtable_align => {
501+
let ptr = self.read_pointer(&args[0])?;
502+
let (_size, align) = self.get_vtable_size_and_align(ptr)?;
503+
self.write_scalar(Scalar::from_machine_usize(align.bytes(), self), dest)?;
504+
}
505+
494506
_ => return Ok(false),
495507
}
496508

Diff for: compiler/rustc_span/src/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1553,6 +1553,8 @@ symbols! {
15531553
volatile_store,
15541554
vreg,
15551555
vreg_low16,
1556+
vtable_align,
1557+
vtable_size,
15561558
warn,
15571559
wasm_abi,
15581560
wasm_import_module,

Diff for: compiler/rustc_typeck/src/check/intrinsic.rs

+4
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
400400

401401
sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)),
402402

403+
sym::vtable_size | sym::vtable_align => {
404+
(0, vec![tcx.mk_imm_ptr(tcx.mk_unit())], tcx.types.usize)
405+
}
406+
403407
other => {
404408
tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
405409
return;

Diff for: library/core/src/intrinsics.rs

+10
Original file line numberDiff line numberDiff line change
@@ -2291,6 +2291,16 @@ extern "rust-intrinsic" {
22912291
/// [`std::hint::black_box`]: crate::hint::black_box
22922292
#[rustc_const_unstable(feature = "const_black_box", issue = "none")]
22932293
pub fn black_box<T>(dummy: T) -> T;
2294+
2295+
/// `ptr` must point to a vtable.
2296+
/// The intrinsic will return the size stored in that vtable.
2297+
#[cfg(not(bootstrap))]
2298+
pub fn vtable_size(ptr: *const ()) -> usize;
2299+
2300+
/// `ptr` must point to a vtable.
2301+
/// The intrinsic will return the alignment stored in that vtable.
2302+
#[cfg(not(bootstrap))]
2303+
pub fn vtable_align(ptr: *const ()) -> usize;
22942304
}
22952305

22962306
// Some functions are defined here because they accidentally got made

Diff for: library/core/src/ptr/metadata.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,20 @@ pub struct DynMetadata<Dyn: ?Sized> {
180180
phantom: crate::marker::PhantomData<Dyn>,
181181
}
182182

183+
/// Opaque type for accessing vtables.
184+
///
185+
/// Private implementation detail of `DynMetadata::size_of` etc.
186+
/// Must be zero-sized since there is conceptually not actually any Abstract Machine memory behind this pointer.
187+
/// However, we can require pointer alignment.
188+
#[repr(C)]
189+
#[cfg(not(bootstrap))]
190+
struct VTable([usize; 0]);
191+
183192
/// The common prefix of all vtables. It is followed by function pointers for trait methods.
184193
///
185194
/// Private implementation detail of `DynMetadata::size_of` etc.
186195
#[repr(C)]
196+
#[cfg(bootstrap)]
187197
struct VTable {
188198
drop_in_place: fn(*mut ()),
189199
size_of: usize,
@@ -194,13 +204,25 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
194204
/// Returns the size of the type associated with this vtable.
195205
#[inline]
196206
pub fn size_of(self) -> usize {
197-
self.vtable_ptr.size_of
207+
#[cfg(bootstrap)]
208+
return self.vtable_ptr.size_of;
209+
#[cfg(not(bootstrap))]
210+
// SAFETY: DynMetadata always contains a valid vtable pointer
211+
return unsafe {
212+
crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ())
213+
};
198214
}
199215

200216
/// Returns the alignment of the type associated with this vtable.
201217
#[inline]
202218
pub fn align_of(self) -> usize {
203-
self.vtable_ptr.align_of
219+
#[cfg(bootstrap)]
220+
return self.vtable_ptr.align_of;
221+
#[cfg(not(bootstrap))]
222+
// SAFETY: DynMetadata always contains a valid vtable pointer
223+
return unsafe {
224+
crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ())
225+
};
204226
}
205227

206228
/// Returns the size and alignment together as a `Layout`

0 commit comments

Comments
 (0)