Skip to content

Commit be91c35

Browse files
committed
Auto merge of #54380 - RalfJung:miri-snapshot, r=eddyb
move CTFE engine snapshot state out of miri engine into CTFE machine instance It still lives in the `interpret` module as it needs access to all sorts of private stuff. Also rename a thing to make @eddyb happy :D The goal was not to change any behavior.
2 parents 2287a7a + 8e74ee0 commit be91c35

File tree

20 files changed

+286
-314
lines changed

20 files changed

+286
-314
lines changed

src/librustc_codegen_llvm/mir/constant.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use llvm;
1212
use rustc::mir::interpret::{ConstEvalErr, read_target_uint};
13-
use rustc_mir::interpret::{const_field};
13+
use rustc_mir::const_eval::const_field;
1414
use rustc::hir::def_id::DefId;
1515
use rustc::mir;
1616
use rustc_data_structures::indexed_vec::Idx;

src/librustc_lint/builtin.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1612,7 +1612,7 @@ fn validate_const<'a, 'tcx>(
16121612
gid: ::rustc::mir::interpret::GlobalId<'tcx>,
16131613
what: &str,
16141614
) {
1615-
let ecx = ::rustc_mir::interpret::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
1615+
let ecx = ::rustc_mir::const_eval::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
16161616
let result = (|| {
16171617
let op = ecx.const_to_op(constant)?;
16181618
let mut todo = vec![(op, Vec::new())];

src/librustc_mir/const_eval.rs

+78-27
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc::ty::subst::Subst;
2222
use rustc_data_structures::indexed_vec::IndexVec;
2323

2424
use syntax::ast::Mutability;
25-
use syntax::source_map::Span;
25+
use syntax::source_map::{Span, DUMMY_SP};
2626

2727
use rustc::mir::interpret::{
2828
EvalResult, EvalError, EvalErrorKind, GlobalId,
@@ -31,17 +31,25 @@ use rustc::mir::interpret::{
3131
use interpret::{self,
3232
Place, PlaceTy, MemPlace, OpTy, Operand, Value,
3333
EvalContext, StackPopCleanup, MemoryKind,
34+
snapshot,
3435
};
3536

37+
/// Number of steps until the detector even starts doing anything.
38+
/// Also, a warning is shown to the user when this number is reached.
39+
const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000;
40+
/// The number of steps between loop detector snapshots.
41+
/// Should be a power of two for performance reasons.
42+
const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
43+
3644
pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
3745
tcx: TyCtxt<'a, 'tcx, 'tcx>,
3846
instance: Instance<'tcx>,
3947
mir: &'mir mir::Mir<'tcx>,
4048
span: Span,
41-
) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> {
49+
) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> {
4250
debug!("mk_borrowck_eval_cx: {:?}", instance);
4351
let param_env = tcx.param_env(instance.def_id());
44-
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
52+
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), ());
4553
// insert a stack frame so any queries have the correct substs
4654
ecx.stack.push(interpret::Frame {
4755
block: mir::START_BLOCK,
@@ -60,10 +68,10 @@ pub fn mk_eval_cx<'a, 'tcx>(
6068
tcx: TyCtxt<'a, 'tcx, 'tcx>,
6169
instance: Instance<'tcx>,
6270
param_env: ty::ParamEnv<'tcx>,
63-
) -> EvalResult<'tcx, EvalContext<'a, 'tcx, 'tcx, CompileTimeEvaluator>> {
71+
) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'tcx, 'tcx>> {
6472
debug!("mk_eval_cx: {:?}, {:?}", instance, param_env);
6573
let span = tcx.def_span(instance.def_id());
66-
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
74+
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), ());
6775
let mir = ecx.load_mir(instance.def)?;
6876
// insert a stack frame so any queries have the correct substs
6977
ecx.push_stack_frame(
@@ -76,19 +84,18 @@ pub fn mk_eval_cx<'a, 'tcx>(
7684
Ok(ecx)
7785
}
7886

79-
pub fn eval_promoted<'a, 'mir, 'tcx>(
80-
ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
87+
pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
88+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
8189
cid: GlobalId<'tcx>,
8290
mir: &'mir mir::Mir<'tcx>,
8391
param_env: ty::ParamEnv<'tcx>,
8492
) -> EvalResult<'tcx, OpTy<'tcx>> {
85-
ecx.with_fresh_body(|ecx| {
86-
eval_body_using_ecx(ecx, cid, Some(mir), param_env)
87-
})
93+
let mut ecx = mk_borrowck_eval_cx(tcx, cid.instance, mir, DUMMY_SP).unwrap();
94+
eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env)
8895
}
8996

9097
pub fn op_to_const<'tcx>(
91-
ecx: &EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>,
98+
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
9299
op: OpTy<'tcx>,
93100
normalize: bool,
94101
) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
@@ -128,19 +135,19 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
128135
cid: GlobalId<'tcx>,
129136
mir: Option<&'mir mir::Mir<'tcx>>,
130137
param_env: ty::ParamEnv<'tcx>,
131-
) -> (EvalResult<'tcx, OpTy<'tcx>>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
138+
) -> (EvalResult<'tcx, OpTy<'tcx>>, CompileTimeEvalContext<'a, 'mir, 'tcx>) {
132139
// we start out with the best span we have
133140
// and try improving it down the road when more information is available
134141
let span = tcx.def_span(cid.instance.def_id());
135142
let span = mir.map(|mir| mir.span).unwrap_or(span);
136-
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
143+
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), ());
137144
let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
138145
(r, ecx)
139146
}
140147

