Implement trait objects (cc #14)
This commit is contained in:
parent
62a0203a5a
commit
6196146ac4
9 changed files with 243 additions and 177 deletions
|
@ -1,137 +0,0 @@
|
||||||
From 307aba455c6ee3227d7c522c07761cda19dc716c Mon Sep 17 00:00:00 2001
|
|
||||||
From: bjorn3 <bjorn3@users.noreply.github.com>
|
|
||||||
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: ?Sized>(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<Self>)
|
|
||||||
-> 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<A> SlicePartialEq<A> 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
|
|
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -416,6 +416,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ar 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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 0.21.0 (git+https://github.com/CraneStation/cranelift.git)",
|
||||||
"cranelift-faerie 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)",
|
"cranelift-module 0.21.0 (git+https://github.com/CraneStation/cranelift.git)",
|
||||||
|
|
|
@ -24,6 +24,7 @@ target-lexicon = "0.0.3"
|
||||||
faerie = "0.5.0"
|
faerie = "0.5.0"
|
||||||
ar = "0.6.0"
|
ar = "0.6.0"
|
||||||
bitflags = "1.0.3"
|
bitflags = "1.0.3"
|
||||||
|
byteorder = "1.2.6"
|
||||||
|
|
||||||
# Uncomment to use local checkout of cranelift
|
# Uncomment to use local checkout of cranelift
|
||||||
#[patch."https://github.com/CraneStation/cranelift.git"]
|
#[patch."https://github.com/CraneStation/cranelift.git"]
|
||||||
|
|
|
@ -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"]
|
#[lang = "start"]
|
||||||
fn start<T: Termination + 'static>(
|
fn start<T: Termination + 'static>(
|
||||||
main: fn() -> T,
|
main: fn() -> T,
|
||||||
|
@ -45,15 +57,28 @@ static NUM_REF: &'static u8 = unsafe { &NUM };
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let slice: &[u8] = b"Hello\0" as &[u8; 6];
|
let hello: &[u8] = b"Hello\0" as &[u8; 6];
|
||||||
if intrinsics::size_of_val(slice) as u8 != 6 {
|
let ptr: *const u8 = hello as *const [u8] as *const u8;
|
||||||
panic(&("eji", "frjio", 0, 0));
|
|
||||||
};
|
|
||||||
let ptr: *const u8 = slice as *const [u8] as *const u8;
|
|
||||||
let world = box "World!\0";
|
|
||||||
puts(ptr);
|
puts(ptr);
|
||||||
|
|
||||||
|
let world = box "World!\0";
|
||||||
puts(*world as *const str as *const u8);
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
//panic(&("panic msg", "abc.rs", 0, 43));
|
let a: &dyn SomeTrait = &"abc\0";
|
||||||
|
a.object_safe();
|
||||||
|
|
||||||
|
if intrinsics::size_of_val(a) as u8 != 16 {
|
||||||
|
panic(&("", "", 0, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
85
src/abi.rs
85
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>(
|
pub fn cton_sig_from_fn_ty<'a, 'tcx: 'a>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
fn_ty: Ty<'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> {
|
impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
|
||||||
/// Instance must be monomorphized
|
/// 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 (name, sig) = get_function_name_and_sig(self.tcx, inst);
|
||||||
let func_id = self
|
self.module
|
||||||
.module
|
|
||||||
.declare_function(&name, Linkage::Import, &sig)
|
.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
|
self.module
|
||||||
.declare_func_in_func(func_id, &mut self.bcx.func)
|
.declare_func_in_func(func_id, &mut self.bcx.func)
|
||||||
}
|
}
|
||||||
|
@ -468,29 +484,51 @@ pub fn codegen_call<'a, 'tcx: 'a>(
|
||||||
PassMode::ByVal(_) => None,
|
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<Value>; // 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<Value> = return_ptr
|
let call_args: Vec<Value> = return_ptr
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(args.into_iter().map(|arg| {
|
.chain(first_arg)
|
||||||
match get_pass_mode(fx.tcx, sig.abi, arg.layout().ty, false) {
|
.chain(
|
||||||
PassMode::NoPass => unimplemented!("pass mode nopass"),
|
args.into_iter()
|
||||||
PassMode::ByVal(_) => arg.load_value(fx),
|
.skip(1)
|
||||||
PassMode::ByRef => arg.force_stack(fx),
|
.map(|arg| adjust_arg_for_abi(fx, sig, arg)),
|
||||||
}
|
).collect::<Vec<_>>();
|
||||||
})).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
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));
|
let sig = fx.bcx.import_signature(cton_sig_from_fn_ty(fx.tcx, fn_ty));
|
||||||
fx.bcx.ins().call_indirect(sig, func, &call_args)
|
let call_inst = if let Some(func_ref) = func_ref {
|
||||||
}
|
fx.bcx.ins().call_indirect(sig, func_ref, &call_args)
|
||||||
_ => bug!("{:?}", fn_ty),
|
} 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 {
|
match output_pass_mode {
|
||||||
|
@ -610,6 +648,7 @@ fn codegen_intrinsic_call<'a, 'tcx: 'a>(
|
||||||
let elem_size = fx.layout_of(elem).size.bytes();
|
let elem_size = fx.layout_of(elem).size.bytes();
|
||||||
fx.bcx.ins().imul_imm(len, elem_size as i64)
|
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),
|
ty => unimplemented!("size_of_val for {:?}", ty),
|
||||||
};
|
};
|
||||||
ret.write_cvalue(fx, CValue::ByVal(size, usize_layout));
|
ret.write_cvalue(fx, CValue::ByVal(size, usize_layout));
|
||||||
|
|
|
@ -12,7 +12,7 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
|
||||||
pub fn trans_mono_item<'a, 'tcx: 'a>(
|
pub fn trans_mono_item<'a, 'tcx: 'a>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
module: &mut Module<impl Backend>,
|
module: &mut Module<impl Backend>,
|
||||||
caches: &mut Caches,
|
caches: &mut Caches<'tcx>,
|
||||||
ccx: &mut crate::constant::ConstantCx,
|
ccx: &mut crate::constant::ConstantCx,
|
||||||
mono_item: MonoItem<'tcx>,
|
mono_item: MonoItem<'tcx>,
|
||||||
) {
|
) {
|
||||||
|
@ -59,7 +59,7 @@ fn trans_fn<'a, 'tcx: 'a>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
module: &mut Module<impl Backend>,
|
module: &mut Module<impl Backend>,
|
||||||
constants: &mut crate::constant::ConstantCx,
|
constants: &mut crate::constant::ConstantCx,
|
||||||
caches: &mut Caches,
|
caches: &mut Caches<'tcx>,
|
||||||
instance: Instance<'tcx>,
|
instance: Instance<'tcx>,
|
||||||
) {
|
) {
|
||||||
// Step 1. Get mir
|
// Step 1. Get mir
|
||||||
|
|
|
@ -236,9 +236,13 @@ impl<'tcx> CValue<'tcx> {
|
||||||
}
|
}
|
||||||
_ => bug!("unsize non array {:?} to slice", ty),
|
_ => 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),
|
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!(
|
_ => bug!(
|
||||||
"unsize of type {:?} to {:?}",
|
"unsize of type {:?} to {:?}",
|
||||||
|
@ -556,7 +560,7 @@ pub struct FunctionCx<'a, 'tcx: 'a, B: Backend + 'a> {
|
||||||
pub local_map: HashMap<Local, CPlace<'tcx>>,
|
pub local_map: HashMap<Local, CPlace<'tcx>>,
|
||||||
pub comments: HashMap<Inst, String>,
|
pub comments: HashMap<Inst, String>,
|
||||||
pub constants: &'a mut crate::constant::ConstantCx,
|
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
|
/// add_global_comment inserts a comment here
|
||||||
pub top_nop: Option<Inst>,
|
pub top_nop: Option<Inst>,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![feature(rustc_private, macro_at_most_once_rep)]
|
#![feature(rustc_private, macro_at_most_once_rep)]
|
||||||
#![allow(intra_doc_link_resolution_failure)]
|
#![allow(intra_doc_link_resolution_failure)]
|
||||||
|
|
||||||
|
extern crate byteorder;
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
|
@ -53,6 +54,7 @@ mod common;
|
||||||
mod constant;
|
mod constant;
|
||||||
mod metadata;
|
mod metadata;
|
||||||
mod pretty_clif;
|
mod pretty_clif;
|
||||||
|
mod vtable;
|
||||||
|
|
||||||
mod prelude {
|
mod prelude {
|
||||||
pub use std::any::Any;
|
pub use std::any::Any;
|
||||||
|
@ -100,14 +102,16 @@ mod prelude {
|
||||||
use crate::constant::ConstantCx;
|
use crate::constant::ConstantCx;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct Caches {
|
pub struct Caches<'tcx> {
|
||||||
pub context: Context,
|
pub context: Context,
|
||||||
|
pub vtables: HashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Caches {
|
impl<'tcx> Caches<'tcx> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Caches {
|
Caches {
|
||||||
context: Context::new(),
|
context: Context::new(),
|
||||||
|
vtables: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
129
src/vtable.rs
Normal file
129
src/vtable.rs
Normal file
|
@ -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<ty::PolyExistentialTraitRef<'tcx>>,
|
||||||
|
) -> 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<ty::PolyExistentialTraitRef<'tcx>>,
|
||||||
|
) -> 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::<Vec<u8>>()
|
||||||
|
.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::<LittleEndian>(num, usize_size),
|
||||||
|
layout::Endian::Big => target.write_uint::<BigEndian>(num, usize_size),
|
||||||
|
}.unwrap()
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue