Skip to content

Commit 169f791

Browse files
committed
move CTFE engine snapshot state out of miri engine into CTFE machine instance
1 parent ff6422d commit 169f791

File tree

16 files changed

+266
-282
lines changed

16 files changed

+266
-282
lines changed

src/librustc_mir/const_eval.rs

Lines changed: 76 additions & 26 deletions
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,18 @@ use rustc::mir::interpret::{
3131
use interpret::{self,
3232
Place, PlaceTy, MemPlace, OpTy, Operand, Value,
3333
EvalContext, StackPopCleanup, MemoryKind,
34+
snapshot,
3435
};
3536

3637
pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
3738
tcx: TyCtxt<'a, 'tcx, 'tcx>,
3839
instance: Instance<'tcx>,
3940
mir: &'mir mir::Mir<'tcx>,
4041
span: Span,
41-
) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> {
42+
) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> {
4243
debug!("mk_borrowck_eval_cx: {:?}", instance);
4344
let param_env = tcx.param_env(instance.def_id());
44-
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
45+
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator::new(), ());
4546
// insert a stack frame so any queries have the correct substs
4647
ecx.stack.push(interpret::Frame {
4748
block: mir::START_BLOCK,
@@ -60,10 +61,10 @@ pub fn mk_eval_cx<'a, 'tcx>(
6061
tcx: TyCtxt<'a, 'tcx, 'tcx>,
6162
instance: Instance<'tcx>,
6263
param_env: ty::ParamEnv<'tcx>,
63-
) -> EvalResult<'tcx, EvalContext<'a, 'tcx, 'tcx, CompileTimeEvaluator>> {
64+
) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'tcx, 'tcx>> {
6465
debug!("mk_eval_cx: {:?}, {:?}", instance, param_env);
6566
let span = tcx.def_span(instance.def_id());
66-
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
67+
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator::new(), ());
6768
let mir = ecx.load_mir(instance.def)?;
6869
// insert a stack frame so any queries have the correct substs
6970
ecx.push_stack_frame(
@@ -77,18 +78,17 @@ pub fn mk_eval_cx<'a, 'tcx>(
7778
}
7879

7980
pub fn eval_promoted<'a, 'mir, 'tcx>(
80-
ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
81+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
8182
cid: GlobalId<'tcx>,
8283
mir: &'mir mir::Mir<'tcx>,
8384
param_env: ty::ParamEnv<'tcx>,
8485
) -> EvalResult<'tcx, OpTy<'tcx>> {
85-
ecx.with_fresh_body(|ecx| {
86-
eval_body_using_ecx(ecx, cid, Some(mir), param_env)
87-
})
86+
let mut ecx = mk_borrowck_eval_cx(tcx, cid.instance, mir, DUMMY_SP).unwrap();
87+
eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env)
8888
}
8989

9090
pub fn op_to_const<'tcx>(
91-
ecx: &EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>,
91+
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
9292
op: OpTy<'tcx>,
9393
normalize: bool,
9494
) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
@@ -128,19 +128,19 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
128128
cid: GlobalId<'tcx>,
129129
mir: Option<&'mir mir::Mir<'tcx>>,
130130
param_env: ty::ParamEnv<'tcx>,
131-
) -> (EvalResult<'tcx, OpTy<'tcx>>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
131+
) -> (EvalResult<'tcx, OpTy<'tcx>>, CompileTimeEvalContext<'a, 'mir, 'tcx>) {
132132
// we start out with the best span we have
133133
// and try improving it down the road when more information is available
134134
let span = tcx.def_span(cid.instance.def_id());
135135
let span = mir.map(|mir| mir.span).unwrap_or(span);
136-
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
136+
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator::new(), ());
137137
let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
138138
(r, ecx)
139139
}
140140

141141
// 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>,
142+
fn eval_body_using_ecx<'mir, 'tcx>(
143+
ecx: &mut CompileTimeEvalContext<'_, 'mir, 'tcx>,
144144
cid: GlobalId<'tcx>,
145145
mir: Option<&'mir mir::Mir<'tcx>>,
146146
param_env: ty::ParamEnv<'tcx>,
@@ -187,17 +187,12 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>(
187187
Ok(ret.into())
188188
}
189189

190-
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
191-
pub struct CompileTimeEvaluator;
192-
193190
impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
194191
fn into(self) -> EvalError<'tcx> {
195192
EvalErrorKind::MachineError(self.to_string()).into()
196193
}
197194
}
198195

199-
impl_stable_hash_for!(struct CompileTimeEvaluator {});
200-
201196
#[derive(Clone, Debug)]
202197
enum ConstEvalError {
203198
NeedsRfc(String),
@@ -234,14 +229,39 @@ impl Error for ConstEvalError {
234229
}
235230
}
236231

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

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

244-
fn find_fn<'a>(
264+
fn find_fn(
245265
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
246266
instance: ty::Instance<'tcx>,
247267
args: &[OpTy<'tcx>],
@@ -275,7 +295,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
275295
}))
276296
}
277297

278-
fn call_intrinsic<'a>(
298+
fn call_intrinsic(
279299
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
280300
instance: ty::Instance<'tcx>,
281301
args: &[OpTy<'tcx>],
@@ -291,7 +311,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
291311
)
292312
}
293313

294-
fn ptr_op<'a>(
314+
fn ptr_op(
295315
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
296316
_bin_op: mir::BinOp,
297317
_left: Scalar,
@@ -304,21 +324,51 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
304324
)
305325
}
306326

307-
fn find_foreign_static<'a>(
327+
fn find_foreign_static(
308328
_tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
309329
_def_id: DefId,
310330
) -> EvalResult<'tcx, &'tcx Allocation> {
311331
err!(ReadForeignStatic)
312332
}
313333

314-
fn box_alloc<'a>(
334+
fn box_alloc(
315335
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
316336
_dest: PlaceTy<'tcx>,
317337
) -> EvalResult<'tcx> {
318338
Err(
319339
ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into(),
320340
)
321341
}
342+
343+
fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
344+
{
345+
let steps = &mut ecx.machine.steps_since_detector_enabled;
346+
347+
*steps += 1;
348+
if *steps < 0 {
349+
return Ok(());
350+
}
351+
352+
*steps %= snapshot::DETECTOR_SNAPSHOT_PERIOD;
353+
if *steps != 0 {
354+
return Ok(());
355+
}
356+
}
357+
358+
if ecx.machine.loop_detector.is_empty() {
359+
// First run of the loop detector
360+
361+
// FIXME(#49980): make this warning a lint
362+
ecx.tcx.sess.span_warn(ecx.frame().span,
363+
"Constant evaluating a complex constant, this might take some time");
364+
}
365+
366+
ecx.machine.loop_detector.observe_and_analyze(
367+
&ecx.tcx,
368+
&ecx.memory,
369+
&ecx.stack[..],
370+
)
371+
}
322372
}
323373

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

src/librustc_mir/interpret/cast.rs

Lines changed: 1 addition & 1 deletion
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)