@@ -77,9 +77,6 @@ enum UnwindReason {
77
77
}
78
78
79
79
struct FrameState {
80
- code : PyCodeRef ,
81
- /// Variables
82
- scope : Scope ,
83
80
// We need 1 stack per frame
84
81
/// The main data frame of the stack machine
85
82
stack : Vec < PyObjectRef > ,
@@ -161,65 +158,79 @@ impl Frame {
161
158
// locals.extend(callargs);
162
159
163
160
Frame {
164
- // we have 2 references to the same code object (and scope) so that we don't have to
165
- // a) lock the state to get the code, which is immutable anyway
166
- // b) pass around a bunch of reference to code inside of the FrameState methods
167
- code : code. clone ( ) ,
168
- scope : scope. clone ( ) ,
161
+ code,
162
+ scope,
169
163
state : Mutex :: new ( FrameState {
170
- code,
171
- scope,
172
164
stack : Vec :: new ( ) ,
173
165
blocks : Vec :: new ( ) ,
174
166
lasti : 0 ,
175
167
} ) ,
176
168
}
177
169
}
170
+ }
171
+
172
+ impl FrameRef {
173
+ fn with_exec < R > ( & self , f : impl FnOnce ( ExecutingFrame ) -> R ) -> R {
174
+ let mut state = self . state . lock ( ) . unwrap ( ) ;
175
+ let exec = ExecutingFrame {
176
+ code : & self . code ,
177
+ scope : & self . scope ,
178
+ object : & self ,
179
+ state : & mut state,
180
+ } ;
181
+ f ( exec)
182
+ }
178
183
179
184
// #[cfg_attr(feature = "flame-it", flame("Frame"))]
180
- pub fn run ( zelf : PyRef < Self > , vm : & VirtualMachine ) -> PyResult < ExecutionResult > {
181
- zelf . state . lock ( ) . unwrap ( ) . run ( & zelf , vm )
185
+ pub fn run ( & self , vm : & VirtualMachine ) -> PyResult < ExecutionResult > {
186
+ self . with_exec ( | mut exec| exec . run ( vm ) )
182
187
}
183
188
184
189
pub ( crate ) fn resume (
185
- zelf : PyRef < Self > ,
190
+ & self ,
186
191
value : PyObjectRef ,
187
192
vm : & VirtualMachine ,
188
193
) -> PyResult < ExecutionResult > {
189
- let mut state = zelf. state . lock ( ) . unwrap ( ) ;
190
- state. push_value ( value) ;
191
- state. run ( & zelf, vm)
194
+ self . with_exec ( |mut exec| {
195
+ exec. push_value ( value) ;
196
+ exec. run ( vm)
197
+ } )
192
198
}
193
199
194
200
pub ( crate ) fn gen_throw (
195
- zelf : PyRef < Self > ,
201
+ & self ,
196
202
vm : & VirtualMachine ,
197
203
exc_type : PyObjectRef ,
198
204
exc_val : PyObjectRef ,
199
205
exc_tb : PyObjectRef ,
200
206
) -> PyResult < ExecutionResult > {
201
- zelf. state
202
- . lock ( )
203
- . unwrap ( )
204
- . gen_throw ( & zelf, vm, exc_type, exc_val, exc_tb)
207
+ self . with_exec ( |mut exec| exec. gen_throw ( vm, exc_type, exc_val, exc_tb) )
205
208
}
206
209
207
210
pub fn current_location ( & self ) -> bytecode:: Location {
208
- let state = self . state . lock ( ) . unwrap ( ) ;
209
- state. current_location ( )
211
+ self . with_exec ( |exec| exec. current_location ( ) )
210
212
}
211
213
212
214
pub fn yield_from_target ( & self ) -> Option < PyObjectRef > {
213
- self . state . lock ( ) . unwrap ( ) . yield_from_target ( )
215
+ self . with_exec ( |exec| exec . yield_from_target ( ) )
214
216
}
215
217
216
218
pub fn lasti ( & self ) -> usize {
217
219
self . state . lock ( ) . unwrap ( ) . lasti
218
220
}
219
221
}
220
222
221
- impl FrameState {
222
- fn run ( & mut self , frameref : & FrameRef , vm : & VirtualMachine ) -> PyResult < ExecutionResult > {
223
+ /// An executing frame; essentially just a struct to combine the immutable data outside the mutex
224
+ /// with the mutable data inside
225
+ struct ExecutingFrame < ' a > {
226
+ code : & ' a PyCodeRef ,
227
+ scope : & ' a Scope ,
228
+ object : & ' a FrameRef ,
229
+ state : & ' a mut FrameState ,
230
+ }
231
+
232
+ impl ExecutingFrame < ' _ > {
233
+ fn run ( & mut self , vm : & VirtualMachine ) -> PyResult < ExecutionResult > {
223
234
flame_guard ! ( format!( "Frame::run({})" , self . code. obj_name) ) ;
224
235
// Execute until return or exception:
225
236
loop {
@@ -239,7 +250,7 @@ impl FrameState {
239
250
let next = exception. traceback ( ) ;
240
251
241
252
let new_traceback =
242
- PyTraceback :: new ( next, frameref . clone ( ) , self . lasti , loc. row ( ) ) ;
253
+ PyTraceback :: new ( next, self . object . clone ( ) , self . state . lasti , loc. row ( ) ) ;
243
254
exception. set_traceback ( Some ( new_traceback. into_ref ( vm) ) ) ;
244
255
vm_trace ! ( "Adding to traceback: {:?} {:?}" , new_traceback, lineno) ;
245
256
@@ -260,7 +271,8 @@ impl FrameState {
260
271
}
261
272
262
273
fn yield_from_target ( & self ) -> Option < PyObjectRef > {
263
- if let Some ( bytecode:: Instruction :: YieldFrom ) = self . code . instructions . get ( self . lasti ) {
274
+ if let Some ( bytecode:: Instruction :: YieldFrom ) = self . code . instructions . get ( self . state . lasti )
275
+ {
264
276
Some ( self . last_value ( ) )
265
277
} else {
266
278
None
@@ -269,7 +281,6 @@ impl FrameState {
269
281
270
282
fn gen_throw (
271
283
& mut self ,
272
- frameref : & FrameRef ,
273
284
vm : & VirtualMachine ,
274
285
exc_type : PyObjectRef ,
275
286
exc_val : PyObjectRef ,
@@ -282,15 +293,15 @@ impl FrameState {
282
293
} ;
283
294
res. or_else ( |err| {
284
295
self . pop_value ( ) ;
285
- self . lasti += 1 ;
296
+ self . state . lasti += 1 ;
286
297
let val = objiter:: stop_iter_value ( vm, & err) ?;
287
298
self . _send ( coro, val, vm)
288
299
} )
289
300
. map ( ExecutionResult :: Yield )
290
301
} else {
291
302
let exception = exceptions:: normalize ( exc_type, exc_val, exc_tb, vm) ?;
292
303
match self . unwind_blocks ( vm, UnwindReason :: Raising { exception } ) {
293
- Ok ( None ) => self . run ( frameref , vm) ,
304
+ Ok ( None ) => self . run ( vm) ,
294
305
Ok ( Some ( result) ) => Ok ( result) ,
295
306
Err ( exception) => Err ( exception) ,
296
307
}
@@ -301,11 +312,8 @@ impl FrameState {
301
312
fn execute_instruction ( & mut self , vm : & VirtualMachine ) -> FrameResult {
302
313
vm. check_signals ( ) ?;
303
314
304
- // we get a separate code reference because we know that code isn't mutable, but borrowck will still
305
- // complain that we borrow immutable here and mutably later
306
- let co = self . code . clone ( ) ;
307
- let instruction = & co. instructions [ self . lasti ] ;
308
- self . lasti += 1 ;
315
+ let instruction = & self . code . instructions [ self . state . lasti ] ;
316
+ self . state . lasti += 1 ;
309
317
310
318
flame_guard ! ( format!( "Frame::execute_instruction({:?})" , instruction) ) ;
311
319
@@ -689,8 +697,8 @@ impl FrameState {
689
697
}
690
698
}
691
699
bytecode:: Instruction :: Reverse { amount } => {
692
- let stack_len = self . stack . len ( ) ;
693
- self . stack [ stack_len - amount..stack_len] . reverse ( ) ;
700
+ let stack_len = self . state . stack . len ( ) ;
701
+ self . state . stack [ stack_len - amount..stack_len] . reverse ( ) ;
694
702
Ok ( None )
695
703
}
696
704
}
@@ -1108,7 +1116,7 @@ impl FrameState {
1108
1116
match result {
1109
1117
ExecutionResult :: Yield ( value) => {
1110
1118
// Set back program counter:
1111
- self . lasti -= 1 ;
1119
+ self . state . lasti -= 1 ;
1112
1120
Ok ( Some ( ExecutionResult :: Yield ( value) ) )
1113
1121
}
1114
1122
ExecutionResult :: Return ( value) => {
@@ -1158,8 +1166,8 @@ impl FrameState {
1158
1166
fn jump ( & mut self , label : bytecode:: Label ) {
1159
1167
let target_pc = self . code . label_map [ & label] ;
1160
1168
#[ cfg( feature = "vm-tracing-logging" ) ]
1161
- trace ! ( "jump from {:?} to {:?}" , self . lasti, target_pc) ;
1162
- self . lasti = target_pc;
1169
+ trace ! ( "jump from {:?} to {:?}" , self . state . lasti, target_pc) ;
1170
+ self . state . lasti = target_pc;
1163
1171
}
1164
1172
1165
1173
/// The top of stack contains the iterator, lets push it forward
@@ -1411,47 +1419,51 @@ impl FrameState {
1411
1419
}
1412
1420
1413
1421
fn current_location ( & self ) -> bytecode:: Location {
1414
- self . code . locations [ self . lasti ]
1422
+ self . code . locations [ self . state . lasti ]
1415
1423
}
1416
1424
1417
1425
fn push_block ( & mut self , typ : BlockType ) {
1418
- self . blocks . push ( Block {
1426
+ self . state . blocks . push ( Block {
1419
1427
typ,
1420
- level : self . stack . len ( ) ,
1428
+ level : self . state . stack . len ( ) ,
1421
1429
} ) ;
1422
1430
}
1423
1431
1424
1432
fn pop_block ( & mut self ) -> Block {
1425
- let block = self . blocks . pop ( ) . expect ( "No more blocks to pop!" ) ;
1426
- self . stack . truncate ( block. level ) ;
1433
+ let block = self . state . blocks . pop ( ) . expect ( "No more blocks to pop!" ) ;
1434
+ self . state . stack . truncate ( block. level ) ;
1427
1435
block
1428
1436
}
1429
1437
1430
1438
fn current_block ( & self ) -> Option < Block > {
1431
- self . blocks . last ( ) . cloned ( )
1439
+ self . state . blocks . last ( ) . cloned ( )
1432
1440
}
1433
1441
1434
1442
fn push_value ( & mut self , obj : PyObjectRef ) {
1435
- self . stack . push ( obj) ;
1443
+ self . state . stack . push ( obj) ;
1436
1444
}
1437
1445
1438
1446
fn pop_value ( & mut self ) -> PyObjectRef {
1439
- self . stack
1447
+ self . state
1448
+ . stack
1440
1449
. pop ( )
1441
1450
. expect ( "Tried to pop value but there was nothing on the stack" )
1442
1451
}
1443
1452
1444
1453
fn pop_multiple ( & mut self , count : usize ) -> Vec < PyObjectRef > {
1445
- let stack_len = self . stack . len ( ) ;
1446
- self . stack . drain ( stack_len - count..stack_len) . collect ( )
1454
+ let stack_len = self . state . stack . len ( ) ;
1455
+ self . state
1456
+ . stack
1457
+ . drain ( stack_len - count..stack_len)
1458
+ . collect ( )
1447
1459
}
1448
1460
1449
1461
fn last_value ( & self ) -> PyObjectRef {
1450
- self . stack . last ( ) . unwrap ( ) . clone ( )
1462
+ self . state . stack . last ( ) . unwrap ( ) . clone ( )
1451
1463
}
1452
1464
1453
1465
fn nth_value ( & self , depth : usize ) -> PyObjectRef {
1454
- self . stack [ self . stack . len ( ) - depth - 1 ] . clone ( )
1466
+ self . state . stack [ self . state . stack . len ( ) - depth - 1 ] . clone ( )
1455
1467
}
1456
1468
}
1457
1469
@@ -1477,7 +1489,7 @@ impl fmt::Debug for Frame {
1477
1489
. iter ( )
1478
1490
. map ( |elem| format ! ( "\n > {:?}" , elem) )
1479
1491
. collect :: < String > ( ) ;
1480
- let dict = state . scope . get_locals ( ) ;
1492
+ let dict = self . scope . get_locals ( ) ;
1481
1493
let local_str = dict
1482
1494
. into_iter ( )
1483
1495
. map ( |elem| format ! ( "\n {:?} = {:?}" , elem. 0 , elem. 1 ) )
0 commit comments