Skip to content

Commit 163475f

Browse files
committed
Fixes
1 parent 39a9041 commit 163475f

File tree

7 files changed

+111
-20
lines changed

7 files changed

+111
-20
lines changed

Include/internal/pycore_interpframe.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *
214214

215215
#ifdef Py_GIL_DISABLED
216216
static inline void
217-
_PyFrame_InitializeTLBC(PyThreadState *tstate, _PyInterpreterFrameCore *frame,
217+
_PyFrame_InitializeTLBC(PyThreadState *tstate, _PyInterpreterFrame *frame,
218218
PyCodeObject *code)
219219
{
220220
_Py_CODEUNIT *tlbc = _PyCode_GetTLBCFast(tstate, code);

Lib/test/test_capi/test_misc.py

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import _thread
55
from collections import deque
66
import contextlib
7-
import dis
87
import importlib.machinery
98
import importlib.util
109
import json
@@ -2858,6 +2857,85 @@ def func():
28582857
names = ["func", "outer", "outer", "inner", "inner", "outer", "inner"]
28592858
self.do_test(func, names)
28602859

2860+
def test_jit_frame(self):
2861+
def fakefunc():
2862+
pass
2863+
2864+
def f():
2865+
return sys._getframe(1)
2866+
2867+
res = _testinternalcapi.call_with_jit_frame(fakefunc, f, ())
2868+
2869+
def test_jit_frame_globals(self):
2870+
"""jit executable can fill in globals when accessed"""
2871+
def fakefunc():
2872+
pass
2873+
2874+
fake_globals = {"abc":42}
2875+
def callback():
2876+
return {"globals": fake_globals}
2877+
2878+
res = _testinternalcapi.call_with_jit_frame(fakefunc, globals, (), callback)
2879+
self.assertEqual(res, fake_globals)
2880+
2881+
def test_jit_frame_builtins(self):
2882+
"""jit executable can fill in builtins when accessed"""
2883+
def fakefunc():
2884+
pass
2885+
2886+
fake_builtins = {"abc":42}
2887+
def callback():
2888+
return {"builtins": fake_builtins}
2889+
2890+
res = _testinternalcapi.call_with_jit_frame(fakefunc, _testlimitedcapi.eval_getbuiltins, (), callback)
2891+
self.assertEqual(res, fake_builtins)
2892+
2893+
def test_jit_frame_instr_ptr(self):
2894+
"""jit executable can fill in the instr ptr each time the frame is queried"""
2895+
def fakefunc():
2896+
pass
2897+
pass
2898+
pass
2899+
pass
2900+
2901+
offset = 0
2902+
linenos = []
2903+
def test():
2904+
for op in dis.get_instructions(fakefunc):
2905+
if op.opname in ("RESUME", "NOP", "RETURN_VALUE"):
2906+
nonlocal offset
2907+
offset = op.offset//2
2908+
linenos.append(sys._getframe(1).f_lineno)
2909+
2910+
def callback():
2911+
return {"instr_ptr": offset}
2912+
2913+
_testinternalcapi.call_with_jit_frame(fakefunc, test, (), callback)
2914+
base = fakefunc.__code__.co_firstlineno
2915+
self.assertEqual(linenos, [base, base + 1, base + 2, base + 3, base + 4])
2916+
2917+
def test_jit_frame_code(self):
2918+
"""internal C api checks the for a code executor"""
2919+
def fakefunc():
2920+
pass
2921+
2922+
def callback():
2923+
return _testinternalcapi.iframe_getcode(sys._getframe(1))
2924+
2925+
res = _testinternalcapi.call_with_jit_frame(fakefunc, callback, ())
2926+
self.assertEqual(res, fakefunc.__code__)
2927+
2928+
def test_jit_frame_line(self):
2929+
"""internal C api checks the for a code executor"""
2930+
def fakefunc():
2931+
pass
2932+
2933+
def callback():
2934+
return _testinternalcapi.iframe_getline(sys._getframe(1))
2935+
2936+
res = _testinternalcapi.call_with_jit_frame(fakefunc, callback, ())
2937+
self.assertEqual(res, fakefunc.__code__.co_firstlineno)
2938+
28612939

28622940
@unittest.skipUnless(support.Py_GIL_DISABLED, 'need Py_GIL_DISABLED')
28632941
class TestPyThreadId(unittest.TestCase):

Modules/_testinternalcapi/interpreter.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ Test_EvalFrame(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)
100100
/* Load thread-local bytecode */
101101
if (frame->tlbc_index != ((_PyThreadStateImpl *)tstate)->tlbc_index) {
102102
_Py_CODEUNIT *bytecode =
103-
_PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame));
103+
_PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(_PyFrame_Core(frame)));
104104
if (bytecode == NULL) {
105105
goto early_exit;
106106
}
107-
ptrdiff_t off = frame->instr_ptr - _PyFrame_GetBytecode(frame);
107+
ptrdiff_t off = frame->instr_ptr - _PyFrame_GetBytecode(_PyFrame_Core(frame));
108108
frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index;
109109
frame->instr_ptr = bytecode + off;
110110
}

