aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Include/internal/pycore_stackref.h
diff options
context:
space:
mode:
Diffstat (limited to 'Include/internal/pycore_stackref.h')
-rw-r--r--Include/internal/pycore_stackref.h116
1 files changed, 78 insertions, 38 deletions
diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h
index 40ec00c8119..87914767252 100644
--- a/Include/internal/pycore_stackref.h
+++ b/Include/internal/pycore_stackref.h
@@ -62,14 +62,15 @@ PyAPI_FUNC(void) _Py_stackref_record_borrow(_PyStackRef ref, const char *filenam
extern void _Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef ref);
static const _PyStackRef PyStackRef_NULL = { .index = 0 };
+static const _PyStackRef PyStackRef_ERROR = { .index = 2 };
// Use the first 3 even numbers for None, True and False.
// Odd numbers are reserved for (tagged) integers
-#define PyStackRef_None ((_PyStackRef){ .index = 2 } )
-#define PyStackRef_False ((_PyStackRef){ .index = 4 })
-#define PyStackRef_True ((_PyStackRef){ .index = 6 })
+#define PyStackRef_None ((_PyStackRef){ .index = 4 } )
+#define PyStackRef_False ((_PyStackRef){ .index = 6 })
+#define PyStackRef_True ((_PyStackRef){ .index = 8 })
-#define INITIAL_STACKREF_INDEX 8
+#define INITIAL_STACKREF_INDEX 10
static inline int
PyStackRef_IsNull(_PyStackRef ref)
@@ -77,6 +78,19 @@ PyStackRef_IsNull(_PyStackRef ref)
return ref.index == 0;
}
+static inline bool
+PyStackRef_IsError(_PyStackRef ref)
+{
+ return ref.index == 2;
+}
+
+static inline bool
+PyStackRef_IsValid(_PyStackRef ref)
+{
+ /* Invalid values are ERROR and NULL */
+ return !PyStackRef_IsError(ref) && !PyStackRef_IsNull(ref);
+}
+
static inline int
PyStackRef_IsTrue(_PyStackRef ref)
{
@@ -104,6 +118,7 @@ PyStackRef_IsTaggedInt(_PyStackRef ref)
static inline PyObject *
_PyStackRef_AsPyObjectBorrow(_PyStackRef ref, const char *filename, int linenumber)
{
+ assert(!PyStackRef_IsError(ref));
assert(!PyStackRef_IsTaggedInt(ref));
_Py_stackref_record_borrow(ref, filename, linenumber);
return _Py_stackref_get_object(ref);
@@ -155,6 +170,7 @@ _PyStackRef_CLOSE(_PyStackRef ref, const char *filename, int linenumber)
static inline void
_PyStackRef_XCLOSE(_PyStackRef ref, const char *filename, int linenumber)
{
+ assert(!PyStackRef_IsError(ref));
if (PyStackRef_IsNull(ref)) {
return;
}
@@ -165,6 +181,7 @@ _PyStackRef_XCLOSE(_PyStackRef ref, const char *filename, int linenumber)
static inline _PyStackRef
_PyStackRef_DUP(_PyStackRef ref, const char *filename, int linenumber)
{
+ assert(!PyStackRef_IsError(ref));
if (PyStackRef_IsTaggedInt(ref)) {
return ref;
}
@@ -232,18 +249,38 @@ extern intptr_t PyStackRef_UntagInt(_PyStackRef ref);
extern _PyStackRef PyStackRef_TagInt(intptr_t i);
+/* Increments a tagged int, but does not check for overflow */
+extern _PyStackRef PyStackRef_IncrementTaggedIntNoOverflow(_PyStackRef ref);
+
extern bool
PyStackRef_IsNullOrInt(_PyStackRef ref);
#else
#define Py_INT_TAG 3
+#define Py_TAG_INVALID 2
#define Py_TAG_REFCNT 1
+#define Py_TAG_BITS 3
+
+static const _PyStackRef PyStackRef_ERROR = { .bits = Py_TAG_INVALID };
+
+static inline bool
+PyStackRef_IsError(_PyStackRef ref)
+{
+ return ref.bits == Py_TAG_INVALID;
+}
+
+static inline bool
+PyStackRef_IsValid(_PyStackRef ref)
+{
+ /* Invalid values are ERROR and NULL */
+ return ref.bits >= Py_INT_TAG;
+}
static inline bool
PyStackRef_IsTaggedInt(_PyStackRef i)
{
- return (i.bits & Py_INT_TAG) == Py_INT_TAG;
+ return (i.bits & Py_TAG_BITS) == Py_INT_TAG;
}
static inline _PyStackRef
@@ -262,15 +299,25 @@ PyStackRef_UntagInt(_PyStackRef i)
}
+static inline _PyStackRef
+PyStackRef_IncrementTaggedIntNoOverflow(_PyStackRef ref)
+{
+ assert((ref.bits & Py_TAG_BITS) == Py_INT_TAG); // Is tagged int
+ assert((ref.bits & (~Py_TAG_BITS)) != (INT_MAX & (~Py_TAG_BITS))); // Isn't about to overflow
+ return (_PyStackRef){ .bits = ref.bits + 4 };
+}
+
+#define PyStackRef_IsDeferredOrTaggedInt(ref) (((ref).bits & Py_TAG_REFCNT) != 0)
+
#ifdef Py_GIL_DISABLED
#define Py_TAG_DEFERRED Py_TAG_REFCNT
#define Py_TAG_PTR ((uintptr_t)0)
-#define Py_TAG_BITS ((uintptr_t)1)
static const _PyStackRef PyStackRef_NULL = { .bits = Py_TAG_DEFERRED};
+
#define PyStackRef_IsNull(stackref) ((stackref).bits == PyStackRef_NULL.bits)
#define PyStackRef_True ((_PyStackRef){.bits = ((uintptr_t)&_Py_TrueStruct) | Py_TAG_DEFERRED })
#define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) | Py_TAG_DEFERRED })
@@ -379,7 +426,7 @@ PyStackRef_FromPyObjectBorrow(PyObject *obj)
do { \
_PyStackRef _close_tmp = (REF); \
assert(!PyStackRef_IsNull(_close_tmp)); \
- if (!PyStackRef_IsDeferred(_close_tmp)) { \
+ if (!PyStackRef_IsDeferredOrTaggedInt(_close_tmp)) { \
Py_DECREF(PyStackRef_AsPyObjectBorrow(_close_tmp)); \
} \
} while (0)
@@ -395,7 +442,7 @@ static inline _PyStackRef
PyStackRef_DUP(_PyStackRef stackref)
{
assert(!PyStackRef_IsNull(stackref));
- if (PyStackRef_IsDeferred(stackref)) {
+ if (PyStackRef_IsDeferredOrTaggedInt(stackref)) {
return stackref;
}
Py_INCREF(PyStackRef_AsPyObjectBorrow(stackref));
@@ -442,7 +489,6 @@ PyStackRef_AsStrongReference(_PyStackRef stackref)
/* References to immortal objects always have their tag bit set to Py_TAG_REFCNT
* as they can (must) have their reclamation deferred */
-#define Py_TAG_BITS 3
#if _Py_IMMORTAL_FLAGS != Py_TAG_REFCNT
# error "_Py_IMMORTAL_FLAGS != Py_TAG_REFCNT"
#endif
@@ -678,7 +724,13 @@ PyStackRef_XCLOSE(_PyStackRef ref)
#endif // !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG)
-#define PyStackRef_TYPE(stackref) Py_TYPE(PyStackRef_AsPyObjectBorrow(stackref))
+static inline PyTypeObject *
+PyStackRef_TYPE(_PyStackRef stackref) {
+ if (PyStackRef_IsTaggedInt(stackref)) {
+ return &PyLong_Type;
+ }
+ return Py_TYPE(PyStackRef_AsPyObjectBorrow(stackref));
+}
// Converts a PyStackRef back to a PyObject *, converting the
// stackref to a new reference.
@@ -686,42 +738,30 @@ PyStackRef_XCLOSE(_PyStackRef ref)
// StackRef type checks
-static inline bool
-PyStackRef_GenCheck(_PyStackRef stackref)
-{
- return PyGen_Check(PyStackRef_AsPyObjectBorrow(stackref));
-}
+#define STACKREF_CHECK_FUNC(T) \
+ static inline bool \
+ PyStackRef_ ## T ## Check(_PyStackRef stackref) { \
+ if (PyStackRef_IsTaggedInt(stackref)) { \
+ return false; \
+ } \
+ return Py ## T ## _Check(PyStackRef_AsPyObjectBorrow(stackref)); \
+ }
-static inline bool
-PyStackRef_BoolCheck(_PyStackRef stackref)
-{
- return PyBool_Check(PyStackRef_AsPyObjectBorrow(stackref));
-}
+STACKREF_CHECK_FUNC(Gen)
+STACKREF_CHECK_FUNC(Bool)
+STACKREF_CHECK_FUNC(ExceptionInstance)
+STACKREF_CHECK_FUNC(Code)
+STACKREF_CHECK_FUNC(Function)
static inline bool
PyStackRef_LongCheck(_PyStackRef stackref)
{
+ if (PyStackRef_IsTaggedInt(stackref)) {
+ return true;
+ }
return PyLong_Check(PyStackRef_AsPyObjectBorrow(stackref));
}
-static inline bool
-PyStackRef_ExceptionInstanceCheck(_PyStackRef stackref)
-{
- return PyExceptionInstance_Check(PyStackRef_AsPyObjectBorrow(stackref));
-}
-
-static inline bool
-PyStackRef_CodeCheck(_PyStackRef stackref)
-{
- return PyCode_Check(PyStackRef_AsPyObjectBorrow(stackref));
-}
-
-static inline bool
-PyStackRef_FunctionCheck(_PyStackRef stackref)
-{
- return PyFunction_Check(PyStackRef_AsPyObjectBorrow(stackref));
-}
-
static inline void
_PyThreadState_PushCStackRef(PyThreadState *tstate, _PyCStackRef *ref)
{