Skip to content
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

gh-117139: Set up the tagged evaluation stack #117186

Closed
Closed
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
7ca9b11
Tag objects in ceval, type, gen, frame
Fidget-Spinner Mar 23, 2024
09dbeca
partially convert cases
Fidget-Spinner Mar 23, 2024
84142a5
fix the rest
Fidget-Spinner Mar 23, 2024
25bf135
fixups
Fidget-Spinner Mar 23, 2024
d484628
fix all remaining warnings
Fidget-Spinner Mar 26, 2024
744357e
fix tests
Fidget-Spinner Mar 26, 2024
4cc9fb8
fix frames
Fidget-Spinner Mar 26, 2024
8423e75
Merge remote-tracking branch 'upstream/main' into tagged_evaluation_s…
Fidget-Spinner Mar 26, 2024
6b9ad92
📜🤖 Added by blurb_it.
blurb-it[bot] Mar 26, 2024
0bb6def
fix mypy errors
Fidget-Spinner Mar 26, 2024
8fe65c1
Merge branch 'tagged_evaluation_stack' of github.com:Fidget-Spinner/c…
Fidget-Spinner Mar 26, 2024
8412d46
fix mypy for real this time
Fidget-Spinner Mar 26, 2024
973c41c
fix windows builds
Fidget-Spinner Mar 26, 2024
4428279
fix JIT builds
Fidget-Spinner Mar 26, 2024
a4917ae
untag into temp stack for vectorcall
Fidget-Spinner Mar 27, 2024
3f7f25a
address review
Fidget-Spinner Mar 27, 2024
adfbd43
remove .obj field
Fidget-Spinner Mar 27, 2024
868b78e
add ways to test this
Fidget-Spinner Mar 27, 2024
6024a4b
minor fixups
Fidget-Spinner Mar 27, 2024
b1a614b
fix all remaining uses of PyObject **
Fidget-Spinner Mar 29, 2024
e4fa6da
minor fix
Fidget-Spinner Mar 29, 2024
7bead7f
fixed gdb
Fidget-Spinner Mar 29, 2024
eb9e9a5
move tags to internal header
Fidget-Spinner Mar 29, 2024
59b237a
replace incref decrefs with tagged versions
Fidget-Spinner Mar 29, 2024
b566e39
no-op tags on default build
Fidget-Spinner Mar 29, 2024
a036f57
fix operator associativity
Fidget-Spinner Mar 29, 2024
02408cc
Merge remote-tracking branch 'upstream/main' into tagged_evaluation_s…
Fidget-Spinner Mar 29, 2024
6b1bcf3
rename to tag/untag
Fidget-Spinner Mar 29, 2024
340f5e1
rename as requested
Fidget-Spinner Mar 29, 2024
7471fe3
default to tagged pointers in cases generator (part 1)
Fidget-Spinner Mar 29, 2024
8be49a5
(broken) convert default to tagged ptr
Fidget-Spinner Mar 29, 2024
5e2018c
swap order of tags and refcounts
Fidget-Spinner Mar 29, 2024
adff67f
Merge remote-tracking branch 'upstream/main' into tagged_evaluation_s…
Fidget-Spinner Apr 1, 2024
c09ddee
minor fixes (still broken)
Fidget-Spinner Apr 1, 2024
515536e
bunch of fixes
Fidget-Spinner Apr 1, 2024
7d7ef29
fix everything
Fidget-Spinner Apr 1, 2024
4be812f
fix some tests
Fidget-Spinner Apr 1, 2024
2f972c5
Merge remote-tracking branch 'upstream/main' into tagged_evaluation_s…
Fidget-Spinner Apr 7, 2024
72ff61b
fix up warnings
Fidget-Spinner Apr 7, 2024
2e9b411
Rename _PyTaggedPtr -> _PyStackRef
Fidget-Spinner Apr 7, 2024
b5e4c83
make ownership clear in tagging and untagging
Fidget-Spinner Apr 7, 2024
175700c
further cleanup
Fidget-Spinner Apr 7, 2024
b75c171
rename tagged -> stackref
Fidget-Spinner Apr 7, 2024
ed3a3e6
Introduced owned references
Fidget-Spinner Apr 7, 2024
6e7a917
fix syntaxerror on nogil
Fidget-Spinner Apr 7, 2024
4675ce8
Fix mypy errors
Fidget-Spinner Apr 7, 2024
629a303
fix slices
Fidget-Spinner Apr 10, 2024
4170db1
Merge remote-tracking branch 'upstream/main' into tagged_evaluation_s…
Fidget-Spinner Apr 10, 2024
038cb8a
Merge Sam's deferred refcounting in
Fidget-Spinner Apr 10, 2024
65da5a0
Fix STORE_SUBSCR, and friends
Fidget-Spinner Apr 10, 2024
6a9e1bc
traverse the stack in GC
Fidget-Spinner Apr 11, 2024
bc2a6ec
fix bugs in frame pushing and popping
Fidget-Spinner Apr 12, 2024
3bb3de2
fix for shim frames
Fidget-Spinner Apr 12, 2024
8afd8b6
stackref -> tagged
Fidget-Spinner Apr 12, 2024
87fda3e
Merge remote-tracking branch 'upstream/main' into tagged_evaluation_s…
Fidget-Spinner Apr 12, 2024
3269f20
Fix _PyFrame_Copy
Fidget-Spinner Apr 12, 2024
693b64b
fix memleak and address sam's comment
Fidget-Spinner Apr 12, 2024
03af3a4
all tests pass except references
Fidget-Spinner Apr 13, 2024
aef8e3c
Fix some refleaks
Fidget-Spinner Apr 13, 2024
87112bb
fix another references
Fidget-Spinner Apr 13, 2024
a34cec8
clean up a little
Fidget-Spinner Apr 13, 2024
5b4ddb6
undo gc changes
Fidget-Spinner Apr 13, 2024
019bc3d
rename stack to stackref
Fidget-Spinner Apr 16, 2024
b38e507
defer stack for bound methods
Fidget-Spinner Apr 16, 2024
933b5b4
fix a bunch of ownership, and deferred methods
Fidget-Spinner Apr 24, 2024
11af18d
Merge remote-tracking branch 'upstream/main' into tagged_evaluation_s…
Fidget-Spinner Apr 24, 2024
1bbf021
fix upstream merge conflicts
Fidget-Spinner Apr 24, 2024
bd6889b
Merge remote-tracking branch 'upstream/main' into tagged_evaluation_s…
Fidget-Spinner Apr 25, 2024
bafd342
fix merge conflicts
Fidget-Spinner Apr 25, 2024
752a49b
lint
Fidget-Spinner Apr 25, 2024
c6be5aa
use old code, fix decref on traceback
Fidget-Spinner Apr 26, 2024
d59145b
make bound methods work for keyword calls as well
Fidget-Spinner Apr 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Include/cpython/tupleobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ PyTuple_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) {
PyTupleObject *tuple = _PyTuple_CAST(op);
assert(0 <= index);
assert(index < Py_SIZE(tuple));
#ifdef Py_TAG_TEST
// Make sure it's not a tagged pointer
assert(((uintptr_t)op & Py_TAG_TEST) == 0);
#endif
tuple->ob_item[index] = value;
}
#define PyTuple_SET_ITEM(op, index, value) \
Expand Down
18 changes: 18 additions & 0 deletions Include/internal/pycore_call.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,24 @@ extern void _PyStack_UnpackDict_FreeNoDecRef(
PyObject *const *stack,
PyObject *kwnames);

