1
1
use std:: fmt;
2
+ use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
2
3
use std:: sync:: Mutex ;
3
4
4
5
use indexmap:: IndexMap ;
@@ -82,14 +83,14 @@ struct FrameState {
82
83
stack : Vec < PyObjectRef > ,
83
84
/// Block frames, for controlling loops and exceptions
84
85
blocks : Vec < Block > ,
85
- /// index of last instruction ran
86
- lasti : usize ,
87
86
}
88
87
89
88
#[ pyclass]
90
89
pub struct Frame {
91
90
pub code : PyCodeRef ,
92
91
pub scope : Scope ,
92
+ /// index of last instruction ran
93
+ pub lasti : AtomicUsize ,
93
94
state : Mutex < FrameState > ,
94
95
}
95
96
@@ -160,10 +161,10 @@ impl Frame {
160
161
Frame {
161
162
code,
162
163
scope,
164
+ lasti : AtomicUsize :: new ( 0 ) ,
163
165
state : Mutex :: new ( FrameState {
164
166
stack : Vec :: new ( ) ,
165
167
blocks : Vec :: new ( ) ,
166
- lasti : 0 ,
167
168
} ) ,
168
169
}
169
170
}
@@ -175,6 +176,7 @@ impl FrameRef {
175
176
let exec = ExecutingFrame {
176
177
code : & self . code ,
177
178
scope : & self . scope ,
179
+ lasti : & self . lasti ,
178
180
object : & self ,
179
181
state : & mut state,
180
182
} ;
@@ -208,15 +210,15 @@ impl FrameRef {
208
210
}
209
211
210
212
pub fn current_location ( & self ) -> bytecode:: Location {
211
- self . with_exec ( |exec| exec . current_location ( ) )
213
+ self . code . locations [ self . lasti . load ( Ordering :: Relaxed ) ]
212
214
}
213
215
214
216
pub fn yield_from_target ( & self ) -> Option < PyObjectRef > {
215
217
self . with_exec ( |exec| exec. yield_from_target ( ) )
216
218
}
217
219
218
220
pub fn lasti ( & self ) -> usize {
219
- self . state . lock ( ) . unwrap ( ) . lasti
221
+ self . lasti . load ( Ordering :: Relaxed )
220
222
}
221
223
}
222
224
@@ -226,6 +228,7 @@ struct ExecutingFrame<'a> {
226
228
code : & ' a PyCodeRef ,
227
229
scope : & ' a Scope ,
228
230
object : & ' a FrameRef ,
231
+ lasti : & ' a AtomicUsize ,
229
232
state : & ' a mut FrameState ,
230
233
}
231
234
@@ -250,7 +253,7 @@ impl ExecutingFrame<'_> {
250
253
let next = exception. traceback ( ) ;
251
254
252
255
let new_traceback =
253
- PyTraceback :: new ( next, self . object . clone ( ) , self . state . lasti , loc. row ( ) ) ;
256
+ PyTraceback :: new ( next, self . object . clone ( ) , self . lasti ( ) , loc. row ( ) ) ;
254
257
exception. set_traceback ( Some ( new_traceback. into_ref ( vm) ) ) ;
255
258
vm_trace ! ( "Adding to traceback: {:?} {:?}" , new_traceback, lineno) ;
256
259
@@ -271,8 +274,7 @@ impl ExecutingFrame<'_> {
271
274
}
272
275
273
276
fn yield_from_target ( & self ) -> Option < PyObjectRef > {
274
- if let Some ( bytecode:: Instruction :: YieldFrom ) = self . code . instructions . get ( self . state . lasti )
275
- {
277
+ if let Some ( bytecode:: Instruction :: YieldFrom ) = self . code . instructions . get ( self . lasti ( ) ) {
276
278
Some ( self . last_value ( ) )
277
279
} else {
278
280
None
@@ -293,7 +295,7 @@ impl ExecutingFrame<'_> {
293
295
} ;
294
296
res. or_else ( |err| {
295
297
self . pop_value ( ) ;
296
- self . state . lasti += 1 ;
298
+ self . lasti . fetch_add ( 1 , Ordering :: Relaxed ) ;
297
299
let val = objiter:: stop_iter_value ( vm, & err) ?;
298
300
self . _send ( coro, val, vm)
299
301
} )
@@ -312,8 +314,7 @@ impl ExecutingFrame<'_> {
312
314
fn execute_instruction ( & mut self , vm : & VirtualMachine ) -> FrameResult {
313
315
vm. check_signals ( ) ?;
314
316
315
- let instruction = & self . code . instructions [ self . state . lasti ] ;
316
- self . state . lasti += 1 ;
317
+ let instruction = & self . code . instructions [ self . lasti . fetch_add ( 1 , Ordering :: Relaxed ) ] ;
317
318
318
319
flame_guard ! ( format!( "Frame::execute_instruction({:?})" , instruction) ) ;
319
320
@@ -1116,7 +1117,7 @@ impl ExecutingFrame<'_> {
1116
1117
match result {
1117
1118
ExecutionResult :: Yield ( value) => {
1118
1119
// Set back program counter:
1119
- self . state . lasti -= 1 ;
1120
+ self . lasti . fetch_sub ( 1 , Ordering :: Relaxed ) ;
1120
1121
Ok ( Some ( ExecutionResult :: Yield ( value) ) )
1121
1122
}
1122
1123
ExecutionResult :: Return ( value) => {
@@ -1166,8 +1167,8 @@ impl ExecutingFrame<'_> {
1166
1167
fn jump ( & mut self , label : bytecode:: Label ) {
1167
1168
let target_pc = self . code . label_map [ & label] ;
1168
1169
#[ cfg( feature = "vm-tracing-logging" ) ]
1169
- trace ! ( "jump from {:?} to {:?}" , self . state . lasti, target_pc) ;
1170
- self . state . lasti = target_pc;
1170
+ trace ! ( "jump from {:?} to {:?}" , self . lasti( ) , target_pc) ;
1171
+ self . lasti . store ( target_pc, Ordering :: Relaxed ) ;
1171
1172
}
1172
1173
1173
1174
/// The top of stack contains the iterator, lets push it forward
@@ -1418,8 +1419,15 @@ impl ExecutingFrame<'_> {
1418
1419
Ok ( None )
1419
1420
}
1420
1421
1422
+ fn lasti ( & self ) -> usize {
1423
+ // it's okay to make this Relaxed, because we know that we only
1424
+ // mutate lasti if the mutex is held, and any other thread that
1425
+ // wants to guarantee the value of this will use a Lock anyway
1426
+ self . lasti . load ( Ordering :: Relaxed )
1427
+ }
1428
+
1421
1429
fn current_location ( & self ) -> bytecode:: Location {
1422
- self . code . locations [ self . state . lasti ]
1430
+ self . code . locations [ self . lasti ( ) ]
1423
1431
}
1424
1432
1425
1433
fn push_block ( & mut self , typ : BlockType ) {
0 commit comments