1
- use std:: collections:: HashSet ;
2
1
use std:: fmt:: Write ;
3
2
4
3
use rustc:: hir:: def_id:: DefId ;
4
+ use rustc:: hir:: def:: Def ;
5
5
use rustc:: hir:: map:: definitions:: DefPathData ;
6
6
use rustc:: middle:: const_val:: { ConstVal , ErrKind } ;
7
7
use rustc:: mir;
8
8
use rustc:: ty:: layout:: { self , Size , Align , HasDataLayout , LayoutOf , TyLayout } ;
9
9
use rustc:: ty:: subst:: { Subst , Substs } ;
10
10
use rustc:: ty:: { self , Ty , TyCtxt } ;
11
11
use rustc:: ty:: maps:: TyCtxtAt ;
12
- use rustc_data_structures:: indexed_vec:: Idx ;
12
+ use rustc_data_structures:: indexed_vec:: { IndexVec , Idx } ;
13
13
use rustc:: middle:: const_val:: FrameInfo ;
14
14
use syntax:: codemap:: { self , Span } ;
15
15
use syntax:: ast:: Mutability ;
16
16
use rustc:: mir:: interpret:: {
17
17
GlobalId , Value , Pointer , PrimVal , PrimValKind ,
18
18
EvalError , EvalResult , EvalErrorKind , MemoryPointer ,
19
19
} ;
20
+ use std:: mem;
20
21
21
22
use super :: { Place , PlaceExtra , Memory ,
22
23
HasMemory , MemoryKind ,
@@ -71,12 +72,12 @@ pub struct Frame<'mir, 'tcx: 'mir> {
71
72
pub return_place : Place ,
72
73
73
74
/// The list of locals for this stack frame, stored in order as
74
- /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
75
+ /// `[return_ptr, arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
75
76
/// `None` represents a local that is currently dead, while a live local
76
77
/// can either directly contain `PrimVal` or refer to some part of an `Allocation`.
77
78
///
78
79
/// Before being initialized, arguments are `Value::ByVal(PrimVal::Undef)` and other locals are `None`.
79
- pub locals : Vec < Option < Value > > ,
80
+ pub locals : IndexVec < mir :: Local , Option < Value > > ,
80
81
81
82
////////////////////////////////////////////////////////////////////////////////
82
83
// Current position within the function
@@ -383,39 +384,29 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
383
384
) -> EvalResult < ' tcx > {
384
385
:: log_settings:: settings ( ) . indentation += 1 ;
385
386
386
- /// Return the set of locals that have a storage annotation anywhere
387
- fn collect_storage_annotations < ' mir , ' tcx > ( mir : & ' mir mir:: Mir < ' tcx > ) -> HashSet < mir:: Local > {
388
- use rustc:: mir:: StatementKind :: * ;
389
-
390
- let mut set = HashSet :: new ( ) ;
391
- for block in mir. basic_blocks ( ) {
392
- for stmt in block. statements . iter ( ) {
393
- match stmt. kind {
394
- StorageLive ( local) |
395
- StorageDead ( local) => {
396
- set. insert ( local) ;
387
+ let locals = if mir. local_decls . len ( ) > 1 {
388
+ let mut locals = IndexVec :: from_elem ( Some ( Value :: ByVal ( PrimVal :: Undef ) ) , & mir. local_decls ) ;
389
+ match self . tcx . describe_def ( instance. def_id ( ) ) {
390
+ // statics and constants don't have `Storage*` statements, no need to look for them
391
+ Some ( Def :: Static ( ..) ) | Some ( Def :: Const ( ..) ) | Some ( Def :: AssociatedConst ( ..) ) => { } ,
392
+ _ => {
393
+ trace ! ( "push_stack_frame: {:?}: num_bbs: {}" , span, mir. basic_blocks( ) . len( ) ) ;
394
+ for block in mir. basic_blocks ( ) {
395
+ for stmt in block. statements . iter ( ) {
396
+ use rustc:: mir:: StatementKind :: { StorageDead , StorageLive } ;
397
+ match stmt. kind {
398
+ StorageLive ( local) |
399
+ StorageDead ( local) => locals[ local] = None ,
400
+ _ => { }
401
+ }
397
402
}
398
- _ => { }
399
403
}
400
- }
401
- }
402
- set
403
- }
404
-
405
- // Subtract 1 because `local_decls` includes the ReturnMemoryPointer, but we don't store a local
406
- // `Value` for that.
407
- let num_locals = mir. local_decls . len ( ) - 1 ;
408
-
409
- let locals = {
410
- let annotated_locals = collect_storage_annotations ( mir) ;
411
- let mut locals = vec ! [ None ; num_locals] ;
412
- for i in 0 ..num_locals {
413
- let local = mir:: Local :: new ( i + 1 ) ;
414
- if !annotated_locals. contains ( & local) {
415
- locals[ i] = Some ( Value :: ByVal ( PrimVal :: Undef ) ) ;
416
- }
404
+ } ,
417
405
}
418
406
locals
407
+ } else {
408
+ // don't allocate at all for trivial constants
409
+ IndexVec :: new ( )
419
410
} ;
420
411
421
412
self . stack . push ( Frame {
@@ -973,8 +964,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
973
964
pub fn force_allocation ( & mut self , place : Place ) -> EvalResult < ' tcx , Place > {
974
965
let new_place = match place {
975
966
Place :: Local { frame, local } => {
976
- // -1 since we don't store the return value
977
- match self . stack [ frame] . locals [ local. index ( ) - 1 ] {
967
+ match self . stack [ frame] . locals [ local] {
978
968
None => return err ! ( DeadLocal ) ,
979
969
Some ( Value :: ByRef ( ptr, align) ) => {
980
970
Place :: Ptr {
@@ -988,7 +978,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
988
978
let ty = self . monomorphize ( ty, self . stack [ frame] . instance . substs ) ;
989
979
let layout = self . layout_of ( ty) ?;
990
980
let ptr = self . alloc_ptr ( ty) ?;
991
- self . stack [ frame] . locals [ local. index ( ) - 1 ] =
981
+ self . stack [ frame] . locals [ local] =
992
982
Some ( Value :: ByRef ( ptr. into ( ) , layout. align ) ) ; // it stays live
993
983
let place = Place :: from_ptr ( ptr, layout. align ) ;
994
984
self . write_value ( ValTy { value : val, ty } , place) ?;
@@ -1702,13 +1692,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
1702
1692
1703
1693
impl < ' mir , ' tcx > Frame < ' mir , ' tcx > {
1704
1694
pub fn get_local ( & self , local : mir:: Local ) -> EvalResult < ' tcx , Value > {
1705
- // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1706
- self . locals [ local. index ( ) - 1 ] . ok_or ( EvalErrorKind :: DeadLocal . into ( ) )
1695
+ self . locals [ local] . ok_or ( EvalErrorKind :: DeadLocal . into ( ) )
1707
1696
}
1708
1697
1709
1698
fn set_local ( & mut self , local : mir:: Local , value : Value ) -> EvalResult < ' tcx > {
1710
- // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1711
- match self . locals [ local. index ( ) - 1 ] {
1699
+ match self . locals [ local] {
1712
1700
None => err ! ( DeadLocal ) ,
1713
1701
Some ( ref mut local) => {
1714
1702
* local = value;
@@ -1717,20 +1705,17 @@ impl<'mir, 'tcx> Frame<'mir, 'tcx> {
1717
1705
}
1718
1706
}
1719
1707
1720
- pub fn storage_live ( & mut self , local : mir:: Local ) -> EvalResult < ' tcx , Option < Value > > {
1708
+ pub fn storage_live ( & mut self , local : mir:: Local ) -> Option < Value > {
1721
1709
trace ! ( "{:?} is now live" , local) ;
1722
1710
1723
- let old = self . locals [ local. index ( ) - 1 ] ;
1724
- self . locals [ local. index ( ) - 1 ] = Some ( Value :: ByVal ( PrimVal :: Undef ) ) ; // StorageLive *always* kills the value that's currently stored
1725
- return Ok ( old) ;
1711
+ // StorageLive *always* kills the value that's currently stored
1712
+ mem:: replace ( & mut self . locals [ local] , Some ( Value :: ByVal ( PrimVal :: Undef ) ) )
1726
1713
}
1727
1714
1728
1715
/// Returns the old value of the local
1729
- pub fn storage_dead ( & mut self , local : mir:: Local ) -> EvalResult < ' tcx , Option < Value > > {
1716
+ pub fn storage_dead ( & mut self , local : mir:: Local ) -> Option < Value > {
1730
1717
trace ! ( "{:?} is now dead" , local) ;
1731
1718
1732
- let old = self . locals [ local. index ( ) - 1 ] ;
1733
- self . locals [ local. index ( ) - 1 ] = None ;
1734
- return Ok ( old) ;
1719
+ self . locals [ local] . take ( )
1735
1720
}
1736
1721
}
0 commit comments