diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2014-07-20 20:31:12 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2014-07-20 20:31:12 -0400 |
commit | a8ace9db7e4ba7fbcf2a068b8f1e52fee5a3624a (patch) | |
tree | 641b0bd7b21190fa368fe674ed221cb6776daeb7 /coverage/tracer.c | |
parent | 7bebd77165852ba165406df1587f8b9a69ab1363 (diff) | |
download | python-coveragepy-git-a8ace9db7e4ba7fbcf2a068b8f1e52fee5a3624a.tar.gz |
Refactor some C tracer code in prep for data stacks
--HG--
branch : c-coroutine
Diffstat (limited to 'coverage/tracer.c')
-rw-r--r-- | coverage/tracer.c | 116 |
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 |