Python/ceval.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,11 +1225,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
12251225
/* Load thread-local bytecode */
12261226
if (frame->tlbc_index != ((_PyThreadStateImpl *)tstate)->tlbc_index) {
12271227
_Py_CODEUNIT *bytecode =
1228-
_PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame));
1228+
_PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(_PyFrame_Core(frame)));
12291229
if (bytecode == NULL) {
12301230
goto early_exit;
12311231
}
1232-
ptrdiff_t off = frame->instr_ptr - _PyFrame_GetBytecode(frame);
1232+
ptrdiff_t off = frame->instr_ptr - _PyFrame_GetBytecode(_PyFrame_Core(frame));
12331233
frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index;
12341234
frame->instr_ptr = bytecode + off;
12351235
}

Python/ceval_macros.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
277277
#if defined(Py_DEBUG) && !defined(_Py_JIT)
278278
// This allows temporary stack "overflows", provided it's all in the cache at any point of time.
279279
#define WITHIN_STACK_BOUNDS_IGNORING_CACHE() \
280-
(frame->owner == FRAME_OWNED_BY_INTERPRETER || (STACK_LEVEL() >= 0 && (STACK_LEVEL()) <= STACK_SIZE()))
280+
(_PyFrame_Core(frame)->owner == FRAME_OWNED_BY_INTERPRETER || (STACK_LEVEL() >= 0 && (STACK_LEVEL()) <= STACK_SIZE()))
281281
#else
282282
#define WITHIN_STACK_BOUNDS_IGNORING_CACHE WITHIN_STACK_BOUNDS
283283
#endif

Python/gc_free_threading.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -278,18 +278,23 @@ frame_disable_deferred_refcounting(_PyInterpreterFrameCore *frame)
278278
frame->owner & FRAME_OWNED_BY_GENERATOR);
279279

280280
frame->f_executable = PyStackRef_AsStrongReference(frame->f_executable);
281+
if (_PyFrame_IsExternalFrame(frame)) {
282+
return;
283+
}
284+
285+
_PyInterpreterFrame *f = _PyFrame_Full(frame);
281286

282287
if (frame->owner & FRAME_OWNED_BY_GENERATOR) {
283-
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame);
288+
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(f);
284289
if (gen->gi_frame_state == FRAME_CLEARED) {
285290
// gh-124068: if the generator is cleared, then most fields other
286291
// than f_executable are not valid.
287292
return;
288293
}
289294
}
290295

