diff options
| author | Simon Marlow <simonmar@microsoft.com> | 2007-07-27 10:41:57 +0000 |
|---|---|---|
| committer | Simon Marlow <simonmar@microsoft.com> | 2007-07-27 10:41:57 +0000 |
| commit | 6015a94f9108a502150565577b66c23650796639 (patch) | |
| tree | 20d499d1a9644c2c98374d99f511a4a1c2cb7d1d /rts/sm/GC.c | |
| parent | 04d444716b2e5415fb8f13771e49f1192ef8c8f8 (diff) | |
| download | haskell-6015a94f9108a502150565577b66c23650796639.tar.gz | |
Pointer Tagging
This patch implements pointer tagging as per our ICFP'07 paper "Faster
laziness using dynamic pointer tagging". It improves performance by
10-15% for most workloads, including GHC itself.
The original patches were by Alexey Rodriguez Yakushev
<mrchebas@gmail.com>, with additions and improvements by me. I've
re-recorded the development as a single patch.
The basic idea is this: we use the low 2 bits of a pointer to a heap
object (3 bits on a 64-bit architecture) to encode some information
about the object pointed to. For a constructor, we encode the "tag"
of the constructor (e.g. True vs. False), for a function closure its
arity. This enables some decisions to be made without dereferencing
the pointer, which speeds up some common operations. In particular it
enables us to avoid costly indirect jumps in many cases.
More information in the commentary:
http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/HaskellExecution/PointerTagging
Diffstat (limited to 'rts/sm/GC.c')
| -rw-r--r-- | rts/sm/GC.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/rts/sm/GC.c b/rts/sm/GC.c index 1fee394139..216d3cbe44 100644 --- a/rts/sm/GC.c +++ b/rts/sm/GC.c @@ -1031,6 +1031,7 @@ GarbageCollect ( rtsBool force_major_gc ) closure if it is alive, or NULL otherwise. NOTE: Use it before compaction only! + It untags and (if needed) retags pointers to closures. -------------------------------------------------------------------------- */ @@ -1039,8 +1040,12 @@ isAlive(StgClosure *p) { const StgInfoTable *info; bdescr *bd; + StgWord tag; while (1) { + /* The tag and the pointer are split, to be merged later when needed. */ + tag = GET_CLOSURE_TAG(p); + p = UNTAG_CLOSURE(p); ASSERT(LOOKS_LIKE_CLOSURE_PTR(p)); info = get_itbl(p); @@ -1052,18 +1057,18 @@ isAlive(StgClosure *p) // for static closures with an empty SRT or CONSTR_STATIC_NOCAFs. // if (!HEAP_ALLOCED(p)) { - return p; + return TAG_CLOSURE(tag,p); } // ignore closures in generations that we're not collecting. bd = Bdescr((P_)p); if (bd->gen_no > N) { - return p; + return TAG_CLOSURE(tag,p); } // if it's a pointer into to-space, then we're done if (bd->flags & BF_EVACUATED) { - return p; + return TAG_CLOSURE(tag,p); } // large objects use the evacuated flag @@ -1073,7 +1078,7 @@ isAlive(StgClosure *p) // check the mark bit for compacted steps if ((bd->flags & BF_COMPACTED) && is_marked((P_)p,bd)) { - return p; + return TAG_CLOSURE(tag,p); } switch (info->type) { |
