Skip to content

Commit a5991bf

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

File tree

7 files changed

+64
-40
lines changed

7 files changed

+64
-40
lines changed

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: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ _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+
assert(!PyStackRef_IsTaggedInt(*ref));
550551
if (!PyStackRef_RefcountOnObject(*ref) && (visit == visit_decref)) {
551552
return 0;
552553
}
@@ -560,7 +561,9 @@ _PyGC_VisitFrameStack(_PyInterpreterFrame *frame, visitproc visit, void *arg)
560561
_PyStackRef *ref = _PyFrame_GetLocalsArray(frame);
561562
/* locals and stack */
562563
for (; ref < frame->stackpointer; ref++) {
563-
_Py_VISIT_STACKREF(*ref);
564+
if (!PyStackRef_IsTaggedInt(*ref)) {
565+
_Py_VISIT_STACKREF(*ref);
566+
}
564567
}
565568
return 0;
566569
}
@@ -1495,8 +1498,11 @@ mark_stacks(PyInterpreterState *interp, PyGC_Head *visited, int visited_space, b
14951498
objects_marked += move_to_reachable(func, &reachable, visited_space);
14961499
while (sp > locals) {
14971500
sp--;
1501+
if (PyStackRef_IsNullOrInt(*sp)) {
1502+
continue;
1503+
}
14981504
PyObject *op = PyStackRef_AsPyObjectBorrow(*sp);
1499-
if (op == NULL || _Py_IsImmortal(op)) {
1505+
if (_Py_IsImmortal(op)) {
15001506
continue;
15011507
}
15021508
if (_PyObject_IS_GC(op)) {

Python/gc_free_threading.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,6 +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+
assert(!PyStackRef_IsTaggedInt(*ref));
16971698
if (!PyStackRef_IsDeferred(*ref) ||
16981699
(visit != visit_decref && visit != visit_decref_unreachable))
16991700
{

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)