1 /////////////// Profile.proto ///////////////
2 //@requires: Exceptions.c::PyErrFetchRestore
3 //@substitute: naming
4 
5 // Note that cPython ignores PyTrace_EXCEPTION,
6 // but maybe some other profilers don't.
7 
8 #ifndef CYTHON_PROFILE
9 #if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON
10   #define CYTHON_PROFILE 0
11 #else
12   #define CYTHON_PROFILE 1
13 #endif
14 #endif
15 
16 #ifndef CYTHON_TRACE_NOGIL
17   #define CYTHON_TRACE_NOGIL 0
18 #else
19   #if CYTHON_TRACE_NOGIL && !defined(CYTHON_TRACE)
20     #define CYTHON_TRACE 1
21   #endif
22 #endif
23 
24 #ifndef CYTHON_TRACE
25   #define CYTHON_TRACE 0
26 #endif
27 
28 #if CYTHON_TRACE
29   #undef CYTHON_PROFILE_REUSE_FRAME
30 #endif
31 
32 #ifndef CYTHON_PROFILE_REUSE_FRAME
33   #define CYTHON_PROFILE_REUSE_FRAME 0
34 #endif
35 
36 #if CYTHON_PROFILE || CYTHON_TRACE
37 
38   #include "compile.h"
39   #include "frameobject.h"
40   #include "traceback.h"
41 
42   #if CYTHON_PROFILE_REUSE_FRAME
43     #define CYTHON_FRAME_MODIFIER static
44     #define CYTHON_FRAME_DEL(frame)
45   #else
46     #define CYTHON_FRAME_MODIFIER
47     #define CYTHON_FRAME_DEL(frame) Py_CLEAR(frame)
48   #endif
49 
50   #define __Pyx_TraceDeclarations                                         \
51       static PyCodeObject *$frame_code_cname = NULL;                      \
52       CYTHON_FRAME_MODIFIER PyFrameObject *$frame_cname = NULL;           \
53       int __Pyx_use_tracing = 0;
54 
55   #define __Pyx_TraceFrameInit(codeobj)                                   \
56       if (codeobj) $frame_code_cname = (PyCodeObject*) codeobj;
57 
58 #if PY_VERSION_HEX >= 0x030a00b1
59   #define __Pyx_IsTracing(tstate, check_tracing, check_funcs) \
60      (unlikely((tstate)->cframe->use_tracing) && \
61          (!(check_tracing) || !(tstate)->tracing) && \
62          (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc)))
63 
64   #define __Pyx_SetTracing(tstate, enable) \
65       (tstate)->cframe->use_tracing = (enable)
66 
67 #else
68   #define __Pyx_IsTracing(tstate, check_tracing, check_funcs) \
69      (unlikely((tstate)->use_tracing) && \
70          (!(check_tracing) || !(tstate)->tracing) && \
71          (!(check_funcs) || (tstate)->c_profilefunc || (CYTHON_TRACE && (tstate)->c_tracefunc)))
72 
73   #define __Pyx_SetTracing(tstate, enable) \
74       (tstate)->use_tracing = (enable)
75 #endif
76 
77   #ifdef WITH_THREAD
78   #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error)             \
79   if (nogil) {                                                                           \
80       if (CYTHON_TRACE_NOGIL) {                                                          \
81           PyThreadState *tstate;                                                         \
82           PyGILState_STATE state = PyGILState_Ensure();                                  \
83           tstate = __Pyx_PyThreadState_Current;                                          \
84           if (__Pyx_IsTracing(tstate, 1, 1)) {                                           \
85               __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&$frame_code_cname, &$frame_cname, tstate, funcname, srcfile, firstlineno);  \
86           }                                                                              \
87           PyGILState_Release(state);                                                     \
88           if (unlikely(__Pyx_use_tracing < 0)) goto_error;                               \
89       }                                                                                  \
90   } else {                                                                               \
91       PyThreadState* tstate = PyThreadState_GET();                                       \
92       if (__Pyx_IsTracing(tstate, 1, 1)) {                                               \
93           __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&$frame_code_cname, &$frame_cname, tstate, funcname, srcfile, firstlineno);  \
94           if (unlikely(__Pyx_use_tracing < 0)) goto_error;                               \
95       }                                                                                  \
96   }
97   #else
98   #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error)             \
99   {   PyThreadState* tstate = PyThreadState_GET();                                       \
100       if (__Pyx_IsTracing(tstate, 1, 1)) {                                               \
101           __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&$frame_code_cname, &$frame_cname, tstate, funcname, srcfile, firstlineno);  \
102           if (unlikely(__Pyx_use_tracing < 0)) goto_error;                               \
103       }                                                                                  \
104   }
105   #endif
106 
107   #define __Pyx_TraceException()                                                           \
108   if (likely(!__Pyx_use_tracing)); else {                                                  \
109       PyThreadState* tstate = __Pyx_PyThreadState_Current;                                 \
110       if (__Pyx_IsTracing(tstate, 0, 1)) {                                                 \
111           tstate->tracing++;                                                               \
112           __Pyx_SetTracing(tstate, 0);                                                     \
113           PyObject *exc_info = __Pyx_GetExceptionTuple(tstate);                            \
114           if (exc_info) {                                                                  \
115               if (CYTHON_TRACE && tstate->c_tracefunc)                                     \
116                   tstate->c_tracefunc(                                                     \
117                       tstate->c_traceobj, $frame_cname, PyTrace_EXCEPTION, exc_info);      \
118               tstate->c_profilefunc(                                                       \
119                   tstate->c_profileobj, $frame_cname, PyTrace_EXCEPTION, exc_info);        \
120               Py_DECREF(exc_info);                                                         \
121           }                                                                                \
122           __Pyx_SetTracing(tstate, 1);                                                     \
123           tstate->tracing--;                                                               \
124       }                                                                                    \
125   }
126 
__Pyx_call_return_trace_func(PyThreadState * tstate,PyFrameObject * frame,PyObject * result)127   static void __Pyx_call_return_trace_func(PyThreadState *tstate, PyFrameObject *frame, PyObject *result) {
128       PyObject *type, *value, *traceback;
129       __Pyx_ErrFetchInState(tstate, &type, &value, &traceback);
130       tstate->tracing++;
131       __Pyx_SetTracing(tstate, 0);
132       if (CYTHON_TRACE && tstate->c_tracefunc)
133           tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_RETURN, result);
134       if (tstate->c_profilefunc)
135           tstate->c_profilefunc(tstate->c_profileobj, frame, PyTrace_RETURN, result);
136       CYTHON_FRAME_DEL(frame);
137       __Pyx_SetTracing(tstate, 1);
138       tstate->tracing--;
139       __Pyx_ErrRestoreInState(tstate, type, value, traceback);
140   }
141 
142   #ifdef WITH_THREAD
143   #define __Pyx_TraceReturn(result, nogil)                                                \
144   if (likely(!__Pyx_use_tracing)); else {                                                 \
145       if (nogil) {                                                                        \
146           if (CYTHON_TRACE_NOGIL) {                                                       \
147               PyThreadState *tstate;                                                      \
148               PyGILState_STATE state = PyGILState_Ensure();                               \
149               tstate = __Pyx_PyThreadState_Current;                                       \
150               if (__Pyx_IsTracing(tstate, 0, 0)) {                                        \
151                   __Pyx_call_return_trace_func(tstate, $frame_cname, (PyObject*)result);  \
152               }                                                                           \
153               PyGILState_Release(state);                                                  \
154           }                                                                               \
155       } else {                                                                            \
156           PyThreadState* tstate = __Pyx_PyThreadState_Current;                            \
157           if (__Pyx_IsTracing(tstate, 0, 0)) {                                            \
158               __Pyx_call_return_trace_func(tstate, $frame_cname, (PyObject*)result);      \
159           }                                                                               \
160       }                                                                                   \
161   }
162   #else
163   #define __Pyx_TraceReturn(result, nogil)                                                \
164   if (likely(!__Pyx_use_tracing)); else {                                                 \
165       PyThreadState* tstate = __Pyx_PyThreadState_Current;                                \
166       if (__Pyx_IsTracing(tstate, 0, 0)) {                                                \
167           __Pyx_call_return_trace_func(tstate, $frame_cname, (PyObject*)result);          \
168       }                                                                                   \
169   }
170   #endif
171 
172   static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno); /*proto*/
173   static int __Pyx_TraceSetupAndCall(PyCodeObject** code, PyFrameObject** frame, PyThreadState* tstate, const char *funcname, const char *srcfile, int firstlineno); /*proto*/
174 
175 #else
176 
177   #define __Pyx_TraceDeclarations
178   #define __Pyx_TraceFrameInit(codeobj)
179   // mark error label as used to avoid compiler warnings
180   #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error)   if ((1)); else goto_error;
181   #define __Pyx_TraceException()
182   #define __Pyx_TraceReturn(result, nogil)
183 
184 #endif /* CYTHON_PROFILE */
185 
186 #if CYTHON_TRACE
187   // see call_trace_protected() in CPython's ceval.c
__Pyx_call_line_trace_func(PyThreadState * tstate,PyFrameObject * frame,int lineno)188   static int __Pyx_call_line_trace_func(PyThreadState *tstate, PyFrameObject *frame, int lineno) {
189       int ret;
190       PyObject *type, *value, *traceback;
191       __Pyx_ErrFetchInState(tstate, &type, &value, &traceback);
192       __Pyx_PyFrame_SetLineNumber(frame, lineno);
193       tstate->tracing++;
194       __Pyx_SetTracing(tstate, 0);
195 
196       ret = tstate->c_tracefunc(tstate->c_traceobj, frame, PyTrace_LINE, NULL);
197 
198       __Pyx_SetTracing(tstate, 1);
199       tstate->tracing--;
200       if (likely(!ret)) {
201           __Pyx_ErrRestoreInState(tstate, type, value, traceback);
202       } else {
203           Py_XDECREF(type);
204           Py_XDECREF(value);
205           Py_XDECREF(traceback);
206       }
207       return ret;
208   }
209 
210   #ifdef WITH_THREAD
211   #define __Pyx_TraceLine(lineno, nogil, goto_error)                                       \
212   if (likely(!__Pyx_use_tracing)); else {                                                  \
213       if (nogil) {                                                                         \
214           if (CYTHON_TRACE_NOGIL) {                                                        \
215               int ret = 0;                                                                 \
216               PyThreadState *tstate;                                                       \
217               PyGILState_STATE state = PyGILState_Ensure();                                \
218               tstate = __Pyx_PyThreadState_Current;                                        \
219               if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && $frame_cname->f_trace) { \
220                   ret = __Pyx_call_line_trace_func(tstate, $frame_cname, lineno);          \
221               }                                                                            \
222               PyGILState_Release(state);                                                   \
223               if (unlikely(ret)) goto_error;                                               \
224           }                                                                                \
225       } else {                                                                             \
226           PyThreadState* tstate = __Pyx_PyThreadState_Current;                             \
227           if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && $frame_cname->f_trace) { \
228               int ret = __Pyx_call_line_trace_func(tstate, $frame_cname, lineno);          \
229               if (unlikely(ret)) goto_error;                                               \
230           }                                                                                \
231       }                                                                                    \
232   }
233   #else
234   #define __Pyx_TraceLine(lineno, nogil, goto_error)                                       \
235   if (likely(!__Pyx_use_tracing)); else {                                                  \
236       PyThreadState* tstate = __Pyx_PyThreadState_Current;                                 \
237       if (__Pyx_IsTracing(tstate, 0, 0) && tstate->c_tracefunc && $frame_cname->f_trace) { \
238           int ret = __Pyx_call_line_trace_func(tstate, $frame_cname, lineno);              \
239           if (unlikely(ret)) goto_error;                                                   \
240       }                                                                                    \
241   }
242   #endif
243 #else
244   // mark error label as used to avoid compiler warnings
245   #define __Pyx_TraceLine(lineno, nogil, goto_error)   if ((1)); else goto_error;
246 #endif
247 
248 /////////////// Profile ///////////////
249 //@substitute: naming
250 
251 #if CYTHON_PROFILE
252 
__Pyx_TraceSetupAndCall(PyCodeObject ** code,PyFrameObject ** frame,PyThreadState * tstate,const char * funcname,const char * srcfile,int firstlineno)253 static int __Pyx_TraceSetupAndCall(PyCodeObject** code,
254                                    PyFrameObject** frame,
255                                    PyThreadState* tstate,
256                                    const char *funcname,
257                                    const char *srcfile,
258                                    int firstlineno) {
259     PyObject *type, *value, *traceback;
260     int retval;
261     if (*frame == NULL || !CYTHON_PROFILE_REUSE_FRAME) {
262         if (*code == NULL) {
263             *code = __Pyx_createFrameCodeObject(funcname, srcfile, firstlineno);
264             if (*code == NULL) return 0;
265         }
266         *frame = PyFrame_New(
267             tstate,                          /*PyThreadState *tstate*/
268             *code,                           /*PyCodeObject *code*/
269             $moddict_cname,                  /*PyObject *globals*/
270             0                                /*PyObject *locals*/
271         );
272         if (*frame == NULL) return 0;
273         if (CYTHON_TRACE && (*frame)->f_trace == NULL) {
274             // this enables "f_lineno" lookup, at least in CPython ...
275             Py_INCREF(Py_None);
276             (*frame)->f_trace = Py_None;
277         }
278 #if PY_VERSION_HEX < 0x030400B1
279     } else {
280         (*frame)->f_tstate = tstate;
281 #endif
282     }
283     __Pyx_PyFrame_SetLineNumber(*frame, firstlineno);
284 
285     retval = 1;
286     tstate->tracing++;
287     __Pyx_SetTracing(tstate, 0);
288     __Pyx_ErrFetchInState(tstate, &type, &value, &traceback);
289 
290     #if CYTHON_TRACE
291     if (tstate->c_tracefunc)
292         retval = tstate->c_tracefunc(tstate->c_traceobj, *frame, PyTrace_CALL, NULL) == 0;
293     if (retval && tstate->c_profilefunc)
294     #endif
295         retval = tstate->c_profilefunc(tstate->c_profileobj, *frame, PyTrace_CALL, NULL) == 0;
296 
297     __Pyx_SetTracing(tstate, (tstate->c_profilefunc || (CYTHON_TRACE && tstate->c_tracefunc)));
298     tstate->tracing--;
299     if (retval) {
300         __Pyx_ErrRestoreInState(tstate, type, value, traceback);
301         return __Pyx_IsTracing(tstate, 0, 0) && retval;
302     } else {
303         Py_XDECREF(type);
304         Py_XDECREF(value);
305         Py_XDECREF(traceback);
306         return -1;
307     }
308 }
309 
__Pyx_createFrameCodeObject(const char * funcname,const char * srcfile,int firstlineno)310 static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno) {
311     PyCodeObject *py_code = 0;
312 
313 #if PY_MAJOR_VERSION >= 3
314     py_code = PyCode_NewEmpty(srcfile, funcname, firstlineno);
315     // make CPython use a fresh dict for "f_locals" at need (see GH #1836)
316     if (likely(py_code)) {
317         py_code->co_flags |= CO_OPTIMIZED | CO_NEWLOCALS;
318     }
319 #else
320     PyObject *py_srcfile = 0;
321     PyObject *py_funcname = 0;
322 
323     py_funcname = PyString_FromString(funcname);
324     if (unlikely(!py_funcname)) goto bad;
325     py_srcfile = PyString_FromString(srcfile);
326     if (unlikely(!py_srcfile)) goto bad;
327 
328     py_code = PyCode_New(
329         0,                /*int argcount,*/
330         0,                /*int nlocals,*/
331         0,                /*int stacksize,*/
332         // make CPython use a fresh dict for "f_locals" at need (see GH #1836)
333         CO_OPTIMIZED | CO_NEWLOCALS,  /*int flags,*/
334         $empty_bytes,     /*PyObject *code,*/
335         $empty_tuple,     /*PyObject *consts,*/
336         $empty_tuple,     /*PyObject *names,*/
337         $empty_tuple,     /*PyObject *varnames,*/
338         $empty_tuple,     /*PyObject *freevars,*/
339         $empty_tuple,     /*PyObject *cellvars,*/
340         py_srcfile,       /*PyObject *filename,*/
341         py_funcname,      /*PyObject *name,*/
342         firstlineno,      /*int firstlineno,*/
343         $empty_bytes      /*PyObject *lnotab*/
344     );
345 
346 bad:
347     Py_XDECREF(py_srcfile);
348     Py_XDECREF(py_funcname);
349 #endif
350 
351     return py_code;
352 }
353 
354 #endif /* CYTHON_PROFILE */
355