Skip to content

Commit 3d04e89

Browse files
committed
Use tagged integers on the evaluation stack for lasti
1 parent d87e7f3 commit 3d04e89

7 files changed

Lines changed: 60 additions & 40 deletions

File tree

Include/internal/pycore_stackref.h

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,32 @@ _PyStackRef_FromPyObjectNewMortal(PyObject *obj, const char *filename, int linen
210210

211211
extern int PyStackRef_Is(_PyStackRef a, _PyStackRef b);
212212

213+
extern _PyStackRef PyStackRef_TagInt(intptr_t i);
214+
213215
#else
214216

217+
#define Py_INT_TAG 3
218+
219+
static inline bool
220+
PyStackRef_IsTaggedInt(_PyStackRef i)
221+
{
222+
return (i.bits & Py_INT_TAG) == Py_INT_TAG;
223+
}
224+
225+
static inline _PyStackRef
226+
PyStackRef_TagInt(intptr_t i)
227+
{
228+
assert(Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, (i << 2), 2) == i);
229+
return (_PyStackRef){ .bits = ((((uintptr_t)i) << 2) | Py_INT_TAG) };
230+
}
231+
232+
static inline intptr_t
233+
PyStackRef_UntagInt(_PyStackRef i)
234+
{
235+
assert((i.bits & Py_INT_TAG) == Py_INT_TAG);
236+
return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, i.bits, 2);
237+
}
238+
215239

216240
#ifdef Py_GIL_DISABLED
217241

@@ -232,6 +256,8 @@ static const _PyStackRef PyStackRef_NULL = { .bits = Py_TAG_DEFERRED};
232256
#define PyStackRef_IsTrue(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_True)
233257
#define PyStackRef_IsFalse(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_False)
234258

259+
#define PyStackRef_IsNullOrInt(stackref) (PyStackRef_IsNull(stackref) || PyStackRef_IsTaggedInt(stackref))
260+
235261
static inline PyObject *
236262
PyStackRef_AsPyObjectBorrow(_PyStackRef stackref)
237263
{
@@ -451,6 +477,7 @@ PyStackRef_RefcountOnObject(_PyStackRef ref)
451477
static inline PyObject *
452478
PyStackRef_AsPyObjectBorrow(_PyStackRef ref)
453479
{
480+
assert(!PyStackRef_IsTaggedInt(ref));
454481
return BITS_TO_PTR_MASKED(ref);
455482
}
456483

@@ -587,6 +614,12 @@ PyStackRef_CLOSE(_PyStackRef ref)
587614
}
588615
#endif
589616

617+
static inline bool
618+
PyStackRef_IsNullOrInt(_PyStackRef ref)
619+
{
620+
return PyStackRef_IsNull(ref) || PyStackRef_IsTaggedInt(ref);
621+
}
622+
590623
static inline void
591624
PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct)
592625
{
@@ -726,7 +759,7 @@ _Py_TryXGetStackRef(PyObject **src, _PyStackRef *out)
726759
// Like Py_VISIT but for _PyStackRef fields
727760
#define _Py_VISIT_STACKREF(ref) \
728761
do { \
729-
if (!PyStackRef_IsNull(ref)) { \
762+
if (!PyStackRef_IsNullOrInt(ref)) { \
730763
int vret = _PyGC_VisitStackRef(&(ref), visit, arg); \
731764
if (vret) \
732765
return vret; \

Python/bytecodes.c

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,16 +1385,7 @@ dummy_func(
13851385

13861386
assert(oparg >= 0 && oparg <= 2);
13871387
if (oparg) {
1388-
PyObject *lasti = PyStackRef_AsPyObjectBorrow(values[0]);
1389-
if (PyLong_Check(lasti)) {
1390-
frame->instr_ptr = _PyFrame_GetBytecode(frame) + PyLong_AsLong(lasti);
1391-
assert(!_PyErr_Occurred(tstate));
1392-
}
1393-
else {
1394-
_PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int");
1395-
Py_DECREF(exc);
1396-
ERROR_NO_POP();
1397-
}
1388+
frame->instr_ptr = _PyFrame_GetBytecode(frame) + PyStackRef_UntagInt(values[0]);
13981389
}
13991390
assert(exc && PyExceptionInstance_Check(exc));
14001391
_PyErr_SetRaisedException(tstate, exc);
@@ -3458,7 +3449,7 @@ dummy_func(
34583449
if (tb == NULL) {
34593450
tb = Py_None;
34603451
}
3461-
assert(PyStackRef_LongCheck(lasti));
3452+
assert(PyStackRef_IsTaggedInt(lasti));
34623453
(void)lasti; // Shut up compiler warning if asserts are off
34633454
PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb};
34643455
int has_self = !PyStackRef_IsNull(exit_self);
@@ -5351,11 +5342,8 @@ dummy_func(
53515342
}
53525343
if (lasti) {
53535344
int frame_lasti = _PyInterpreterFrame_LASTI(frame);
5354-
PyObject *lasti = PyLong_FromLong(frame_lasti);
5355-
if (lasti == NULL) {
5356-
goto exception_unwind;
5357-
}
5358-
_PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(lasti));
5345+
_PyStackRef lasti = PyStackRef_TagInt(frame_lasti);
5346+
_PyFrame_StackPush(frame, lasti);
53595347
}
53605348

53615349
/* Make the raw exception data

Python/ceval.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ dump_item(_PyStackRef item)
146146
printf("<NULL>");
147147
return;
148148
}
149+
if (PyStackRef_IsTaggedInt(item)) {
150+
printf("%ld", PyStackRef_UntagInt(item));
151+
}
149152
PyObject *obj = PyStackRef_AsPyObjectBorrow(item);
150153
if (obj == NULL) {
151154
printf("<nil>");

Python/executor_cases.c.h

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/gc.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1495,8 +1495,11 @@ mark_stacks(PyInterpreterState *interp, PyGC_Head *visited, int visited_space, b
14951495
objects_marked += move_to_reachable(func, &reachable, visited_space);
14961496
while (sp > locals) {
14971497
sp--;
1498+
if (PyStackRef_IsNullOrInt(*sp)) {
1499+
continue;
1500+
}
14981501
PyObject *op = PyStackRef_AsPyObjectBorrow(*sp);
1499-
if (op == NULL || _Py_IsImmortal(op)) {
1502+
if (_Py_IsImmortal(op)) {
15001503
continue;
15011504
}
15021505
if (_PyObject_IS_GC(op)) {

Python/gc_free_threading.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1694,7 +1694,7 @@ _PyGC_VisitStackRef(_PyStackRef *ref, visitproc visit, void *arg)
16941694
// This is a bit tricky! We want to ignore deferred references when
16951695
// computing the incoming references, but otherwise treat them like
16961696
// regular references.
1697-
if (!PyStackRef_IsDeferred(*ref) ||
1697+
if (PyStackRef_IsDeferred(*ref) ||
16981698
(visit != visit_decref && visit != visit_decref_unreachable))
16991699
{
17001700
Py_VISIT(PyStackRef_AsPyObjectBorrow(*ref));

Python/generated_cases.c.h

Lines changed: 11 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)