Skip to content

Commit dc6b12d

Browse files
gh-117139: Add header for tagged pointers (GH-118330)
--------- Co-authored-by: Sam Gross <655866+colesbury@users.noreply.github.com>
1 parent e93c39b commit dc6b12d

File tree

4 files changed

+200
-0
lines changed

4 files changed

+200
-0
lines changed

Diff for: Include/internal/pycore_stackref.h

+195
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
#ifndef Py_INTERNAL_STACKREF_H
2+
#define Py_INTERNAL_STACKREF_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#ifndef Py_BUILD_CORE
8+
# error "this header requires Py_BUILD_CORE define"
9+
#endif
10+
11+
#include <stddef.h>
12+
13+
typedef union {
14+
uintptr_t bits;
15+
} _PyStackRef;
16+
17+
static const _PyStackRef Py_STACKREF_NULL = { .bits = 0 };
18+
19+
#define Py_TAG_DEFERRED (1)
20+
21+
// Gets a PyObject * from a _PyStackRef
22+
#if defined(Py_GIL_DISABLED)
23+
static inline PyObject *
24+
PyStackRef_Get(_PyStackRef tagged)
25+
{
26+
PyObject *cleared = ((PyObject *)((tagged).bits & (~Py_TAG_DEFERRED)));
27+
return cleared;
28+
}
29+
#else
30+
# define PyStackRef_Get(tagged) ((PyObject *)((tagged).bits))
31+
#endif
32+
33+
// Converts a PyObject * to a PyStackRef, stealing the reference.
34+
#if defined(Py_GIL_DISABLED)
35+
static inline _PyStackRef
36+
_PyStackRef_StealRef(PyObject *obj)
37+
{
38+
// Make sure we don't take an already tagged value.
39+
assert(((uintptr_t)obj & Py_TAG_DEFERRED) == 0);
40+
return ((_PyStackRef){.bits = ((uintptr_t)(obj))});
41+
}
42+
# define PyStackRef_StealRef(obj) _PyStackRef_StealRef(_PyObject_CAST(obj))
43+
#else
44+
# define PyStackRef_StealRef(obj) ((_PyStackRef){.bits = ((uintptr_t)(obj))})
45+
#endif
46+
47+
// Converts a PyObject * to a PyStackRef, with a new reference
48+
#if defined(Py_GIL_DISABLED)
49+
static inline _PyStackRef
50+
_PyStackRef_NewRefDeferred(PyObject *obj)
51+
{
52+
// Make sure we don't take an already tagged value.
53+
assert(((uintptr_t)obj & Py_TAG_DEFERRED) == 0);
54+
assert(obj != NULL);
55+
if (_PyObject_HasDeferredRefcount(obj)) {
56+
return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_DEFERRED };
57+
}
58+
else {
59+
return (_PyStackRef){ .bits = (uintptr_t)Py_NewRef(obj) };
60+
}
61+
}
62+
# define PyStackRef_NewRefDeferred(obj) _PyStackRef_NewRefDeferred(_PyObject_CAST(obj))
63+
#else
64+
# define PyStackRef_NewRefDeferred(obj) PyStackRef_NewRef(((_PyStackRef){.bits = ((uintptr_t)(obj))}))
65+
#endif
66+
67+
#if defined(Py_GIL_DISABLED)
68+
static inline _PyStackRef
69+
_PyStackRef_XNewRefDeferred(PyObject *obj)
70+
{
71+
// Make sure we don't take an already tagged value.
72+
assert(((uintptr_t)obj & Py_TAG_DEFERRED) == 0);
73+
if (obj == NULL) {
74+
return Py_STACKREF_NULL;
75+
}
76+
return _PyStackRef_NewRefDeferred(obj);
77+
}
78+
# define PyStackRef_XNewRefDeferred(obj) _PyStackRef_XNewRefDeferred(_PyObject_CAST(obj))
79+
#else
80+
# define PyStackRef_XNewRefDeferred(obj) PyStackRef_XNewRef(((_PyStackRef){.bits = ((uintptr_t)(obj))}))
81+
#endif
82+
83+
// Converts a PyStackRef back to a PyObject *.
84+
#if defined(Py_GIL_DISABLED)
85+
static inline PyObject *
86+
PyStackRef_StealObject(_PyStackRef tagged)
87+
{
88+
if ((tagged.bits & Py_TAG_DEFERRED) == Py_TAG_DEFERRED) {
89+
assert(_PyObject_HasDeferredRefcount(PyStackRef_Get(tagged)));
90+
return Py_NewRef(PyStackRef_Get(tagged));
91+
}
92+
return PyStackRef_Get(tagged);
93+
}
94+
#else
95+
# define PyStackRef_StealObject(tagged) PyStackRef_Get(tagged)
96+
#endif
97+
98+
static inline void
99+
_Py_untag_stack_borrowed(PyObject **dst, const _PyStackRef *src, size_t length)
100+
{
101+
for (size_t i = 0; i < length; i++) {
102+
dst[i] = PyStackRef_Get(src[i]);
103+
}
104+
}
105+
106+
static inline void
107+
_Py_untag_stack_steal(PyObject **dst, const _PyStackRef *src, size_t length)
108+
{
109+
for (size_t i = 0; i < length; i++) {
110+
dst[i] = PyStackRef_StealObject(src[i]);
111+
}
112+
}
113+
114+
115+
#define PyStackRef_XSETREF(dst, src) \
116+
do { \
117+
_PyStackRef *_tmp_dst_ptr = &(dst) \
118+
_PyStackRef _tmp_old_dst = (*_tmp_dst_ptr); \
119+
*_tmp_dst_ptr = (src); \
120+
PyStackRef_XDECREF(_tmp_old_dst); \
121+
} while (0)
122+
123+
#define PyStackRef_SETREF(dst, src) \
124+
do { \
125+
_PyStackRef *_tmp_dst_ptr = &(dst); \
126+
_PyStackRef _tmp_old_dst = (*_tmp_dst_ptr); \
127+
*_tmp_dst_ptr = (src); \
128+
PyStackRef_DECREF(_tmp_old_dst); \
129+
} while (0)
130+
131+
#define PyStackRef_CLEAR(op) \
132+
do { \
133+
_PyStackRef *_tmp_op_ptr = &(op); \
134+
_PyStackRef _tmp_old_op = (*_tmp_op_ptr); \
135+
if (_tmp_old_op.bits != Py_STACKREF_NULL.bits) { \
136+
*_tmp_op_ptr = Py_STACKREF_NULL; \
137+
PyStackRef_DECREF(_tmp_old_op); \
138+
} \
139+
} while (0)
140+
141+
#if defined(Py_GIL_DISABLED)
142+
static inline void
143+
PyStackRef_DECREF(_PyStackRef tagged)
144+
{
145+
if ((tagged.bits & Py_TAG_DEFERRED) == Py_TAG_DEFERRED) {
146+
return;
147+
}
148+
Py_DECREF(PyStackRef_Get(tagged));
149+
}
150+
#else
151+
# define PyStackRef_DECREF(op) Py_DECREF(PyStackRef_Get(op))
152+
#endif
153+
154+
#if defined(Py_GIL_DISABLED)
155+
static inline void
156+
PyStackRef_INCREF(_PyStackRef tagged)
157+
{
158+
if ((tagged.bits & Py_TAG_DEFERRED) == Py_TAG_DEFERRED) {
159+
assert(_PyObject_HasDeferredRefcount(PyStackRef_Get(tagged)));
160+
return;
161+
}
162+
Py_INCREF(PyStackRef_Get(tagged));
163+
}
164+
#else
165+
# define PyStackRef_INCREF(op) Py_INCREF(PyStackRef_Get(op))
166+
#endif
167+
168+
static inline void
169+
PyStackRef_XDECREF(_PyStackRef op)
170+
{
171+
if (op.bits != Py_STACKREF_NULL.bits) {
172+
PyStackRef_DECREF(op);
173+
}
174+
}
175+
176+
static inline _PyStackRef
177+
PyStackRef_NewRef(_PyStackRef obj)
178+
{
179+
PyStackRef_INCREF(obj);
180+
return obj;
181+
}
182+
183+
static inline _PyStackRef
184+
PyStackRef_XNewRef(_PyStackRef obj)
185+
{
186+
if (obj.bits == Py_STACKREF_NULL.bits) {
187+
return obj;
188+
}
189+
return PyStackRef_NewRef(obj);
190+
}
191+
192+
#ifdef __cplusplus
193+
}
194+
#endif
195+
#endif /* !Py_INTERNAL_STACKREF_H */

