diff --git a/mps/code/global.c b/mps/code/global.c index 9b535ecb25f..26439c3c2c8 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -614,7 +614,7 @@ Bool ArenaAccess(Addr addr, AccessSet mode, MutatorContext context) * thread. */ mode &= SegPM(seg); if (mode != AccessSetEMPTY) { - res = PoolAccess(SegPool(seg), seg, addr, mode, context); + res = SegAccess(seg, arena, addr, mode, context); AVER(res == ResOK); /* Mutator can't continue unless this succeeds */ } else { /* Protection was already cleared, for example by another thread diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 3f6edcb61bd..9346f03d850 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -221,8 +221,6 @@ extern BufferClass PoolDefaultBufferClass(Pool pool); extern Res PoolAlloc(Addr *pReturn, Pool pool, Size size); extern void PoolFree(Pool pool, Addr old, Size size); extern Res PoolTraceBegin(Pool pool, Trace trace); -extern Res PoolAccess(Pool pool, Seg seg, Addr addr, - AccessSet mode, MutatorContext context); extern void PoolFreeWalk(Pool pool, FreeBlockVisitor f, void *p); extern Size PoolTotalSize(Pool pool); extern Size PoolFreeSize(Pool pool); @@ -244,12 +242,6 @@ extern void PoolTrivBufferEmpty(Pool pool, Buffer buffer, extern Res PoolAbsDescribe(Inst inst, mps_lib_FILE *stream, Count depth); extern Res PoolNoTraceBegin(Pool pool, Trace trace); extern Res PoolTrivTraceBegin(Pool pool, Trace trace); -extern Res PoolNoAccess(Pool pool, Seg seg, Addr addr, - AccessSet mode, MutatorContext context); -extern Res PoolSegAccess(Pool pool, Seg seg, Addr addr, - AccessSet mode, MutatorContext context); -extern Res PoolSingleAccess(Pool pool, Seg seg, Addr addr, - AccessSet mode, MutatorContext context); extern Res PoolNoScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg); extern void PoolNoRampBegin(Pool pool, Buffer buf, Bool collectAll); extern void PoolTrivRampBegin(Pool pool, Buffer buf, Bool collectAll); @@ -644,6 +636,12 @@ extern void SegSetRankSet(Seg seg, RankSet rankSet); extern void SegSetRankAndSummary(Seg seg, RankSet rankSet, RefSet summary); extern Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi); extern Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at); +extern Res SegAccess(Seg seg, Arena arena, Addr addr, + AccessSet mode, MutatorContext context); +extern Res SegWholeAccess(Seg seg, Arena arena, Addr addr, + AccessSet mode, MutatorContext context); +extern Res SegSingleAccess(Seg seg, Arena arena, Addr addr, + AccessSet mode, MutatorContext context); extern Res SegWhiten(Seg seg, Trace trace); extern void SegGreyen(Seg seg, Trace trace); extern void SegBlacken(Seg seg, TraceSet traceSet); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index d8401c7152a..48e71426a56 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -59,7 +59,6 @@ typedef struct mps_pool_class_s { PoolFreeMethod free; /* free memory to pool */ PoolBufferFillMethod bufferFill; /* out-of-line reserve */ PoolBufferEmptyMethod bufferEmpty; /* out-of-line commit */ - PoolAccessMethod access; /* handles read/write accesses */ PoolRampBeginMethod rampBegin;/* begin a ramp pattern */ PoolRampEndMethod rampEnd; /* end a ramp pattern */ PoolFramePushMethod framePush; /* push an allocation frame */ @@ -219,6 +218,7 @@ typedef struct SegClassStruct { SegSetRankSummaryMethod setRankSummary; /* change rank set & summary */ SegMergeMethod merge; /* merge two adjacent segments */ SegSplitMethod split; /* split a segment into two */ + SegAccessMethod access; /* handles read/write accesses */ SegWhitenMethod whiten; /* whiten objects */ SegGreyenMethod greyen; /* greyen non-white objects */ SegBlackenMethod blacken; /* blacken grey objects without scanning */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 4f1af17f221..e75137053e7 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -164,6 +164,8 @@ typedef Res (*SegMergeMethod)(Seg seg, Seg segHi, Addr base, Addr mid, Addr limit); typedef Res (*SegSplitMethod)(Seg seg, Seg segHi, Addr base, Addr mid, Addr limit); +typedef Res (*SegAccessMethod)(Seg seg, Arena arena, Addr addr, + AccessSet mode, MutatorContext context); typedef Res (*SegWhitenMethod)(Seg seg, Trace trace); typedef void (*SegGreyenMethod)(Seg seg, Trace trace); typedef void (*SegBlackenMethod)(Seg seg, TraceSet traceSet); @@ -199,8 +201,6 @@ typedef Res (*PoolBufferFillMethod)(Addr *baseReturn, Addr *limitReturn, Pool pool, Buffer buffer, Size size); typedef void (*PoolBufferEmptyMethod)(Pool pool, Buffer buffer, Addr init, Addr limit); -typedef Res (*PoolAccessMethod)(Pool pool, Seg seg, Addr addr, - AccessSet mode, MutatorContext context); typedef void (*PoolRampBeginMethod)(Pool pool, Buffer buf, Bool collectAll); typedef void (*PoolRampEndMethod)(Pool pool, Buffer buf); typedef Res (*PoolFramePushMethod)(AllocFrame *frameReturn, diff --git a/mps/code/pool.c b/mps/code/pool.c index ab839eb2bb9..dff33b2859f 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -47,7 +47,6 @@ Bool PoolClassCheck(PoolClass klass) CHECKL(FUNCHECK(klass->free)); CHECKL(FUNCHECK(klass->bufferFill)); CHECKL(FUNCHECK(klass->bufferEmpty)); - CHECKL(FUNCHECK(klass->access)); CHECKL(FUNCHECK(klass->rampBegin)); CHECKL(FUNCHECK(klass->rampEnd)); CHECKL(FUNCHECK(klass->framePush)); @@ -267,20 +266,6 @@ void PoolFree(Pool pool, Addr old, Size size) } -Res PoolAccess(Pool pool, Seg seg, Addr addr, - AccessSet mode, MutatorContext context) -{ - AVERT(Pool, pool); - AVERT(Seg, seg); - AVER(SegBase(seg) <= addr); - AVER(addr < SegLimit(seg)); - AVERT(AccessSet, mode); - AVERT(MutatorContext, context); - - return Method(Pool, pool, access)(pool, seg, addr, mode, context); -} - - /* PoolFreeWalk -- walk free blocks in this pool * * PoolFreeWalk is not required to find all free blocks. diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c index 9deddbe3d93..35fc019a08d 100644 --- a/mps/code/poolabs.c +++ b/mps/code/poolabs.c @@ -59,7 +59,8 @@ void PoolClassMixInBuffer(PoolClass klass) void PoolClassMixInScan(PoolClass klass) { /* Can't check klass because it's not initialized yet */ - klass->access = PoolSegAccess; + /* FIXME: check that segment class has access != NoAcess */ + UNUSED(klass); } @@ -180,7 +181,6 @@ DEFINE_CLASS(Pool, AbstractPool, klass) klass->free = PoolNoFree; klass->bufferFill = PoolNoBufferFill; klass->bufferEmpty = PoolNoBufferEmpty; - klass->access = PoolNoAccess; klass->rampBegin = PoolNoRampBegin; klass->rampEnd = PoolNoRampEnd; klass->framePush = PoolNoFramePush; @@ -370,129 +370,6 @@ Res PoolTrivTraceBegin(Pool pool, Trace trace) return ResOK; } -/* NoAccess - * - * Should be used (for the access method) by Pool Classes which do - * not expect to ever have pages which the mutator will fault on. - * That is, no protected pages, or only pages which are inaccessible - * by the mutator are protected. - */ -Res PoolNoAccess(Pool pool, Seg seg, Addr addr, - AccessSet mode, MutatorContext context) -{ - AVERT(Pool, pool); - AVERT(Seg, seg); - AVER(SegBase(seg) <= addr); - AVER(addr < SegLimit(seg)); - AVERT(AccessSet, mode); - AVERT(MutatorContext, context); - UNUSED(mode); - UNUSED(context); - - NOTREACHED; - return ResUNIMPL; -} - - -/* SegAccess - * - * See also PoolSingleAccess - * - * Should be used (for the access method) by Pool Classes which intend - * to handle page faults by scanning the entire segment and lowering - * the barrier. - */ -Res PoolSegAccess(Pool pool, Seg seg, Addr addr, - AccessSet mode, MutatorContext context) -{ - AVERT(Pool, pool); - AVERT(Seg, seg); - AVER(SegBase(seg) <= addr); - AVER(addr < SegLimit(seg)); - AVER(SegPool(seg) == pool); - AVERT(AccessSet, mode); - AVERT(MutatorContext, context); - - UNUSED(addr); - UNUSED(context); - TraceSegAccess(PoolArena(pool), seg, mode); - return ResOK; -} - - -/* SingleAccess - * - * See also ArenaRead, and PoolSegAccess. - * - * Handles page faults by attempting emulation. If the faulting - * instruction cannot be emulated then this function returns ResFAIL. - * - * Due to the assumptions made below, pool classes should only use - * this function if all words in an object are tagged or traceable. - * - * .single-access.assume.ref: It currently assumes that the address - * being faulted on contains a plain reference or a tagged non-reference. - * .single-access.improve.format: Later this will be abstracted - * through the cleint object format interface, so that - * no such assumption is necessary. - */ -Res PoolSingleAccess(Pool pool, Seg seg, Addr addr, - AccessSet mode, MutatorContext context) -{ - Arena arena; - - AVERT(Pool, pool); - AVERT(Seg, seg); - AVER(SegBase(seg) <= addr); - AVER(addr < SegLimit(seg)); - AVER(SegPool(seg) == pool); - AVERT(AccessSet, mode); - AVERT(MutatorContext, context); - - arena = PoolArena(pool); - - if (MutatorContextCanStepInstruction(context)) { - Ref ref; - Res res; - - ShieldExpose(arena, seg); - - if(mode & SegSM(seg) & AccessREAD) { - /* Read access. */ - /* .single-access.assume.ref */ - /* .single-access.improve.format */ - ref = *(Ref *)addr; - /* .tagging: Check that the reference is aligned to a word boundary */ - /* (we assume it is not a reference otherwise). */ - if(WordIsAligned((Word)ref, sizeof(Word))) { - Rank rank; - /* See the note in TraceRankForAccess */ - /* (). */ - - rank = TraceRankForAccess(arena, seg); - TraceScanSingleRef(arena->flippedTraces, rank, arena, - seg, (Ref *)addr); - } - } - res = MutatorContextStepInstruction(context); - AVER(res == ResOK); - - /* Update SegSummary according to the possibly changed reference. */ - ref = *(Ref *)addr; - /* .tagging: ought to check the reference for a tag. But - * this is conservative. */ - SegSetSummary(seg, RefSetAdd(arena, SegSummary(seg), ref)); - - ShieldCover(arena, seg); - - return ResOK; - } else { - /* couldn't single-step instruction */ - return ResFAIL; - } -} - - void PoolNoRampBegin(Pool pool, Buffer buf, Bool collectAll) { AVERT(Pool, pool); diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index a2f0231d1ab..0afadaededa 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -48,6 +48,8 @@ SRCID(poolawl, "$Id$"); #define AWLSig ((Sig)0x519B7A37) /* SIGnature PooL AWL */ +static Res awlSegAccess(Seg seg, Arena arena, Addr addr, + AccessSet mode, MutatorContext context); static Res awlSegWhiten(Seg seg, Trace trace); static void awlSegGreyen(Seg seg, Trace trace); static void awlSegBlacken(Seg seg, TraceSet traceSet); @@ -291,6 +293,7 @@ DEFINE_CLASS(Seg, AWLSeg, klass) klass->instClassStruct.finish = AWLSegFinish; klass->size = sizeof(AWLSegStruct); klass->init = AWLSegInit; + klass->access = awlSegAccess; klass->whiten = awlSegWhiten; klass->greyen = awlSegGreyen; klass->blacken = awlSegBlacken; @@ -328,11 +331,12 @@ Bool AWLHaveTotalSALimit = AWL_HAVE_TOTAL_SA_LIMIT; /* Determine whether to permit scanning a single ref. */ -static Bool AWLCanTrySingleAccess(Arena arena, AWL awl, Seg seg, Addr addr) +static Bool awlSegCanTrySingleAccess(Arena arena, Seg seg, Addr addr) { AWLSeg awlseg; + AWL awl; - AVERT(AWL, awl); + AVERT(Arena, arena); AVERT(Seg, seg); AVER(addr != NULL); @@ -355,6 +359,7 @@ static Bool AWLCanTrySingleAccess(Arena arena, AWL awl, Seg seg, Addr addr) return FALSE; awlseg = MustBeA(AWLSeg, seg); + awl = MustBeA(AWLPool, SegPool(seg)); /* If there have been too many single accesses in a row then don't keep trying them, even if it means retaining objects. */ @@ -1124,24 +1129,25 @@ static void awlSegReclaim(Seg seg, Trace trace) } -/* AWLAccess -- handle a barrier hit */ +/* awlSegAccess -- handle a barrier hit */ -static Res AWLAccess(Pool pool, Seg seg, Addr addr, - AccessSet mode, MutatorContext context) +static Res awlSegAccess(Seg seg, Arena arena, Addr addr, + AccessSet mode, MutatorContext context) { - AWL awl = MustBeA(AWLPool, pool); + AWL awl; Res res; AVERT(Seg, seg); AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); - AVER(SegPool(seg) == pool); AVERT(AccessSet, mode); AVERT(MutatorContext, context); + awl = MustBeA(AWLPool, SegPool(seg)); + /* Attempt scanning a single reference if permitted */ - if(AWLCanTrySingleAccess(PoolArena(pool), awl, seg, addr)) { - res = PoolSingleAccess(pool, seg, addr, mode, context); + if(awlSegCanTrySingleAccess(arena, seg, addr)) { + res = SegSingleAccess(seg, arena, addr, mode, context); switch(res) { case ResOK: AWLNoteRefAccess(awl, seg, addr); @@ -1155,7 +1161,7 @@ static Res AWLAccess(Pool pool, Seg seg, Addr addr, } /* Have to scan the entire seg anyway. */ - res = PoolSegAccess(pool, seg, addr, mode, context); + res = SegWholeAccess(seg, arena, addr, mode, context); if(ResOK == res) { AWLNoteSegAccess(awl, seg, addr); } @@ -1249,7 +1255,6 @@ DEFINE_CLASS(Pool, AWLPool, klass) klass->bufferClass = RankBufClassGet; klass->bufferFill = AWLBufferFill; klass->bufferEmpty = AWLBufferEmpty; - klass->access = AWLAccess; klass->totalSize = AWLTotalSize; klass->freeSize = AWLFreeSize; } diff --git a/mps/code/seg.c b/mps/code/seg.c index 156f359b56c..b5f6c4fff22 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -686,6 +686,23 @@ failControl: } +/* SegAccess -- mutator read/write access to a segment */ + +Res SegAccess(Seg seg, Arena arena, Addr addr, + AccessSet mode, MutatorContext context) +{ + AVERT(Seg, seg); + AVERT(Arena, arena); + AVER(arena == PoolArena(SegPool(seg))); + AVER(SegBase(seg) <= addr); + AVER(addr < SegLimit(seg)); + AVERT(AccessSet, mode); + AVERT(MutatorContext, context); + + return Method(Seg, seg, access)(seg, arena, addr, mode, context); +} + + /* SegWhiten -- whiten objects */ Res SegWhiten(Seg seg, Trace trace) @@ -1145,6 +1162,127 @@ static Res segTrivSplit(Seg seg, Seg segHi, } +/* segNoAccess -- access method for non-GC segs + * + * Should be used (for the access method) by segment classes which do + * not expect to ever have pages which the mutator will fault on. That + * is, no protected pages, or only pages which are inaccessible by the + * mutator are protected. + */ +static Res segNoAccess(Seg seg, Arena arena, Addr addr, + AccessSet mode, MutatorContext context) +{ + AVERT(Seg, seg); + AVERT(Arena, arena); + AVER(SegBase(seg) <= addr); + AVER(addr < SegLimit(seg)); + AVERT(AccessSet, mode); + AVERT(MutatorContext, context); + UNUSED(mode); + UNUSED(context); + + NOTREACHED; + return ResUNIMPL; +} + + +/* SegWholeAccess + * + * See also SegSingleAccess + * + * Should be used (for the access method) by segment classes which + * intend to handle page faults by scanning the entire segment and + * lowering the barrier. + */ +Res SegWholeAccess(Seg seg, Arena arena, Addr addr, + AccessSet mode, MutatorContext context) +{ + AVERT(Seg, seg); + AVERT(Arena, arena); + AVER(arena == PoolArena(SegPool(seg))); + AVER(SegBase(seg) <= addr); + AVER(addr < SegLimit(seg)); + AVERT(AccessSet, mode); + AVERT(MutatorContext, context); + + UNUSED(addr); + UNUSED(context); + TraceSegAccess(arena, seg, mode); + return ResOK; +} + + +/* SegSingleAccess + * + * See also ArenaRead, and SegWhileAccess. + * + * Handles page faults by attempting emulation. If the faulting + * instruction cannot be emulated then this function returns ResFAIL. + * + * Due to the assumptions made below, segment classes should only use + * this function if all words in an object are tagged or traceable. + * + * .single-access.assume.ref: It currently assumes that the address + * being faulted on contains a plain reference or a tagged + * non-reference. + * + * .single-access.improve.format: Later this will be abstracted + * through the client object format interface, so that no such + * assumption is necessary. + */ +Res SegSingleAccess(Seg seg, Arena arena, Addr addr, + AccessSet mode, MutatorContext context) +{ + AVERT(Seg, seg); + AVERT(Arena, arena); + AVER(arena == PoolArena(SegPool(seg))); + AVER(SegBase(seg) <= addr); + AVER(addr < SegLimit(seg)); + AVERT(AccessSet, mode); + AVERT(MutatorContext, context); + + if (MutatorContextCanStepInstruction(context)) { + Ref ref; + Res res; + + ShieldExpose(arena, seg); + + if(mode & SegSM(seg) & AccessREAD) { + /* Read access. */ + /* .single-access.assume.ref */ + /* .single-access.improve.format */ + ref = *(Ref *)addr; + /* .tagging: Check that the reference is aligned to a word boundary */ + /* (we assume it is not a reference otherwise). */ + if(WordIsAligned((Word)ref, sizeof(Word))) { + Rank rank; + /* See the note in TraceRankForAccess */ + /* (). */ + + rank = TraceRankForAccess(arena, seg); + TraceScanSingleRef(arena->flippedTraces, rank, arena, + seg, (Ref *)addr); + } + } + res = MutatorContextStepInstruction(context); + AVER(res == ResOK); + + /* Update SegSummary according to the possibly changed reference. */ + ref = *(Ref *)addr; + /* .tagging: ought to check the reference for a tag. But + * this is conservative. */ + SegSetSummary(seg, RefSetAdd(arena, SegSummary(seg), ref)); + + ShieldCover(arena, seg); + + return ResOK; + } else { + /* couldn't single-step instruction */ + return ResFAIL; + } +} + + /* segNoWhiten -- whiten method for non-GC segs */ static Res segNoWhiten(Seg seg, Trace trace) @@ -1845,6 +1983,7 @@ Bool SegClassCheck(SegClass klass) CHECKL(FUNCHECK(klass->setRankSummary)); CHECKL(FUNCHECK(klass->merge)); CHECKL(FUNCHECK(klass->split)); + CHECKL(FUNCHECK(klass->access)); CHECKL(FUNCHECK(klass->whiten)); CHECKL(FUNCHECK(klass->greyen)); CHECKL(FUNCHECK(klass->blacken)); @@ -1882,6 +2021,7 @@ DEFINE_CLASS(Seg, Seg, klass) klass->setRankSummary = segNoSetRankSummary; klass->merge = segTrivMerge; klass->split = segTrivSplit; + klass->access = segNoAccess; klass->whiten = segNoWhiten; klass->greyen = segNoGreyen; klass->blacken = segNoBlacken; @@ -1916,6 +2056,7 @@ DEFINE_CLASS(Seg, GCSeg, klass) klass->setRankSummary = gcSegSetRankSummary; klass->merge = gcSegMerge; klass->split = gcSegSplit; + klass->access = SegWholeAccess; klass->whiten = gcSegWhiten; klass->greyen = gcSegGreyen; klass->blacken = gcSegTrivBlacken; diff --git a/mps/design/pool.txt b/mps/design/pool.txt index 406cba92c06..036181b1d07 100644 --- a/mps/design/pool.txt +++ b/mps/design/pool.txt @@ -182,32 +182,6 @@ part between init and limit). This method must be provided if and only if ``bufferFill`` is provided. This method is called by the generic function ``BufferDetach()``. -``typedef Res (*PoolAccessMethod)(Pool pool, Seg seg, Addr addr, AccessSet mode, MutatorContext context)`` - -_`.method.access`: The ``access`` method indicates that the client -program attempted to access the address ``addr``, but has been denied -due to a protection fault. The ``mode`` indicates whether the client -program was trying to read (``AccessREAD``) or write (``AccessWRITE``) -the address. If this can't be determined, ``mode`` is ``AccessREAD | -AccessWRITE``. The pool should perform any work necessary to remove -the protection whilst still preserving appropriate invariants (this -might scanning the region containing ``addr``). Pool classes are not -required to provide this method, and not doing so indicates they never -protect any memory managed by the pool. This method is called via the -generic function ``PoolAccess()``. - -``typedef void (*PoolWalkMethod)(Pool pool, Seg seg, FormattedObjectsVisitor f, void *v, size_t s)`` - -_`.method.walk`: The ``walk`` method must call the visitor function -``f`` (along with its closure parameters ``v`` and ``s`` and the -appropriate object format) once for each of the *black* objects in the -segment ``seg``. Padding objects may or may not be included in the -walk, at the pool's discretion: it is the responsibility of the client -program to handle them. Forwarding objects must not be included in the -walk. Pool classes need not provide this method. If they do, they must -set the ``AttrFMT`` attribute. This method is called by the heap -walker ``mps_arena_formatted_objects_walk()``. - ``typedef Size (*PoolSizeMethod)(Pool pool)`` _`.method.totalSize`: The ``totalSize`` method must return the total diff --git a/mps/design/seg.txt b/mps/design/seg.txt index 9c195479896..0c47e0e5304 100644 --- a/mps/design/seg.txt +++ b/mps/design/seg.txt @@ -230,6 +230,20 @@ Extensibility Garbage collection .................. +``typedef Res (*SegAccessMethod)(Seg seg, Arena arena, Addr addr, AccessSet mode, MutatorContext context)`` + +_`.method.access`: The ``access`` method indicates that the client +program attempted to access the address ``addr``, but has been denied +due to a protection fault. The ``mode`` indicates whether the client +program was trying to read (``AccessREAD``) or write (``AccessWRITE``) +the address. If this can't be determined, ``mode`` is ``AccessREAD | +AccessWRITE``. The segment should perform any work necessary to remove +the protection whilst still preserving appropriate invariants (this +might scanning the region containing ``addr``). Segment classes are +not required to provide this method, and not doing so indicates they +never protect any memory managed by the pool. This method is called +via the generic function ``SegAccess()``. + ``typedef Res (*SegWhitenMethod)(Seg seg, Trace trace)`` _`.method.whiten`: The ``whiten`` method requests that the segment @@ -319,6 +333,19 @@ classes are not required to provide this method. If they do, pools that use them must set the ``AttrGC`` attribute. This method is called via the generic function ``SegReclaim()``. +``typedef void (*SegWalkMethod)(Seg seg, FormattedObjectsVisitor f, void *v, size_t s)`` + +_`.method.walk`: The ``walk`` method must call the visitor function +``f`` (along with its closure parameters ``v`` and ``s`` and the +appropriate object format) once for each of the *black* objects in the +segment ``seg``. Padding objects may or may not be included in the +walk, at the segmen's discretion: it is the responsibility of the +client program to handle them. Forwarding objects must not be included +in the walk. Segment classes need not provide this method. If they do, +pool classes that use them must set the ``AttrFMT`` attribute. This +method is called by the genetic function ``SegWalk()``, which is +called by the heap walker ``mps_arena_formatted_objects_walk()``. + Splitting and merging ..................... diff --git a/mps/design/sp.txt b/mps/design/sp.txt index 503a72b7883..6a4bafee4a5 100644 --- a/mps/design/sp.txt +++ b/mps/design/sp.txt @@ -88,8 +88,8 @@ documented in the manual. ==== ====== ======================== Args Locals Function ==== ====== ======================== - 5 0 ``PoolAccess()`` - 5 0 ``PoolSegAccess()`` + 5 0 ``SegAccess()`` + 5 0 ``SegWholeAccess()`` 3 5 ``TraceSegAccess()`` 4 1 ``traceScanSeg()`` 4 8 ``traceScanSegRes()``