diff --git a/docs/GarbageCollection.html b/docs/GarbageCollection.html index c2236d4d81a..1508bcf2231 100644 --- a/docs/GarbageCollection.html +++ b/docs/GarbageCollection.html @@ -26,9 +26,9 @@
  • Getting started
  • @@ -166,11 +166,12 @@ concerned are:

    @@ -178,10 +179,13 @@ concerned are:

    There are additional areas that LLVM does not directly address:

    In general, LLVM's support for GC does not include features which can be @@ -208,11 +212,11 @@ compiler matures.

  • Write a runtime library or find an existing one which implements a GC heap.
    1. Implement a memory allocator.
    2. -
    3. Design a binary interface for frame descriptors, used to identify - references within a stack frame.*
    4. +
    5. Design a binary interface for the stack map, used to identify + references within a stack frame on the machine stack.*
    6. Implement a stack crawler to discover functions on the call stack.*
    7. Implement a registry for global roots.
    8. -
    9. Design a binary interface for type descriptors, used to map references +
    10. Design a binary interface for type maps, used to identify references within heap objects.
    11. Implement a collection routine bringing together all of the above.
  • @@ -225,12 +229,13 @@ compiler matures.

    manipulate GC references, if necessary.
  • Allocate memory using the GC allocation routine provided by the runtime library.
  • -
  • Generate type descriptors according to your runtime's binary interface.
  • +
  • Generate type maps according to your runtime's binary interface.
  • Write a compiler plugin to interface LLVM with the runtime library.*
  • Load the plugin into the compiler. Use llc -load or link the plugin statically with your language's compiler.*
  • @@ -290,14 +295,14 @@ code.)

    /// @brief A constant shadow stack frame descriptor. The compiler emits one of
    -///        these for each function.
    +>/// @brief The map for a single function's stack frame. One of these is
    +///        compiled as constant data into the executable for each function.
     /// 
    -/// Storage of metadata values is elided if the %meta parameter to @llvm.gcroot
    -/// is null.
    +/// Storage of metadata values is elided if the %metadata parameter to
    +/// @llvm.gcroot is null.
     struct FrameMap {
       int32_t NumRoots;    //< Number of roots in stack frame.
    -  int32_t NumMeta;     //< Number of metadata descriptors. May be < NumRoots.
    +  int32_t NumMeta;     //< Number of metadata entries. May be < NumRoots.
       const void *Meta[0]; //< Metadata for each root.
     };
     
    @@ -345,11 +350,13 @@ void visitGCRoots(void (*Visitor)(void **Root, const void *Meta)) {
     

    Unlike many GC algorithms which rely on a cooperative code generator to -generate stack maps, this algorithm carefully maintains a linked list of stack -root descriptors [Henderson2002]. This so-called -"shadow stack" mirrors the machine stack. Maintaining this data structure is -slower than using stack maps, but has a significant portability advantage -because it requires no special support from the target code generator.

    +compile stack maps, this algorithm carefully maintains a linked list of stack +roots [Henderson2002]. This so-called "shadow stack" +mirrors the machine stack. Maintaining this data structure is slower than using +a stack map compiled into the executable as constant data, but has a significant +portability advantage because it requires no special support from the target +code generator, and does not require tricky platform-specific code to crawl +the machine stack.

    The tradeoff for this simplicity and portability is:

    @@ -358,7 +365,10 @@ because it requires no special support from the target code generator.

  • Not thread-safe.
  • -

    Still, it's an easy way to get started.

    +

    Still, it's an easy way to get started. After your compiler and runtime are +up and running, writing a plugin will allow you to take +advantage of more advanced GC features of LLVM +in order to improve performance.

    @@ -520,6 +530,11 @@ require the corresponding barrier. If so, the GC plugin will replace the intrinsic calls with the corresponding load or store instruction if they are used.

    +

    LLVM does not enforce any particular relationship between the object and +derived pointer (although a plugin might). However, it +would be unusual that the derived pointer not be a getelementptr of the +object pointer.

    +
    @@ -581,15 +596,16 @@ function attribute or, equivalently, with the setGC method of

    To implement a GC plugin, it is necessary to subclass llvm::GCStrategy, which can be accomplished in a few lines of boilerplate code. LLVM's infrastructure provides access to several important -algorithms. For an uncontroversial collector, all that remains may be to emit -the assembly code for the collector's unique stack map data structure, which -might be accomplished in as few as 100 LOC.

    +algorithms. For an uncontroversial collector, all that remains may be to +compile LLVM's computed stack map to assembly code (using the binary +representation expected by the runtime library). This can be accomplished in +about 100 lines of code.

    This is not the appropriate place to implement a garbage collected heap or a garbage collector itself. That code should exist in the language's runtime library. The compiler plugin is responsible for generating code which conforms to the binary interface defined by library, most essentially the -stack map.

    +stack map.

    To subclass llvm::GCStrategy and register it with the compiler:

    @@ -611,9 +627,21 @@ namespace { X("mygc", "My bespoke garbage collector."); } +

    This boilerplate collector does nothing. More specifically:

    + + +

    Using the LLVM makefiles (like the sample -project), this can be built into a plugin using a simple makefile:

    +project), this code can be compiled as a plugin using a simple +makefile:

    # lib/MyGC/Makefile
    @@ -648,20 +676,11 @@ as a language-specific compiler front-end.

    -

    The boilerplate collector above does nothing. More specifically:

    - -
      -
    • llvm.gcread calls are replaced with the corresponding - load instruction.
    • -
    • llvm.gcwrite calls are replaced with the corresponding - store instruction.
    • -
    • No stack map is emitted, and no safe points are added.
    • -
    - -

    Collector provides a range of features through which a plugin -collector may do useful work. This matrix summarizes the supported (and planned) -features and correlates them with the collection techniques which typically -require them.

    +

    GCStrategy provides a range of features through which a plugin +may do useful work. Some of these are callbacks, some are algorithms that can +be enabled, disabled, or customized. This matrix summarizes the supported (and +planned) features and correlates them with the collection techniques which +typically require them.

    @@ -898,8 +917,7 @@ require them.

    Shadow Stack
    -
    The mutator carefully maintains a linked list of stack root - descriptors.
    +
    The mutator carefully maintains a linked list of stack roots.
    Reference Counting
    The mutator maintains a reference count for each object and frees an object when its count falls to zero.
    @@ -947,6 +965,33 @@ interest.

    +

    LLVM automatically computes a stack map. One of the most important features +of a GCStrategy is to compile this information into the executable in +the binary representation expected by the runtime library.

    + +

    The stack map consists of the location and identity of each GC root in the +each function in the module. For each root:

    + +
      +
    • RootNum: The index of the root.
    • +
    • StackOffset: The offset of the object relative to the frame + pointer.
    • +
    • RootMetadata: The value passed as the %metadata + parameter to the @llvm.gcroot intrinsic.
    • +
    + +

    Also, for the function as a whole:

    + +
      +
    • getFrameSize(): The overall size of the function's initial + stack frame, not accounting for any dynamic allocation.
    • +
    • roots_size(): The count of roots in the function.
    • +
    + +

    To access the stack map, use GCFunctionMetadata::roots_begin() and +-end() from the GCMetadataPrinter:

    +
    for (iterator I = begin(), E = end(); I != E; ++I) {
       GCFunctionInfo *FI = *I;
    @@ -962,10 +1007,9 @@ interest.

    } }
    -

    LLVM automatically computes a stack map. All a GCStrategy needs to do -is access it using GCFunctionMetadata::roots_begin() and --end(). If the llvm.gcroot intrinsic is eliminated before code -generation by a custom lowering pass, LLVM's stack map will be empty.

    +

    If the llvm.gcroot intrinsic is eliminated before code generation by +a custom lowering pass, LLVM will compute an empty stack map. This may be useful +for collector plugins which implement reference counting or a shadow stack.

    @@ -1027,8 +1071,8 @@ the corresponding intrinsics and instead calls

    LLVM's default action for each intrinsic is as follows:

      -
    • llvm.gcroot: Pass through to the code generator to generate a - stack map.
    • +
    • llvm.gcroot: Leave it alone. The code generator must see it + or the stack map will not be computed.
    • llvm.gcread: Substitute a load instruction.
    • llvm.gcwrite: Substitute a store instruction.
    @@ -1156,9 +1200,9 @@ safe point (because only the topmost function has been patched).

    -

    LLVM allows a GC to print arbitrary assembly code before and after the rest -of a module's assembly code. At the end of the module, the GC can print stack -maps built by the code generator. (At the beginning, this information is not +

    LLVM allows a plugin to print arbitrary assembly code before and after the +rest of a module's assembly code. At the end of the module, the GC can compile +the LLVM stack map into assembly code. (At the beginning, this information is not yet computed.)

    Since AsmWriter and CodeGen are separate components of LLVM, a separate @@ -1172,6 +1216,8 @@ will look for such a subclass if the GCStrategy sets UsesMetadata = true; } +

    This separation allows JIT-only clients to be smaller.

    +

    Note that LLVM does not currently have analogous APIs to support code generation in the JIT, nor using the object writers.

    @@ -1249,7 +1295,7 @@ void MyGCPrinter::finishAssembly(std::ostream &OS, AsmPrinter &AP, // Align to address width. AP.EmitAlignment(AddressAlignLog); - // Emit the symbol by which the stack map can be found. + // Emit the symbol by which the stack map entry can be found. std::string Symbol; Symbol += TAI.getGlobalPrefix(); Symbol += "__gcmap_";