Thanks to visit codestin.com
Credit goes to github.com

Skip to content

bpo-45753: Move function object struct to an internal header. #29516

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

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
80 changes: 9 additions & 71 deletions Include/cpython/funcobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,7 @@
extern "C" {
#endif


#define COMMON_FIELDS(PREFIX) \
PyObject *PREFIX ## globals; \
PyObject *PREFIX ## builtins; \
PyObject *PREFIX ## name; \
PyObject *PREFIX ## qualname; \
PyObject *PREFIX ## code; /* A code object, the __code__ attribute */ \
PyObject *PREFIX ## defaults; /* NULL or a tuple */ \
PyObject *PREFIX ## kwdefaults; /* NULL or a dict */ \
PyObject *PREFIX ## closure; /* NULL or a tuple of cell objects */

typedef struct {
COMMON_FIELDS(fc_)
} PyFrameConstructor;

/* Function objects and code objects should not be confused with each other:
*
* Function objects are created by the execution of the 'def' statement.
* They reference a code object in their __code__ attribute, which is a
* purely syntactic object, i.e. nothing more than a compiled version of some
* source code lines. There is one code object per source code "fragment",
* but each code object can be referenced by zero or many function objects
* depending only on how many times the 'def' statement in the source was
* executed so far.
*/

typedef struct {
PyObject_HEAD
COMMON_FIELDS(func_)
PyObject *func_doc; /* The __doc__ attribute, can be anything */
PyObject *func_dict; /* The __dict__ attribute, a dict or NULL */
PyObject *func_weakreflist; /* List of weak references */
PyObject *func_module; /* The __module__ attribute, can be anything */
PyObject *func_annotations; /* Annotations, a dict or NULL */
vectorcallfunc vectorcall;
/* Version number for use by specializer.
* Can set to non-zero when we want to specialize.
* Will be set to zero if any of these change:
* defaults
* kwdefaults (only if the object changes, not the contents of the dict)
* code
* annotations */
uint32_t func_version;

/* Invariant:
* func_closure contains the bindings for func_code->co_freevars, so
* PyTuple_Size(func_closure) == PyCode_GetNumFree(func_code)
* (func_closure may be NULL if PyCode_GetNumFree(func_code) == 0).
*/
} PyFunctionObject;
typedef struct _functionobject PyFunctionObject;

PyAPI_DATA(PyTypeObject) PyFunction_Type;

Expand All @@ -82,27 +33,14 @@ PyAPI_FUNC(PyObject *) _PyFunction_Vectorcall(
size_t nargsf,
PyObject *kwnames);

uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func);

/* Macros for direct access to these values. Type checks are *not*
done, so use with care. */
#define PyFunction_GET_CODE(func) \
(((PyFunctionObject *)func) -> func_code)
#define PyFunction_GET_GLOBALS(func) \
(((PyFunctionObject *)func) -> func_globals)
#define PyFunction_GET_MODULE(func) \
(((PyFunctionObject *)func) -> func_module)
#define PyFunction_GET_DEFAULTS(func) \
(((PyFunctionObject *)func) -> func_defaults)
#define PyFunction_GET_KW_DEFAULTS(func) \
(((PyFunctionObject *)func) -> func_kwdefaults)
#define PyFunction_GET_CLOSURE(func) \
(((PyFunctionObject *)func) -> func_closure)
#define PyFunction_GET_ANNOTATIONS(func) \
(((PyFunctionObject *)func) -> func_annotations)

#define PyFunction_AS_FRAME_CONSTRUCTOR(func) \
((PyFrameConstructor *)&((PyFunctionObject *)(func))->func_globals)
/* Macros for backwards compatibility. */
#define PyFunction_GET_CODE(func) PyFunction_GetCode(func)
#define PyFunction_GET_GLOBALS(func) PyFunction_GetGlobals(func)
#define PyFunction_GET_MODULE(func) PyFunction_GetModule(func)
#define PyFunction_GET_DEFAULTS(func) PyFunction_GetDefaults(func)
#define PyFunction_GET_KW_DEFAULTS(func) PyFunction_GetKwDefaults(func)
#define PyFunction_GET_CLOSURE(func) PyFunction_GetClosure(func)
#define PyFunction_GET_ANNOTATIONS(func) PyFunction_GetAnnotations(func)

