Mark Shannon avatar Mark Shannon committed c03dd08 Draft

Ensure trace execution/recording cannot happen recursively due to GC.

Comments (0)

Files changed (6)

Include/pystate.h

     long thread_id; /* Thread id where this tstate was created */
 
     PyObject *registers[HOTPY_REGISTER_COUNT];
-    int trace_recording;
+    int trace_executing;
     PyObject *trace_cache;
     struct _optimiserobject* optimiser;
     struct _hotpy_context* execution_context;
         tstate->trace_cache = NULL;
         tstate->optimiser = NULL;
         tstate->execution_context = NULL;
-        tstate->trace_recording = 0;
+        tstate->trace_executing = 0;
 #ifdef Py_DEBUG
         tstate->_InstructionLog = NULL;
 #endif

Python/recording_interpreter.c

         retval = PyEval_EvalFrame_C(tstate, NULL, WHY_NOT);
     while (tstate->real_frame != caller_frame) {
         if (retval.why == WHY_NOT && py_surrogates_loaded &&
-            tstate->trace_recording == 0) {
+            tstate->trace_executing == 0) {
             /* FindTrace returns a new reference which Execute steals */
             int stack = tstate->real_frame->f_stacktop -
                         tstate->real_frame->f_valuestack;

Python/register_interpreter.c

         TRANSFER_TO(exit_trace, exit->exit_context);
     }
     if (exit->exit_trace == NULL) {
+        HotPyReturnValue res;
         if (tstate->execution_context) {
             HotPy_RestoreThreadState(tstate, tstate->execution_context);
             tstate->execution_context = NULL;
         }
         Py_DECREF(trace);
-        return HotPyTraceObject_RaiseAtExit(tstate, exit);
+        /* Decrement trace_executing to allow tracing to continue */
+        tstate->trace_executing--;
+        res = HotPyTraceObject_RaiseAtExit(tstate, exit);
+        tstate->trace_executing++;
+        return res;
     }
     _HotPy_Stats.exception_exits++;
     goto handle_error;

Python/trace_interpreter.c

         TRANSFER_TO(exit_trace, exit->exit_context);
     }
     if (exit->exit_trace == NULL) {
+        HotPyReturnValue res;
         if (tstate->execution_context) {
             HotPy_RestoreThreadState(tstate, tstate->execution_context);
             tstate->execution_context = NULL;
         }
         Py_DECREF(trace);
-        return HotPyTraceObject_RaiseAtExit(tstate, exit);
+        /* Decrement trace_executing to allow tracing to continue */
+        tstate->trace_executing--;
+        res = HotPyTraceObject_RaiseAtExit(tstate, exit);
+        tstate->trace_executing++;
+        return res;
     }
     _HotPy_Stats.exception_exits++;
     goto handle_error;

Python/trace_manager.c

 {
     HotPyReturnValue ret;
     assert(trace->status == TRACE_INVALID);
+    assert(ts->trace_executing == 1);
     trace->execution_count++;
     HotPy_RestoreThreadState(ts, trace->trace_context);
-    if (ts->trace_recording > 0 || _Py_TracingPossible ||
-        trace->execution_count <= _HotPy_Thresholds.warm) {
+    if (_Py_TracingPossible || trace->execution_count <= _HotPy_Thresholds.warm) {
         Py_DECREF(trace);
         return (HotPyReturnValue)
             { HotPyIP_ToAddr(trace->trace_context->cf_instrs[0]), WHY_NOT };
     ts->optimiser->start_context = trace->trace_context;
     ts->optimiser->instruction_count = 0;
     ts->optimiser->start(ts->optimiser, trace, ts->real_frame, trace->trace_context, reason);
-    ts->trace_recording++;
     assert(ts->real_frame->f_stacktop);
     ret = PyEval_RecordingEval(ts, trace->trace_context, ts->optimiser);
     assert(trace->status != TRACE_NOT_READY);
-    ts->trace_recording--;
     ts->optimiser->clear(ts->optimiser);
     ts->optimiser->start_context = NULL;
     Py_DECREF(trace);
 HotPyTrace_Execute(PyThreadState *tstate, HotPyTraceObject *trace)
 {
     HotPyReturnValue result;
+    assert(tstate->trace_executing == 0);
+    tstate->trace_executing++;
     if (trace->status == TRACE_VALID) {
         if (_HotPy_Options.register_vm)
             result = _HotPy_TraceRegisterInterpreter(tstate, trace);
     else {
         result = _HotPy_TraceExcecuteCold(tstate, trace, "top-level");
     }
+    tstate->trace_executing--;
     assert(tstate->execution_context == NULL);
     return result;
 }
     HotPyTraceObject *trace;
     PyObject *e_ty, *e_ex, *e_tb, *key;
     assert(PyErr_Occurred());
-    if (ts->trace_recording > 0 || ++exit->execution_count < _HotPy_Thresholds.warm)
+    if (ts->trace_executing > 0 || ++exit->execution_count < _HotPy_Thresholds.warm)
         return(HotPyReturnValue) { NULL, WHY_EXCEPTION };
     /* Want to unwind the stack as much as possible,
     adjusting the context and recording as we go */
     ts->optimiser->instruction_count = 0;
     ts->optimiser->start(ts->optimiser, trace, ts->real_frame, trace->trace_context, "raise");
     PyErr_Restore(e_ty, e_ex, e_tb);
-    ts->trace_recording++;
+    ts->trace_executing++;
     res = _HotPy_RecordUnwinding(ts, ts->optimiser, trace->trace_context);
     assert(trace->status != TRACE_NOT_READY);
-    ts->trace_recording--;
+    ts->trace_executing--;
     ts->optimiser->clear(ts->optimiser);
     if (res.why == WHY_EXCEPTION) {
         Py_DECREF(trace);
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.