Skip to content

Commit

Permalink
add intrinsic to access vtable size and align
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Jul 18, 2022
1 parent 332f61e commit 88c84b2
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 2 deletions.
14 changes: 14 additions & 0 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,20 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
return;
}

sym::vtable_size | sym::vtable_align => {
let ptr = args[0].immediate();
let layout = self.layout_of(self.tcx.types.usize);
let type_ = self.backend_type(layout);
let offset = match name {
sym::vtable_size => 1,
sym::vtable_align => 2,
_ => bug!(),
};
let offset = self.const_int(type_, offset);
let vtable_field_ptr = self.inbounds_gep(type_, ptr, &[offset]);
self.load(type_, vtable_field_ptr, layout.align.abi)
}

_ if name.as_str().starts_with("simd_") => {
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
Ok(llval) => llval,
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
self.write_scalar(result, dest)?;
}

sym::vtable_size => {
let ptr = self.read_pointer(&args[0])?;
let (size, _align) = self.get_vtable_size_and_align(ptr)?;
self.write_scalar(Scalar::from_machine_usize(size.bytes(), self), dest)?;
}
sym::vtable_align => {
let ptr = self.read_pointer(&args[0])?;
let (_size, align) = self.get_vtable_size_and_align(ptr)?;
self.write_scalar(Scalar::from_machine_usize(align.bytes(), self), dest)?;
}

_ => return Ok(false),
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,8 @@ symbols! {
volatile_store,
vreg,
vreg_low16,
vtable_align,
vtable_size,
warn,
wasm_abi,
wasm_import_module,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_typeck/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {

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

sym::vtable_size | sym::vtable_align => {
(0, vec![tcx.mk_imm_ptr(tcx.mk_unit())], tcx.types.usize)
}

other => {
tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
return;
Expand Down
10 changes: 10 additions & 0 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2291,6 +2291,16 @@ extern "rust-intrinsic" {
/// [`std::hint::black_box`]: crate::hint::black_box
#[rustc_const_unstable(feature = "const_black_box", issue = "none")]
pub fn black_box<T>(dummy: T) -> T;

/// `ptr` must point to a vtable.
/// The intrinsic will return the size stored in that vtable.
#[cfg(not(bootstrap))]
pub fn vtable_size(ptr: *const ()) -> usize;

/// `ptr` must point to a vtable.
/// The intrinsic will return the alignment stored in that vtable.
#[cfg(not(bootstrap))]
pub fn vtable_align(ptr: *const ()) -> usize;
}

// Some functions are defined here because they accidentally got made
Expand Down
26 changes: 24 additions & 2 deletions library/core/src/ptr/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,20 @@ pub struct DynMetadata<Dyn: ?Sized> {
phantom: crate::marker::PhantomData<Dyn>,
}

/// Opaque type for accessing vtables.
///
/// Private implementation detail of `DynMetadata::size_of` etc.
/// Must be zero-sized since there is conceptually not actually any Abstract Machine memory behind this pointer.
/// However, we can require pointer alignment.
#[repr(C)]
#[cfg(not(bootstrap))]
struct VTable([usize; 0]);

/// The common prefix of all vtables. It is followed by function pointers for trait methods.
///
/// Private implementation detail of `DynMetadata::size_of` etc.
#[repr(C)]
#[cfg(bootstrap)]
struct VTable {
drop_in_place: fn(*mut ()),
size_of: usize,
Expand All @@ -194,13 +204,25 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
/// Returns the size of the type associated with this vtable.
#[inline]
pub fn size_of(self) -> usize {
self.vtable_ptr.size_of
#[cfg(bootstrap)]
return self.vtable_ptr.size_of;
#[cfg(not(bootstrap))]
// SAFETY: DynMetadata always contains a valid vtable pointer
return unsafe {
crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ())
};
}

/// Returns the alignment of the type associated with this vtable.
#[inline]
pub fn align_of(self) -> usize {
self.vtable_ptr.align_of
#[cfg(bootstrap)]
return self.vtable_ptr.align_of;
#[cfg(not(bootstrap))]
// SAFETY: DynMetadata always contains a valid vtable pointer
return unsafe {
crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ())
};
}

/// Returns the size and alignment together as a `Layout`
Expand Down

0 comments on commit 88c84b2

Please sign in to comment.