Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
colesbury committed Sep 20, 2023
1 parent 754519a commit e95c12c
Show file tree
Hide file tree
Showing 12 changed files with 227 additions and 14 deletions.
1 change: 1 addition & 0 deletions Include/internal/pycore_global_objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extern "C" {
struct _Py_cached_objects {
// XXX We could statically allocate the hashtable.
_Py_hashtable_t *interned_strings;
_Py_hashtable_t *moduledef_objects;
};

struct _Py_static_objects {
Expand Down
6 changes: 6 additions & 0 deletions Include/internal/pycore_moduleobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ typedef struct {
PyObject *md_name;
} PyModuleObject;

// Wrapper around PyModule_Def for PyModuleDef_Init
typedef struct {
PyObject_HEAD
PyModuleDef *def;
} PyModuleDefObject;

static inline PyModuleDef* _PyModule_GetDef(PyObject *mod) {
assert(PyModule_Check(mod));
return ((PyModuleObject *)mod)->md_def;
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_unicodeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ PyAPI_FUNC(Py_ssize_t) _PyUnicode_ScanIdentifier(PyObject *);

extern void _PyUnicode_InitState(PyInterpreterState *);
extern PyStatus _PyUnicode_InitGlobalObjects(PyInterpreterState *);
extern PyStatus _PyModule_InitGlobalObjects(PyInterpreterState *);
extern PyStatus _PyUnicode_InitTypes(PyInterpreterState *);
extern void _PyUnicode_Fini(PyInterpreterState *);
extern void _PyUnicode_FiniTypes(PyInterpreterState *);
Expand Down
4 changes: 2 additions & 2 deletions Include/moduleobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ PyAPI_DATA(PyTypeObject) PyModuleDef_Type;
#endif

typedef struct PyModuleDef_Base {
PyObject_HEAD
struct { Py_ssize_t _private1; PyTypeObject *_private2; } ob_base;
/* The function used to re-initialize the module.
This is only set for legacy (single-phase init) extension modules
and only used for those that support multiple initializations
Expand All @@ -58,7 +58,7 @@ typedef struct PyModuleDef_Base {
} PyModuleDef_Base;

#define PyModuleDef_HEAD_INIT { \
PyObject_HEAD_INIT(_Py_NULL) \
{ 0 }, \
_Py_NULL, /* m_init */ \
0, /* m_index */ \
_Py_NULL, /* m_copy */ \
Expand Down
115 changes: 110 additions & 5 deletions Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,20 @@ whose size is determined when the object is allocated.
# define Py_REF_DEBUG
#endif

#if defined(Py_ABI_VERSION_4) && !defined(Py_LIMITED_API)
#error "Py_ABI_VERSION_4 must not be defined unless Py_LIMITED_API is defined"
#endif

#if defined(Py_ABI_VERSION_4) && Py_LIMITED_API+0<0x03070000
#error "Py_ABI_VERSION_4 requires Py_LIMITED_API>=0x03070000"
#endif

/* PyObject_HEAD defines the initial segment of every PyObject. */
#if defined(Py_ABI_VERSION_4)
#define PyObject_HEAD struct { uint32_t _padding0[2]; uintptr_t _padding1[3]; } ob_base;
#else
#define PyObject_HEAD PyObject ob_base;
#endif

/*
Immortalization:
Expand Down Expand Up @@ -142,6 +154,7 @@ check by comparing the reference count field to the immortality reference count.
* by hand. Similarly every pointer to a variable-size Python object can,
* in addition, be cast to PyVarObject*.
*/
#if !defined(Py_ABI_VERSION_4)
struct _object {
#if (defined(__GNUC__) || defined(__clang__)) \
&& !(defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L)
Expand All @@ -166,15 +179,24 @@ struct _object {

PyTypeObject *ob_type;
};
#endif

/* Cast argument to PyObject* type. */
#define _PyObject_CAST(op) _Py_CAST(PyObject*, (op))

typedef struct {
#if defined(Py_ABI_VERSION_4)
# if Py_LIMITED_API+0 < 0x030d0000
struct _varobject_abi3 {
struct _object_abi3 ob_base;
Py_ssize_t ob_size;
};
# endif
#else
struct _varobject {
PyObject ob_base;
Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

} /* PyVarObject */;
#endif
/* Cast argument to PyVarObject* type. */
#define _PyVarObject_CAST(op) _Py_CAST(PyVarObject*, (op))

Expand All @@ -183,9 +205,36 @@ typedef struct {
PyAPI_FUNC(int) Py_Is(PyObject *x, PyObject *y);
#define Py_Is(x, y) ((x) == (y))

#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
PyAPI_FUNC(PyTypeObject *) Py_Type(PyObject *o);
PyAPI_FUNC(void) Py_SetType(PyObject *o, PyTypeObject *type);
PyAPI_FUNC(Py_ssize_t) Py_Refcnt(PyObject *o);
PyAPI_FUNC(void) Py_SetRefcnt(PyObject *o, Py_ssize_t refcnt);
PyAPI_FUNC(Py_ssize_t) PyVarObject_Size(PyObject *o);
PyAPI_FUNC(void) PyVarObject_SetSize(PyObject *o, Py_ssize_t size);
PyAPI_FUNC(int) Py_IsImmortal(PyObject *o);
#endif

#if defined(Py_ABI_VERSION_4) && Py_LIMITED_API+0 < 0x030d0000
PyAPI_FUNC(PyTypeObject *) Py_Type(PyObject *o) Py_ATTRIBUTE_WEAK;
PyAPI_FUNC(void) Py_SetType(PyObject *o, PyTypeObject *type) Py_ATTRIBUTE_WEAK;
PyAPI_FUNC(Py_ssize_t) Py_Refcnt(PyObject *o) Py_ATTRIBUTE_WEAK;
PyAPI_FUNC(void) Py_SetRefcnt(PyObject *o, Py_ssize_t refcnt) Py_ATTRIBUTE_WEAK;
PyAPI_FUNC(Py_ssize_t) PyVarObject_Size(PyObject *o) Py_ATTRIBUTE_WEAK;
PyAPI_FUNC(void) PyVarObject_SetSize(PyObject *o, Py_ssize_t size) Py_ATTRIBUTE_WEAK;
#endif

static inline Py_ssize_t Py_REFCNT(PyObject *ob) {
#if defined(Py_ABI_VERSION_4) && Py_LIMITED_API+0 < 0x030d0000
if (Py_Refcnt) {
return Py_Refcnt(ob);
}
return ((struct _object_abi3 *)ob)->ob_refcnt;
#elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030d0000
return ob->ob_refcnt;
#else
return Py_Refcnt(ob);
#endif
}
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
# define Py_REFCNT(ob) Py_REFCNT(_PyObject_CAST(ob))
Expand All @@ -194,7 +243,18 @@ static inline Py_ssize_t Py_REFCNT(PyObject *ob) {

// bpo-39573: The Py_SET_TYPE() function must be used to set an object type.
static inline PyTypeObject* Py_TYPE(PyObject *ob) {
#if defined(Py_ABI_VERSION_4) && Py_LIMITED_API+0 < 0x030d0000
if (Py_Type) {
return Py_Type(ob);
}
else {
return ((struct _object_abi3 *)ob)->ob_type;
}
#elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030d0000
return ob->ob_type;
#else
return Py_Type(ob);
#endif
}
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
# define Py_TYPE(ob) Py_TYPE(_PyObject_CAST(ob))
Expand All @@ -205,15 +265,27 @@ PyAPI_DATA(PyTypeObject) PyBool_Type;

// bpo-39573: The Py_SET_SIZE() function must be used to set an object size.
static inline Py_ssize_t Py_SIZE(PyObject *ob) {
#if defined(Py_ABI_VERSION_4) && Py_LIMITED_API+0 < 0x030d0000
if (PyVarObject_Size) {
return PyVarObject_Size(ob);
}
else {
return ((struct _varobject_abi3 *)ob)->ob_size;
}
#elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030d0000
assert(ob->ob_type != &PyLong_Type);
assert(ob->ob_type != &PyBool_Type);
PyVarObject *var_ob = _PyVarObject_CAST(ob);
return var_ob->ob_size;
#else
return PyVarObject_Size(ob);
#endif
}
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
# define Py_SIZE(ob) Py_SIZE(_PyObject_CAST(ob))
#endif

#if !defined(Py_ABI_VERSION_4) && (!defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030d0000)
static inline Py_ALWAYS_INLINE int _Py_IsImmortal(PyObject *op)
{
#if SIZEOF_VOID_P > 4
Expand All @@ -223,6 +295,7 @@ static inline Py_ALWAYS_INLINE int _Py_IsImmortal(PyObject *op)
#endif
}
#define _Py_IsImmortal(op) _Py_IsImmortal(_PyObject_CAST(op))
#endif

static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
return Py_TYPE(ob) == type;
Expand All @@ -232,6 +305,7 @@ static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
#endif


#if (!defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030d0000) && !defined(Py_ABI_VERSION_4)
static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) {
// This immortal check is for code that is unaware of immortal objects.
// The runtime tracks these objects and we should avoid as much
Expand All @@ -245,19 +319,42 @@ static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) {
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
# define Py_SET_REFCNT(ob, refcnt) Py_SET_REFCNT(_PyObject_CAST(ob), (refcnt))
#endif
#endif


static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) {
#if defined(Py_ABI_VERSION_4) && Py_LIMITED_API+0 < 0x030d0000
if (Py_SetType) {
Py_SetType(ob, type);
}
else {
((struct _object_abi3 *)ob)->ob_type = type;
}
#elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030d0000
ob->ob_type = type;
#else
Py_SetType(ob, type);
#endif
}
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
# define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type)
#endif

static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) {
#if defined(Py_ABI_VERSION_4) && Py_LIMITED_API+0 < 0x030d0000
if (PyVarObject_SetSize) {
PyVarObject_SetSize(_PyObject_CAST(ob), size);
}
else {
((struct _varobject_abi3 *)ob)->ob_size = size;
}
#elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030d0000
assert(ob->ob_base.ob_type != &PyLong_Type);
assert(ob->ob_base.ob_type != &PyBool_Type);
ob->ob_size = size;
#else
PyVarObject_SetSize(_PyObject_CAST(ob), size);
#endif
}
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
# define Py_SET_SIZE(ob, size) Py_SET_SIZE(_PyVarObject_CAST(ob), (size))
Expand Down Expand Up @@ -605,7 +702,7 @@ PyAPI_FUNC(void) _Py_DecRef(PyObject *);

static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op)
{
#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG))
#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG) || defined(Py_ABI_VERSION_4))
// Stable ABI implements Py_INCREF() as a function call on limited C API
// version 3.12 and newer, and on Python built in debug mode. _Py_IncRef()
// was added to Python 3.10.0a7, use Py_IncRef() on older Python versions.
Expand Down Expand Up @@ -643,7 +740,7 @@ static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op)
# define Py_INCREF(op) Py_INCREF(_PyObject_CAST(op))
#endif

#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG))
#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG) || defined(Py_ABI_VERSION_4))
// Stable ABI implements Py_DECREF() as a function call on limited C API
// version 3.12 and newer, and on Python built in debug mode. _Py_DecRef() was
// added to Python 3.10.0a7, use Py_DecRef() on older Python versions.
Expand Down Expand Up @@ -827,7 +924,11 @@ PyAPI_FUNC(int) Py_IsNone(PyObject *x);
#define Py_IsNone(x) Py_Is((x), Py_None)

/* Macro for returning Py_None from a function */
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
#define Py_RETURN_NONE return Py_None
#else
#define Py_RETURN_NONE return Py_NewRef(Py_None)
#endif

/*
Py_NotImplemented is a singleton used to signal that an operation is
Expand All @@ -837,7 +938,11 @@ PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */
#define Py_NotImplemented (&_Py_NotImplementedStruct)

/* Macro for returning Py_NotImplemented from a function */
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
#define Py_RETURN_NOTIMPLEMENTED return Py_NotImplemented
#else
#define Py_RETURN_NOTIMPLEMENTED return Py_NewRef(Py_NotImplemented)
#endif

/* Rich comparison opcodes */
#define Py_LT 0
Expand Down
8 changes: 8 additions & 0 deletions Include/pyport.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,14 @@ extern "C" {

#include "exports.h"


// Py_ATTRIBUTE_WEAK
#if defined(__APPLE__)
#define Py_ATTRIBUTE_WEAK __attribute__((weak_import))
#elif defined(__GNUC__)
#define Py_ATTRIBUTE_WEAK __attribute__((weak))
#endif

/* limits.h constants that may be missing */

#ifndef INT_MAX
Expand Down
1 change: 1 addition & 0 deletions Include/pytypedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ typedef struct PyGetSetDef PyGetSetDef;
typedef struct PyMemberDef PyMemberDef;

typedef struct _object PyObject;
typedef struct _varobject PyVarObject;
typedef struct _longobject PyLongObject;
typedef struct _typeobject PyTypeObject;
typedef struct PyCodeObject PyCodeObject;
Expand Down
53 changes: 48 additions & 5 deletions Objects/moduleobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "Python.h"
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_interp.h" // PyInterpreterState.importlib
#include "pycore_modsupport.h" // _PyModule_CreateInitialized()
#include "pycore_moduleobject.h" // _PyModule_GetDef()
Expand All @@ -21,7 +22,7 @@ static PyMemberDef module_members[] = {
PyTypeObject PyModuleDef_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"moduledef", /* tp_name */
sizeof(PyModuleDef), /* tp_basicsize */
sizeof(PyModuleDefObject), /* tp_basicsize */
0, /* tp_itemsize */
};

Expand All @@ -43,12 +44,33 @@ PyObject*
PyModuleDef_Init(PyModuleDef* def)
{
assert(PyModuleDef_Type.tp_flags & Py_TPFLAGS_READY);
_Py_hashtable_t *table = _PyRuntime.cached_objects.moduledef_objects;
if (def->m_base.m_index == 0) {
Py_SET_REFCNT(def, 1);
Py_SET_TYPE(def, &PyModuleDef_Type);
def->m_base.m_index = _PyImport_GetNextModuleIndex();
PyModuleDefObject *wrapper = PyObject_New(PyModuleDefObject, &PyModuleDef_Type);
if (wrapper == NULL) {
return NULL;
}
wrapper->def = def;
Py_ssize_t index = _PyImport_GetNextModuleIndex();
if (_Py_hashtable_set(table, def, wrapper) < 0) {
Py_DECREF(wrapper);
return PyErr_NoMemory();
}
def->m_base.m_index = index;
return (PyObject *)wrapper;
}
else {
PyObject *wrapper = _Py_hashtable_get(table, def);
if (wrapper == NULL) {
// should never happen
_Py_FatalErrorFormat(
__func__,
"missing PyModuleDefObject for %s (%p)",
def->m_name,
def);
}
return wrapper;
}
return (PyObject*)def;
}

static int
Expand Down Expand Up @@ -793,6 +815,27 @@ _PyModuleSpec_IsUninitializedSubmodule(PyObject *spec, PyObject *name)
return is_uninitialized;
}

PyStatus
_PyModule_InitGlobalObjects(PyInterpreterState *interp)
{
// Initialize the global module def hashtable
if (_Py_IsMainInterpreter(interp)) {
_Py_hashtable_allocator_t hashtable_alloc = {PyMem_RawMalloc, PyMem_RawFree};
_Py_hashtable_t *table = _Py_hashtable_new_full(
&_Py_hashtable_hash_ptr,
&_Py_hashtable_compare_direct,
NULL,
NULL,
&hashtable_alloc
);
if (table == NULL) {
return _PyStatus_NO_MEMORY();
}
interp->runtime->cached_objects.moduledef_objects = table;
}
return _PyStatus_OK();
}

PyObject*
_Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress)
{
Expand Down
Loading

0 comments on commit e95c12c

Please sign in to comment.