about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2022-07-18 09:48:20 -0400
committerRalf Jung <post@ralfj.de>2022-07-20 17:12:07 -0400
commit8affef2ccba424f37445f6df6592426600d00a31 (patch)
treebf7eaa8bff6f56ebce2e23eea36f5997e78340cb
parentb5a32d01f4cbc032efa093ff672f1e33087f0efb (diff)
downloadrust-8affef2ccba424f37445f6df6592426600d00a31.tar.gz
rust-8affef2ccba424f37445f6df6592426600d00a31.zip
add intrinsic to access vtable size and align
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs12
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs4
-rw-r--r--library/core/src/intrinsics.rs10
-rw-r--r--library/core/src/ptr/metadata.rs26
6 files changed, 66 insertions, 2 deletions
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 9f364749287..01e276ac902 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -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,
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 0f6eb2ecaa3..025f8647c95 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -492,6 +492,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),
         }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ec1d2c39b80..a207927c9d2 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1564,6 +1564,8 @@ symbols! {
         volatile_store,
         vreg,
         vreg_low16,
+        vtable_align,
+        vtable_size,
         warn,
         wasm_abi,
         wasm_import_module,
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 7fe710cf8f4..3f2a0da8d65 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -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;
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 998f7be3f73..dc82b32214c 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -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
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index 287ae69acd1..fc0fd221b40 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -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,
@@ -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`