@@ -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 , LocalValue < ' tcx , Tag > > ,
81
80
82
81
////////////////////////////////////////////////////////////////////////////////
83
82
// Current position within the function
@@ -106,9 +105,17 @@ 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 LocalValue < ' tcx , Tag =( ) , Id =AllocId > {
111
+ pub state : LocalState < 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
- pub enum LocalValue < Tag =( ) , Id =AllocId > {
118
+ pub enum LocalState < Tag =( ) , Id =AllocId > {
112
119
Dead ,
113
120
// Mostly for convenience, we re-use the `Operand` type here.
114
121
// This is an optimization over just always having a pointer here;
@@ -117,18 +124,18 @@ 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 > LocalValue < ' tcx , Tag > {
121
128
pub fn access ( & self ) -> EvalResult < ' tcx , & Operand < Tag > > {
122
- match self {
123
- LocalValue :: Dead => err ! ( DeadLocal ) ,
124
- LocalValue :: Live ( ref val) => Ok ( val) ,
129
+ match self . state {
130
+ LocalState :: Dead => err ! ( DeadLocal ) ,
131
+ LocalState :: 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 {
130
- LocalValue :: Dead => err ! ( DeadLocal ) ,
131
- LocalValue :: Live ( ref mut val) => Ok ( val) ,
136
+ match self . state {
137
+ LocalState :: Dead => err ! ( DeadLocal ) ,
138
+ LocalState :: Live ( ref mut val) => Ok ( val) ,
132
139
}
133
140
}
134
141
}
@@ -312,7 +319,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
312
319
frame : & Frame < ' mir , ' tcx , M :: PointerTag , M :: FrameExtra > ,
313
320
local : mir:: Local
314
321
) -> EvalResult < ' tcx , TyLayout < ' tcx > > {
315
- let cell = & frame. local_layouts [ local] ;
322
+ let cell = & frame. locals [ local] . layout ;
316
323
if cell. get ( ) . is_none ( ) {
317
324
let local_ty = frame. mir . local_decls [ local] . ty ;
318
325
let local_ty = self . monomorphize_with_substs ( local_ty, frame. instance . substs ) ;
@@ -454,7 +461,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
454
461
// empty local array, we fill it in below, after we are inside the stack frame and
455
462
// all methods actually know about the frame
456
463
locals : IndexVec :: new ( ) ,
457
- local_layouts : IndexVec :: from_elem_n ( Default :: default ( ) , mir. local_decls . len ( ) ) ,
458
464
span,
459
465
instance,
460
466
stmt : 0 ,
@@ -464,14 +470,18 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
464
470
// don't allocate at all for trivial constants
465
471
if mir. local_decls . len ( ) > 1 {
466
472
// We put some marker immediate into the locals that we later want to initialize.
467
- // This can be anything except for LocalValue ::Dead -- because *that* is the
473
+ // This can be anything except for LocalState ::Dead -- because *that* is the
468
474
// value we use for things that we know are initially dead.
469
- let dummy =
470
- LocalValue :: Live ( Operand :: Immediate ( Immediate :: Scalar ( ScalarMaybeUndef :: Undef ) ) ) ;
475
+ let dummy = LocalValue {
476
+ state : LocalState :: Live ( Operand :: Immediate ( Immediate :: Scalar (
477
+ ScalarMaybeUndef :: Undef ,
478
+ ) ) ) ,
479
+ layout : Cell :: new ( None ) ,
480
+ } ;
471
481
let mut locals = IndexVec :: from_elem ( dummy, & mir. local_decls ) ;
472
482
// Return place is handled specially by the `eval_place` functions, and the
473
483
// entry in `locals` should never be used. Make it dead, to be sure.
474
- locals[ mir:: RETURN_PLACE ] = LocalValue :: Dead ;
484
+ locals[ mir:: RETURN_PLACE ] . state = LocalState :: Dead ;
475
485
// Now mark those locals as dead that we do not want to initialize
476
486
match self . tcx . describe_def ( instance. def_id ( ) ) {
477
487
// statics and constants don't have `Storage*` statements, no need to look for them
@@ -484,7 +494,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
484
494
match stmt. kind {
485
495
StorageLive ( local) |
486
496
StorageDead ( local) => {
487
- locals[ local] = LocalValue :: Dead ;
497
+ locals[ local] . state = LocalState :: Dead ;
488
498
}
489
499
_ => { }
490
500
}
@@ -494,13 +504,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
494
504
}
495
505
// Finally, properly initialize all those that still have the dummy value
496
506
for ( idx, local) in locals. iter_enumerated_mut ( ) {
497
- match * local {
498
- LocalValue :: Live ( _) => {
507
+ match local. state {
508
+ LocalState :: Live ( _) => {
499
509
// This needs to be peoperly initialized.
500
510
let layout = self . layout_of_local ( self . frame ( ) , idx) ?;
501
- * local = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
511
+ local. state = LocalState :: Live ( self . uninit_operand ( layout) ?) ;
502
512
}
503
- LocalValue :: Dead => {
513
+ LocalState :: Dead => {
504
514
// Nothing to do
505
515
}
506
516
}
@@ -543,7 +553,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
543
553
}
544
554
// Deallocate all locals that are backed by an allocation.
545
555
for local in frame. locals {
546
- self . deallocate_local ( local) ?;
556
+ self . deallocate_local ( local. state ) ?;
547
557
}
548
558
// Validate the return value. Do this after deallocating so that we catch dangling
549
559
// references.
@@ -587,31 +597,31 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
587
597
pub fn storage_live (
588
598
& mut self ,
589
599
local : mir:: Local
590
- ) -> EvalResult < ' tcx , LocalValue < M :: PointerTag > > {
600
+ ) -> EvalResult < ' tcx , LocalState < M :: PointerTag > > {
591
601
assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place live" ) ;
592
602
trace ! ( "{:?} is now live" , local) ;
593
603
594
604
let layout = self . layout_of_local ( self . frame ( ) , local) ?;
595
- let init = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
605
+ let init = LocalState :: Live ( self . uninit_operand ( layout) ?) ;
596
606
// StorageLive *always* kills the value that's currently stored
597
- Ok ( mem:: replace ( & mut self . frame_mut ( ) . locals [ local] , init) )
607
+ Ok ( mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . state , init) )
598
608
}
599
609
600
610
/// Returns the old value of the local.
601
611
/// Remember to deallocate that!
602
- pub fn storage_dead ( & mut self , local : mir:: Local ) -> LocalValue < M :: PointerTag > {
612
+ pub fn storage_dead ( & mut self , local : mir:: Local ) -> LocalState < M :: PointerTag > {
603
613
assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place dead" ) ;
604
614
trace ! ( "{:?} is now dead" , local) ;
605
615
606
- mem:: replace ( & mut self . frame_mut ( ) . locals [ local] , LocalValue :: Dead )
616
+ mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . state , LocalState :: Dead )
607
617
}
608
618
609
619
pub ( super ) fn deallocate_local (
610
620
& mut self ,
611
- local : LocalValue < M :: PointerTag > ,
621
+ local : LocalState < M :: PointerTag > ,
612
622
) -> EvalResult < ' tcx > {
613
623
// FIXME: should we tell the user that there was a local which was never written to?
614
- if let LocalValue :: Live ( Operand :: Indirect ( MemPlace { ptr, .. } ) ) = local {
624
+ if let LocalState :: Live ( Operand :: Indirect ( MemPlace { ptr, .. } ) ) = local {
615
625
trace ! ( "deallocating local" ) ;
616
626
let ptr = ptr. to_ptr ( ) ?;
617
627
self . memory . dump_alloc ( ptr. alloc_id ) ;
0 commit comments