diff options
| author | Ralf Jung <post@ralfj.de> | 2022-07-18 09:48:20 -0400 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2022-07-20 17:12:07 -0400 |
| commit | 8affef2ccba424f37445f6df6592426600d00a31 (patch) | |
| tree | bf7eaa8bff6f56ebce2e23eea36f5997e78340cb | |
| parent | b5a32d01f4cbc032efa093ff672f1e33087f0efb (diff) | |
| download | rust-8affef2ccba424f37445f6df6592426600d00a31.tar.gz rust-8affef2ccba424f37445f6df6592426600d00a31.zip | |
add intrinsic to access vtable size and align
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/intrinsic.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/intrinsics.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/intrinsic.rs | 4 | ||||
| -rw-r--r-- | library/core/src/intrinsics.rs | 10 | ||||
| -rw-r--r-- | library/core/src/ptr/metadata.rs | 26 |
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` |
