@@ -37,6 +37,7 @@ typedef struct {
37
37
PyCodeObject * code ; // The code object for the bounds. May be NULL.
38
38
int instr_prev ; // Only valid if code != NULL.
39
39
PyCodeAddressRange bounds ; // Only valid if code != NULL.
40
+ CFrame cframe ;
40
41
} PyTraceInfo ;
41
42
42
43
@@ -1109,8 +1110,6 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type,
1109
1110
static int do_raise (PyThreadState * tstate , PyObject * exc , PyObject * cause );
1110
1111
static int unpack_iterable (PyThreadState * , PyObject * , int , int , PyObject * * );
1111
1112
1112
- #define _Py_TracingPossible (ceval ) ((ceval)->tracing_possible)
1113
-
1114
1113
1115
1114
PyObject *
1116
1115
PyEval_EvalCode (PyObject * co , PyObject * globals , PyObject * locals )
@@ -1307,7 +1306,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
1307
1306
1308
1307
#define DISPATCH () \
1309
1308
{ \
1310
- if (_Py_TracingPossible(ceval2) OR_DTRACE_LINE OR_LLTRACE) { \
1309
+ if (trace_info.cframe.use_tracing OR_DTRACE_LINE OR_LLTRACE) { \
1311
1310
goto tracing_dispatch; \
1312
1311
} \
1313
1312
f->f_lasti = INSTR_OFFSET(); \
@@ -1595,8 +1594,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
1595
1594
int oparg ; /* Current opcode argument, if any */
1596
1595
PyObject * * fastlocals , * * freevars ;
1597
1596
PyObject * retval = NULL ; /* Return value */
1598
- struct _ceval_state * const ceval2 = & tstate -> interp -> ceval ;
1599
- _Py_atomic_int * const eval_breaker = & ceval2 -> eval_breaker ;
1597
+ _Py_atomic_int * const eval_breaker = & tstate -> interp -> ceval .eval_breaker ;
1600
1598
PyCodeObject * co ;
1601
1599
1602
1600
const _Py_CODEUNIT * first_instr ;
@@ -1616,11 +1614,20 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
1616
1614
/* Mark trace_info as uninitialized */
1617
1615
trace_info .code = NULL ;
1618
1616
1617
+ /* WARNING: Because the CFrame lives on the C stack,
1618
+ * but can be accessed from a heap allocated object (tstate)
1619
+ * strict stack discipline must be maintained.
1620
+ */
1621
+ CFrame * prev_cframe = tstate -> cframe ;
1622
+ trace_info .cframe .use_tracing = prev_cframe -> use_tracing ;
1623
+ trace_info .cframe .previous = prev_cframe ;
1624
+ tstate -> cframe = & trace_info .cframe ;
1625
+
1619
1626
/* push frame */
1620
1627
tstate -> frame = f ;
1621
1628
co = f -> f_code ;
1622
1629
1623
- if (tstate -> use_tracing ) {
1630
+ if (trace_info . cframe . use_tracing ) {
1624
1631
if (tstate -> c_tracefunc != NULL ) {
1625
1632
/* tstate->c_tracefunc, if defined, is a
1626
1633
function that will be called on *every* entry
@@ -1782,7 +1789,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
1782
1789
1783
1790
/* line-by-line tracing support */
1784
1791
1785
- if (_Py_TracingPossible ( ceval2 ) &&
1792
+ if (trace_info . cframe . use_tracing &&
1786
1793
tstate -> c_tracefunc != NULL && !tstate -> tracing ) {
1787
1794
int err ;
1788
1795
/* see maybe_call_line_trace()
@@ -4543,7 +4550,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
4543
4550
PUSH (val );
4544
4551
PUSH (exc );
4545
4552
JUMPTO (handler );
4546
- if (_Py_TracingPossible ( ceval2 ) ) {
4553
+ if (trace_info . cframe . use_tracing ) {
4547
4554
trace_info .instr_prev = INT_MAX ;
4548
4555
}
4549
4556
/* Resume normal execution */
@@ -4567,7 +4574,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
4567
4574
f -> f_stackdepth = 0 ;
4568
4575
f -> f_state = FRAME_RAISED ;
4569
4576
exiting :
4570
- if (tstate -> use_tracing ) {
4577
+ if (trace_info . cframe . use_tracing ) {
4571
4578
if (tstate -> c_tracefunc ) {
4572
4579
if (call_trace_protected (tstate -> c_tracefunc , tstate -> c_traceobj ,
4573
4580
tstate , f , & trace_info , PyTrace_RETURN , retval )) {
@@ -4584,6 +4591,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
4584
4591
4585
4592
/* pop frame */
4586
4593
exit_eval_frame :
4594
+ /* Restore previous cframe */
4595
+ tstate -> cframe = trace_info .cframe .previous ;
4596
+ tstate -> cframe -> use_tracing = trace_info .cframe .use_tracing ;
4597
+
4587
4598
if (PyDTrace_FUNCTION_RETURN_ENABLED ())
4588
4599
dtrace_function_return (f );
4589
4600
_Py_LeaveRecursiveCall (tstate );
@@ -5507,7 +5518,7 @@ call_trace(Py_tracefunc func, PyObject *obj,
5507
5518
if (tstate -> tracing )
5508
5519
return 0 ;
5509
5520
tstate -> tracing ++ ;
5510
- tstate -> use_tracing = 0 ;
5521
+ tstate -> cframe -> use_tracing = 0 ;
5511
5522
if (frame -> f_lasti < 0 ) {
5512
5523
frame -> f_lineno = frame -> f_code -> co_firstlineno ;
5513
5524
}
@@ -5517,7 +5528,7 @@ call_trace(Py_tracefunc func, PyObject *obj,
5517
5528
}
5518
5529
result = func (obj , frame , what , arg );
5519
5530
frame -> f_lineno = 0 ;
5520
- tstate -> use_tracing = ((tstate -> c_tracefunc != NULL )
5531
+ tstate -> cframe -> use_tracing = ((tstate -> c_tracefunc != NULL )
5521
5532
|| (tstate -> c_profilefunc != NULL ));
5522
5533
tstate -> tracing -- ;
5523
5534
return result ;
@@ -5528,15 +5539,15 @@ _PyEval_CallTracing(PyObject *func, PyObject *args)
5528
5539
{
5529
5540
PyThreadState * tstate = _PyThreadState_GET ();
5530
5541
int save_tracing = tstate -> tracing ;
5531
- int save_use_tracing = tstate -> use_tracing ;
5542
+ int save_use_tracing = tstate -> cframe -> use_tracing ;
5532
5543
PyObject * result ;
5533
5544
5534
5545
tstate -> tracing = 0 ;
5535
- tstate -> use_tracing = ((tstate -> c_tracefunc != NULL )
5546
+ tstate -> cframe -> use_tracing = ((tstate -> c_tracefunc != NULL )
5536
5547
|| (tstate -> c_profilefunc != NULL ));
5537
5548
result = PyObject_Call (func , args , NULL );
5538
5549
tstate -> tracing = save_tracing ;
5539
- tstate -> use_tracing = save_use_tracing ;
5550
+ tstate -> cframe -> use_tracing = save_use_tracing ;
5540
5551
return result ;
5541
5552
}
5542
5553
@@ -5590,15 +5601,15 @@ _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
5590
5601
tstate -> c_profilefunc = NULL ;
5591
5602
tstate -> c_profileobj = NULL ;
5592
5603
/* Must make sure that tracing is not ignored if 'profileobj' is freed */
5593
- tstate -> use_tracing = tstate -> c_tracefunc != NULL ;
5604
+ tstate -> cframe -> use_tracing = tstate -> c_tracefunc != NULL ;
5594
5605
Py_XDECREF (profileobj );
5595
5606
5596
5607
Py_XINCREF (arg );
5597
5608
tstate -> c_profileobj = arg ;
5598
5609
tstate -> c_profilefunc = func ;
5599
5610
5600
5611
/* Flag that tracing or profiling is turned on */
5601
- tstate -> use_tracing = (func != NULL ) || (tstate -> c_tracefunc != NULL );
5612
+ tstate -> cframe -> use_tracing = (func != NULL ) || (tstate -> c_tracefunc != NULL );
5602
5613
return 0 ;
5603
5614
}
5604
5615
@@ -5626,22 +5637,20 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
5626
5637
return -1 ;
5627
5638
}
5628
5639
5629
- struct _ceval_state * ceval2 = & tstate -> interp -> ceval ;
5630
5640
PyObject * traceobj = tstate -> c_traceobj ;
5631
- ceval2 -> tracing_possible += (func != NULL ) - (tstate -> c_tracefunc != NULL );
5632
5641
5633
5642
tstate -> c_tracefunc = NULL ;
5634
5643
tstate -> c_traceobj = NULL ;
5635
5644
/* Must make sure that profiling is not ignored if 'traceobj' is freed */
5636
- tstate -> use_tracing = (tstate -> c_profilefunc != NULL );
5645
+ tstate -> cframe -> use_tracing = (tstate -> c_profilefunc != NULL );
5637
5646
Py_XDECREF (traceobj );
5638
5647
5639
5648
Py_XINCREF (arg );
5640
5649
tstate -> c_traceobj = arg ;
5641
5650
tstate -> c_tracefunc = func ;
5642
5651
5643
5652
/* Flag that tracing or profiling is turned on */
5644
- tstate -> use_tracing = ((func != NULL )
5653
+ tstate -> cframe -> use_tracing = ((func != NULL )
5645
5654
|| (tstate -> c_profilefunc != NULL ));
5646
5655
5647
5656
return 0 ;
@@ -5836,7 +5845,7 @@ PyEval_GetFuncDesc(PyObject *func)
5836
5845
}
5837
5846
5838
5847
#define C_TRACE (x , call ) \
5839
- if (tstate-> use_tracing && tstate->c_profilefunc) { \
5848
+ if (trace_info->cframe. use_tracing && tstate->c_profilefunc) { \
5840
5849
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
5841
5850
tstate, tstate->frame, trace_info, \
5842
5851
PyTrace_C_CALL, func)) { \
@@ -5917,7 +5926,7 @@ call_function(PyThreadState *tstate,
5917
5926
Py_ssize_t nargs = oparg - nkwargs ;
5918
5927
PyObject * * stack = (* pp_stack ) - nargs - nkwargs ;
5919
5928
5920
- if (tstate -> use_tracing ) {
5929
+ if (trace_info -> cframe . use_tracing ) {
5921
5930
x = trace_call_function (tstate , trace_info , func , stack , nargs , kwnames );
5922
5931
}
5923
5932
else {
@@ -5950,7 +5959,7 @@ do_call_core(PyThreadState *tstate,
5950
5959
}
5951
5960
else if (Py_IS_TYPE (func , & PyMethodDescr_Type )) {
5952
5961
Py_ssize_t nargs = PyTuple_GET_SIZE (callargs );
5953
- if (nargs > 0 && tstate -> use_tracing ) {
5962
+ if (nargs > 0 && trace_info -> cframe . use_tracing ) {
5954
5963
/* We need to create a temporary bound method as argument
5955
5964
for profiling.
5956
5965
0 commit comments