about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2017-09-25 15:55:21 +0200
committerRalf Jung <post@ralfj.de>2017-09-25 15:55:21 +0200
commita8980fd5e8ad734ebd98a45654631cf8fed1dbe7 (patch)
tree3629a42ac1e8aaa151202905f0b22c397071ae04
parenta5503a33e6bfe503089cd776c97da9cc8e00bd37 (diff)
downloadrust-a8980fd5e8ad734ebd98a45654631cf8fed1dbe7.tar.gz
rust-a8980fd5e8ad734ebd98a45654631cf8fed1dbe7.zip
use exchange_malloc lang item for Box statements
-rw-r--r--miri/fn_call.rs5
-rw-r--r--miri/lib.rs59
-rw-r--r--src/librustc_mir/interpret/const_eval.rs3
-rw-r--r--src/librustc_mir/interpret/eval_context.rs3
-rw-r--r--src/librustc_mir/interpret/lvalue.rs2
-rw-r--r--src/librustc_mir/interpret/machine.rs3
-rw-r--r--src/librustc_mir/interpret/step.rs7
7 files changed, 66 insertions, 16 deletions
diff --git a/miri/fn_call.rs b/miri/fn_call.rs
index 36d9c0b481f..79ef3f97a9e 100644
--- a/miri/fn_call.rs
+++ b/miri/fn_call.rs
@@ -176,8 +176,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                     Lvalue::undef(),
                     StackPopCleanup::Goto(dest_block),
                 )?;
+                let mut args = self.frame().mir.args_iter();
 
