From 1c583cde131b2a6fc74f33e76d85142c3da19d98 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 19 Feb 2014 18:25:40 +0000 Subject: [PATCH] Naive nailboard implementation (complete). Copied from Perforce Change: 184395 ServerID: perforce.ravenbrook.com --- mps/code/nailboard.c | 163 ++++++++++++++++++++--------- mps/code/nailboard.h | 16 +-- mps/design/index.txt | 30 +++--- mps/design/nailboard.txt | 27 +++++ mps/manual/source/design/index.rst | 1 + 5 files changed, 168 insertions(+), 69 deletions(-) diff --git a/mps/code/nailboard.c b/mps/code/nailboard.c index 5ddf13e0069..a32f619e145 100644 --- a/mps/code/nailboard.c +++ b/mps/code/nailboard.c @@ -15,31 +15,61 @@ SRCID(nailboard, "$Id$"); Bool NailboardCheck(Nailboard board) { + Index i; CHECKS(Nailboard, board); CHECKU(Arena, board->arena); CHECKL(RangeCheck(&board->range)); - /* nails is >= number of set bits in mark, but we can't check this */ - /* We know that shift corresponds to pool->align. */ - CHECKL(BoolCheck(board->newNails)); + CHECKL(board->levels <= NAILBOARD_MAX_LEVELS); + CHECKL(0 < board->alignShift); + CHECKL(0 < board->levelShift); + for (i = 0; i < board->levels; ++i) { + /* weak check for BTs @@@@ */ + CHECKL(board->level[i] != NULL); + } + /* distinctNails must be the same as the number of set bits in + * level[0].mark, but we don't want to check this as it's O(n). + */ CHECKL(board->distinctNails <= board->nails); - /* weak check for BTs @@@@ */ - CHECKL(board->mark != NULL); + CHECKL(BoolCheck(board->newNails)); return TRUE; } +static Size nailboardSize(Count bits, Count levels, Shift shift) +{ + Index i; + Size size; + AVER(bits >> ((levels - 1) * shift) != 0); + AVER(bits >> (levels * shift) == 0); + size = 0; + for (i = 0; i < levels; ++i) { + size += BTSize(bits >> (i * shift)); + } + return size; +} + Res NailboardCreate(Nailboard *boardReturn, Arena arena, Align alignment, Addr base, Addr limit) { void *p; Nailboard board; - Count bits; + Count bits, levels; + Index i; + Size size; Res res; + Shift levelShift = MPS_WORD_SHIFT; AVER(boardReturn != NULL); AVERT(Arena, arena); + AVERT(Align, alignment); AVER(base < limit); + AVER(AddrIsAligned(base, alignment)); + AVER(AddrIsAligned(limit, alignment)); - res = ControlAlloc(&p, arena, sizeof(NailboardStruct), FALSE); + bits = AddrOffset(base, limit) / alignment; + levels = SizeRoundUp(SizeLog2(bits), levelShift) / levelShift; + AVER(levels <= NAILBOARD_MAX_LEVELS); + size = sizeof(NailboardStruct) + sizeof(BT*) * (levels - 1); + res = ControlAlloc(&p, arena, size, FALSE); if(res != ResOK) goto failAllocNailboard; board = p; @@ -47,20 +77,31 @@ Res NailboardCreate(Nailboard *boardReturn, Arena arena, Align alignment, board->nails = (Count)0; board->distinctNails = (Count)0; board->newNails = FALSE; - board->markShift = SizeLog2((Size)alignment); + board->levels = levels; + board->alignShift = SizeLog2(alignment); + board->levelShift = levelShift; RangeInit(&board->range, base, limit); - bits = RangeSize(&board->range) >> board->markShift; - res = ControlAlloc(&p, arena, BTSize(bits), FALSE); + + res = ControlAlloc(&p, arena, nailboardSize(bits, levels, levelShift), FALSE); if(res != ResOK) - goto failMarkTable; - board->mark = p; - BTResRange(board->mark, 0, bits); + goto failAllocNails; + + AVER(bits == RangeSize(&board->range) >> board->alignShift); + for (i = 0; i < levels; ++i) { + AVER(bits > 0); + board->level[i] = p; + BTResRange(board->level[i], 0, bits); + p = AddrAdd(p, BTSize(bits)); + bits >>= levelShift; + } + AVER(bits == 0); + board->sig = NailboardSig; AVERT(Nailboard, board); *boardReturn = board; return ResOK; -failMarkTable: +failAllocNails: ControlFree(arena, board, sizeof(NailboardStruct)); failAllocNailboard: return res; @@ -72,17 +113,18 @@ void NailboardDestroy(Nailboard board) Count bits; AVERT(Nailboard, board); - arena = board->arena; - bits = RangeSize(&board->range) >> board->markShift; - ControlFree(board->arena, board->mark, BTSize(bits)); + arena = board->arena; + bits = RangeSize(&board->range) >> board->alignShift; + ControlFree(arena, board->level[0], + nailboardSize(bits, board->levels, board->levelShift)); board->sig = SigInvalid; ControlFree(arena, board, sizeof(NailboardStruct)); } Align NailboardAlignment(Nailboard board) { - return (Align)1 << board->markShift; + return (Align)1 << board->alignShift; } void NailboardClearNewNails(Nailboard board) @@ -95,77 +137,102 @@ Bool NailboardNewNails(Nailboard board) return board->newNails; } -/* nailboardIndex -- return the index of the nail corresponding to addr */ - -static Index nailboardIndex(Nailboard board, Addr addr) +/* nailboardIndex -- return the index of the nail corresponding to + * addr in the given level. + */ +static Index nailboardIndex(Nailboard board, Index level, Addr addr) { - return AddrOffset(RangeBase(&board->range), addr) >> board->markShift; + AVERT(Nailboard, board); + AVER(level < board->levels); + AVER(RangeBase(&board->range) <= addr); + AVER(addr <= RangeLimit(&board->range)); + + return AddrOffset(RangeBase(&board->range), addr) + >> (board->alignShift + level * board->levelShift); } /* nailboardIndexRange -- update *ibaseReturn and *ilimitReturn to be * the indexes of the nail corresponding to base and limit - * respectively. + * respectively, in the given level. */ static void nailboardIndexRange(Index *ibaseReturn, Index *ilimitReturn, - Nailboard board, Addr base, Addr limit) + Nailboard board, Index level, + Addr base, Addr limit) { - AVERT(Nailboard, board); - AVER(RangeBase(&board->range) <= base); - AVER(base <= limit); - AVER(limit <= RangeLimit(&board->range)); + AVER(base < limit); - *ibaseReturn = nailboardIndex(board, base); - *ilimitReturn = nailboardIndex(board, limit); + *ibaseReturn = nailboardIndex(board, level, base); + *ilimitReturn = nailboardIndex(board, level, AddrSub(limit, 1)) + 1; } Bool NailboardGet(Nailboard board, Addr addr) { AVERT(Nailboard, board); AVER(RangeContains(&board->range, addr)); - return BTGet(board->mark, nailboardIndex(board, addr)); + return BTGet(board->level[0], nailboardIndex(board, 0, addr)); } Bool NailboardSet(Nailboard board, Addr addr) { - Index i; + Index i, j; AVERT(Nailboard, board); AVER(RangeContains(&board->range, addr)); ++ board->nails; - i = nailboardIndex(board, addr); - if (!BTGet(board->mark, i)) { - BTSet(board->mark, i); - board->newNails = TRUE; - ++ board->distinctNails; - return FALSE; + j = nailboardIndex(board, 0, addr); + if (BTGet(board->level[0], j)) { + return TRUE; } - return TRUE; + BTSet(board->level[0], j); + board->newNails = TRUE; + ++ board->distinctNails; + for (i = 1; i < board->levels; ++i) { + j = nailboardIndex(board, i, addr); + if (BTGet(board->level[i], j)) { + break; + } + BTSet(board->level[i], j); + } + return FALSE; } void NailboardSetRange(Nailboard board, Addr base, Addr limit) { - Index ibase, ilimit; - nailboardIndexRange(&ibase, &ilimit, board, base, limit); - AVER(BTIsResRange(board->mark, ibase, ilimit)); - BTSetRange(board->mark, ibase, ilimit); + Index i, ibase, ilimit; + nailboardIndexRange(&ibase, &ilimit, board, 0, base, limit); + AVER(BTIsResRange(board->level[0], ibase, ilimit)); + BTSetRange(board->level[0], ibase, ilimit); board->nails += ilimit - ibase; board->distinctNails += ilimit - ibase; + for (i = 1; i < board->levels; ++i) { + nailboardIndexRange(&ibase, &ilimit, board, i, base, limit); + BTSetRange(board->level[i], ibase, ilimit); + } } Bool NailboardIsSetRange(Nailboard board, Addr base, Addr limit) { Index ibase, ilimit; - nailboardIndexRange(&ibase, &ilimit, board, base, limit); + AVERT(Nailboard, board); + nailboardIndexRange(&ibase, &ilimit, board, 0, base, limit); return board->distinctNails >= ilimit - ibase - && BTIsSetRange(board->mark, ibase, ilimit); + && BTIsSetRange(board->level[0], ibase, ilimit); } Bool NailboardIsResRange(Nailboard board, Addr base, Addr limit) { - Index ibase, ilimit; - nailboardIndexRange(&ibase, &ilimit, board, base, limit); - return BTIsResRange(board->mark, ibase, ilimit); + Index i; + AVERT(Nailboard, board); + i = board->levels; + while (i > 0) { + Index ibase, ilimit; + i -= 1; + nailboardIndexRange(&ibase, &ilimit, board, i, base, limit); + if (BTIsResRange(board->level[i], ibase, ilimit)) + return TRUE; + } + return FALSE; } diff --git a/mps/code/nailboard.h b/mps/code/nailboard.h index e211feba78d..fa1240a5435 100644 --- a/mps/code/nailboard.h +++ b/mps/code/nailboard.h @@ -12,17 +12,21 @@ #include "mpmtypes.h" #include "range.h" +#define NAILBOARD_MAX_LEVELS ((MPS_WORD_WIDTH + MPS_WORD_SHIFT - 1) / MPS_WORD_SHIFT) + typedef struct NailboardStruct *Nailboard; typedef struct NailboardStruct { Sig sig; Arena arena; - RangeStruct range; /* range covered by nailboard */ - Shift markShift; /* to convert offset into bit index for mark */ - BT mark; /* mark table used to record ambiguous fixes */ - Count nails; /* no. of ambigFixes, not necessarily distinct */ - Count distinctNails; /* number of distinct ambigFixes */ - Bool newNails; /* set to TRUE if a new nail is set */ + RangeStruct range; /* range of addresses covered by nailboard */ + Count levels; /* number of levels */ + Count nails; /* number of calls to NailboardSet */ + Count distinctNails; /* number of nails in the board */ + Bool newNails; /* set to TRUE if a new nail is set */ + Shift alignShift; /* shift due to address alignment */ + Shift levelShift; /* additional shift for each level */ + BT level[1]; /* bit tables for each level */ } NailboardStruct; #define NailboardSig ((Sig)0x5194A17B) /* SIGnature NAILBoard */ diff --git a/mps/design/index.txt b/mps/design/index.txt index 27b9b3a6f48..d5e9d390dc2 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -191,21 +191,21 @@ References Document History ---------------- -- 2002-05-23 RB_ Created empty catalogue based on P4DTI design document catalogue. -- 2002-06-07 RB_ Added a bunch of design documents referenced by the source code. -- 2002-06-21 NB_ Remove P4DTI reference, which doesn't fit here. Maybe one day we'll have a corporate design document procedure. -- 2002-06-24 RB_ Added fix, object-debug, thread-manager, and thread-safety. -- 2007-02-08 RHSK Added message-gc and shield. -- 2007-06-12 RHSK Added cstyle. -- 2007-06-28 RHSK Added diag. -- 2008-12-04 RHSK Added tests. -- 2008-12-10 RHSK Correct description of message-gc: gc begin or end. -- 2012-09-14 RB_ Added link to critical-path -- 2013-05-10 RB_ Fixed link to sig and added guide.hex.trans -- 2013-05-22 GDR_ Add link to keyword-arguments. -- 2013-05-25 RB_ Replacing "cstyle" with reworked "guide.impl.c.format". -- 2013-06-07 RB_ Converting to reST_. Linking to [RB_2002-06-18]_. -- 2014-01-17 GDR_ Add abq, nailboard, range. +- 2002-05-23 RB_ Created empty catalogue based on P4DTI design document catalogue. +- 2002-06-07 RB_ Added a bunch of design documents referenced by the source code. +- 2002-06-21 NB_ Remove P4DTI reference, which doesn't fit here. Maybe one day we'll have a corporate design document procedure. +- 2002-06-24 RB_ Added fix, object-debug, thread-manager, and thread-safety. +- 2007-02-08 RHSK Added message-gc and shield. +- 2007-06-12 RHSK Added cstyle. +- 2007-06-28 RHSK Added diag. +- 2008-12-04 RHSK Added tests. +- 2008-12-10 RHSK Correct description of message-gc: gc begin or end. +- 2012-09-14 RB_ Added link to critical-path +- 2013-05-10 RB_ Fixed link to sig and added guide.hex.trans +- 2013-05-22 GDR_ Add link to keyword-arguments. +- 2013-05-25 RB_ Replacing "cstyle" with reworked "guide.impl.c.format". +- 2013-06-07 RB_ Converting to reST_. Linking to [RB_2002-06-18]_. +- 2014-01-17 GDR_ Add abq, nailboard, range. .. _RB: http://www.ravenbrook.com/consultants/rb .. _NB: http://www.ravenbrook.com/consultants/nb diff --git a/mps/design/nailboard.txt b/mps/design/nailboard.txt index e7d9c8bb95b..45c9e44e5d2 100644 --- a/mps/design/nailboard.txt +++ b/mps/design/nailboard.txt @@ -52,6 +52,33 @@ logarithmic in the size of the range. (Because scanning overhead must be proportional to the number of objects, not to their size.) +Overview +-------- + +We maintain a (level 0) bit table with one bit for each (aligned) +address in the range. In addition, we maintain a (level 1) bit table +with one bit for each ``scale`` bits in the level 0 bit table (this +bit is set if any bit in the corresponding word in the level 0 table +is set). And so on until we reach the level *k* bit table which is +just one word long. + +The size of the level *i* bit table is the ceiling of + + (``limit`` − ``base``) / (``align`` × ``scale``\ :superscript:`i`\ ) + +where ``base`` and ``limit`` are the bounds of the address range being +represented in the nailboard, ``align`` is the pool alignment. + +The address *a* may be looked up in the level *i* bit table at the bit + + (*a* − ``base``) / (``align`` × ``scale``\ :superscript:`i`\ ) + +and since ``align`` and ``scale`` are powers of 2, that's + + (*a* − ``base``) >> (log\ :subscript:`2`\ ``align`` + *i* log\ :subscript:`2`\ ``scale``) + + + Interface --------- diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 3cf6719ac74..f7207cc9950 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -14,6 +14,7 @@ Design guide.hex.trans guide.impl.c.format keyword-arguments + nailboard range ring sig