Skip to content

Commit d06227d

Browse files
authored
Merge pull request rust-lang#52 from oli-obk/vtable
Vtable
2 parents 248bfde + 3562118 commit d06227d

File tree

6 files changed

+362
-47
lines changed

6 files changed

+362
-47
lines changed

src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ pub enum EvalError<'tcx> {
4040
required: usize,
4141
has: usize,
4242
},
43+
CalledClosureAsFunction,
44+
VtableForArgumentlessMethod,
4345
}
4446

4547
pub type EvalResult<'tcx, T> = Result<T, EvalError<'tcx>>;
@@ -88,6 +90,10 @@ impl<'tcx> Error for EvalError<'tcx> {
8890
"reached the configured maximum number of stack frames",
8991
EvalError::AlignmentCheckFailed{..} =>
9092
"tried to execute a misaligned read or write",
93+
EvalError::CalledClosureAsFunction =>
94+
"tried to call a closure through a function pointer",
95+
EvalError::VtableForArgumentlessMethod =>
96+
"tried to call a vtable function without arguments",
9197
}
9298
}
9399

src/interpreter/mod.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use std::collections::HashMap;
2323
mod step;
2424
mod terminator;
2525
mod cast;
26+
mod vtable;
2627

2728
pub struct EvalContext<'a, 'tcx: 'a> {
2829
/// The results of the type checker, from rustc.
@@ -108,7 +109,7 @@ struct Lvalue {
108109
enum LvalueExtra {
109110
None,
110111
Length(u64),
111-
// TODO(solson): Vtable(memory::AllocId),
112+
Vtable(Pointer),
112113
DowncastVariant(usize),
113114
}
114115

@@ -569,6 +570,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
569570
LvalueExtra::Length(len) => {
570571
self.memory.write_usize(extra, len)?;
571572
}
573+
LvalueExtra::Vtable(ptr) => {
574+
self.memory.write_ptr(extra, ptr)?;
575+
},
572576
LvalueExtra::DowncastVariant(..) =>
573577
bug!("attempted to take a reference to an enum downcast lvalue"),
574578
}
@@ -587,6 +591,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
587591
Unsize => {
588592
let src = self.eval_operand(operand)?;
589593
let src_ty = self.operand_ty(operand);
594+
let dest_ty = self.monomorphize(dest_ty, self.substs());
595+
assert!(self.type_is_fat_ptr(dest_ty));
590596
let (ptr, extra) = self.get_fat_ptr(dest);
591597
self.move_(src, ptr, src_ty)?;
592598
let src_pointee_ty = pointee_type(src_ty).unwrap();
@@ -596,8 +602,22 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
596602
(&ty::TyArray(_, length), &ty::TySlice(_)) => {
597603
self.memory.write_usize(extra, length as u64)?;
598604
}
599-
600-
_ => return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue))),
605+
(&ty::TyTrait(_), &ty::TyTrait(_)) => {
606+
// For now, upcasts are limited to changes in marker
607+
// traits, and hence never actually require an actual
608+
// change to the vtable.
609+
let (_, src_extra) = self.get_fat_ptr(src);
610+
let src_extra = self.memory.read_ptr(src_extra)?;
611+
self.memory.write_ptr(extra, src_extra)?;
612+
},
613+
(_, &ty::TyTrait(ref data)) => {
614+
let trait_ref = data.principal.with_self_ty(self.tcx, src_pointee_ty);
615+
let trait_ref = self.tcx.erase_regions(&trait_ref);
616+
let vtable = self.get_vtable(trait_ref)?;
617+
self.memory.write_ptr(extra, vtable)?;
618+
},
619+
620+
_ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty),
601621
}
602622
}
603623

