File: interp_pickle.py

package info (click to toggle)
pypy3 7.3.19%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 212,236 kB
  • sloc: python: 2,098,316; ansic: 540,565; sh: 21,462; asm: 14,419; cpp: 4,451; makefile: 4,209; objc: 761; xml: 530; exp: 499; javascript: 314; pascal: 244; lisp: 45; csh: 12; awk: 4
file content (112 lines) | stat: -rw-r--r-- 4,112 bytes parent folder | download | duplicates (2)
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
from pypy.tool import stdlib_opcode as pythonopcode
from rpython.rlib import jit
from pypy.interpreter.error import OperationError
from pypy.interpreter.pyframe import PyFrame
from pypy.module._continuation.interp_continuation import (
    State, global_state, build_sthread, pre_switch, post_switch,
    get_result, geterror)


def getunpickle(space):
    cs = space.fromcache(State)
    return cs.w_unpickle


def reduce(self):
    # xxx this is known to be not completely correct with respect
    # to subclasses, e.g. no __slots__ support, no looking for a
    # __getnewargs__ or __getstate__ defined in the subclass, etc.
    # Doing the right thing looks involved, though...
    space = self.space
    w_frame = self.descr_get_frame(space)
    w_continulet_type = space.type(self)
    w_dict = self.getdict(space) or space.w_None
    args = [getunpickle(space),
            space.newtuple([w_continulet_type]),
            space.newtuple2(w_frame, w_dict),
            ]
    return space.newtuple(args)

def setstate(self, w_args):
    space = self.space
    if self.sthread is not None:
        raise geterror(space, "continulet.__setstate__() on an already-"
                              "initialized continulet")
    w_frame, w_dict = space.fixedview(w_args, expected_length=2)
    if not space.is_w(w_dict, space.w_None):
        self.setdict(space, w_dict)
    if space.is_w(w_frame, space.w_False):
        return    # not initialized
    sthread = build_sthread(self.space)
    self.sthread = sthread
    self.bottomframe = space.interp_w(PyFrame, w_frame, can_be_None=True)
    #
    global_state.origin = self
    if self.bottomframe is not None:
        sthread.frame2continulet.set(self.bottomframe, self)
    self.h = sthread.new(resume_trampoline_callback)
    get_result()    # propagate the eventual MemoryError

# ____________________________________________________________

def resume_trampoline_callback(h, arg):
    self = global_state.origin
    self.h = h
    space = self.space
    sthread = self.sthread
    try:
        global_state.clear()
        if self.bottomframe is None:
            w_result = space.w_None
        else:
            saved_exception = pre_switch(sthread)
            h = sthread.switch(self.h)
            try:
                w_result = post_switch(sthread, h, saved_exception)
                operr = None
            except OperationError as e:
                w_result = None
                operr = e
            #
            while True:
                ec = sthread.ec
                frame = ec.topframeref()
                assert frame is not None     # XXX better error message
                exit_continulet = sthread.frame2continulet.get(frame)
                #
                continue_after_call(frame)
                #
                # small hack: unlink frame out of the execution context,
                # because execute_frame will add it there again
                ec.topframeref = frame.f_backref
                #
                try:
                    w_result = frame.execute_frame(w_result, operr)
                    operr = None
                except OperationError as e:
                    w_result = None
                    operr = e
                if exit_continulet is not None:
                    self = exit_continulet
                    break
            sthread.ec.topframeref = jit.vref_None
            if operr:
                raise operr
    except Exception as e:
        global_state.propagate_exception = e
    else:
        global_state.w_value = w_result
    global_state.origin = self
    global_state.destination = self
    return self.h

def continue_after_call(frame):
    code = frame.pycode.co_code
    instr = frame.last_instr
    opcode = ord(code[instr])
    map = pythonopcode.opmap
    call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'],
                map['CALL_FUNCTION_VAR'], map['CALL_FUNCTION_VAR_KW'],
                map['CALL_METHOD']]
    assert opcode in call_ops   # XXX check better, and complain better
    frame.last_instr = instr + 2    # continue after the call