@@ -76,8 +76,7 @@ pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> {
7676 /// The locals are stored as `Option<Value>`s.
7777 /// `None` represents a local that is currently dead, while a live local
7878 /// 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 > > ,
8180
8281 ////////////////////////////////////////////////////////////////////////////////
8382 // Current position within the function
@@ -106,7 +105,15 @@ pub enum StackPopCleanup {
106105 None { cleanup : bool } ,
107106}
108107
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
110117#[ derive( Copy , Clone , PartialEq , Eq , Hash ) ]
111118pub enum LocalValue < Tag =( ) , Id =AllocId > {
112119 Dead ,
@@ -117,16 +124,16 @@ pub enum LocalValue<Tag=(), Id=AllocId> {
117124 Live ( Operand < Tag , Id > ) ,
118125}
119126
120- impl < ' tcx , Tag > LocalValue < Tag > {
127+ impl < ' tcx , Tag > LocalState < ' tcx , Tag > {
121128 pub fn access ( & self ) -> EvalResult < ' tcx , & Operand < Tag > > {
122- match self {
129+ match self . state {
123130 LocalValue :: Dead => err ! ( DeadLocal ) ,
124131 LocalValue :: Live ( ref val) => Ok ( val) ,
125132 }
126133 }
127134
128135 pub fn access_mut ( & mut self ) -> EvalResult < ' tcx , & mut Operand < Tag > > {
129- match self {
136+ match self . state {
130137 LocalValue :: Dead => err ! ( DeadLocal ) ,
131138 LocalValue :: Live ( ref mut val) => Ok ( val) ,
132139 }
@@ -310,17 +317,21 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
310317 pub fn layout_of_local (
311318 & self ,
312319 frame : & Frame < ' mir , ' tcx , M :: PointerTag , M :: FrameExtra > ,
313- local : mir:: Local
320+ local : mir:: Local ,
321+ layout : Option < TyLayout < ' tcx > > ,
314322 ) -> 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) ,
321334 }
322-
323- Ok ( cell. get ( ) . unwrap ( ) )
324335 }
325336
326337 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
454465 // empty local array, we fill it in below, after we are inside the stack frame and
455466 // all methods actually know about the frame
456467 locals : IndexVec :: new ( ) ,
457- local_layouts : IndexVec :: from_elem_n ( Default :: default ( ) , mir. local_decls . len ( ) ) ,
458468 span,
459469 instance,
460470 stmt : 0 ,
@@ -466,12 +476,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
466476 // We put some marker immediate into the locals that we later want to initialize.
467477 // This can be anything except for LocalValue::Dead -- because *that* is the
468478 // 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+ } ;
471485 let mut locals = IndexVec :: from_elem ( dummy, & mir. local_decls ) ;
472486 // Return place is handled specially by the `eval_place` functions, and the
473487 // 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 ;
475489 // Now mark those locals as dead that we do not want to initialize
476490 match self . tcx . describe_def ( instance. def_id ( ) ) {
477491 // 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
484498 match stmt. kind {
485499 StorageLive ( local) |
486500 StorageDead ( local) => {
487- locals[ local] = LocalValue :: Dead ;
501+ locals[ local] . state = LocalValue :: Dead ;
488502 }
489503 _ => { }
490504 }
@@ -494,11 +508,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
494508 }
495509 // Finally, properly initialize all those that still have the dummy value
496510 for ( idx, local) in locals. iter_enumerated_mut ( ) {
497- match * local {
511+ match local. state {
498512 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) ) ;
502518 }
503519 LocalValue :: Dead => {
504520 // Nothing to do
@@ -543,7 +559,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
543559 }
544560 // Deallocate all locals that are backed by an allocation.
545561 for local in frame. locals {
546- self . deallocate_local ( local) ?;
562+ self . deallocate_local ( local. state ) ?;
547563 }
548564 // Validate the return value. Do this after deallocating so that we catch dangling
549565 // references.
@@ -591,10 +607,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
591607 assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place live" ) ;
592608 trace ! ( "{:?} is now live" , local) ;
593609
594- let layout = self . layout_of_local ( self . frame ( ) , local) ?;
610+ let layout = self . layout_of_local ( self . frame ( ) , local, None ) ?;
595611 let init = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
596612 // 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) )
598614 }
599615
600616 /// 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
603619 assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place dead" ) ;
604620 trace ! ( "{:?} is now dead" , local) ;
605621
606- mem:: replace ( & mut self . frame_mut ( ) . locals [ local] , LocalValue :: Dead )
622+ mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . state , LocalValue :: Dead )
607623 }
608624
609625 pub ( super ) fn deallocate_local (
0 commit comments