Message ID | 1462394970-55471-4-git-send-email-dmalcolm@redhat.com |
---|---|
State | New |
Headers | show |
On Wed, May 4, 2016 at 10:49 PM, David Malcolm <dmalcolm@redhat.com> wrote: > In order to faithfully load RTL dumps that contain references to > source locations, the RTL frontend needs to be able to parse file > and line information and turn then into location_t values. > > Unfortunately, the libcpp API makes it rather fiddly to create > location_t values from a sequence of arbitrary file/line pairs: the > API assumes that the locations are created in ascending order as > if we were parsing the source file, but as we read an RTL dump, > the insns could be jumping forwards and backwards in lines and > between files. Also, if we want to support column numbers, the > presence of a very high column number could exceed the bits available > in a line_map_ordinary for storing it. > > The JIT has some code for handling this, in gcc/jit/jit-playback.[ch], > (since the JIT support source location information, and doesn't impose > any ordering requirement on users of the API). > > This patch moves the relevant code from > gcc/jit/jit-playback.[ch] > into a new pair of files: > gcc/deferred-locations.[ch] > > The idea is that a deferred_locations instances manages these > "deferred locations"; they are created, and then all of the location_t > values are created at once by calling > deferred_locations::add_to_line_table > After this call, the actual location_t values can be read from out of > deferred_location instances. > > There are some suboptimal parts of the code (some linear searches, and > the use of gc), but it's mostly a move of existing code from out of the > jit subdirectory and into "gcc" proper for reuse by the RTL frontend. > > This is likely to be useful for the gimple frontend as well. > > OK for trunk? The LTO FE faces similar issues - see lto-streamer-in.c Richard. > gcc/ChangeLog: > * Makefile.in (OBJS): Add deferred-locations.o. > * deferred-locations.c: New file, adapted from parts of > jit/jit-playback.c. > * deferred-locations.h: New file, adapted from parts of > jit/jit-playback.h. > > gcc/jit/ChangeLog: > * jit-common.h: Include deferred-locations.h. > (gcc::jit::playback::source_file): Remove forward decl. > (gcc::jit::playback::source_line): Likewise. > (gcc::jit::playback::location): Replace forward decl, with > a typedef, aliasing deferred_location. > * jit-playback.c (gcc::jit::playback::context::context): Remove > create call on m_source_files. > (line_comparator): Move to deferred-locations.c. > (location_comparator): Likewise. > (handle_locations): Move logic to deferred-locations.c, as > deferred_locations::add_to_line_table. > (get_recording_loc): New function. > (gcc::jit::playback::context::add_error): Call get_recording_loc > as a function, rather than as a method. > (gcc::jit::playback::context::add_error_va): Likewise. > (gcc::jit::playback::context::get_source_file): Update return type > to reflect move of source_file to deferred-locations.h. > Replace body with a call to m_deferred_locations.get_source_file. > (gcc::jit::playback::source_file::source_file): Move to > deferred-locations.h, losing the namespaces. > (gcc::jit::playback::source_file::finalizer): Likewise. > (gcc::jit::playback::source_file::get_source_line): Likewise. > (gcc::jit::playback::source_line::source_line): Likewise. > (gcc::jit::playback::source_line::finalizer): Likewise. > (gcc::jit::playback::source_line::get_location): Likewise. > (gcc::jit::playback::location::location): Likewise, renaming to > deferred_location. > * jit-playback.h: Include deferred-locations.h. > (gcc::jit::playback::context::m_source_files): Replace field with > m_deferred_locations. > (gcc::jit::playback::source_file): Move to deferred-locations.h, > losing the namespaces. > (gcc::jit::playback::source_line): Likewise. > (gcc::jit::playback::location): Likewise, renaming to > deferred_location. Eliminate get_recording_loc accessor and > m_recording_loc field in favor of get_user_data and m_user_data > respectively. > --- > gcc/Makefile.in | 1 + > gcc/deferred-locations.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++ > gcc/deferred-locations.h | 139 +++++++++++++++++++++++++++ > gcc/jit/jit-common.h | 5 +- > gcc/jit/jit-playback.c | 194 ++++---------------------------------- > gcc/jit/jit-playback.h | 73 +------------- > 6 files changed, 402 insertions(+), 250 deletions(-) > create mode 100644 gcc/deferred-locations.c > create mode 100644 gcc/deferred-locations.h > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > index 6c5adc0..c61f303 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -1239,6 +1239,7 @@ OBJS = \ > dce.o \ > ddg.o \ > debug.o \ > + deferred-locations.o \ > df-core.o \ > df-problems.o \ > df-scan.o \ > diff --git a/gcc/deferred-locations.c b/gcc/deferred-locations.c > new file mode 100644 > index 0000000..cd02938 > --- /dev/null > +++ b/gcc/deferred-locations.c > @@ -0,0 +1,240 @@ > +/* Dealing with the linemap API. > + Copyright (C) 2013-2016 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 "input.h" > +#include "deferred-locations.h" > +#include "stringpool.h" > +#include "tree.h" > + > +/* The wrapper subclasses are GC-managed, but can own non-GC memory. > + Provide this finalization hook for calling then they are collected, > + which calls the finalizer vfunc. This allows them to call "release" > + on any vec<> within them. */ > + > +static void > +wrapper_finalizer (void *ptr) > +{ > + wrapper *w = reinterpret_cast <wrapper *> (ptr); > + w->finalizer (); > +} > + > +/* wrapper subclasses are GC-managed: > + allocate them using ggc_internal_cleared_alloc. */ > + > +void * > +wrapper::operator new (size_t sz) > +{ > + return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1); > + > +} > + > +/* Constructor for source_file. */ > + > +source_file::source_file (tree filename) : > + m_source_lines (), > + m_filename (filename) > +{ > +} > + > +/* Don't leak vec's internal buffer (in non-GC heap) when we are > + GC-ed. */ > + > +void > +source_file::finalizer () > +{ > + m_source_lines.release (); > +} > + > +/* Construct a source_line for the given line > + within this source file, if one doesn't exist already. */ > + > +source_line * > +source_file::get_source_line (int line_num) > +{ > + /* Locate the line. > + For simplicitly, this is currently a linear search. > + Replace with a hash if this shows up in the profile. */ > + int i; > + source_line *line; > + > + FOR_EACH_VEC_ELT (m_source_lines, i, line) > + if (line->get_line_num () == line_num) > + return line; > + > + /* Not found. */ > + line = new source_line (this, line_num); > + m_source_lines.safe_push (line); > + return line; > +} > + > +const char * > +source_file::get_filename () const > +{ > + return IDENTIFIER_POINTER (m_filename); > +} > + > +/* Constructor for source_line. */ > + > +source_line::source_line (source_file *file, int line_num) : > + m_locations (), > + m_source_file (file), > + m_line_num (line_num) > +{ > +} > + > +/* Don't leak vec's internal buffer (in non-GC heap) when we are > + GC-ed. */ > + > +void > +source_line::finalizer () > +{ > + m_locations.release (); > +} > + > +/* Construct a location for the given column > + within this line of a specific source file, if one doesn't exist > + already. */ > + > +deferred_location * > +source_line::get_location (void *user_data, int column_num) > +{ > + int i; > + deferred_location *loc; > + > + /* Another linear search that probably should be a hash table. */ > + FOR_EACH_VEC_ELT (m_locations, i, loc) > + if (loc->get_column_num () == column_num) > + return loc; > + > + /* Not found. */ > + loc = new deferred_location (user_data, this, column_num); > + m_locations.safe_push (loc); > + return loc; > +} > + > +/* Constructor for deferred_location. */ > +deferred_location::deferred_location (void *user_data, > + source_line *line, > + int column_num) : > + m_srcloc (UNKNOWN_LOCATION), > + m_user_data (user_data), > + m_line (line), > + m_column_num(column_num) > +{ > +} > + > +/* qsort comparator for comparing pairs of source_line *, > + ordering them by line number. */ > + > +static int > +line_comparator (const void *lhs, const void *rhs) > +{ > + const source_line *line_lhs = *static_cast<const source_line * const*> (lhs); > + const source_line *line_rhs = *static_cast<const source_line * const*> (rhs); > + return line_lhs->get_line_num () - line_rhs->get_line_num (); > +} > + > +/* qsort comparator for comparing pairs of deferred_location *, > + ordering them by column number. */ > + > +static int > +location_comparator (const void *lhs, const void *rhs) > +{ > + const deferred_location *loc_lhs = \ > + *static_cast<const deferred_location * const *> (lhs); > + const deferred_location *loc_rhs = \ > + *static_cast<const deferred_location * const *> (rhs); > + return loc_lhs->get_column_num () - loc_rhs->get_column_num (); > +} > + > +/* class deferred_locations */ > + > +deferred_locations::deferred_locations () > +{ > + m_source_files.create (0); > +} > + > +/* Construct a source_file for the given source > + filename, if it doesn't exist already. */ > + > +source_file * > +deferred_locations::get_source_file (const char *filename) > +{ > + /* Locate the file. > + For simplicitly, this is currently a linear search. > + Replace with a hash if this shows up in the profile. */ > + int i; > + source_file *file; > + tree ident_filename = get_identifier (filename); > + > + FOR_EACH_VEC_ELT (m_source_files, i, file) > + if (file->filename_as_tree () == ident_filename) > + return file; > + > + /* Not found. */ > + file = new source_file (ident_filename); > + m_source_files.safe_push (file); > + return file; > + > +} > + > +void > +deferred_locations::add_to_line_table () > +{ > + int i; > + source_file *file; > + > + FOR_EACH_VEC_ELT (m_source_files, i, file) > + { > + linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0); > + > + /* Sort lines by ascending line numbers. */ > + file->m_source_lines.qsort (&line_comparator); > + > + int j; > + source_line *line; > + FOR_EACH_VEC_ELT (file->m_source_lines, j, line) > + { > + int k; > + deferred_location *loc; > + > + /* Sort locations in line by ascending column numbers. */ > + line->m_locations.qsort (&location_comparator); > + > + /* Determine maximum column within this line. */ > + gcc_assert (line->m_locations.length () > 0); > + deferred_location *final_column = > + line->m_locations[line->m_locations.length () - 1]; > + int max_col = final_column->get_column_num (); > + > + linemap_line_start (line_table, line->get_line_num (), max_col); > + FOR_EACH_VEC_ELT (line->m_locations, k, loc) > + { > + loc->m_srcloc = > + linemap_position_for_column (line_table, loc->get_column_num ()); > + } > + } > + > + linemap_add (line_table, LC_LEAVE, false, NULL, 0); > + } > + > +} > diff --git a/gcc/deferred-locations.h b/gcc/deferred-locations.h > new file mode 100644 > index 0000000..209cb0d > --- /dev/null > +++ b/gcc/deferred-locations.h > @@ -0,0 +1,139 @@ > +/* Dealing with the linemap API. > + Copyright (C) 2013-2016 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/>. */ > + > +#ifndef GCC_DEFERRED_LOCATIONS_H > +#define GCC_DEFERRED_LOCATIONS_H > + > +/* Dealing with the linemap API. > + > + libcpp requires locations to be created as if by > + a tokenizer, creating them by filename, in ascending order of > + line/column, whereas the libgccjit API doesn't impose any such constraints: > + we allow client code to create locations in arbitrary orders. > + > + To square this circle, we need to cache all location creation, > + grouping things up by filename/line, and then creating the linemap > + entries in a post-processing phase. */ > + > +/* A temporary wrapper object. > + These objects are (mostly) only valid during replay. > + We allocate them on the GC heap, so that they will be cleaned > + the next time the GC collects. */ > +class wrapper > +{ > +public: > + /* Allocate in the GC heap. */ > + void *operator new (size_t sz); > + > + /* Some wrapper subclasses contain vec<> and so need to > + release them when they are GC-ed. */ > + virtual void finalizer () { } > +}; > + > +class source_file; > +class source_line; > +class deferred_location; > + > +/* A set of locations, all sharing a filename */ > +class source_file : public wrapper > +{ > +public: > + source_file (tree filename); > + void finalizer (); > + > + source_line * > + get_source_line (int line_num); > + > + tree filename_as_tree () const { return m_filename; } > + > + const char *get_filename () const; > + > + vec<source_line *> m_source_lines; > + > +private: > + tree m_filename; > +}; > + > +/* A source line, with one or more locations of interest. */ > +class source_line : public wrapper > +{ > +public: > + source_line (source_file *file, int line_num); > + void finalizer (); > + > + deferred_location * > + get_location (void *user_data, int column_num); > + > + int get_line_num () const { return m_line_num; } > + > + vec<deferred_location *> m_locations; > + > +private: > + source_file *m_source_file; > + int m_line_num; > +}; > + > +/* A specific location on a source line. This is what we expose > + to the JIT client API. */ > +class deferred_location : public wrapper > +{ > +public: > + deferred_location (void *user_data, source_line *line, int column_num); > + > + int get_column_num () const { return m_column_num; } > + > + void *get_user_data () const { return m_user_data; } > + > + source_location m_srcloc; > + > +private: > + void *m_user_data; > + source_line *m_line; > + int m_column_num; > +}; > + > +/* A class for managing the deferred creation of location_t values. > + > + Locations are created in two phases: > + > + - first phase: creation of source_file instances (via > + deferred_locations::get_source_file), from which source_line > + instances can be created (via source_file::get_source_line), from > + which deferred_location instances can be created (via > + source_line::get_location). > + > + - second phase: call deferred_location::add_to_line_table, which > + walks all of the above and populates line_table, filling in > + the various deferred_location instances with source_location > + (aka location_t) values. */ > + > +class deferred_locations > +{ > + public: > + deferred_locations (); > + > + source_file *get_source_file (const char *filename); > + > + void add_to_line_table (); > + > + private: > + auto_vec<source_file *> m_source_files; > +}; > + > +#endif /* #ifndef GCC_DEFERRED_LOCATIONS_H */ > diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h > index 8a6cd74..0a10cdf 100644 > --- a/gcc/jit/jit-common.h > +++ b/gcc/jit/jit-common.h > @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see > #include "tree.h" > #include "inchash.h" > #include "tree-iterator.h" > +#include "deferred-locations.h" > > #ifdef GCC_VERSION > #if GCC_VERSION >= 4001 > @@ -146,9 +147,7 @@ namespace playback { > class rvalue; > class lvalue; > class param; > - class source_file; > - class source_line; > - class location; > + typedef deferred_location location; > class case_; > > /* End of playback types. */ > diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c > index 579230d..f17c55b 100644 > --- a/gcc/jit/jit-playback.c > +++ b/gcc/jit/jit-playback.c > @@ -85,7 +85,6 @@ playback::context::context (recording::context *ctxt) > JIT_LOG_SCOPE (get_logger ()); > m_functions.create (0); > m_globals.create (0); > - m_source_files.create (0); > m_cached_locations.create (0); > } > > @@ -2705,32 +2704,6 @@ get_path_so_file () const > return m_tempdir->get_path_so_file (); > } > > -/* qsort comparator for comparing pairs of playback::source_line *, > - ordering them by line number. */ > - > -static int > -line_comparator (const void *lhs, const void *rhs) > -{ > - const playback::source_line *line_lhs = \ > - *static_cast<const playback::source_line * const*> (lhs); > - const playback::source_line *line_rhs = \ > - *static_cast<const playback::source_line * const*> (rhs); > - return line_lhs->get_line_num () - line_rhs->get_line_num (); > -} > - > -/* qsort comparator for comparing pairs of playback::location *, > - ordering them by column number. */ > - > -static int > -location_comparator (const void *lhs, const void *rhs) > -{ > - const playback::location *loc_lhs = \ > - *static_cast<const playback::location * const *> (lhs); > - const playback::location *loc_rhs = \ > - *static_cast<const playback::location * const *> (rhs); > - return loc_lhs->get_column_num () - loc_rhs->get_column_num (); > -} > - > /* Our API allows locations to be created in arbitrary orders, but the > linemap API requires locations to be created in ascending order > as if we were tokenizing files. > @@ -2748,47 +2721,13 @@ handle_locations () > > line_table is a global. */ > JIT_LOG_SCOPE (get_logger ()); > - int i; > - source_file *file; > - > - FOR_EACH_VEC_ELT (m_source_files, i, file) > - { > - linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0); > - > - /* Sort lines by ascending line numbers. */ > - file->m_source_lines.qsort (&line_comparator); > - > - int j; > - source_line *line; > - FOR_EACH_VEC_ELT (file->m_source_lines, j, line) > - { > - int k; > - location *loc; > - > - /* Sort locations in line by ascending column numbers. */ > - line->m_locations.qsort (&location_comparator); > - > - /* Determine maximum column within this line. */ > - gcc_assert (line->m_locations.length () > 0); > - location *final_column = > - line->m_locations[line->m_locations.length () - 1]; > - int max_col = final_column->get_column_num (); > - > - linemap_line_start (line_table, line->get_line_num (), max_col); > - FOR_EACH_VEC_ELT (line->m_locations, k, loc) > - { > - loc->m_srcloc = \ > - linemap_position_for_column (line_table, loc->get_column_num ()); > - } > - } > - > - linemap_add (line_table, LC_LEAVE, false, NULL, 0); > - } > > + m_deferred_locations.add_to_line_table (); > /* line_table should now be populated; every playback::location should > now have an m_srcloc. */ > > /* Now assign them to tree nodes as appropriate. */ > + int i; > std::pair<tree, location *> *cached_location; > > FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location) > @@ -2808,6 +2747,17 @@ handle_locations () > } > } > > +/* Return the recording::location for playback::location LOC. > + Return NULL if LOC is NULL. */ > + > +static recording::location * > +get_recording_loc (playback::location *loc) > +{ > + if (!loc) > + return NULL; > + return reinterpret_cast <recording::location *> (loc->get_user_data ()); > +} > + > /* We handle errors on a playback::context by adding them to the > corresponding recording::context. */ > > @@ -2817,8 +2767,7 @@ add_error (location *loc, const char *fmt, ...) > { > va_list ap; > va_start (ap, fmt); > - m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL, > - fmt, ap); > + m_recording_ctxt->add_error_va (get_recording_loc (loc), fmt, ap); > va_end (ap); > } > > @@ -2829,8 +2778,7 @@ void > playback::context:: > add_error_va (location *loc, const char *fmt, va_list ap) > { > - m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL, > - fmt, ap); > + m_recording_ctxt->add_error_va (get_recording_loc (loc), fmt, ap); > } > > /* Dealing with the linemap API. */ > @@ -2868,120 +2816,14 @@ set_tree_location (tree t, location *loc) > } > > > -/* Construct a playback::source_file for the given source > +/* Construct a source_file for the given source > filename, if it doesn't exist already. */ > > -playback::source_file * > +source_file * > playback::context:: > get_source_file (const char *filename) > { > - /* Locate the file. > - For simplicitly, this is currently a linear search. > - Replace with a hash if this shows up in the profile. */ > - int i; > - source_file *file; > - tree ident_filename = get_identifier (filename); > - > - FOR_EACH_VEC_ELT (m_source_files, i, file) > - if (file->filename_as_tree () == ident_filename) > - return file; > - > - /* Not found. */ > - file = new source_file (ident_filename); > - m_source_files.safe_push (file); > - return file; > -} > - > -/* Constructor for gcc::jit::playback::source_file. */ > - > -playback::source_file::source_file (tree filename) : > - m_source_lines (), > - m_filename (filename) > -{ > -} > - > -/* Don't leak vec's internal buffer (in non-GC heap) when we are > - GC-ed. */ > - > -void > -playback::source_file::finalizer () > -{ > - m_source_lines.release (); > -} > - > -/* Construct a playback::source_line for the given line > - within this source file, if one doesn't exist already. */ > - > -playback::source_line * > -playback::source_file:: > -get_source_line (int line_num) > -{ > - /* Locate the line. > - For simplicitly, this is currently a linear search. > - Replace with a hash if this shows up in the profile. */ > - int i; > - source_line *line; > - > - FOR_EACH_VEC_ELT (m_source_lines, i, line) > - if (line->get_line_num () == line_num) > - return line; > - > - /* Not found. */ > - line = new source_line (this, line_num); > - m_source_lines.safe_push (line); > - return line; > -} > - > -/* Constructor for gcc::jit::playback::source_line. */ > - > -playback::source_line::source_line (source_file *file, int line_num) : > - m_locations (), > - m_source_file (file), > - m_line_num (line_num) > -{ > -} > - > -/* Don't leak vec's internal buffer (in non-GC heap) when we are > - GC-ed. */ > - > -void > -playback::source_line::finalizer () > -{ > - m_locations.release (); > -} > - > -/* Construct a playback::location for the given column > - within this line of a specific source file, if one doesn't exist > - already. */ > - > -playback::location * > -playback::source_line:: > -get_location (recording::location *rloc, int column_num) > -{ > - int i; > - location *loc; > - > - /* Another linear search that probably should be a hash table. */ > - FOR_EACH_VEC_ELT (m_locations, i, loc) > - if (loc->get_column_num () == column_num) > - return loc; > - > - /* Not found. */ > - loc = new location (rloc, this, column_num); > - m_locations.safe_push (loc); > - return loc; > -} > - > -/* Constructor for gcc::jit::playback::location. */ > - > -playback::location::location (recording::location *loc, > - source_line *line, > - int column_num) : > - m_srcloc (UNKNOWN_LOCATION), > - m_recording_loc (loc), > - m_line (line), > - m_column_num(column_num) > -{ > + return m_deferred_locations.get_source_file (filename); > } > > /* The active gcc::jit::playback::context instance. This is a singleton, > diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h > index 7519bc4..86118d9 100644 > --- a/gcc/jit/jit-playback.h > +++ b/gcc/jit/jit-playback.h > @@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see > #include <utility> // for std::pair > > #include "timevar.h" > +#include "deferred-locations.h" > > #include "jit-recording.h" > > @@ -305,7 +306,7 @@ private: > tree m_const_char_ptr; > > /* Source location handling. */ > - auto_vec<source_file *> m_source_files; > + deferred_locations m_deferred_locations; > > auto_vec<std::pair<tree, location *> > m_cached_locations; > }; > @@ -603,76 +604,6 @@ public: > {} > }; > > -/* Dealing with the linemap API. > - > - It appears that libcpp requires locations to be created as if by > - a tokenizer, creating them by filename, in ascending order of > - line/column, whereas our API doesn't impose any such constraints: > - we allow client code to create locations in arbitrary orders. > - > - To square this circle, we need to cache all location creation, > - grouping things up by filename/line, and then creating the linemap > - entries in a post-processing phase. */ > - > -/* A set of locations, all sharing a filename */ > -class source_file : public wrapper > -{ > -public: > - source_file (tree filename); > - void finalizer (); > - > - source_line * > - get_source_line (int line_num); > - > - tree filename_as_tree () const { return m_filename; } > - > - const char* > - get_filename () const { return IDENTIFIER_POINTER (m_filename); } > - > - vec<source_line *> m_source_lines; > - > -private: > - tree m_filename; > -}; > - > -/* A source line, with one or more locations of interest. */ > -class source_line : public wrapper > -{ > -public: > - source_line (source_file *file, int line_num); > - void finalizer (); > - > - location * > - get_location (recording::location *rloc, int column_num); > - > - int get_line_num () const { return m_line_num; } > - > - vec<location *> m_locations; > - > -private: > - source_file *m_source_file; > - int m_line_num; > -}; > - > -/* A specific location on a source line. This is what we expose > - to the client API. */ > -class location : public wrapper > -{ > -public: > - location (recording::location *loc, source_line *line, int column_num); > - > - int get_column_num () const { return m_column_num; } > - > - recording::location *get_recording_loc () const { return m_recording_loc; } > - > - source_location m_srcloc; > - > -private: > - recording::location *m_recording_loc; > - source_line *m_line; > - int m_column_num; > -}; > - > } // namespace gcc::jit::playback > > extern playback::context *active_playback_ctxt; > -- > 1.8.5.3 >
diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 6c5adc0..c61f303 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1239,6 +1239,7 @@ OBJS = \ dce.o \ ddg.o \ debug.o \ + deferred-locations.o \ df-core.o \ df-problems.o \ df-scan.o \ diff --git a/gcc/deferred-locations.c b/gcc/deferred-locations.c new file mode 100644 index 0000000..cd02938 --- /dev/null +++ b/gcc/deferred-locations.c @@ -0,0 +1,240 @@ +/* Dealing with the linemap API. + Copyright (C) 2013-2016 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 "input.h" +#include "deferred-locations.h" +#include "stringpool.h" +#include "tree.h" + +/* The wrapper subclasses are GC-managed, but can own non-GC memory. + Provide this finalization hook for calling then they are collected, + which calls the finalizer vfunc. This allows them to call "release" + on any vec<> within them. */ + +static void +wrapper_finalizer (void *ptr) +{ + wrapper *w = reinterpret_cast <wrapper *> (ptr); + w->finalizer (); +} + +/* wrapper subclasses are GC-managed: + allocate them using ggc_internal_cleared_alloc. */ + +void * +wrapper::operator new (size_t sz) +{ + return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1); + +} + +/* Constructor for source_file. */ + +source_file::source_file (tree filename) : + m_source_lines (), + m_filename (filename) +{ +} + +/* Don't leak vec's internal buffer (in non-GC heap) when we are + GC-ed. */ + +void +source_file::finalizer () +{ + m_source_lines.release (); +} + +/* Construct a source_line for the given line + within this source file, if one doesn't exist already. */ + +source_line * +source_file::get_source_line (int line_num) +{ + /* Locate the line. + For simplicitly, this is currently a linear search. + Replace with a hash if this shows up in the profile. */ + int i; + source_line *line; + + FOR_EACH_VEC_ELT (m_source_lines, i, line) + if (line->get_line_num () == line_num) + return line; + + /* Not found. */ + line = new source_line (this, line_num); + m_source_lines.safe_push (line); + return line; +} + +const char * +source_file::get_filename () const +{ + return IDENTIFIER_POINTER (m_filename); +} + +/* Constructor for source_line. */ + +source_line::source_line (source_file *file, int line_num) : + m_locations (), + m_source_file (file), + m_line_num (line_num) +{ +} + +/* Don't leak vec's internal buffer (in non-GC heap) when we are + GC-ed. */ + +void +source_line::finalizer () +{ + m_locations.release (); +} + +/* Construct a location for the given column + within this line of a specific source file, if one doesn't exist + already. */ + +deferred_location * +source_line::get_location (void *user_data, int column_num) +{ + int i; + deferred_location *loc; + + /* Another linear search that probably should be a hash table. */ + FOR_EACH_VEC_ELT (m_locations, i, loc) + if (loc->get_column_num () == column_num) + return loc; + + /* Not found. */ + loc = new deferred_location (user_data, this, column_num); + m_locations.safe_push (loc); + return loc; +} + +/* Constructor for deferred_location. */ +deferred_location::deferred_location (void *user_data, + source_line *line, + int column_num) : + m_srcloc (UNKNOWN_LOCATION), + m_user_data (user_data), + m_line (line), + m_column_num(column_num) +{ +} + +/* qsort comparator for comparing pairs of source_line *, + ordering them by line number. */ + +static int +line_comparator (const void *lhs, const void *rhs) +{ + const source_line *line_lhs = *static_cast<const source_line * const*> (lhs); + const source_line *line_rhs = *static_cast<const source_line * const*> (rhs); + return line_lhs->get_line_num () - line_rhs->get_line_num (); +} + +/* qsort comparator for comparing pairs of deferred_location *, + ordering them by column number. */ + +static int +location_comparator (const void *lhs, const void *rhs) +{ + const deferred_location *loc_lhs = \ + *static_cast<const deferred_location * const *> (lhs); + const deferred_location *loc_rhs = \ + *static_cast<const deferred_location * const *> (rhs); + return loc_lhs->get_column_num () - loc_rhs->get_column_num (); +} + +/* class deferred_locations */ + +deferred_locations::deferred_locations () +{ + m_source_files.create (0); +} + +/* Construct a source_file for the given source + filename, if it doesn't exist already. */ + +source_file * +deferred_locations::get_source_file (const char *filename) +{ + /* Locate the file. + For simplicitly, this is currently a linear search. + Replace with a hash if this shows up in the profile. */ + int i; + source_file *file; + tree ident_filename = get_identifier (filename); + + FOR_EACH_VEC_ELT (m_source_files, i, file) + if (file->filename_as_tree () == ident_filename) + return file; + + /* Not found. */ + file = new source_file (ident_filename); + m_source_files.safe_push (file); + return file; + +} + +void +deferred_locations::add_to_line_table () +{ + int i; + source_file *file; + + FOR_EACH_VEC_ELT (m_source_files, i, file) + { + linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0); + + /* Sort lines by ascending line numbers. */ + file->m_source_lines.qsort (&line_comparator); + + int j; + source_line *line; + FOR_EACH_VEC_ELT (file->m_source_lines, j, line) + { + int k; + deferred_location *loc; + + /* Sort locations in line by ascending column numbers. */ + line->m_locations.qsort (&location_comparator); + + /* Determine maximum column within this line. */ + gcc_assert (line->m_locations.length () > 0); + deferred_location *final_column = + line->m_locations[line->m_locations.length () - 1]; + int max_col = final_column->get_column_num (); + + linemap_line_start (line_table, line->get_line_num (), max_col); + FOR_EACH_VEC_ELT (line->m_locations, k, loc) + { + loc->m_srcloc = + linemap_position_for_column (line_table, loc->get_column_num ()); + } + } + + linemap_add (line_table, LC_LEAVE, false, NULL, 0); + } + +} diff --git a/gcc/deferred-locations.h b/gcc/deferred-locations.h new file mode 100644 index 0000000..209cb0d --- /dev/null +++ b/gcc/deferred-locations.h @@ -0,0 +1,139 @@ +/* Dealing with the linemap API. + Copyright (C) 2013-2016 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/>. */ + +#ifndef GCC_DEFERRED_LOCATIONS_H +#define GCC_DEFERRED_LOCATIONS_H + +/* Dealing with the linemap API. + + libcpp requires locations to be created as if by + a tokenizer, creating them by filename, in ascending order of + line/column, whereas the libgccjit API doesn't impose any such constraints: + we allow client code to create locations in arbitrary orders. + + To square this circle, we need to cache all location creation, + grouping things up by filename/line, and then creating the linemap + entries in a post-processing phase. */ + +/* A temporary wrapper object. + These objects are (mostly) only valid during replay. + We allocate them on the GC heap, so that they will be cleaned + the next time the GC collects. */ +class wrapper +{ +public: + /* Allocate in the GC heap. */ + void *operator new (size_t sz); + + /* Some wrapper subclasses contain vec<> and so need to + release them when they are GC-ed. */ + virtual void finalizer () { } +}; + +class source_file; +class source_line; +class deferred_location; + +/* A set of locations, all sharing a filename */ +class source_file : public wrapper +{ +public: + source_file (tree filename); + void finalizer (); + + source_line * + get_source_line (int line_num); + + tree filename_as_tree () const { return m_filename; } + + const char *get_filename () const; + + vec<source_line *> m_source_lines; + +private: + tree m_filename; +}; + +/* A source line, with one or more locations of interest. */ +class source_line : public wrapper +{ +public: + source_line (source_file *file, int line_num); + void finalizer (); + + deferred_location * + get_location (void *user_data, int column_num); + + int get_line_num () const { return m_line_num; } + + vec<deferred_location *> m_locations; + +private: + source_file *m_source_file; + int m_line_num; +}; + +/* A specific location on a source line. This is what we expose + to the JIT client API. */ +class deferred_location : public wrapper +{ +public: + deferred_location (void *user_data, source_line *line, int column_num); + + int get_column_num () const { return m_column_num; } + + void *get_user_data () const { return m_user_data; } + + source_location m_srcloc; + +private: + void *m_user_data; + source_line *m_line; + int m_column_num; +}; + +/* A class for managing the deferred creation of location_t values. + + Locations are created in two phases: + + - first phase: creation of source_file instances (via + deferred_locations::get_source_file), from which source_line + instances can be created (via source_file::get_source_line), from + which deferred_location instances can be created (via + source_line::get_location). + + - second phase: call deferred_location::add_to_line_table, which + walks all of the above and populates line_table, filling in + the various deferred_location instances with source_location + (aka location_t) values. */ + +class deferred_locations +{ + public: + deferred_locations (); + + source_file *get_source_file (const char *filename); + + void add_to_line_table (); + + private: + auto_vec<source_file *> m_source_files; +}; + +#endif /* #ifndef GCC_DEFERRED_LOCATIONS_H */ diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h index 8a6cd74..0a10cdf 100644 --- a/gcc/jit/jit-common.h +++ b/gcc/jit/jit-common.h @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "inchash.h" #include "tree-iterator.h" +#include "deferred-locations.h" #ifdef GCC_VERSION #if GCC_VERSION >= 4001 @@ -146,9 +147,7 @@ namespace playback { class rvalue; class lvalue; class param; - class source_file; - class source_line; - class location; + typedef deferred_location location; class case_; /* End of playback types. */ diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 579230d..f17c55b 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -85,7 +85,6 @@ playback::context::context (recording::context *ctxt) JIT_LOG_SCOPE (get_logger ()); m_functions.create (0); m_globals.create (0); - m_source_files.create (0); m_cached_locations.create (0); } @@ -2705,32 +2704,6 @@ get_path_so_file () const return m_tempdir->get_path_so_file (); } -/* qsort comparator for comparing pairs of playback::source_line *, - ordering them by line number. */ - -static int -line_comparator (const void *lhs, const void *rhs) -{ - const playback::source_line *line_lhs = \ - *static_cast<const playback::source_line * const*> (lhs); - const playback::source_line *line_rhs = \ - *static_cast<const playback::source_line * const*> (rhs); - return line_lhs->get_line_num () - line_rhs->get_line_num (); -} - -/* qsort comparator for comparing pairs of playback::location *, - ordering them by column number. */ - -static int -location_comparator (const void *lhs, const void *rhs) -{ - const playback::location *loc_lhs = \ - *static_cast<const playback::location * const *> (lhs); - const playback::location *loc_rhs = \ - *static_cast<const playback::location * const *> (rhs); - return loc_lhs->get_column_num () - loc_rhs->get_column_num (); -} - /* Our API allows locations to be created in arbitrary orders, but the linemap API requires locations to be created in ascending order as if we were tokenizing files. @@ -2748,47 +2721,13 @@ handle_locations () line_table is a global. */ JIT_LOG_SCOPE (get_logger ()); - int i; - source_file *file; - - FOR_EACH_VEC_ELT (m_source_files, i, file) - { - linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0); - - /* Sort lines by ascending line numbers. */ - file->m_source_lines.qsort (&line_comparator); - - int j; - source_line *line; - FOR_EACH_VEC_ELT (file->m_source_lines, j, line) - { - int k; - location *loc; - - /* Sort locations in line by ascending column numbers. */ - line->m_locations.qsort (&location_comparator); - - /* Determine maximum column within this line. */ - gcc_assert (line->m_locations.length () > 0); - location *final_column = - line->m_locations[line->m_locations.length () - 1]; - int max_col = final_column->get_column_num (); - - linemap_line_start (line_table, line->get_line_num (), max_col); - FOR_EACH_VEC_ELT (line->m_locations, k, loc) - { - loc->m_srcloc = \ - linemap_position_for_column (line_table, loc->get_column_num ()); - } - } - - linemap_add (line_table, LC_LEAVE, false, NULL, 0); - } + m_deferred_locations.add_to_line_table (); /* line_table should now be populated; every playback::location should now have an m_srcloc. */ /* Now assign them to tree nodes as appropriate. */ + int i; std::pair<tree, location *> *cached_location; FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location) @@ -2808,6 +2747,17 @@ handle_locations () } } +/* Return the recording::location for playback::location LOC. + Return NULL if LOC is NULL. */ + +static recording::location * +get_recording_loc (playback::location *loc) +{ + if (!loc) + return NULL; + return reinterpret_cast <recording::location *> (loc->get_user_data ()); +} + /* We handle errors on a playback::context by adding them to the corresponding recording::context. */ @@ -2817,8 +2767,7 @@ add_error (location *loc, const char *fmt, ...) { va_list ap; va_start (ap, fmt); - m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL, - fmt, ap); + m_recording_ctxt->add_error_va (get_recording_loc (loc), fmt, ap); va_end (ap); } @@ -2829,8 +2778,7 @@ void playback::context:: add_error_va (location *loc, const char *fmt, va_list ap) { - m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL, - fmt, ap); + m_recording_ctxt->add_error_va (get_recording_loc (loc), fmt, ap); } /* Dealing with the linemap API. */ @@ -2868,120 +2816,14 @@ set_tree_location (tree t, location *loc) } -/* Construct a playback::source_file for the given source +/* Construct a source_file for the given source filename, if it doesn't exist already. */ -playback::source_file * +source_file * playback::context:: get_source_file (const char *filename) { - /* Locate the file. - For simplicitly, this is currently a linear search. - Replace with a hash if this shows up in the profile. */ - int i; - source_file *file; - tree ident_filename = get_identifier (filename); - - FOR_EACH_VEC_ELT (m_source_files, i, file) - if (file->filename_as_tree () == ident_filename) - return file; - - /* Not found. */ - file = new source_file (ident_filename); - m_source_files.safe_push (file); - return file; -} - -/* Constructor for gcc::jit::playback::source_file. */ - -playback::source_file::source_file (tree filename) : - m_source_lines (), - m_filename (filename) -{ -} - -/* Don't leak vec's internal buffer (in non-GC heap) when we are - GC-ed. */ - -void -playback::source_file::finalizer () -{ - m_source_lines.release (); -} - -/* Construct a playback::source_line for the given line - within this source file, if one doesn't exist already. */ - -playback::source_line * -playback::source_file:: -get_source_line (int line_num) -{ - /* Locate the line. - For simplicitly, this is currently a linear search. - Replace with a hash if this shows up in the profile. */ - int i; - source_line *line; - - FOR_EACH_VEC_ELT (m_source_lines, i, line) - if (line->get_line_num () == line_num) - return line; - - /* Not found. */ - line = new source_line (this, line_num); - m_source_lines.safe_push (line); - return line; -} - -/* Constructor for gcc::jit::playback::source_line. */ - -playback::source_line::source_line (source_file *file, int line_num) : - m_locations (), - m_source_file (file), - m_line_num (line_num) -{ -} - -/* Don't leak vec's internal buffer (in non-GC heap) when we are - GC-ed. */ - -void -playback::source_line::finalizer () -{ - m_locations.release (); -} - -/* Construct a playback::location for the given column - within this line of a specific source file, if one doesn't exist - already. */ - -playback::location * -playback::source_line:: -get_location (recording::location *rloc, int column_num) -{ - int i; - location *loc; - - /* Another linear search that probably should be a hash table. */ - FOR_EACH_VEC_ELT (m_locations, i, loc) - if (loc->get_column_num () == column_num) - return loc; - - /* Not found. */ - loc = new location (rloc, this, column_num); - m_locations.safe_push (loc); - return loc; -} - -/* Constructor for gcc::jit::playback::location. */ - -playback::location::location (recording::location *loc, - source_line *line, - int column_num) : - m_srcloc (UNKNOWN_LOCATION), - m_recording_loc (loc), - m_line (line), - m_column_num(column_num) -{ + return m_deferred_locations.get_source_file (filename); } /* The active gcc::jit::playback::context instance. This is a singleton, diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 7519bc4..86118d9 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see #include <utility> // for std::pair #include "timevar.h" +#include "deferred-locations.h" #include "jit-recording.h" @@ -305,7 +306,7 @@ private: tree m_const_char_ptr; /* Source location handling. */ - auto_vec<source_file *> m_source_files; + deferred_locations m_deferred_locations; auto_vec<std::pair<tree, location *> > m_cached_locations; }; @@ -603,76 +604,6 @@ public: {} }; -/* Dealing with the linemap API. - - It appears that libcpp requires locations to be created as if by - a tokenizer, creating them by filename, in ascending order of - line/column, whereas our API doesn't impose any such constraints: - we allow client code to create locations in arbitrary orders. - - To square this circle, we need to cache all location creation, - grouping things up by filename/line, and then creating the linemap - entries in a post-processing phase. */ - -/* A set of locations, all sharing a filename */ -class source_file : public wrapper -{ -public: - source_file (tree filename); - void finalizer (); - - source_line * - get_source_line (int line_num); - - tree filename_as_tree () const { return m_filename; } - - const char* - get_filename () const { return IDENTIFIER_POINTER (m_filename); } - - vec<source_line *> m_source_lines; - -private: - tree m_filename; -}; - -/* A source line, with one or more locations of interest. */ -class source_line : public wrapper -{ -public: - source_line (source_file *file, int line_num); - void finalizer (); - - location * - get_location (recording::location *rloc, int column_num); - - int get_line_num () const { return m_line_num; } - - vec<location *> m_locations; - -private: - source_file *m_source_file; - int m_line_num; -}; - -/* A specific location on a source line. This is what we expose - to the client API. */ -class location : public wrapper -{ -public: - location (recording::location *loc, source_line *line, int column_num); - - int get_column_num () const { return m_column_num; } - - recording::location *get_recording_loc () const { return m_recording_loc; } - - source_location m_srcloc; - -private: - recording::location *m_recording_loc; - source_line *m_line; - int m_column_num; -}; - } // namespace gcc::jit::playback extern playback::context *active_playback_ctxt;