On Fri, Nov 16, 2012 at 1:59 AM, Diego Novillo <dnovi...@google.com> wrote:
> As we continue adding new C++ features in the compiler, gengtype
> is becoming an increasing source of pain.  In this proposal, we
> want to explore different approaches to GC that we could
> implement.
>
> At this point, we are trying to reach consensus on the general
> direction that we should take.  Given how intertwined GC and PCH
> are, the choices we make for one affect the other.
>
> We don't have a strong preference at the moment, but we are
> leaning in these directions:
>
> Diego:
>         Get rid of GC completely.  Move into pool allocation.
>         If we continue to use GC, then either use boehm-gc or
>         continue use the precise allocator, but with user
>         generated  marking.
>
> Lawrence:
>         Get rid of GC completely.  Move into pool allocation.
>         If we continue to use GC, either move to user-generated
>         marking or implement the GTY attributes in cc1plus (read
>         below).  For PCH, used a fixed address where all the
>         PCH-able data would go, as this would represent less work
>         than implementing streamable types.
>
>
>
> Gengtype is a poor C parser. It is a long way from handling all
> of the C++ constructs what are used by the C++ standard library.
> We have a few potential solutions. Solution: Stick with Gengtype
>
>
> As gengtype currently does not handle what we need, something
> must change.

I'd say the most pragmatic solution is to stick with gengtype but
make it more dependent on annotations (thus, explicit).  That is,
instead of trying to parse a struct declaration annotate respective
things explicitely thus,

class X GTY(()) : public Y GTY((base)) {
  Foo *x GTY(());
  Bar y;
};

thus in the above example instead of GTY((skip)) on y explicitely
mark 'x' as to be handled by gengtype.

I suppose I agree that garbage collection is not technically
required for writing a compiler, but getting rid of GC in GCC
entirely will be a hard and error-prone task (even if you
factor out PCH which is an entirely different mess).

Richard.

>
> === Approach: Limit the Language Used
>
> We could avoid the problem by limiting the language we use to
> near that which gengtype currently understands.  This approach
> has significant consequences. It will make the standard library
> incompatible with GTY.  It will prevent the use of common idioms,
> such as iterators, within GTY types.  These limitations are
> significant and not desirable. Approach: Upgrade Gengtype
>
>
> Full C++ support would essentially require building a new C++
> parser.
>
>
> === Approach: Both Limit and Upgrade
>
> We can try upgrading gengtype to handle a more extensive subset
> of C++, without trying to handle the full language. See Thoughts
> on Gengtype and Single Inheritance. Taking this approach would
> likely mean we would be unable to use the C++ standard library
> within GCC.
>
>
> === Approach: Move GTY to cc1plus.
>
> Instead of a separate weak parser, we would make cc1plus
> understand GTY attributes.  The compiler would emit IL in the
> object files instead of generating source.
>
> This solution would require a first boot stage that did not
> support PCH, because we cannot rely on the seed compiler
> supporting GTY.  We would probably need to use the Boehm
> collector during the first stage as well.
>
> Because the first stage would be fundamentally different from the
> second stage, we may need to add an additional pass for correct
> object file comparisons.
>
>
> === Approach: Do GTY manually
>
> In this approach we would be converting GTY from a declarative
> form into a procedural one using the C++ type system and
> manually-implemented structure field handlers.  At the highest
> level, this roughly means that all the structures using GTY(())
> markers will start using GTY((user)).
>
> The marking code dealing with the semantics of the marked data
> structure is co-located with the data structure.  When GC
> problems occur, this simplifies debugging.  The user is no longer
> faced with a mass of auto generated code that is unfamiliar and
> hard to trace. The code to implement is straightforward.  For
> every pointer field in the given instance pointer, a single
> "mark" function needs to be called.
>
> Common facilities to mark arrays will be provided via a base GC
> class. No generated header files to #include at the end of the
> source file. No new dependencies to add to the Makefile. No need
> to parse C++.
>
> The problem with this approach is that the declarative approach
> puts the field additions and the GTY annotations in the same
> place, as opposed to in separate code. While it is possible to
> use standard library containers with GC pointers in them, we
> would not be able to write these containers to PCH images.
>
>
> === Approach: Get rid of GTY
>
> This approach engenders more choices.  The pre-compiled header
> implementation uses gengtype, so this approach is not viable
> unless we have an alternate implementation for PCH. We will also
> need another approach to memory management.
>
>
> === Approach: Permanent Addresses for PCH
>
> Create an alternate implementation of PCH using mmap and a region
> allocator. The essential difference is that we need to allocate
> the data structures in their final location, rather than the
> current approach of allocating someplace and then walking the
> trees to move them to the desired and fixed mmap address. Because
> this implementation would not do a final copy, it may leave
> allocation holes in the memory region.  To reduce this cost, we
> can zero all unallocated memory in the region and then compress
> it before writing the PCH file.  Compressing the file has already
> proven effective on existing PCH files, and so the compression
> work would not be a problem.
>
> We still need to indicate which objects go into PCH memory.  For
> compiler-specific types that always go into PCH memory, we can
> create a base class that provides class-member operators new and
> delete. These would allocate from the region allocator.  For C++
> standard library structures parameterized by allocators, we could
> provide an allocator that does the same thing.  For other types,
> we would require more explicit allocation and deallocation.
>
>
> === Approach: Manual PCH using streamable types
>
> Every type knows how to build a bytecode vector for its contents.
> A stream manager asks all the instances to build their bytecode
> vectors and writes them to disk. This build on the streaming
> support implemented for LTO.
>
>
> === Approach: Use the Boehm collector.
>
> The general approach is to define allocation and deallocation
> functions to the Boehm collector that handle memory within the
> PCH range.  We would also provide a class to register global
> roots at the point of declaration of those roots. We would likely
> configure the collector to collect only on command, not
> automatically.  Laurynas says previous efforts showed
> that the peak memory usage was slightly higher that with the
> existing collectors due to Boehm's conservativeness. The run time
> was comparable.
>
>
> === Approach: Move RTL back to obstacks.
>
> Laurynas started this in 2011.  I'm not sure what the status of
> this is.  Laurynas?
>
>
> === Approach: Replace GC with smart pointers.
>
> We need to identify all pointers that result in circular
> structures and not use smart pointers for them.  We would
> probably still have some circular structures resulting from the
> compilation of mutually referencing structs.
>
>
> So, the options seem numerous.  Before we start running in any
> particular direction, we'd like to get a sense of what folks
> think would be the best approach long term.
>
> In this, we want to stress that we would rather shoot for
> long-term viability/maintainability, even if it means
> short/medium term pain.  We are thinking of targetting 4.9 or
> even 5.0.
>
> In the meantime, we will need to apply some more duct tape and
> string to keep gengtype puttering along.
>
>
> Thanks.

Reply via email to