@@ -11,12 +11,12 @@ use crate::{
11
11
coroutine:: Coro ,
12
12
exceptions:: ExceptionCtor ,
13
13
function:: { FuncArgs , IntoPyResult } ,
14
- protocol:: { PyIter , PyIterReturn } ,
14
+ protocol:: { PyIter , PyIterReturn , PyMapping } ,
15
15
scope:: Scope ,
16
16
stdlib:: builtins,
17
17
types:: PyComparisonOp ,
18
- IdProtocol , ItemProtocol , PyMethod , PyObjectRef , PyRef , PyResult , PyValue , TryFromObject ,
19
- TypeProtocol , VirtualMachine ,
18
+ IdProtocol , ItemProtocol , PyMethod , PyObjectRef , PyObjectWrap , PyRef , PyResult , PyValue ,
19
+ TryFromObject , TypeProtocol , VirtualMachine ,
20
20
} ;
21
21
use indexmap:: IndexMap ;
22
22
use itertools:: Itertools ;
@@ -99,7 +99,7 @@ pub struct Frame {
99
99
100
100
pub fastlocals : PyMutex < Box < [ Option < PyObjectRef > ] > > ,
101
101
pub ( crate ) cells_frees : Box < [ PyCellRef ] > ,
102
- pub locals : PyDictRef ,
102
+ pub locals : PyMapping ,
103
103
pub globals : PyDictRef ,
104
104
pub builtins : PyDictRef ,
105
105
@@ -179,7 +179,7 @@ impl FrameRef {
179
179
f ( exec)
180
180
}
181
181
182
- pub fn locals ( & self , vm : & VirtualMachine ) -> PyResult < PyDictRef > {
182
+ pub fn locals ( & self , vm : & VirtualMachine ) -> PyResult < PyMapping > {
183
183
let locals = & self . locals ;
184
184
let code = & * * self . code ;
185
185
let map = & code. varnames ;
@@ -188,9 +188,16 @@ impl FrameRef {
188
188
let fastlocals = self . fastlocals . lock ( ) ;
189
189
for ( k, v) in itertools:: zip ( & map[ ..j] , & * * fastlocals) {
190
190
if let Some ( v) = v {
191
- locals. set_item ( k. clone ( ) , v. clone ( ) , vm) ?;
191
+ match locals. as_object ( ) . clone ( ) . downcast_exact :: < PyDict > ( vm) {
192
+ Ok ( d) => d. set_item ( k. clone ( ) , v. clone ( ) , vm) ?,
193
+ Err ( o) => o. set_item ( k. clone ( ) , v. clone ( ) , vm) ?,
194
+ } ;
192
195
} else {
193
- match locals. del_item ( k. clone ( ) , vm) {
196
+ let res = match locals. as_object ( ) . clone ( ) . downcast_exact :: < PyDict > ( vm) {
197
+ Ok ( d) => d. del_item ( k. clone ( ) , vm) ,
198
+ Err ( o) => o. del_item ( k. clone ( ) , vm) ,
199
+ } ;
200
+ match res {
194
201
Ok ( ( ) ) => { }
195
202
Err ( e) if e. isinstance ( & vm. ctx . exceptions . key_error ) => { }
196
203
Err ( e) => return Err ( e) ,
@@ -202,9 +209,16 @@ impl FrameRef {
202
209
let map_to_dict = |keys : & [ PyStrRef ] , values : & [ PyCellRef ] | {
203
210
for ( k, v) in itertools:: zip ( keys, values) {
204
211
if let Some ( v) = v. get ( ) {
205
- locals. set_item ( k. clone ( ) , v, vm) ?;
212
+ match locals. as_object ( ) . clone ( ) . downcast_exact :: < PyDict > ( vm) {
213
+ Ok ( d) => d. set_item ( k. clone ( ) , v, vm) ?,
214
+ Err ( o) => o. set_item ( k. clone ( ) , v, vm) ?,
215
+ } ;
206
216
} else {
207
- match locals. del_item ( k. clone ( ) , vm) {
217
+ let res = match locals. as_object ( ) . clone ( ) . downcast_exact :: < PyDict > ( vm) {
218
+ Ok ( d) => d. del_item ( k. clone ( ) , vm) ,
219
+ Err ( o) => o. del_item ( k. clone ( ) , vm) ,
220
+ } ;
221
+ match res {
208
222
Ok ( ( ) ) => { }
209
223
Err ( e) if e. isinstance ( & vm. ctx . exceptions . key_error ) => { }
210
224
Err ( e) => return Err ( e) ,
@@ -275,7 +289,7 @@ struct ExecutingFrame<'a> {
275
289
code : & ' a PyRef < PyCode > ,
276
290
fastlocals : & ' a PyMutex < Box < [ Option < PyObjectRef > ] > > ,
277
291
cells_frees : & ' a [ PyCellRef ] ,
278
- locals : & ' a PyDictRef ,
292
+ locals : & ' a PyMapping ,
279
293
globals : & ' a PyDictRef ,
280
294
builtins : & ' a PyDictRef ,
281
295
object : & ' a FrameRef ,
@@ -496,12 +510,20 @@ impl ExecutingFrame<'_> {
496
510
}
497
511
bytecode:: Instruction :: LoadNameAny ( idx) => {
498
512
let name = & self . code . names [ * idx as usize ] ;
499
- let x = self . locals . get_item_option ( name. clone ( ) , vm) ?;
500
- let x = match x {
513
+ // Try using locals as dict first, if not, fallback to generic method.
514
+ let x = match self
515
+ . locals
516
+ . clone ( )
517
+ . into_object ( )
518
+ . downcast_exact :: < PyDict > ( vm)
519
+ {
520
+ Ok ( d) => d. get_item_option ( name. clone ( ) , vm) ?,
521
+ Err ( o) => o. get_item ( name. clone ( ) , vm) . ok ( ) ,
522
+ } ;
523
+ self . push_value ( match x {
501
524
Some ( x) => x,
502
525
None => self . load_global_or_builtin ( name, vm) ?,
503
- } ;
504
- self . push_value ( x) ;
526
+ } ) ;
505
527
Ok ( None )
506
528
}
507
529
bytecode:: Instruction :: LoadGlobal ( idx) => {
@@ -521,14 +543,22 @@ impl ExecutingFrame<'_> {
521
543
bytecode:: Instruction :: LoadClassDeref ( i) => {
522
544
let i = * i as usize ;
523
545
let name = self . code . freevars [ i - self . code . cellvars . len ( ) ] . clone ( ) ;
524
- let value = if let Some ( value) = self . locals . get_item_option ( name, vm) ? {
525
- value
526
- } else {
527
- self . cells_frees [ i]
528
- . get ( )
529
- . ok_or_else ( || self . unbound_cell_exception ( i, vm) ) ?
546
+ // Try using locals as dict first, if not, fallback to generic method.
547
+ let value = match self
548
+ . locals
549
+ . clone ( )
550
+ . into_object ( )
551
+ . downcast_exact :: < PyDict > ( vm)
552
+ {
553
+ Ok ( d) => d. get_item_option ( name, vm) ?,
554
+ Err ( o) => o. get_item ( name, vm) . ok ( ) ,
530
555
} ;
531
- self . push_value ( value) ;
556
+ self . push_value ( match value {
557
+ Some ( v) => v,
558
+ None => self . cells_frees [ i]
559
+ . get ( )
560
+ . ok_or_else ( || self . unbound_cell_exception ( i, vm) ) ?,
561
+ } ) ;
532
562
Ok ( None )
533
563
}
534
564
bytecode:: Instruction :: StoreFast ( idx) => {
@@ -538,8 +568,15 @@ impl ExecutingFrame<'_> {
538
568
}
539
569
bytecode:: Instruction :: StoreLocal ( idx) => {
540
570
let value = self . pop_value ( ) ;
541
- self . locals
542
- . set_item ( self . code . names [ * idx as usize ] . clone ( ) , value, vm) ?;
571
+ match self
572
+ . locals
573
+ . clone ( )
574
+ . into_object ( )
575
+ . downcast_exact :: < PyDict > ( vm)
576
+ {
577
+ Ok ( d) => d. set_item ( self . code . names [ * idx as usize ] . clone ( ) , value, vm) ?,
578
+ Err ( o) => o. set_item ( self . code . names [ * idx as usize ] . clone ( ) , value, vm) ?,
579
+ } ;
543
580
Ok ( None )
544
581
}
545
582
bytecode:: Instruction :: StoreGlobal ( idx) => {
@@ -559,7 +596,17 @@ impl ExecutingFrame<'_> {
559
596
}
560
597
bytecode:: Instruction :: DeleteLocal ( idx) => {
561
598
let name = & self . code . names [ * idx as usize ] ;
562
- match self . locals . del_item ( name. clone ( ) , vm) {
599
+ let res = match self
600
+ . locals
601
+ . clone ( )
602
+ . into_object ( )
603
+ . downcast_exact :: < PyDict > ( vm)
604
+ {
605
+ Ok ( d) => d. del_item ( name. clone ( ) , vm) ,
606
+ Err ( o) => o. del_item ( name. clone ( ) , vm) ,
607
+ } ;
608
+
609
+ match res {
563
610
Ok ( ( ) ) => { }
564
611
Err ( e) if e. isinstance ( & vm. ctx . exceptions . key_error ) => {
565
612
return Err ( vm. new_name_error ( format ! ( "name '{}' is not defined" , name) ) )
@@ -717,9 +764,25 @@ impl ExecutingFrame<'_> {
717
764
}
718
765
bytecode:: Instruction :: YieldFrom => self . execute_yield_from ( vm) ,
719
766
bytecode:: Instruction :: SetupAnnotation => {
720
- if !self . locals . contains_key ( "__annotations__" , vm) {
721
- self . locals
722
- . set_item ( "__annotations__" , vm. ctx . new_dict ( ) . into ( ) , vm) ?;
767
+ // Try using locals as dict first, if not, fallback to generic method.
768
+ let has_annotations = match self
769
+ . locals
770
+ . clone ( )
771
+ . into_object ( )
772
+ . downcast_exact :: < PyDict > ( vm)
773
+ {
774
+ Ok ( d) => d. contains_key ( "__annotations__" , vm) ,
775
+ Err ( o) => {
776
+ let needle = vm. new_pyobj ( "__annotations__" ) ;
777
+ self . _in ( vm, needle, o) ?
778
+ }
779
+ } ;
780
+ if !has_annotations {
781
+ self . locals . as_object ( ) . set_item (
782
+ "__annotations__" ,
783
+ vm. ctx . new_dict ( ) . into ( ) ,
784
+ vm,
785
+ ) ?;
723
786
}
724
787
Ok ( None )
725
788
}
@@ -1132,7 +1195,15 @@ impl ExecutingFrame<'_> {
1132
1195
for ( k, v) in & dict {
1133
1196
let k = PyStrRef :: try_from_object ( vm, k) ?;
1134
1197
if filter_pred ( k. as_str ( ) ) {
1135
- self . locals . set_item ( k, v, vm) ?;
1198
+ match self
1199
+ . locals
1200
+ . clone ( )
1201
+ . into_object ( )
1202
+ . downcast_exact :: < PyDict > ( vm)
1203
+ {
1204
+ Ok ( d) => d. set_item ( k, v, vm) ?,
1205
+ Err ( o) => o. set_item ( k, v, vm) ?,
1206
+ } ;
1136
1207
}
1137
1208
}
1138
1209
}
@@ -1822,15 +1893,11 @@ impl fmt::Debug for Frame {
1822
1893
. map ( |elem| format ! ( "\n > {:?}" , elem) )
1823
1894
. collect :: < String > ( ) ;
1824
1895
// TODO: fix this up
1825
- let dict = self . locals . clone ( ) ;
1826
- let local_str = dict
1827
- . into_iter ( )
1828
- . map ( |elem| format ! ( "\n {:?} = {:?}" , elem. 0 , elem. 1 ) )
1829
- . collect :: < String > ( ) ;
1896
+ let locals = self . locals . clone ( ) ;
1830
1897
write ! (
1831
1898
f,
1832
- "Frame Object {{ \n Stack:{}\n Blocks:{}\n Locals:{}\n }}" ,
1833
- stack_str, block_str, local_str
1899
+ "Frame Object {{ \n Stack:{}\n Blocks:{}\n Locals:{:? }\n }}" ,
1900
+ stack_str, block_str, locals
1834
1901
)
1835
1902
}
1836
1903
}
0 commit comments