mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-25 23:10:47 -08:00
1201 lines
No EOL
118 KiB
HTML
1201 lines
No EOL
118 KiB
HTML
|
|
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
|
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
|
|
<title>3. Garbage collecting a language with the Memory Pool System — Memory Pool System 1.111.0 documentation</title>
|
|
|
|
<link rel="stylesheet" href="../_static/mps.css" type="text/css" />
|
|
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
|
|
|
<script type="text/javascript">
|
|
var DOCUMENTATION_OPTIONS = {
|
|
URL_ROOT: '../',
|
|
VERSION: '1.111.0',
|
|
COLLAPSE_INDEX: false,
|
|
FILE_SUFFIX: '.html',
|
|
HAS_SOURCE: true
|
|
};
|
|
</script>
|
|
<script type="text/javascript" src="../_static/jquery.js"></script>
|
|
<script type="text/javascript" src="../_static/underscore.js"></script>
|
|
<script type="text/javascript" src="../_static/doctools.js"></script>
|
|
<link rel="copyright" title="Copyright" href="../copyright.html" />
|
|
<link rel="top" title="Memory Pool System 1.111.0 documentation" href="../index.html" />
|
|
<link rel="up" title="Guide" href="index.html" />
|
|
<link rel="next" title="4. Debugging with the Memory Pool System" href="debug.html" />
|
|
<link rel="prev" title="2. Building the Memory Pool System" href="build.html" />
|
|
</head>
|
|
<body>
|
|
<div class="related">
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li class="right" style="margin-right: 10px">
|
|
<a href="../genindex.html" title="General Index"
|
|
accesskey="I">index</a></li>
|
|
<li class="right" >
|
|
<a href="debug.html" title="4. Debugging with the Memory Pool System"
|
|
accesskey="N">next</a> |</li>
|
|
<li class="right" >
|
|
<a href="build.html" title="2. Building the Memory Pool System"
|
|
accesskey="P">previous</a> |</li>
|
|
<li><a href="../index.html">Memory Pool System 1.111.0 documentation</a> »</li>
|
|
<li><a href="index.html" accesskey="U">Guide</a> »</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="document">
|
|
<div class="documentwrapper">
|
|
<div class="bodywrapper">
|
|
<div class="body">
|
|
|
|
<div class="section" id="garbage-collecting-a-language-with-the-memory-pool-system">
|
|
<span id="guide-lang"></span><span id="index-0"></span><h1>3. Garbage collecting a language with the Memory Pool System<a class="headerlink" href="#garbage-collecting-a-language-with-the-memory-pool-system" title="Permalink to this headline">¶</a></h1>
|
|
<p>Have you written the lexer, parser, code generator and the runtime
|
|
system for your programming language, and come to the realization that
|
|
you are going to need a memory manager too? If so, you’ve come to the
|
|
right place.</p>
|
|
<p>In this guide, I’ll explain how to use the MPS to add incremental,
|
|
moving, generational garbage collection to the runtime system for a
|
|
programming language.</p>
|
|
<p>I’m assuming that you are familiar with the overall architecture of
|
|
the MPS (see the chapter <a class="reference internal" href="overview.html#guide-overview"><em>Overview of the Memory Pool System</em></a>) and that you’ve
|
|
downloaded and built the MPS (see the chapter <a class="reference internal" href="build.html#guide-build"><em>Building the Memory Pool System</em></a>).</p>
|
|
<div class="section" id="the-scheme-interpreter">
|
|
<span id="index-1"></span><h2>3.1. The Scheme interpreter<a class="headerlink" href="#the-scheme-interpreter" title="Permalink to this headline">¶</a></h2>
|
|
<p>As a running example throughout this guide, I’ll be using a small
|
|
interpreter for a subset of the <a class="reference internal" href="../mmref/lang.html#term-scheme"><em class="xref std std-term">Scheme</em></a> programming language.
|
|
I’ll be quoting the relevant sections of code as needed, but you may
|
|
find it helpful to experiment with this interpreter yourself, in either
|
|
of its versions:</p>
|
|
<p><a class="reference download internal" href="../_downloads/scheme-malloc.c"><tt class="xref download docutils literal"><span class="pre">scheme-malloc.c</span></tt></a></p>
|
|
<blockquote>
|
|
<div>The toy Scheme interpreter before integration with the MPS, using
|
|
<a class="reference internal" href="../glossary/m.html#term-malloc"><em class="xref std std-term">malloc</em></a> and <a class="reference internal" href="../glossary/f.html#term-free-2"><em class="xref std std-term">free<sup>(2)</sup></em></a> for memory management.</div></blockquote>
|
|
<p><a class="reference download internal" href="../_downloads/scheme.c"><tt class="xref download docutils literal"><span class="pre">scheme.c</span></tt></a></p>
|
|
<blockquote>
|
|
<div>The toy Scheme interpreter after integration with the MPS.</div></blockquote>
|
|
<p>This simple interpreter allocates two kinds of objects on the
|
|
<a class="reference internal" href="../glossary/h.html#term-heap"><em class="xref std std-term">heap</em></a>:</p>
|
|
<ol class="arabic simple">
|
|
<li>All Scheme objects (there are no <a class="reference internal" href="../glossary/u.html#term-unboxed"><em class="xref std std-term">unboxed</em></a> objects).</li>
|
|
<li>The global symbol table: a hash table consisting of a vector of
|
|
pointers to strings.</li>
|
|
</ol>
|
|
<p>A Scheme object (whose type is not necessarily known) is represented by
|
|
an <tt class="docutils literal"><span class="pre">obj_t</span></tt>, which is a pointer to a union of every type in the
|
|
language:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">typedef</span> <span class="k">union</span> <span class="n">obj_u</span> <span class="o">*</span><span class="n">obj_t</span><span class="p">;</span>
|
|
<span class="k">typedef</span> <span class="k">union</span> <span class="n">obj_u</span> <span class="p">{</span>
|
|
<span class="n">type_s</span> <span class="n">type</span><span class="p">;</span>
|
|
<span class="n">pair_s</span> <span class="n">pair</span><span class="p">;</span>
|
|
<span class="n">symbol_s</span> <span class="n">symbol</span><span class="p">;</span>
|
|
<span class="n">integer_s</span> <span class="n">integer</span><span class="p">;</span>
|
|
<span class="n">special_s</span> <span class="n">special</span><span class="p">;</span>
|
|
<span class="n">operator_s</span> <span class="n">operator</span><span class="p">;</span>
|
|
<span class="n">string_s</span> <span class="n">string</span><span class="p">;</span>
|
|
<span class="n">port_s</span> <span class="n">port</span><span class="p">;</span>
|
|
<span class="n">character_s</span> <span class="n">character</span><span class="p">;</span>
|
|
<span class="n">vector_s</span> <span class="n">vector</span><span class="p">;</span>
|
|
<span class="n">table_s</span> <span class="n">table</span><span class="p">;</span>
|
|
<span class="n">buckets_s</span> <span class="n">buckets</span><span class="p">;</span>
|
|
<span class="p">}</span> <span class="n">obj_s</span><span class="p">;</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Each of these types is a structure whose first word is a number
|
|
specifying the type of the object (<tt class="docutils literal"><span class="pre">TYPE_PAIR</span></tt> for pairs,
|
|
<tt class="docutils literal"><span class="pre">TYPE_SYMBOL</span></tt> for symbols, and so on). For example, pairs are
|
|
represented by a pointer to the structure <tt class="docutils literal"><span class="pre">pair_s</span></tt> defined as
|
|
follows:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">typedef</span> <span class="k">struct</span> <span class="n">pair_s</span> <span class="p">{</span>
|
|
<span class="n">type_t</span> <span class="n">type</span><span class="p">;</span> <span class="cm">/* TYPE_PAIR */</span>
|
|
<span class="n">obj_t</span> <span class="n">car</span><span class="p">,</span> <span class="n">cdr</span><span class="p">;</span> <span class="cm">/* first and second projections */</span>
|
|
<span class="p">}</span> <span class="n">pair_s</span><span class="p">;</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Because the first word of every object is its type, functions can
|
|
operate on objects generically, testing <tt class="docutils literal"><span class="pre">TYPE(obj)</span></tt> as necessary
|
|
(which is a macro for <tt class="docutils literal"><span class="pre">obj->type.type</span></tt>). For example, the
|
|
<tt class="docutils literal"><span class="pre">print()</span></tt> function is implemented like this:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">void</span> <span class="nf">print</span><span class="p">(</span><span class="n">obj_t</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">depth</span><span class="p">,</span> <span class="kt">FILE</span> <span class="o">*</span><span class="n">stream</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="k">switch</span> <span class="p">(</span><span class="n">TYPE</span><span class="p">(</span><span class="n">obj</span><span class="p">))</span> <span class="p">{</span>
|
|
<span class="k">case</span> <span class="n">TYPE_INTEGER</span>:
|
|
<span class="n">fprintf</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="s">"%ld"</span><span class="p">,</span> <span class="n">obj</span><span class="o">-></span><span class="n">integer</span><span class="p">.</span><span class="n">integer</span><span class="p">);</span>
|
|
<span class="k">break</span><span class="p">;</span>
|
|
|
|
<span class="k">case</span> <span class="n">TYPE_SYMBOL</span>:
|
|
<span class="n">fputs</span><span class="p">(</span><span class="n">obj</span><span class="o">-></span><span class="n">symbol</span><span class="p">.</span><span class="n">string</span><span class="p">,</span> <span class="n">stream</span><span class="p">);</span>
|
|
<span class="k">break</span><span class="p">;</span>
|
|
|
|
<span class="cm">/* ... and so on for the other types ... */</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Each constructor allocates memory for the new object by calling
|
|
<tt class="docutils literal"><span class="pre">malloc</span></tt>. For example, <tt class="docutils literal"><span class="pre">make_pair</span></tt> is the constructor for pairs:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">obj_t</span> <span class="nf">make_pair</span><span class="p">(</span><span class="n">obj_t</span> <span class="n">car</span><span class="p">,</span> <span class="n">obj_t</span> <span class="n">cdr</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">obj_t</span> <span class="n">obj</span> <span class="o">=</span> <span class="p">(</span><span class="n">obj_t</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">pair_s</span><span class="p">));</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">obj</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"out of memory"</span><span class="p">);</span>
|
|
<span class="n">obj</span><span class="o">-></span><span class="n">pair</span><span class="p">.</span><span class="n">type</span> <span class="o">=</span> <span class="n">TYPE_PAIR</span><span class="p">;</span>
|
|
<span class="n">CAR</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">car</span><span class="p">;</span>
|
|
<span class="n">CDR</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">cdr</span><span class="p">;</span>
|
|
<span class="k">return</span> <span class="n">obj</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Objects are never freed, because it is necessary to prove that they
|
|
are <a class="reference internal" href="../glossary/d.html#term-dead"><em class="xref std std-term">dead</em></a> before their memory can be <a class="reference internal" href="../glossary/r.html#term-reclaim"><em class="xref std std-term">reclaimed</em></a>. To
|
|
prove that they are dead, we need a <a class="reference internal" href="../glossary/t.html#term-trace"><em class="xref std std-term">tracing</em></a>
|
|
<a class="reference internal" href="../glossary/g.html#term-garbage-collector"><em class="xref std std-term">garbage collector</em></a>, which the MPS will provide.</p>
|
|
</div>
|
|
<div class="section" id="choosing-an-arena-class">
|
|
<span id="index-2"></span><h2>3.2. Choosing an arena class<a class="headerlink" href="#choosing-an-arena-class" title="Permalink to this headline">¶</a></h2>
|
|
<p>You’ll recall from the <a class="reference internal" href="overview.html#guide-overview"><em>Overview of the Memory Pool System</em></a> that the functionality of
|
|
the MPS is divided between the <a class="reference internal" href="../glossary/a.html#term-arena"><em class="xref std std-term">arenas</em></a>, which request memory
|
|
from (and return it to) the operating system, and <a class="reference internal" href="../glossary/p.html#term-pool"><em class="xref std std-term">pools</em></a>, which
|
|
allocate blocks of memory for your program.</p>
|
|
<p>There are two main classes of arena: the <a class="reference internal" href="../glossary/c.html#term-client-arena"><em class="xref std std-term">client arena</em></a>,
|
|
<a class="reference internal" href="../topic/arena.html#mps_arena_class_cl" title="mps_arena_class_cl"><tt class="xref c c-func docutils literal"><span class="pre">mps_arena_class_cl()</span></tt></a>, which gets its memory from your program,
|
|
and the <a class="reference internal" href="../glossary/v.html#term-virtual-memory-arena"><em class="xref std std-term">virtual memory arena</em></a>, <a class="reference internal" href="../topic/arena.html#mps_arena_class_vm" title="mps_arena_class_vm"><tt class="xref c c-func docutils literal"><span class="pre">mps_arena_class_vm()</span></tt></a>,
|
|
which gets its memory from the operating system’s <a class="reference internal" href="../glossary/v.html#term-virtual-memory"><em class="xref std std-term">virtual
|
|
memory</em></a> interface.</p>
|
|
<p>The client arena is intended for use on embedded systems where there
|
|
is no virtual memory, and has a couple of disadvantages (you have to
|
|
decide how much memory you are going to use; and the MPS can’t return
|
|
memory to the operating system for use by other processes) so for
|
|
general-purpose programs you’ll want to use the virtual memory arena.</p>
|
|
<p>You’ll need a couple of headers: <tt class="docutils literal"><span class="pre">mps.h</span></tt> for the MPS interface, and
|
|
<tt class="docutils literal"><span class="pre">mpsavm.h</span></tt> for the virtual memory arena class:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="cp">#include "mps.h"</span>
|
|
<span class="cp">#include "mpsavm.h"</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>There’s only one arena, and many MPS functions take an arena as an
|
|
argument, so it makes sense for the arena to be a global variable
|
|
rather than having to pass it around everywhere:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">mps_arena_t</span> <span class="n">arena</span><span class="p">;</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Create an arena by calling <a class="reference internal" href="../topic/arena.html#mps_arena_create_k" title="mps_arena_create_k"><tt class="xref c c-func docutils literal"><span class="pre">mps_arena_create_k()</span></tt></a>. This function
|
|
takes a <a class="reference internal" href="../glossary/k.html#term-keyword-argument"><em class="xref std std-term">keyword argument</em></a> when creating a virtual memory arena:
|
|
the size of virtual <a class="reference internal" href="../glossary/a.html#term-address-space"><em class="xref std std-term">address space</em></a> (<em>not</em> <a class="reference internal" href="../glossary/r.html#term-ram"><em class="xref std std-term">RAM</em></a>), in
|
|
bytes, that the arena will reserve initially. The MPS will ask for
|
|
more address space if it runs out, but the more times it has to extend
|
|
its address space, the less efficient garbage collection will become.
|
|
The MPS works best if you reserve an address space that is several
|
|
times larger than your peak memory usage.</p>
|
|
<div class="admonition-note admonition">
|
|
<p class="first admonition-title">Note</p>
|
|
<p class="last">Functions in the MPS interface take <a class="reference internal" href="../glossary/k.html#term-keyword-argument"><em class="xref std std-term">keyword arguments</em></a> for
|
|
arguments that are optional, or are only required in some
|
|
circumstances. These argument are passed in the form of an array
|
|
of structures of type <a class="reference internal" href="../topic/keyword.html#mps_arg_s" title="mps_arg_s"><tt class="xref c c-type docutils literal"><span class="pre">mps_arg_s</span></tt></a>. See
|
|
<a class="reference internal" href="../topic/keyword.html#topic-keyword"><em>Keyword arguments</em></a> for the full details.</p>
|
|
</div>
|
|
<p>Let’s reserve 32 megabytes:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="n">mps_res_t</span> <span class="n">res</span><span class="p">;</span>
|
|
<span class="n">MPS_ARGS_BEGIN</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="n">MPS_ARGS_ADD</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="n">MPS_KEY_ARENA_SIZE</span><span class="p">,</span> <span class="mi">32</span> <span class="o">*</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024</span><span class="p">);</span>
|
|
<span class="n">MPS_ARGS_DONE</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_arena_create_k</span><span class="p">(</span><span class="o">&</span><span class="n">arena</span><span class="p">,</span> <span class="n">mps_arena_class_vm</span><span class="p">(),</span> <span class="n">args</span><span class="p">);</span>
|
|
<span class="p">}</span> <span class="n">MPS_ARGS_END</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't create arena"</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
<p><a class="reference internal" href="../topic/arena.html#mps_arena_create_k" title="mps_arena_create_k"><tt class="xref c c-func docutils literal"><span class="pre">mps_arena_create_k()</span></tt></a> is typical of functions in the MPS
|
|
interface in that it stores its result in a location pointed to by an
|
|
<a class="reference internal" href="../glossary/o.html#term-out-parameter"><em class="xref std std-term">out parameter</em></a> (here, <tt class="docutils literal"><span class="pre">&arena</span></tt>) and returns a <a class="reference internal" href="../glossary/r.html#term-result-code"><em class="xref std std-term">result
|
|
code</em></a>, which is <a class="reference internal" href="../topic/error.html#MPS_RES_OK" title="MPS_RES_OK"><tt class="xref c c-macro docutils literal"><span class="pre">MPS_RES_OK</span></tt></a> if the function succeeded, or
|
|
some other value if it failed.</p>
|
|
<div class="admonition-note admonition">
|
|
<p class="first admonition-title">Note</p>
|
|
<p>The MPS is designed to co-operate with other memory managers, so
|
|
when integrating your language with the MPS you need not feel
|
|
obliged to move all your memory management to the MPS: you can
|
|
continue to use <tt class="docutils literal"><span class="pre">malloc</span></tt> and <tt class="docutils literal"><span class="pre">free</span></tt> to manage some of your
|
|
memory, for example, while using the MPS for the rest.</p>
|
|
<p class="last">The toy Scheme interpreter illustrates this by continuing to use
|
|
<tt class="docutils literal"><span class="pre">malloc</span></tt> and <tt class="docutils literal"><span class="pre">free</span></tt> to manage its global symbol table.</p>
|
|
</div>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topics</p>
|
|
<p class="last"><a class="reference internal" href="../topic/arena.html#topic-arena"><em>Arenas</em></a>, <a class="reference internal" href="../topic/error.html#topic-error"><em>Error handing</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="choosing-a-pool-class">
|
|
<span id="index-3"></span><h2>3.3. Choosing a pool class<a class="headerlink" href="#choosing-a-pool-class" title="Permalink to this headline">¶</a></h2>
|
|
<p>Pool classes come with a policy for how their memory will be managed:
|
|
some pool classes use <a class="reference internal" href="../glossary/a.html#term-automatic-memory-management"><em class="xref std std-term">automatic memory management</em></a> and others
|
|
use <a class="reference internal" href="../glossary/m.html#term-manual-memory-management"><em class="xref std std-term">manual</em></a>; some use <a class="reference internal" href="../glossary/m.html#term-moving-garbage-collector"><em class="xref std std-term">moving
|
|
collection</em></a> and others <a class="reference internal" href="../glossary/n.html#term-non-moving-garbage-collector"><em class="xref std std-term">non-moving</em></a>.</p>
|
|
<p>The section <a class="reference internal" href="../pool/intro.html#pool-choose"><em>Choosing a pool class</em></a> in the <a class="reference internal" href="../pool/index.html#pool"><em>Pool reference</em></a> contains a procedure
|
|
for choosing a pool class. In the case of the toy Scheme interpreter,
|
|
the answers to the questions are (1) yes, the MPS needs to
|
|
automatically reclaim unreachable blocks; (2) yes, it’s acceptable for
|
|
the MPS to move blocks in memory and protect them with <a class="reference internal" href="../glossary/b.html#term-barrier-1"><em class="xref std std-term">barriers<sup>(1)</sup></em></a>; and (3) the Scheme objects will contain <a class="reference internal" href="../glossary/e.html#term-exact-reference"><em class="xref std std-term">exact references</em></a>
|
|
to other Scheme objects in the same pool.</p>
|
|
<p>The recommended class is <a class="reference internal" href="../pool/amc.html#pool-amc"><em>AMC (Automatic Mostly-Copying)</em></a>. This pool class uses
|
|
automatic memory management, moving garbage collection,
|
|
<a class="reference internal" href="../glossary/a.html#term-allocation-point"><em class="xref std std-term">allocation points</em></a> and <a class="reference internal" href="../glossary/f.html#term-formatted-object"><em class="xref std std-term">formatted objects</em></a>, so it will
|
|
provide an introduction to these features of the MPS.</p>
|
|
<div class="admonition-note admonition">
|
|
<p class="first admonition-title">Note</p>
|
|
<p class="last">The MPS is designed for pools of different classes to co-exist in
|
|
the same arena, so that objects requiring different memory
|
|
management policies can be segregated into pools of suitable
|
|
classes.</p>
|
|
</div>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topic</p>
|
|
<p class="last"><a class="reference internal" href="../topic/pool.html#topic-pool"><em>Pools</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="describing-your-objects">
|
|
<span id="index-4"></span><h2>3.4. Describing your objects<a class="headerlink" href="#describing-your-objects" title="Permalink to this headline">¶</a></h2>
|
|
<p>In order for the MPS to be able to automatically manage your objects,
|
|
you need to tell it how to perform various operations on an object
|
|
(<a class="reference internal" href="../glossary/s.html#term-scan"><em class="xref std std-term">scan</em></a> it for <a class="reference internal" href="../glossary/r.html#term-reference"><em class="xref std std-term">references</em></a>; replace it with a
|
|
<a class="reference internal" href="../glossary/f.html#term-forwarding-object"><em class="xref std std-term">forwarding</em></a> or <a class="reference internal" href="../glossary/p.html#term-padding-object"><em class="xref std std-term">padding object</em></a>, and
|
|
so on). You do this by creating an <a class="reference internal" href="../glossary/o.html#term-object-format"><em class="xref std std-term">object format</em></a>. Here’s the
|
|
code for creating the object format for the toy Scheme interpreter:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">struct</span> <span class="n">mps_fmt_A_s</span> <span class="n">obj_fmt_s</span> <span class="o">=</span> <span class="p">{</span>
|
|
<span class="n">ALIGNMENT</span><span class="p">,</span>
|
|
<span class="n">obj_scan</span><span class="p">,</span>
|
|
<span class="n">obj_skip</span><span class="p">,</span>
|
|
<span class="nb">NULL</span><span class="p">,</span>
|
|
<span class="n">obj_fwd</span><span class="p">,</span>
|
|
<span class="n">obj_isfwd</span><span class="p">,</span>
|
|
<span class="n">obj_pad</span><span class="p">,</span>
|
|
<span class="p">};</span>
|
|
|
|
<span class="n">mps_fmt_t</span> <span class="n">obj_fmt</span><span class="p">;</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_fmt_create_A</span><span class="p">(</span><span class="o">&</span><span class="n">obj_fmt</span><span class="p">,</span> <span class="n">arena</span><span class="p">,</span> <span class="o">&</span><span class="n">obj_fmt_s</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't create obj format"</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>The structure <a class="reference internal" href="../topic/format.html#mps_fmt_A_s" title="mps_fmt_A_s"><tt class="xref c c-type docutils literal"><span class="pre">mps_fmt_A_s</span></tt></a> is the simplest of several object
|
|
format variants that are appropriate for moving pools like AMC.</p>
|
|
<p>The first element of the structure is the <a class="reference internal" href="../glossary/a.html#term-alignment"><em class="xref std std-term">alignment</em></a> of objects
|
|
belonging to this format. Determining the alignment is hard to do
|
|
portably, because it depends on the target architecture and on the way
|
|
the compiler lays out its structures in memory. Here are some things
|
|
you might try:</p>
|
|
<ol class="arabic">
|
|
<li><p class="first">Some modern compilers support the <tt class="docutils literal"><span class="pre">alignof</span></tt> operator:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="cp">#define ALIGNMENT alignof(obj_s)</span>
|
|
</pre></div>
|
|
</div>
|
|
</li>
|
|
<li><p class="first">On older compilers you may be able to use this trick:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="cp">#define ALIGNMENT offsetof(struct {char c; obj_s obj;}, obj)</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>but this is not reliable because some compilers pack structures
|
|
more tightly than their alignment requirements in some
|
|
circumstances (for example, GCC if the <tt class="docutils literal"><span class="pre">-fstruct-pack</span></tt> option is
|
|
specified).</p>
|
|
</li>
|
|
<li><p class="first">The MPS interface provides the type <a class="reference internal" href="../topic/interface.html#mps_word_t" title="mps_word_t"><tt class="xref c c-type docutils literal"><span class="pre">mps_word_t</span></tt></a>, which is
|
|
an unsigned integral type that is the same size as the platform’s
|
|
<a class="reference internal" href="../glossary/o.html#term-object-pointer"><em class="xref std std-term">object pointer</em></a> types.</p>
|
|
<p>So if you know that all your objects can be word-aligned, you can
|
|
use:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="cp">#define ALIGNMENT sizeof(mps_word_t)</span>
|
|
</pre></div>
|
|
</div>
|
|
</li>
|
|
</ol>
|
|
<p>The other elements of the structure are the <a class="reference internal" href="../glossary/f.html#term-format-method"><em class="xref std std-term">format methods</em></a>,
|
|
which are described in the following sections. (The <tt class="docutils literal"><span class="pre">NULL</span></tt> in the
|
|
structure is a placeholder for the <a class="reference internal" href="../glossary/c.html#term-copy-method"><em class="xref std std-term">copy method</em></a>, which is now
|
|
obsolete.)</p>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topic</p>
|
|
<p class="last"><a class="reference internal" href="../topic/format.html#topic-format"><em>Object formats</em></a>.</p>
|
|
</div>
|
|
<div class="section" id="the-scan-method">
|
|
<span id="guide-lang-scan"></span><span id="index-5"></span><h3>3.4.1. The scan method<a class="headerlink" href="#the-scan-method" title="Permalink to this headline">¶</a></h3>
|
|
<p>The <a class="reference internal" href="../glossary/s.html#term-scan-method"><em class="xref std std-term">scan method</em></a> is a function of type
|
|
<a class="reference internal" href="../topic/format.html#mps_fmt_scan_t" title="mps_fmt_scan_t"><tt class="xref c c-type docutils literal"><span class="pre">mps_fmt_scan_t</span></tt></a>. It is called by the MPS to <a class="reference internal" href="../glossary/s.html#term-scan"><em class="xref std std-term">scan</em></a> a
|
|
block of memory. Its task is to identify all references within the
|
|
objects in the block of memory, and “fix” them, by calling the macros
|
|
<a class="reference internal" href="../topic/scanning.html#MPS_FIX1" title="MPS_FIX1"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX1()</span></tt></a> and <a class="reference internal" href="../topic/scanning.html#MPS_FIX2" title="MPS_FIX2"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX2()</span></tt></a> on each reference (possibly
|
|
via the convenience macro <a class="reference internal" href="../topic/scanning.html#MPS_FIX12" title="MPS_FIX12"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX12()</span></tt></a>).</p>
|
|
<p>“Fixing” is a generic operation whose effect depends on the context in
|
|
which the scan method was called. The scan method is called to
|
|
discover references and so determine which objects are <a class="reference internal" href="../glossary/l.html#term-live"><em class="xref std std-term">alive</em></a> and which are <a class="reference internal" href="../glossary/d.html#term-dead"><em class="xref std std-term">dead</em></a>, and also to update references
|
|
after objects have been moved.</p>
|
|
<p>Here’s the scan method for the toy Scheme interpreter:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">mps_res_t</span> <span class="nf">obj_scan</span><span class="p">(</span><span class="n">mps_ss_t</span> <span class="n">ss</span><span class="p">,</span> <span class="n">mps_addr_t</span> <span class="n">base</span><span class="p">,</span> <span class="n">mps_addr_t</span> <span class="n">limit</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">MPS_SCAN_BEGIN</span><span class="p">(</span><span class="n">ss</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="k">while</span> <span class="p">(</span><span class="n">base</span> <span class="o"><</span> <span class="n">limit</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="n">obj_t</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">base</span><span class="p">;</span>
|
|
<span class="k">switch</span> <span class="p">(</span><span class="n">TYPE</span><span class="p">(</span><span class="n">obj</span><span class="p">))</span> <span class="p">{</span>
|
|
<span class="k">case</span> <span class="n">TYPE_PAIR</span>:
|
|
<span class="n">FIX</span><span class="p">(</span><span class="n">CAR</span><span class="p">(</span><span class="n">obj</span><span class="p">));</span>
|
|
<span class="n">FIX</span><span class="p">(</span><span class="n">CDR</span><span class="p">(</span><span class="n">obj</span><span class="p">));</span>
|
|
<span class="n">base</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">base</span> <span class="o">+</span> <span class="n">ALIGN</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">pair_s</span><span class="p">));</span>
|
|
<span class="k">break</span><span class="p">;</span>
|
|
<span class="k">case</span> <span class="n">TYPE_INTEGER</span>:
|
|
<span class="n">base</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">base</span> <span class="o">+</span> <span class="n">ALIGN</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">integer_s</span><span class="p">));</span>
|
|
<span class="k">break</span><span class="p">;</span>
|
|
<span class="cm">/* ... and so on for the other types ... */</span>
|
|
<span class="nl">default:</span>
|
|
<span class="n">assert</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
|
|
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Unexpected object on the heap</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
|
<span class="n">abort</span><span class="p">();</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span> <span class="n">MPS_SCAN_END</span><span class="p">(</span><span class="n">ss</span><span class="p">);</span>
|
|
<span class="k">return</span> <span class="n">MPS_RES_OK</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>The scan method receives a <a class="reference internal" href="../glossary/s.html#term-scan-state"><em class="xref std std-term">scan state</em></a> (<tt class="docutils literal"><span class="pre">ss</span></tt>) argument, and
|
|
the block of memory to scan, from <tt class="docutils literal"><span class="pre">base</span></tt> (inclusive) to <tt class="docutils literal"><span class="pre">limit</span></tt>
|
|
(exclusive). This block of memory is known to be packed with objects
|
|
belonging to the object format, and so the scan method loops over the
|
|
objects in the block, dispatching on the type of each object, and then
|
|
updating <tt class="docutils literal"><span class="pre">base</span></tt> to point to the next object in the block.</p>
|
|
<p>For each reference in an object <tt class="docutils literal"><span class="pre">obj_scan</span></tt> fixes it by calling
|
|
<a class="reference internal" href="../topic/scanning.html#MPS_FIX12" title="MPS_FIX12"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX12()</span></tt></a> via the macro <tt class="docutils literal"><span class="pre">FIX</span></tt>, which is defined as
|
|
follows:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="cp">#define FIX(ref) \</span>
|
|
<span class="cp"> do { \</span>
|
|
<span class="cp"> mps_addr_t _addr = (ref); </span><span class="cm">/* copy to local to avoid type pun */</span><span class="cp"> \</span>
|
|
<span class="cp"> mps_res_t res = MPS_FIX12(ss, &_addr); \</span>
|
|
<span class="cp"> if (res != MPS_RES_OK) return res; \</span>
|
|
<span class="cp"> (ref) = _addr; \</span>
|
|
<span class="cp"> } while (0)</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Each call to <a class="reference internal" href="../topic/scanning.html#MPS_FIX12" title="MPS_FIX12"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX12()</span></tt></a> must appear between calls to the
|
|
macros <a class="reference internal" href="../topic/scanning.html#MPS_SCAN_BEGIN" title="MPS_SCAN_BEGIN"><tt class="xref c c-func docutils literal"><span class="pre">MPS_SCAN_BEGIN()</span></tt></a> and <a class="reference internal" href="../topic/scanning.html#MPS_SCAN_END" title="MPS_SCAN_END"><tt class="xref c c-func docutils literal"><span class="pre">MPS_SCAN_END()</span></tt></a>. It’s
|
|
usually most convenient to call <a class="reference internal" href="../topic/scanning.html#MPS_SCAN_BEGIN" title="MPS_SCAN_BEGIN"><tt class="xref c c-func docutils literal"><span class="pre">MPS_SCAN_BEGIN()</span></tt></a> at the start
|
|
of the function and <a class="reference internal" href="../topic/scanning.html#MPS_SCAN_END" title="MPS_SCAN_END"><tt class="xref c c-func docutils literal"><span class="pre">MPS_SCAN_END()</span></tt></a> at the end, as here.</p>
|
|
<div class="admonition-note admonition">
|
|
<p class="first admonition-title">Notes</p>
|
|
<ol class="last arabic simple">
|
|
<li>When the MPS calls your scan method, it may be part-way through
|
|
moving your objects. It is therefore essential that the scan
|
|
method only examine objects in the range of addresses it is
|
|
given. Objects in other ranges of addresses are not guaranteed
|
|
to be in a consistent state.</li>
|
|
<li>Scanning is an operation on the <a class="reference internal" href="../glossary/c.html#term-critical-path"><em class="xref std std-term">critical path</em></a> of the
|
|
MPS, which means that it is important that it runs as quickly
|
|
as possible.</li>
|
|
<li>If your reference is <a class="reference internal" href="../glossary/t.html#term-tagged-reference"><em class="xref std std-term">tagged</em></a>, you
|
|
must remove the tag before fixing it. (This is not quite true,
|
|
but see <a class="reference internal" href="../topic/scanning.html#topic-scanning-tag"><em>Tagged references</em></a> for the full story.)</li>
|
|
<li>The “fix” operation may update the reference. So if your
|
|
reference is tagged, you must make sure that the tag is
|
|
restored after the reference is updated.</li>
|
|
<li>The “fix” operation may fail by returning a <a class="reference internal" href="../glossary/r.html#term-result-code"><em class="xref std std-term">result code</em></a>
|
|
other than <a class="reference internal" href="../topic/error.html#MPS_RES_OK" title="MPS_RES_OK"><tt class="xref c c-macro docutils literal"><span class="pre">MPS_RES_OK</span></tt></a>. A scan function must
|
|
propagate such a result code to the caller, and should do so as
|
|
soon as practicable.</li>
|
|
</ol>
|
|
</div>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topics</p>
|
|
<p class="last"><a class="reference internal" href="../topic/format.html#topic-format"><em>Object formats</em></a>, <a class="reference internal" href="../topic/scanning.html#topic-scanning"><em>Scanning</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="the-skip-method">
|
|
<span id="guide-lang-skip"></span><span id="index-6"></span><h3>3.4.2. The skip method<a class="headerlink" href="#the-skip-method" title="Permalink to this headline">¶</a></h3>
|
|
<p>The <a class="reference internal" href="../glossary/s.html#term-skip-method"><em class="xref std std-term">skip method</em></a> is a function of type
|
|
<a class="reference internal" href="../topic/format.html#mps_fmt_skip_t" title="mps_fmt_skip_t"><tt class="xref c c-type docutils literal"><span class="pre">mps_fmt_skip_t</span></tt></a>. It is called by the MPS to skip over an
|
|
object belonging to the format, and also to determine its size.</p>
|
|
<p>Here’s the skip method for the toy Scheme interpreter:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">mps_addr_t</span> <span class="nf">obj_skip</span><span class="p">(</span><span class="n">mps_addr_t</span> <span class="n">base</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">obj_t</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">base</span><span class="p">;</span>
|
|
<span class="k">switch</span> <span class="p">(</span><span class="n">TYPE</span><span class="p">(</span><span class="n">obj</span><span class="p">))</span> <span class="p">{</span>
|
|
<span class="k">case</span> <span class="n">TYPE_PAIR</span>:
|
|
<span class="n">base</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">base</span> <span class="o">+</span> <span class="n">ALIGN</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">pair_s</span><span class="p">));</span>
|
|
<span class="k">break</span><span class="p">;</span>
|
|
<span class="k">case</span> <span class="n">TYPE_INTEGER</span>:
|
|
<span class="n">base</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">base</span> <span class="o">+</span> <span class="n">ALIGN</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">integer_s</span><span class="p">));</span>
|
|
<span class="k">break</span><span class="p">;</span>
|
|
<span class="cm">/* ... and so on for the other types ... */</span>
|
|
<span class="nl">default:</span>
|
|
<span class="n">assert</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
|
|
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Unexpected object on the heap</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
|
<span class="n">abort</span><span class="p">();</span>
|
|
<span class="p">}</span>
|
|
<span class="k">return</span> <span class="n">base</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>The argument <tt class="docutils literal"><span class="pre">base</span></tt> is the address to the base of the object. The
|
|
skip method must return the address of the base of the “next object”:
|
|
in formats of variant A like this one, this is the address just past
|
|
the end of the object, rounded up to the object format’s alignment.</p>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topic</p>
|
|
<p class="last"><a class="reference internal" href="../topic/format.html#topic-format"><em>Object formats</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="the-forward-method">
|
|
<span id="guide-lang-fwd"></span><span id="index-7"></span><h3>3.4.3. The forward method<a class="headerlink" href="#the-forward-method" title="Permalink to this headline">¶</a></h3>
|
|
<p>The <a class="reference internal" href="../glossary/f.html#term-forward-method"><em class="xref std std-term">forward method</em></a> is a function of type
|
|
<a class="reference internal" href="../topic/format.html#mps_fmt_fwd_t" title="mps_fmt_fwd_t"><tt class="xref c c-type docutils literal"><span class="pre">mps_fmt_fwd_t</span></tt></a>. It is called by the MPS after it has moved an
|
|
object, and its task is to replace the old object with a
|
|
<a class="reference internal" href="../glossary/f.html#term-forwarding-object"><em class="xref std std-term">forwarding object</em></a> pointing to the new location of the object.</p>
|
|
<div class="figure align-center">
|
|
<img alt="Diagram: Copying garbage collection." src="../_images/copying1.svg" /><p class="caption">Copying garbage collection.</p>
|
|
</div>
|
|
<p>The forwarding object must satisfy these properties:</p>
|
|
<ol class="arabic simple">
|
|
<li>It must be scannable and skippable, and so it will need to have a
|
|
type field to distinguish it from other Scheme objects.</li>
|
|
<li>It must contain a pointer to the new location of the object (a
|
|
<a class="reference internal" href="../glossary/f.html#term-forwarding-pointer"><em class="xref std std-term">forwarding pointer</em></a>).</li>
|
|
<li>The <a class="reference internal" href="#guide-lang-scan"><em>scan method</em></a> and the <a class="reference internal" href="#guide-lang-skip"><em>skip method</em></a> will both need to know the length of the
|
|
forwarding object. This can be arbitrarily long (in the case of
|
|
string objects, for example) so it must contain a length field.</li>
|
|
</ol>
|
|
<p>This poses a problem, because the above analysis suggests that
|
|
forwarding objects need to contain at least three words, but Scheme
|
|
objects might be as small as two words (for example, integers).</p>
|
|
<p>This conundrum can be solved by having two types of forwarding object.
|
|
The first type is suitable for forwarding objects of three words or
|
|
longer:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">typedef</span> <span class="k">struct</span> <span class="n">fwd_s</span> <span class="p">{</span>
|
|
<span class="n">type_t</span> <span class="n">type</span><span class="p">;</span> <span class="cm">/* TYPE_FWD */</span>
|
|
<span class="n">obj_t</span> <span class="n">fwd</span><span class="p">;</span> <span class="cm">/* forwarded object */</span>
|
|
<span class="kt">size_t</span> <span class="n">size</span><span class="p">;</span> <span class="cm">/* total size of this object */</span>
|
|
<span class="p">}</span> <span class="n">fwd_s</span><span class="p">;</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>while the second type is suitable for forwarding objects of two words:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">typedef</span> <span class="k">struct</span> <span class="n">fwd2_s</span> <span class="p">{</span>
|
|
<span class="n">type_t</span> <span class="n">type</span><span class="p">;</span> <span class="cm">/* TYPE_FWD2 */</span>
|
|
<span class="n">obj_t</span> <span class="n">fwd</span><span class="p">;</span> <span class="cm">/* forwarded object */</span>
|
|
<span class="p">}</span> <span class="n">fwd2_s</span><span class="p">;</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Here’s the forward method for the toy Scheme interpreter:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">void</span> <span class="nf">obj_fwd</span><span class="p">(</span><span class="n">mps_addr_t</span> <span class="n">old</span><span class="p">,</span> <span class="n">mps_addr_t</span> <span class="n">new</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">obj_t</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">old</span><span class="p">;</span>
|
|
<span class="n">mps_addr_t</span> <span class="n">limit</span> <span class="o">=</span> <span class="n">obj_skip</span><span class="p">(</span><span class="n">old</span><span class="p">);</span>
|
|
<span class="kt">size_t</span> <span class="n">size</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">limit</span> <span class="o">-</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">old</span><span class="p">;</span>
|
|
<span class="n">assert</span><span class="p">(</span><span class="n">size</span> <span class="o">>=</span> <span class="n">ALIGN_UP</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">fwd2_s</span><span class="p">)));</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">==</span> <span class="n">ALIGN_UP</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">fwd2_s</span><span class="p">)))</span> <span class="p">{</span>
|
|
<span class="n">TYPE</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">TYPE_FWD2</span><span class="p">;</span>
|
|
<span class="n">obj</span><span class="o">-></span><span class="n">fwd2</span><span class="p">.</span><span class="n">fwd</span> <span class="o">=</span> <span class="n">new</span><span class="p">;</span>
|
|
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
|
|
<span class="n">TYPE</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">TYPE_FWD</span><span class="p">;</span>
|
|
<span class="n">obj</span><span class="o">-></span><span class="n">fwd</span><span class="p">.</span><span class="n">fwd</span> <span class="o">=</span> <span class="n">new</span><span class="p">;</span>
|
|
<span class="n">obj</span><span class="o">-></span><span class="n">fwd</span><span class="p">.</span><span class="n">size</span> <span class="o">=</span> <span class="n">size</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>The argument <tt class="docutils literal"><span class="pre">old</span></tt> is the old address of the object, and <tt class="docutils literal"><span class="pre">new</span></tt> is
|
|
the location to which it has been moved.</p>
|
|
<p>The forwarding objects must be scannable and skippable, so the
|
|
following code must be added to <tt class="docutils literal"><span class="pre">obj_scan</span></tt> and <tt class="docutils literal"><span class="pre">obj_skip</span></tt>:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">case</span> <span class="n">TYPE_FWD</span>:
|
|
<span class="n">base</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">base</span> <span class="o">+</span> <span class="n">ALIGN_UP</span><span class="p">(</span><span class="n">obj</span><span class="o">-></span><span class="n">fwd</span><span class="p">.</span><span class="n">size</span><span class="p">);</span>
|
|
<span class="k">break</span><span class="p">;</span>
|
|
<span class="k">case</span> <span class="n">TYPE_FWD2</span>:
|
|
<span class="n">base</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">base</span> <span class="o">+</span> <span class="n">ALIGN_UP</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">fwd2_s</span><span class="p">));</span>
|
|
<span class="k">break</span><span class="p">;</span>
|
|
</pre></div>
|
|
</div>
|
|
<div class="admonition-note admonition">
|
|
<p class="first admonition-title">Note</p>
|
|
<p>Objects that consist of a single word present a problem for the
|
|
design of the forwarding object. In the toy Scheme interpreter, this
|
|
happens on some 64-bit platforms, where a pointer is 8 bytes long,
|
|
and a <tt class="docutils literal"><span class="pre">character_s</span></tt> object (which consists of a 4-byte <tt class="docutils literal"><span class="pre">int</span></tt>
|
|
and a 1-byte <tt class="docutils literal"><span class="pre">char</span></tt>) is also 8 bytes long.</p>
|
|
<p>There are a couple of solutions to this problem:</p>
|
|
<ol class="last arabic simple">
|
|
<li>Allocate the small objects with enough padding so that they can
|
|
be forwarded. (This is how the problem is solved in the toy
|
|
Scheme interpreter.)</li>
|
|
<li>Use a <a class="reference internal" href="../glossary/t.html#term-tag"><em class="xref std std-term">tag</em></a> to distinguish between the client object and
|
|
a forwarding object that replaces it. It might help to allocate
|
|
the small objects in their own pool so that the number of types
|
|
that the scan method has to distinguish is minimized. Since
|
|
these objects do not contain references, they could be
|
|
allocated from the <a class="reference internal" href="../pool/amcz.html#pool-amcz"><em>AMCZ (Automatic Mostly-Copying Zero-rank)</em></a> pool, and so the cost of
|
|
scanning them could be avoided.</li>
|
|
</ol>
|
|
</div>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topic</p>
|
|
<p class="last"><a class="reference internal" href="../topic/format.html#topic-format"><em>Object formats</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="the-is-forwarded-method">
|
|
<span id="guide-lang-isfwd"></span><span id="index-8"></span><h3>3.4.4. The is-forwarded method<a class="headerlink" href="#the-is-forwarded-method" title="Permalink to this headline">¶</a></h3>
|
|
<p>The <a class="reference internal" href="../glossary/i.html#term-is-forwarded-method"><em class="xref std std-term">is-forwarded method</em></a> is a function of type
|
|
<a class="reference internal" href="../topic/format.html#mps_fmt_isfwd_t" title="mps_fmt_isfwd_t"><tt class="xref c c-type docutils literal"><span class="pre">mps_fmt_isfwd_t</span></tt></a>. It is called by the MPS to determine if an
|
|
object is a <a class="reference internal" href="../glossary/f.html#term-forwarding-object"><em class="xref std std-term">forwarding object</em></a>, and if it is, to determine the
|
|
location where that object was moved.</p>
|
|
<p>Here’s the is-forwarded method for the toy Scheme interpreter:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">mps_addr_t</span> <span class="nf">obj_isfwd</span><span class="p">(</span><span class="n">mps_addr_t</span> <span class="n">addr</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">obj_t</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">addr</span><span class="p">;</span>
|
|
<span class="k">switch</span> <span class="p">(</span><span class="n">TYPE</span><span class="p">(</span><span class="n">obj</span><span class="p">))</span> <span class="p">{</span>
|
|
<span class="k">case</span> <span class="n">TYPE_FWD2</span>:
|
|
<span class="k">return</span> <span class="n">obj</span><span class="o">-></span><span class="n">fwd2</span><span class="p">.</span><span class="n">fwd</span><span class="p">;</span>
|
|
<span class="k">case</span> <span class="n">TYPE_FWD</span>:
|
|
<span class="k">return</span> <span class="n">obj</span><span class="o">-></span><span class="n">fwd</span><span class="p">.</span><span class="n">fwd</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
<span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>It receives the address of an object, and returns the address to which
|
|
that object was moved, or <tt class="docutils literal"><span class="pre">NULL</span></tt> if the object was not moved.</p>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topic</p>
|
|
<p class="last"><a class="reference internal" href="../topic/format.html#topic-format"><em>Object formats</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="the-padding-method">
|
|
<span id="guide-lang-pad"></span><span id="index-9"></span><h3>3.4.5. The padding method<a class="headerlink" href="#the-padding-method" title="Permalink to this headline">¶</a></h3>
|
|
<p>The <a class="reference internal" href="../glossary/p.html#term-padding-method"><em class="xref std std-term">padding method</em></a> is a function of type
|
|
<a class="reference internal" href="../topic/format.html#mps_fmt_pad_t" title="mps_fmt_pad_t"><tt class="xref c c-type docutils literal"><span class="pre">mps_fmt_pad_t</span></tt></a>. It is called by the MPS to fill a block of
|
|
memory with a <a class="reference internal" href="../glossary/p.html#term-padding-object"><em class="xref std std-term">padding object</em></a>: this is an object that fills
|
|
gaps in a block of <a class="reference internal" href="../glossary/f.html#term-formatted-object"><em class="xref std std-term">formatted objects</em></a>, for
|
|
example to enable the MPS to pack objects into fixed-size units (such
|
|
as operating system <a class="reference internal" href="../glossary/p.html#term-page"><em class="xref std std-term">pages</em></a>).</p>
|
|
<p>A padding object must be scannable and skippable, and not confusable
|
|
with a <a class="reference internal" href="../glossary/f.html#term-forwarding-object"><em class="xref std std-term">forwarding object</em></a>. This means they need a type and a
|
|
size. However, padding objects might need to be as small as the
|
|
alignment of the object format, which was specified to be a single
|
|
word. As with forwarding objects, this can be solved by having two
|
|
types of padding object. The first type is suitable for padding
|
|
objects of two words or longer:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">typedef</span> <span class="k">struct</span> <span class="n">pad_s</span> <span class="p">{</span>
|
|
<span class="n">type_t</span> <span class="n">type</span><span class="p">;</span> <span class="cm">/* TYPE_PAD */</span>
|
|
<span class="kt">size_t</span> <span class="n">size</span><span class="p">;</span> <span class="cm">/* total size of this object */</span>
|
|
<span class="p">}</span> <span class="n">pad_s</span><span class="p">;</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>while the second type is suitable for padding objects consisting of a
|
|
single word:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">typedef</span> <span class="k">struct</span> <span class="n">pad1_s</span> <span class="p">{</span>
|
|
<span class="n">type_t</span> <span class="n">type</span><span class="p">;</span> <span class="cm">/* TYPE_PAD1 */</span>
|
|
<span class="p">}</span> <span class="n">pad1_s</span><span class="p">;</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Here’s the padding method:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">void</span> <span class="nf">obj_pad</span><span class="p">(</span><span class="n">mps_addr_t</span> <span class="n">addr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">size</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">obj_t</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">addr</span><span class="p">;</span>
|
|
<span class="n">assert</span><span class="p">(</span><span class="n">size</span> <span class="o">>=</span> <span class="n">ALIGN</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">pad1_s</span><span class="p">)));</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">==</span> <span class="n">ALIGN</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">pad1_s</span><span class="p">)))</span> <span class="p">{</span>
|
|
<span class="n">TYPE</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">TYPE_PAD1</span><span class="p">;</span>
|
|
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
|
|
<span class="n">TYPE</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">TYPE_PAD</span><span class="p">;</span>
|
|
<span class="n">obj</span><span class="o">-></span><span class="n">pad</span><span class="p">.</span><span class="n">size</span> <span class="o">=</span> <span class="n">size</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>The argument <tt class="docutils literal"><span class="pre">addr</span></tt> is the address at which the padding object must be created, and <tt class="docutils literal"><span class="pre">size</span></tt> is its size in bytes: this will always be a multiple of the alignment of the object format.</p>
|
|
<p>The padding objects must be scannable and skippable, so the following
|
|
code must be added to <tt class="docutils literal"><span class="pre">obj_scan</span></tt> and <tt class="docutils literal"><span class="pre">obj_skip</span></tt>:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">case</span> <span class="n">TYPE_PAD</span>:
|
|
<span class="n">base</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">base</span> <span class="o">+</span> <span class="n">ALIGN</span><span class="p">(</span><span class="n">obj</span><span class="o">-></span><span class="n">pad</span><span class="p">.</span><span class="n">size</span><span class="p">);</span>
|
|
<span class="k">break</span><span class="p">;</span>
|
|
<span class="k">case</span> <span class="n">TYPE_PAD1</span>:
|
|
<span class="n">base</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">base</span> <span class="o">+</span> <span class="n">ALIGN</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">pad1_s</span><span class="p">));</span>
|
|
<span class="k">break</span><span class="p">;</span>
|
|
</pre></div>
|
|
</div>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topic</p>
|
|
<p class="last"><a class="reference internal" href="../topic/format.html#topic-format"><em>Object formats</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="generation-chains">
|
|
<span id="index-10"></span><h2>3.5. Generation chains<a class="headerlink" href="#generation-chains" title="Permalink to this headline">¶</a></h2>
|
|
<p>The AMC pool requires not only an object format but a
|
|
<a class="reference internal" href="../glossary/g.html#term-generation-chain"><em class="xref std std-term">generation chain</em></a>. This specifies the generation structure of
|
|
the <a class="reference internal" href="../glossary/g.html#term-generational-garbage-collection"><em class="xref std std-term">generational garbage collection</em></a>.</p>
|
|
<p>You create a generation chain by constructing an array of structures
|
|
of type <a class="reference internal" href="../topic/collection.html#mps_gen_param_s" title="mps_gen_param_s"><tt class="xref c c-type docutils literal"><span class="pre">mps_gen_param_s</span></tt></a>, one for each generation, and
|
|
passing them to <a class="reference internal" href="../topic/collection.html#mps_chain_create" title="mps_chain_create"><tt class="xref c c-func docutils literal"><span class="pre">mps_chain_create()</span></tt></a>. Each of these structures
|
|
contains two values, the <em>capacity</em> of the generation in
|
|
<a class="reference internal" href="../glossary/k.html#term-kilobyte"><em class="xref std std-term">kilobytes</em></a>, and the <em>mortality</em>, the proportion of
|
|
objects in the generation that you expect to survive a collection of
|
|
that generation.</p>
|
|
<p>These numbers are <em>hints</em> to the MPS that it may use to make decisions
|
|
about when and what to collect: nothing will go wrong (other than
|
|
suboptimal performance) if you make poor choices. Making good choices
|
|
for the capacity and mortality of each generation is not easy, and is postponed to the chapter <a class="reference internal" href="perf.html#guide-perf"><em>Tuning the Memory Pool System for performance</em></a>.</p>
|
|
<p>Here’s the code for creating the generation chain for the toy Scheme
|
|
interpreter:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="n">mps_gen_param_s</span> <span class="n">obj_gen_params</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
|
|
<span class="p">{</span> <span class="mi">150</span><span class="p">,</span> <span class="mf">0.85</span> <span class="p">},</span>
|
|
<span class="p">{</span> <span class="mi">170</span><span class="p">,</span> <span class="mf">0.45</span> <span class="p">},</span>
|
|
<span class="p">};</span>
|
|
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_chain_create</span><span class="p">(</span><span class="o">&</span><span class="n">obj_chain</span><span class="p">,</span>
|
|
<span class="n">arena</span><span class="p">,</span>
|
|
<span class="n">LENGTH</span><span class="p">(</span><span class="n">obj_gen_params</span><span class="p">),</span>
|
|
<span class="n">obj_gen_params</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't create obj chain"</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Note that these numbers have have been deliberately chosen to be
|
|
small, so that the MPS is forced to collect often, so that you can see
|
|
it working. Don’t just copy these numbers unless you also want to see
|
|
frequent garbage collections!</p>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topic</p>
|
|
<p class="last"><a class="reference internal" href="../topic/collection.html#topic-collection"><em>Garbage collection</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="creating-the-pool">
|
|
<span id="index-11"></span><h2>3.6. Creating the pool<a class="headerlink" href="#creating-the-pool" title="Permalink to this headline">¶</a></h2>
|
|
<p>Now you know enough to create an <a class="reference internal" href="../pool/amc.html#pool-amc"><em>AMC (Automatic Mostly-Copying)</em></a> pool! Let’s review
|
|
the pool creation code. First, the header for the AMC pool class:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="cp">#include "mpscamc.h"</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Second, the <a class="reference internal" href="../glossary/o.html#term-object-format"><em class="xref std std-term">object format</em></a>:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">struct</span> <span class="n">mps_fmt_A_s</span> <span class="n">obj_fmt_s</span> <span class="o">=</span> <span class="p">{</span>
|
|
<span class="k">sizeof</span><span class="p">(</span><span class="n">mps_word_t</span><span class="p">),</span>
|
|
<span class="n">obj_scan</span><span class="p">,</span>
|
|
<span class="n">obj_skip</span><span class="p">,</span>
|
|
<span class="nb">NULL</span><span class="p">,</span>
|
|
<span class="n">obj_fwd</span><span class="p">,</span>
|
|
<span class="n">obj_isfwd</span><span class="p">,</span>
|
|
<span class="n">obj_pad</span><span class="p">,</span>
|
|
<span class="p">};</span>
|
|
|
|
<span class="n">mps_fmt_t</span> <span class="n">obj_fmt</span><span class="p">;</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_fmt_create_A</span><span class="p">(</span><span class="o">&</span><span class="n">obj_fmt</span><span class="p">,</span> <span class="n">arena</span><span class="p">,</span> <span class="o">&</span><span class="n">obj_fmt_s</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't create obj format"</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Third, the <a class="reference internal" href="../glossary/g.html#term-generation-chain"><em class="xref std std-term">generation chain</em></a>:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="n">mps_gen_param_s</span> <span class="n">obj_gen_params</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
|
|
<span class="p">{</span> <span class="mi">150</span><span class="p">,</span> <span class="mf">0.85</span> <span class="p">},</span>
|
|
<span class="p">{</span> <span class="mi">170</span><span class="p">,</span> <span class="mf">0.45</span> <span class="p">},</span>
|
|
<span class="p">};</span>
|
|
|
|
<span class="n">mps_chain_t</span> <span class="n">obj_chain</span><span class="p">;</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_chain_create</span><span class="p">(</span><span class="o">&</span><span class="n">obj_chain</span><span class="p">,</span>
|
|
<span class="n">arena</span><span class="p">,</span>
|
|
<span class="n">LENGTH</span><span class="p">(</span><span class="n">obj_gen_params</span><span class="p">),</span>
|
|
<span class="n">obj_gen_params</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't create obj chain"</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>And finally the <a class="reference internal" href="../glossary/p.html#term-pool"><em class="xref std std-term">pool</em></a>:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="n">mps_pool_t</span> <span class="n">obj_pool</span><span class="p">;</span>
|
|
<span class="n">MPS_ARGS_BEGIN</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="n">MPS_ARGS_ADD</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="n">MPS_KEY_CHAIN</span><span class="p">,</span> <span class="n">obj_chain</span><span class="p">);</span>
|
|
<span class="n">MPS_ARGS_ADD</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="n">MPS_KEY_FORMAT</span><span class="p">,</span> <span class="n">obj_fmt</span><span class="p">);</span>
|
|
<span class="n">MPS_ARGS_DONE</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_pool_create_k</span><span class="p">(</span><span class="o">&</span><span class="n">obj_pool</span><span class="p">,</span> <span class="n">arena</span><span class="p">,</span> <span class="n">mps_class_amc</span><span class="p">(),</span> <span class="n">args</span><span class="p">);</span>
|
|
<span class="p">}</span> <span class="n">MPS_ARGS_END</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't create obj pool"</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="roots">
|
|
<span id="guide-lang-root"></span><span id="index-12"></span><h2>3.7. Roots<a class="headerlink" href="#roots" title="Permalink to this headline">¶</a></h2>
|
|
<p>The <a class="reference internal" href="../glossary/o.html#term-object-format"><em class="xref std std-term">object format</em></a> tells the MPS how to find <a class="reference internal" href="../glossary/r.html#term-reference"><em class="xref std std-term">references</em></a> from one object to another. This allows the MPS to
|
|
extrapolate the reachability property: if object <em>A</em> is
|
|
<a class="reference internal" href="../glossary/r.html#term-reachable"><em class="xref std std-term">reachable</em></a>, and the <a class="reference internal" href="../glossary/s.html#term-scan-method"><em class="xref std std-term">scan method</em></a> fixes a reference from
|
|
<em>A</em> to another object <em>B</em>, then <em>B</em> is reachable too.</p>
|
|
<p>But how does this process get started? How does the MPS know which
|
|
objects are reachable <em>a priori</em>? Such objects are known as
|
|
<a class="reference internal" href="../glossary/r.html#term-root"><em class="xref std std-term">roots</em></a>, and you must register them with the MPS,
|
|
creating root descriptions of type <a class="reference internal" href="../topic/root.html#mps_root_t" title="mps_root_t"><tt class="xref c c-type docutils literal"><span class="pre">mps_root_t</span></tt></a>.</p>
|
|
<p>The most important root consists of the contents of the
|
|
<a class="reference internal" href="../glossary/r.html#term-register"><em class="xref std std-term">registers</em></a> and the <a class="reference internal" href="../glossary/c.html#term-control-stack"><em class="xref std std-term">control stack</em></a> of each <a class="reference internal" href="../glossary/t.html#term-thread"><em class="xref std std-term">thread</em></a>
|
|
in your program: this is covered in <a class="reference internal" href="#guide-lang-threads"><em>Threads</em></a>, below.</p>
|
|
<p>Other roots may be found in static variables in your program, or in
|
|
memory allocated by other memory managers. For these roots you must
|
|
describe to the MPS how to <a class="reference internal" href="../glossary/s.html#term-scan"><em class="xref std std-term">scan</em></a> them for references.</p>
|
|
<p>The toy Scheme interpreter has a number of static variables that point
|
|
to heap-allocated objects. First, the special objects, including:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">obj_t</span> <span class="n">obj_empty</span><span class="p">;</span> <span class="cm">/* (), the empty list */</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Second, the predefined symbols, including:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">obj_t</span> <span class="n">obj_quote</span><span class="p">;</span> <span class="cm">/* "quote" symbol */</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>And third, the global symbol table:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">obj_t</span> <span class="o">*</span><span class="n">symtab</span><span class="p">;</span>
|
|
<span class="k">static</span> <span class="kt">size_t</span> <span class="n">symtab_size</span><span class="p">;</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>You tell the MPS how to scan these by writing root scanning functions
|
|
of type <a class="reference internal" href="../topic/root.html#mps_reg_scan_t" title="mps_reg_scan_t"><tt class="xref c c-type docutils literal"><span class="pre">mps_reg_scan_t</span></tt></a>. These functions are similar to the
|
|
<a class="reference internal" href="#guide-lang-scan"><em>scan method</em></a> in an <a class="reference internal" href="../glossary/o.html#term-object-format"><em class="xref std std-term">object format</em></a>,
|
|
described above.</p>
|
|
<p>In the case of the toy Scheme interpreter, the root scanning function
|
|
for the special objects and the predefined symbols could be written
|
|
like this:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">mps_res_t</span> <span class="nf">globals_scan</span><span class="p">(</span><span class="n">mps_ss_t</span> <span class="n">ss</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">p</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">s</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">MPS_SCAN_BEGIN</span><span class="p">(</span><span class="n">ss</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="n">FIX</span><span class="p">(</span><span class="n">obj_empty</span><span class="p">);</span>
|
|
<span class="cm">/* ... and so on for the special objects ... */</span>
|
|
<span class="n">FIX</span><span class="p">(</span><span class="n">obj_quote</span><span class="p">);</span>
|
|
<span class="cm">/* ... and so on for the predefined symbols ... */</span>
|
|
<span class="p">}</span> <span class="n">MPS_SCAN_END</span><span class="p">(</span><span class="n">ss</span><span class="p">);</span>
|
|
<span class="k">return</span> <span class="n">MPS_RES_OK</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>but in fact the interpreter already has tables of these global
|
|
objects, so it’s simpler and more extensible for the root scanning
|
|
function to iterate over them:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">mps_res_t</span> <span class="nf">globals_scan</span><span class="p">(</span><span class="n">mps_ss_t</span> <span class="n">ss</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">p</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">s</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">MPS_SCAN_BEGIN</span><span class="p">(</span><span class="n">ss</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="kt">size_t</span> <span class="n">i</span><span class="p">;</span>
|
|
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">LENGTH</span><span class="p">(</span><span class="n">sptab</span><span class="p">);</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span>
|
|
<span class="n">FIX</span><span class="p">(</span><span class="o">*</span><span class="n">sptab</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">varp</span><span class="p">);</span>
|
|
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">LENGTH</span><span class="p">(</span><span class="n">isymtab</span><span class="p">);</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span>
|
|
<span class="n">FIX</span><span class="p">(</span><span class="o">*</span><span class="n">isymtab</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">varp</span><span class="p">);</span>
|
|
<span class="p">}</span> <span class="n">MPS_SCAN_END</span><span class="p">(</span><span class="n">ss</span><span class="p">);</span>
|
|
<span class="k">return</span> <span class="n">MPS_RES_OK</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Each root scanning function must be registered with the MPS by calling
|
|
<a class="reference internal" href="../topic/root.html#mps_root_create" title="mps_root_create"><tt class="xref c c-func docutils literal"><span class="pre">mps_root_create()</span></tt></a>, like this:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="n">mps_root_t</span> <span class="n">globals_root</span><span class="p">;</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_root_create</span><span class="p">(</span><span class="o">&</span><span class="n">globals_root</span><span class="p">,</span> <span class="n">arena</span><span class="p">,</span> <span class="n">mps_rank_exact</span><span class="p">(),</span> <span class="mi">0</span><span class="p">,</span>
|
|
<span class="n">globals_scan</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't register globals root"</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>The third argument (here <a class="reference internal" href="../topic/root.html#mps_rank_exact" title="mps_rank_exact"><tt class="xref c c-func docutils literal"><span class="pre">mps_rank_exact()</span></tt></a>) is the <a class="reference internal" href="../glossary/r.html#term-rank"><em class="xref std std-term">rank</em></a>
|
|
of references in the root. “<a class="reference internal" href="../glossary/e.html#term-exact-reference"><em class="xref std std-term">Exact</em></a>” means
|
|
that:</p>
|
|
<ol class="arabic simple">
|
|
<li>each reference in the root is a genuine pointer to another object
|
|
managed by the MPS, or else a null pointer (unlike <a class="reference internal" href="../glossary/a.html#term-ambiguous-reference"><em class="xref std std-term">ambiguous
|
|
references</em></a>); and</li>
|
|
<li>each reference keeps the target of the reference alive (unlike
|
|
<a class="reference internal" href="../glossary/w.html#term-weak-reference-1"><em class="xref std std-term">weak references<sup>(1)</sup></em></a>).</li>
|
|
</ol>
|
|
<p>The fourth argument is the <a class="reference internal" href="../glossary/r.html#term-root-mode"><em class="xref std std-term">root mode</em></a>, which tells the MPS
|
|
whether it is allowed to place a <a class="reference internal" href="../glossary/b.html#term-barrier-1"><em class="xref std std-term">barrier<sup>(1)</sup></em></a> on the root. The
|
|
root mode <tt class="docutils literal"><span class="pre">0</span></tt> means that it is not allowed.</p>
|
|
<p>The sixth and seventh arguments (here <tt class="docutils literal"><span class="pre">NULL</span></tt> and <tt class="docutils literal"><span class="pre">0</span></tt>) are passed
|
|
to the root scanning function where they are received as the
|
|
parameters <tt class="docutils literal"><span class="pre">p</span></tt> and <tt class="docutils literal"><span class="pre">s</span></tt> respectively. In this case there was no
|
|
need to use them.</p>
|
|
<p>What about the global symbol table? This is trickier, because it gets
|
|
rehashed from time to time, and during the rehashing process there are
|
|
two copies of the symbol table in existence. Because the MPS is
|
|
<a class="reference internal" href="../glossary/a.html#term-asynchronous-garbage-collector"><em class="xref std std-term">asynchronous</em></a>, it might be
|
|
scanning, moving, or collecting, at any point in time, and if it is
|
|
doing so during the rehashing of the symbol table it had better scan
|
|
both the old and new copies of the table. This is most conveniently
|
|
done by registering a new root to refer to the new copy, and then
|
|
after the rehash has completed, de-registering the old root by calling
|
|
<a class="reference internal" href="../topic/root.html#mps_root_destroy" title="mps_root_destroy"><tt class="xref c c-func docutils literal"><span class="pre">mps_root_destroy()</span></tt></a>.</p>
|
|
<p>It would be possible to write a root scanning function of type
|
|
<a class="reference internal" href="../topic/root.html#mps_reg_scan_t" title="mps_reg_scan_t"><tt class="xref c c-type docutils literal"><span class="pre">mps_reg_scan_t</span></tt></a>, as described above, to fix the references in
|
|
the global symbol table, but the case of a table of references is
|
|
sufficiently common that the MPS provides a convenient (and optimized)
|
|
function, <a class="reference internal" href="../topic/root.html#mps_root_create_table" title="mps_root_create_table"><tt class="xref c c-func docutils literal"><span class="pre">mps_root_create_table()</span></tt></a>, for registering it:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">mps_root_t</span> <span class="n">symtab_root</span><span class="p">;</span>
|
|
|
|
<span class="cm">/* ... */</span>
|
|
|
|
<span class="n">mps_addr_t</span> <span class="n">ref</span> <span class="o">=</span> <span class="n">symtab</span><span class="p">;</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_root_create_table</span><span class="p">(</span><span class="o">&</span><span class="n">symtab_root</span><span class="p">,</span> <span class="n">arena</span><span class="p">,</span> <span class="n">mps_rank_exact</span><span class="p">(),</span> <span class="mi">0</span><span class="p">,</span>
|
|
<span class="n">ref</span><span class="p">,</span> <span class="n">symtab_size</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't register new symtab root"</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
<p id="guide-lang-roots-rehash">The root must be re-registered whenever the global symbol table
|
|
changes size:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">void</span> <span class="nf">rehash</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="n">obj_t</span> <span class="o">*</span><span class="n">old_symtab</span> <span class="o">=</span> <span class="n">symtab</span><span class="p">;</span>
|
|
<span class="kt">unsigned</span> <span class="n">old_symtab_size</span> <span class="o">=</span> <span class="n">symtab_size</span><span class="p">;</span>
|
|
<span class="n">mps_root_t</span> <span class="n">old_symtab_root</span> <span class="o">=</span> <span class="n">symtab_root</span><span class="p">;</span>
|
|
<span class="kt">unsigned</span> <span class="n">i</span><span class="p">;</span>
|
|
<span class="n">mps_addr_t</span> <span class="n">ref</span><span class="p">;</span>
|
|
<span class="n">mps_res_t</span> <span class="n">res</span><span class="p">;</span>
|
|
|
|
<span class="n">symtab_size</span> <span class="o">*=</span> <span class="mi">2</span><span class="p">;</span>
|
|
<span class="n">symtab</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">obj_t</span><span class="p">)</span> <span class="o">*</span> <span class="n">symtab_size</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">symtab</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"out of memory"</span><span class="p">);</span>
|
|
|
|
<span class="cm">/* Initialize the new table to NULL so that "find" will work. */</span>
|
|
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">symtab_size</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span>
|
|
<span class="n">symtab</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
|
|
|
|
<span class="n">ref</span> <span class="o">=</span> <span class="n">symtab</span><span class="p">;</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_root_create_table</span><span class="p">(</span><span class="o">&</span><span class="n">symtab_root</span><span class="p">,</span> <span class="n">arena</span><span class="p">,</span> <span class="n">mps_rank_exact</span><span class="p">(),</span> <span class="mi">0</span><span class="p">,</span>
|
|
<span class="n">ref</span><span class="p">,</span> <span class="n">symtab_size</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't register new symtab root"</span><span class="p">);</span>
|
|
|
|
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">old_symtab_size</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">old_symtab</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="n">obj_t</span> <span class="o">*</span><span class="n">where</span> <span class="o">=</span> <span class="n">find</span><span class="p">(</span><span class="n">old_symtab</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">-></span><span class="n">symbol</span><span class="p">.</span><span class="n">string</span><span class="p">);</span>
|
|
<span class="n">assert</span><span class="p">(</span><span class="n">where</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">);</span> <span class="cm">/* new table shouldn't be full */</span>
|
|
<span class="n">assert</span><span class="p">(</span><span class="o">*</span><span class="n">where</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">);</span> <span class="cm">/* shouldn't be in new table */</span>
|
|
<span class="o">*</span><span class="n">where</span> <span class="o">=</span> <span class="n">old_symtab</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="n">mps_root_destroy</span><span class="p">(</span><span class="n">old_symtab_root</span><span class="p">);</span>
|
|
<span class="n">free</span><span class="p">(</span><span class="n">old_symtab</span><span class="p">);</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<div class="admonition-note admonition">
|
|
<p class="first admonition-title">Notes</p>
|
|
<ol class="last arabic simple">
|
|
<li>The old root description (referring to the old copy of the
|
|
symbol table) is not destroyed until after the new root
|
|
description has been registered. This is because the MPS is
|
|
<a class="reference internal" href="../glossary/a.html#term-asynchronous-garbage-collector"><em class="xref std std-term">asynchronous</em></a>: it might
|
|
be scanning, moving, or collecting, at any point in time. If
|
|
the old root description were destroyed before the new root
|
|
description was registered, there would be a period during
|
|
which:<ol class="loweralpha">
|
|
<li>the symbol table was not reachable (at least as far as the
|
|
MPS was concerned) and so all the objects referenced by it
|
|
(and all the objects reachable from <em>those</em> objects) might
|
|
be dead; and</li>
|
|
<li>if the MPS moved an object, it would not know that the
|
|
object was referenced by the symbol table, and so would not
|
|
update the reference there to point to the new location of
|
|
the object. This would result in out-of-date references in
|
|
the old symbol table, and these would be copied into the new
|
|
symbol table.</li>
|
|
</ol>
|
|
</li>
|
|
<li>The root might be scanned as soon as it is registered, so it is
|
|
important to fill it with scannable references (<tt class="docutils literal"><span class="pre">NULL</span></tt> in
|
|
this case) before registering it.</li>
|
|
<li>The order of operations at the end is important: the old root
|
|
must be de-registered before its memory is freed.</li>
|
|
</ol>
|
|
</div>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topic</p>
|
|
<p class="last"><a class="reference internal" href="../topic/root.html#topic-root"><em>Roots</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="threads">
|
|
<span id="guide-lang-threads"></span><span id="index-13"></span><h2>3.8. Threads<a class="headerlink" href="#threads" title="Permalink to this headline">¶</a></h2>
|
|
<p>In a multi-threaded environment where <a class="reference internal" href="../glossary/i.html#term-incremental-garbage-collection"><em class="xref std std-term">incremental garbage
|
|
collection</em></a> is used, you must register each of your <a class="reference internal" href="../glossary/t.html#term-thread"><em class="xref std std-term">threads</em></a>
|
|
with the MPS so that the MPS can examine their state.</p>
|
|
<p>Even in a single-threaded environment (like the toy Scheme
|
|
interpreter) it may also be necessary to register the (only) thread if
|
|
either of these conditions apply:</p>
|
|
<ol class="arabic simple">
|
|
<li>you are using <a class="reference internal" href="../glossary/m.html#term-moving-garbage-collector"><em class="xref std std-term">moving garbage collection</em></a> (as with the <a class="reference internal" href="../pool/amc.html#pool-amc"><em>AMC (Automatic Mostly-Copying)</em></a> pool);</li>
|
|
<li>the thread’s <a class="reference internal" href="../glossary/r.html#term-register"><em class="xref std std-term">registers</em></a> and <a class="reference internal" href="../glossary/c.html#term-control-stack"><em class="xref std std-term">control stack</em></a>
|
|
constitute a <a class="reference internal" href="../glossary/r.html#term-root"><em class="xref std std-term">root</em></a> (that is, objects may be kept alive via
|
|
references in local variables: this is almost always the case for
|
|
programs written in <a class="reference internal" href="../mmref/lang.html#term-c"><em class="xref std std-term">C</em></a>).</li>
|
|
</ol>
|
|
<p>You register a thread with an <a class="reference internal" href="../glossary/a.html#term-arena"><em class="xref std std-term">arena</em></a> by calling
|
|
<a class="reference internal" href="../topic/thread.html#mps_thread_reg" title="mps_thread_reg"><tt class="xref c c-func docutils literal"><span class="pre">mps_thread_reg()</span></tt></a>:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="n">mps_thr_t</span> <span class="kr">thread</span><span class="p">;</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_thread_reg</span><span class="p">(</span><span class="o">&</span><span class="kr">thread</span><span class="p">,</span> <span class="n">arena</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't register thread"</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>You register the thread’s registers and control stack as a root by
|
|
calling <a class="reference internal" href="../topic/root.html#mps_root_create_reg" title="mps_root_create_reg"><tt class="xref c c-func docutils literal"><span class="pre">mps_root_create_reg()</span></tt></a> and passing
|
|
<a class="reference internal" href="../topic/root.html#mps_stack_scan_ambig" title="mps_stack_scan_ambig"><tt class="xref c c-func docutils literal"><span class="pre">mps_stack_scan_ambig()</span></tt></a>:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="kt">void</span> <span class="o">*</span><span class="n">marker</span> <span class="o">=</span> <span class="o">&</span><span class="n">marker</span><span class="p">;</span>
|
|
<span class="n">mps_root_t</span> <span class="n">reg_root</span><span class="p">;</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_root_create_reg</span><span class="p">(</span><span class="o">&</span><span class="n">reg_root</span><span class="p">,</span>
|
|
<span class="n">arena</span><span class="p">,</span>
|
|
<span class="n">mps_rank_ambig</span><span class="p">(),</span>
|
|
<span class="mi">0</span><span class="p">,</span>
|
|
<span class="kr">thread</span><span class="p">,</span>
|
|
<span class="n">mps_stack_scan_ambig</span><span class="p">,</span>
|
|
<span class="n">marker</span><span class="p">,</span>
|
|
<span class="mi">0</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't create root"</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>In order to scan the control stack, the MPS needs to know where the
|
|
bottom of the stack is, and that’s the role of the <tt class="docutils literal"><span class="pre">marker</span></tt>
|
|
variable: the compiler places it on the stack, so its address is a
|
|
position within the stack. As long as you don’t exit from this
|
|
function while the MPS is running, your program’s active local
|
|
variables will always be higher up on the stack than <tt class="docutils literal"><span class="pre">marker</span></tt>, and
|
|
so will be scanned for references by the MPS.</p>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topic</p>
|
|
<p class="last"><a class="reference internal" href="../topic/thread.html#topic-thread"><em>Threads</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="allocation">
|
|
<span id="guide-lang-allocation"></span><span id="index-14"></span><h2>3.9. Allocation<a class="headerlink" href="#allocation" title="Permalink to this headline">¶</a></h2>
|
|
<p>It probably seemed a long journey to get here, but at last we’re ready
|
|
to start allocating.</p>
|
|
<p><a class="reference internal" href="../glossary/m.html#term-manual-memory-management"><em class="xref std std-term">Manual</em></a> pools typically support
|
|
<a class="reference internal" href="../glossary/m.html#term-malloc"><em class="xref std std-term">malloc</em></a>-like allocation using the function
|
|
<a class="reference internal" href="../topic/allocation.html#mps_alloc" title="mps_alloc"><tt class="xref c c-func docutils literal"><span class="pre">mps_alloc()</span></tt></a>. But <a class="reference internal" href="../glossary/a.html#term-automatic-memory-management"><em class="xref std std-term">automatic</em></a> pools cannot, because of the following problem:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">obj_t</span> <span class="nf">make_pair</span><span class="p">(</span><span class="n">obj_t</span> <span class="n">car</span><span class="p">,</span> <span class="n">obj_t</span> <span class="n">cdr</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">obj_t</span> <span class="n">obj</span><span class="p">;</span>
|
|
<span class="n">mps_addr_t</span> <span class="n">addr</span><span class="p">;</span>
|
|
<span class="n">mps_res_t</span> <span class="n">res</span><span class="p">;</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_alloc</span><span class="p">(</span><span class="o">&</span><span class="n">addr</span><span class="p">,</span> <span class="n">pool</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">pair_s</span><span class="p">));</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"out of memory in make_pair"</span><span class="p">);</span>
|
|
<span class="n">obj</span> <span class="o">=</span> <span class="n">addr</span><span class="p">;</span>
|
|
|
|
<span class="cm">/* What happens if the MPS scans obj just now? */</span>
|
|
|
|
<span class="n">obj</span><span class="o">-></span><span class="n">pair</span><span class="p">.</span><span class="n">type</span> <span class="o">=</span> <span class="n">TYPE_PAIR</span><span class="p">;</span>
|
|
<span class="n">CAR</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">car</span><span class="p">;</span>
|
|
<span class="n">CDR</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">cdr</span><span class="p">;</span>
|
|
<span class="k">return</span> <span class="n">obj</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Because the MPS is <a class="reference internal" href="../glossary/a.html#term-asynchronous-garbage-collector"><em class="xref std std-term">asynchronous</em></a>, it might scan any reachable object at any time, including
|
|
immediately after the object has been allocated. In this case, if the
|
|
MPS attempts to scan <tt class="docutils literal"><span class="pre">obj</span></tt> at the indicated point, the object’s
|
|
<tt class="docutils literal"><span class="pre">type</span></tt> field will be uninitialized, and so the <a class="reference internal" href="../glossary/s.html#term-scan-method"><em class="xref std std-term">scan method</em></a>
|
|
may abort.</p>
|
|
<p>The MPS solves this problem via the fast, nearly lock-free
|
|
<a class="reference internal" href="../topic/allocation.html#topic-allocation-point-protocol"><em>Allocation point protocol</em></a>. This needs an additional
|
|
structure, an <a class="reference internal" href="../glossary/a.html#term-allocation-point"><em class="xref std std-term">allocation point</em></a>, to be attached to the pool by
|
|
calling <a class="reference internal" href="../topic/allocation.html#mps_ap_create_k" title="mps_ap_create_k"><tt class="xref c c-func docutils literal"><span class="pre">mps_ap_create_k()</span></tt></a>:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">mps_ap_t</span> <span class="n">obj_ap</span><span class="p">;</span>
|
|
|
|
<span class="cm">/* ... */</span>
|
|
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">mps_ap_create_k</span><span class="p">(</span><span class="o">&</span><span class="n">obj_ap</span><span class="p">,</span> <span class="n">obj_pool</span><span class="p">,</span> <span class="n">mps_args_none</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"Couldn't create obj allocation point"</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>And then the constructor can be implemented like this:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">obj_t</span> <span class="nf">make_pair</span><span class="p">(</span><span class="n">obj_t</span> <span class="n">car</span><span class="p">,</span> <span class="n">obj_t</span> <span class="n">cdr</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">obj_t</span> <span class="n">obj</span><span class="p">;</span>
|
|
<span class="n">mps_addr_t</span> <span class="n">addr</span><span class="p">;</span>
|
|
<span class="kt">size_t</span> <span class="n">size</span> <span class="o">=</span> <span class="n">ALIGN</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">pair_s</span><span class="p">));</span>
|
|
<span class="k">do</span> <span class="p">{</span>
|
|
<span class="n">mps_res_t</span> <span class="n">res</span> <span class="o">=</span> <span class="n">mps_reserve</span><span class="p">(</span><span class="o">&</span><span class="n">addr</span><span class="p">,</span> <span class="n">obj_ap</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"out of memory in make_pair"</span><span class="p">);</span>
|
|
<span class="n">obj</span> <span class="o">=</span> <span class="n">addr</span><span class="p">;</span>
|
|
<span class="n">obj</span><span class="o">-></span><span class="n">pair</span><span class="p">.</span><span class="n">type</span> <span class="o">=</span> <span class="n">TYPE_PAIR</span><span class="p">;</span>
|
|
<span class="n">CAR</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">car</span><span class="p">;</span>
|
|
<span class="n">CDR</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">cdr</span><span class="p">;</span>
|
|
<span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">mps_commit</span><span class="p">(</span><span class="n">obj_ap</span><span class="p">,</span> <span class="n">addr</span><span class="p">,</span> <span class="n">size</span><span class="p">));</span>
|
|
<span class="k">return</span> <span class="n">obj</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>The function <a class="reference internal" href="../topic/allocation.html#mps_reserve" title="mps_reserve"><tt class="xref c c-func docutils literal"><span class="pre">mps_reserve()</span></tt></a> allocates a block of memory that
|
|
the MPS knows is uninitialized: the MPS promises not to scan this
|
|
block or move it until after it is <a class="reference internal" href="../glossary/c.html#term-committed-2"><em class="xref std std-term">committed<sup>(2)</sup></em></a> by calling
|
|
<a class="reference internal" href="../topic/allocation.html#mps_commit" title="mps_commit"><tt class="xref c c-func docutils literal"><span class="pre">mps_commit()</span></tt></a>. So the new object can be initialized safely.</p>
|
|
<p>However, there’s a second problem:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre> <span class="n">CAR</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">car</span><span class="p">;</span>
|
|
<span class="n">CDR</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="o">=</span> <span class="n">cdr</span><span class="p">;</span>
|
|
|
|
<span class="cm">/* What if the MPS moves car or cdr just now? */</span>
|
|
|
|
<span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">mps_commit</span><span class="p">(</span><span class="n">obj_ap</span><span class="p">,</span> <span class="n">addr</span><span class="p">,</span> <span class="n">size</span><span class="p">));</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Because <tt class="docutils literal"><span class="pre">obj</span></tt> is not yet committed, the MPS won’t scan it, and that
|
|
means that it won’t discover that it contains references to <tt class="docutils literal"><span class="pre">car</span></tt>
|
|
and <tt class="docutils literal"><span class="pre">cdr</span></tt>, and so won’t update these references to point to their
|
|
new locations.</p>
|
|
<p>In such a circumstance (that is, when objects have moved since you
|
|
called <a class="reference internal" href="../topic/allocation.html#mps_reserve" title="mps_reserve"><tt class="xref c c-func docutils literal"><span class="pre">mps_reserve()</span></tt></a>), <a class="reference internal" href="../topic/allocation.html#mps_commit" title="mps_commit"><tt class="xref c c-func docutils literal"><span class="pre">mps_commit()</span></tt></a> returns false, and
|
|
we have to initialize the object again (most conveniently done via a
|
|
<tt class="docutils literal"><span class="pre">while</span></tt> loop, as here).</p>
|
|
<div class="admonition-note admonition">
|
|
<p class="first admonition-title">Notes</p>
|
|
<ol class="last arabic simple">
|
|
<li>When using the <a class="reference internal" href="../topic/allocation.html#topic-allocation-point-protocol"><em>Allocation point protocol</em></a> it is up
|
|
to you to ensure that the requested size is aligned, because
|
|
<a class="reference internal" href="../topic/allocation.html#mps_reserve" title="mps_reserve"><tt class="xref c c-func docutils literal"><span class="pre">mps_reserve()</span></tt></a> is on the MPS’s <a class="reference internal" href="../glossary/c.html#term-critical-path"><em class="xref std std-term">critical path</em></a>,
|
|
and so it is highly optimized: in nearly all cases it is just
|
|
an increment to a pointer and a test.</li>
|
|
<li>It is very rare for <a class="reference internal" href="../topic/allocation.html#mps_commit" title="mps_commit"><tt class="xref c c-func docutils literal"><span class="pre">mps_commit()</span></tt></a> to return false, but
|
|
in the course of millions of allocations even very rare events
|
|
occur, so it is important not to do anything you don’t want to
|
|
repeat between calling <a class="reference internal" href="../topic/allocation.html#mps_reserve" title="mps_reserve"><tt class="xref c c-func docutils literal"><span class="pre">mps_reserve()</span></tt></a> and
|
|
<a class="reference internal" href="../topic/allocation.html#mps_commit" title="mps_commit"><tt class="xref c c-func docutils literal"><span class="pre">mps_commit()</span></tt></a>. Also, the shorter the interval, the less
|
|
likely <a class="reference internal" href="../topic/allocation.html#mps_commit" title="mps_commit"><tt class="xref c c-func docutils literal"><span class="pre">mps_commit()</span></tt></a> is to return false.</li>
|
|
</ol>
|
|
</div>
|
|
<div class="admonition-topic admonition">
|
|
<p class="first admonition-title">Topic</p>
|
|
<p class="last"><a class="reference internal" href="../topic/allocation.html#topic-allocation"><em>Allocation</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="maintaining-consistency">
|
|
<span id="index-15"></span><h2>3.10. Maintaining consistency<a class="headerlink" href="#maintaining-consistency" title="Permalink to this headline">¶</a></h2>
|
|
<p>The MPS is <a class="reference internal" href="../glossary/a.html#term-asynchronous-garbage-collector"><em class="xref std std-term">asynchronous</em></a>:
|
|
this means that it might be scanning, moving, or collecting, at any
|
|
point in time (potentially, between any pair of instructions in your
|
|
program). So you must make sure that your data structures always obey
|
|
these rules:</p>
|
|
<ol class="arabic">
|
|
<li><p class="first">A <a class="reference internal" href="../glossary/r.html#term-root"><em class="xref std std-term">root</em></a> must be scannable by its root scanning function as
|
|
soon as it has been registered.</p>
|
|
<p>See the discussion of the <a class="reference internal" href="#guide-lang-roots-rehash"><em>global symbol table</em></a> in the toy Scheme interpreter.</p>
|
|
</li>
|
|
<li><p class="first">A <a class="reference internal" href="../glossary/f.html#term-formatted-object"><em class="xref std std-term">formatted object</em></a> must be scannable by the <a class="reference internal" href="../glossary/s.html#term-scan-method"><em class="xref std std-term">scan
|
|
method</em></a> as soon as it has been <a class="reference internal" href="../glossary/c.html#term-committed-2"><em class="xref std std-term">committed<sup>(2)</sup></em></a> by calling
|
|
<a class="reference internal" href="../topic/allocation.html#mps_commit" title="mps_commit"><tt class="xref c c-func docutils literal"><span class="pre">mps_commit()</span></tt></a>.</p>
|
|
<p>See the discussion of the <a class="reference internal" href="#guide-lang-allocation"><em>pair constructor</em></a> in the toy Scheme interpreter.</p>
|
|
</li>
|
|
<li><p class="first">All objects in automatically managed pools that are
|
|
<a class="reference internal" href="../glossary/r.html#term-reachable"><em class="xref std std-term">reachable</em></a> by your code must always be provably reachable
|
|
from a root via a chain of <a class="reference internal" href="../glossary/r.html#term-reference"><em class="xref std std-term">references</em></a> that are
|
|
<a class="reference internal" href="../glossary/f.html#term-fix"><em class="xref std std-term">fixed</em></a> by a scanning function.</p>
|
|
<p>See the discussion of the <a class="reference internal" href="#guide-lang-roots-rehash"><em>global symbol table</em></a> in the toy Scheme interpreter.</p>
|
|
</li>
|
|
<li><p class="first">Formatted objects must remain scannable throughout their
|
|
<a class="reference internal" href="../glossary/l.html#term-lifetime"><em class="xref std std-term">lifetime</em></a>.</p>
|
|
</li>
|
|
</ol>
|
|
<p>Examples of code that breaks these rules, together with tactics for
|
|
tracking down the causes, appear in the chapter <a class="reference internal" href="debug.html#guide-debug"><em>Debugging with the Memory Pool System</em></a>.</p>
|
|
</div>
|
|
<div class="section" id="tidying-up">
|
|
<span id="index-16"></span><h2>3.11. Tidying up<a class="headerlink" href="#tidying-up" title="Permalink to this headline">¶</a></h2>
|
|
<p>When your program is done with the MPS, it’s good practice to tear
|
|
down all the MPS data structures. This causes the MPS to check the
|
|
consistency of its data structures and report any problems it
|
|
detects. It also causes the MPS to flush its <a class="reference internal" href="../glossary/t.html#term-telemetry-stream"><em class="xref std std-term">telemetry stream</em></a>.</p>
|
|
<p>MPS data structures must be destroyed or deregistered in the reverse
|
|
order to that in which they were registered or created. So you must
|
|
destroy all <a class="reference internal" href="../glossary/a.html#term-allocation-point"><em class="xref std std-term">allocation points</em></a> created in a
|
|
<a class="reference internal" href="../glossary/p.html#term-pool"><em class="xref std std-term">pool</em></a> before destroying the pool; destroy all <a class="reference internal" href="../glossary/r.html#term-root"><em class="xref std std-term">roots</em></a> and pools, and deregister all <a class="reference internal" href="../glossary/t.html#term-thread"><em class="xref std std-term">threads</em></a>, that
|
|
were created in an <a class="reference internal" href="../glossary/a.html#term-arena"><em class="xref std std-term">arena</em></a> before destroying the arena, and so
|
|
on.</p>
|
|
<p>Here’s the tear-down code from the toy Scheme interpreter:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="n">mps_ap_destroy</span><span class="p">(</span><span class="n">obj_ap</span><span class="p">);</span>
|
|
<span class="n">mps_pool_destroy</span><span class="p">(</span><span class="n">obj_pool</span><span class="p">);</span>
|
|
<span class="n">mps_chain_destroy</span><span class="p">(</span><span class="n">obj_chain</span><span class="p">);</span>
|
|
<span class="n">mps_fmt_destroy</span><span class="p">(</span><span class="n">obj_fmt</span><span class="p">);</span>
|
|
<span class="n">mps_root_destroy</span><span class="p">(</span><span class="n">reg_root</span><span class="p">);</span>
|
|
<span class="n">mps_thread_dereg</span><span class="p">(</span><span class="kr">thread</span><span class="p">);</span>
|
|
<span class="n">mps_arena_destroy</span><span class="p">(</span><span class="n">arena</span><span class="p">);</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="what-next">
|
|
<h2>3.12. What next?<a class="headerlink" href="#what-next" title="Permalink to this headline">¶</a></h2>
|
|
<p>This article has covered the basic knowledge needed to add
|
|
incremental, moving, generational garbage collection to the runtime
|
|
system for a programming language.</p>
|
|
<p>If everything is working for your language, then the next step is
|
|
the chapter <a class="reference internal" href="perf.html#guide-perf"><em>Tuning the Memory Pool System for performance</em></a>.</p>
|
|
<p>But in the more likely event that things don’t work out quite as
|
|
smoothly for your language as they did in the toy Scheme interpreter,
|
|
then you’ll be more interested in the chapter <a class="reference internal" href="debug.html#guide-debug"><em>Debugging with the Memory Pool System</em></a>.</p>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sphinxsidebar">
|
|
<div class="sphinxsidebarwrapper">
|
|
<p class="logo"><a href="../index.html">
|
|
<img class="logo" src="../_static/logo.png" alt="Logo"/>
|
|
</a></p>
|
|
<h3><a href="../index.html">Table Of Contents</a></h3>
|
|
<ul>
|
|
<li><a class="reference internal" href="#">3. Garbage collecting a language with the Memory Pool System</a><ul>
|
|
<li><a class="reference internal" href="#the-scheme-interpreter">3.1. The Scheme interpreter</a></li>
|
|
<li><a class="reference internal" href="#choosing-an-arena-class">3.2. Choosing an arena class</a></li>
|
|
<li><a class="reference internal" href="#choosing-a-pool-class">3.3. Choosing a pool class</a></li>
|
|
<li><a class="reference internal" href="#describing-your-objects">3.4. Describing your objects</a><ul>
|
|
<li><a class="reference internal" href="#the-scan-method">3.4.1. The scan method</a></li>
|
|
<li><a class="reference internal" href="#the-skip-method">3.4.2. The skip method</a></li>
|
|
<li><a class="reference internal" href="#the-forward-method">3.4.3. The forward method</a></li>
|
|
<li><a class="reference internal" href="#the-is-forwarded-method">3.4.4. The is-forwarded method</a></li>
|
|
<li><a class="reference internal" href="#the-padding-method">3.4.5. The padding method</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="reference internal" href="#generation-chains">3.5. Generation chains</a></li>
|
|
<li><a class="reference internal" href="#creating-the-pool">3.6. Creating the pool</a></li>
|
|
<li><a class="reference internal" href="#roots">3.7. Roots</a></li>
|
|
<li><a class="reference internal" href="#threads">3.8. Threads</a></li>
|
|
<li><a class="reference internal" href="#allocation">3.9. Allocation</a></li>
|
|
<li><a class="reference internal" href="#maintaining-consistency">3.10. Maintaining consistency</a></li>
|
|
<li><a class="reference internal" href="#tidying-up">3.11. Tidying up</a></li>
|
|
<li><a class="reference internal" href="#what-next">3.12. What next?</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
|
|
<h4>Previous topic</h4>
|
|
<p class="topless"><a href="build.html"
|
|
title="previous chapter">2. Building the Memory Pool System</a></p>
|
|
<h4>Next topic</h4>
|
|
<p class="topless"><a href="debug.html"
|
|
title="next chapter">4. Debugging with the Memory Pool System</a></p><h4>Downloads</h4>
|
|
|
|
<p class="topless">
|
|
<a href="http://www.ravenbrook.com/project/mps/release/1.111.0/">MPS Kit release 1.111.0</a><br>
|
|
<a href="http://www.ravenbrook.com/project/mps/release/">All MPS Kit releases</a>
|
|
</p>
|
|
|
|
<h4>Issues</h4>
|
|
|
|
<p class="topless">
|
|
<a href="http://www.ravenbrook.com/project/mps/issue/?action=list&view=status%3dopen&display=Job:Priority:Title&sort=Priority">Known issues</a><br>
|
|
<a href="http://www.ravenbrook.com/project/mps/issue/?action=fixed&release_fixed=1.111.0">Issues fixed in release 1.111.0</a>
|
|
</p><h4>Contact us</h4>
|
|
|
|
<p class="topless"><a href="mailto:mps-questions@ravenbrook.com">mps-questions@ravenbrook.com</a></p>
|
|
</div>
|
|
</div>
|
|
<div class="clearer"></div>
|
|
</div>
|
|
<div class="related">
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li class="right" style="margin-right: 10px">
|
|
<a href="../genindex.html" title="General Index"
|
|
>index</a></li>
|
|
<li class="right" >
|
|
<a href="debug.html" title="4. Debugging with the Memory Pool System"
|
|
>next</a> |</li>
|
|
<li class="right" >
|
|
<a href="build.html" title="2. Building the Memory Pool System"
|
|
>previous</a> |</li>
|
|
<li><a href="../index.html">Memory Pool System 1.111.0 documentation</a> »</li>
|
|
<li><a href="index.html" >Guide</a> »</li>
|
|
</ul>
|
|
</div>
|
|
<div class="footer">
|
|
© <a href="../copyright.html">Copyright</a> 2013, Ravenbrook Limited.
|
|
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
|
|
</div>
|
|
</body>
|
|
</html> |