Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d3ff497

Browse files
committedJun 28, 2021
Update other codegens to use tcx managed vtable allocations.
1 parent 654e334 commit d3ff497

File tree

12 files changed

+143
-249
lines changed

12 files changed

+143
-249
lines changed
 

‎compiler/rustc_codegen_cranelift/src/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
233233
pub(crate) module: &'m mut dyn Module,
234234
pub(crate) tcx: TyCtxt<'tcx>,
235235
pub(crate) pointer_type: Type, // Cached from module
236-
pub(crate) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
236+
pub(crate) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Pointer>,
237237
pub(crate) constants_cx: ConstantCx,
238238

239239
pub(crate) instance: Instance<'tcx>,

‎compiler/rustc_codegen_cranelift/src/constant.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ pub(crate) fn codegen_const_value<'tcx>(
249249
}
250250
}
251251

252-
fn pointer_for_allocation<'tcx>(
252+
pub(crate) fn pointer_for_allocation<'tcx>(
253253
fx: &mut FunctionCx<'_, '_, 'tcx>,
254254
alloc: &'tcx Allocation,
255255
) -> crate::pointer::Pointer {

‎compiler/rustc_codegen_cranelift/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ mod prelude {
9898
pub(crate) use cranelift_codegen::isa::{self, CallConv};
9999
pub(crate) use cranelift_codegen::Context;
100100
pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
101-
pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module};
101+
pub(crate) use cranelift_module::{self, DataContext, FuncId, Linkage, Module};
102102

103103
pub(crate) use crate::abi::*;
104104
pub(crate) use crate::base::{codegen_operand, codegen_place};

‎compiler/rustc_codegen_cranelift/src/unsize.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,7 @@ pub(crate) fn unsized_info<'tcx>(
3131
// change to the vtable.
3232
old_info.expect("unsized_info: missing old info for trait upcast")
3333
}
34-
(_, &ty::Dynamic(ref data, ..)) => {
35-
crate::vtable::get_vtable(fx, fx.layout_of(source), data.principal())
36-
}
34+
(_, &ty::Dynamic(ref data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()),
3735
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
3836
}
3937
}

‎compiler/rustc_codegen_cranelift/src/vtable.rs

Lines changed: 10 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// FIXME dedup this logic between miri, cg_llvm and cg_clif
55

66
use crate::prelude::*;
7-
use ty::VtblEntry;
7+
use super::constant::pointer_for_allocation;
88

99
fn vtable_memflags() -> MemFlags {
1010
let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
@@ -66,105 +66,19 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
6666

6767
pub(crate) fn get_vtable<'tcx>(
6868
fx: &mut FunctionCx<'_, '_, 'tcx>,
69-
layout: TyAndLayout<'tcx>,
69+
ty: Ty<'tcx>,
7070
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
7171
) -> Value {
72-
let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) {
73-
*data_id
72+
let vtable_ptr = if let Some(vtable_ptr) = fx.vtables.get(&(ty, trait_ref)) {
73+
*vtable_ptr
7474
} else {
75-
let data_id = build_vtable(fx, layout, trait_ref);
76-
fx.vtables.insert((layout.ty, trait_ref), data_id);
77-
data_id
78-
};
79-
80-
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
81-
fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
82-
}
83-
84-
fn build_vtable<'tcx>(
85-
fx: &mut FunctionCx<'_, '_, 'tcx>,
86-
layout: TyAndLayout<'tcx>,
87-
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
88-
) -> DataId {
89-
let tcx = fx.tcx;
90-
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
75+
let vtable_alloc_id = fx.tcx.vtable_allocation(ty, trait_ref);
76+
let vtable_allocation = fx.tcx.global_alloc(vtable_alloc_id).unwrap_memory();
77+
let vtable_ptr = pointer_for_allocation(fx, vtable_allocation);
9178

92-
let drop_in_place_fn = import_function(
93-
tcx,
94-
fx.module,
95-
Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx),
96-
);
97-
98-
let vtable_entries = if let Some(trait_ref) = trait_ref {
99-
tcx.vtable_entries(trait_ref.with_self_ty(tcx, layout.ty))
100-
} else {
101-
ty::COMMON_VTABLE_ENTRIES
79+
fx.vtables.insert((ty, trait_ref), vtable_ptr);
80+
vtable_ptr
10281
};
10382