141148
// Returns a pointer to where the result lives
142-
fn eval_body_using_ecx<'a, 'mir, 'tcx>(
143-
ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
149+
fn eval_body_using_ecx<'mir, 'tcx>(
150+
ecx: &mut CompileTimeEvalContext<'_, 'mir, 'tcx>,
144151
cid: GlobalId<'tcx>,
145152
mir: Option<&'mir mir::Mir<'tcx>>,
146153
param_env: ty::ParamEnv<'tcx>,
@@ -187,17 +194,12 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>(
187194
Ok(ret.into())
188195
}
189196

190-
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
191-
pub struct CompileTimeEvaluator;
192-
193197
impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
194198
fn into(self) -> EvalError<'tcx> {
195199
EvalErrorKind::MachineError(self.to_string()).into()
196200
}
197201
}
198202

199-
impl_stable_hash_for!(struct CompileTimeEvaluator {});
200-
201203
#[derive(Clone, Debug)]
202204
enum ConstEvalError {
203205
NeedsRfc(String),
@@ -234,14 +236,39 @@ impl Error for ConstEvalError {
234236
}
235237
}
236238

237-
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
239+
// Extra machine state for CTFE, and the Machine instance
240+
pub struct CompileTimeInterpreter<'a, 'mir, 'tcx: 'a+'mir> {
241+
/// When this value is negative, it indicates the number of interpreter
242+
/// steps *until* the loop detector is enabled. When it is positive, it is
243+
/// the number of steps after the detector has been enabled modulo the loop
244+
/// detector period.
245+
pub(super) steps_since_detector_enabled: isize,
246+
247+
/// Extra state to detect loops.
248+
pub(super) loop_detector: snapshot::InfiniteLoopDetector<'a, 'mir, 'tcx>,
249+
}
250+
251+
impl<'a, 'mir, 'tcx> CompileTimeInterpreter<'a, 'mir, 'tcx> {
252+
fn new() -> Self {
253+
CompileTimeInterpreter {
254+
loop_detector: Default::default(),
255+
steps_since_detector_enabled: -STEPS_UNTIL_DETECTOR_ENABLED,
256+
}
257+
}
258+
}
259+
260+
type CompileTimeEvalContext<'a, 'mir, 'tcx> =
261+
EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>;
262+
263+
impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
264+
for CompileTimeInterpreter<'a, 'mir, 'tcx>
265+
{
238266
type MemoryData = ();
239267
type MemoryKinds = !;
240268

241269
const MUT_STATIC_KIND: Option<!> = None; // no mutating of statics allowed
242-
const DETECT_LOOPS: bool = true;
243270

244-
fn find_fn<'a>(
271+
fn find_fn(
245272
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
246273
instance: ty::Instance<'tcx>,
247274
args: &[OpTy<'tcx>],
@@ -275,7 +302,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
275302
}))
276303
}
277304

278-
fn call_intrinsic<'a>(
305+
fn call_intrinsic(
279306
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
280307
instance: ty::Instance<'tcx>,
281308
args: &[OpTy<'tcx>],
@@ -291,7 +318,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
291318
)
292319
}
293320

294-
fn ptr_op<'a>(
321+
fn ptr_op(
295322
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
296323
_bin_op: mir::BinOp,
297324
_left: Scalar,
@@ -304,21 +331,45 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
304331
)
305332
}
306333

307-
fn find_foreign_static<'a>(
334+
fn find_foreign_static(
308335
_tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
309336
_def_id: DefId,
310337
) -> EvalResult<'tcx, &'tcx Allocation> {
311338
err!(ReadForeignStatic)
312339
}
313340

314-
fn box_alloc<'a>(
341+
fn box_alloc(
315342
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
316343
_dest: PlaceTy<'tcx>,
317344
) -> EvalResult<'tcx> {
318345
Err(
319346
ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into(),
320347
)
321348
}
349+
350+
fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
351+
{
352+
let steps = &mut ecx.machine.steps_since_detector_enabled;
353+
354+
*steps += 1;
355+
if *steps < 0 {
356+
return Ok(());
357+
}
358+
359+
*steps %= DETECTOR_SNAPSHOT_PERIOD;
360+
if *steps != 0 {
361+
return Ok(());
362+
}
363+
}
364+
365+
let span = ecx.frame().span;
366+
ecx.machine.loop_detector.observe_and_analyze(
367+
&ecx.tcx,
368+
span,
369+
&ecx.memory,
370+
&ecx.stack[..],
371+
)
372+
}
322373
}
323374

324375
/// Project to a field of a (variant of a) const

src/librustc_mir/hair/pattern/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ mod check_match;
1616
pub use self::check_match::check_crate;
1717
pub(crate) use self::check_match::check_match;
1818

19-
use interpret::{const_field, const_variant_index};
19+
use const_eval::{const_field, const_variant_index};
2020

2121
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
2222
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};

src/librustc_mir/interpret/cast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_apfloat::Float;
2121

2222
use super::{EvalContext, Machine, PlaceTy, OpTy, Value};
2323

24-
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
24+
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
2525
fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
2626
match ty.sty {
2727
ty::RawPtr(ty::TypeAndMut { ty, .. }) |

0 commit comments

Comments
 (0)