Skip to content

Commit 6196146

Browse files
committed
Implement trait objects (cc rust-lang#14)
1 parent 62a0203 commit 6196146

File tree

9 files changed

+243
-177
lines changed

9 files changed

+243
-177
lines changed

0006-Disable-all-trait-object-unsizing.patch

Lines changed: 0 additions & 137 deletions
This file was deleted.

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ target-lexicon = "0.0.3"
2424
faerie = "0.5.0"
2525
ar = "0.6.0"
2626
bitflags = "1.0.3"
27+
byteorder = "1.2.6"
2728

2829
# Uncomment to use local checkout of cranelift
2930
#[patch."https://github.com/CraneStation/cranelift.git"]

examples/mini_core_hello_world.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ impl Termination for () {
3131
}
3232
}
3333

34+
trait SomeTrait {
35+
fn object_safe(&self);
36+
}
37+
38+
impl SomeTrait for &'static str {
39+
fn object_safe(&self) {
40+
unsafe {
41+
puts(*self as *const str as *const u8);
42+
}
43+
}
44+
}
45+
3446
#[lang = "start"]
3547
fn start<T: Termination + 'static>(
3648
main: fn() -> T,
@@ -45,15 +57,28 @@ static NUM_REF: &'static u8 = unsafe { &NUM };
4557

4658
fn main() {
4759
unsafe {
48-
let slice: &[u8] = b"Hello\0" as &[u8; 6];
49-
if intrinsics::size_of_val(slice) as u8 != 6 {
50-
panic(&("eji", "frjio", 0, 0));
51-
};
52-
let ptr: *const u8 = slice as *const [u8] as *const u8;
53-
let world = box "World!\0";
60+
let hello: &[u8] = b"Hello\0" as &[u8; 6];
61+
let ptr: *const u8 = hello as *const [u8] as *const u8;
5462
puts(ptr);
63+
64+
let world = box "World!\0";
5565
puts(*world as *const str as *const u8);
56-
}
5766

58-
//panic(&("panic msg", "abc.rs", 0, 43));
67+
if intrinsics::size_of_val(hello) as u8 != 6 {
68+
panic(&("", "", 0, 0));
69+
};
70+
71+
let chars = &['C', 'h', 'a', 'r', 's'];
72+
let chars = chars as &[char];
73+
if intrinsics::size_of_val(chars) as u8 != 4 * 5 {
74+
panic(&("", "", 0, 0));
75+
}
76+
77+
let a: &dyn SomeTrait = &"abc\0";
78+
a.object_safe();
79+
80+
if intrinsics::size_of_val(a) as u8 != 16 {
81+
panic(&("", "", 0, 0));
82+
}
83+
}
5984
}

src/abi.rs

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ fn get_pass_mode<'a, 'tcx: 'a>(
5050
}
5151
}
5252

53+
fn adjust_arg_for_abi<'a, 'tcx: 'a>(
54+
fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
55+
sig: FnSig<'tcx>,
56+
arg: CValue<'tcx>,
57+
) -> Value {
58+
match get_pass_mode(fx.tcx, sig.abi, arg.layout().ty, false) {
59+
PassMode::NoPass => unimplemented!("pass mode nopass"),
60+
PassMode::ByVal(_) => arg.load_value(fx),
61+
PassMode::ByRef => arg.force_stack(fx),
62+
}
63+
}
64+
5365
pub fn cton_sig_from_fn_ty<'a, 'tcx: 'a>(
5466
tcx: TyCtxt<'a, 'tcx, 'tcx>,
5567
fn_ty: Ty<'tcx>,
@@ -164,12 +176,16 @@ pub fn get_function_name_and_sig<'a, 'tcx>(
164176

165177
impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
166178
/// Instance must be monomorphized
167-
pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
179+
pub fn get_function_id(&mut self, inst: Instance<'tcx>) -> FuncId {
168180
let (name, sig) = get_function_name_and_sig(self.tcx, inst);
169-
let func_id = self
170-
.module
181+
self.module
171182
.declare_function(&name, Linkage::Import, &sig)
172-
.unwrap();
183+
.unwrap()
184+
}
185+
186+
/// Instance must be monomorphized
187+
pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
188+
let func_id = self.get_function_id(inst);
173189
self.module
174190
.declare_func_in_func(func_id, &mut self.bcx.func)
175191
}
@@ -468,29 +484,51 @@ pub fn codegen_call<'a, 'tcx: 'a>(
468484
PassMode::ByVal(_) => None,
469485
};
470486