104-
let mut data_ctx = DataContext::new();
105-
let mut data = ::std::iter::repeat(0u8)
106-
.take(vtable_entries.len() * usize_size)
107-
.collect::<Vec<u8>>()
108-
.into_boxed_slice();
109-
110-
for (idx, entry) in vtable_entries.iter().enumerate() {
111-
match entry {
112-
VtblEntry::MetadataSize => {
113-
write_usize(fx.tcx, &mut data, idx, layout.size.bytes());
114-
}
115-
VtblEntry::MetadataAlign => {
116-
write_usize(fx.tcx, &mut data, idx, layout.align.abi.bytes());
117-
}
118-
VtblEntry::MetadataDropInPlace | VtblEntry::Vacant | VtblEntry::Method(_, _) => {}
119-
}
120-
}
121-
data_ctx.define(data);
122-
123-
for (idx, entry) in vtable_entries.iter().enumerate() {
124-
match entry {
125-
VtblEntry::MetadataDropInPlace => {
126-
let func_ref = fx.module.declare_func_in_data(drop_in_place_fn, &mut data_ctx);
127-
data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
128-
}
129-
VtblEntry::Method(def_id, substs) => {
130-
let func_id = import_function(
131-
tcx,
132-
fx.module,
133-
Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), *def_id, substs)
134-
.unwrap()
135-
.polymorphize(fx.tcx),
136-
);
137-
let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
138-
data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
139-
}
140-
VtblEntry::MetadataSize | VtblEntry::MetadataAlign | VtblEntry::Vacant => {}
141-
}
142-
}
143-
144-
data_ctx.set_align(fx.tcx.data_layout.pointer_align.pref.bytes());
145-
146-
let data_id = fx.module.declare_anonymous_data(false, false).unwrap();
147-
148-
fx.module.define_data(data_id, &data_ctx).unwrap();
149-
150-
data_id
151-
}
152-
153-
fn write_usize(tcx: TyCtxt<'_>, buf: &mut [u8], idx: usize, num: u64) {
154-
let pointer_size =
155-
tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.usize)).unwrap().size.bytes() as usize;
156-
let target = &mut buf[idx * pointer_size..(idx + 1) * pointer_size];
157-
158-
match tcx.data_layout.endian {
159-
rustc_target::abi::Endian::Little => match pointer_size {
160-
4 => target.copy_from_slice(&(num as u32).to_le_bytes()),
161-
8 => target.copy_from_slice(&(num as u64).to_le_bytes()),
162-
_ => todo!("pointer size {} is not yet supported", pointer_size),
163-
},
164-
rustc_target::abi::Endian::Big => match pointer_size {
165-
4 => target.copy_from_slice(&(num as u32).to_be_bytes()),
166-
8 => target.copy_from_slice(&(num as u64).to_be_bytes()),
167-
_ => todo!("pointer size {} is not yet supported", pointer_size),
168-
},
169-
}
83+
vtable_ptr.get_addr(fx)
17084
}

‎compiler/rustc_codegen_llvm/src/common.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,10 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
282282
}
283283
}
284284

285+
fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value {
286+
const_alloc_to_llvm(self, alloc)
287+
}
288+
285289
fn from_const_alloc(
286290
&self,
287291
layout: TyAndLayout<'tcx>,

‎compiler/rustc_codegen_ssa/src/meth.rs

Lines changed: 4 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::traits::*;
22

3-
use rustc_middle::ty::{self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES};
3+
use rustc_middle::ty::{self, Ty};
44
use rustc_target::abi::call::FnAbi;
55

66
#[derive(Copy, Clone, Debug)]
@@ -70,48 +70,13 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
7070
return val;
7171
}
7272