291-
frame->f_funcobj = PyStackRef_AsStrongReference(frame->f_funcobj);
292-
for (_PyStackRef *ref = frame->localsplus; ref < frame->stackpointer; ref++) {
296+
f->f_funcobj = PyStackRef_AsStrongReference(f->f_funcobj);
297+
for (_PyStackRef *ref = f->localsplus; ref < f->stackpointer; ref++) {
293298
if (!PyStackRef_IsNullOrInt(*ref) && !PyStackRef_RefcountOnObject(*ref)) {
294299
*ref = PyStackRef_AsStrongReference(*ref);
295300
}
@@ -315,10 +320,10 @@ disable_deferred_refcounting(PyObject *op)
315320
// use strong references, in case the generator or frame object is
316321
// resurrected by a finalizer.
317322
if (PyGen_CheckExact(op) || PyCoro_CheckExact(op) || PyAsyncGen_CheckExact(op)) {
318-
frame_disable_deferred_refcounting(&((PyGenObject *)op)->gi_iframe);
323+
frame_disable_deferred_refcounting(_PyFrame_Core(&((PyGenObject *)op)->gi_iframe));
319324
}
320325
else if (PyFrame_Check(op)) {
321-
frame_disable_deferred_refcounting(((PyFrameObject *)op)->f_frame);
326+
frame_disable_deferred_refcounting(_PyFrame_Core(((PyFrameObject *)op)->f_frame));
322327
}
323328
}
324329

@@ -478,11 +483,12 @@ gc_visit_thread_stacks(PyInterpreterState *interp, struct collection_state *stat
478483
}
479484

480485
for (_PyInterpreterFrameCore *f = p->current_frame; f != NULL; f = f->previous) {
481-
if (f->owner >= FRAME_OWNED_BY_INTERPRETER) {
486+
if (f->owner >= FRAME_OWNED_BY_INTERPRETER || _PyFrame_IsExternalFrame(f)) {
482487
continue;
483488
}
484489

485-
_PyStackRef *top = f->stackpointer;
490+
_PyInterpreterFrame *frame = _PyFrame_Full(f);
491+
_PyStackRef *top = frame->stackpointer;
486492
if (top == NULL) {
487493
// GH-129236: The stackpointer may be NULL in cases where
488494
// the GC is run during a PyStackRef_CLOSE() call. Skip this
@@ -492,7 +498,7 @@ gc_visit_thread_stacks(PyInterpreterState *interp, struct collection_state *stat
492498
}
493499

494500
gc_visit_stackref(f->f_executable);
495-
while (top != f->localsplus) {
501+
while (top != frame->localsplus) {
496502
--top;
497503
gc_visit_stackref(*top);
498504
}
@@ -875,23 +881,24 @@ gc_visit_thread_stacks_mark_alive(PyInterpreterState *interp, gc_mark_args_t *ar
875881
int err = 0;
876882
_Py_FOR_EACH_TSTATE_BEGIN(interp, p) {
877883
for (_PyInterpreterFrameCore *f = p->current_frame; f != NULL; f = f->previous) {
878-
if (f->owner >= FRAME_OWNED_BY_INTERPRETER) {
884+
if (f->owner >= FRAME_OWNED_BY_INTERPRETER || _PyFrame_IsExternalFrame(f)) {
879885
continue;
880886
}
881887

882-
if (f->stackpointer == NULL) {
888+
_PyInterpreterFrame *frame = _PyFrame_Full(f);
889+
if (frame->stackpointer == NULL) {
883890
// GH-129236: The stackpointer may be NULL in cases where
884891
// the GC is run during a PyStackRef_CLOSE() call. Skip this
885892
// frame for now.
886893
continue;
887894
}
888895

889-
_PyStackRef *top = f->stackpointer;
896+
_PyStackRef *top = frame->stackpointer;
890897
if (gc_visit_stackref_mark_alive(args, f->f_executable) < 0) {
891898
err = -1;
892899
goto exit;
893900
}
894-
while (top != f->localsplus) {
901+
while (top != frame->localsplus) {
895902
--top;
896903
if (gc_visit_stackref_mark_alive(args, *top) < 0) {
897904
err = -1;

Tools/gdb/libpython.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1138,7 +1138,13 @@ def _f_lasti(self):
11381138
return int(instr_ptr - first_instr)
11391139

11401140
def core(self):
1141-
return self._gdbval['core']
1141+
try:
1142+
return self._gdbval['core']
1143+
except:
1144+
import traceback
1145+
traceback.print_stack()
1146+
print('no core', self._gdbval, self._gdbval.type)
1147+
return None
11421148

11431149
def is_shim(self):
11441150
return int(self.core()['owner']) == FRAME_OWNED_BY_INTERPRETER

0 commit comments

Comments
 (0)