PyAPI_FUNC(PyObject *)
PyObject_Vectorcall_Tagged(PyObject *callable,
const _PyStackRef *tagged, size_t nargs, PyObject *kwnames);

PyAPI_FUNC(PyObject *)
PyObject_TypeVectorcall_Tagged(PyTypeObject *callable,
const _PyStackRef *tagged, size_t nargs, PyObject *kwnames);

PyAPI_FUNC(PyObject *)
PyObject_PyCFunctionFastCall_Tagged(PyCFunctionFast cfunc,
PyObject *self,
const _PyStackRef *tagged, Py_ssize_t nargs);
PyAPI_FUNC(PyObject *)
PyObject_PyCFunctionFastWithKeywordsCall_Tagged(PyCFunctionFastWithKeywords cfunc,
PyObject *self,
const _PyStackRef *tagged, Py_ssize_t nargs,
PyObject *kwds);

#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *c
PyAPI_FUNC(void) _PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwargs);
PyAPI_FUNC(PyObject *)_PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type, Py_ssize_t nargs, PyObject *kwargs);
PyAPI_FUNC(PyObject *)_PyEval_MatchKeys(PyThreadState *tstate, PyObject *map, PyObject *keys);
PyAPI_FUNC(int) _PyEval_UnpackIterable(PyThreadState *tstate, PyObject *v, int argcnt, int argcntafter, PyObject **sp);
PyAPI_FUNC(int) _PyEval_UnpackTaggedIterable(PyThreadState *tstate, PyObject *v, int argcnt, int argcntafter, _PyStackRef *sp);
PyAPI_FUNC(void) _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame);


Expand Down
3 changes: 2 additions & 1 deletion Include/internal/pycore_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif

#include "pycore_tagged.h" // _PyStackRef

