|  | ===================================== | 
|  | Garbage Collection with LLVM | 
|  | ===================================== | 
|  |  | 
|  | .. contents:: | 
|  | :local: | 
|  |  | 
|  | Abstract | 
|  | ======== | 
|  |  | 
|  | This document covers how to integrate LLVM into a compiler for a language which | 
|  | supports garbage collection.  **Note that LLVM itself does not provide a | 
|  | garbage collector.**  You must provide your own. | 
|  |  | 
|  | Quick Start | 
|  | ============ | 
|  |  | 
|  | First, you should pick a collector strategy.  LLVM includes a number of built | 
|  | in ones, but you can also implement a loadable plugin with a custom definition. | 
|  | Note that the collector strategy is a description of how LLVM should generate | 
|  | code such that it interacts with your collector and runtime, not a description | 
|  | of the collector itself. | 
|  |  | 
|  | Next, mark your generated functions as using your chosen collector strategy. | 
|  | From c++, you can call: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | F.setGC(<collector description name>); | 
|  |  | 
|  |  | 
|  | This will produce IR like the following fragment: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define void @foo() gc "<collector description name>" { ... } | 
|  |  | 
|  |  | 
|  | When generating LLVM IR for your functions, you will need to: | 
|  |  | 
|  | * Use ``@llvm.gcread`` and/or ``@llvm.gcwrite`` in place of standard load and | 
|  | store instructions.  These intrinsics are used to represent load and store | 
|  | barriers.  If you collector does not require such barriers, you can skip | 
|  | this step. | 
|  |  | 
|  | * Use the memory allocation routines provided by your garbage collector's | 
|  | runtime library. | 
|  |  | 
|  | * If your collector requires them, generate type maps according to your | 
|  | runtime's binary interface.  LLVM is not involved in the process.  In | 
|  | particular, the LLVM type system is not suitable for conveying such | 
|  | information though the compiler. | 
|  |  | 
|  | * Insert any coordination code required for interacting with your collector. | 
|  | Many collectors require running application code to periodically check a | 
|  | flag and conditionally call a runtime function.  This is often referred to | 
|  | as a safepoint poll. | 
|  |  | 
|  | You will need to identify roots (i.e. references to heap objects your collector | 
|  | needs to know about) in your generated IR, so that LLVM can encode them into | 
|  | your final stack maps.  Depending on the collector strategy chosen, this is | 
|  | accomplished by using either the ``@llvm.gcroot`` intrinsics or an | 
|  | ``gc.statepoint`` relocation sequence. | 
|  |  | 
|  | Don't forget to create a root for each intermediate value that is generated when | 
|  | evaluating an expression.  In ``h(f(), g())``, the result of ``f()`` could | 
|  | easily be collected if evaluating ``g()`` triggers a collection. | 
|  |  | 
|  | Finally, you need to link your runtime library with the generated program | 
|  | executable (for a static compiler) or ensure the appropriate symbols are | 
|  | available for the runtime linker (for a JIT compiler). | 
|  |  | 
|  |  | 
|  | Introduction | 
|  | ============ | 
|  |  | 
|  | What is Garbage Collection? | 
|  | --------------------------- | 
|  |  | 
|  | Garbage collection is a widely used technique that frees the programmer from | 
|  | having to know the lifetimes of heap objects, making software easier to produce | 
|  | and maintain.  Many programming languages rely on garbage collection for | 
|  | automatic memory management.  There are two primary forms of garbage collection: | 
|  | conservative and accurate. | 
|  |  | 
|  | Conservative garbage collection often does not require any special support from | 
|  | either the language or the compiler: it can handle non-type-safe programming | 
|  | languages (such as C/C++) and does not require any special information from the | 
|  | compiler.  The `Boehm collector | 
|  | <http://www.hpl.hp.com/personal/Hans_Boehm/gc/>`__ is an example of a | 
|  | state-of-the-art conservative collector. | 
|  |  | 
|  | Accurate garbage collection requires the ability to identify all pointers in the | 
|  | program at run-time (which requires that the source-language be type-safe in | 
|  | most cases).  Identifying pointers at run-time requires compiler support to | 
|  | locate all places that hold live pointer variables at run-time, including the | 
|  | :ref:`processor stack and registers <gcroot>`. | 
|  |  | 
|  | Conservative garbage collection is attractive because it does not require any | 
|  | special compiler support, but it does have problems.  In particular, because the | 
|  | conservative garbage collector cannot *know* that a particular word in the | 
|  | machine is a pointer, it cannot move live objects in the heap (preventing the | 
|  | use of compacting and generational GC algorithms) and it can occasionally suffer | 
|  | from memory leaks due to integer values that happen to point to objects in the | 
|  | program.  In addition, some aggressive compiler transformations can break | 
|  | conservative garbage collectors (though these seem rare in practice). | 
|  |  | 
|  | Accurate garbage collectors do not suffer from any of these problems, but they | 
|  | can suffer from degraded scalar optimization of the program.  In particular, | 
|  | because the runtime must be able to identify and update all pointers active in | 
|  | the program, some optimizations are less effective.  In practice, however, the | 
|  | locality and performance benefits of using aggressive garbage collection | 
|  | techniques dominates any low-level losses. | 
|  |  | 
|  | This document describes the mechanisms and interfaces provided by LLVM to | 
|  | support accurate garbage collection. | 
|  |  | 
|  | Goals and non-goals | 
|  | ------------------- | 
|  |  | 
|  | LLVM's intermediate representation provides :ref:`garbage collection intrinsics | 
|  | <gc_intrinsics>` that offer support for a broad class of collector models.  For | 
|  | instance, the intrinsics permit: | 
|  |  | 
|  | * semi-space collectors | 
|  |  | 
|  | * mark-sweep collectors | 
|  |  | 
|  | * generational collectors | 
|  |  | 
|  | * incremental collectors | 
|  |  | 
|  | * concurrent collectors | 
|  |  | 
|  | * cooperative collectors | 
|  |  | 
|  | * reference counting | 
|  |  | 
|  | We hope that the support built into the LLVM IR is sufficient to support a | 
|  | broad class of garbage collected languages including Scheme, ML, Java, C#, | 
|  | Perl, Python, Lua, Ruby, other scripting languages, and more. | 
|  |  | 
|  | Note that LLVM **does not itself provide a garbage collector** --- this should | 
|  | be part of your language's runtime library.  LLVM provides a framework for | 
|  | describing the garbage collectors requirements to the compiler.  In particular, | 
|  | LLVM provides support for generating stack maps at call sites, polling for a | 
|  | safepoint, and emitting load and store barriers.  You can also extend LLVM - | 
|  | possibly through a loadable :ref:`code generation plugins <plugin>` - to | 
|  | generate code and data structures which conforms to the *binary interface* | 
|  | specified by the *runtime library*.  This is similar to the relationship between | 
|  | LLVM and DWARF debugging info, for example.  The difference primarily lies in | 
|  | the lack of an established standard in the domain of garbage collection --- thus | 
|  | the need for a flexible extension mechanism. | 
|  |  | 
|  | The aspects of the binary interface with which LLVM's GC support is | 
|  | concerned are: | 
|  |  | 
|  | * Creation of GC safepoints within code where collection is allowed to execute | 
|  | safely. | 
|  |  | 
|  | * Computation of the stack map.  For each safe point in the code, object | 
|  | references within the stack frame must be identified so that the collector may | 
|  | traverse and perhaps update them. | 
|  |  | 
|  | * Write barriers when storing object references to the heap.  These are commonly | 
|  | used to optimize incremental scans in generational collectors. | 
|  |  | 
|  | * Emission of read barriers when loading object references.  These are useful | 
|  | for interoperating with concurrent collectors. | 
|  |  | 
|  | There are additional areas that LLVM does not directly address: | 
|  |  | 
|  | * Registration of global roots with the runtime. | 
|  |  | 
|  | * Registration of stack map entries with the runtime. | 
|  |  | 
|  | * The functions used by the program to allocate memory, trigger a collection, | 
|  | etc. | 
|  |  | 
|  | * Computation or compilation of type maps, or registration of them with the | 
|  | runtime.  These are used to crawl the heap for object references. | 
|  |  | 
|  | In general, LLVM's support for GC does not include features which can be | 
|  | adequately addressed with other features of the IR and does not specify a | 
|  | particular binary interface.  On the plus side, this means that you should be | 
|  | able to integrate LLVM with an existing runtime.  On the other hand, it can | 
|  | have the effect of leaving a lot of work for the developer of a novel | 
|  | language.  We try to mitigate this by providing built in collector strategy | 
|  | descriptions that can work with many common collector designs and easy | 
|  | extension points.  If you don't already have a specific binary interface | 
|  | you need to support, we recommend trying to use one of these built in collector | 
|  | strategies. | 
|  |  | 
|  | .. _gc_intrinsics: | 
|  |  | 
|  | LLVM IR Features | 
|  | ================ | 
|  |  | 
|  | This section describes the garbage collection facilities provided by the | 
|  | :doc:`LLVM intermediate representation <LangRef>`.  The exact behavior of these | 
|  | IR features is specified by the selected :ref:`GC strategy description | 
|  | <plugin>`. | 
|  |  | 
|  | Specifying GC code generation: ``gc "..."`` | 
|  | ------------------------------------------- | 
|  |  | 
|  | .. code-block:: text | 
|  |  | 
|  | define <returntype> @name(...) gc "name" { ... } | 
|  |  | 
|  | The ``gc`` function attribute is used to specify the desired GC strategy to the | 
|  | compiler.  Its programmatic equivalent is the ``setGC`` method of ``Function``. | 
|  |  | 
|  | Setting ``gc "name"`` on a function triggers a search for a matching subclass | 
|  | of GCStrategy.  Some collector strategies are built in.  You can add others | 
|  | using either the loadable plugin mechanism, or by patching your copy of LLVM. | 
|  | It is the selected GC strategy which defines the exact nature of the code | 
|  | generated to support GC.  If none is found, the compiler will raise an error. | 
|  |  | 
|  | Specifying the GC style on a per-function basis allows LLVM to link together | 
|  | programs that use different garbage collection algorithms (or none at all). | 
|  |  | 
|  | .. _gcroot: | 
|  |  | 
|  | Identifying GC roots on the stack | 
|  | ---------------------------------- | 
|  |  | 
|  | LLVM currently supports two different mechanisms for describing references in | 
|  | compiled code at safepoints.  ``llvm.gcroot`` is the older mechanism; | 
|  | ``gc.statepoint`` has been added more recently.  At the moment, you can choose | 
|  | either implementation (on a per :ref:`GC strategy <plugin>` basis).  Longer | 
|  | term, we will probably either migrate away from ``llvm.gcroot`` entirely, or | 
|  | substantially merge their implementations. Note that most new development | 
|  | work is focused on ``gc.statepoint``. | 
|  |  | 
|  | Using ``gc.statepoint`` | 
|  | ^^^^^^^^^^^^^^^^^^^^^^^^ | 
|  | :doc:`This page <Statepoints>` contains detailed documentation for | 
|  | ``gc.statepoint``. | 
|  |  | 
|  | Using ``llvm.gcwrite`` | 
|  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | void @llvm.gcroot(i8** %ptrloc, i8* %metadata) | 
|  |  | 
|  | The ``llvm.gcroot`` intrinsic is used to inform LLVM that a stack variable | 
|  | references an object on the heap and is to be tracked for garbage collection. | 
|  | The exact impact on generated code is specified by the Function's selected | 
|  | :ref:`GC strategy <plugin>`.  All calls to ``llvm.gcroot`` **must** reside | 
|  | inside the first basic block. | 
|  |  | 
|  | The first argument **must** be a value referring to an alloca instruction or a | 
|  | bitcast of an alloca.  The second contains a pointer to metadata that should be | 
|  | associated with the pointer, and **must** be a constant or global value | 
|  | address.  If your target collector uses tags, use a null pointer for metadata. | 
|  |  | 
|  | A compiler which performs manual SSA construction **must** ensure that SSA | 
|  | values representing GC references are stored in to the alloca passed to the | 
|  | respective ``gcroot`` before every call site and reloaded after every call. | 
|  | A compiler which uses mem2reg to raise imperative code using ``alloca`` into | 
|  | SSA form need only add a call to ``@llvm.gcroot`` for those variables which | 
|  | are pointers into the GC heap. | 
|  |  | 
|  | It is also important to mark intermediate values with ``llvm.gcroot``.  For | 
|  | example, consider ``h(f(), g())``.  Beware leaking the result of ``f()`` in the | 
|  | case that ``g()`` triggers a collection.  Note, that stack variables must be | 
|  | initialized and marked with ``llvm.gcroot`` in function's prologue. | 
|  |  | 
|  | The ``%metadata`` argument can be used to avoid requiring heap objects to have | 
|  | 'isa' pointers or tag bits. [Appel89_, Goldberg91_, Tolmach94_] If specified, | 
|  | its value will be tracked along with the location of the pointer in the stack | 
|  | frame. | 
|  |  | 
|  | Consider the following fragment of Java code: | 
|  |  | 
|  | .. code-block:: java | 
|  |  | 
|  | { | 
|  | Object X;   // A null-initialized reference to an object | 
|  | ... | 
|  | } | 
|  |  | 
|  | This block (which may be located in the middle of a function or in a loop nest), | 
|  | could be compiled to this LLVM code: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | Entry: | 
|  | ;; In the entry block for the function, allocate the | 
|  | ;; stack space for X, which is an LLVM pointer. | 
|  | %X = alloca %Object* | 
|  |  | 
|  | ;; Tell LLVM that the stack space is a stack root. | 
|  | ;; Java has type-tags on objects, so we pass null as metadata. | 
|  | %tmp = bitcast %Object** %X to i8** | 
|  | call void @llvm.gcroot(i8** %tmp, i8* null) | 
|  | ... | 
|  |  | 
|  | ;; "CodeBlock" is the block corresponding to the start | 
|  | ;;  of the scope above. | 
|  | CodeBlock: | 
|  | ;; Java null-initializes pointers. | 
|  | store %Object* null, %Object** %X | 
|  |  | 
|  | ... | 
|  |  | 
|  | ;; As the pointer goes out of scope, store a null value into | 
|  | ;; it, to indicate that the value is no longer live. | 
|  | store %Object* null, %Object** %X | 
|  | ... | 
|  |  | 
|  | Reading and writing references in the heap | 
|  | ------------------------------------------ | 
|  |  | 
|  | Some collectors need to be informed when the mutator (the program that needs | 
|  | garbage collection) either reads a pointer from or writes a pointer to a field | 
|  | of a heap object.  The code fragments inserted at these points are called *read | 
|  | barriers* and *write barriers*, respectively.  The amount of code that needs to | 
|  | be executed is usually quite small and not on the critical path of any | 
|  | computation, so the overall performance impact of the barrier is tolerable. | 
|  |  | 
|  | Barriers often require access to the *object pointer* rather than the *derived | 
|  | pointer* (which is a pointer to the field within the object).  Accordingly, | 
|  | these intrinsics take both pointers as separate arguments for completeness.  In | 
|  | this snippet, ``%object`` is the object pointer, and ``%derived`` is the derived | 
|  | pointer: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | ;; An array type. | 
|  | %class.Array = type { %class.Object, i32, [0 x %class.Object*] } | 
|  | ... | 
|  |  | 
|  | ;; Load the object pointer from a gcroot. | 
|  | %object = load %class.Array** %object_addr | 
|  |  | 
|  | ;; Compute the derived pointer. | 
|  | %derived = getelementptr %object, i32 0, i32 2, i32 %n | 
|  |  | 
|  | LLVM does not enforce this relationship between the object and derived pointer | 
|  | (although a particular :ref:`collector strategy <plugin>` might).  However, it | 
|  | would be an unusual collector that violated it. | 
|  |  | 
|  | The use of these intrinsics is naturally optional if the target GC does not | 
|  | require the corresponding barrier.  The GC strategy used with such a collector | 
|  | should replace the intrinsic calls with the corresponding ``load`` or | 
|  | ``store`` instruction if they are used. | 
|  |  | 
|  | One known deficiency with the current design is that the barrier intrinsics do | 
|  | not include the size or alignment of the underlying operation performed.  It is | 
|  | currently assumed that the operation is of pointer size and the alignment is | 
|  | assumed to be the target machine's default alignment. | 
|  |  | 
|  | Write barrier: ``llvm.gcwrite`` | 
|  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | void @llvm.gcwrite(i8* %value, i8* %object, i8** %derived) | 
|  |  | 
|  | For write barriers, LLVM provides the ``llvm.gcwrite`` intrinsic function.  It | 
|  | has exactly the same semantics as a non-volatile ``store`` to the derived | 
|  | pointer (the third argument).  The exact code generated is specified by the | 
|  | Function's selected :ref:`GC strategy <plugin>`. | 
|  |  | 
|  | Many important algorithms require write barriers, including generational and | 
|  | concurrent collectors.  Additionally, write barriers could be used to implement | 
|  | reference counting. | 
|  |  | 
|  | Read barrier: ``llvm.gcread`` | 
|  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | i8* @llvm.gcread(i8* %object, i8** %derived) | 
|  |  | 
|  | For read barriers, LLVM provides the ``llvm.gcread`` intrinsic function.  It has | 
|  | exactly the same semantics as a non-volatile ``load`` from the derived pointer | 
|  | (the second argument).  The exact code generated is specified by the Function's | 
|  | selected :ref:`GC strategy <plugin>`. | 
|  |  | 
|  | Read barriers are needed by fewer algorithms than write barriers, and may have a | 
|  | greater performance impact since pointer reads are more frequent than writes. | 
|  |  | 
|  | .. _plugin: | 
|  |  | 
|  | .. _builtin-gc-strategies: | 
|  |  | 
|  | Built In GC Strategies | 
|  | ====================== | 
|  |  | 
|  | LLVM includes built in support for several varieties of garbage collectors. | 
|  |  | 
|  | The Shadow Stack GC | 
|  | ---------------------- | 
|  |  | 
|  | To use this collector strategy, mark your functions with: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | F.setGC("shadow-stack"); | 
|  |  | 
|  | Unlike many GC algorithms which rely on a cooperative code generator to compile | 
|  | stack maps, this algorithm carefully maintains a linked list of stack roots | 
|  | [:ref:`Henderson2002 <henderson02>`].  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: | 
|  |  | 
|  | * High overhead per function call. | 
|  |  | 
|  | * Not thread-safe. | 
|  |  | 
|  | Still, it's an easy way to get started.  After your compiler and runtime are up | 
|  | and running, writing a :ref:`plugin <plugin>` will allow you to take advantage | 
|  | of :ref:`more advanced GC features <collector-algos>` of LLVM in order to | 
|  | improve performance. | 
|  |  | 
|  |  | 
|  | The shadow stack doesn't imply a memory allocation algorithm.  A semispace | 
|  | collector or building atop ``malloc`` are great places to start, and can be | 
|  | implemented with very little code. | 
|  |  | 
|  | When it comes time to collect, however, your runtime needs to traverse the stack | 
|  | roots, and for this it needs to integrate with the shadow stack.  Luckily, doing | 
|  | so is very simple. (This code is heavily commented to help you understand the | 
|  | data structure, but there are only 20 lines of meaningful code.) | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | /// 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 %metadata parameter to | 
|  | /// @llvm.gcroot is null. | 
|  | struct FrameMap { | 
|  | int32_t NumRoots;    //< Number of roots in stack frame. | 
|  | int32_t NumMeta;     //< Number of metadata entries.  May be < NumRoots. | 
|  | const void *Meta[0]; //< Metadata for each root. | 
|  | }; | 
|  |  | 
|  | /// A link in the dynamic shadow stack.  One of these is embedded in | 
|  | ///        the stack frame of each function on the call stack. | 
|  | struct StackEntry { | 
|  | StackEntry *Next;    //< Link to next stack entry (the caller's). | 
|  | const FrameMap *Map; //< Pointer to constant FrameMap. | 
|  | void *Roots[0];      //< Stack roots (in-place array). | 
|  | }; | 
|  |  | 
|  | /// The head of the singly-linked list of StackEntries.  Functions push | 
|  | ///        and pop onto this in their prologue and epilogue. | 
|  | /// | 
|  | /// Since there is only a global list, this technique is not threadsafe. | 
|  | StackEntry *llvm_gc_root_chain; | 
|  |  | 
|  | /// Calls Visitor(root, meta) for each GC root on the stack. | 
|  | ///        root and meta are exactly the values passed to | 
|  | ///        @llvm.gcroot. | 
|  | /// | 
|  | /// Visitor could be a function to recursively mark live objects.  Or it | 
|  | /// might copy them to another heap or generation. | 
|  | /// | 
|  | /// @param Visitor A function to invoke for every GC root on the stack. | 
|  | void visitGCRoots(void (*Visitor)(void **Root, const void *Meta)) { | 
|  | for (StackEntry *R = llvm_gc_root_chain; R; R = R->Next) { | 
|  | unsigned i = 0; | 
|  |  | 
|  | // For roots [0, NumMeta), the metadata pointer is in the FrameMap. | 
|  | for (unsigned e = R->Map->NumMeta; i != e; ++i) | 
|  | Visitor(&R->Roots[i], R->Map->Meta[i]); | 
|  |  | 
|  | // For roots [NumMeta, NumRoots), the metadata pointer is null. | 
|  | for (unsigned e = R->Map->NumRoots; i != e; ++i) | 
|  | Visitor(&R->Roots[i], NULL); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | The 'Erlang' and 'Ocaml' GCs | 
|  | ----------------------------- | 
|  |  | 
|  | LLVM ships with two example collectors which leverage the ``gcroot`` | 
|  | mechanisms.  To our knowledge, these are not actually used by any language | 
|  | runtime, but they do provide a reasonable starting point for someone interested | 
|  | in writing an ``gcroot`` compatible GC plugin.  In particular, these are the | 
|  | only in tree examples of how to produce a custom binary stack map format using | 
|  | a ``gcroot`` strategy. | 
|  |  | 
|  | As there names imply, the binary format produced is intended to model that | 
|  | used by the Erlang and OCaml compilers respectively. | 
|  |  | 
|  | .. _statepoint_example_gc: | 
|  |  | 
|  | The Statepoint Example GC | 
|  | ------------------------- | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | F.setGC("statepoint-example"); | 
|  |  | 
|  | This GC provides an example of how one might use the infrastructure provided | 
|  | by ``gc.statepoint``. This example GC is compatible with the | 
|  | :ref:`PlaceSafepoints` and :ref:`RewriteStatepointsForGC` utility passes | 
|  | which simplify ``gc.statepoint`` sequence insertion. If you need to build a | 
|  | custom GC strategy around the ``gc.statepoints`` mechanisms, it is recommended | 
|  | that you use this one as a starting point. | 
|  |  | 
|  | This GC strategy does not support read or write barriers.  As a result, these | 
|  | intrinsics are lowered to normal loads and stores. | 
|  |  | 
|  | The stack map format generated by this GC strategy can be found in the | 
|  | :ref:`stackmap-section` using a format documented :ref:`here | 
|  | <statepoint-stackmap-format>`. This format is intended to be the standard | 
|  | format supported by LLVM going forward. | 
|  |  | 
|  | The CoreCLR GC | 
|  | ------------------------- | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | F.setGC("coreclr"); | 
|  |  | 
|  | This GC leverages the ``gc.statepoint`` mechanism to support the | 
|  | `CoreCLR <https://github.com/dotnet/coreclr>`__ runtime. | 
|  |  | 
|  | Support for this GC strategy is a work in progress. This strategy will | 
|  | differ from | 
|  | :ref:`statepoint-example GC<statepoint_example_gc>` strategy in | 
|  | certain aspects like: | 
|  |  | 
|  | * Base-pointers of interior pointers are not explicitly | 
|  | tracked and reported. | 
|  |  | 
|  | * A different format is used for encoding stack maps. | 
|  |  | 
|  | * Safe-point polls are only needed before loop-back edges | 
|  | and before tail-calls (not needed at function-entry). | 
|  |  | 
|  | Custom GC Strategies | 
|  | ==================== | 
|  |  | 
|  | If none of the built in GC strategy descriptions met your needs above, you will | 
|  | need to define a custom GCStrategy and possibly, a custom LLVM pass to perform | 
|  | lowering.  Your best example of where to start defining a custom GCStrategy | 
|  | would be to look at one of the built in strategies. | 
|  |  | 
|  | You may be able to structure this additional code as a loadable plugin library. | 
|  | Loadable plugins are sufficient if all you need is to enable a different | 
|  | combination of built in functionality, but if you need to provide a custom | 
|  | lowering pass, you will need to build a patched version of LLVM.  If you think | 
|  | you need a patched build, please ask for advice on llvm-dev.  There may be an | 
|  | easy way we can extend the support to make it work for your use case without | 
|  | requiring a custom build. | 
|  |  | 
|  | Collector Requirements | 
|  | ---------------------- | 
|  |  | 
|  | You should be able to leverage any existing collector library that includes the following elements: | 
|  |  | 
|  | #. A memory allocator which exposes an allocation function your compiled | 
|  | code can call. | 
|  |  | 
|  | #. A binary format for the stack map.  A stack map describes the location | 
|  | of references at a safepoint and is used by precise collectors to identify | 
|  | references within a stack frame on the machine stack. Note that collectors | 
|  | which conservatively scan the stack don't require such a structure. | 
|  |  | 
|  | #. A stack crawler to discover functions on the call stack, and enumerate the | 
|  | references listed in the stack map for each call site. | 
|  |  | 
|  | #. A mechanism for identifying references in global locations (e.g. global | 
|  | variables). | 
|  |  | 
|  | #. If you collector requires them, an LLVM IR implementation of your collectors | 
|  | load and store barriers.  Note that since many collectors don't require | 
|  | barriers at all, LLVM defaults to lowering such barriers to normal loads | 
|  | and stores unless you arrange otherwise. | 
|  |  | 
|  |  | 
|  | Implementing a collector plugin | 
|  | ------------------------------- | 
|  |  | 
|  | User code specifies which GC code generation to use with the ``gc`` function | 
|  | attribute or, equivalently, with the ``setGC`` method of ``Function``. | 
|  |  | 
|  | 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 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 :ref:`stack map | 
|  | <stack-map>`. | 
|  |  | 
|  | To subclass ``llvm::GCStrategy`` and register it with the compiler: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | // lib/MyGC/MyGC.cpp - Example LLVM GC plugin | 
|  |  | 
|  | #include "llvm/CodeGen/GCStrategy.h" | 
|  | #include "llvm/CodeGen/GCMetadata.h" | 
|  | #include "llvm/Support/Compiler.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  | class LLVM_LIBRARY_VISIBILITY MyGC : public GCStrategy { | 
|  | public: | 
|  | MyGC() {} | 
|  | }; | 
|  |  | 
|  | GCRegistry::Add<MyGC> | 
|  | X("mygc", "My bespoke garbage collector."); | 
|  | } | 
|  |  | 
|  | This boilerplate collector 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 safe points are added to the code. | 
|  |  | 
|  | * The stack map is not compiled into the executable. | 
|  |  | 
|  | Using the LLVM makefiles, this code | 
|  | can be compiled as a plugin using a simple makefile: | 
|  |  | 
|  | .. code-block:: make | 
|  |  | 
|  | # lib/MyGC/Makefile | 
|  |  | 
|  | LEVEL := ../.. | 
|  | LIBRARYNAME = MyGC | 
|  | LOADABLE_MODULE = 1 | 
|  |  | 
|  | include $(LEVEL)/Makefile.common | 
|  |  | 
|  | Once the plugin is compiled, code using it may be compiled using ``llc | 
|  | -load=MyGC.so`` (though MyGC.so may have some other platform-specific | 
|  | extension): | 
|  |  | 
|  | :: | 
|  |  | 
|  | $ cat sample.ll | 
|  | define void @f() gc "mygc" { | 
|  | entry: | 
|  | ret void | 
|  | } | 
|  | $ llvm-as < sample.ll | llc -load=MyGC.so | 
|  |  | 
|  | It is also possible to statically link the collector plugin into tools, such as | 
|  | a language-specific compiler front-end. | 
|  |  | 
|  | .. _collector-algos: | 
|  |  | 
|  | Overview of available features | 
|  | ------------------------------ | 
|  |  | 
|  | ``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. | 
|  |  | 
|  | .. |v| unicode:: 0x2714 | 
|  | :trim: | 
|  |  | 
|  | .. |x| unicode:: 0x2718 | 
|  | :trim: | 
|  |  | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | Algorithm  | Done | Shadow | refcount | mark- | copying | incremental | threaded | concurrent | | 
|  | |            |      | stack  |          | sweep |         |             |          |            | | 
|  | +============+======+========+==========+=======+=========+=============+==========+============+ | 
|  | | stack map  | |v|  |        |          | |x|   | |x|     | |x|         | |x|      | |x|        | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | initialize | |v|  | |x|    | |x|      | |x|   | |x|     | |x|         | |x|      | |x|        | | 
|  | | roots      |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | derived    | NO   |        |          |       |         |             | **N**\*  | **N**\*    | | 
|  | | pointers   |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | **custom   | |v|  |        |          |       |         |             |          |            | | 
|  | | lowering** |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | *gcroot*   | |v|  | |x|    | |x|      |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | *gcwrite*  | |v|  |        | |x|      |       |         | |x|         |          | |x|        | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | *gcread*   | |v|  |        |          |       |         |             |          | |x|        | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | **safe     |      |        |          |       |         |             |          |            | | 
|  | | points**   |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | *in        | |v|  |        |          | |x|   | |x|     | |x|         | |x|      | |x|        | | 
|  | | calls*     |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | *before    | |v|  |        |          |       |         |             | |x|      | |x|        | | 
|  | | calls*     |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | *for       | NO   |        |          |       |         |             | **N**    | **N**      | | 
|  | | loops*     |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | *before    | |v|  |        |          |       |         |             | |x|      | |x|        | | 
|  | | escape*    |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | emit code  | NO   |        |          |       |         |             | **N**    | **N**      | | 
|  | | at safe    |      |        |          |       |         |             |          |            | | 
|  | | points     |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | **output** |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | *assembly* | |v|  |        |          | |x|   | |x|     | |x|         | |x|      | |x|        | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | *JIT*      | NO   |        |          | **?** | **?**   | **?**       | **?**    | **?**      | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | *obj*      | NO   |        |          | **?** | **?**   | **?**       | **?**    | **?**      | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | live       | NO   |        |          | **?** | **?**   | **?**       | **?**    | **?**      | | 
|  | | analysis   |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | register   | NO   |        |          | **?** | **?**   | **?**       | **?**    | **?**      | | 
|  | | map        |      |        |          |       |         |             |          |            | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | \* Derived pointers only pose a hasard to copying collections.                                | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  | | **?** denotes a feature which could be utilized if available.                                 | | 
|  | +------------+------+--------+----------+-------+---------+-------------+----------+------------+ | 
|  |  | 
|  | To be clear, the collection techniques above are defined as: | 
|  |  | 
|  | Shadow Stack | 
|  | 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. | 
|  |  | 
|  | Mark-Sweep | 
|  | When the heap is exhausted, the collector marks reachable objects starting | 
|  | from the roots, then deallocates unreachable objects in a sweep phase. | 
|  |  | 
|  | Copying | 
|  | As reachability analysis proceeds, the collector copies objects from one heap | 
|  | area to another, compacting them in the process.  Copying collectors enable | 
|  | highly efficient "bump pointer" allocation and can improve locality of | 
|  | reference. | 
|  |  | 
|  | Incremental | 
|  | (Including generational collectors.) Incremental collectors generally have all | 
|  | the properties of a copying collector (regardless of whether the mature heap | 
|  | is compacting), but bring the added complexity of requiring write barriers. | 
|  |  | 
|  | Threaded | 
|  | Denotes a multithreaded mutator; the collector must still stop the mutator | 
|  | ("stop the world") before beginning reachability analysis.  Stopping a | 
|  | multithreaded mutator is a complicated problem.  It generally requires highly | 
|  | platform-specific code in the runtime, and the production of carefully | 
|  | designed machine code at safe points. | 
|  |  | 
|  | Concurrent | 
|  | In this technique, the mutator and the collector run concurrently, with the | 
|  | goal of eliminating pause times.  In a *cooperative* collector, the mutator | 
|  | further aids with collection should a pause occur, allowing collection to take | 
|  | advantage of multiprocessor hosts.  The "stop the world" problem of threaded | 
|  | collectors is generally still present to a limited extent.  Sophisticated | 
|  | marking algorithms are necessary.  Read barriers may be necessary. | 
|  |  | 
|  | As the matrix indicates, LLVM's garbage collection infrastructure is already | 
|  | suitable for a wide variety of collectors, but does not currently extend to | 
|  | multithreaded programs.  This will be added in the future as there is | 
|  | interest. | 
|  |  | 
|  | .. _stack-map: | 
|  |  | 
|  | Computing stack maps | 
|  | -------------------- | 
|  |  | 
|  | 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 :ref:`GCMetadataPrinter <assembly>`: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | for (iterator I = begin(), E = end(); I != E; ++I) { | 
|  | GCFunctionInfo *FI = *I; | 
|  | unsigned FrameSize = FI->getFrameSize(); | 
|  | size_t RootCount = FI->roots_size(); | 
|  |  | 
|  | for (GCFunctionInfo::roots_iterator RI = FI->roots_begin(), | 
|  | RE = FI->roots_end(); | 
|  | RI != RE; ++RI) { | 
|  | int RootNum = RI->Num; | 
|  | int RootStackOffset = RI->StackOffset; | 
|  | Constant *RootMetadata = RI->Metadata; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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. | 
|  |  | 
|  | .. _init-roots: | 
|  |  | 
|  | Initializing roots to null: ``InitRoots`` | 
|  | ----------------------------------------- | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | MyGC::MyGC() { | 
|  | InitRoots = true; | 
|  | } | 
|  |  | 
|  | When set, LLVM will automatically initialize each root to ``null`` upon entry to | 
|  | the function.  This prevents the GC's sweep phase from visiting uninitialized | 
|  | pointers, which will almost certainly cause it to crash.  This initialization | 
|  | occurs before custom lowering, so the two may be used together. | 
|  |  | 
|  | Since LLVM does not yet compute liveness information, there is no means of | 
|  | distinguishing an uninitialized stack root from an initialized one.  Therefore, | 
|  | this feature should be used by all GC plugins.  It is enabled by default. | 
|  |  | 
|  | Custom lowering of intrinsics: ``CustomRoots``, ``CustomReadBarriers``, and ``CustomWriteBarriers`` | 
|  | --------------------------------------------------------------------------------------------------- | 
|  |  | 
|  | For GCs which use barriers or unusual treatment of stack roots, these | 
|  | flags allow the collector to perform arbitrary transformations of the | 
|  | LLVM IR: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | class MyGC : public GCStrategy { | 
|  | public: | 
|  | MyGC() { | 
|  | CustomRoots = true; | 
|  | CustomReadBarriers = true; | 
|  | CustomWriteBarriers = true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | If any of these flags are set, LLVM suppresses its default lowering for | 
|  | the corresponding intrinsics.  Instead, you must provide a custom Pass | 
|  | which lowers the intrinsics as desired.  If you have opted in to custom | 
|  | lowering of a particular intrinsic your pass **must** eliminate all | 
|  | instances of the corresponding intrinsic in functions which opt in to | 
|  | your GC.  The best example of such a pass is the ShadowStackGC and it's | 
|  | ShadowStackGCLowering pass. | 
|  |  | 
|  | There is currently no way to register such a custom lowering pass | 
|  | without building a custom copy of LLVM. | 
|  |  | 
|  | .. _safe-points: | 
|  |  | 
|  | Generating safe points: ``NeededSafePoints`` | 
|  | -------------------------------------------- | 
|  |  | 
|  | LLVM can compute four kinds of safe points: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | namespace GC { | 
|  | /// PointKind - The type of a collector-safe point. | 
|  | /// | 
|  | enum PointKind { | 
|  | Loop,    //< Instr is a loop (backwards branch). | 
|  | Return,  //< Instr is a return instruction. | 
|  | PreCall, //< Instr is a call instruction. | 
|  | PostCall //< Instr is the return address of a call. | 
|  | }; | 
|  | } | 
|  |  | 
|  | A collector can request any combination of the four by setting the | 
|  | ``NeededSafePoints`` mask: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | MyGC::MyGC()  { | 
|  | NeededSafePoints = 1 << GC::Loop | 
|  | | 1 << GC::Return | 
|  | | 1 << GC::PreCall | 
|  | | 1 << GC::PostCall; | 
|  | } | 
|  |  | 
|  | It can then use the following routines to access safe points. | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | for (iterator I = begin(), E = end(); I != E; ++I) { | 
|  | GCFunctionInfo *MD = *I; | 
|  | size_t PointCount = MD->size(); | 
|  |  | 
|  | for (GCFunctionInfo::iterator PI = MD->begin(), | 
|  | PE = MD->end(); PI != PE; ++PI) { | 
|  | GC::PointKind PointKind = PI->Kind; | 
|  | unsigned PointNum = PI->Num; | 
|  | } | 
|  | } | 
|  |  | 
|  | Almost every collector requires ``PostCall`` safe points, since these correspond | 
|  | to the moments when the function is suspended during a call to a subroutine. | 
|  |  | 
|  | Threaded programs generally require ``Loop`` safe points to guarantee that the | 
|  | application will reach a safe point within a bounded amount of time, even if it | 
|  | is executing a long-running loop which contains no function calls. | 
|  |  | 
|  | Threaded collectors may also require ``Return`` and ``PreCall`` safe points to | 
|  | implement "stop the world" techniques using self-modifying code, where it is | 
|  | important that the program not exit the function without reaching a safe point | 
|  | (because only the topmost function has been patched). | 
|  |  | 
|  | .. _assembly: | 
|  |  | 
|  | Emitting assembly code: ``GCMetadataPrinter`` | 
|  | --------------------------------------------- | 
|  |  | 
|  | 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 abstract | 
|  | base class and registry is provided for printing assembly code, the | 
|  | ``GCMetadaPrinter`` and ``GCMetadataPrinterRegistry``.  The AsmWriter will look | 
|  | for such a subclass if the ``GCStrategy`` sets ``UsesMetadata``: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | MyGC::MyGC() { | 
|  | 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. | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | // lib/MyGC/MyGCPrinter.cpp - Example LLVM GC printer | 
|  |  | 
|  | #include "llvm/CodeGen/GCMetadataPrinter.h" | 
|  | #include "llvm/Support/Compiler.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  | class LLVM_LIBRARY_VISIBILITY MyGCPrinter : public GCMetadataPrinter { | 
|  | public: | 
|  | virtual void beginAssembly(AsmPrinter &AP); | 
|  |  | 
|  | virtual void finishAssembly(AsmPrinter &AP); | 
|  | }; | 
|  |  | 
|  | GCMetadataPrinterRegistry::Add<MyGCPrinter> | 
|  | X("mygc", "My bespoke garbage collector."); | 
|  | } | 
|  |  | 
|  | The collector should use ``AsmPrinter`` to print portable assembly code.  The | 
|  | collector itself contains the stack map for the entire module, and may access | 
|  | the ``GCFunctionInfo`` using its own ``begin()`` and ``end()`` methods.  Here's | 
|  | a realistic example: | 
|  |  | 
|  | .. code-block:: c++ | 
|  |  | 
|  | #include "llvm/CodeGen/AsmPrinter.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/IR/DataLayout.h" | 
|  | #include "llvm/Target/TargetAsmInfo.h" | 
|  | #include "llvm/Target/TargetMachine.h" | 
|  |  | 
|  | void MyGCPrinter::beginAssembly(AsmPrinter &AP) { | 
|  | // Nothing to do. | 
|  | } | 
|  |  | 
|  | void MyGCPrinter::finishAssembly(AsmPrinter &AP) { | 
|  | MCStreamer &OS = AP.OutStreamer; | 
|  | unsigned IntPtrSize = AP.getPointerSize(); | 
|  |  | 
|  | // Put this in the data section. | 
|  | OS.SwitchSection(AP.getObjFileLowering().getDataSection()); | 
|  |  | 
|  | // For each function... | 
|  | for (iterator FI = begin(), FE = end(); FI != FE; ++FI) { | 
|  | GCFunctionInfo &MD = **FI; | 
|  |  | 
|  | // A compact GC layout. Emit this data structure: | 
|  | // | 
|  | // struct { | 
|  | //   int32_t PointCount; | 
|  | //   void *SafePointAddress[PointCount]; | 
|  | //   int32_t StackFrameSize; // in words | 
|  | //   int32_t StackArity; | 
|  | //   int32_t LiveCount; | 
|  | //   int32_t LiveOffsets[LiveCount]; | 
|  | // } __gcmap_<FUNCTIONNAME>; | 
|  |  | 
|  | // Align to address width. | 
|  | AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); | 
|  |  | 
|  | // Emit PointCount. | 
|  | OS.AddComment("safe point count"); | 
|  | AP.emitInt32(MD.size()); | 
|  |  | 
|  | // And each safe point... | 
|  | for (GCFunctionInfo::iterator PI = MD.begin(), | 
|  | PE = MD.end(); PI != PE; ++PI) { | 
|  | // Emit the address of the safe point. | 
|  | OS.AddComment("safe point address"); | 
|  | MCSymbol *Label = PI->Label; | 
|  | AP.EmitLabelPlusOffset(Label/*Hi*/, 0/*Offset*/, 4/*Size*/); | 
|  | } | 
|  |  | 
|  | // Stack information never change in safe points! Only print info from the | 
|  | // first call-site. | 
|  | GCFunctionInfo::iterator PI = MD.begin(); | 
|  |  | 
|  | // Emit the stack frame size. | 
|  | OS.AddComment("stack frame size (in words)"); | 
|  | AP.emitInt32(MD.getFrameSize() / IntPtrSize); | 
|  |  | 
|  | // Emit stack arity, i.e. the number of stacked arguments. | 
|  | unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6; | 
|  | unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs ? | 
|  | MD.getFunction().arg_size() - RegisteredArgs : 0; | 
|  | OS.AddComment("stack arity"); | 
|  | AP.emitInt32(StackArity); | 
|  |  | 
|  | // Emit the number of live roots in the function. | 
|  | OS.AddComment("live root count"); | 
|  | AP.emitInt32(MD.live_size(PI)); | 
|  |  | 
|  | // And for each live root... | 
|  | for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI), | 
|  | LE = MD.live_end(PI); | 
|  | LI != LE; ++LI) { | 
|  | // Emit live root's offset within the stack frame. | 
|  | OS.AddComment("stack index (offset / wordsize)"); | 
|  | AP.emitInt32(LI->StackOffset); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | References | 
|  | ========== | 
|  |  | 
|  | .. _appel89: | 
|  |  | 
|  | [Appel89] Runtime Tags Aren't Necessary. Andrew W. Appel. Lisp and Symbolic | 
|  | Computation 19(7):703-705, July 1989. | 
|  |  | 
|  | .. _goldberg91: | 
|  |  | 
|  | [Goldberg91] Tag-free garbage collection for strongly typed programming | 
|  | languages. Benjamin Goldberg. ACM SIGPLAN PLDI'91. | 
|  |  | 
|  | .. _tolmach94: | 
|  |  | 
|  | [Tolmach94] Tag-free garbage collection using explicit type parameters. Andrew | 
|  | Tolmach. Proceedings of the 1994 ACM conference on LISP and functional | 
|  | programming. | 
|  |  | 
|  | .. _henderson02: | 
|  |  | 
|  | [Henderson2002] `Accurate Garbage Collection in an Uncooperative Environment | 
|  | <http://citeseer.ist.psu.edu/henderson02accurate.html>`__ |