73-
// Not in the cache; build it.
74-
let nullptr = cx.const_null(cx.type_i8p_ext(cx.data_layout().instruction_address_space));
75-
76-
let vtable_entries = if let Some(trait_ref) = trait_ref {
77-
tcx.vtable_entries(trait_ref.with_self_ty(tcx, ty))
78-
} else {
79-
COMMON_VTABLE_ENTRIES
80-
};
81-
82-
let layout = cx.layout_of(ty);
83-
// /////////////////////////////////////////////////////////////////////////////////////////////
84-
// If you touch this code, be sure to also make the corresponding changes to
85-
// `get_vtable` in `rust_mir/interpret/traits.rs`.
86-
// /////////////////////////////////////////////////////////////////////////////////////////////
87-
let components: Vec<_> = vtable_entries
88-
.iter()
89-
.map(|entry| match entry {
90-
VtblEntry::MetadataDropInPlace => {
91-
cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty))
92-
}
93-
VtblEntry::MetadataSize => cx.const_usize(layout.size.bytes()),
94-
VtblEntry::MetadataAlign => cx.const_usize(layout.align.abi.bytes()),
95-
VtblEntry::Vacant => nullptr,
96-
VtblEntry::Method(def_id, substs) => cx.get_fn_addr(
97-
ty::Instance::resolve_for_vtable(
98-
cx.tcx(),
99-
ty::ParamEnv::reveal_all(),
100-
*def_id,
101-
substs,
102-
)
103-
.unwrap()
104-
.polymorphize(cx.tcx()),
105-
),
106-
})
107-
.collect();
108-
109-
let vtable_const = cx.const_struct(&components, false);
73+
let vtable_alloc_id = tcx.vtable_allocation(ty, trait_ref);
74+
let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory();
75+
let vtable_const = cx.const_data_from_alloc(vtable_allocation);
11076
let align = cx.data_layout().pointer_align.abi;
11177
let vtable = cx.static_addr_of(vtable_const, align, Some("vtable"));
11278

11379
cx.create_vtable_metadata(ty, vtable);
114-
11580
cx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
11681
vtable
11782
}

‎compiler/rustc_codegen_ssa/src/traits/consts.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ pub trait ConstMethods<'tcx>: BackendTypes {
2626
fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
2727
fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
2828

29+
fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value;
30+
2931
fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: Self::Type) -> Self::Value;
3032
fn from_const_alloc(
3133
&self,

‎compiler/rustc_middle/src/ty/context.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::middle;
1111
use crate::middle::cstore::{CrateStoreDyn, EncodedMetadata};
1212
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetimeDefault};
1313
use crate::middle::stability;
14-
use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
14+
use crate::mir::interpret::{self, AllocId, Allocation, ConstValue, Scalar};
1515
use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
1616
use crate::thir::Thir;
1717
use crate::traits;
@@ -1045,6 +1045,9 @@ pub struct GlobalCtxt<'tcx> {
10451045
output_filenames: Arc<OutputFilenames>,
10461046

10471047
pub main_def: Option<MainDefinition>,
1048+
1049+
pub(super) vtables_cache:
1050+
Lock<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), AllocId>>,
10481051
}
10491052

10501053
impl<'tcx> TyCtxt<'tcx> {
@@ -1202,6 +1205,7 @@ impl<'tcx> TyCtxt<'tcx> {
12021205
alloc_map: Lock::new(interpret::AllocMap::new()),
12031206
output_filenames: Arc::new(output_filenames),
12041207
main_def: resolutions.main_def,
1208+
vtables_cache: Default::default(),
12051209
}
12061210
}
12071211

‎compiler/rustc_middle/src/ty/mod.rs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub use adt::*;
1818
pub use assoc::*;
1919
pub use closure::*;
2020
pub use generics::*;
21+
pub use vtable::*;
2122

2223
use crate::hir::exports::ExportMap;
2324
use crate::ich::StableHashingContext;
@@ -94,6 +95,7 @@ pub mod relate;
9495
pub mod subst;
9596
pub mod trait_def;
9697
pub mod util;
98+
pub mod vtable;
9799
pub mod walk;
98100

