struct arc_info *pred_next;
} arc_t;
+/* Describes which locations (lines and files) are associated with
+ a basic block. */
+
+struct block_location_info
+{
+ block_location_info (unsigned _source_file_idx):
+ source_file_idx (_source_file_idx)
+ {}
+
+ unsigned source_file_idx;
+ vector<unsigned> lines;
+};
+
/* Describes a basic block. Contains lists of arcs to successor and
predecessor blocks. */
/* Block is a landing pad for longjmp or throw. */
unsigned is_nonlocal_return : 1;
- union
+ vector<block_location_info> locations;
+
+ struct
{
- struct
- {
- /* Array of line numbers and source files. source files are
- introduced by a linenumber of zero, the next 'line number' is
- the number of the source file. Always starts with a source
- file. */
- unsigned *encoding;
- unsigned num;
- } line; /* Valid until blocks are linked onto lines */
- struct
- {
- /* Single line graph cycle workspace. Used for all-blocks
- mode. */
- arc_t *arc;
- unsigned ident;
- } cycle; /* Used in all-blocks mode, after blocks are linked onto
- lines. */
- } u;
+ /* Single line graph cycle workspace. Used for all-blocks
+ mode. */
+ arc_t *arc;
+ unsigned ident;
+ } cycle; /* Used in all-blocks mode, after blocks are linked onto
+ lines. */
/* Temporary chain for solving graph, and for chaining blocks on one
line. */
typedef struct function_info
{
+ function_info ();
+ ~function_info ();
+
/* Name of function. */
char *name;
char *demangled_name;
at blocks[0] and the exit block is at blocks[1]. */
#define ENTRY_BLOCK (0)
#define EXIT_BLOCK (1)
- block_t *blocks;
- unsigned num_blocks;
+ vector<block_t> blocks;
unsigned blocks_executed;
/* Raw arc coverage counts. */
static char *make_gcov_file_name (const char *, const char *);
static char *mangle_name (const char *, char *);
static void release_structures (void);
-static void release_function (function_t *);
extern int main (int, char **);
+function_info::function_info ()
+{
+ /* The type is POD, so that we can use memset. */
+ memset (this, 0, sizeof (*this));
+}
+
+function_info::~function_info ()
+{
+ for (int i = blocks.size () - 1; i >= 0; i--)
+ {
+ arc_t *arc, *arc_n;
+
+ for (arc = blocks[i].succ; arc; arc = arc_n)
+ {
+ arc_n = arc->succ_next;
+ free (arc);
+ }
+ }
+ free (counts);
+ if (flag_demangled_names && demangled_name != name)
+ free (demangled_name);
+ free (name);
+}
+
/* Cycle detection!
There are a bajillion algorithms that do this. Boost's function is named
hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
*prev = fn;
/* Mark last line in files touched by function. */
- for (block_no = 0; block_no != fn->num_blocks; block_no++)
+ for (block_no = 0; block_no != fn->blocks.size (); block_no++)
{
- unsigned *enc = fn->blocks[block_no].u.line.encoding;
- unsigned num = fn->blocks[block_no].u.line.num;
+ block_t *block = &fn->blocks[block_no];
+ for (unsigned i = 0; i < block->locations.size (); i++)
+ {
+ unsigned s = block->locations[i].source_file_idx;
- for (; num--; enc++)
- if (!*enc)
- {
- if (enc[1] != src)
- {
- if (line >= sources[src].num_lines)
- sources[src].num_lines = line + 1;
- line = 0;
- src = enc[1];
- }
- enc++;
- num--;
- }
- else if (*enc > line)
- line = *enc;
+ /* Sort lines of locations. */
+ sort (block->locations[i].lines.begin (),
+ block->locations[i].lines.end ());
+
+ if (!block->locations[i].lines.empty ())
+ {
+ unsigned last_line
+ = block->locations[i].lines.back () + 1;
+ if (last_line > sources[s].num_lines)
+ sources[s].num_lines = last_line;
+ }
+ }
}
- if (line >= sources[src].num_lines)
- sources[src].num_lines = line + 1;
solve_flow_graph (fn);
if (fn->has_catch)
else
/* The function was not in the executable -- some other
instance must have been selected. */
- release_function (fn);
+ delete fn;
}
}
executed_summary (total_lines, total_executed);
}
-/* Release a function structure */
-
-static void
-release_function (function_t *fn)
-{
- unsigned ix;
- block_t *block;
-
- for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
- {
- arc_t *arc, *arc_n;
-
- for (arc = block->succ; arc; arc = arc_n)
- {
- arc_n = arc->succ_next;
- free (arc);
- }
- }
- free (fn->blocks);
- free (fn->counts);
- if (flag_demangled_names && fn->demangled_name != fn->name)
- free (fn->demangled_name);
- free (fn->name);
-}
-
/* Release all memory used. */
static void
while ((fn = functions))
{
functions = fn->next;
- release_function (fn);
+ delete fn;
}
}
function_t *fn = NULL;
function_t *fns = NULL;
function_t **fns_end = &fns;
- unsigned src_idx = 0;
- unsigned ix;
unsigned tag;
if (!gcov_open (bbg_file_name, 1))
lineno_checksum = gcov_read_unsigned ();
cfg_checksum = gcov_read_unsigned ();
function_name = xstrdup (gcov_read_string ());
- src_idx = find_source (gcov_read_string ());
+ unsigned src_idx = find_source (gcov_read_string ());
lineno = gcov_read_unsigned ();
- fn = XCNEW (function_t);
+ fn = new function_t;
fn->name = function_name;
if (flag_demangled_names)
{
}
else if (fn && tag == GCOV_TAG_BLOCKS)
{
- if (fn->blocks)
+ if (!fn->blocks.empty ())
fnotice (stderr, "%s:already seen blocks for '%s'\n",
bbg_file_name, fn->name);
else
- {
- fn->num_blocks = gcov_read_unsigned ();
- fn->blocks = XCNEWVEC (block_t, fn->num_blocks);
- }
+ fn->blocks.resize (gcov_read_unsigned ());
}
else if (fn && tag == GCOV_TAG_ARCS)
{
unsigned mark_catches = 0;
struct arc_info *arc;
- if (src >= fn->num_blocks || fn->blocks[src].succ)
+ if (src >= fn->blocks.size () || fn->blocks[src].succ)
goto corrupt;
while (num_dests--)
unsigned dest = gcov_read_unsigned ();
unsigned flags = gcov_read_unsigned ();
- if (dest >= fn->num_blocks)
+ if (dest >= fn->blocks.size ())
goto corrupt;
arc = XCNEW (arc_t);
else if (fn && tag == GCOV_TAG_LINES)
{
unsigned blockno = gcov_read_unsigned ();
- unsigned *line_nos = XCNEWVEC (unsigned, length - 1);
+ block_t *block = &fn->blocks[blockno];
- if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
+ if (blockno >= fn->blocks.size ())
goto corrupt;
- for (ix = 0; ; )
+ while (true)
{
unsigned lineno = gcov_read_unsigned ();
if (lineno)
- {
- if (!ix)
- {
- line_nos[ix++] = 0;
- line_nos[ix++] = src_idx;
- }
- line_nos[ix++] = lineno;
- }
+ block->locations.back ().lines.push_back (lineno);
else
{
const char *file_name = gcov_read_string ();
if (!file_name)
break;
- src_idx = find_source (file_name);
- line_nos[ix++] = 0;
- line_nos[ix++] = src_idx;
+ block->locations.push_back (block_location_info
+ (find_source (file_name)));
}
}
-
- fn->blocks[blockno].u.line.encoding = line_nos;
- fn->blocks[blockno].u.line.num = ix;
}
else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
{
block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */
/* The arcs were built in reverse order. Fix that now. */
- for (ix = fn->num_blocks; ix--;)
+ for (ix = fn->blocks.size (); ix--;)
{
arc_t *arc_p, *arc_n;
fn->blocks[ix].pred = arc_p;
}
- if (fn->num_blocks < 2)
+ if (fn->blocks.size () < 2)
fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
bbg_file_name, fn->name);
else
/* Propagate the measured counts, this must be done in the same
order as the code in profile.c */
- for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
+ for (unsigned i = 0; i < fn->blocks.size (); i++)
{
+ blk = &fn->blocks[i];
block_t const *prev_dst = NULL;
int out_of_order = 0;
int non_fake_succ = 0;
/* If the graph has been correctly solved, every block will have a
valid count. */
- for (ix = 0; ix < fn->num_blocks; ix++)
- if (!fn->blocks[ix].count_valid)
+ for (unsigned i = 0; ix < fn->blocks.size (); i++)
+ if (!fn->blocks[i].count_valid)
{
fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
bbg_file_name, fn->name);
find_exception_blocks (function_t *fn)
{
unsigned ix;
- block_t **queue = XALLOCAVEC (block_t *, fn->num_blocks);
+ block_t **queue = XALLOCAVEC (block_t *, fn->blocks.size ());
/* First mark all blocks as exceptional. */
- for (ix = fn->num_blocks; ix--;)
+ for (ix = fn->blocks.size (); ix--;)
fn->blocks[ix].exceptional = 1;
/* Now mark all the blocks reachable via non-fake edges */
- queue[0] = fn->blocks;
+ queue[0] = &fn->blocks[0];
queue[0]->exceptional = 0;
for (ix = 1; ix;)
{
next. */
/* Scan each basic block. */
- for (ix = 0; ix != fn->num_blocks; ix++)
+ for (ix = 0; ix != fn->blocks.size (); ix++)
{
block_t *block = &fn->blocks[ix];
- unsigned *encoding;
- const source_t *src = NULL;
- unsigned jx;
-
- if (block->count && ix && ix + 1 != fn->num_blocks)
+ if (block->count && ix && ix + 1 != fn->blocks.size ())
fn->blocks_executed++;
- for (jx = 0, encoding = block->u.line.encoding;
- jx != block->u.line.num; jx++, encoding++)
- if (!*encoding)
- {
- src = &sources[*++encoding];
- jx++;
- }
- else
- {
- line = &src->lines[*encoding];
+ for (unsigned i = 0; i < block->locations.size (); i++)
+ {
+ const source_t *src = &sources[block->locations[i].source_file_idx];
- if (coverage)
- {
- if (!line->exists)
- coverage->lines++;
- if (!line->count && block->count)
- coverage->lines_executed++;
- }
- line->exists = 1;
- if (!block->exceptional)
- line->unexceptional = 1;
- line->count += block->count;
- }
- free (block->u.line.encoding);
- block->u.cycle.arc = NULL;
- block->u.cycle.ident = ~0U;
+ vector<unsigned> &lines = block->locations[i].lines;
+ for (unsigned j = 0; j < lines.size (); j++)
+ {
+ line = &src->lines[lines[j]];
+ if (coverage)
+ {
+ if (!line->exists)
+ coverage->lines++;
+ if (!line->count && block->count)
+ coverage->lines_executed++;
+ }
+ line->exists = 1;
+ if (!block->exceptional)
+ line->unexceptional = 1;
+ line->count += block->count;
+ }
+ }
+ block->cycle.arc = NULL;
+ block->cycle.ident = ~0U;
- if (!ix || ix + 1 == fn->num_blocks)
+ if (!ix || ix + 1 == fn->blocks.size ())
/* Entry or exit block */;
else if (flag_all_blocks)
{
{
block_n = block->chain;
block->chain = block_p;
- block->u.cycle.ident = ix;
+ block->cycle.ident = ix;
}
line->u.blocks = block_p;
fprintf (gcov_file, " returned %s",
format_gcov (return_count, called_count, 0));
fprintf (gcov_file, " blocks executed %s",
- format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
+ format_gcov (fn->blocks_executed, fn->blocks.size () - 2,
+ 0));
fprintf (gcov_file, "\n");
}