Skip to content

Commit

Permalink
implement by-value object safety
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Apr 7, 2019
1 parent 944ffbf commit b00fd57
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 13 deletions.
38 changes: 27 additions & 11 deletions src/librustc_mir/interpret/terminator.rs
Expand Up @@ -407,25 +407,41 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
} }
// cannot use the shim here, because that will only result in infinite recursion // cannot use the shim here, because that will only result in infinite recursion
ty::InstanceDef::Virtual(_, idx) => { ty::InstanceDef::Virtual(_, idx) => {
let mut args = args.to_vec();
let ptr_size = self.pointer_size(); let ptr_size = self.pointer_size();
let ptr = self.deref_operand(args[0])?; // We have to implement all "object safe receivers". Currently we
let vtable = ptr.vtable()?; // support built-in pointers (&, &mut, Box) as well as unsized-self. We do
// not yet support custom self types.
// Also see librustc_codegen_llvm/abi.rs and librustc_codegen_llvm/mir/block.rs.
let receiver_place = match args[0].layout.ty.builtin_deref(true) {
Some(_) => {
// Built-in pointer.
self.deref_operand(args[0])?
}
None => {
// Unsized self.
args[0].to_mem_place()
}
};
// Find and consult vtable
let vtable = receiver_place.vtable()?;
self.memory.check_align(vtable.into(), self.tcx.data_layout.pointer_align.abi)?; self.memory.check_align(vtable.into(), self.tcx.data_layout.pointer_align.abi)?;
let fn_ptr = self.memory.get(vtable.alloc_id)?.read_ptr_sized( let fn_ptr = self.memory.get(vtable.alloc_id)?.read_ptr_sized(
self, self,
vtable.offset(ptr_size * (idx as u64 + 3), self)?, vtable.offset(ptr_size * (idx as u64 + 3), self)?,
)?.to_ptr()?; )?.to_ptr()?;
let instance = self.memory.get_fn(fn_ptr)?; let instance = self.memory.get_fn(fn_ptr)?;


// We have to patch the self argument, in particular get the layout // `*mut receiver_place.layout.ty` is almost the layout that we
// expected by the actual function. Cannot just use "field 0" due to // want for args[0]: We have to project to field 0 because we want
// Box<self>. // a thin pointer.
let mut args = args.to_vec(); assert!(receiver_place.layout.is_unsized());
let pointee = args[0].layout.ty.builtin_deref(true).unwrap().ty; let receiver_ptr_ty = self.tcx.mk_mut_ptr(receiver_place.layout.ty);
let fake_fat_ptr_ty = self.tcx.mk_mut_ptr(pointee); let this_receiver_ptr = self.layout_of(receiver_ptr_ty)?.field(self, 0)?;
args[0] = OpTy::from(ImmTy { // strip vtable // Adjust receiver argument.
layout: self.layout_of(fake_fat_ptr_ty)?.field(self, 0)?, args[0] = OpTy::from(ImmTy {
imm: Immediate::Scalar(ptr.ptr.into()) layout: this_receiver_ptr,
imm: Immediate::Scalar(receiver_place.ptr.into())
}); });
trace!("Patched self operand to {:#?}", args[0]); trace!("Patched self operand to {:#?}", args[0]);
// recurse with concrete function // recurse with concrete function
Expand Down
11 changes: 9 additions & 2 deletions src/librustc_mir/interpret/traits.rs
Expand Up @@ -3,7 +3,7 @@ use rustc::ty::{self, Ty};
use rustc::ty::layout::{Size, Align, LayoutOf}; use rustc::ty::layout::{Size, Align, LayoutOf};
use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic}; use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic};


use super::{InterpretCx, Machine, MemoryKind}; use super::{InterpretCx, InterpError, Machine, MemoryKind};


impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
Expand Down Expand Up @@ -76,7 +76,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>


for (i, method) in methods.iter().enumerate() { for (i, method) in methods.iter().enumerate() {
if let Some((def_id, substs)) = *method { if let Some((def_id, substs)) = *method {
let instance = self.resolve(def_id, substs)?; // resolve for vtable: insert thims where needed
let substs = self.subst_and_normalize_erasing_regions(substs)?;
let instance = ty::Instance::resolve_for_vtable(
*self.tcx,
self.param_env,
def_id,
substs,
).ok_or_else(|| InterpError::TooGeneric)?;
let fn_ptr = self.memory.create_fn_alloc(instance).with_default_tag(); let fn_ptr = self.memory.create_fn_alloc(instance).with_default_tag();
let method_ptr = vtable.offset(ptr_size * (3 + i as u64), self)?; let method_ptr = vtable.offset(ptr_size * (3 + i as u64), self)?;
self.memory self.memory
Expand Down

0 comments on commit b00fd57

Please sign in to comment.