diff --git a/0006-Disable-all-trait-object-unsizing.patch b/0006-Disable-all-trait-object-unsizing.patch deleted file mode 100644 index 96226073ce3f..000000000000 --- a/0006-Disable-all-trait-object-unsizing.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 307aba455c6ee3227d7c522c07761cda19dc716c Mon Sep 17 00:00:00 2001 -From: bjorn3 -Date: Wed, 29 Aug 2018 14:29:05 +0200 -Subject: [PATCH] Disable all trait object unsizing - ---- - src/libcore/alloc.rs | 2 +- - src/libcore/fmt/builders.rs | 13 ++++++++----- - src/libcore/fmt/mod.rs | 3 ++- - src/libcore/panic.rs | 5 +++-- - src/libcore/slice/mod.rs | 2 +- - 5 files changed, 15 insertions(+), 10 deletions(-) - -diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs -index 35e4eea..28b6e2f 100644 ---- a/src/libcore/alloc.rs -+++ b/src/libcore/alloc.rs -@@ -144,7 +144,7 @@ impl Layout { - #[stable(feature = "alloc_layout", since = "1.28.0")] - #[inline] - pub fn for_value(t: &T) -> Self { -- let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); -+ let (size, align) = panic!(); //(mem::size_of_val(t), mem::align_of_val(t)); - // See rationale in `new` for why this us using an unsafe variant below - debug_assert!(Layout::from_size_align(size, align).is_ok()); - unsafe { -diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs -index 3c5f934..1427ab3 100644 ---- a/src/libcore/fmt/builders.rs -+++ b/src/libcore/fmt/builders.rs -@@ -18,6 +18,7 @@ struct PadAdapter<'a> { - impl<'a> PadAdapter<'a> { - fn wrap<'b, 'c: 'a+'b>(fmt: &'c mut fmt::Formatter, slot: &'b mut Option) - -> fmt::Formatter<'b> { -+ /* - fmt.wrap_buf(move |buf| { - *slot = Some(PadAdapter { - buf, -@@ -25,6 +26,8 @@ impl<'a> PadAdapter<'a> { - }); - slot.as_mut().unwrap() - }) -+ */ -+ panic!(); - } - } - -@@ -107,7 +110,7 @@ pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, - impl<'a, 'b: 'a> DebugStruct<'a, 'b> { - /// Adds a new field to the generated struct output. - #[stable(feature = "debug_builders", since = "1.2.0")] -- pub fn field(&mut self, name: &str, value: &dyn fmt::Debug) -> &mut DebugStruct<'a, 'b> { -+ pub fn field(&mut self, name: &str, value: &impl fmt::Debug) -> &mut DebugStruct<'a, 'b> { - self.result = self.result.and_then(|_| { - let prefix = if self.has_fields { - "," -@@ -204,7 +207,7 @@ pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> D - impl<'a, 'b: 'a> DebugTuple<'a, 'b> { - /// Adds a new field to the generated tuple struct output. - #[stable(feature = "debug_builders", since = "1.2.0")] -- pub fn field(&mut self, value: &dyn fmt::Debug) -> &mut DebugTuple<'a, 'b> { -+ pub fn field(&mut self, value: &impl fmt::Debug) -> &mut DebugTuple<'a, 'b> { - self.result = self.result.and_then(|_| { - let (prefix, space) = if self.fields > 0 { - (",", " ") -@@ -258,7 +261,7 @@ struct DebugInner<'a, 'b: 'a> { - } - - impl<'a, 'b: 'a> DebugInner<'a, 'b> { -- fn entry(&mut self, entry: &dyn fmt::Debug) { -+ fn entry(&mut self, entry: &impl fmt::Debug) { - self.result = self.result.and_then(|_| { - if self.is_pretty() { - let mut slot = None; -@@ -340,7 +343,7 @@ pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b - impl<'a, 'b: 'a> DebugSet<'a, 'b> { - /// Adds a new entry to the set output. - #[stable(feature = "debug_builders", since = "1.2.0")] -- pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut DebugSet<'a, 'b> { -+ pub fn entry(&mut self, entry: &impl fmt::Debug) -> &mut DebugSet<'a, 'b> { - self.inner.entry(entry); - self - } -@@ -411,7 +414,7 @@ pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, - impl<'a, 'b: 'a> DebugList<'a, 'b> { - /// Adds a new entry to the list output. - #[stable(feature = "debug_builders", since = "1.2.0")] -- pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut DebugList<'a, 'b> { -+ pub fn entry(&mut self, entry: &impl fmt::Debug) -> &mut DebugList<'a, 'b> { - self.inner.entry(entry); - self - } -diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs -index 928f95e..ad33906 100644 ---- a/src/libcore/fmt/mod.rs -+++ b/src/libcore/fmt/mod.rs -@@ -224,7 +224,8 @@ pub trait Write { - } - } - -- write(&mut Adapter(self), args) -+ //write(&mut Adapter(self), args) -+ panic!() - } - } - -diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs -index 17cac5a..27b7dde 100644 ---- a/src/libcore/panic.rs -+++ b/src/libcore/panic.rs -@@ -58,8 +58,9 @@ impl<'a> PanicInfo<'a> { - pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>, - location: Location<'a>) - -> Self { -- struct NoPayload; -- PanicInfo { payload: &NoPayload, location, message } -+ //struct NoPayload; -+ //PanicInfo { payload: &NoPayload, location, message } -+ panic!(); - } - - #[doc(hidden)] -diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs -index 88fdd76..8537f0e 100644 ---- a/src/libcore/slice/mod.rs -+++ b/src/libcore/slice/mod.rs -@@ -4003,7 +4003,7 @@ impl SlicePartialEq for [A] - return true; - } - unsafe { -- let size = mem::size_of_val(self); -+ let size = panic!(); //mem::size_of_val(self); - memcmp(self.as_ptr() as *const u8, - other.as_ptr() as *const u8, size) == 0 - } --- -2.11.0 diff --git a/Cargo.lock b/Cargo.lock index 9fe1639b7052..8e52485c2fc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -416,6 +416,7 @@ version = "0.1.0" dependencies = [ "ar 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift 0.21.0 (git+https://github.com/CraneStation/cranelift.git)", "cranelift-faerie 0.21.0 (git+https://github.com/CraneStation/cranelift.git)", "cranelift-module 0.21.0 (git+https://github.com/CraneStation/cranelift.git)", diff --git a/Cargo.toml b/Cargo.toml index 5f0893e97b24..5a3da6179bef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ target-lexicon = "0.0.3" faerie = "0.5.0" ar = "0.6.0" bitflags = "1.0.3" +byteorder = "1.2.6" # Uncomment to use local checkout of cranelift #[patch."https://github.com/CraneStation/cranelift.git"] diff --git a/examples/mini_core_hello_world.rs b/examples/mini_core_hello_world.rs index 984c0341efb4..b9614cf00a7a 100644 --- a/examples/mini_core_hello_world.rs +++ b/examples/mini_core_hello_world.rs @@ -31,6 +31,18 @@ impl Termination for () { } } +trait SomeTrait { + fn object_safe(&self); +} + +impl SomeTrait for &'static str { + fn object_safe(&self) { + unsafe { + puts(*self as *const str as *const u8); + } + } +} + #[lang = "start"] fn start( main: fn() -> T, @@ -45,15 +57,28 @@ static NUM_REF: &'static u8 = unsafe { &NUM }; fn main() { unsafe { - let slice: &[u8] = b"Hello\0" as &[u8; 6]; - if intrinsics::size_of_val(slice) as u8 != 6 { - panic(&("eji", "frjio", 0, 0)); - }; - let ptr: *const u8 = slice as *const [u8] as *const u8; - let world = box "World!\0"; + let hello: &[u8] = b"Hello\0" as &[u8; 6]; + let ptr: *const u8 = hello as *const [u8] as *const u8; puts(ptr); - puts(*world as *const str as *const u8); - } - //panic(&("panic msg", "abc.rs", 0, 43)); + let world = box "World!\0"; + puts(*world as *const str as *const u8); + + if intrinsics::size_of_val(hello) as u8 != 6 { + panic(&("", "", 0, 0)); + }; + + let chars = &['C', 'h', 'a', 'r', 's']; + let chars = chars as &[char]; + if intrinsics::size_of_val(chars) as u8 != 4 * 5 { + panic(&("", "", 0, 0)); + } + + let a: &dyn SomeTrait = &"abc\0"; + a.object_safe(); + + if intrinsics::size_of_val(a) as u8 != 16 { + panic(&("", "", 0, 0)); + } + } } diff --git a/src/abi.rs b/src/abi.rs index f77009be9811..3d020087e476 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -50,6 +50,18 @@ fn get_pass_mode<'a, 'tcx: 'a>( } } +fn adjust_arg_for_abi<'a, 'tcx: 'a>( + fx: &mut FunctionCx<'a, 'tcx, impl Backend>, + sig: FnSig<'tcx>, + arg: CValue<'tcx>, +) -> Value { + match get_pass_mode(fx.tcx, sig.abi, arg.layout().ty, false) { + PassMode::NoPass => unimplemented!("pass mode nopass"), + PassMode::ByVal(_) => arg.load_value(fx), + PassMode::ByRef => arg.force_stack(fx), + } +} + pub fn cton_sig_from_fn_ty<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_ty: Ty<'tcx>, @@ -164,12 +176,16 @@ pub fn get_function_name_and_sig<'a, 'tcx>( impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> { /// Instance must be monomorphized - pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef { + pub fn get_function_id(&mut self, inst: Instance<'tcx>) -> FuncId { let (name, sig) = get_function_name_and_sig(self.tcx, inst); - let func_id = self - .module + self.module .declare_function(&name, Linkage::Import, &sig) - .unwrap(); + .unwrap() + } + + /// Instance must be monomorphized + pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef { + let func_id = self.get_function_id(inst); self.module .declare_func_in_func(func_id, &mut self.bcx.func) } @@ -468,29 +484,51 @@ pub fn codegen_call<'a, 'tcx: 'a>( PassMode::ByVal(_) => None, }; + let instance = match fn_ty.sty { + ty::FnDef(def_id, substs) => { + Some(Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap()) + } + _ => None, + }; + + let func_ref: Option; // Indirect call target + + let first_arg = { + if let Some(Instance { + def: InstanceDef::Virtual(_, idx), + .. + }) = instance + { + let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0], idx); + func_ref = Some(method); + Some(ptr) + } else { + func_ref = if instance.is_none() { + let func = trans_operand(fx, func); + Some(func.load_value(fx)) + } else { + None + }; + + args.get(0).map(|arg| adjust_arg_for_abi(fx, sig, *arg)) + }.into_iter() + }; + let call_args: Vec = return_ptr .into_iter() - .chain(args.into_iter().map(|arg| { - match get_pass_mode(fx.tcx, sig.abi, arg.layout().ty, false) { - PassMode::NoPass => unimplemented!("pass mode nopass"), - PassMode::ByVal(_) => arg.load_value(fx), - PassMode::ByRef => arg.force_stack(fx), - } - })).collect::>(); + .chain(first_arg) + .chain( + args.into_iter() + .skip(1) + .map(|arg| adjust_arg_for_abi(fx, sig, arg)), + ).collect::>(); - let call_inst = match fn_ty.sty { - ty::FnDef(def_id, substs) => { - let inst = Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(); - let func_ref = fx.get_function_ref(inst); - fx.bcx.ins().call(func_ref, &call_args) - } - ty::FnPtr(_) => { - let func = trans_operand(fx, func); - let func = func.load_value(fx); - let sig = fx.bcx.import_signature(cton_sig_from_fn_ty(fx.tcx, fn_ty)); - fx.bcx.ins().call_indirect(sig, func, &call_args) - } - _ => bug!("{:?}", fn_ty), + let sig = fx.bcx.import_signature(cton_sig_from_fn_ty(fx.tcx, fn_ty)); + let call_inst = if let Some(func_ref) = func_ref { + fx.bcx.ins().call_indirect(sig, func_ref, &call_args) + } else { + let func_ref = fx.get_function_ref(instance.expect("non-indirect call on non-FnDef type")); + fx.bcx.ins().call(func_ref, &call_args) }; match output_pass_mode { @@ -610,6 +648,7 @@ fn codegen_intrinsic_call<'a, 'tcx: 'a>( let elem_size = fx.layout_of(elem).size.bytes(); fx.bcx.ins().imul_imm(len, elem_size as i64) } + ty::Dynamic(..) => crate::vtable::size_of_obj(fx, args[0]), ty => unimplemented!("size_of_val for {:?}", ty), }; ret.write_cvalue(fx, CValue::ByVal(size, usize_layout)); diff --git a/src/base.rs b/src/base.rs index 9e0178541678..caa4eae75f86 100644 --- a/src/base.rs +++ b/src/base.rs @@ -12,7 +12,7 @@ impl String> Drop for PrintOnPanic { pub fn trans_mono_item<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, module: &mut Module, - caches: &mut Caches, + caches: &mut Caches<'tcx>, ccx: &mut crate::constant::ConstantCx, mono_item: MonoItem<'tcx>, ) { @@ -59,7 +59,7 @@ fn trans_fn<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, module: &mut Module, constants: &mut crate::constant::ConstantCx, - caches: &mut Caches, + caches: &mut Caches<'tcx>, instance: Instance<'tcx>, ) { // Step 1. Get mir diff --git a/src/common.rs b/src/common.rs index a7159c210ea8..55cf333bbdc8 100644 --- a/src/common.rs +++ b/src/common.rs @@ -236,9 +236,13 @@ impl<'tcx> CValue<'tcx> { } _ => bug!("unsize non array {:?} to slice", ty), }, - ty::Dynamic(_, _) => match ty.sty { + ty::Dynamic(data, _) => match ty.sty { ty::Dynamic(_, _) => self.load_value_pair(fx), - _ => unimpl!("unsize of type ... to {:?}", dest.layout().ty), + _ => { + let ptr = self.load_value(fx); + let vtable = crate::vtable::get_vtable(fx, ty, data.principal()); + (ptr, vtable) + } }, _ => bug!( "unsize of type {:?} to {:?}", @@ -556,7 +560,7 @@ pub struct FunctionCx<'a, 'tcx: 'a, B: Backend + 'a> { pub local_map: HashMap>, pub comments: HashMap, pub constants: &'a mut crate::constant::ConstantCx, - pub caches: &'a mut Caches, + pub caches: &'a mut Caches<'tcx>, /// add_global_comment inserts a comment here pub top_nop: Option, diff --git a/src/lib.rs b/src/lib.rs index c1aea7739b86..7e8f5ac0e47e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![feature(rustc_private, macro_at_most_once_rep)] #![allow(intra_doc_link_resolution_failure)] +extern crate byteorder; extern crate syntax; #[macro_use] extern crate rustc; @@ -53,6 +54,7 @@ mod common; mod constant; mod metadata; mod pretty_clif; +mod vtable; mod prelude { pub use std::any::Any; @@ -100,14 +102,16 @@ mod prelude { use crate::constant::ConstantCx; use crate::prelude::*; -pub struct Caches { +pub struct Caches<'tcx> { pub context: Context, + pub vtables: HashMap<(Ty<'tcx>, Option>), DataId>, } -impl Caches { +impl<'tcx> Caches<'tcx> { fn new() -> Self { Caches { context: Context::new(), + vtables: HashMap::new(), } } } diff --git a/src/vtable.rs b/src/vtable.rs new file mode 100644 index 000000000000..4d2382979c97 --- /dev/null +++ b/src/vtable.rs @@ -0,0 +1,129 @@ +//! See librustc_codegen_llvm/meth.rs for reference + +use crate::prelude::*; + +const DROP_FN_INDEX: usize = 0; +const SIZE_INDEX: usize = 1; +const ALIGN_INDEX: usize = 2; + +pub fn size_of_obj<'a, 'tcx: 'a>( + fx: &mut FunctionCx<'a, 'tcx, impl Backend>, + val: CValue<'tcx>, +) -> Value { + let (_ptr, vtable) = val.load_value_pair(fx); + let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; + fx.bcx.ins().load( + pointer_ty(fx.tcx), + MemFlags::new(), + vtable, + (SIZE_INDEX * usize_size) as i32, + ) +} + +pub fn get_ptr_and_method_ref<'a, 'tcx: 'a>( + fx: &mut FunctionCx<'a, 'tcx, impl Backend>, + arg: CValue<'tcx>, + idx: usize, +) -> (Value, Value) { + let (ptr, vtable) = arg.load_value_pair(fx); + let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes(); + let func_ref = fx.bcx.ins().load( + pointer_ty(fx.tcx), + MemFlags::new(), + vtable, + ((idx + 3) * usize_size as usize) as i32, + ); + (ptr, func_ref) +} + +pub fn get_vtable<'a, 'tcx: 'a>( + fx: &mut FunctionCx<'a, 'tcx, impl Backend>, + ty: Ty<'tcx>, + trait_ref: Option>, +) -> Value { + let data_id = if let Some(data_id) = fx.caches.vtables.get(&(ty, trait_ref)) { + *data_id + } else { + let data_id = build_vtable(fx, ty, trait_ref); + fx.caches.vtables.insert((ty, trait_ref), data_id); + data_id + }; + + let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + fx.bcx + .ins() + .global_value(fx.module.pointer_type(), local_data_id) +} + +fn build_vtable<'a, 'tcx: 'a>( + fx: &mut FunctionCx<'a, 'tcx, impl Backend>, + ty: Ty<'tcx>, + trait_ref: Option>, +) -> DataId { + let tcx = fx.tcx; + let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; + + let (size, align) = tcx + .layout_of(ParamEnv::reveal_all().and(ty)) + .unwrap() + .size_and_align(); + let drop_in_place_fn = + fx.get_function_id(::rustc_mir::monomorphize::resolve_drop_in_place(tcx, ty)); + + let mut components: Vec<_> = vec![Some(drop_in_place_fn), None, None]; + + if let Some(trait_ref) = trait_ref { + let trait_ref = trait_ref.with_self_ty(tcx, ty); + let methods = tcx.vtable_methods(trait_ref); + let methods = methods.iter().cloned().map(|opt_mth| { + opt_mth.map_or(None, |(def_id, substs)| { + Some(fx.get_function_id( + Instance::resolve(tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(), + )) + }) + }); + components.extend(methods); + } + + let mut data_ctx = DataContext::new(); + let mut data = ::std::iter::repeat(0u8) + .take(components.len() * usize_size) + .collect::>() + .into_boxed_slice(); + write_usize(fx.tcx, &mut data, SIZE_INDEX, size.bytes()); + write_usize(fx.tcx, &mut data, ALIGN_INDEX, align.abi()); + data_ctx.define(data); + + for (i, component) in components.into_iter().enumerate() { + if let Some(func_id) = component { + let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx); + data_ctx.write_function_addr((i * usize_size) as u32, func_ref); + } + } + + let data_id = fx + .module + .declare_data( + &format!("vtable.{:?}.for.{:?}", trait_ref, ty), + Linkage::Local, + false, + ).unwrap(); + fx.module.define_data(data_id, &data_ctx).unwrap(); + data_id +} + +fn write_usize(tcx: TyCtxt, buf: &mut [u8], idx: usize, num: u64) { + use byteorder::{BigEndian, LittleEndian, WriteBytesExt}; + + let usize_size = tcx + .layout_of(ParamEnv::reveal_all().and(tcx.types.usize)) + .unwrap() + .size + .bytes() as usize; + let mut target = &mut buf[idx * usize_size..(idx + 1) * usize_size]; + + match tcx.data_layout.endian { + layout::Endian::Little => target.write_uint::(num, usize_size), + layout::Endian::Big => target.write_uint::(num, usize_size), + }.unwrap() +}