123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872 |
- /* Data and functions related to line maps and input files.
- Copyright (C) 2004-2015 Free Software Foundation, Inc.
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "intl.h"
- #include "input.h"
- #include "vec.h"
- /* This is a cache used by get_next_line to store the content of a
- file to be searched for file lines. */
- struct fcache
- {
- /* These are information used to store a line boundary. */
- struct line_info
- {
- /* The line number. It starts from 1. */
- size_t line_num;
- /* The position (byte count) of the beginning of the line,
- relative to the file data pointer. This starts at zero. */
- size_t start_pos;
- /* The position (byte count) of the last byte of the line. This
- normally points to the '\n' character, or to one byte after the
- last byte of the file, if the file doesn't contain a '\n'
- character. */
- size_t end_pos;
- line_info (size_t l, size_t s, size_t e)
- : line_num (l), start_pos (s), end_pos (e)
- {}
- line_info ()
- :line_num (0), start_pos (0), end_pos (0)
- {}
- };
- /* The number of time this file has been accessed. This is used
- to designate which file cache to evict from the cache
- array. */
- unsigned use_count;
- const char *file_path;
- FILE *fp;
- /* This points to the content of the file that we've read so
- far. */
- char *data;
- /* The size of the DATA array above.*/
- size_t size;
- /* The number of bytes read from the underlying file so far. This
- must be less (or equal) than SIZE above. */
- size_t nb_read;
- /* The index of the beginning of the current line. */
- size_t line_start_idx;
- /* The number of the previous line read. This starts at 1. Zero
- means we've read no line so far. */
- size_t line_num;
- /* This is the total number of lines of the current file. At the
- moment, we try to get this information from the line map
- subsystem. Note that this is just a hint. When using the C++
- front-end, this hint is correct because the input file is then
- completely tokenized before parsing starts; so the line map knows
- the number of lines before compilation really starts. For e.g,
- the C front-end, it can happen that we start emitting diagnostics
- before the line map has seen the end of the file. */
- size_t total_lines;
- /* This is a record of the beginning and end of the lines we've seen
- while reading the file. This is useful to avoid walking the data
- from the beginning when we are asked to read a line that is
- before LINE_START_IDX above. Note that the maximum size of this
- record is fcache_line_record_size, so that the memory consumption
- doesn't explode. We thus scale total_lines down to
- fcache_line_record_size. */
- vec<line_info, va_heap> line_record;
- fcache ();
- ~fcache ();
- };
- /* Current position in real source file. */
- location_t input_location = UNKNOWN_LOCATION;
- struct line_maps *line_table;
- static fcache *fcache_tab;
- static const size_t fcache_tab_size = 16;
- static const size_t fcache_buffer_size = 4 * 1024;
- static const size_t fcache_line_record_size = 100;
- /* Expand the source location LOC into a human readable location. If
- LOC resolves to a builtin location, the file name of the readable
- location is set to the string "<built-in>". If EXPANSION_POINT_P is
- TRUE and LOC is virtual, then it is resolved to the expansion
- point of the involved macro. Otherwise, it is resolved to the
- spelling location of the token.
- When resolving to the spelling location of the token, if the
- resulting location is for a built-in location (that is, it has no
- associated line/column) in the context of a macro expansion, the
- returned location is the first one (while unwinding the macro
- location towards its expansion point) that is in real source
- code. */
- static expanded_location
- expand_location_1 (source_location loc,
- bool expansion_point_p)
- {
- expanded_location xloc;
- const struct line_map *map;
- enum location_resolution_kind lrk = LRK_MACRO_EXPANSION_POINT;
- tree block = NULL;
- if (IS_ADHOC_LOC (loc))
- {
- block = LOCATION_BLOCK (loc);
- loc = LOCATION_LOCUS (loc);
- }
- memset (&xloc, 0, sizeof (xloc));
- if (loc >= RESERVED_LOCATION_COUNT)
- {
- if (!expansion_point_p)
- {
- /* We want to resolve LOC to its spelling location.
- But if that spelling location is a reserved location that
- appears in the context of a macro expansion (like for a
- location for a built-in token), let's consider the first
- location (toward the expansion point) that is not reserved;
- that is, the first location that is in real source code. */
- loc = linemap_unwind_to_first_non_reserved_loc (line_table,
- loc, &map);
- lrk = LRK_SPELLING_LOCATION;
- }
- loc = linemap_resolve_location (line_table, loc,
- lrk, &map);
- xloc = linemap_expand_location (line_table, map, loc);
- }
- xloc.data = block;
- if (loc <= BUILTINS_LOCATION)
- xloc.file = loc == UNKNOWN_LOCATION ? NULL : _("<built-in>");
- return xloc;
- }
- /* Initialize the set of cache used for files accessed by caret
- diagnostic. */
- static void
- diagnostic_file_cache_init (void)
- {
- if (fcache_tab == NULL)
- fcache_tab = new fcache[fcache_tab_size];
- }
- /* Free the resources used by the set of cache used for files accessed
- by caret diagnostic. */
- void
- diagnostic_file_cache_fini (void)
- {
- if (fcache_tab)
- {
- delete [] (fcache_tab);
- fcache_tab = NULL;
- }
- }
- /* Return the total lines number that have been read so far by the
- line map (in the preprocessor) so far. For languages like C++ that
- entirely preprocess the input file before starting to parse, this
- equals the actual number of lines of the file. */
- static size_t
- total_lines_num (const char *file_path)
- {
- size_t r = 0;
- source_location l = 0;
- if (linemap_get_file_highest_location (line_table, file_path, &l))
- {
- gcc_assert (l >= RESERVED_LOCATION_COUNT);
- expanded_location xloc = expand_location (l);
- r = xloc.line;
- }
- return r;
- }
- /* Lookup the cache used for the content of a given file accessed by
- caret diagnostic. Return the found cached file, or NULL if no
- cached file was found. */
- static fcache*
- lookup_file_in_cache_tab (const char *file_path)
- {
- if (file_path == NULL)
- return NULL;
- diagnostic_file_cache_init ();
- /* This will contain the found cached file. */
- fcache *r = NULL;
- for (unsigned i = 0; i < fcache_tab_size; ++i)
- {
- fcache *c = &fcache_tab[i];
- if (c->file_path && !strcmp (c->file_path, file_path))
- {
- ++c->use_count;
- r = c;
- }
- }
- if (r)
- ++r->use_count;
- return r;
- }
- /* Return the file cache that has been less used, recently, or the
- first empty one. If HIGHEST_USE_COUNT is non-null,
- *HIGHEST_USE_COUNT is set to the highest use count of the entries
- in the cache table. */
- static fcache*
- evicted_cache_tab_entry (unsigned *highest_use_count)
- {
- diagnostic_file_cache_init ();
- fcache *to_evict = &fcache_tab[0];
- unsigned huc = to_evict->use_count;
- for (unsigned i = 1; i < fcache_tab_size; ++i)
- {
- fcache *c = &fcache_tab[i];
- bool c_is_empty = (c->file_path == NULL);
- if (c->use_count < to_evict->use_count
- || (to_evict->file_path && c_is_empty))
- /* We evict C because it's either an entry with a lower use
- count or one that is empty. */
- to_evict = c;
- if (huc < c->use_count)
- huc = c->use_count;
- if (c_is_empty)
- /* We've reached the end of the cache; subsequent elements are
- all empty. */
- break;
- }
- if (highest_use_count)
- *highest_use_count = huc;
- return to_evict;
- }
- /* Create the cache used for the content of a given file to be
- accessed by caret diagnostic. This cache is added to an array of
- cache and can be retrieved by lookup_file_in_cache_tab. This
- function returns the created cache. Note that only the last
- fcache_tab_size files are cached. */
- static fcache*
- add_file_to_cache_tab (const char *file_path)
- {
- FILE *fp = fopen (file_path, "r");
- if (fp == NULL)
- return NULL;
- unsigned highest_use_count = 0;
- fcache *r = evicted_cache_tab_entry (&highest_use_count);
- r->file_path = file_path;
- if (r->fp)
- fclose (r->fp);
- r->fp = fp;
- r->nb_read = 0;
- r->line_start_idx = 0;
- r->line_num = 0;
- r->line_record.truncate (0);
- /* Ensure that this cache entry doesn't get evicted next time
- add_file_to_cache_tab is called. */
- r->use_count = ++highest_use_count;
- r->total_lines = total_lines_num (file_path);
- return r;
- }
- /* Lookup the cache used for the content of a given file accessed by
- caret diagnostic. If no cached file was found, create a new cache
- for this file, add it to the array of cached file and return
- it. */
- static fcache*
- lookup_or_add_file_to_cache_tab (const char *file_path)
- {
- fcache *r = lookup_file_in_cache_tab (file_path);
- if (r == NULL)
- r = add_file_to_cache_tab (file_path);
- return r;
- }
- /* Default constructor for a cache of file used by caret
- diagnostic. */
- fcache::fcache ()
- : use_count (0), file_path (NULL), fp (NULL), data (0),
- size (0), nb_read (0), line_start_idx (0), line_num (0),
- total_lines (0)
- {
- line_record.create (0);
- }
- /* Destructor for a cache of file used by caret diagnostic. */
- fcache::~fcache ()
- {
- if (fp)
- {
- fclose (fp);
- fp = NULL;
- }
- if (data)
- {
- XDELETEVEC (data);
- data = 0;
- }
- line_record.release ();
- }
- /* Returns TRUE iff the cache would need to be filled with data coming
- from the file. That is, either the cache is empty or full or the
- current line is empty. Note that if the cache is full, it would
- need to be extended and filled again. */
- static bool
- needs_read (fcache *c)
- {
- return (c->nb_read == 0
- || c->nb_read == c->size
- || (c->line_start_idx >= c->nb_read - 1));
- }
- /* Return TRUE iff the cache is full and thus needs to be
- extended. */
- static bool
- needs_grow (fcache *c)
- {
- return c->nb_read == c->size;
- }
- /* Grow the cache if it needs to be extended. */
- static void
- maybe_grow (fcache *c)
- {
- if (!needs_grow (c))
- return;
- size_t size = c->size == 0 ? fcache_buffer_size : c->size * 2;
- c->data = XRESIZEVEC (char, c->data, size + 1);
- c->size = size;
- }
- /* Read more data into the cache. Extends the cache if need be.
- Returns TRUE iff new data could be read. */
- static bool
- read_data (fcache *c)
- {
- if (feof (c->fp) || ferror (c->fp))
- return false;
- maybe_grow (c);
- char * from = c->data + c->nb_read;
- size_t to_read = c->size - c->nb_read;
- size_t nb_read = fread (from, 1, to_read, c->fp);
- if (ferror (c->fp))
- return false;
- c->nb_read += nb_read;
- return !!nb_read;
- }
- /* Read new data iff the cache needs to be filled with more data
- coming from the file FP. Return TRUE iff the cache was filled with
- mode data. */
- static bool
- maybe_read_data (fcache *c)
- {
- if (!needs_read (c))
- return false;
- return read_data (c);
- }
- /* Read a new line from file FP, using C as a cache for the data
- coming from the file. Upon successful completion, *LINE is set to
- the beginning of the line found. Space for that line has been
- allocated in the cache thus *LINE has the same life time as C.
- *LINE_LEN is set to the length of the line. Note that the line
- does not contain any terminal delimiter. This function returns
- true if some data was read or process from the cache, false
- otherwise. Note that subsequent calls to get_next_line return the
- next lines of the file and might overwrite the content of
- *LINE. */
- static bool
- get_next_line (fcache *c, char **line, ssize_t *line_len)
- {
- /* Fill the cache with data to process. */
- maybe_read_data (c);
- size_t remaining_size = c->nb_read - c->line_start_idx;
- if (remaining_size == 0)
- /* There is no more data to process. */
- return false;
- char *line_start = c->data + c->line_start_idx;
- char *next_line_start = NULL;
- size_t len = 0;
- char *line_end = (char *) memchr (line_start, '\n', remaining_size);
- if (line_end == NULL)
- {
- /* We haven't found the end-of-line delimiter in the cache.
- Fill the cache with more data from the file and look for the
- '\n'. */
- while (maybe_read_data (c))
- {
- line_start = c->data + c->line_start_idx;
- remaining_size = c->nb_read - c->line_start_idx;
- line_end = (char *) memchr (line_start, '\n', remaining_size);
- if (line_end != NULL)
- {
- next_line_start = line_end + 1;
- break;
- }
- }
- if (line_end == NULL)
- /* We've loadded all the file into the cache and still no
- '\n'. Let's say the line ends up at one byte passed the
- end of the file. This is to stay consistent with the case
- of when the line ends up with a '\n' and line_end points to
- that terminal '\n'. That consistency is useful below in
- the len calculation. */
- line_end = c->data + c->nb_read ;
- }
- else
- next_line_start = line_end + 1;
- if (ferror (c->fp))
- return -1;
- /* At this point, we've found the end of the of line. It either
- points to the '\n' or to one byte after the last byte of the
- file. */
- gcc_assert (line_end != NULL);
- len = line_end - line_start;
- if (c->line_start_idx < c->nb_read)
- *line = line_start;
- ++c->line_num;
- /* Before we update our line record, make sure the hint about the
- total number of lines of the file is correct. If it's not, then
- we give up recording line boundaries from now on. */
- bool update_line_record = true;
- if (c->line_num > c->total_lines)
- update_line_record = false;
- /* Now update our line record so that re-reading lines from the
- before c->line_start_idx is faster. */
- if (update_line_record
- && c->line_record.length () < fcache_line_record_size)
- {
- /* If the file lines fits in the line record, we just record all
- its lines ...*/
- if (c->total_lines <= fcache_line_record_size
- && c->line_num > c->line_record.length ())
- c->line_record.safe_push (fcache::line_info (c->line_num,
- c->line_start_idx,
- line_end - c->data));
- else if (c->total_lines > fcache_line_record_size)
- {
- /* ... otherwise, we just scale total_lines down to
- (fcache_line_record_size lines. */
- size_t n = (c->line_num * fcache_line_record_size) / c->total_lines;
- if (c->line_record.length () == 0
- || n >= c->line_record.length ())
- c->line_record.safe_push (fcache::line_info (c->line_num,
- c->line_start_idx,
- line_end - c->data));
- }
- }
- /* Update c->line_start_idx so that it points to the next line to be
- read. */
- if (next_line_start)
- c->line_start_idx = next_line_start - c->data;
- else
- /* We didn't find any terminal '\n'. Let's consider that the end
- of line is the end of the data in the cache. The next
- invocation of get_next_line will either read more data from the
- underlying file or return false early because we've reached the
- end of the file. */
- c->line_start_idx = c->nb_read;
- *line_len = len;
- return true;
- }
- /* Reads the next line from FILE into *LINE. If *LINE is too small
- (or NULL) it is allocated (or extended) to have enough space to
- containe the line. *LINE_LENGTH must contain the size of the
- initial*LINE buffer. It's then updated by this function to the
- actual length of the returned line. Note that the returned line
- can contain several zero bytes. Also note that the returned string
- is allocated in static storage that is going to be re-used by
- subsequent invocations of read_line. */
- static bool
- read_next_line (fcache *cache, char ** line, ssize_t *line_len)
- {
- char *l = NULL;
- ssize_t len = 0;
- if (!get_next_line (cache, &l, &len))
- return false;
- if (*line == NULL)
- *line = XNEWVEC (char, len);
- else
- if (*line_len < len)
- *line = XRESIZEVEC (char, *line, len);
- memcpy (*line, l, len);
- *line_len = len;
- return true;
- }
- /* Consume the next bytes coming from the cache (or from its
- underlying file if there are remaining unread bytes in the file)
- until we reach the next end-of-line (or end-of-file). There is no
- copying from the cache involved. Return TRUE upon successful
- completion. */
- static bool
- goto_next_line (fcache *cache)
- {
- char *l;
- ssize_t len;
- return get_next_line (cache, &l, &len);
- }
- /* Read an arbitrary line number LINE_NUM from the file cached in C.
- The line is copied into *LINE. *LINE_LEN must have been set to the
- length of *LINE. If *LINE is too small (or NULL) it's extended (or
- allocated) and *LINE_LEN is adjusted accordingly. *LINE ends up
- with a terminal zero byte and can contain additional zero bytes.
- This function returns bool if a line was read. */
- static bool
- read_line_num (fcache *c, size_t line_num,
- char ** line, ssize_t *line_len)
- {
- gcc_assert (line_num > 0);
- if (line_num <= c->line_num)
- {
- /* We've been asked to read lines that are before c->line_num.
- So lets use our line record (if it's not empty) to try to
- avoid re-reading the file from the beginning again. */
- if (c->line_record.is_empty ())
- {
- c->line_start_idx = 0;
- c->line_num = 0;
- }
- else
- {
- fcache::line_info *i = NULL;
- if (c->total_lines <= fcache_line_record_size)
- {
- /* In languages where the input file is not totally
- preprocessed up front, the c->total_lines hint
- can be smaller than the number of lines of the
- file. In that case, only the first
- c->total_lines have been recorded.
- Otherwise, the first c->total_lines we've read have
- their start/end recorded here. */
- i = (line_num <= c->total_lines)
- ? &c->line_record[line_num - 1]
- : &c->line_record[c->total_lines - 1];
- gcc_assert (i->line_num <= line_num);
- }
- else
- {
- /* So the file had more lines than our line record
- size. Thus the number of lines we've recorded has
- been scaled down to fcache_line_reacord_size. Let's
- pick the start/end of the recorded line that is
- closest to line_num. */
- size_t n = (line_num <= c->total_lines)
- ? line_num * fcache_line_record_size / c->total_lines
- : c ->line_record.length () - 1;
- if (n < c->line_record.length ())
- {
- i = &c->line_record[n];
- gcc_assert (i->line_num <= line_num);
- }
- }
- if (i && i->line_num == line_num)
- {
- /* We have the start/end of the line. Let's just copy
- it again and we are done. */
- ssize_t len = i->end_pos - i->start_pos + 1;
- if (*line_len < len)
- *line = XRESIZEVEC (char, *line, len);
- memmove (*line, c->data + i->start_pos, len);
- (*line)[len - 1] = '\0';
- *line_len = --len;
- return true;
- }
- if (i)
- {
- c->line_start_idx = i->start_pos;
- c->line_num = i->line_num - 1;
- }
- else
- {
- c->line_start_idx = 0;
- c->line_num = 0;
- }
- }
- }
- /* Let's walk from line c->line_num up to line_num - 1, without
- copying any line. */
- while (c->line_num < line_num - 1)
- if (!goto_next_line (c))
- return false;
- /* The line we want is the next one. Let's read and copy it back to
- the caller. */
- return read_next_line (c, line, line_len);
- }
- /* Return the physical source line that corresponds to xloc in a
- buffer that is statically allocated. The newline is replaced by
- the null character. Note that the line can contain several null
- characters, so LINE_LEN, if non-null, points to the actual length
- of the line. */
- const char *
- location_get_source_line (expanded_location xloc,
- int *line_len)
- {
- static char *buffer;
- static ssize_t len;
- if (xloc.line == 0)
- return NULL;
- fcache *c = lookup_or_add_file_to_cache_tab (xloc.file);
- if (c == NULL)
- return NULL;
- bool read = read_line_num (c, xloc.line, &buffer, &len);
- if (read && line_len)
- *line_len = len;
- return read ? buffer : NULL;
- }
- /* Test if the location originates from the spelling location of a
- builtin-tokens. That is, return TRUE if LOC is a (possibly
- virtual) location of a built-in token that appears in the expansion
- list of a macro. Please note that this function also works on
- tokens that result from built-in tokens. For instance, the
- function would return true if passed a token "4" that is the result
- of the expansion of the built-in __LINE__ macro. */
- bool
- is_location_from_builtin_token (source_location loc)
- {
- const line_map *map = NULL;
- loc = linemap_resolve_location (line_table, loc,
- LRK_SPELLING_LOCATION, &map);
- return loc == BUILTINS_LOCATION;
- }
- /* Expand the source location LOC into a human readable location. If
- LOC is virtual, it resolves to the expansion point of the involved
- macro. If LOC resolves to a builtin location, the file name of the
- readable location is set to the string "<built-in>". */
- expanded_location
- expand_location (source_location loc)
- {
- return expand_location_1 (loc, /*expansion_point_p=*/true);
- }
- /* Expand the source location LOC into a human readable location. If
- LOC is virtual, it resolves to the expansion location of the
- relevant macro. If LOC resolves to a builtin location, the file
- name of the readable location is set to the string
- "<built-in>". */
- expanded_location
- expand_location_to_spelling_point (source_location loc)
- {
- return expand_location_1 (loc, /*expansion_point_p=*/false);
- }
- /* If LOCATION is in a system header and if it is a virtual location for
- a token coming from the expansion of a macro, unwind it to the
- location of the expansion point of the macro. Otherwise, just return
- LOCATION.
- This is used for instance when we want to emit diagnostics about a
- token that may be located in a macro that is itself defined in a
- system header, for example, for the NULL macro. In such a case, if
- LOCATION were passed directly to diagnostic functions such as
- warning_at, the diagnostic would be suppressed (unless
- -Wsystem-headers). */
- source_location
- expansion_point_location_if_in_system_header (source_location location)
- {
- if (in_system_header_at (location))
- location = linemap_resolve_location (line_table, location,
- LRK_MACRO_EXPANSION_POINT,
- NULL);
- return location;
- }
- #define ONE_K 1024
- #define ONE_M (ONE_K * ONE_K)
- /* Display a number as an integer multiple of either:
- - 1024, if said integer is >= to 10 K (in base 2)
- - 1024 * 1024, if said integer is >= 10 M in (base 2)
- */
- #define SCALE(x) ((unsigned long) ((x) < 10 * ONE_K \
- ? (x) \
- : ((x) < 10 * ONE_M \
- ? (x) / ONE_K \
- : (x) / ONE_M)))
- /* For a given integer, display either:
- - the character 'k', if the number is higher than 10 K (in base 2)
- but strictly lower than 10 M (in base 2)
- - the character 'M' if the number is higher than 10 M (in base2)
- - the charcter ' ' if the number is strictly lower than 10 K */
- #define STAT_LABEL(x) ((x) < 10 * ONE_K ? ' ' : ((x) < 10 * ONE_M ? 'k' : 'M'))
- /* Display an integer amount as multiple of 1K or 1M (in base 2).
- Display the correct unit (either k, M, or ' ') after the amout, as
- well. */
- #define FORMAT_AMOUNT(size) SCALE (size), STAT_LABEL (size)
- /* Dump statistics to stderr about the memory usage of the line_table
- set of line maps. This also displays some statistics about macro
- expansion. */
- void
- dump_line_table_statistics (void)
- {
- struct linemap_stats s;
- long total_used_map_size,
- macro_maps_size,
- total_allocated_map_size;
- memset (&s, 0, sizeof (s));
- linemap_get_statistics (line_table, &s);
- macro_maps_size = s.macro_maps_used_size
- + s.macro_maps_locations_size;
- total_allocated_map_size = s.ordinary_maps_allocated_size
- + s.macro_maps_allocated_size
- + s.macro_maps_locations_size;
- total_used_map_size = s.ordinary_maps_used_size
- + s.macro_maps_used_size
- + s.macro_maps_locations_size;
- fprintf (stderr, "Number of expanded macros: %5ld\n",
- s.num_expanded_macros);
- if (s.num_expanded_macros != 0)
- fprintf (stderr, "Average number of tokens per macro expansion: %5ld\n",
- s.num_macro_tokens / s.num_expanded_macros);
- fprintf (stderr,
- "\nLine Table allocations during the "
- "compilation process\n");
- fprintf (stderr, "Number of ordinary maps used: %5ld%c\n",
- SCALE (s.num_ordinary_maps_used),
- STAT_LABEL (s.num_ordinary_maps_used));
- fprintf (stderr, "Ordinary map used size: %5ld%c\n",
- SCALE (s.ordinary_maps_used_size),
- STAT_LABEL (s.ordinary_maps_used_size));
- fprintf (stderr, "Number of ordinary maps allocated: %5ld%c\n",
- SCALE (s.num_ordinary_maps_allocated),
- STAT_LABEL (s.num_ordinary_maps_allocated));
- fprintf (stderr, "Ordinary maps allocated size: %5ld%c\n",
- SCALE (s.ordinary_maps_allocated_size),
- STAT_LABEL (s.ordinary_maps_allocated_size));
- fprintf (stderr, "Number of macro maps used: %5ld%c\n",
- SCALE (s.num_macro_maps_used),
- STAT_LABEL (s.num_macro_maps_used));
- fprintf (stderr, "Macro maps used size: %5ld%c\n",
- SCALE (s.macro_maps_used_size),
- STAT_LABEL (s.macro_maps_used_size));
- fprintf (stderr, "Macro maps locations size: %5ld%c\n",
- SCALE (s.macro_maps_locations_size),
- STAT_LABEL (s.macro_maps_locations_size));
- fprintf (stderr, "Macro maps size: %5ld%c\n",
- SCALE (macro_maps_size),
- STAT_LABEL (macro_maps_size));
- fprintf (stderr, "Duplicated maps locations size: %5ld%c\n",
- SCALE (s.duplicated_macro_maps_locations_size),
- STAT_LABEL (s.duplicated_macro_maps_locations_size));
- fprintf (stderr, "Total allocated maps size: %5ld%c\n",
- SCALE (total_allocated_map_size),
- STAT_LABEL (total_allocated_map_size));
- fprintf (stderr, "Total used maps size: %5ld%c\n",
- SCALE (total_used_map_size),
- STAT_LABEL (total_used_map_size));
- fprintf (stderr, "\n");
- }
|