@@ -50,33 +50,47 @@ bool PyTemporaryReferenceTracer::isLineNewStatement(PyObject* code, int line) {
5050
5151
5252int PyTemporaryReferenceTracer::globalTraceFun (PyObject* dummyObj, PyFrameObject* frame, int what, PyObject* arg) {
53- if (frame != globalTracer.mostRecentEmptyFrame ) {
54- bool shouldProcess = true ;
55-
56- if (what == PyTrace_LINE) {
57- shouldProcess = globalTracer.isLineNewStatement (
58- (PyObject*)frame->f_code ,
59- frame->f_lineno
60- );
61- }
53+ if (frame != globalTracer.mostRecentEmptyFrame &&
54+ globalTracer.frameToActions .find (frame) != globalTracer.frameToActions .end ()) {
55+ // always process exception and return statements
56+ bool forceProcess = (
57+ what == PyTrace_EXCEPTION ||
58+ what == PyTrace_RETURN
59+ );
6260
63- if (shouldProcess) {
64- auto it = globalTracer.frameToHandles .find (frame);
61+ // we process any statement on a line that's a new statement
62+ bool shouldProcess = globalTracer.isLineNewStatement (
63+ (PyObject*)frame->f_code ,
64+ PyFrame_GetLineNumber (frame)
65+ );
6566
66- if (it == globalTracer.frameToHandles .end ()) {
67+ if (shouldProcess || forceProcess) {
68+ auto it = globalTracer.frameToActions .find (frame);
69+
70+ if (it == globalTracer.frameToActions .end ()) {
6771 globalTracer.mostRecentEmptyFrame = frame;
6872 } else {
6973 globalTracer.mostRecentEmptyFrame = nullptr ;
7074
71- for (auto objAndAction: it->second ) {
72- if (objAndAction.second == TraceAction::ConvertTemporaryReference) {
73- ((PyInstance*)objAndAction.first )->resolveTemporaryReference ();
74- }
75+ std::vector<FrameAction> persistingActions;
7576
76- decref (objAndAction.first );
77+ for (auto & frameAction: it->second ) {
78+ if (frameAction.lineNumber != PyFrame_GetLineNumber (frame) || forceProcess) {
79+ if (frameAction.action == TraceAction::ConvertTemporaryReference) {
80+ ((PyInstance*)frameAction.obj )->resolveTemporaryReference ();
81+ }
82+
83+ decref (frameAction.obj );
84+ } else {
85+ persistingActions.push_back (frameAction);
86+ }
7787 }
7888
79- globalTracer.frameToHandles .erase (it);
89+ if (persistingActions.size ()) {
90+ it->second = persistingActions;
91+ } else {
92+ globalTracer.frameToActions .erase (it);
93+ }
8094 }
8195 }
8296 }
@@ -88,7 +102,7 @@ int PyTemporaryReferenceTracer::globalTraceFun(PyObject* dummyObj, PyFrameObject
88102 );
89103 }
90104
91- if (globalTracer.frameToHandles .size () == 0 ) {
105+ if (globalTracer.frameToActions .size () == 0 ) {
92106 // uninstall ourself
93107 PyEval_SetTrace (globalTracer.priorTraceFunc , globalTracer.priorTraceFuncArg );
94108 decref (globalTracer.priorTraceFuncArg );
@@ -115,7 +129,13 @@ void PyTemporaryReferenceTracer::installGlobalTraceHandlerIfNecessary() {
115129
116130void PyTemporaryReferenceTracer::traceObject (PyObject* o, PyFrameObject* f) {
117131 // mark that we're going to trace
118- globalTracer.frameToHandles [f].push_back (std::make_pair (incref (o), TraceAction::ConvertTemporaryReference));
132+ globalTracer.frameToActions [f].push_back (
133+ FrameAction (
134+ incref (o),
135+ TraceAction::ConvertTemporaryReference,
136+ PyFrame_GetLineNumber (f)
137+ )
138+ );
119139
120140 if (globalTracer.mostRecentEmptyFrame == f) {
121141 globalTracer.mostRecentEmptyFrame = nullptr ;
@@ -126,7 +146,13 @@ void PyTemporaryReferenceTracer::traceObject(PyObject* o, PyFrameObject* f) {
126146
127147void PyTemporaryReferenceTracer::keepaliveForCurrentInstruction (PyObject* o, PyFrameObject* f) {
128148 // mark that we're going to trace
129- globalTracer.frameToHandles [f].push_back (std::make_pair (incref (o), TraceAction::Decref));
149+ globalTracer.frameToActions [f].push_back (
150+ FrameAction (
151+ incref (o),
152+ TraceAction::Decref,
153+ PyFrame_GetLineNumber (f)
154+ )
155+ );
130156
131157 if (globalTracer.mostRecentEmptyFrame == f) {
132158 globalTracer.mostRecentEmptyFrame = nullptr ;
0 commit comments