99101
mod adt;
@@ -2009,19 +2011,3 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> {
20092011
fmt::Display::fmt(&self.name, fmt)
20102012
}
20112013
}
2012-
2013-
#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
2014-
pub enum VtblEntry<'tcx> {
2015-
MetadataDropInPlace,
2016-
MetadataSize,
2017-
MetadataAlign,
2018-
Vacant,
2019-
Method(DefId, SubstsRef<'tcx>),
2020-
}
2021-
2022-
pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
2023-
&[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign];
2024-
2025-
pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0;
2026-
pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1;
2027-
pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2;
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use std::convert::TryFrom;
2+
3+
use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar};
4+
use crate::ty::fold::TypeFoldable;
5+
use crate::ty::{self, DefId, SubstsRef, Ty, TyCtxt};
6+
use rustc_ast::Mutability;
7+
8+
#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
9+
pub enum VtblEntry<'tcx> {
10+
MetadataDropInPlace,
11+
MetadataSize,
12+
MetadataAlign,
13+
Vacant,
14+
Method(DefId, SubstsRef<'tcx>),
15+
}
16+
17+
pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
18+
&[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign];
19+
20+
pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0;
21+
pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1;
22+
pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2;
23+
24+
impl<'tcx> TyCtxt<'tcx> {
25+
/// Retrieves an allocation that represents the contents of a vtable.
26+
/// There's a cache within `TyCtxt` so it will be deduplicated.
27+
pub fn vtable_allocation(
28+
self,
29+
ty: Ty<'tcx>,
30+
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
31+
) -> AllocId {
32+
let tcx = self;
33+
let vtables_cache = tcx.vtables_cache.lock();
34+
if let Some(alloc_id) = vtables_cache.get(&(ty, poly_trait_ref)).cloned() {
35+
return alloc_id;
36+
}
37+
drop(vtables_cache);
38+
39+
// See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674
40+
assert!(
41+
!ty.needs_subst() && !poly_trait_ref.map_or(false, |trait_ref| trait_ref.needs_subst())
42+
);
43+
let param_env = ty::ParamEnv::reveal_all();
44+
let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
45+
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
46+
let trait_ref = tcx.erase_regions(trait_ref);
47+
48+
tcx.vtable_entries(trait_ref)
49+
} else {
50+
COMMON_VTABLE_ENTRIES
51+
};
52+
53+
let layout =
54+
tcx.layout_of(param_env.and(ty)).expect("failed to build vtable representation");
55+
assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
56+
let size = layout.size.bytes();
57+
let align = layout.align.abi.bytes();
58+
59+
let ptr_size = tcx.data_layout.pointer_size;
60+
let ptr_align = tcx.data_layout.pointer_align.abi;
61+
62+
let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
63+
let mut vtable = Allocation::uninit(vtable_size, ptr_align);
64+
65+
// No need to do any alignment checks on the memory accesses below, because we know the
66+
// allocation is correctly aligned as we created it above. Also we're only offsetting by
67+
// multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
68+
69+
for (idx, entry) in vtable_entries.iter().enumerate() {
70+
let idx: u64 = u64::try_from(idx).unwrap();
71+
let scalar = match entry {
72+
VtblEntry::MetadataDropInPlace => {
73+
let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
74+
let fn_alloc_id = tcx.create_fn_alloc(instance);
75+
let fn_ptr = Pointer::from(fn_alloc_id);
76+
fn_ptr.into()
77+
}
78+
VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(),
79+
VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(),
80+
VtblEntry::Vacant => continue,
81+
VtblEntry::Method(def_id, substs) => {
82+
// See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674
83+
assert!(!substs.needs_subst());
84+
85+
// Prepare the fn ptr we write into the vtable.
86+
let instance =
87+
ty::Instance::resolve_for_vtable(tcx, param_env, *def_id, substs)
88+
.expect("resolution failed during building vtable representation")
89+
.polymorphize(tcx);
90+
let fn_alloc_id = tcx.create_fn_alloc(instance);
91+
let fn_ptr = Pointer::from(fn_alloc_id);
92+
fn_ptr.into()
93+
}
94+
};
95+
vtable
96+
.write_scalar(&tcx, alloc_range(ptr_size * idx, ptr_size), scalar)
97+
.expect("failed to build vtable representation");
98+
}
99+
100+
vtable.mutability = Mutability::Not;
101+
let alloc_id = tcx.create_memory_alloc(tcx.intern_const_alloc(vtable));
102+
let mut vtables_cache = self.vtables_cache.lock();
103+
vtables_cache.insert((ty, poly_trait_ref), alloc_id);
104+
alloc_id
105+
}
106+
}

‎compiler/rustc_mir/src/interpret/traits.rs

Lines changed: 6 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,14 @@
11
use std::convert::TryFrom;
22

3-
use rustc_middle::mir::interpret::{
4-
AllocError, InterpError, InterpResult, Pointer, PointerArithmetic, Scalar,
5-
UndefinedBehaviorInfo, UnsupportedOpInfo,
6-
};
3+
use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar};
74
use rustc_middle::ty::{
8-
self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN,
5+
self, Ty, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN,
96
COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE,
107
};
11-
use rustc_target::abi::{Align, LayoutOf, Size};
8+
use rustc_target::abi::{Align, Size};
129

