-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #140 from stealthrocket/py309
Python 3.9 support
- Loading branch information
Showing
27 changed files
with
462 additions
and
331 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,61 @@ | ||
from types import FrameType | ||
from typing import Any, AsyncGenerator, Coroutine, Generator, Tuple | ||
from typing import Any, AsyncGenerator, Coroutine, Generator, Tuple, Union | ||
|
||
def get_frame_ip(frame: FrameType | Coroutine | Generator | AsyncGenerator) -> int: | ||
def get_frame_ip(frame: Union[FrameType, Coroutine, Generator, AsyncGenerator]) -> int: | ||
"""Get instruction pointer of a generator or coroutine.""" | ||
|
||
def set_frame_ip(frame: FrameType | Coroutine | Generator | AsyncGenerator, ip: int): | ||
def set_frame_ip( | ||
frame: Union[FrameType, Coroutine, Generator, AsyncGenerator], ip: int | ||
): | ||
"""Set instruction pointer of a generator or coroutine.""" | ||
|
||
def get_frame_sp(frame: FrameType | Coroutine | Generator | AsyncGenerator) -> int: | ||
def get_frame_sp(frame: Union[FrameType, Coroutine, Generator, AsyncGenerator]) -> int: | ||
"""Get stack pointer of a generator or coroutine.""" | ||
|
||
def set_frame_sp(frame: FrameType | Coroutine | Generator | AsyncGenerator, sp: int): | ||
def set_frame_sp( | ||
frame: Union[FrameType, Coroutine, Generator, AsyncGenerator], sp: int | ||
): | ||
"""Set stack pointer of a generator or coroutine.""" | ||
|
||
def get_frame_bp(frame: FrameType | Coroutine | Generator | AsyncGenerator) -> int: | ||
def get_frame_bp(frame: Union[FrameType, Coroutine, Generator, AsyncGenerator]) -> int: | ||
"""Get block pointer of a generator or coroutine.""" | ||
|
||
def set_frame_bp(frame: FrameType | Coroutine | Generator | AsyncGenerator, bp: int): | ||
def set_frame_bp( | ||
frame: Union[FrameType, Coroutine, Generator, AsyncGenerator], bp: int | ||
): | ||
"""Set block pointer of a generator or coroutine.""" | ||
|
||
def get_frame_stack_at( | ||
frame: FrameType | Coroutine | Generator | AsyncGenerator, index: int | ||
frame: Union[FrameType, Coroutine, Generator, AsyncGenerator], index: int | ||
) -> Tuple[bool, Any]: | ||
"""Get an object from a generator or coroutine's stack, as an (is_null, obj) tuple.""" | ||
|
||
def set_frame_stack_at( | ||
frame: FrameType | Coroutine | Generator | AsyncGenerator, | ||
frame: Union[FrameType, Coroutine, Generator, AsyncGenerator], | ||
index: int, | ||
unset: bool, | ||
value: Any, | ||
): | ||
"""Set or unset an object on the stack of a generator or coroutine.""" | ||
|
||
def get_frame_block_at( | ||
frame: FrameType | Coroutine | Generator | AsyncGenerator, index: int | ||
frame: Union[FrameType, Coroutine, Generator, AsyncGenerator], index: int | ||
) -> Tuple[int, int, int]: | ||
"""Get a block from a generator or coroutine.""" | ||
|
||
def set_frame_block_at( | ||
frame: FrameType | Coroutine | Generator | AsyncGenerator, | ||
frame: Union[FrameType, Coroutine, Generator, AsyncGenerator], | ||
index: int, | ||
value: Tuple[int, int, int], | ||
): | ||
"""Restore a block of a generator or coroutine.""" | ||
|
||
def get_frame_state( | ||
frame: FrameType | Coroutine | Generator | AsyncGenerator, | ||
frame: Union[FrameType, Coroutine, Generator, AsyncGenerator], | ||
) -> int: | ||
"""Get frame state of a generator or coroutine.""" | ||
|
||
def set_frame_state( | ||
frame: FrameType | Coroutine | Generator | AsyncGenerator, state: int | ||
frame: Union[FrameType, Coroutine, Generator, AsyncGenerator], state: int | ||
): | ||
"""Set frame state of a generator or coroutine.""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// This is a redefinition of the private/opaque frame object. | ||
// https://github.com/python/cpython/blob/3.9/Include/cpython/frameobject.h#L17 | ||
// | ||
// In Python <= 3.10, `struct _frame` is both the PyFrameObject and | ||
// PyInterpreterFrame. From Python 3.11 onwards, the two were split with the | ||
// PyFrameObject (struct _frame) pointing to struct _PyInterpreterFrame. | ||
struct Frame { | ||
PyObject_VAR_HEAD | ||
struct Frame *f_back; // struct _frame | ||
PyCodeObject *f_code; | ||
PyObject *f_builtins; | ||
PyObject *f_globals; | ||
PyObject *f_locals; | ||
PyObject **f_valuestack; | ||
PyObject **f_stacktop; | ||
PyObject *f_trace; | ||
char f_trace_lines; | ||
char f_trace_opcodes; | ||
PyObject *f_gen; | ||
int f_lasti; | ||
int f_lineno; | ||
int f_iblock; | ||
char f_executing; | ||
PyTryBlock f_blockstack[CO_MAXBLOCKS]; | ||
PyObject *f_localsplus[1]; | ||
}; | ||
|
||
// Python 3.9 and prior didn't have an explicit enum of frame states, | ||
// but we can derive them based on the presence of a frame, and other | ||
// information found on the frame, for compatibility with later versions. | ||
typedef enum _framestate { | ||
FRAME_CREATED = -2, | ||
FRAME_EXECUTING = 0, | ||
FRAME_CLEARED = 4 | ||
} FrameState; | ||
|
||
/* | ||
// This is the definition of PyGenObject for reference to developers | ||
// working on the extension. | ||
// | ||
// Note that PyCoroObject and PyAsyncGenObject have the same layout as | ||
// PyGenObject, however the struct fields have a cr_ and ag_ prefix | ||
// (respectively) rather than a gi_ prefix. In Python <= 3.10, PyCoroObject | ||
// and PyAsyncGenObject have extra fields compared to PyGenObject. In Python | ||
// 3.11 onwards, the three objects are identical (except for field name | ||
// prefixes). The extra fields in Python <= 3.10 are not applicable to the | ||
// extension at this time. | ||
// | ||
// https://github.com/python/cpython/blob/3.9/Include/genobject.h#L15 | ||
typedef struct { | ||
PyObject_HEAD | ||
PyFrameObject *gi_frame; | ||
char gi_running; | ||
PyObject *gi_code; | ||
PyObject *gi_weakreflist; | ||
PyObject *gi_name; | ||
PyObject *gi_qualname; | ||
_PyErr_StackItem gi_exc_state; | ||
} PyGenObject; | ||
*/ | ||
|
||
static Frame *get_frame(PyGenObject *gen_like) { | ||
Frame *frame = (Frame *)(gen_like->gi_frame); | ||
assert(frame); | ||
return frame; | ||
} | ||
|
||
static PyCodeObject *get_frame_code(Frame *frame) { | ||
PyCodeObject *code = frame->f_code; | ||
assert(code); | ||
return code; | ||
} | ||
|
||
static int get_frame_lasti(Frame *frame) { | ||
return frame->f_lasti; | ||
} | ||
|
||
static void set_frame_lasti(Frame *frame, int lasti) { | ||
frame->f_lasti = lasti; | ||
} | ||
|
||
static int get_frame_state(PyGenObject *gen_like) { | ||
// Python 3.9 doesn't have frame states, but we can derive | ||
// some for compatibility with later versions and to simplify | ||
// the extension. | ||
Frame *frame = (Frame *)(gen_like->gi_frame); | ||
if (!frame) { | ||
return FRAME_CLEARED; | ||
} | ||
return frame->f_executing ? FRAME_EXECUTING : FRAME_CREATED; | ||
} | ||
|
||
static void set_frame_state(PyGenObject *gen_like, int fs) { | ||
Frame *frame = get_frame(gen_like); | ||
frame->f_executing = (fs == FRAME_EXECUTING); | ||
} | ||
|
||
static int valid_frame_state(int fs) { | ||
return fs == FRAME_CREATED || fs == FRAME_EXECUTING || fs == FRAME_CLEARED; | ||
} | ||
|
||
static int get_frame_stacktop_limit(Frame *frame) { | ||
PyCodeObject *code = get_frame_code(frame); | ||
return code->co_stacksize + code->co_nlocals; | ||
} | ||
|
||
static int get_frame_stacktop(Frame *frame) { | ||
assert(frame->f_localsplus); | ||
int stacktop = (int)(frame->f_stacktop - frame->f_localsplus); | ||
assert(stacktop >= 0 && stacktop < get_frame_stacktop_limit(frame)); | ||
return stacktop; | ||
} | ||
|
||
static void set_frame_stacktop(Frame *frame, int stacktop) { | ||
assert(stacktop >= 0 && stacktop < get_frame_stacktop_limit(frame)); | ||
assert(frame->f_localsplus); | ||
frame->f_stacktop = frame->f_localsplus + stacktop; | ||
} | ||
|
||
static PyObject **get_frame_localsplus(Frame *frame) { | ||
PyObject **localsplus = frame->f_localsplus; | ||
assert(localsplus); | ||
return localsplus; | ||
} | ||
|
||
static int get_frame_iblock_limit(Frame *frame) { | ||
return CO_MAXBLOCKS; | ||
} | ||
|
||
static int get_frame_iblock(Frame *frame) { | ||
return frame->f_iblock; | ||
} | ||
|
||
static void set_frame_iblock(Frame *frame, int iblock) { | ||
assert(iblock >= 0 && iblock < get_frame_iblock_limit(frame)); | ||
frame->f_iblock = iblock; | ||
} | ||
|
||
static PyTryBlock *get_frame_blockstack(Frame *frame) { | ||
PyTryBlock *blockstack = frame->f_blockstack; | ||
assert(blockstack); | ||
return blockstack; | ||
} | ||
|
Oops, something went wrong.