From 00af5b53ffc221c19636d27f43db0173404d40f8 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 3 Jan 2023 16:40:53 +0000 Subject: [PATCH 1/8] gh-100720: refactor calculation of number of frame slots for a code object into the new function _PyCode_GetNumFrameSlots --- Include/internal/pycore_code.h | 2 ++ Objects/codeobject.c | 7 +++++++ Objects/frameobject.c | 2 +- Objects/genobject.c | 4 ++-- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 9e59fc98bf3d57..8d1bb8c52e26b0 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -199,6 +199,8 @@ extern PyObject* _PyCode_GetCellvars(PyCodeObject *); extern PyObject* _PyCode_GetFreevars(PyCodeObject *); extern PyObject* _PyCode_GetCode(PyCodeObject *); +extern int _PyCode_GetNumFrameSlots(PyCodeObject *); + /** API for initializing the line number tables. */ extern int _PyCode_InitAddressRange(PyCodeObject* co, PyCodeAddressRange *bounds); diff --git a/Objects/codeobject.c b/Objects/codeobject.c index e174c6fee9cc24..070b1d934af459 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1520,6 +1520,13 @@ PyCode_GetFreevars(PyCodeObject *code) return _PyCode_GetFreevars(code); } +int +_PyCode_GetNumFrameSlots(PyCodeObject *code) +{ + assert(code->co_framesize - FRAME_SPECIALS_SIZE >= 0); + return code->co_framesize - FRAME_SPECIALS_SIZE; +} + static void deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len) { diff --git a/Objects/frameobject.c b/Objects/frameobject.c index eab85c08fc0165..2780357b015291 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -946,7 +946,7 @@ frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored)) Py_ssize_t res; res = offsetof(PyFrameObject, _f_frame_data) + offsetof(_PyInterpreterFrame, localsplus); PyCodeObject *code = f->f_frame->f_code; - res += (code->co_nlocalsplus+code->co_stacksize) * sizeof(PyObject *); + res += _PyCode_GetNumFrameSlots(code) * sizeof(PyObject *); return PyLong_FromSsize_t(res); } diff --git a/Objects/genobject.c b/Objects/genobject.c index c006f1af2177f9..26aee2b3864cb9 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -769,7 +769,7 @@ gen_sizeof(PyGenObject *gen, PyObject *Py_UNUSED(ignored)) Py_ssize_t res; res = offsetof(PyGenObject, gi_iframe) + offsetof(_PyInterpreterFrame, localsplus); PyCodeObject *code = gen->gi_code; - res += (code->co_nlocalsplus+code->co_stacksize) * sizeof(PyObject *); + res += _PyCode_GetNumFrameSlots(code) * sizeof(PyObject *); return PyLong_FromSsize_t(res); } @@ -850,7 +850,7 @@ static PyObject * make_gen(PyTypeObject *type, PyFunctionObject *func) { PyCodeObject *code = (PyCodeObject *)func->func_code; - int slots = code->co_nlocalsplus + code->co_stacksize; + int slots = _PyCode_GetNumFrameSlots(code); PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, slots); if (gen == NULL) { return NULL; From 7194bd19d7aa27e5675b0eba1dc5aa65d1fea957 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 3 Jan 2023 16:50:44 +0000 Subject: [PATCH 2/8] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst new file mode 100644 index 00000000000000..8932b27fc7153e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst @@ -0,0 +1 @@ +Added `_PyCode_GetNumFrameSlots`, which returns the number of slots needed in a frame for a given code object. From 342397e7831edd3e1517c7578529da28315ef137 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 3 Jan 2023 17:06:13 +0000 Subject: [PATCH 3/8] fix news formatting and signed/unsigned comparison --- .../2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst | 2 +- Objects/codeobject.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst index 8932b27fc7153e..ba2d843df52e7b 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst @@ -1 +1 @@ -Added `_PyCode_GetNumFrameSlots`, which returns the number of slots needed in a frame for a given code object. +Added ``_PyCode_GetNumFrameSlots``, which returns the number of slots needed in a frame for a given code object. diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 070b1d934af459..987ce61beacb32 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1523,7 +1523,7 @@ PyCode_GetFreevars(PyCodeObject *code) int _PyCode_GetNumFrameSlots(PyCodeObject *code) { - assert(code->co_framesize - FRAME_SPECIALS_SIZE >= 0); + assert(code->co_framesize >= (int)FRAME_SPECIALS_SIZE); return code->co_framesize - FRAME_SPECIALS_SIZE; } From 4b0cb9169ea1750958bf9b2df712b0e383b9e088 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 3 Jan 2023 20:18:31 +0000 Subject: [PATCH 4/8] add comments that deepfreeze.py and Objects/codeobject.c need to be kept in sync --- Objects/codeobject.c | 1 + Tools/build/deepfreeze.py | 1 + 2 files changed, 2 insertions(+) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 987ce61beacb32..106f8f9cfe39d0 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1523,6 +1523,7 @@ PyCode_GetFreevars(PyCodeObject *code) int _PyCode_GetNumFrameSlots(PyCodeObject *code) { + /* This function needs to remain in sync with Tools/build/deepfreeze.py */ assert(code->co_framesize >= (int)FRAME_SPECIALS_SIZE); return code->co_framesize - FRAME_SPECIALS_SIZE; } diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 7f4e24280133f2..ca3d004e6fd979 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -262,6 +262,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.field(code, "co_argcount") self.field(code, "co_posonlyargcount") self.field(code, "co_kwonlyargcount") + # The following should remain in sync with _PyCode_GetNumFrameSlots self.write(f".co_framesize = {code.co_stacksize + len(localsplusnames)} + FRAME_SPECIALS_SIZE,") self.field(code, "co_stacksize") self.field(code, "co_firstlineno") From b4d44083b0feb5454856104993b828d9e299c384 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 3 Jan 2023 22:51:08 +0000 Subject: [PATCH 5/8] clearer comment --- Objects/codeobject.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 106f8f9cfe39d0..0713a88f9d0e55 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1523,7 +1523,8 @@ PyCode_GetFreevars(PyCodeObject *code) int _PyCode_GetNumFrameSlots(PyCodeObject *code) { - /* This function needs to remain in sync with Tools/build/deepfreeze.py */ + /* This function needs to remain in sync with the calculation of + * co_framesize in Tools/build/deepfreeze.py */ assert(code->co_framesize >= (int)FRAME_SPECIALS_SIZE); return code->co_framesize - FRAME_SPECIALS_SIZE; } From bc5d99282cbb8db783cacca30deab125bc071c00 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 4 Jan 2023 11:27:36 +0000 Subject: [PATCH 6/8] move cast to macro --- Include/internal/pycore_frame.h | 2 +- Objects/codeobject.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index f18723b303224f..95d76f2193a3d3 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -92,7 +92,7 @@ static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, PyObject *value) { f->stacktop++; } -#define FRAME_SPECIALS_SIZE ((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *)) +#define FRAME_SPECIALS_SIZE ((int)((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *))) void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest); diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 0713a88f9d0e55..2c9eb312085de9 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1525,7 +1525,7 @@ _PyCode_GetNumFrameSlots(PyCodeObject *code) { /* This function needs to remain in sync with the calculation of * co_framesize in Tools/build/deepfreeze.py */ - assert(code->co_framesize >= (int)FRAME_SPECIALS_SIZE); + assert(code->co_framesize >= FRAME_SPECIALS_SIZE); return code->co_framesize - FRAME_SPECIALS_SIZE; } From 6a46ae3e5474b322836358ceccc07d734326c71c Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 4 Jan 2023 11:52:30 +0000 Subject: [PATCH 7/8] _PyCode_GetNumFrameSlots --> _PyFrame_NumSlotsForCodeObject. Move it to pycore_frame.h and make it static inline --- Include/internal/pycore_code.h | 2 -- Include/internal/pycore_frame.h | 9 +++++++++ Objects/codeobject.c | 9 --------- Objects/frameobject.c | 2 +- Objects/genobject.c | 4 ++-- Tools/build/deepfreeze.py | 2 +- 6 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 8d1bb8c52e26b0..9e59fc98bf3d57 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -199,8 +199,6 @@ extern PyObject* _PyCode_GetCellvars(PyCodeObject *); extern PyObject* _PyCode_GetFreevars(PyCodeObject *); extern PyObject* _PyCode_GetCode(PyCodeObject *); -extern int _PyCode_GetNumFrameSlots(PyCodeObject *); - /** API for initializing the line number tables. */ extern int _PyCode_InitAddressRange(PyCodeObject* co, PyCodeAddressRange *bounds); diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 95d76f2193a3d3..d5c1dcc82a883d 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -94,6 +94,15 @@ static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, PyObject *value) { #define FRAME_SPECIALS_SIZE ((int)((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *))) +static inline int +_PyFrame_NumSlotsForCodeObject(PyCodeObject *code) +{ + /* This function needs to remain in sync with the calculation of + * co_framesize in Tools/build/deepfreeze.py */ + assert(code->co_framesize >= FRAME_SPECIALS_SIZE); + return code->co_framesize - FRAME_SPECIALS_SIZE; +} + void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest); /* Consumes reference to func and locals. diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 2c9eb312085de9..e174c6fee9cc24 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1520,15 +1520,6 @@ PyCode_GetFreevars(PyCodeObject *code) return _PyCode_GetFreevars(code); } -int -_PyCode_GetNumFrameSlots(PyCodeObject *code) -{ - /* This function needs to remain in sync with the calculation of - * co_framesize in Tools/build/deepfreeze.py */ - assert(code->co_framesize >= FRAME_SPECIALS_SIZE); - return code->co_framesize - FRAME_SPECIALS_SIZE; -} - static void deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len) { diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 2780357b015291..98f0b3838723da 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -946,7 +946,7 @@ frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored)) Py_ssize_t res; res = offsetof(PyFrameObject, _f_frame_data) + offsetof(_PyInterpreterFrame, localsplus); PyCodeObject *code = f->f_frame->f_code; - res += _PyCode_GetNumFrameSlots(code) * sizeof(PyObject *); + res += _PyFrame_NumSlotsForCodeObject(code) * sizeof(PyObject *); return PyLong_FromSsize_t(res); } diff --git a/Objects/genobject.c b/Objects/genobject.c index 26aee2b3864cb9..ea3382d3e31a34 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -769,7 +769,7 @@ gen_sizeof(PyGenObject *gen, PyObject *Py_UNUSED(ignored)) Py_ssize_t res; res = offsetof(PyGenObject, gi_iframe) + offsetof(_PyInterpreterFrame, localsplus); PyCodeObject *code = gen->gi_code; - res += _PyCode_GetNumFrameSlots(code) * sizeof(PyObject *); + res += _PyFrame_NumSlotsForCodeObject(code) * sizeof(PyObject *); return PyLong_FromSsize_t(res); } @@ -850,7 +850,7 @@ static PyObject * make_gen(PyTypeObject *type, PyFunctionObject *func) { PyCodeObject *code = (PyCodeObject *)func->func_code; - int slots = _PyCode_GetNumFrameSlots(code); + int slots = _PyFrame_NumSlotsForCodeObject(code); PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, slots); if (gen == NULL) { return NULL; diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index ca3d004e6fd979..e4b422820f7db7 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -262,7 +262,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.field(code, "co_argcount") self.field(code, "co_posonlyargcount") self.field(code, "co_kwonlyargcount") - # The following should remain in sync with _PyCode_GetNumFrameSlots + # The following should remain in sync with _PyFrame_NumSlotsForCodeObject self.write(f".co_framesize = {code.co_stacksize + len(localsplusnames)} + FRAME_SPECIALS_SIZE,") self.field(code, "co_stacksize") self.field(code, "co_firstlineno") From 76b8cabcb0064da0af7eaa31ad3b2490463c1fcb Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Wed, 4 Jan 2023 11:54:14 +0000 Subject: [PATCH 8/8] update news file --- .../2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst index ba2d843df52e7b..4c194eccf8a5cc 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2023-01-03-16-50-42.gh-issue-100720.UhE7P-.rst @@ -1 +1 @@ -Added ``_PyCode_GetNumFrameSlots``, which returns the number of slots needed in a frame for a given code object. +Added ``_PyFrame_NumSlotsForCodeObject``, which returns the number of slots needed in a frame for a given code object.