summaryrefslogtreecommitdiff
path: root/coverage/tracer.c
diff options
context:
space:
mode:
Diffstat (limited to 'coverage/tracer.c')
-rw-r--r--coverage/tracer.c116
1 files changed, 59 insertions, 57 deletions
diff --git a/coverage/tracer.c b/coverage/tracer.c
index bfebf1d4..3cf8c81d 100644
--- a/coverage/tracer.c
+++ b/coverage/tracer.c
@@ -54,10 +54,23 @@
frame.
*/
typedef struct {
- PyObject * file_data; /* PyMem_Malloc'ed, a borrowed ref. */
+ /* The current file_data dictionary. Borrowed. */
+ PyObject * file_data;
+
+ /* The line number of the last line recorded, for tracing arcs.
+ -1 means there was no previous line, as when entering a code object.
+ */
int last_line;
} DataStackEntry;
+/* A data stack is a dynamically allocated vector of DataStackEntry's. */
+typedef struct {
+ int depth; /* The index of the last-used entry in stack. */
+ int alloc; /* number of entries allocated at stack. */
+ /* The file data at each level, or NULL if not recording. */
+ DataStackEntry * stack;
+} DataStack;
+
/* The CTracer type. */
typedef struct {
@@ -87,19 +100,11 @@ typedef struct {
the keys are line numbers. In both cases, the value is irrelevant
(None).
*/
- /* The index of the last-used entry in data_stack. */
- int depth;
- /* The file data at each level, or NULL if not recording. */
- DataStackEntry * data_stack;
- int data_stack_alloc; /* number of entries allocated at data_stack. */
- /* The current file_data dictionary. Borrowed. */
- PyObject * cur_file_data;
+ DataStack data_stack;
- /* The line number of the last line recorded, for tracing arcs.
- -1 means there was no previous line, as when entering a code object.
- */
- int last_line;
+ /* The current file's data stack entry, copied from the stack. */
+ DataStackEntry cur_entry;
/* The parent frame for the last exception event, to fix missing returns. */
PyFrameObject * last_exc_back;
@@ -147,17 +152,17 @@ CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused)
self->started = 0;
self->tracing_arcs = 0;
- self->depth = -1;
- self->data_stack = PyMem_Malloc(STACK_DELTA*sizeof(DataStackEntry));
- if (self->data_stack == NULL) {
+ self->data_stack.depth = -1;
+ self->data_stack.stack = PyMem_Malloc(STACK_DELTA*sizeof(DataStackEntry));
+ if (self->data_stack.stack == NULL) {
STATS( self->stats.errors++; )
PyErr_NoMemory();
return RET_ERROR;
}
- self->data_stack_alloc = STACK_DELTA;
+ self->data_stack.alloc = STACK_DELTA;
- self->cur_file_data = NULL;
- self->last_line = -1;
+ self->cur_entry.file_data = NULL;
+ self->cur_entry.last_line = -1;
self->last_exc_back = NULL;
@@ -177,7 +182,7 @@ CTracer_dealloc(CTracer *self)
Py_XDECREF(self->data);
Py_XDECREF(self->should_trace_cache);
- PyMem_Free(self->data_stack);
+ PyMem_Free(self->data_stack.stack);
Py_TYPE(self)->tp_free((PyObject*)self);
}
@@ -232,7 +237,7 @@ showlog(int depth, int lineno, PyObject * filename, const char * msg)
static const char * what_sym[] = {"CALL", "EXC ", "LINE", "RET "};
#endif
-/* Record a pair of integers in self->cur_file_data. */
+/* Record a pair of integers in self->cur_entry.file_data. */
static int
CTracer_record_pair(CTracer *self, int l1, int l2)
{
@@ -240,7 +245,7 @@ CTracer_record_pair(CTracer *self, int l1, int l2)
PyObject * t = Py_BuildValue("(ii)", l1, l2);
if (t != NULL) {
- if (PyDict_SetItem(self->cur_file_data, t, Py_None) < 0) {
+ if (PyDict_SetItem(self->cur_entry.file_data, t, Py_None) < 0) {
STATS( self->stats.errors++; )
ret = RET_ERROR;
}
@@ -309,16 +314,15 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse
we'll need to keep more of the missed frame's state.
*/
STATS( self->stats.missed_returns++; )
- if (self->depth >= 0) {
- if (self->tracing_arcs && self->cur_file_data) {
- if (CTracer_record_pair(self, self->last_line, -self->last_exc_firstlineno) < 0) {
+ if (self->data_stack.depth >= 0) {
+ if (self->tracing_arcs && self->cur_entry.file_data) {
+ if (CTracer_record_pair(self, self->cur_entry.last_line, -self->last_exc_firstlineno) < 0) {
return RET_ERROR;
}
}
- SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "missedreturn");
- self->cur_file_data = self->data_stack[self->depth].file_data;
- self->last_line = self->data_stack[self->depth].last_line;
- self->depth--;
+ SHOWLOG(self->data_stack.depth, frame->f_lineno, frame->f_code->co_filename, "missedreturn");
+ self->cur_entry = self->data_stack.stack[self->data_stack.depth];
+ self->data_stack.depth--;
}
}
self->last_exc_back = NULL;
@@ -329,25 +333,24 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse
case PyTrace_CALL: /* 0 */
STATS( self->stats.calls++; )
/* Grow the stack. */
- self->depth++;
- if (self->depth >= self->data_stack_alloc) {
+ self->data_stack.depth++;
+ if (self->data_stack.depth >= self->data_stack.alloc) {
STATS( self->stats.stack_reallocs++; )
/* We've outgrown our data_stack array: make it bigger. */
- int bigger = self->data_stack_alloc + STACK_DELTA;
- DataStackEntry * bigger_data_stack = PyMem_Realloc(self->data_stack, bigger * sizeof(DataStackEntry));
+ int bigger = self->data_stack.alloc + STACK_DELTA;
+ DataStackEntry * bigger_data_stack = PyMem_Realloc(self->data_stack.stack, bigger * sizeof(DataStackEntry));
if (bigger_data_stack == NULL) {
STATS( self->stats.errors++; )
PyErr_NoMemory();
- self->depth--;
+ self->data_stack.depth--;
return RET_ERROR;
}
- self->data_stack = bigger_data_stack;
- self->data_stack_alloc = bigger;
+ self->data_stack.stack = bigger_data_stack;
+ self->data_stack.alloc = bigger;
}
/* Push the current state on the stack. */
- self->data_stack[self->depth].file_data = self->cur_file_data;
- self->data_stack[self->depth].last_line = self->last_line;
+ self->data_stack.stack[self->data_stack.depth] = self->cur_entry;
/* Check if we should trace this line. */
filename = frame->f_code->co_filename;
@@ -399,50 +402,49 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse
return RET_ERROR;
}
}
- self->cur_file_data = file_data;
+ self->cur_entry.file_data = file_data;
/* Make the frame right in case settrace(gettrace()) happens. */
Py_INCREF(self);
frame->f_trace = (PyObject*)self;
- SHOWLOG(self->depth, frame->f_lineno, filename, "traced");
+ SHOWLOG(self->data_stack.depth, frame->f_lineno, filename, "traced");
}
else {
- self->cur_file_data = NULL;
- SHOWLOG(self->depth, frame->f_lineno, filename, "skipped");
+ self->cur_entry.file_data = NULL;
+ SHOWLOG(self->data_stack.depth, frame->f_lineno, filename, "skipped");
}
Py_DECREF(tracename);
Py_DECREF(disposition);
- self->last_line = -1;
+ self->cur_entry.last_line = -1;
break;
case PyTrace_RETURN: /* 3 */
STATS( self->stats.returns++; )
/* A near-copy of this code is above in the missing-return handler. */
- if (self->depth >= 0) {
- if (self->tracing_arcs && self->cur_file_data) {
+ if (self->data_stack.depth >= 0) {
+ if (self->tracing_arcs && self->cur_entry.file_data) {
int first = frame->f_code->co_firstlineno;
- if (CTracer_record_pair(self, self->last_line, -first) < 0) {
+ if (CTracer_record_pair(self, self->cur_entry.last_line, -first) < 0) {
return RET_ERROR;
}
}
- SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "return");
- self->cur_file_data = self->data_stack[self->depth].file_data;
- self->last_line = self->data_stack[self->depth].last_line;
- self->depth--;
+ SHOWLOG(self->data_stack.depth, frame->f_lineno, frame->f_code->co_filename, "return");
+ self->cur_entry = self->data_stack.stack[self->data_stack.depth];
+ self->data_stack.depth--;
}
break;
case PyTrace_LINE: /* 2 */
STATS( self->stats.lines++; )
- if (self->depth >= 0) {
- SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "line");
- if (self->cur_file_data) {
+ if (self->data_stack.depth >= 0) {
+ SHOWLOG(self->data_stack.depth, frame->f_lineno, frame->f_code->co_filename, "line");
+ if (self->cur_entry.file_data) {
/* We're tracing in this frame: record something. */
if (self->tracing_arcs) {
/* Tracing arcs: key is (last_line,this_line). */
- if (CTracer_record_pair(self, self->last_line, frame->f_lineno) < 0) {
+ if (CTracer_record_pair(self, self->cur_entry.last_line, frame->f_lineno) < 0) {
return RET_ERROR;
}
}
@@ -453,7 +455,7 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse
STATS( self->stats.errors++; )
return RET_ERROR;
}
- ret = PyDict_SetItem(self->cur_file_data, this_line, Py_None);
+ ret = PyDict_SetItem(self->cur_entry.file_data, this_line, Py_None);
Py_DECREF(this_line);
if (ret < 0) {
STATS( self->stats.errors++; )
@@ -461,7 +463,7 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse
}
}
}
- self->last_line = frame->f_lineno;
+ self->cur_entry.last_line = frame->f_lineno;
}
break;
@@ -577,7 +579,7 @@ CTracer_start(CTracer *self, PyObject *args_unused)
PyEval_SetTrace((Py_tracefunc)CTracer_trace, (PyObject*)self);
self->started = 1;
self->tracing_arcs = self->arcs && PyObject_IsTrue(self->arcs);
- self->last_line = -1;
+ self->cur_entry.last_line = -1;
/* start() returns a trace function usable with sys.settrace() */
Py_INCREF(self);
@@ -609,7 +611,7 @@ CTracer_get_stats(CTracer *self)
"new_files", self->stats.new_files,
"missed_returns", self->stats.missed_returns,
"stack_reallocs", self->stats.stack_reallocs,
- "stack_alloc", self->data_stack_alloc,
+ "stack_alloc", self->data_stack.alloc,
"errors", self->stats.errors
);
#else