Skip to content

Commit 33b1fe4

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

7 files changed

Lines changed: 58 additions & 43 deletions

File tree

Include/internal/pycore_stackref.h

Lines changed: 25 additions & 0 deletions
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

@@ -451,6 +475,7 @@ PyStackRef_RefcountOnObject(_PyStackRef ref)
451475
static inline PyObject *
452476
PyStackRef_AsPyObjectBorrow(_PyStackRef ref)
453477
{
478+
assert(!PyStackRef_IsTaggedInt(ref));
454479
return BITS_TO_PTR_MASKED(ref);
455480
}
456481

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: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,8 +547,10 @@ _PyGC_VisitStackRef(_PyStackRef *ref, visitproc visit, void *arg)
547547
// This is a bit tricky! We want to ignore stackrefs with embedded
548548
// refcounts when computing the incoming references, but otherwise treat
549549
// them like normal.
550-
if (!PyStackRef_RefcountOnObject(*ref) && (visit == visit_decref)) {
551-
return 0;
550+
if (!PyStackRef_RefcountOnObject(*ref)) {
551+
if (visit == visit_decref || PyStackRef_IsTaggedInt(*ref)) {
552+
return 0;
553+
}
552554
}
553555
Py_VISIT(PyStackRef_AsPyObjectBorrow(*ref));
554556
return 0;
@@ -1495,6 +1497,9 @@ mark_stacks(PyInterpreterState *interp, PyGC_Head *visited, int visited_space, b
14951497
objects_marked += move_to_reachable(func, &reachable, visited_space);
14961498
while (sp > locals) {
14971499
sp--;
1500+
if (PyStackRef_IsTaggedInt(*sp)) {
1501+
continue;
1502+
}
14981503
PyObject *op = PyStackRef_AsPyObjectBorrow(*sp);
14991504
if (op == NULL || _Py_IsImmortal(op)) {
15001505
continue;

Python/gc_free_threading.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,11 +1694,12 @@ _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) ||
1698-
(visit != visit_decref && visit != visit_decref_unreachable))
1699-
{
1700-
Py_VISIT(PyStackRef_AsPyObjectBorrow(*ref));
1697+
if (PyStackRef_IsDeferred(*ref)) {
1698+
if ((visit != visit_decref && visit != visit_decref_unreachable) || PyStackRef_IsTaggedInt(*ref)) {
1699+
return 0;
1700+
}
17011701
}
1702+
Py_VISIT(PyStackRef_AsPyObjectBorrow(*ref));
17021703
return 0;
17031704
}
17041705

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)