@@ -4,7 +4,6 @@ use super::{
4
4
TerminatorTarget ,
5
5
ConstantId ,
6
6
GlobalEvalContext ,
7
- Frame ,
8
7
} ;
9
8
use error:: EvalResult ;
10
9
use rustc:: mir:: repr as mir;
@@ -13,6 +12,7 @@ use rustc::hir::def_id::DefId;
13
12
use rustc:: mir:: visit:: { Visitor , LvalueContext } ;
14
13
use syntax:: codemap:: Span ;
15
14
use std:: rc:: Rc ;
15
+ use memory:: Pointer ;
16
16
17
17
pub enum Event {
18
18
Constant ,
@@ -24,13 +24,18 @@ pub enum Event {
24
24
pub struct Stepper < ' fncx , ' a : ' fncx , ' b : ' a + ' mir , ' mir : ' fncx , ' tcx : ' b > {
25
25
fncx : & ' fncx mut FnEvalContext < ' a , ' b , ' mir , ' tcx > ,
26
26
process : fn ( & mut Stepper < ' fncx , ' a , ' b , ' mir , ' tcx > ) -> EvalResult < ( ) > ,
27
+
28
+ // a cache of the constants to be computed before the next statement/terminator
29
+ // this is an optimization, so we don't have to allocate a new vector for every statement
30
+ constants : Vec < ( ConstantId < ' tcx > , Span , Pointer , CachedMir < ' mir , ' tcx > ) > ,
27
31
}
28
32
29
33
impl < ' fncx , ' a , ' b : ' a + ' mir , ' mir , ' tcx : ' b > Stepper < ' fncx , ' a , ' b , ' mir , ' tcx > {
30
34
pub ( super ) fn new ( fncx : & ' fncx mut FnEvalContext < ' a , ' b , ' mir , ' tcx > ) -> Self {
31
35
Stepper {
32
36
fncx : fncx,
33
37
process : Self :: dummy,
38
+ constants : Vec :: new ( ) ,
34
39
}
35
40
}
36
41
@@ -60,22 +65,13 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx
60
65
match term {
61
66
TerminatorTarget :: Block => { } ,
62
67
TerminatorTarget :: Return => {
63
- assert ! ( self . fncx. frame( ) . constants. is_empty( ) ) ;
64
68
self . fncx . pop_stack_frame ( ) ;
65
69
} ,
66
70
TerminatorTarget :: Call => { } ,
67
71
}
68
72
Ok ( ( ) )
69
73
}
70
74
71
- fn constant ( & mut self ) -> EvalResult < ( ) > {
72
- let ( cid, span, return_ptr, mir) = self . fncx . frame_mut ( ) . constants . pop ( ) . expect ( "state machine broken" ) ;
73
- let def_id = cid. def_id ( ) ;
74
- let substs = cid. substs ( ) ;
75
- self . fncx . push_stack_frame ( def_id, span, mir, substs, Some ( return_ptr) ) ;
76
- Ok ( ( ) )
77
- }
78
-
79
75
pub fn step ( & mut self ) -> EvalResult < Event > {
80
76
( self . process ) ( self ) ?;
81
77
@@ -85,48 +81,60 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx
85
81
return Ok ( Event :: Done ) ;
86
82
}
87
83
88
- if !self . fncx . frame ( ) . constants . is_empty ( ) {
89
- self . process = Self :: constant;
90
- return Ok ( Event :: Constant ) ;
91
- }
92
-
93
84
let block = self . fncx . frame ( ) . next_block ;
94
85
let stmt = self . fncx . frame ( ) . stmt ;
95
86
let mir = self . fncx . mir ( ) ;
96
87
let basic_block = mir. basic_block_data ( block) ;
97
88
98
89
if let Some ( ref stmt) = basic_block. statements . get ( stmt) {
99
- assert ! ( self . fncx . frame ( ) . constants. is_empty( ) ) ;
90
+ assert ! ( self . constants. is_empty( ) ) ;
100
91
ConstantExtractor {
101
92
span : stmt. span ,
93
+ substs : self . fncx . substs ( ) ,
94
+ def_id : self . fncx . frame ( ) . def_id ,
102
95
gecx : self . fncx . gecx ,
103
- frame : self . fncx . stack . last_mut ( ) . expect ( "stack empty" ) ,
96
+ constants : & mut self . constants ,
97
+ mir : & mir,
104
98
} . visit_statement ( block, stmt) ;
105
- if self . fncx . frame ( ) . constants . is_empty ( ) {
99
+ if self . constants . is_empty ( ) {
106
100
self . process = Self :: statement;
107
101
return Ok ( Event :: Assignment ) ;
108
102
} else {
109
- self . process = Self :: constant;
103
+ self . process = Self :: statement;
104
+ self . extract_constants ( ) ;
110
105
return Ok ( Event :: Constant ) ;
111
106
}
112
107
}
113
108
114
109
let terminator = basic_block. terminator ( ) ;
115
- assert ! ( self . fncx . frame ( ) . constants. is_empty( ) ) ;
110
+ assert ! ( self . constants. is_empty( ) ) ;
116
111
ConstantExtractor {
117
112
span : terminator. span ,
113
+ substs : self . fncx . substs ( ) ,
114
+ def_id : self . fncx . frame ( ) . def_id ,
118
115
gecx : self . fncx . gecx ,
119
- frame : self . fncx . stack . last_mut ( ) . expect ( "stack empty" ) ,
116
+ constants : & mut self . constants ,
117
+ mir : & mir,
120
118
} . visit_terminator ( block, terminator) ;
121
- if self . fncx . frame ( ) . constants . is_empty ( ) {
119
+ if self . constants . is_empty ( ) {
122
120
self . process = Self :: terminator;
123
121
Ok ( Event :: Terminator )
124
122
} else {
125
- self . process = Self :: constant;
123
+ self . process = Self :: statement;
124
+ self . extract_constants ( ) ;
126
125
Ok ( Event :: Constant )
127
126
}
128
127
}
129
128
129
+ fn extract_constants ( & mut self ) {
130
+ assert ! ( !self . constants. is_empty( ) ) ;
131
+ for ( cid, span, return_ptr, mir) in self . constants . drain ( ..) {
132
+ let def_id = cid. def_id ( ) ;
133
+ let substs = cid. substs ( ) ;
134
+ self . fncx . push_stack_frame ( def_id, span, mir, substs, Some ( return_ptr) ) ;
135
+ }
136
+ }
137
+
130
138
/// returns the statement that will be processed next
131
139
pub fn stmt ( & self ) -> & mir:: Statement {
132
140
& self . fncx . basic_block ( ) . statements [ self . fncx . frame ( ) . stmt ]
@@ -144,8 +152,11 @@ impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx
144
152
145
153
struct ConstantExtractor < ' a , ' b : ' mir , ' mir : ' a , ' tcx : ' b > {
146
154
span : Span ,
147
- frame : & ' a mut Frame < ' mir , ' tcx > ,
155
+ constants : & ' a mut Vec < ( ConstantId < ' tcx > , Span , Pointer , CachedMir < ' mir , ' tcx > ) > ,
148
156
gecx : & ' a mut GlobalEvalContext < ' b , ' tcx > ,
157
+ mir : & ' a mir:: Mir < ' tcx > ,
158
+ def_id : DefId ,
159
+ substs : & ' tcx subst:: Substs < ' tcx > ,
149
160
}
150
161
151
162
impl < ' a , ' b , ' mir , ' tcx > ConstantExtractor < ' a , ' b , ' mir , ' tcx > {
@@ -160,7 +171,7 @@ impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> {
160
171
let mir = self . gecx . load_mir ( def_id) ;
161
172
let ptr = self . gecx . alloc_ret_ptr ( mir. return_ty , substs) . expect ( "there's no such thing as an unreachable static" ) ;
162
173
self . gecx . statics . insert ( cid. clone ( ) , ptr) ;
163
- self . frame . constants . push ( ( cid, span, ptr, mir) ) ;
174
+ self . constants . push ( ( cid, span, ptr, mir) ) ;
164
175
}
165
176
}
166
177
@@ -180,19 +191,19 @@ impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx>
180
191
} ,
181
192
mir:: Literal :: Promoted { index } => {
182
193
let cid = ConstantId :: Promoted {
183
- def_id : self . frame . def_id ,
184
- substs : self . frame . substs ,
194
+ def_id : self . def_id ,
195
+ substs : self . substs ,
185
196
index : index,
186
197
} ;
187
198
if self . gecx . statics . contains_key ( & cid) {
188
199
return ;
189
200
}
190
- let mir = self . frame . mir . promoted [ index] . clone ( ) ;
201
+ let mir = self . mir . promoted [ index] . clone ( ) ;
191
202
let return_ty = mir. return_ty ;
192
203
let return_ptr = self . gecx . alloc_ret_ptr ( return_ty, cid. substs ( ) ) . expect ( "there's no such thing as an unreachable static" ) ;
193
204
let mir = CachedMir :: Owned ( Rc :: new ( mir) ) ;
194
205
self . gecx . statics . insert ( cid. clone ( ) , return_ptr) ;
195
- self . frame . constants . push ( ( cid, constant. span , return_ptr, mir) ) ;
206
+ self . constants . push ( ( cid, constant. span , return_ptr, mir) ) ;
196
207
}
197
208
}
198
209
}
0 commit comments