@@ -76,8 +76,7 @@ pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> {
76
76
/// The locals are stored as `Option<Value>`s.
77
77
/// `None` represents a local that is currently dead, while a live local
78
78
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
79
- pub locals : IndexVec < mir:: Local , LocalValue < Tag > > ,
80
- pub local_layouts : IndexVec < mir:: Local , Cell < Option < TyLayout < ' tcx > > > > ,
79
+ pub locals : IndexVec < mir:: Local , LocalState < ' tcx , Tag > > ,
81
80
82
81
////////////////////////////////////////////////////////////////////////////////
83
82
// Current position within the function
@@ -106,7 +105,15 @@ pub enum StackPopCleanup {
106
105
None { cleanup : bool } ,
107
106
}
108
107
109
- // State of a local variable
108
+ /// State of a local variable including a memoized layout
109
+ #[ derive( Clone , PartialEq , Eq ) ]
110
+ pub struct LocalState < ' tcx , Tag =( ) , Id =AllocId > {
111
+ pub state : LocalValue < Tag , Id > ,
112
+ /// Don't modify if `Some`, this is only used to prevent computing the layout twice
113
+ pub layout : Cell < Option < TyLayout < ' tcx > > > ,
114
+ }
115
+
116
+ /// State of a local variable
110
117
#[ derive( Copy , Clone , PartialEq , Eq , Hash ) ]
111
118
pub enum LocalValue < Tag =( ) , Id =AllocId > {
112
119
Dead ,
@@ -117,16 +124,16 @@ pub enum LocalValue<Tag=(), Id=AllocId> {
117
124
Live ( Operand < Tag , Id > ) ,
118
125
}
119
126
120
- impl < ' tcx , Tag > LocalValue < Tag > {
127
+ impl < ' tcx , Tag > LocalState < ' tcx , Tag > {
121
128
pub fn access ( & self ) -> EvalResult < ' tcx , & Operand < Tag > > {
122
- match self {
129
+ match self . state {
123
130
LocalValue :: Dead => err ! ( DeadLocal ) ,
124
131
LocalValue :: Live ( ref val) => Ok ( val) ,
125
132
}
126
133
}
127
134
128
135
pub fn access_mut ( & mut self ) -> EvalResult < ' tcx , & mut Operand < Tag > > {
129
- match self {
136
+ match self . state {
130
137
LocalValue :: Dead => err ! ( DeadLocal ) ,
131
138
LocalValue :: Live ( ref mut val) => Ok ( val) ,
132
139
}
@@ -310,17 +317,21 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
310
317
pub fn layout_of_local (
311
318
& self ,
312
319
frame : & Frame < ' mir , ' tcx , M :: PointerTag , M :: FrameExtra > ,
313
- local : mir:: Local
320
+ local : mir:: Local ,
321
+ layout : Option < TyLayout < ' tcx > > ,
314
322
) -> EvalResult < ' tcx , TyLayout < ' tcx > > {
315
- let cell = & frame. local_layouts [ local] ;
316
- if cell. get ( ) . is_none ( ) {
317
- let local_ty = frame. mir . local_decls [ local] . ty ;
318
- let local_ty = self . monomorphize_with_substs ( local_ty, frame. instance . substs ) ;
319
- let layout = self . layout_of ( local_ty) ?;
320
- cell. set ( Some ( layout) ) ;
323
+ match frame. locals [ local] . layout . get ( ) {
324
+ None => {
325
+ let layout = :: interpret:: operand:: from_known_layout ( layout, || {
326
+ let local_ty = frame. mir . local_decls [ local] . ty ;
327
+ let local_ty = self . monomorphize_with_substs ( local_ty, frame. instance . substs ) ;
328
+ self . layout_of ( local_ty)
329
+ } ) ?;
330
+ frame. locals [ local] . layout . set ( Some ( layout) ) ;
331
+ Ok ( layout)
332
+ }
333
+ Some ( layout) => Ok ( layout) ,
321
334
}
322
-
323
- Ok ( cell. get ( ) . unwrap ( ) )
324
335
}
325
336
326
337
pub fn str_to_immediate ( & mut self , s : & str ) -> EvalResult < ' tcx , Immediate < M :: PointerTag > > {
@@ -454,7 +465,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
454
465
// empty local array, we fill it in below, after we are inside the stack frame and
455
466
// all methods actually know about the frame
456
467
locals : IndexVec :: new ( ) ,
457
- local_layouts : IndexVec :: from_elem_n ( Default :: default ( ) , mir. local_decls . len ( ) ) ,
458
468
span,
459
469
instance,
460
470
stmt : 0 ,
@@ -466,12 +476,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
466
476
// We put some marker immediate into the locals that we later want to initialize.
467
477
// This can be anything except for LocalValue::Dead -- because *that* is the
468
478
// value we use for things that we know are initially dead.
469
- let dummy =
470
- LocalValue :: Live ( Operand :: Immediate ( Immediate :: Scalar ( ScalarMaybeUndef :: Undef ) ) ) ;
479
+ let dummy = LocalState {
480
+ state : LocalValue :: Live ( Operand :: Immediate ( Immediate :: Scalar (
481
+ ScalarMaybeUndef :: Undef ,
482
+ ) ) ) ,
483
+ layout : Cell :: new ( None ) ,
484
+ } ;
471
485
let mut locals = IndexVec :: from_elem ( dummy, & mir. local_decls ) ;
472
486
// Return place is handled specially by the `eval_place` functions, and the
473
487
// entry in `locals` should never be used. Make it dead, to be sure.
474
- locals[ mir:: RETURN_PLACE ] = LocalValue :: Dead ;
488
+ locals[ mir:: RETURN_PLACE ] . state = LocalValue :: Dead ;
475
489
// Now mark those locals as dead that we do not want to initialize
476
490
match self . tcx . describe_def ( instance. def_id ( ) ) {
477
491
// statics and constants don't have `Storage*` statements, no need to look for them
@@ -484,7 +498,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
484
498
match stmt. kind {
485
499
StorageLive ( local) |
486
500
StorageDead ( local) => {
487
- locals[ local] = LocalValue :: Dead ;
501
+ locals[ local] . state = LocalValue :: Dead ;
488
502
}
489
503
_ => { }
490
504
}
@@ -494,11 +508,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
494
508
}
495
509
// Finally, properly initialize all those that still have the dummy value
496
510
for ( idx, local) in locals. iter_enumerated_mut ( ) {
497
- match * local {
511
+ match local. state {
498
512
LocalValue :: Live ( _) => {
499
- // This needs to be peoperly initialized.
500
- let layout = self . layout_of_local ( self . frame ( ) , idx) ?;
501
- * local = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
513
+ // This needs to be properly initialized.
514
+ let ty = self . monomorphize ( mir. local_decls [ idx] . ty ) ?;
515
+ let layout = self . layout_of ( ty) ?;
516
+ local. state = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
517
+ local. layout = Cell :: new ( Some ( layout) ) ;
502
518
}
503
519
LocalValue :: Dead => {
504
520
// Nothing to do
@@ -543,7 +559,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
543
559
}
544
560
// Deallocate all locals that are backed by an allocation.
545
561
for local in frame. locals {
546
- self . deallocate_local ( local) ?;
562
+ self . deallocate_local ( local. state ) ?;
547
563
}
548
564
// Validate the return value. Do this after deallocating so that we catch dangling
549
565
// references.
@@ -591,10 +607,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
591
607
assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place live" ) ;
592
608
trace ! ( "{:?} is now live" , local) ;
593
609
594
- let layout = self . layout_of_local ( self . frame ( ) , local) ?;
610
+ let layout = self . layout_of_local ( self . frame ( ) , local, None ) ?;
595
611
let init = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
596
612
// StorageLive *always* kills the value that's currently stored
597
- Ok ( mem:: replace ( & mut self . frame_mut ( ) . locals [ local] , init) )
613
+ Ok ( mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . state , init) )
598
614
}
599
615
600
616
/// Returns the old value of the local.
@@ -603,7 +619,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
603
619
assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place dead" ) ;
604
620
trace ! ( "{:?} is now dead" , local) ;
605
621
606
- mem:: replace ( & mut self . frame_mut ( ) . locals [ local] , LocalValue :: Dead )
622
+ mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . state , LocalValue :: Dead )
607
623
}
608
624
609
625
pub ( super ) fn deallocate_local (
0 commit comments