From 3d5826b52e7c916b496151bea2dae6211b0cc90e Mon Sep 17 00:00:00 2001 From: WildCard65 Date: Wed, 1 Jul 2020 11:53:49 -0400 Subject: [PATCH 1/6] Added new type member 'tp_obj_offset'. This member is the companion member required for 'Py_TPFLAGS_USES_OPAQUE_OBJECT' flag. --- Doc/c-api/typeobj.rst | 8 ++++++++ Include/cpython/object.h | 2 ++ Include/object.h | 3 +++ 3 files changed, 13 insertions(+) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 385c7f94c672f2..0453438fa1821d 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -147,6 +147,8 @@ Quick Reference +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ | :c:member:`~PyTypeObject.tp_vectorcall` | :c:type:`vectorcallfunc` | | | | | | +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ + | :c:member:`~PyTypeObject.tp_obj_offset` | const Py_ssize_t | | | X | ~ | | + +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ .. [#slots] A slot name in parentheses indicates it is (effectively) deprecated. @@ -1015,6 +1017,12 @@ and :c:type:`PyType_Type` effectively act as defaults.) :c:func:`PyType_HasFeature` takes a type and a flags value, *tp* and *f*, and checks whether ``tp->tp_flags & f`` is non-zero. + .. data:: Py_TPFLAGS_USES_OPAQUE_OBJECT + + This bit is set when the type object's :c:member:`PyTypeObject.tp_basicsize` is configured + for an opaque :c:type:`PyObject` structure. The value of :c:member:`PyTypeObject.tp_basicsize` is the size of the type's + internal object structure EXCLUDING the base type's structure size. + .. data:: Py_TPFLAGS_HEAPTYPE This bit is set when the type object itself is allocated on the heap, for diff --git a/Include/cpython/object.h b/Include/cpython/object.h index ae3920d4508e14..584883055dc681 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -263,6 +263,8 @@ struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; + /* INTERNAL USE ONLY! MODIFYING THIS CAN CRASH PYTHON! */ + const Py_ssize_t tp_obj_offset; }; /* The *real* layout of a type object when allocated on the heap */ diff --git a/Include/object.h b/Include/object.h index 537567040f9871..536167c27a62fd 100644 --- a/Include/object.h +++ b/Include/object.h @@ -317,6 +317,9 @@ Code can use PyType_HasFeature(type_ob, flag_value) to test whether the given type object has a specified feature. */ +/* Set if the type object's tp_basicsize is set for opague object */ +#define Py_TPFLAGS_OPAQUE_OBJECT (1UL << 8) + /* Set if the type object is dynamically allocated */ #define Py_TPFLAGS_HEAPTYPE (1UL << 9) From ff05339dcace5cfc707a8b2aaf8314b6ba2e897f Mon Sep 17 00:00:00 2001 From: WildCard65 Date: Wed, 1 Jul 2020 14:54:28 -0400 Subject: [PATCH 2/6] Added static library "slib_pythoncore" to act as a medium between CPython's internals and external users. Note: This static library is incomplete. --- Include/object.h | 53 +++++++++-- Include/pyport.h | 2 + PC/pyconfig.h | 7 ++ PCbuild/pcbuild.sln | 30 +++++++ PCbuild/pythoncore.vcxproj | 8 +- PCbuild/slib_pythoncore.vcxproj | 113 ++++++++++++++++++++++++ PCbuild/slib_pythoncore.vcxproj.filters | 25 ++++++ SLib/object.c | 61 +++++++++++++ 8 files changed, 292 insertions(+), 7 deletions(-) create mode 100644 PCbuild/slib_pythoncore.vcxproj create mode 100644 PCbuild/slib_pythoncore.vcxproj.filters create mode 100644 SLib/object.c diff --git a/Include/object.h b/Include/object.h index 536167c27a62fd..3937c16841dd65 100644 --- a/Include/object.h +++ b/Include/object.h @@ -121,7 +121,35 @@ typedef struct { #define _PyVarObject_CAST(op) ((PyVarObject*)(op)) #define _PyVarObject_CAST_CONST(op) ((const PyVarObject*)(op)) +Py_SLIB_LOCAL(Py_ssize_t) PyObject_GetRefCount(const PyObject *ob); +Py_SLIB_LOCAL(PyTypeObject *) PyObject_GetType(const PyObject *ob); +Py_SLIB_LOCAL(void) PyObject_SetRefCount(PyObject *ob, const Py_ssize_t refcnt); +Py_SLIB_LOCAL(void) PyObject_SetType(PyObject *ob, const PyTypeObject *type); + + +Py_SLIB_LOCAL(Py_ssize_t) PyVarObject_GetSize(const PyVarObject *ob); + +Py_SLIB_LOCAL(void) PyVarObject_SetSize(PyVarObject *ob, const Py_ssize_t size); + + +Py_SLIB_LOCAL(int) PyObject_IsType(const PyObject *ob, const PyTypeObject *type); + + +#ifdef Py_USE_SLIB +#define Py_REFCNT(ob) PyObject_GetRefCount(_PyObject_CAST_CONST(ob)) +#define Py_TYPE(ob) PyObject_GetType(_PyObject_CAST_CONST(ob)) + +#define Py_SET_REFCNT(ob, refcnt) PyObject_SetRefCount(_PyObject_CAST(ob), refcnt) +#define Py_SET_TYPE(ob, type) PyObject_SetType(_PyObject_CAST(ob), type) + + +#define Py_SIZE(ob) PyVarObject_GetSize(_PyVarObject_CAST_CONST(ob)) + +#define Py_SET_SIZE(ob, size) PyVarObject_SetSize(_PyVarObject_CAST(ob), size) + +#define Py_IS_TYPE(ob, type) PyObject_IsType(_PyObject_CAST_CONST(ob), type) +#else static inline Py_ssize_t _Py_REFCNT(const PyObject *ob) { return ob->ob_refcnt; } @@ -162,7 +190,7 @@ static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { ob->ob_size = size; } #define Py_SET_SIZE(ob, size) _Py_SET_SIZE(_PyVarObject_CAST(ob), size) - +#endif /* Type objects contain a string containing the type name (to help somewhat @@ -318,7 +346,7 @@ given type object has a specified feature. */ /* Set if the type object's tp_basicsize is set for opague object */ -#define Py_TPFLAGS_OPAQUE_OBJECT (1UL << 8) +#define Py_TPFLAGS_OMIT_PYOBJECT_SIZE (1UL << 8) /* Set if the type object is dynamically allocated */ #define Py_TPFLAGS_HEAPTYPE (1UL << 9) @@ -422,6 +450,23 @@ PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno, PyAPI_FUNC(void) _Py_Dealloc(PyObject *); +Py_SLIB_LOCAL(void) PyObject_IncRef(PyObject *op); + +Py_SLIB_LOCAL(void) PyObject_DecRef( +#ifdef Py_REF_DEBUG + const char *filename, int lineno, +#endif + PyObject *op); + +#ifdef Py_USE_SLIB +# define Py_INCREF(op) PyObject_IncRef(_PyObject_CAST(op)) + +# ifdef Py_REF_DEBUG +# define Py_DECREF(op) PyObject_DecRef(__FILE__, __LINE__, _PyObject_CAST(op)) +# else +# define Py_DECREF(op) PyObject_DecRef(_PyObject_CAST(op)) +# endif +#else static inline void _Py_INCREF(PyObject *op) { #ifdef Py_REF_DEBUG @@ -429,7 +474,6 @@ static inline void _Py_INCREF(PyObject *op) #endif op->ob_refcnt++; } - #define Py_INCREF(op) _Py_INCREF(_PyObject_CAST(op)) static inline void _Py_DECREF( @@ -452,13 +496,12 @@ static inline void _Py_DECREF( _Py_Dealloc(op); } } - #ifdef Py_REF_DEBUG # define Py_DECREF(op) _Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op)) #else # define Py_DECREF(op) _Py_DECREF(_PyObject_CAST(op)) #endif - +#endif /* Safely decref `op` and set `op` to NULL, especially useful in tp_clear * and tp_dealloc implementations. diff --git a/Include/pyport.h b/Include/pyport.h index 7137006870bf01..e93cdc2cf79e34 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -187,9 +187,11 @@ typedef int Py_ssize_clean_t; /* ignore warnings if the compiler decides not to inline a function */ # pragma warning(disable: 4710) /* fastest possible local call under MSVC */ +# define Py_SLIB_LOCAL(type) type __fastcall # define Py_LOCAL(type) static type __fastcall # define Py_LOCAL_INLINE(type) static __inline type __fastcall #else +# define Py_SLIB_LOCAL(type) type # define Py_LOCAL(type) static type # define Py_LOCAL_INLINE(type) static inline type #endif diff --git a/PC/pyconfig.h b/PC/pyconfig.h index b29f63c35bccb1..de04a1b2914a15 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -260,6 +260,10 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ /* All windows compilers that use this header support __declspec */ #define HAVE_DECLSPEC_DLL +#if !defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_BUILTIN) +# define Py_USE_SLIB +#endif + /* For an MSVC DLL, we can nominate the .lib files used by extensions */ #ifdef MS_COREDLL # if !defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_BUILTIN) @@ -269,10 +273,13 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ file in their Makefile (other compilers are generally taken care of by distutils.) */ # if defined(_DEBUG) +# pragma comment(lib, "slib_python310_d.lib") # pragma comment(lib,"python310_d.lib") # elif defined(Py_LIMITED_API) +# pragma comment(lib, "slib_python3.lib") # pragma comment(lib,"python3.lib") # else +# pragma comment(lib, "slib_python310.lib") # pragma comment(lib,"python310.lib") # endif /* _DEBUG */ # endif /* _MSC_VER */ diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln index 4b6dc1e6771dc3..2cf9e3638b0eb0 100644 --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -107,6 +107,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pythonw_uwp", "pythonw_uwp. EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_uuid", "_uuid.vcxproj", "{CB435430-EBB1-478B-8F4E-C256F6838F55}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slib_pythoncore", "slib_pythoncore.vcxproj", "{983BBA6B-A34B-40F8-927C-A57C714F1887}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -1508,6 +1510,34 @@ Global {CB435430-EBB1-478B-8F4E-C256F6838F55}.Release|Win32.Build.0 = Release|Win32 {CB435430-EBB1-478B-8F4E-C256F6838F55}.Release|x64.ActiveCfg = Release|x64 {CB435430-EBB1-478B-8F4E-C256F6838F55}.Release|x64.Build.0 = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Debug|ARM.ActiveCfg = Debug|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Debug|ARM64.ActiveCfg = Debug|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Debug|Win32.ActiveCfg = Debug|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Debug|Win32.Build.0 = Debug|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Debug|x64.ActiveCfg = Debug|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Debug|x64.Build.0 = Debug|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGInstrument|ARM.ActiveCfg = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGInstrument|ARM.Build.0 = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGInstrument|ARM64.ActiveCfg = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGInstrument|ARM64.Build.0 = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGInstrument|Win32.ActiveCfg = Release|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGInstrument|Win32.Build.0 = Release|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGInstrument|x64.ActiveCfg = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGInstrument|x64.Build.0 = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGUpdate|ARM.ActiveCfg = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGUpdate|ARM.Build.0 = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGUpdate|ARM64.ActiveCfg = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGUpdate|ARM64.Build.0 = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGUpdate|Win32.ActiveCfg = Release|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGUpdate|Win32.Build.0 = Release|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGUpdate|x64.ActiveCfg = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.PGUpdate|x64.Build.0 = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Release|ARM.ActiveCfg = Release|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Release|ARM64.ActiveCfg = Release|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Release|Win32.ActiveCfg = Release|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Release|Win32.Build.0 = Release|Win32 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Release|x64.ActiveCfg = Release|x64 + {983BBA6B-A34B-40F8-927C-A57C714F1887}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index db26e38911bc05..5665f5815e1052 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -501,6 +501,11 @@ + + + {983bba6b-a34b-40f8-927c-a57c714f1887} + + @@ -533,7 +538,6 @@ - @@ -542,4 +546,4 @@ - + \ No newline at end of file diff --git a/PCbuild/slib_pythoncore.vcxproj b/PCbuild/slib_pythoncore.vcxproj new file mode 100644 index 00000000000000..5422930cd503da --- /dev/null +++ b/PCbuild/slib_pythoncore.vcxproj @@ -0,0 +1,113 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + PGInstrument + ARM + + + PGInstrument + ARM64 + + + PGInstrument + Win32 + + + PGInstrument + x64 + + + PGUpdate + ARM + + + PGUpdate + ARM64 + + + PGUpdate + Win32 + + + PGUpdate + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {983bba6b-a34b-40f8-927c-a57c714f1887} + slib_pythoncore + + + + + StaticLibrary + false + + + + + + false + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + slib_$(PyDllName) + + + Link + + + + /Zm200 %(AdditionalOptions) + $(PySourcePath)Python;%(AdditionalIncludeDirectories) + $(zlibDir);%(AdditionalIncludeDirectories) + _USRDLL;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions) + + + + + AssemblyAndSourceCode + + + + + + \ No newline at end of file diff --git a/PCbuild/slib_pythoncore.vcxproj.filters b/PCbuild/slib_pythoncore.vcxproj.filters new file mode 100644 index 00000000000000..46f286dafd724a --- /dev/null +++ b/PCbuild/slib_pythoncore.vcxproj.filters @@ -0,0 +1,25 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {87f89d00-deec-4816-998c-fc76b8c42c23} + + + + + Source Files\Objects + + + \ No newline at end of file diff --git a/SLib/object.c b/SLib/object.c new file mode 100644 index 00000000000000..a935f0200d8436 --- /dev/null +++ b/SLib/object.c @@ -0,0 +1,61 @@ +#include // TODO: Replace with appropriate INTERNAL ONLY header. + +Py_SLIB_LOCAL(Py_ssize_t) PyObject_GetRefCount(const PyObject *ob) { + return ob->ob_refcnt; +} + +Py_SLIB_LOCAL(PyTypeObject *) PyObject_GetType(const PyObject *ob) { + return ob->ob_type; +} + +Py_SLIB_LOCAL(void) PyObject_SetRefCount(PyObject *ob, const Py_ssize_t refcnt) { + ob->ob_refcnt = (Py_ssize_t)refcnt; +} + +Py_SLIB_LOCAL(void) PyObject_SetType(PyObject *ob, const PyTypeObject *type) { + ob->ob_type = (PyTypeObject *)type; +} + + +Py_SLIB_LOCAL(Py_ssize_t) PyVarObject_GetSize(const PyVarObject *ob) { + return ob->ob_size; +} + +Py_SLIB_LOCAL(void) PyVarObject_SetSize(PyVarObject *ob, const Py_ssize_t size) { + ob->ob_size = (Py_ssize_t)size; +} + + +Py_SLIB_LOCAL(int) PyObject_IsType(const PyObject *ob, const PyTypeObject *type) { + return Py_TYPE(ob) == type; +} + + +Py_SLIB_LOCAL(void) PyObject_IncRef(PyObject *ob) +{ +#ifdef Py_REF_DEBUG + ++_Py_RefTotal; +#endif + ++ob->ob_refcnt; +} + +Py_SLIB_LOCAL(void) PyObject_DecRef( +#ifdef Py_REF_DEBUG + const char *filename, int lineno, +#endif + PyObject *ob) +{ +#ifdef Py_REF_DEBUG + --_Py_RefTotal; +#endif + if (--ob->ob_refcnt != 0) { +#ifdef Py_REF_DEBUG + if (ob->ob_refcnt < 0) { + _Py_NegativeRefcount(filename, lineno, ob); + } +#endif + } + else { + _Py_Dealloc(ob); + } +} From 8aa000ee3bdc20c4985c201474a361582065eda6 Mon Sep 17 00:00:00 2001 From: WildCard65 Date: Wed, 1 Jul 2020 22:22:51 -0400 Subject: [PATCH 3/6] Added basic implementation of "Py_TPFLAGS_OMIT_PYOBJECT_SIZE". --- Include/cpython/object.h | 4 +++- Include/cpython/objimpl.h | 9 +++++---- Include/object.h | 22 +++++++++++++++------- Lib/test/test_sys.py | 2 +- Objects/typeobject.c | 21 ++++++++++++++++++--- PCbuild/python3dll.vcxproj | 5 +++++ PCbuild/slib_pythoncore.vcxproj | 2 +- SLib/object.c | 10 ++++++++++ 8 files changed, 58 insertions(+), 17 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 584883055dc681..e9182e8ee4b924 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -263,8 +263,10 @@ struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; + /* INTERNAL USE ONLY! MODIFYING THIS CAN CRASH PYTHON! */ - const Py_ssize_t tp_obj_offset; + const Py_ssize_t tp_obj_offset; /* Offset from "PyObject *" pointer */ + const Py_ssize_t tp_obj_size; /* Total memory allocation size */ }; /* The *real* layout of a type object when allocated on the heap */ diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h index 15999a239f7a9a..645f0f35248c54 100644 --- a/Include/cpython/objimpl.h +++ b/Include/cpython/objimpl.h @@ -18,10 +18,11 @@ # error "_PyObject_VAR_SIZE requires SIZEOF_VOID_P be a power of 2" #endif -#define _PyObject_VAR_SIZE(typeobj, nitems) \ - _Py_SIZE_ROUND_UP((typeobj)->tp_basicsize + \ - (nitems)*(typeobj)->tp_itemsize, \ - SIZEOF_VOID_P) +static inline Py_ssize_t _PyObject_VAR_SIZE(PyTypeObject *typeobj, Py_ssize_t nitems) +{ + Py_ssize_t size = (PyType_HasFeature(typeobj, Py_TPFLAGS_OMIT_PYOBJECT_SIZE) ? typeobj->tp_obj_size : typeobj->tp_basicsize); + return _Py_SIZE_ROUND_UP((size + (nitems * (typeobj->tp_itemsize))), SIZEOF_VOID_P); +} /* This example code implements an object constructor with a custom diff --git a/Include/object.h b/Include/object.h index 3937c16841dd65..16a69dc88378b7 100644 --- a/Include/object.h +++ b/Include/object.h @@ -102,21 +102,26 @@ typedef struct _typeobject PyTypeObject; * by hand. Similarly every pointer to a variable-size Python object can, * in addition, be cast to PyVarObject*. */ -typedef struct _object { + +typedef struct _object PyObject; +typedef struct _varobject PyVarObject; + +// TODO: Send "_object" and "_varobject" to CPython internal only. +struct _object { _PyObject_HEAD_EXTRA Py_ssize_t ob_refcnt; PyTypeObject *ob_type; -} PyObject; +}; + +struct _varobject { + PyObject ob_base; + Py_ssize_t ob_size; /* Number of items in variable part */ +}; /* Cast argument to PyObject* type. */ #define _PyObject_CAST(op) ((PyObject*)(op)) #define _PyObject_CAST_CONST(op) ((const PyObject*)(op)) -typedef struct { - PyObject ob_base; - Py_ssize_t ob_size; /* Number of items in variable part */ -} PyVarObject; - /* Cast argument to PyVarObject* type. */ #define _PyVarObject_CAST(op) ((PyVarObject*)(op)) #define _PyVarObject_CAST_CONST(op) ((const PyVarObject*)(op)) @@ -136,6 +141,9 @@ Py_SLIB_LOCAL(void) PyVarObject_SetSize(PyVarObject *ob, const Py_ssize_t size); Py_SLIB_LOCAL(int) PyObject_IsType(const PyObject *ob, const PyTypeObject *type); +Py_SLIB_LOCAL(void *) PyObject_GetStructure(const PyObject *ob, const PyTypeObject *type); +#define Py_GET_STRUCTURE(ob, type) PyObject_GetStructure(_PyObject_CAST_CONST(ob), (const PyTypeObject *)type) + #ifdef Py_USE_SLIB #define Py_REFCNT(ob) PyObject_GetRefCount(_PyObject_CAST_CONST(ob)) #define Py_TYPE(ob) PyObject_GetType(_PyObject_CAST_CONST(ob)) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index aaba6630ff4396..9020e0d33b2968 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1334,7 +1334,7 @@ def delx(self): del self.__x check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject - fmt = 'P2nPI13Pl4Pn9Pn11PIPP' + fmt = 'P2nPI13Pl4Pn9Pn11PIPPll' s = vsize(fmt) check(int, s) # class diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f0e349ecd2bb92..4e8f7698fb4918 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2086,11 +2086,13 @@ best_base(PyObject *bases) return base; } +#define GET_TYPE_TOTALSIZE(type) (_PyType_HasFeature(type, Py_TPFLAGS_OMIT_PYOBJECT_SIZE) ? type->tp_obj_size : type->tp_basicsize) + static int extra_ivars(PyTypeObject *type, PyTypeObject *base) { - size_t t_size = type->tp_basicsize; - size_t b_size = base->tp_basicsize; + size_t t_size = GET_TYPE_TOTALSIZE(type); + size_t b_size = GET_TYPE_TOTALSIZE(base); assert(t_size >= b_size); /* Else type smaller than base! */ if (type->tp_itemsize || base->tp_itemsize) { @@ -4846,7 +4848,7 @@ object___sizeof___impl(PyObject *self) isize = Py_TYPE(self)->tp_itemsize; if (isize > 0) res = Py_SIZE(self) * isize; - res += Py_TYPE(self)->tp_basicsize; + res += GET_TYPE_TOTALSIZE(Py_TYPE(self)); return PyLong_FromSsize_t(res); } @@ -5364,6 +5366,8 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) static int add_operators(PyTypeObject *); +#define SET_SPECIAL_TYPEVAR(var, value) *((Py_ssize_t *)&type->##var) = value + int PyType_Ready(PyTypeObject *type) { @@ -5426,6 +5430,17 @@ PyType_Ready(PyTypeObject *type) goto error; } + if (type->tp_flags & Py_TPFLAGS_OMIT_PYOBJECT_SIZE) { + // tp_basicsize doesn't include the size of it's base type. + Py_ssize_t base_size = GET_TYPE_TOTALSIZE(base); + + SET_SPECIAL_TYPEVAR(tp_obj_offset, (base->tp_obj_offset + base_size)); + SET_SPECIAL_TYPEVAR(tp_obj_size, (base_size + type->tp_basicsize)); + } else { // Type uses the size of PyObject, so the special variables are not used. + SET_SPECIAL_TYPEVAR(tp_obj_offset, 0); + SET_SPECIAL_TYPEVAR(tp_obj_size, 0); + } + /* Initialize ob_type if NULL. This means extensions that want to be compilable separately on Windows can call PyType_Ready() instead of initializing the ob_type field of their type objects. */ diff --git a/PCbuild/python3dll.vcxproj b/PCbuild/python3dll.vcxproj index ec22e6fc76e584..f7a740f0b9aedf 100644 --- a/PCbuild/python3dll.vcxproj +++ b/PCbuild/python3dll.vcxproj @@ -104,6 +104,11 @@ + + + {983bba6b-a34b-40f8-927c-a57c714f1887} + + diff --git a/PCbuild/slib_pythoncore.vcxproj b/PCbuild/slib_pythoncore.vcxproj index 5422930cd503da..95bab6533dd415 100644 --- a/PCbuild/slib_pythoncore.vcxproj +++ b/PCbuild/slib_pythoncore.vcxproj @@ -99,7 +99,7 @@ /Zm200 %(AdditionalOptions) $(PySourcePath)Python;%(AdditionalIncludeDirectories) $(zlibDir);%(AdditionalIncludeDirectories) - _USRDLL;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions) + _USRDLL;Py_BUILD_SLIB;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions) diff --git a/SLib/object.c b/SLib/object.c index a935f0200d8436..01117def36c4aa 100644 --- a/SLib/object.c +++ b/SLib/object.c @@ -31,6 +31,16 @@ Py_SLIB_LOCAL(int) PyObject_IsType(const PyObject *ob, const PyTypeObject *type) } +Py_SLIB_LOCAL(void *) PyObject_GetStructure(const PyObject *ob, const PyTypeObject *type) +{ + if (!PyType_HasFeature((PyTypeObject *)type, Py_TPFLAGS_OMIT_PYOBJECT_SIZE) || + type->tp_obj_offset == type->tp_obj_size) // This checks to see if tp_basicsize was 0 (IE: It has no internal structure) + return (void *)ob; + + return (void *)(((unsigned char *)ob) + type->tp_obj_offset); +} + + Py_SLIB_LOCAL(void) PyObject_IncRef(PyObject *ob) { #ifdef Py_REF_DEBUG From 8774b028317936b4bdf6ed8a24283c0ca4f3a1f1 Mon Sep 17 00:00:00 2001 From: WildCard65 Date: Wed, 1 Jul 2020 22:29:25 -0400 Subject: [PATCH 4/6] Fixed GCC error --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4e8f7698fb4918..dc5d677638f208 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5366,7 +5366,7 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) static int add_operators(PyTypeObject *); -#define SET_SPECIAL_TYPEVAR(var, value) *((Py_ssize_t *)&type->##var) = value +#define SET_SPECIAL_TYPEVAR(var, value) *((Py_ssize_t *)&type->var) = value int PyType_Ready(PyTypeObject *type) From da3b98ae763f02efc9bd2b34fa11ba8aa0dca1ed Mon Sep 17 00:00:00 2001 From: WildCard65 Date: Wed, 1 Jul 2020 22:31:13 -0400 Subject: [PATCH 5/6] Add forgotten member documentation. --- Doc/c-api/typeobj.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 0453438fa1821d..0600f361000525 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -149,6 +149,8 @@ Quick Reference +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ | :c:member:`~PyTypeObject.tp_obj_offset` | const Py_ssize_t | | | X | ~ | | +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ + | :c:member:`~PyTypeObject.tp_obj_size` | const Py_ssize_t | | | X | ~ | | + +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ .. [#slots] A slot name in parentheses indicates it is (effectively) deprecated. From 686d65745d3ad2f23fc980cfaab2bb4b56de5a92 Mon Sep 17 00:00:00 2001 From: WildCard65 Date: Thu, 2 Jul 2020 11:08:05 -0400 Subject: [PATCH 6/6] Trick PyObject into believing it's an opaque type. --- Objects/typeobject.c | 52 ++++++++++++++++++++++++++++++-------------- PC/pyconfig.h | 2 +- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index dc5d677638f208..ec521e6d993b2f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2086,13 +2086,19 @@ best_base(PyObject *bases) return base; } -#define GET_TYPE_TOTALSIZE(type) (_PyType_HasFeature(type, Py_TPFLAGS_OMIT_PYOBJECT_SIZE) ? type->tp_obj_size : type->tp_basicsize) +static inline const Py_ssize_t get_type_totalsize(PyTypeObject *type) +{ + if (type->tp_obj_size < sizeof(PyObject)) // PyType_Type->tp_new manages to trigger this. + return type->tp_basicsize; + + return type->tp_obj_size; +} static int extra_ivars(PyTypeObject *type, PyTypeObject *base) { - size_t t_size = GET_TYPE_TOTALSIZE(type); - size_t b_size = GET_TYPE_TOTALSIZE(base); + size_t t_size = get_type_totalsize(type); + size_t b_size = get_type_totalsize(base); assert(t_size >= b_size); /* Else type smaller than base! */ if (type->tp_itemsize || base->tp_itemsize) { @@ -4848,7 +4854,7 @@ object___sizeof___impl(PyObject *self) isize = Py_TYPE(self)->tp_itemsize; if (isize > 0) res = Py_SIZE(self) * isize; - res += GET_TYPE_TOTALSIZE(Py_TYPE(self)); + res += get_type_totalsize(Py_TYPE(self)); return PyLong_FromSsize_t(res); } @@ -4947,7 +4953,8 @@ PyTypeObject PyBaseObject_Type = { PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | /* tp_flags */ + Py_TPFLAGS_OMIT_PYOBJECT_SIZE, object_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -5366,7 +5373,29 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) static int add_operators(PyTypeObject *); -#define SET_SPECIAL_TYPEVAR(var, value) *((Py_ssize_t *)&type->var) = value +void set_type_memory_data(PyTypeObject *type, PyTypeObject *base) +{ + // Obtain the true size of the base type. + Py_ssize_t base_size = 0, base_offset = 0; + if (base != NULL) { // Only possible if we're not dealing with PyBaseObject_Type + if (_PyType_HasFeature(base, Py_TPFLAGS_OMIT_PYOBJECT_SIZE)) { + base_size = base->tp_obj_size; + base_offset = base->tp_obj_offset; + } else { + base_size = base->tp_basicsize; + base_offset = 0; // PyObject ALWAYS occupies the start of the memory block. + } + } + + Py_ssize_t *size_ptr = (Py_ssize_t *)&type->tp_obj_size, *offset_ptr = (Py_ssize_t *)&type->tp_obj_offset; + if (_PyType_HasFeature(type, Py_TPFLAGS_OMIT_PYOBJECT_SIZE)) { + *size_ptr = base_size + type->tp_basicsize; + *offset_ptr = base_offset + base_size; // The type's internal structure occupies the next block of memory. + } else { + *size_ptr = type->tp_basicsize; // tp_basicsize already includes base_size. + *offset_ptr = 0; // The type's internal structure already includes "PyObject". + } +} int PyType_Ready(PyTypeObject *type) @@ -5430,16 +5459,7 @@ PyType_Ready(PyTypeObject *type) goto error; } - if (type->tp_flags & Py_TPFLAGS_OMIT_PYOBJECT_SIZE) { - // tp_basicsize doesn't include the size of it's base type. - Py_ssize_t base_size = GET_TYPE_TOTALSIZE(base); - - SET_SPECIAL_TYPEVAR(tp_obj_offset, (base->tp_obj_offset + base_size)); - SET_SPECIAL_TYPEVAR(tp_obj_size, (base_size + type->tp_basicsize)); - } else { // Type uses the size of PyObject, so the special variables are not used. - SET_SPECIAL_TYPEVAR(tp_obj_offset, 0); - SET_SPECIAL_TYPEVAR(tp_obj_size, 0); - } + set_type_memory_data(type, base); /* Initialize ob_type if NULL. This means extensions that want to be compilable separately on Windows can call PyType_Ready() instead of diff --git a/PC/pyconfig.h b/PC/pyconfig.h index de04a1b2914a15..2353ead1e7f74a 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -276,7 +276,7 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ # pragma comment(lib, "slib_python310_d.lib") # pragma comment(lib,"python310_d.lib") # elif defined(Py_LIMITED_API) -# pragma comment(lib, "slib_python3.lib") +# pragma comment(lib, "slib_python310.lib") # pragma comment(lib,"python3.lib") # else # pragma comment(lib, "slib_python310.lib")