diff --git a/mps/code/global.c b/mps/code/global.c index 9b1fa38ecef..58f1b3ed435 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -107,8 +107,6 @@ Bool GlobalsCheck(Globals arenaGlobals) Arena arena; TraceId ti; Trace trace; - Index i; - RefSet rs; Rank rank; CHECKS(Globals, arenaGlobals); @@ -181,18 +179,7 @@ Bool GlobalsCheck(Globals arenaGlobals) /* no check for arena->lastWorldCollect (Clock) */ /* can't write a check for arena->epoch */ - - /* check that each history entry is a subset of the next oldest */ - rs = RefSetEMPTY; - /* note this loop starts from 1; there is no history age 0 */ - for (i=1; i <= LDHistoryLENGTH; ++ i) { - /* check history age 'i'; 'j' is the history index. */ - Index j = (arena->epoch + LDHistoryLENGTH - i) % LDHistoryLENGTH; - CHECKL(RefSetSub(rs, arena->history[j])); - rs = arena->history[j]; - } - /* the oldest history entry must be a subset of the prehistory */ - CHECKL(RefSetSub(rs, arena->prehistory)); + CHECKD(History, ArenaHistory(arena)); /* we also check the statics now. */ CHECKL(BoolCheck(arenaRingInit)); @@ -218,7 +205,6 @@ Bool GlobalsCheck(Globals arenaGlobals) Res GlobalsInit(Globals arenaGlobals) { Arena arena; - Index i; Rank rank; TraceId ti; @@ -297,11 +283,8 @@ Res GlobalsInit(Globals arenaGlobals) STATISTIC(arena->writeBarrierHitCount = 0); RingInit(&arena->chainRing); - arena->epoch = (Epoch)0; /* */ - arena->prehistory = RefSetEMPTY; - for(i = 0; i < LDHistoryLENGTH; ++i) - arena->history[i] = RefSetEMPTY; - + HistoryInit(ArenaHistory(arena)); + arena->emergency = FALSE; arena->stackAtArenaEnter = NULL; @@ -385,6 +368,7 @@ void GlobalsFinish(Globals arenaGlobals) arenaGlobals->sig = SigInvalid; ShieldFinish(ArenaShield(arena)); + HistoryFinish(ArenaHistory(arena)); RingFinish(&arena->formatRing); RingFinish(&arena->chainRing); RingFinish(&arena->messageRing); @@ -955,7 +939,6 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) Res res; Arena arena; Ring node, nextNode; - Index i; TraceId ti; Trace trace; @@ -988,21 +971,13 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) "threadSerial $U\n", (WriteFU)arena->threadSerial, "busyTraces $B\n", (WriteFB)arena->busyTraces, "flippedTraces $B\n", (WriteFB)arena->flippedTraces, - "epoch $U\n", (WriteFU)arena->epoch, - "prehistory = $B\n", (WriteFB)arena->prehistory, - "history {\n", - " [note: indices are raw, not rotated]\n", NULL); if (res != ResOK) return res; - for(i=0; i < LDHistoryLENGTH; ++ i) { - res = WriteF(stream, depth + 2, - "[$U] = $B\n", (WriteFU)i, (WriteFB)arena->history[i], - NULL); - if (res != ResOK) - return res; - } + res = HistoryDescribe(ArenaHistory(arena), stream, depth); + if (res != ResOK) + return res; res = ShieldDescribe(ArenaShield(arena), stream, depth); if (res != ResOK) diff --git a/mps/code/ld.c b/mps/code/ld.c index c9e79f8a762..71264ff78a7 100644 --- a/mps/code/ld.c +++ b/mps/code/ld.c @@ -51,6 +51,88 @@ SRCID(ld, "$Id$"); +void HistoryInit(History history) +{ + Index i; + + AVER(history != NULL); + + history->epoch = 0; + history->prehistory = RefSetEMPTY; + for (i = 0; i < LDHistoryLENGTH; ++i) + history->history[i] = RefSetEMPTY; + + history->sig = HistorySig; + AVERT(History, history); +} + +Bool HistoryCheck(History history) +{ + Index i; + RefSet rs; + + CHECKS(History, history); + + /* check that each history entry is a subset of the next oldest */ + rs = RefSetEMPTY; + /* note this loop starts from 1; there is no history age 0 */ + for (i = 1; i <= LDHistoryLENGTH; ++i) { + /* check history age 'i'; 'j' is the history index. */ + Index j = (history->epoch + LDHistoryLENGTH - i) % LDHistoryLENGTH; + CHECKL(RefSetSub(rs, history->history[j])); + rs = history->history[j]; + } + /* the oldest history entry must be a subset of the prehistory */ + CHECKL(RefSetSub(rs, history->prehistory)); + + return TRUE; +} + +void HistoryFinish(History history) +{ + AVERT(History, history); + history->sig = SigInvalid; +} + +Res HistoryDescribe(History history, mps_lib_FILE *stream, Count depth) +{ + Res res; + Index i; + + if (!TESTT(History, history)) + return ResPARAM; + if (stream == NULL) + return ResPARAM; + + res = WriteF(stream, depth, + "History $P {\n", (WriteFP)history, + " epoch = $U\n", (WriteFU)history->epoch, + " prehistory = $B\n", (WriteFB)history->prehistory, + " history {\n", + " [note: indices are raw, not rotated]\n", + NULL); + if (res != ResOK) + return res; + + for (i = 0; i < LDHistoryLENGTH; ++i) { + res = WriteF(stream, depth + 4, + "[$U] = $B\n", (WriteFU)i, (WriteFB)history->history[i], + NULL); + if (res != ResOK) + return res; + } + + res = WriteF(stream, depth, + " }\n", + "} History $P\n", (WriteFP)history, + NULL); + if (res != ResOK) + return res; + + return ResOK; +} + + /* LDReset -- reset a dependency to empty * * .reset.sync: This does not need to be synchronized with LDAge @@ -68,7 +150,7 @@ void LDReset(mps_ld_t ld, Arena arena) b = SegOfAddr(&seg, arena, (Addr)ld); if (b) ShieldExpose(arena, seg); /* .ld.access */ - ld->_epoch = arena->epoch; + ld->_epoch = ArenaHistory(arena)->epoch; ld->_rs = RefSetEMPTY; if (b) ShieldCover(arena, seg); @@ -106,7 +188,7 @@ void LDAdd(mps_ld_t ld, Arena arena, Addr addr) { AVER(ld != NULL); AVER(TESTT(Arena, arena)); /* see .add.lock-free */ - AVER(ld->_epoch <= arena->epoch); + AVER(ld->_epoch <= ArenaHistory(arena)->epoch); ld->_rs = RefSetAdd(arena, ld->_rs, addr); } @@ -134,23 +216,25 @@ void LDAdd(mps_ld_t ld, Arena arena, Addr addr) */ Bool LDIsStaleAny(mps_ld_t ld, Arena arena) { + History history; RefSet rs; AVER(ld != NULL); AVER(TESTT(Arena, arena)); /* .stale.thread-safe */ - AVER(ld->_epoch <= arena->epoch); + history = ArenaHistory(arena); + AVER(ld->_epoch <= history->epoch); - if (arena->epoch == ld->_epoch) /* .stale.current */ + if (history->epoch == ld->_epoch) /* .stale.current */ return FALSE; /* Load the history refset, _then_ check to see if it's recent. * This may in fact load an okay refset, which we decide to throw * away and use the pre-history instead. */ - rs = arena->history[ld->_epoch % LDHistoryLENGTH]; + rs = history->history[ld->_epoch % LDHistoryLENGTH]; /* .stale.recent */ /* .stale.recent.conservative */ - if (arena->epoch - ld->_epoch > LDHistoryLENGTH) { - rs = arena->prehistory; /* .stale.old */ + if (history->epoch - ld->_epoch > LDHistoryLENGTH) { + rs = history->prehistory; /* .stale.old */ } return RefSetInter(ld->_rs, rs) != RefSetEMPTY; @@ -186,28 +270,30 @@ Bool LDIsStale(mps_ld_t ld, Arena arena, Addr addr) */ void LDAge(Arena arena, RefSet rs) { + History history; Size i; AVERT(Arena, arena); + history = ArenaHistory(arena); AVER(rs != RefSetEMPTY); /* Replace the entry for epoch - LDHistoryLENGTH by an empty */ /* set which will become the set which has moved since the */ /* current epoch. */ - arena->history[arena->epoch % LDHistoryLENGTH] = RefSetEMPTY; + history->history[history->epoch % LDHistoryLENGTH] = RefSetEMPTY; /* Record the fact that the moved set has moved, by adding it */ /* to all the sets in the history, including the set for the */ /* current epoch. */ for(i = 0; i < LDHistoryLENGTH; ++i) - arena->history[i] = RefSetUnion(arena->history[i], rs); + history->history[i] = RefSetUnion(history->history[i], rs); /* This is the union of all movement since time zero. */ - arena->prehistory = RefSetUnion(arena->prehistory, rs); + history->prehistory = RefSetUnion(history->prehistory, rs); /* Advance the epoch by one. */ - ++arena->epoch; - AVER(arena->epoch != 0); /* .epoch-size */ + ++history->epoch; + AVER(history->epoch != 0); /* .epoch-size */ } @@ -221,9 +307,9 @@ void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from) { AVER(ld != NULL); AVER(TESTT(Arena, arena)); /* .merge.lock-free */ - AVER(ld->_epoch <= arena->epoch); + AVER(ld->_epoch <= ArenaHistory(arena)->epoch); AVER(from != NULL); - AVER(from->_epoch <= arena->epoch); + AVER(from->_epoch <= ArenaHistory(arena)->epoch); /* If a reference has been added since epoch e1 then I've */ /* certainly added since epoch e0 where e0 < e1. Therefore */ diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 4746835a75a..0c49c6b8fff 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -524,7 +524,7 @@ extern Ring GlobalsRememberedSummaryRing(Globals); #define ArenaThreadRing(arena) (&(arena)->threadRing) #define ArenaDeadRing(arena) (&(arena)->deadRing) -#define ArenaEpoch(arena) ((arena)->epoch) /* .epoch.ts */ +#define ArenaEpoch(arena) (ArenaHistory(arena)->epoch) /* .epoch.ts */ #define ArenaTrace(arena, ti) (&(arena)->trace[ti]) #define ArenaZoneShift(arena) ((arena)->zoneShift) #define ArenaStripeSize(arena) ((Size)1 << ArenaZoneShift(arena)) @@ -534,6 +534,7 @@ extern Ring GlobalsRememberedSummaryRing(Globals); #define ArenaChunkTree(arena) RVALUE((arena)->chunkTree) #define ArenaChunkRing(arena) RVALUE(&(arena)->chunkRing) #define ArenaShield(arena) (&(arena)->shieldStruct) +#define ArenaHistory(arena) (&(arena)->historyStruct) extern Bool ArenaGrainSizeCheck(Size size); #define AddrArenaGrainUp(addr, arena) AddrAlignUp(addr, ArenaGrainSize(arena)) @@ -944,6 +945,10 @@ extern void (ShieldFlush)(Arena arena); /* Location Dependency -- see */ +extern void HistoryInit(History history); +extern void HistoryFinish(History); +extern Res HistoryDescribe(History history, mps_lib_FILE *stream, Count depth); +extern Bool HistoryCheck(History history); extern void LDReset(mps_ld_t ld, Arena arena); extern void LDAdd(mps_ld_t ld, Arena arena, Addr addr); extern Bool LDIsStaleAny(mps_ld_t ld, Arena arena); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 72e321fecce..7a9c633313a 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -713,6 +713,21 @@ typedef struct ShieldStruct { } ShieldStruct; +/* History -- location dependency history + * + * See design.mps.arena.ld. + */ + +#define HistorySig ((Sig)0x51981520) /* SIGnature HISTOry */ + +typedef struct HistoryStruct { + Sig sig; /* design.mps.sig */ + Epoch epoch; /* */ + RefSet prehistory; /* */ + RefSet history[LDHistoryLENGTH]; /* */ +} HistoryStruct; + + /* ArenaStruct -- generic arena * * See . @@ -796,11 +811,8 @@ typedef struct mps_arena_s { STATISTIC_DECL(Count writeBarrierHitCount) /* write barrier hits */ RingStruct chainRing; /* ring of chains */ - /* location dependency fields () */ - Epoch epoch; /* */ - RefSet prehistory; /* */ - RefSet history[LDHistoryLENGTH]; /* */ - + struct HistoryStruct historyStruct; + Bool emergency; /* garbage collect in emergency mode? */ Word *stackAtArenaEnter; /* NULL or hot end of client stack, in the thread */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index cb7384dad51..27e71aa06c0 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -112,6 +112,7 @@ typedef struct LandStruct *Land; /* */ typedef struct LandClassStruct *LandClass; /* */ typedef unsigned FindDelete; /* */ typedef struct ShieldStruct *Shield; /* design.mps.shield */ +typedef struct HistoryStruct *History; /* design.mps.arena.ld */ /* Arena*Method -- see */ diff --git a/mps/design/arena.txt b/mps/design/arena.txt index 7d6fe4c0eb7..5b204b5e1cb 100644 --- a/mps/design/arena.txt +++ b/mps/design/arena.txt @@ -567,21 +567,25 @@ end of ``ArenaPoll()`` to the current polling time plus Location dependencies ..................... -_`.ld.epoch`: ``arena->epoch`` is the "current epoch". This is the +_`.ld`: The ``historyStruct`` contains fields used to maintain a +history of garbage collection and in particular object motion in order +to implement location dependency. + +_`.ld.epoch`: The ``epoch`` is the "current epoch". This is the number of 'flips' of traces in the arena since the arena was created. From the mutator's point of view locations change atomically at flip. -_`.ld.history`: ``arena->history`` is a circular buffer of +_`.ld.history`: The ``history`` is a circular buffer of ``LDHistoryLENGTH`` elements of type ``RefSet``. These are the summaries of moved objects since the last ``LDHistoryLENGTH`` epochs. If ``e`` is one of these recent epochs, then :: - arena->history[e % LDHistoryLENGTH] + history->history[e % LDHistoryLENGTH] is a summary of (the original locations of) objects moved since epoch ``e``. -_`.ld.prehistory`: ``arena->prehistory`` is a ``RefSet`` summarizing +_`.ld.prehistory`: The ``prehistory`` is a ``RefSet`` summarizing the original locations of all objects ever moved. When considering whether a really old location dependency is stale, it is compared with this summary.