471-
let call_args: Vec<Value> = return_ptr
472-
.into_iter()
473-
.chain(args.into_iter().map(|arg| {
474-
match get_pass_mode(fx.tcx, sig.abi, arg.layout().ty, false) {
475-
PassMode::NoPass => unimplemented!("pass mode nopass"),
476-
PassMode::ByVal(_) => arg.load_value(fx),
477-
PassMode::ByRef => arg.force_stack(fx),
478-
}
479-
})).collect::<Vec<_>>();
480-
481-
let call_inst = match fn_ty.sty {
487+
let instance = match fn_ty.sty {
482488
ty::FnDef(def_id, substs) => {
483-
let inst = Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap();
484-
let func_ref = fx.get_function_ref(inst);
485-
fx.bcx.ins().call(func_ref, &call_args)
489+
Some(Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap())
486490
}
487-
ty::FnPtr(_) => {
488-
let func = trans_operand(fx, func);
489-
let func = func.load_value(fx);
490-
let sig = fx.bcx.import_signature(cton_sig_from_fn_ty(fx.tcx, fn_ty));
491-
fx.bcx.ins().call_indirect(sig, func, &call_args)
492-
}
493-
_ => bug!("{:?}", fn_ty),
491+
_ => None,
492+
};
493+
494+
let func_ref: Option<Value>; // Indirect call target
495+
496+
let first_arg = {
497+
if let Some(Instance {
498+
def: InstanceDef::Virtual(_, idx),
499+
..
500+
}) = instance
501+
{
502+
let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0], idx);
503+
func_ref = Some(method);
504+
Some(ptr)
505+
} else {
506+
func_ref = if instance.is_none() {
507+
let func = trans_operand(fx, func);
508+
Some(func.load_value(fx))
509+
} else {
510+
None
511+
};
512+
513+
args.get(0).map(|arg| adjust_arg_for_abi(fx, sig, *arg))
514+
}.into_iter()
515+
};
516+
517+
let call_args: Vec<Value> = return_ptr
518+
.into_iter()
519+
.chain(first_arg)
520+
.chain(
521+
args.into_iter()
522+
.skip(1)
523+
.map(|arg| adjust_arg_for_abi(fx, sig, arg)),
524+
).collect::<Vec<_>>();
525+
526+
let sig = fx.bcx.import_signature(cton_sig_from_fn_ty(fx.tcx, fn_ty));
527+
let call_inst = if let Some(func_ref) = func_ref {
528+
fx.bcx.ins().call_indirect(sig, func_ref, &call_args)
529+
} else {
530+
let func_ref = fx.get_function_ref(instance.expect("non-indirect call on non-FnDef type"));
531+
fx.bcx.ins().call(func_ref, &call_args)
494532
};
495533

496534
match output_pass_mode {
@@ -610,6 +648,7 @@ fn codegen_intrinsic_call<'a, 'tcx: 'a>(
610648
let elem_size = fx.layout_of(elem).size.bytes();
611649
fx.bcx.ins().imul_imm(len, elem_size as i64)
612650
}
651+
ty::Dynamic(..) => crate::vtable::size_of_obj(fx, args[0]),
613652
ty => unimplemented!("size_of_val for {:?}", ty),
614653
};
615654
ret.write_cvalue(fx, CValue::ByVal(size, usize_layout));

src/base.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
1212
pub fn trans_mono_item<'a, 'tcx: 'a>(
1313
tcx: TyCtxt<'a, 'tcx, 'tcx>,
1414
module: &mut Module<impl Backend>,
15-
caches: &mut Caches,
15+
caches: &mut Caches<'tcx>,
1616
ccx: &mut crate::constant::ConstantCx,
1717
mono_item: MonoItem<'tcx>,
1818
) {
@@ -59,7 +59,7 @@ fn trans_fn<'a, 'tcx: 'a>(
5959
tcx: TyCtxt<'a, 'tcx, 'tcx>,
6060
module: &mut Module<impl Backend>,
6161
constants: &mut crate::constant::ConstantCx,
62-
caches: &mut Caches,
62+
caches: &mut Caches<'tcx>,
6363
instance: Instance<'tcx>,
6464
) {
6565
// Step 1. Get mir

src/common.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,13 @@ impl<'tcx> CValue<'tcx> {
236236
}
237237
_ => bug!("unsize non array {:?} to slice", ty),
238238
},
239-
ty::Dynamic(_, _) => match ty.sty {
239+
ty::Dynamic(data, _) => match ty.sty {
240240
ty::Dynamic(_, _) => self.load_value_pair(fx),
241-
_ => unimpl!("unsize of type ... to {:?}", dest.layout().ty),
241+
_ => {
242+
let ptr = self.load_value(fx);
243+
let vtable = crate::vtable::get_vtable(fx, ty, data.principal());
244+
(ptr, vtable)
245+
}
242246
},
243247
_ => bug!(
244248
"unsize of type {:?} to {:?}",
@@ -556,7 +560,7 @@ pub struct FunctionCx<'a, 'tcx: 'a, B: Backend + 'a> {
556560
pub local_map: HashMap<Local, CPlace<'tcx>>,
557561
pub comments: HashMap<Inst, String>,
558562
pub constants: &'a mut crate::constant::ConstantCx,
559-
pub caches: &'a mut Caches,
563+
pub caches: &'a mut Caches<'tcx>,
560564

561565
/// add_global_comment inserts a comment here
562566
pub top_nop: Option<Inst>,

0 commit comments

Comments
 (0)