13-
use super::alloc_range;
1410
use super::util::ensure_monomorphic_enough;
15-
use super::{Allocation, FnVal, InterpCx, Machine};
16-
17-
fn vtable_alloc_error_to_interp_error<'tcx>(error: AllocError) -> InterpError<'tcx> {
18-
match error {
19-
AllocError::ReadPointerAsBytes => {
20-
InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes)
21-
}
22-
AllocError::InvalidUninitBytes(_info) => {
23-
InterpError::UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(None))
24-
}
25-
}
26-
}
11+
use super::{FnVal, InterpCx, Machine};
2712

2813
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
2914
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for
@@ -45,79 +30,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
4530
ensure_monomorphic_enough(*self.tcx, ty)?;
4631
ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
4732

48-
if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) {
49-
// This means we guarantee that there are no duplicate vtables, we will
50-
// always use the same vtable for the same (Type, Trait) combination.
51-
// That's not what happens in rustc, but emulating per-crate deduplication
52-
// does not sound like it actually makes anything any better.
53-
return Ok(vtable);
54-
}
55-
56-
let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
57-
let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
58-
let trait_ref = self.tcx.erase_regions(trait_ref);
59-
60-
self.tcx.vtable_entries(trait_ref)
61-
} else {
62-
COMMON_VTABLE_ENTRIES
63-
};
64-
65-
let layout = self.layout_of(ty)?;
66-
assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
67-
let size = layout.size.bytes();
68-
let align = layout.align.abi.bytes();
69-
70-
let tcx = *self.tcx;
71-
let ptr_size = self.pointer_size();
72-
let ptr_align = tcx.data_layout.pointer_align.abi;
73-
// /////////////////////////////////////////////////////////////////////////////////////////
74-
// If you touch this code, be sure to also make the corresponding changes to
75-
// `get_vtable` in `rust_codegen_llvm/meth.rs`.
76-
// /////////////////////////////////////////////////////////////////////////////////////////
77-
let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
78-
let mut vtable = Allocation::uninit(vtable_size, ptr_align);
79-
80-
// No need to do any alignment checks on the memory accesses below, because we know the
81-
// allocation is correctly aligned as we created it above. Also we're only offsetting by
82-
// multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
83-
let scalars = vtable_entries
84-
.iter()
85-
.map(|entry| -> InterpResult<'tcx, _> {
86-
match entry {
87-
VtblEntry::MetadataDropInPlace => {
88-
let instance = Instance::resolve_drop_in_place(tcx, ty);
89-
let fn_alloc_id = tcx.create_fn_alloc(instance);
90-
let fn_ptr = Pointer::from(fn_alloc_id);
91-
Ok(Some(fn_ptr.into()))
92-
}
93-
VtblEntry::MetadataSize => Ok(Some(Scalar::from_uint(size, ptr_size).into())),
94-
VtblEntry::MetadataAlign => Ok(Some(Scalar::from_uint(align, ptr_size).into())),
95-
VtblEntry::Vacant => Ok(None),
96-
VtblEntry::Method(def_id, substs) => {
97-
// Prepare the fn ptr we write into the vtable.
98-
let instance =
99-
Instance::resolve_for_vtable(tcx, self.param_env, *def_id, substs)
100-
.ok_or_else(|| err_inval!(TooGeneric))?;
101-
let fn_alloc_id = tcx.create_fn_alloc(instance);
102-
let fn_ptr = Pointer::from(fn_alloc_id);
103-
Ok(Some(fn_ptr.into()))
104-
}
105-
}
106-
})
107-
.collect::<Result<Vec<_>, _>>()?;
108-
for (idx, scalar) in scalars.into_iter().enumerate() {
109-
if let Some(scalar) = scalar {
110-
let idx: u64 = u64::try_from(idx).unwrap();
111-
vtable
112-
.write_scalar(self, alloc_range(ptr_size * idx, ptr_size), scalar)
113-
.map_err(vtable_alloc_error_to_interp_error)?;
114-
}
115-
}
116-
117-
let vtable_id = tcx.create_memory_alloc(tcx.intern_const_alloc(vtable));
118-
let vtable_ptr = self.memory.global_base_pointer(Pointer::from(vtable_id))?;
33+
let vtable_allocation = self.tcx.vtable_allocation(ty, poly_trait_ref);
11934

120-
assert!(self.vtables.insert((ty, poly_trait_ref), vtable_ptr).is_none());
35+
let vtable_ptr = self.memory.global_base_pointer(Pointer::from(vtable_allocation))?;
12136

12237
Ok(vtable_ptr)
12338
}

0 commit comments

Comments
 (0)
Please sign in to comment.