-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
gh-117139: Convert the evaluation stack to stack refs #118450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
a6275f1
7e7627f
00dde8e
eadc4fc
64e2800
bf6b7e4
865ff8d
b1777c4
50cfefa
39e9057
1bb3c51
18ef669
3fedc6f
1942d78
5a1c46f
dcc55b0
ec70b3b
542cfbb
3af1ef1
6bc29a1
9052526
c38de34
106058c
f545b2f
0d1b38f
a597536
9d43727
bc96ae6
1d71dd1
e12337a
91a8c81
64bdfe2
88e0ea8
64b237c
97f6e14
834cdf0
99611cb
512cd2e
df176bf
576909d
adb54d8
d86652f
bca14a8
4eaece7
4930f6f
8670ee4
144a6fa
c2bbe17
a6bfc97
e21a76a
e12942d
64c070d
4a103fb
0bd7435
51908e9
e99f019
fde830d
c73f8ac
6a6bae2
3d23f56
99fa382
5a5e329
4a5ae8c
4e9740d
c49cf1c
1b45992
e5130a9
505d640
5053536
0242212
12f8c0e
db89f64
79714c2
9a33b7f
18894ca
67e0d25
4423794
66eb526
2eda2f9
8f97ae2
58c3c55
ca92d4a
3356eda
8274425
4405a5c
2d69426
4f4107a
65be3fd
78dbf36
a21eddd
d744c8a
6c76fe3
8dc4fc6
8044c7e
90ebfc4
e4ccb65
2ff4f36
992731d
12f19ce
268eb0e
d3b9e51
680e828
27eda47
be25a04
ae8c050
6e84d69
c523386
d565b0d
983764c
7f3c02d
656f35c
92ada68
24bd03f
fd1140c
fc66d1c
9dda41f
233f9e2
ef5a057
d2c14f7
09a3848
40e72e1
b33d161
b160409
8ffd7ff
cbc1b6f
6adbcbf
fdd24d6
9acd39d
e600102
add5f75
f811462
c4dd69b
60e2bb4
c7eac22
8bf685a
7cf0369
37c31d1
2d38baa
8d82237
a959249
cab1d5b
ee6630f
9b67932
475e2dc
126b60d
197e1ba
4074bc3
50c92d0
ce77fe4
193e216
30f7a09
ff41e0c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ extern "C" { | |
#include <stdbool.h> | ||
#include <stddef.h> // offsetof() | ||
#include "pycore_code.h" // STATS | ||
#include "pycore_stackref.h" // _PyStackRef | ||
|
||
/* See Objects/frame_layout.md for an explanation of the frame stack | ||
* including explanation of the PyFrameObject and _PyInterpreterFrame | ||
|
@@ -67,7 +68,7 @@ typedef struct _PyInterpreterFrame { | |
uint16_t return_offset; /* Only relevant during a function call */ | ||
char owner; | ||
/* Locals and stack */ | ||
PyObject *localsplus[1]; | ||
_PyStackRef localsplus[1]; | ||
} _PyInterpreterFrame; | ||
|
||
#define _PyInterpreterFrame_LASTI(IF) \ | ||
|
@@ -78,23 +79,23 @@ static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) { | |
return (PyCodeObject *)f->f_executable; | ||
} | ||
|
||
static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) { | ||
return f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus; | ||
static inline _PyStackRef *_PyFrame_Stackbase(_PyInterpreterFrame *f) { | ||
return (f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus); | ||
} | ||
|
||
static inline PyObject *_PyFrame_StackPeek(_PyInterpreterFrame *f) { | ||
static inline _PyStackRef _PyFrame_StackPeek(_PyInterpreterFrame *f) { | ||
assert(f->stacktop > _PyFrame_GetCode(f)->co_nlocalsplus); | ||
assert(f->localsplus[f->stacktop-1] != NULL); | ||
assert(PyStackRef_Get(f->localsplus[f->stacktop-1]) != NULL); | ||
return f->localsplus[f->stacktop-1]; | ||
} | ||
|
||
static inline PyObject *_PyFrame_StackPop(_PyInterpreterFrame *f) { | ||
static inline _PyStackRef _PyFrame_StackPop(_PyInterpreterFrame *f) { | ||
assert(f->stacktop > _PyFrame_GetCode(f)->co_nlocalsplus); | ||
f->stacktop--; | ||
return f->localsplus[f->stacktop]; | ||
} | ||
|
||
static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, PyObject *value) { | ||
static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, _PyStackRef value) { | ||
f->localsplus[f->stacktop] = value; | ||
f->stacktop++; | ||
} | ||
|
@@ -120,6 +121,12 @@ static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame * | |
// Don't leave a dangling pointer to the old frame when creating generators | ||
// and coroutines: | ||
dest->previous = NULL; | ||
#ifdef Py_GIL_DISABLED | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shouldn't be necessary. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The top-most frame doesn't necessarily have an up-to-date You could try to keep It's okay for the GC to look at objects that are marked as deferred because only the GC can free them, even if they are above |
||
PyCodeObject *co = (PyCodeObject *)dest->f_executable; | ||
Fidget-Spinner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for (int i = src->stacktop; i < co->co_nlocalsplus + co->co_stacksize; i++) { | ||
dest->localsplus[i] = PyStackRef_StealRef(NULL); | ||
Fidget-Spinner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
#endif | ||
} | ||
|
||
/* Consumes reference to func and locals. | ||
|
@@ -143,14 +150,24 @@ _PyFrame_Initialize( | |
frame->owner = FRAME_OWNED_BY_THREAD; | ||
|
||
for (int i = null_locals_from; i < code->co_nlocalsplus; i++) { | ||
frame->localsplus[i] = NULL; | ||
frame->localsplus[i] = PyStackRef_StealRef(NULL); | ||
} | ||
|
||
#ifdef Py_GIL_DISABLED | ||
// On GIL disabled, we walk the entire stack in GC. Since stacktop | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really don't like adding this sort of workaround. I would much rather fix the underlying issue. Why can't we make sure that stacktop is in sync with the real stack pointer anywhere that GC could occur? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A GC can occur at any There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I created #118926 for discussion on this. |
||
// is not always in sync with the real stack pointer, we have | ||
// no choice but to traverse the entire stack. | ||
// This just makes sure we don't pass the GC invalid stack values. | ||
for (int i = code->co_nlocalsplus; i < code->co_nlocalsplus + code->co_stacksize; i++) { | ||
frame->localsplus[i] = PyStackRef_StealRef(NULL); | ||
} | ||
#endif | ||
} | ||
|
||
/* Gets the pointer to the locals array | ||
* that precedes this frame. | ||
*/ | ||
static inline PyObject** | ||
static inline _PyStackRef* | ||
_PyFrame_GetLocalsArray(_PyInterpreterFrame *frame) | ||
{ | ||
return frame->localsplus; | ||
|
@@ -160,16 +177,16 @@ _PyFrame_GetLocalsArray(_PyInterpreterFrame *frame) | |
Having stacktop <= 0 ensures that invalid | ||
values are not visible to the cycle GC. | ||
We choose -1 rather than 0 to assist debugging. */ | ||
static inline PyObject** | ||
static inline _PyStackRef* | ||
_PyFrame_GetStackPointer(_PyInterpreterFrame *frame) | ||
{ | ||
PyObject **sp = frame->localsplus + frame->stacktop; | ||
_PyStackRef *sp = frame->localsplus + frame->stacktop; | ||
frame->stacktop = -1; | ||
return sp; | ||
} | ||
|
||
static inline void | ||
_PyFrame_SetStackPointer(_PyInterpreterFrame *frame, PyObject **stack_pointer) | ||
_PyFrame_SetStackPointer(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer) | ||
{ | ||
frame->stacktop = (int)(stack_pointer - frame->localsplus); | ||
} | ||
|
@@ -307,6 +324,12 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int | |
frame->instr_ptr = _PyCode_CODE(code); | ||
frame->owner = FRAME_OWNED_BY_THREAD; | ||
frame->return_offset = 0; | ||
#ifdef Py_GIL_DISABLED | ||
Fidget-Spinner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
assert(code->co_nlocalsplus == 0); | ||
for (int i = 0; i < code->co_stacksize; i++) { | ||
frame->localsplus[i] = PyStackRef_StealRef(NULL); | ||
} | ||
#endif | ||
return frame; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#ifndef Py_INTERNAL_OBJECT_DEFERRED_H | ||
Fidget-Spinner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#define Py_INTERNAL_OBJECT_DEFERRED_H | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#include "pycore_gc.h" | ||
|
||
#ifndef Py_BUILD_CORE | ||
# error "this header requires Py_BUILD_CORE define" | ||
#endif | ||
|
||
// Mark an object as supporting deferred reference counting. This is a no-op | ||
// in the default (with GIL) build. Objects that use deferred reference | ||
// counting should be tracked by the GC so that they are eventually collected. | ||
extern void _PyObject_SetDeferredRefcount(PyObject *op); | ||
|
||
static inline int | ||
_PyObject_HasDeferredRefcount(PyObject *op) | ||
{ | ||
#ifdef Py_GIL_DISABLED | ||
return (op->ob_gc_bits & _PyGC_BITS_DEFERRED) != 0; | ||
#else | ||
return 0; | ||
#endif | ||
} | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
#endif // !Py_INTERNAL_OBJECT_DEFERRED_H |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.