Skip to content

Commit 8c11f7a

Browse files
author
Anselm Kruis
committed
Merge branch master into master-slp
Implement the frame evaluation API aspect of PEP 523. The outcome of this merge does not compile.
2 parents a9aceb1 + 3cebf93 commit 8c11f7a

File tree

6 files changed

+47
-3
lines changed

6 files changed

+47
-3
lines changed

Doc/whatsnew/3.6.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,34 @@ Windows improvements:
9797
New Features
9898
============
9999

100+
.. _pep-523:
101+
102+
PEP 523: Adding a frame evaluation API to CPython
103+
=================================================
104+
105+
While Python provides extensive support to customize how code
106+
executes, one place it has not done so is in the evaluation of frame
107+
objects. If you wanted some way to intercept frame evaluation in
108+
Python there really wasn't any way without directly manipulating
109+
function pointers for defined functions.
110+
111+
:pep:`523` changes this by providing an API to make frame
112+
evaluation pluggable at the C level. This will allow for tools such
113+
as debuggers and JITs to intercept frame evaluation before the
114+
execution of Python code begins. This enables the use of alternative
115+
evaluation implementations for Python code, tracking frame
116+
evaluation, etc.
117+
118+
This API is not part of the limited C API and is marked as private to
119+
signal that usage of this API is expected to be limited and only
120+
applicable to very select, low-level use-cases.
121+
122+
.. seealso::
123+
124+
:pep:`523` - Adding a frame evaluation API to CPython
125+
PEP written by Brett Cannon and Dino Viehland.
126+
127+
100128
.. _pep-519:
101129

102130
PEP 519: Adding a file system path protocol

Include/ceval.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ PyAPI_FUNC(const char *) PyEval_GetFuncDesc(PyObject *);
119119
PyAPI_FUNC(PyObject *) PyEval_GetCallStats(PyObject *);
120120
PyAPI_FUNC(PyObject *) PyEval_EvalFrame(struct _frame *);
121121
PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(struct _frame *f, int exc);
122+
#ifndef Py_LIMITED_API
123+
PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(struct _frame *f, int exc);
124+
#endif
122125

123126
#ifdef STACKLESS
124127
PyAPI_FUNC(PyObject *) PyEval_EvalFrame_slp(struct _frame *f, int exc, PyObject *retval);

Include/pystate.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ extern "C" {
1515

1616
struct _ts; /* Forward */
1717
struct _is; /* Forward */
18+
struct _frame; /* Forward declaration for PyFrameObject. */
1819

1920
#ifdef Py_LIMITED_API
2021
typedef struct _is PyInterpreterState;
2122
#else
23+
typedef PyObject* (*_PyFrameEvalFunction)(struct _frame *, int);
24+
2225
typedef struct _is {
2326

2427
struct _is *next;
@@ -45,14 +48,14 @@ typedef struct _is {
4548

4649
PyObject *builtins_copy;
4750
PyObject *import_func;
51+
/* Initialized to PyEval_EvalFrameDefault(). */
52+
_PyFrameEvalFunction eval_frame;
4853
} PyInterpreterState;
4954
#endif
5055

5156

5257
/* State unique per thread */
5358

54-
struct _frame; /* Avoid including frameobject.h */
55-
5659
#ifndef Py_LIMITED_API
5760
/* Py_tracefunc return -1 when raising an exception, or 0 for success. */
5861
typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *);

Misc/NEWS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ Core and Builtins
1717
restriction: in beta 2, backslashes will only be disallowed inside
1818
the braces (where the expressions are). This is a breaking change
1919
from the 3.6 alpha releases.
20-
20+
21+
- Implement the frame evaluation part of PEP 523.
22+
2123
- Issue #27870: A left shift of zero by a large integer no longer attempts
2224
to allocate large amounts of memory.
2325

Python/ceval.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,13 @@ slp_eval_frame_value(PyFrameObject *f, int throwflag, PyObject *retval)
802802
#else
803803
PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
804804
#endif
805+
{
806+
PyThreadState *tstate = PyThreadState_GET();
807+
return tstate->interp->eval_frame(f, throwflag);
808+
}
809+
810+
PyObject *
811+
_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
805812
{
806813
#ifdef DXPAIRS
807814
int lastopcode = 0;

Python/pystate.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ PyInterpreterState_New(void)
109109
interp->fscodec_initialized = 0;
110110
interp->importlib = NULL;
111111
interp->import_func = NULL;
112+
interp->eval_frame = _PyEval_EvalFrameDefault;
112113
#ifdef HAVE_DLOPEN
113114
#if HAVE_DECL_RTLD_NOW
114115
interp->dlopenflags = RTLD_NOW;

0 commit comments

Comments
 (0)