@@ -638,8 +658,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
638658
ty::TyFnPtr(unsafe_fn_ty) => {
639659
let src = self.eval_operand(operand)?;
640660
let ptr = self.memory.read_ptr(src)?;
641-
let fn_def = self.memory.get_fn(ptr.alloc_id)?;
642-
let fn_ptr = self.memory.create_fn_ptr(fn_def.def_id, fn_def.substs, unsafe_fn_ty);
661+
let (def_id, substs, _) = self.memory.get_fn(ptr.alloc_id)?;
662+
let fn_ptr = self.memory.create_fn_ptr(def_id, substs, unsafe_fn_ty);
643663
self.memory.write_ptr(dest, fn_ptr)?;
644664
},
645665
ref other => bug!("fn to unsafe fn cast on {:?}", other),
@@ -827,15 +847,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
827847

828848
Deref => {
829849
let pointee_ty = pointee_type(base_ty).expect("Deref of non-pointer");
830-
self.memory.dump(base.ptr.alloc_id);
831850
let ptr = self.memory.read_ptr(base.ptr)?;
832851
let extra = match pointee_ty.sty {
833852
ty::TySlice(_) | ty::TyStr => {
834853
let (_, extra) = self.get_fat_ptr(base.ptr);
835854
let len = self.memory.read_usize(extra)?;
836855
LvalueExtra::Length(len)
837856
}
838-
ty::TyTrait(_) => unimplemented!(),
857+
ty::TyTrait(_) => {
858+
let (_, extra) = self.get_fat_ptr(base.ptr);
859+
let vtable = self.memory.read_ptr(extra)?;
860+
LvalueExtra::Vtable(vtable)
861+
},
839862
_ => LvalueExtra::None,
840863
};
841864
return Ok(Lvalue { ptr: ptr, extra: extra });

src/interpreter/terminator.rs

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use syntax::codemap::{DUMMY_SP, Span};
1212

1313
use super::{EvalContext, IntegerExt};
1414
use error::{EvalError, EvalResult};
15-
use memory::{Pointer, FunctionDefinition};
15+
use memory::Pointer;
1616

1717
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
1818

@@ -90,7 +90,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
9090
ty::TyFnPtr(bare_fn_ty) => {
9191
let ptr = self.eval_operand(func)?;
9292
let fn_ptr = self.memory.read_ptr(ptr)?;
93-
let FunctionDefinition { def_id, substs, fn_ty } = self.memory.get_fn(fn_ptr.alloc_id)?;
93+
let (def_id, substs, fn_ty) = self.memory.get_fn(fn_ptr.alloc_id)?;
9494
if fn_ty != bare_fn_ty {
9595
return Err(EvalError::FunctionPointerTyMismatch(fn_ty, bare_fn_ty));
9696
}
@@ -172,21 +172,21 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
172172
// TODO(solson): Adjust the first argument when calling a Fn or
173173
// FnMut closure via FnOnce::call_once.
174174

175-
// Only trait methods can have a Self parameter.
176-
let (resolved_def_id, resolved_substs) =
177-
if let Some(trait_id) = self.tcx.trait_of_item(def_id) {
178-
self.trait_method(trait_id, def_id, substs)
179-
} else {
180-
(def_id, substs)
181-
};
182-
183175
let mut arg_srcs = Vec::new();
184176
for arg in args {
185177
let src = self.eval_operand(arg)?;
186178
let src_ty = self.operand_ty(arg);
187179
arg_srcs.push((src, src_ty));
188180
}
189181

182+
// Only trait methods can have a Self parameter.
183+
let (resolved_def_id, resolved_substs) =
184+
if let Some(trait_id) = self.tcx.trait_of_item(def_id) {
185+
self.trait_method(trait_id, def_id, substs, arg_srcs.get_mut(0))?
186+
} else {
187+
(def_id, substs)
188+
};
189+
190190
if fn_ty.abi == Abi::RustCall && !args.is_empty() {
191191
arg_srcs.pop();
192192
let last_arg = args.last().unwrap();
@@ -464,7 +464,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
464464
Ok(())
465465
}
466466

467-
fn fulfill_obligation(&self, trait_ref: ty::PolyTraitRef<'tcx>) -> traits::Vtable<'tcx, ()> {
467+
pub(super) fn fulfill_obligation(&self, trait_ref: ty::PolyTraitRef<'tcx>) -> traits::Vtable<'tcx, ()> {
468468
// Do the initial selection for the obligation. This yields the shallow result we are
469469
// looking for -- that is, what specific impl.
470470
self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
@@ -491,8 +491,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
491491
&self,
492492
trait_id: DefId,
493493
def_id: DefId,
494-
substs: &'tcx Substs<'tcx>
495-
) -> (DefId, &'tcx Substs<'tcx>) {
494+
substs: &'tcx Substs<'tcx>,
495+
first_arg: Option<&mut (Pointer, Ty<'tcx>)>,
496+
) -> EvalResult<'tcx, (DefId, &'tcx Substs<'tcx>)> {
496497
let trait_ref = ty::TraitRef::from_method(self.tcx, trait_id, substs);
497498
let trait_ref = self.tcx.normalize_associated_type(&ty::Binder(trait_ref));
498499

@@ -504,11 +505,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
504505
// and those from the method:
505506
let mth = get_impl_method(self.tcx, substs, impl_did, vtable_impl.substs, mname);
506507

507-
(mth.method.def_id, mth.substs)
508+
Ok((mth.method.def_id, mth.substs))
508509
}
509510

510511
traits::VtableClosure(vtable_closure) =>
511-
(vtable_closure.closure_def_id, vtable_closure.substs.func_substs),
512+
Ok((vtable_closure.closure_def_id, vtable_closure.substs.func_substs)),
512513

513514
traits::VtableFnPointer(_fn_ty) => {
514515
let _trait_closure_kind = self.tcx.lang_items.fn_trait_kind(trait_id).unwrap();
@@ -524,14 +525,22 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
524525
// Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
525526
}
526527

527-
traits::VtableObject(ref _data) => {
528-
unimplemented!()
529-
// Callee {
530-
// data: Virtual(traits::get_vtable_index_of_object_method(
531-
// tcx, data, def_id)),
532-
// ty: def_ty(tcx, def_id, substs)
533-
// }
534-
}
528+
traits::VtableObject(ref data) => {
529+
let idx = self.tcx.get_vtable_index_of_object_method(data, def_id);
530+
if let Some(&mut(first_arg, ref mut first_ty)) = first_arg {
531+
let (_, vtable) = self.get_fat_ptr(first_arg);
532+
let vtable = self.memory.read_ptr(vtable)?;
533+
let idx = idx + 3;
534+
let offset = idx * self.memory.pointer_size();
535+
let fn_ptr = self.memory.read_ptr(vtable.offset(offset as isize))?;
536+
let (def_id, substs, ty) = self.memory.get_fn(fn_ptr.alloc_id)?;
537+
// FIXME: skip_binder is wrong for HKL
538+
*first_ty = ty.sig.skip_binder().inputs[0];
539+
Ok((def_id, substs))
540+
} else {
541+
Err(EvalError::VtableForArgumentlessMethod)
542+
}
543+
},
535544
vtable => bug!("resolved vtable bad vtable {:?} in trans", vtable),
536545
}
537546
}
@@ -566,14 +575,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
566575
}
567576

568577
#[derive(Debug)]
569-
struct ImplMethod<'tcx> {
570-
method: Rc<ty::Method<'tcx>>,
571-
substs: &'tcx Substs<'tcx>,
572-
is_provided: bool,
578+
pub(super) struct ImplMethod<'tcx> {
579+
pub(super) method: Rc<ty::Method<'tcx>>,
580+
pub(super) substs: &'tcx Substs<'tcx>,
581+
pub(super) is_provided: bool,
573582
}
574583

575584
/// Locates the applicable definition of a method, given its name.
576-
fn get_impl_method<'a, 'tcx>(
585+
pub(super) fn get_impl_method<'a, 'tcx>(
577586
tcx: TyCtxt<'a, 'tcx, 'tcx>,
578587
substs: &'tcx Substs<'tcx>,
579588
impl_def_id: DefId,

0 commit comments

Comments
 (0)