-                let arg_local = self.frame().mir.args_iter().next().ok_or(
+                let arg_local = args.next().ok_or(
                     EvalErrorKind::AbiViolation(
                         "Argument to __rust_maybe_catch_panic does not take enough arguments."
                             .to_owned(),
@@ -186,6 +187,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 let arg_dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
                 self.write_ptr(arg_dest, data, u8_ptr_ty)?;
 
+                assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");
+
                 // We ourselves return 0
                 self.write_null(dest, dest_ty)?;
 
diff --git a/miri/lib.rs b/miri/lib.rs
index 428724f7de5..f6ecd6e0b00 100644
--- a/miri/lib.rs
+++ b/miri/lib.rs
@@ -114,6 +114,8 @@ pub fn eval_main<'a, 'tcx: 'a>(
             ecx.memory.write_primval(foo_ptr.into(), PrimVal::Ptr(foo.into()), ptr_size, false)?;
             ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?;
             ecx.write_ptr(dest, foo_ptr.into(), ty)?;
+
+            assert!(args.next().is_none(), "start lang item has more arguments than expected");
         } else {
             ecx.push_stack_frame(
                 main_instance,
@@ -122,6 +124,10 @@ pub fn eval_main<'a, 'tcx: 'a>(
                 Lvalue::undef(),
                 StackPopCleanup::None,
             )?;
+
+            // No arguments
+            let mut args = ecx.frame().mir.args_iter();
+            assert!(args.next().is_none(), "main function must not have arguments");
         }
 
         while ecx.step()? {}
@@ -227,17 +233,52 @@ impl<'tcx> Machine<'tcx> for Evaluator {
     fn box_alloc<'a>(
         ecx: &mut EvalContext<'a, 'tcx, Self>,
         ty: ty::Ty<'tcx>,
-    ) -> EvalResult<'tcx, PrimVal> {
-        // FIXME: call the `exchange_malloc` lang item if available
+        dest: Lvalue,
+    ) -> EvalResult<'tcx> {
         let size = ecx.type_size(ty)?.expect("box only works with sized types");
         let align = ecx.type_align(ty)?;
-        if size == 0 {
-            Ok(PrimVal::Bytes(align.into()))
-        } else {
-            ecx.memory
-                .allocate(size, align, MemoryKind::Machine(memory::MemoryKind::Rust))
-                .map(PrimVal::Ptr)
-        }
+
+        // Call the `exchange_malloc` lang item
+        let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap();
+        let malloc = ty::Instance::mono(ecx.tcx, malloc);
+        let malloc_mir = ecx.load_mir(malloc.def)?;
+        ecx.push_stack_frame(
+            malloc,
+            malloc_mir.span,
+            malloc_mir,
+            dest,
+            // Don't do anything when we are done.  The statement() function will increment
+            // the old stack frame's stmt counter to the next statement, which means that when
+            // exchange_malloc returns, we go on evaluating exactly where we want to be.
+            StackPopCleanup::None,
+        )?;
+
+        let mut args = ecx.frame().mir.args_iter();
+        let usize = ecx.tcx.types.usize;
+
+        // First argument: size
+        let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
+        ecx.write_value(
+            ValTy {
+                value: Value::ByVal(PrimVal::Bytes(size as u128)),
+                ty: usize,
+            },
+            dest,
+        )?;
+
+        // Second argument: align
+        let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
+        ecx.write_value(
+            ValTy {
+                value: Value::ByVal(PrimVal::Bytes(align as u128)),
+                ty: usize,
+            },
+            dest,
+        )?;
+
+        // No more arguments
+        assert!(args.next().is_none(), "exchange_malloc lang item has more arguments than expected");
+        Ok(())
     }
 
     fn global_item_with_linkage<'a>(
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index 7fa28dccbab..075880fc5bf 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -240,7 +240,8 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator {
     fn box_alloc<'a>(
         _ecx: &mut EvalContext<'a, 'tcx, Self>,
         _ty: ty::Ty<'tcx>,
-    ) -> EvalResult<'tcx, PrimVal> {
+        _dest: Lvalue,
+    ) -> EvalResult<'tcx> {
         Err(
             ConstEvalError::NeedsRfc("Heap allocations via `box` keyword".to_string()).into(),
         )
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 0d761c24593..3388031a30c 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -877,8 +877,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             }
 
             NullaryOp(mir::NullOp::Box, ty) => {
-                let ptr = M::box_alloc(self, ty)?;
-                self.write_primval(dest, ptr, dest_ty)?;
+                M::box_alloc(self, ty, dest)?;
             }
 
             NullaryOp(mir::NullOp::SizeOf, ty) => {
diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs
index 7fb6ac4209f..36b396a7a2b 100644
--- a/src/librustc_mir/interpret/lvalue.rs
+++ b/src/librustc_mir/interpret/lvalue.rs
@@ -497,7 +497,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         Ok(Lvalue::Ptr { ptr, extra })
     }
 
-    pub(super) fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
+    pub fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
         self.monomorphize(
             lvalue.ty(self.mir(), self.tcx).to_ty(self.tcx),
             self.substs(),
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index debb17fc0a7..3df5d1b6a31 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -70,7 +70,8 @@ pub trait Machine<'tcx>: Sized {
     fn box_alloc<'a>(
         ecx: &mut EvalContext<'a, 'tcx, Self>,
         ty: ty::Ty<'tcx>,
-    ) -> EvalResult<'tcx, PrimVal>;
+        dest: Lvalue,
+    ) -> EvalResult<'tcx>;
 
     /// Called when trying to access a global declared with a `linkage` attribute
     fn global_item_with_linkage<'a>(
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 1f538707527..c701ebfbf4c 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -92,6 +92,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         trace!("{:?}", stmt);
 
         use rustc::mir::StatementKind::*;
+
+        // Some statements (e.g. box) push new stack frames.  We have to record the stack frame number
+        // *before* executing the statement.
+        let frame_idx = self.cur_frame();
+
         match stmt.kind {
             Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?,
 
@@ -175,7 +180,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             InlineAsm { .. } => return err!(InlineAsm),
         }
 
-        self.frame_mut().stmt += 1;
+        self.stack[frame_idx].stmt += 1;
         Ok(())
     }