Diff for: Makefile.pre.in

+1
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,7 @@ PYTHON_HEADERS= \
12251225
$(srcdir)/Include/internal/pycore_structseq.h \
12261226
$(srcdir)/Include/internal/pycore_symtable.h \
12271227
$(srcdir)/Include/internal/pycore_sysmodule.h \
1228+
$(srcdir)/Include/internal/pycore_stackref.h \
12281229
$(srcdir)/Include/internal/pycore_time.h \
12291230
$(srcdir)/Include/internal/pycore_token.h \
12301231
$(srcdir)/Include/internal/pycore_traceback.h \

Diff for: PCbuild/pythoncore.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@
291291
<ClInclude Include="..\Include\internal\pycore_structseq.h" />
292292
<ClInclude Include="..\Include\internal\pycore_sysmodule.h" />
293293
<ClInclude Include="..\Include\internal\pycore_symtable.h" />
294+
<ClInclude Include="..\Include\internal\pycore_stackref.h" />
294295
<ClInclude Include="..\Include\internal\pycore_time.h" />
295296
<ClInclude Include="..\Include\internal\pycore_token.h" />
296297
<ClInclude Include="..\Include\internal\pycore_traceback.h" />

Diff for: PCbuild/pythoncore.vcxproj.filters

+3
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,9 @@
789789
<ClInclude Include="..\Include\internal\pycore_symtable.h">
790790
<Filter>Include\internal</Filter>
791791
</ClInclude>
792+
<ClInclude Include="..\Include\internal\pycore_stackref.h">
793+
<Filter>Include\internal</Filter>
794+
</ClInclude>
792795
<ClInclude Include="..\Include\internal\pycore_time.h">
793796
<Filter>Include\internal</Filter>
794797
</ClInclude>

0 commit comments

Comments
 (0)