// We hide some of the newer PyCodeObject fields behind macros.
// This helps with backporting certain changes to 3.12.
Expand Down Expand Up @@ -278,7 +279,7 @@ extern void _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub,
extern void _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr,
int nargs);
extern void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
int oparg, PyObject **locals);
int oparg, _PyStackRef *locals);
extern void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs,
_Py_CODEUNIT *instr, int oparg);
extern void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr,
Expand Down
8 changes: 8 additions & 0 deletions Include/internal/pycore_dict.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,14 @@ PyAPI_FUNC(PyObject *)_PyDict_FromItems(
PyObject *const *keys, Py_ssize_t keys_offset,
PyObject *const *values, Py_ssize_t values_offset,
Py_ssize_t length);
PyAPI_FUNC(PyObject *)_PyDict_FromStackItems(
_PyStackRef const *keys, Py_ssize_t keys_offset,
_PyStackRef const *values, Py_ssize_t values_offset,
Py_ssize_t length);
PyAPI_FUNC(PyObject *)_PyDict_FromStackItemsUntaggedKeys(
PyObject *const *keys, Py_ssize_t keys_offset,
_PyStackRef const *values, Py_ssize_t values_offset,
Py_ssize_t length);

static inline uint8_t *
get_insertion_order_array(PyDictValues *values)
Expand Down
41 changes: 29 additions & 12 deletions Include/internal/pycore_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ extern "C" {
#include <stdbool.h>
#include <stddef.h> // offsetof()
#include "pycore_code.h" // STATS
#include "pycore_tagged.h" // _PyStackRef

/* See Objects/frame_layout.md for an explanation of the frame stack
* including explanation of the PyFrameObject and _PyInterpreterFrame
Expand Down Expand Up @@ -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) \
Expand All @@ -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(Py_STACK_UNTAG_BORROWED(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++;
}
Expand Down Expand Up @@ -133,14 +134,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] = Py_STACK_TAG(NULL);
}

#ifdef Py_GIL_DISABLED
// On GIL disabled, we walk the entire stack in GC. Since stacktop
// 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] = Py_STACK_TAG(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;
Expand All @@ -150,16 +161,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);
}
Expand Down Expand Up @@ -294,6 +305,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
assert(code->co_nlocalsplus == 0);
for (int i = 0; i < code->co_stacksize; i++) {
frame->localsplus[i] = Py_STACK_TAG(NULL);
}
#endif
return frame;
}

Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_jit.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ extern "C" {

#ifdef _Py_JIT

typedef _Py_CODEUNIT *(*jit_func)(_PyInterpreterFrame *frame, PyObject **stack_pointer, PyThreadState *tstate);
typedef _Py_CODEUNIT *(*jit_func)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate);

int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length);
void _PyJIT_Free(_PyExecutorObject *executor);
Expand Down
3 changes: 2 additions & 1 deletion Include/internal/pycore_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extern "C" {
#endif

#include "pycore_freelist.h" // _PyFreeListState
#include "pycore_tagged.h" // _PyStackRef

PyAPI_FUNC(PyObject*) _PyList_Extend(PyListObject *, PyObject *);
extern void _PyList_DebugMallocStats(FILE *out);
Expand Down Expand Up @@ -54,7 +55,7 @@ typedef struct {
PyListObject *it_seq; /* Set to NULL when iterator is exhausted */
} _PyListIterObject;

PyAPI_FUNC(PyObject *)_PyList_FromArraySteal(PyObject *const *src, Py_ssize_t n);
PyAPI_FUNC(PyObject *)_PyList_FromStackSteal(_PyStackRef const *src, Py_ssize_t n);

#ifdef __cplusplus
}
Expand Down
14 changes: 0 additions & 14 deletions Include/internal/pycore_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,20 +158,6 @@ static inline void _Py_ClearImmortal(PyObject *op)
op = NULL; \
} while (0)

// 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
}

#if !defined(Py_GIL_DISABLED)
static inline void
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_opcode_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Include/internal/pycore_optimizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ extern int _Py_uop_frame_pop(_Py_UOpsContext *ctx);

PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored);

PyAPI_FUNC(int) _PyOptimizer_Optimize(_PyInterpreterFrame *frame, _Py_CODEUNIT *start, PyObject **stack_pointer, _PyExecutorObject **exec_ptr);
PyAPI_FUNC(int) _PyOptimizer_Optimize(_PyInterpreterFrame *frame, _Py_CODEUNIT *start, _PyStackRef *stack_pointer, _PyExecutorObject **exec_ptr);

#ifdef __cplusplus
}
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_sliceobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extern "C" {
/* runtime lifecycle */

PyAPI_FUNC(PyObject *)
_PyBuildSlice_ConsumeRefs(PyObject *start, PyObject *stop);
_PyBuildSlice_ConsumeStackRefs(_PyStackRef start, _PyStackRef stop);

#ifdef __cplusplus
}
Expand Down
Loading
Loading