1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
|
""" PyFrame class implementation with the interpreter main loop.
"""
import sys
from rpython.rlib import jit
from rpython.rlib.debug import make_sure_not_resized, check_nonneg
from rpython.rlib.debug import ll_assert_not_none
from rpython.rlib.jit import hint
from rpython.rlib.objectmodel import instantiate, specialize, we_are_translated
from rpython.rlib.objectmodel import not_rpython
from rpython.rlib.rarithmetic import intmask, r_uint
from rpython.tool.pairtype import extendabletype
from pypy.interpreter import pycode, pytraceback
from pypy.interpreter.argument import Arguments
from pypy.interpreter.astcompiler import consts
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import (
OperationError, get_cleared_operation_error, oefmt)
from pypy.interpreter.executioncontext import ExecutionContext
from pypy.interpreter.nestedscope import Cell
from pypy.tool import stdlib_opcode
# Define some opcodes used
for op in '''DUP_TOP POP_TOP SETUP_LOOP SETUP_EXCEPT SETUP_FINALLY SETUP_WITH
POP_BLOCK END_FINALLY YIELD_VALUE WITH_CLEANUP'''.split():
globals()[op] = stdlib_opcode.opmap[op]
HAVE_ARGUMENT = stdlib_opcode.HAVE_ARGUMENT
class FrameDebugData(object):
""" A small object that holds debug data for tracing
"""
w_f_trace = None
instr_lb = 0
instr_ub = 0
instr_prev_plus_one = 0
f_lineno = 0 # current lineno for tracing
is_being_profiled = False
is_in_line_tracing = False
w_locals = None
def __init__(self, pycode):
self.f_lineno = pycode.co_firstlineno
self.w_globals = pycode.w_globals
class PyFrame(W_Root):
"""Represents a frame for a regular Python function
that needs to be interpreted.
Public fields:
* 'space' is the object space this frame is running in
* 'code' is the PyCode object this frame runs
* 'w_locals' is the locals dictionary to use, if needed, stored on a
debug object
* 'w_globals' is the attached globals dictionary
* 'builtin' is the attached built-in module
* 'valuestack_w', 'blockstack', control the interpretation
Cell Vars:
my local variables that are exposed to my inner functions
Free Vars:
variables coming from a parent function in which i'm nested
'closure' is a list of Cell instances: the received free vars.
"""
__metaclass__ = extendabletype
frame_finished_execution = False
last_instr = -1
last_exception = None
f_backref = jit.vref_None
escaped = False # see mark_as_escaped()
debugdata = None
pycode = None # code object executed by that frame
locals_cells_stack_w = None # the list of all locals, cells and the valuestack
valuestackdepth = 0 # number of items on valuestack
lastblock = None
# other fields:
# builtin - builtin cache, only if honor__builtins__ is True
# defaults to False
# there is also self.space which is removed by the annotator
# additionally JIT uses vable_token field that is representing
# frame current virtualizable state as seen by the JIT
def __init__(self, space, code, w_globals, outer_func):
if not we_are_translated():
assert type(self) == space.FrameClass, (
"use space.FrameClass(), not directly PyFrame()")
self = hint(self, access_directly=True, fresh_virtualizable=True)
assert isinstance(code, pycode.PyCode)
self.space = space
self.pycode = code
if code.frame_stores_global(w_globals):
self.getorcreatedebug().w_globals = w_globals
ncellvars = len(code.co_cellvars)
nfreevars = len(code.co_freevars)
size = code.co_nlocals + ncellvars + nfreevars + code.co_stacksize
# the layout of this list is as follows:
# | local vars | cells | stack |
self.locals_cells_stack_w = [None] * size
self.valuestackdepth = code.co_nlocals + ncellvars + nfreevars
make_sure_not_resized(self.locals_cells_stack_w)
check_nonneg(self.valuestackdepth)
#
if space.config.objspace.honor__builtins__:
self.builtin = space.builtin.pick_builtin(w_globals)
# regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
# class bodies only have CO_NEWLOCALS.
self.initialize_frame_scopes(outer_func, code)
def getdebug(self):
return self.debugdata
def getorcreatedebug(self):
if self.debugdata is None:
self.debugdata = FrameDebugData(self.pycode)
return self.debugdata
def get_w_globals(self):
debugdata = self.getdebug()
if debugdata is not None:
return debugdata.w_globals
return jit.promote(self.pycode).w_globals
def get_w_f_trace(self):
d = self.getdebug()
if d is None:
return None
return d.w_f_trace
def get_is_being_profiled(self):
d = self.getdebug()
if d is None:
return False
return d.is_being_profiled
def get_w_locals(self):
d = self.getdebug()
if d is None:
return None
return d.w_locals
@not_rpython
def __repr__(self):
# useful in tracebacks
return "<%s.%s executing %s at line %s" % (
self.__class__.__module__, self.__class__.__name__,
self.pycode, self.get_last_lineno())
def _getcell(self, varindex):
cell = self.locals_cells_stack_w[varindex + self.pycode.co_nlocals]
assert isinstance(cell, Cell)
return cell
def mark_as_escaped(self):
"""
Must be called on frames that are exposed to applevel, e.g. by
sys._getframe(). This ensures that the virtualref holding the frame
is properly forced by ec.leave(), and thus the frame will be still
accessible even after the corresponding C stack died.
"""
self.escaped = True
def append_block(self, block):
assert block.previous is self.lastblock
self.lastblock = block
def pop_block(self):
block = self.lastblock
self.lastblock = block.previous
return block
def blockstack_non_empty(self):
return self.lastblock is not None
def get_blocklist(self):
"""Returns a list containing all the blocks in the frame"""
lst = []
block = self.lastblock
while block is not None:
lst.append(block)
block = block.previous
return lst
def set_blocklist(self, lst):
self.lastblock = None
i = len(lst) - 1
while i >= 0:
block = lst[i]
i -= 1
block.previous = self.lastblock
self.lastblock = block
def get_builtin(self):
if self.space.config.objspace.honor__builtins__:
return self.builtin
else:
return self.space.builtin
@jit.unroll_safe
def initialize_frame_scopes(self, outer_func, code):
# regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
# class bodies only have CO_NEWLOCALS.
# CO_NEWLOCALS: make a locals dict unless optimized is also set
# CO_OPTIMIZED: no locals dict needed at all
flags = code.co_flags
if not (flags & pycode.CO_OPTIMIZED):
if flags & pycode.CO_NEWLOCALS:
self.getorcreatedebug().w_locals = self.space.newdict(module=True)
else:
w_globals = self.get_w_globals()
assert w_globals is not None
self.getorcreatedebug().w_locals = w_globals
ncellvars = len(code.co_cellvars)
nfreevars = len(code.co_freevars)
if not nfreevars:
if not ncellvars:
return # no cells needed - fast path
elif outer_func is None:
space = self.space
raise oefmt(space.w_TypeError,
"directly executed code object may not contain free "
"variables")
if outer_func and outer_func.closure:
closure_size = len(outer_func.closure)
else:
closure_size = 0
if closure_size != nfreevars:
raise ValueError("code object received a closure with "
"an unexpected number of free variables")
index = code.co_nlocals
for i in range(ncellvars):
self.locals_cells_stack_w[index] = Cell(
None, self.pycode.cell_families[i])
index += 1
for i in range(nfreevars):
self.locals_cells_stack_w[index] = outer_func.closure[i]
index += 1
def run(self):
"""Start this frame's execution."""
if self.getcode().co_flags & pycode.CO_GENERATOR:
from pypy.interpreter.generator import GeneratorIterator
return GeneratorIterator(self)
else:
return self.execute_frame()
def execute_frame(self, w_inputvalue=None, operr=None):
"""Execute this frame. Main entry point to the interpreter.
The optional arguments are there to handle a generator's frame:
w_inputvalue is for generator.send() and operr is for
generator.throw().
"""
# the following 'assert' is an annotation hint: it hides from
# the annotator all methods that are defined in PyFrame but
# overridden in the {,Host}FrameClass subclasses of PyFrame.
assert (isinstance(self, self.space.FrameClass) or
not self.space.config.translating)
executioncontext = self.space.getexecutioncontext()
executioncontext.enter(self)
got_exception = True
w_exitvalue = self.space.w_None
try:
executioncontext.call_trace(self)
#
try:
if operr is not None:
next_instr = self.handle_operation_error(
executioncontext, operr)
self.last_instr = intmask(next_instr - 1)
else:
# Execution starts just after the last_instr. Initially,
# last_instr is -1. After a generator suspends it points to
# the YIELD_VALUE instruction.
next_instr = r_uint(self.last_instr + 1)
if next_instr != 0:
self.pushvalue(w_inputvalue)
w_exitvalue = self.dispatch(self.pycode, next_instr,
executioncontext)
except OperationError:
raise
except Exception as e: # general fall-back
raise self._convert_unexpected_exception(e)
finally:
executioncontext.return_trace(self, w_exitvalue)
# it used to say self.last_exception = None
# this is now done by the code in pypyjit module
# since we don't want to invalidate the virtualizable
# for no good reason
got_exception = False
finally:
executioncontext.leave(self, w_exitvalue, got_exception)
return w_exitvalue
execute_frame.insert_stack_check_here = True
# stack manipulation helpers
def pushvalue(self, w_object):
depth = self.valuestackdepth
self.locals_cells_stack_w[depth] = ll_assert_not_none(w_object)
self.valuestackdepth = depth + 1
def pushvalue_none(self):
depth = self.valuestackdepth
# the entry is already None, and remains None
assert self.locals_cells_stack_w[depth] is None
self.valuestackdepth = depth + 1
def assert_stack_index(self, index):
if we_are_translated():
return
assert self._check_stack_index(index)
def _check_stack_index(self, index):
code = self.pycode
ncellvars = len(code.co_cellvars)
nfreevars = len(code.co_freevars)
stackstart = code.co_nlocals + ncellvars + nfreevars
return index >= stackstart
def popvalue(self):
return ll_assert_not_none(self.popvalue_maybe_none())
def popvalue_maybe_none(self):
depth = self.valuestackdepth - 1
self.assert_stack_index(depth)
assert depth >= 0
w_object = self.locals_cells_stack_w[depth]
self.locals_cells_stack_w[depth] = None
self.valuestackdepth = depth
return w_object
# we need two popvalues that return different data types:
# one in case we want list another in case of tuple
def _new_popvalues():
@jit.unroll_safe
def popvalues(self, n):
values_w = [None] * n
while True:
n -= 1
if n < 0:
break
values_w[n] = self.popvalue()
return values_w
return popvalues
popvalues = _new_popvalues()
popvalues_mutable = _new_popvalues()
del _new_popvalues
@jit.unroll_safe
def peekvalues(self, n):
values_w = [None] * n
base = self.valuestackdepth - n
self.assert_stack_index(base)
assert base >= 0
while True:
n -= 1
if n < 0:
break
values_w[n] = self.locals_cells_stack_w[base+n]
return values_w
@jit.unroll_safe
def dropvalues(self, n):
n = hint(n, promote=True)
finaldepth = self.valuestackdepth - n
self.assert_stack_index(finaldepth)
assert finaldepth >= 0
while True:
n -= 1
if n < 0:
break
self.locals_cells_stack_w[finaldepth+n] = None
self.valuestackdepth = finaldepth
@jit.unroll_safe
def pushrevvalues(self, n, values_w): # n should be len(values_w)
make_sure_not_resized(values_w)
while True:
n -= 1
if n < 0:
break
self.pushvalue(values_w[n])
@jit.unroll_safe
def dupvalues(self, n):
delta = n-1
while True:
n -= 1
if n < 0:
break
w_value = self.peekvalue(delta)
self.pushvalue(w_value)
def peekvalue(self, index_from_top=0):
# NOTE: top of the stack is peekvalue(0).
# Contrast this with CPython where it's PEEK(-1).
return ll_assert_not_none(self.peekvalue_maybe_none(index_from_top))
def peekvalue_maybe_none(self, index_from_top=0):
index_from_top = hint(index_from_top, promote=True)
index = self.valuestackdepth + ~index_from_top
self.assert_stack_index(index)
assert index >= 0
return self.locals_cells_stack_w[index]
def settopvalue(self, w_object, index_from_top=0):
index_from_top = hint(index_from_top, promote=True)
index = self.valuestackdepth + ~index_from_top
self.assert_stack_index(index)
assert index >= 0
self.locals_cells_stack_w[index] = ll_assert_not_none(w_object)
@jit.unroll_safe
def dropvaluesuntil(self, finaldepth):
depth = self.valuestackdepth - 1
finaldepth = hint(finaldepth, promote=True)
assert finaldepth >= 0
while depth >= finaldepth:
self.locals_cells_stack_w[depth] = None
depth -= 1
self.valuestackdepth = finaldepth
def make_arguments(self, nargs, methodcall=False):
return Arguments(
self.space, self.peekvalues(nargs), methodcall=methodcall)
def argument_factory(self, arguments, keywords, keywords_w, w_star, w_starstar, methodcall=False):
return Arguments(
self.space, arguments, keywords, keywords_w, w_star,
w_starstar, methodcall=methodcall)
@jit.dont_look_inside
def descr__reduce__(self, space):
from pypy.interpreter.mixedmodule import MixedModule
w_mod = space.getbuiltinmodule('_pickle_support')
mod = space.interp_w(MixedModule, w_mod)
new_inst = mod.get('frame_new')
w_tup_state = self._reduce_state(space)
nt = space.newtuple
return nt([new_inst, nt([]), w_tup_state])
@jit.dont_look_inside
def _reduce_state(self, space):
from pypy.module._pickle_support import maker # helper fns
nt = space.newtuple
if self.get_w_f_trace() is None:
f_lineno = self.get_last_lineno()
else:
f_lineno = self.getorcreatedebug().f_lineno
nlocals = self.pycode.co_nlocals
values_w = self.locals_cells_stack_w
w_locals_cells_stack = maker.slp_into_tuple_with_nulls(space, values_w)
w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()])
if self.last_exception is None:
w_exc_value = space.w_None
w_tb = space.w_None
else:
w_exc_value = self.last_exception.get_w_value(space)
w_tb = self.last_exception.get_w_traceback(space)
d = self.getorcreatedebug()
tup_state = [
self.f_backref(),
self.get_builtin(),
self.pycode,
w_locals_cells_stack,
w_blockstack,
w_exc_value, # last_exception
w_tb, #
self.get_w_globals(),
space.newint(self.last_instr),
space.newbool(self.frame_finished_execution),
space.newint(f_lineno),
space.w_None, #XXX placeholder for f_locals
#f_restricted requires no additional data!
space.w_None,
space.newint(d.instr_lb),
space.newint(d.instr_ub),
space.newint(d.instr_prev_plus_one),
space.newint(self.valuestackdepth),
]
return nt(tup_state)
@jit.dont_look_inside
def descr__setstate__(self, space, w_args):
from pypy.module._pickle_support import maker # helper fns
from pypy.interpreter.pycode import PyCode
from pypy.interpreter.module import Module
args_w = space.unpackiterable(w_args, 17)
w_f_back, w_builtin, w_pycode, w_locals_cells_stack, w_blockstack, w_exc_value, w_tb,\
w_globals, w_last_instr, w_finished, w_f_lineno, w_f_locals, \
w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev_plus_one, w_stackdepth = args_w
new_frame = self
pycode = space.interp_w(PyCode, w_pycode)
values_w = maker.slp_from_tuple_with_nulls(space, w_locals_cells_stack)
nfreevars = len(pycode.co_freevars)
closure = None
if nfreevars:
base = pycode.co_nlocals + len(pycode.co_cellvars)
closure = values_w[base: base + nfreevars]
# do not use the instance's __init__ but the base's, because we set
# everything like cells from here
# XXX hack
from pypy.interpreter.function import Function
outer_func = Function(space, None, closure=closure,
forcename="fake")
PyFrame.__init__(self, space, pycode, w_globals, outer_func)
f_back = space.interp_w(PyFrame, w_f_back, can_be_None=True)
new_frame.f_backref = jit.non_virtual_ref(f_back)
if space.config.objspace.honor__builtins__:
new_frame.builtin = space.interp_w(Module, w_builtin)
else:
assert space.interp_w(Module, w_builtin) is space.builtin
new_frame.set_blocklist([unpickle_block(space, w_blk)
for w_blk in space.unpackiterable(w_blockstack)])
self.locals_cells_stack_w = values_w[:]
valuestackdepth = space.int_w(w_stackdepth)
if not self._check_stack_index(valuestackdepth):
raise oefmt(space.w_ValueError, "invalid stackdepth")
assert valuestackdepth >= 0
self.valuestackdepth = valuestackdepth
if space.is_w(w_exc_value, space.w_None):
new_frame.last_exception = None
else:
from pypy.interpreter.pytraceback import PyTraceback
tb = space.interp_w(PyTraceback, w_tb)
new_frame.last_exception = OperationError(space.type(w_exc_value),
w_exc_value, tb
)
new_frame.last_instr = space.int_w(w_last_instr)
new_frame.frame_finished_execution = space.is_true(w_finished)
d = new_frame.getorcreatedebug()
d.f_lineno = space.int_w(w_f_lineno)
if space.is_w(w_f_trace, space.w_None):
d.w_f_trace = None
else:
d.w_f_trace = w_f_trace
d.instr_lb = space.int_w(w_instr_lb) #the three for tracing
d.instr_ub = space.int_w(w_instr_ub)
d.instr_prev_plus_one = space.int_w(w_instr_prev_plus_one)
def hide(self):
return self.pycode.hidden_applevel
def getcode(self):
return hint(self.pycode, promote=True)
@jit.look_inside_iff(lambda self, scope_w: jit.isvirtual(scope_w))
def setfastscope(self, scope_w):
"""Initialize the fast locals from a list of values,
where the order is according to self.pycode.signature()."""
scope_len = len(scope_w)
if scope_len > self.pycode.co_nlocals:
raise ValueError("new fastscope is longer than the allocated area")
# don't assign directly to 'locals_cells_stack_w[:scope_len]' to be
# virtualizable-friendly
for i in range(scope_len):
self.locals_cells_stack_w[i] = scope_w[i]
self.init_cells()
def getdictscope(self):
"""
Get the locals as a dictionary
"""
self.fast2locals()
return self.debugdata.w_locals
def setdictscope(self, w_locals):
"""
Initialize the locals from a dictionary.
"""
self.getorcreatedebug().w_locals = w_locals
self.locals2fast()
@jit.unroll_safe
def fast2locals(self):
# Copy values from the fastlocals to self.w_locals
d = self.getorcreatedebug()
if d.w_locals is None:
d.w_locals = self.space.newdict()
varnames = self.getcode().getvarnames()
for i in range(min(len(varnames), self.getcode().co_nlocals)):
name = varnames[i]
w_value = self.locals_cells_stack_w[i]
if w_value is not None:
self.space.setitem_str(d.w_locals, name, w_value)
else:
w_name = self.space.newtext(name)
try:
self.space.delitem(d.w_locals, w_name)
except OperationError as e:
if not e.match(self.space, self.space.w_KeyError):
raise
# cellvars are values exported to inner scopes
# freevars are values coming from outer scopes
# (see locals2fast for why CO_OPTIMIZED)
freevarnames = self.pycode.co_cellvars
if self.pycode.co_flags & consts.CO_OPTIMIZED:
freevarnames = freevarnames + self.pycode.co_freevars
for i in range(len(freevarnames)):
name = freevarnames[i]
cell = self._getcell(i)
try:
w_value = cell.get()
except ValueError:
pass
else:
self.space.setitem_str(d.w_locals, name, w_value)
@jit.unroll_safe
def locals2fast(self):
# Copy values from self.w_locals to the fastlocals
w_locals = self.getorcreatedebug().w_locals
assert w_locals is not None
varnames = self.getcode().getvarnames()
numlocals = self.getcode().co_nlocals
new_fastlocals_w = [None] * numlocals
for i in range(min(len(varnames), numlocals)):
name = varnames[i]
w_value = self.space.finditem_str(w_locals, name)
if w_value is not None:
new_fastlocals_w[i] = w_value
self.setfastscope(new_fastlocals_w)
freevarnames = self.pycode.co_cellvars
if self.pycode.co_flags & consts.CO_OPTIMIZED:
freevarnames = freevarnames + self.pycode.co_freevars
# If the namespace is unoptimized, then one of the
# following cases applies:
# 1. It does not contain free variables, because it
# uses import * or is a top-level namespace.
# 2. It is a class namespace.
# We don't want to accidentally copy free variables
# into the locals dict used by the class.
for i in range(len(freevarnames)):
name = freevarnames[i]
cell = self._getcell(i)
w_value = self.space.finditem_str(w_locals, name)
if w_value is not None:
cell.set(w_value)
@jit.unroll_safe
def init_cells(self):
"""
Initialize cellvars from self.locals_cells_stack_w.
"""
args_to_copy = self.pycode._args_as_cellvars
index = self.pycode.co_nlocals
for i in range(len(args_to_copy)):
argnum = args_to_copy[i]
if argnum >= 0:
cell = self.locals_cells_stack_w[index]
assert isinstance(cell, Cell)
cell.set(self.locals_cells_stack_w[argnum])
index += 1
def getclosure(self):
return None
def fget_code(self, space):
return self.getcode()
def fget_getdictscope(self, space):
return self.getdictscope()
def fget_w_globals(self, space):
# bit silly, but GetSetProperty passes a space
return self.get_w_globals()
### line numbers ###
def fget_f_lineno(self, space):
"Returns the line number of the instruction currently being executed."
if self.get_w_f_trace() is None:
return space.newint(self.get_last_lineno())
else:
return space.newint(self.getorcreatedebug().f_lineno)
def fset_f_lineno(self, space, w_new_lineno):
"Returns the line number of the instruction currently being executed."
try:
new_lineno = space.int_w(w_new_lineno)
except OperationError:
raise oefmt(space.w_ValueError, "lineno must be an integer")
# You can only do this from within a trace function, not via
# _getframe or similar hackery.
if space.int_w(self.fget_f_lasti(space)) == -1:
raise oefmt(space.w_ValueError,
"can't jump from the 'call' trace event of a new frame")
if self.get_w_f_trace() is None:
raise oefmt(space.w_ValueError,
"f_lineno can only be set by a trace function.")
code = self.pycode.co_code
if ord(code[self.last_instr]) == YIELD_VALUE:
raise oefmt(space.w_ValueError,
"can't jump from a yield statement")
# Only allow jumps when we're tracing a line event.
d = self.getorcreatedebug()
if not d.is_in_line_tracing:
raise oefmt(space.w_ValueError,
"can only jump from a 'line' trace event")
line = self.pycode.co_firstlineno
if new_lineno < line:
raise oefmt(space.w_ValueError,
"line %d comes before the current code.", new_lineno)
elif new_lineno == line:
new_lasti = 0
else:
new_lasti = -1
addr = 0
lnotab = self.pycode.co_lnotab
for offset in xrange(0, len(lnotab), 2):
addr += ord(lnotab[offset])
line += ord(lnotab[offset + 1])
if line >= new_lineno:
new_lasti = addr
new_lineno = line
break
if new_lasti == -1:
raise oefmt(space.w_ValueError,
"line %d comes after the current code.", new_lineno)
# Don't jump to a line with an except in it.
if ord(code[new_lasti]) in (DUP_TOP, POP_TOP):
raise oefmt(space.w_ValueError,
"can't jump to 'except' line as there's no exception")
# Don't jump into or out of a finally block.
f_lasti_setup_addr = -1
new_lasti_setup_addr = -1
blockstack = []
addr = 0
while addr < len(code):
op = ord(code[addr])
if op in (SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH):
blockstack.append([addr, False])
elif op == POP_BLOCK:
setup_op = ord(code[blockstack[-1][0]])
if setup_op == SETUP_FINALLY or setup_op == SETUP_WITH:
blockstack[-1][1] = True
else:
blockstack.pop()
elif op == END_FINALLY:
if len(blockstack) > 0:
setup_op = ord(code[blockstack[-1][0]])
if setup_op == SETUP_FINALLY or setup_op == SETUP_WITH:
blockstack.pop()
if addr == new_lasti or addr == self.last_instr:
for ii in range(len(blockstack)):
setup_addr, in_finally = blockstack[~ii]
if in_finally:
if addr == new_lasti:
new_lasti_setup_addr = setup_addr
if addr == self.last_instr:
f_lasti_setup_addr = setup_addr
break
if op >= HAVE_ARGUMENT:
addr += 3
else:
addr += 1
assert len(blockstack) == 0
if new_lasti_setup_addr != f_lasti_setup_addr:
raise oefmt(space.w_ValueError,
"can't jump into or out of a 'finally' block %d -> %d",
f_lasti_setup_addr, new_lasti_setup_addr)
if new_lasti < self.last_instr:
min_addr = new_lasti
max_addr = self.last_instr
else:
min_addr = self.last_instr
max_addr = new_lasti
delta_iblock = min_delta_iblock = 0
addr = min_addr
while addr < max_addr:
op = ord(code[addr])
if op in (SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH):
delta_iblock += 1
elif op == POP_BLOCK:
delta_iblock -= 1
if delta_iblock < min_delta_iblock:
min_delta_iblock = delta_iblock
if op >= stdlib_opcode.HAVE_ARGUMENT:
addr += 3
else:
addr += 1
f_iblock = 0
block = self.lastblock
while block:
f_iblock += 1
block = block.previous
min_iblock = f_iblock + min_delta_iblock
if new_lasti > self.last_instr:
new_iblock = f_iblock + delta_iblock
else:
new_iblock = f_iblock - delta_iblock
if new_iblock > min_iblock:
raise oefmt(space.w_ValueError,
"can't jump into the middle of a block")
# Pop any blocks that we're jumping out of.
from pypy.interpreter.pyopcode import FinallyBlock
while f_iblock > new_iblock:
block = self.pop_block()
block.cleanup(self)
f_iblock -= 1
if (isinstance(block, FinallyBlock)
and ord(code[block.handlerposition]) == WITH_CLEANUP):
self.popvalue() # Pop the exit function.
d.f_lineno = new_lineno
self.last_instr = new_lasti
def get_last_lineno(self):
"Returns the line number of the instruction currently being executed."
return pytraceback.offset2lineno(self.pycode, self.last_instr)
def fget_f_builtins(self, space):
return self.get_builtin().getdict(space)
def get_f_back(self):
return ExecutionContext.getnextframe_nohidden(self)
def fget_f_back(self, space):
return self.get_f_back()
def fget_f_lasti(self, space):
return self.space.newint(self.last_instr)
def fget_f_trace(self, space):
return self.get_w_f_trace()
def fset_f_trace(self, space, w_trace):
if space.is_w(w_trace, space.w_None):
self.getorcreatedebug().w_f_trace = None
else:
d = self.getorcreatedebug()
d.w_f_trace = w_trace
d.f_lineno = self.get_last_lineno()
def fdel_f_trace(self, space):
self.getorcreatedebug().w_f_trace = None
def fget_f_exc_type(self, space):
if self.last_exception is not None:
f = self.f_backref()
while f is not None and f.last_exception is None:
f = f.f_backref()
if f is not None:
return f.last_exception.w_type
return space.w_None
def fget_f_exc_value(self, space):
if self.last_exception is not None:
f = self.f_backref()
while f is not None and f.last_exception is None:
f = f.f_backref()
if f is not None:
return f.last_exception.get_w_value(space)
return space.w_None
def fget_f_exc_traceback(self, space):
if self.last_exception is not None:
f = self.f_backref()
while f is not None and f.last_exception is None:
f = f.f_backref()
if f is not None:
return f.last_exception.get_w_traceback(space)
return space.w_None
def fget_f_restricted(self, space):
if space.config.objspace.honor__builtins__:
return space.newbool(self.builtin is not space.builtin)
return space.w_False
@jit.unroll_safe
@specialize.arg(2)
def _exc_info_unroll(self, space, for_hidden=False):
"""Return the most recent OperationError being handled in the
call stack
"""
frame = self
while frame:
last = frame.last_exception
if last is not None:
if last is get_cleared_operation_error(self.space):
break
if for_hidden or not frame.hide():
return last
frame = frame.f_backref()
return None
def _convert_unexpected_exception(self, e):
from pypy.interpreter import error
operr = error.get_converted_unexpected_exception(self.space, e)
pytraceback.record_application_traceback(
self.space, operr, self, self.last_instr)
raise operr
# ____________________________________________________________
def get_block_class(opname):
# select the appropriate kind of block
from pypy.interpreter.pyopcode import block_classes
return block_classes[opname]
def unpickle_block(space, w_tup):
w_opname, w_handlerposition, w_valuestackdepth = space.unpackiterable(w_tup)
opname = space.text_w(w_opname)
handlerposition = space.int_w(w_handlerposition)
valuestackdepth = space.int_w(w_valuestackdepth)
assert valuestackdepth >= 0
assert handlerposition >= 0
blk = instantiate(get_block_class(opname))
blk.handlerposition = handlerposition
blk.valuestackdepth = valuestackdepth
return blk
|