/* The classmethod and staticmethod types lives here, too */
PyAPI_DATA(PyTypeObject) PyClassMethod_Type;
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extern "C" {
struct pyruntimestate;
struct _ceval_runtime_state;

#include "pycore_function.h" // PyFrameConstructor
#include "pycore_interp.h" // PyInterpreterState.eval_frame
#include "pycore_pystate.h" // _PyThreadState_GET()

Expand Down
2 changes: 2 additions & 0 deletions Include/internal/pycore_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
extern "C" {
#endif

#include "pycore_function.h" // PyFrameConstructor

/* These values are chosen so that the inline functions below all
* compare f_state to zero.
*/
Expand Down
63 changes: 63 additions & 0 deletions Include/internal/pycore_function.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#ifndef PYCORE_FUNCTION_H
#define PYCORE_FUNCTION_H

#define COMMON_FIELDS(PREFIX) \
PyObject *PREFIX ## globals; \
PyObject *PREFIX ## builtins; \
PyObject *PREFIX ## name; \
PyObject *PREFIX ## qualname; \
PyObject *PREFIX ## code; /* A code object, the __code__ attribute */ \
PyObject *PREFIX ## defaults; /* NULL or a tuple */ \
PyObject *PREFIX ## kwdefaults; /* NULL or a dict */ \
PyObject *PREFIX ## closure; /* NULL or a tuple of cell objects */

typedef struct {
COMMON_FIELDS(fc_)
} PyFrameConstructor;

/* Function objects and code objects should not be confused with each other:
*
* Function objects are created by the execution of the 'def' statement.
* They reference a code object in their __code__ attribute, which is a
* purely syntactic object, i.e. nothing more than a compiled version of some
* source code lines. There is one code object per source code "fragment",
* but each code object can be referenced by zero or many function objects
* depending only on how many times the 'def' statement in the source was
* executed so far.
*/

typedef struct _functionobject {
PyObject_HEAD
COMMON_FIELDS(func_)
PyObject *func_doc; /* The __doc__ attribute, can be anything */
PyObject *func_dict; /* The __dict__ attribute, a dict or NULL */
PyObject *func_weakreflist; /* List of weak references */
PyObject *func_module; /* The __module__ attribute, can be anything */
PyObject *func_annotations; /* Annotations, a dict or NULL */
vectorcallfunc vectorcall;
/* Version number for use by specializer.
* Can set to non-zero when we want to specialize.
* Will be set to zero if any of these change:
* defaults
* kwdefaults (only if the object changes, not the contents of the dict)
* code
* annotations */
uint32_t func_version;

/* Invariant:
* func_closure contains the bindings for func_code->co_freevars, so
* PyTuple_Size(func_closure) == PyCode_GetNumFree(func_code)
* (func_closure may be NULL if PyCode_GetNumFree(func_code) == 0).
*/
} PyFunctionObject;

#define PyFunction_AS_FRAME_CONSTRUCTOR(func) \
((PyFrameConstructor *)&((PyFunctionObject *)(func))->func_globals)

uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func);


#ifdef __cplusplus
}
#endif
#endif // PYCORE_FUNCTION_H
2 changes: 2 additions & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,8 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_dtoa.h \
$(srcdir)/Include/internal/pycore_fileutils.h \
$(srcdir)/Include/internal/pycore_floatobject.h \
$(srcdir)/Include/internal/pycore_frame.h \
$(srcdir)/Include/internal/pycore_function.h \
$(srcdir)/Include/internal/pycore_format.h \
$(srcdir)/Include/internal/pycore_getopt.h \
$(srcdir)/Include/internal/pycore_gil.h \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Move the PyFunctionObject struct to an internal header.

The meaning to the internal fields of the function was never defined and
could result in subtle bugs if misused. This move makes that clearer.
1 change: 1 addition & 0 deletions Objects/call.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "Python.h"
#include "pycore_call.h" // _PyObject_CallNoArgsTstate()
#include "pycore_ceval.h" // _PyEval_EvalFrame()
#include "pycore_function.h" // PyFrameConstructor
#include "pycore_object.h" // _PyObject_GC_TRACK()
#include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "pycore_pystate.h" // _PyThreadState_GET()
Expand Down
2 changes: 2 additions & 0 deletions PCbuild/pythoncore.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@
<ClInclude Include="..\Include\internal\pycore_dtoa.h" />
<ClInclude Include="..\Include\internal\pycore_fileutils.h" />
<ClInclude Include="..\Include\internal\pycore_floatobject.h" />
<ClInclude Include="..\Include\internal\pycore_frame.h" />
<ClInclude Include="..\Include\internal\pycore_function.h" />
<ClInclude Include="..\Include\internal\pycore_format.h" />
<ClInclude Include="..\Include\internal\pycore_gc.h" />
<ClInclude Include="..\Include\internal\pycore_getopt.h" />
Expand Down
6 changes: 6 additions & 0 deletions PCbuild/pythoncore.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,12 @@
<ClInclude Include="..\Include\internal\pycore_floatobject.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_frame.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_function.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_format.h">
<Filter>Include\internal</Filter>
</ClInclude>
Expand Down
1 change: 1 addition & 0 deletions Python/bltinmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "pycore_ast.h" // _PyAST_Validate()
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_compile.h" // _PyAST_Compile()
#include "pycore_function.h" // PyFrameConstructor
#include "pycore_object.h" // _Py_AddToAllObjects()
#include "pycore_pyerrors.h" // _PyErr_NoMemory()
#include "pycore_pystate.h" // _PyThreadState_GET()
Expand Down
4 changes: 3 additions & 1 deletion Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "pycore_call.h" // _PyObject_FastCallDictTstate()
#include "pycore_ceval.h" // _PyEval_SignalAsyncExc()
#include "pycore_code.h"
#include "pycore_function.h"
#include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_object.h" // _PyObject_GC_TRACK()
Expand Down Expand Up @@ -4625,7 +4626,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
}
// Check if the call can be inlined or not
if (Py_TYPE(function) == &PyFunction_Type && tstate->interp->eval_frame == NULL) {
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(function))->co_flags;
PyFunctionObject *func = (PyFunctionObject *)function;
int code_flags = ((PyCodeObject*)func->func_code)->co_flags;
int is_generator = code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR);
if (!is_generator) {
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : PyFunction_GET_GLOBALS(function);
Expand Down
1 change: 1 addition & 0 deletions Python/specialize.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "Python.h"
#include "pycore_code.h"
#include "pycore_function.h"
#include "pycore_dict.h"
#include "pycore_long.h"
#include "pycore_moduleobject.h"
Expand Down