1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-23 06:00:41 -08:00

New function mps_root_create_reg_masked applies a mask and pattern test to all words in registers and on the stack when scanning them. this supports tagged references in these locations.

Consistently use the type "Word *" for pointers into the stack or into saved registers.
Remove TraceScanAreaTagged.

Copied from Perforce
 Change: 188231
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2015-09-04 12:22:03 +01:00
parent 3e9433f28f
commit edf30c06b4
31 changed files with 335 additions and 174 deletions

View file

@ -472,10 +472,9 @@ extern double TraceWorkFactor;
} \
END
extern Res TraceScanArea(ScanState ss, Addr *base, Addr *limit);
extern Res TraceScanAreaTagged(ScanState ss, Addr *base, Addr *limit);
extern Res TraceScanAreaMasked(ScanState ss,
Addr *base, Addr *limit, Word mask);
extern Res TraceScanArea(ScanState ss, Word *base, Word *limit);
extern Res TraceScanAreaMasked(ScanState ss, Word *base, Word *limit,
Word mask, Word value);
extern void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena,
Seg seg, Ref *refIO);
@ -948,15 +947,19 @@ extern void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from);
extern Res RootCreateTable(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
Addr *base, Addr *limit);
Word *base, Word *limit);
extern Res RootCreateTableMasked(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
Addr *base, Addr *limit,
Word *base, Word *limit,
Word mask);
extern Res RootCreateReg(Root *rootReturn, Arena arena,
Rank rank, Thread thread,
mps_reg_scan_t scan,
void *p, size_t s);
extern Res RootCreateRegMasked(Root *rootReturn, Arena arena,
Rank rank, Thread thread,
Word mask, Word pattern,
Addr stackBot);
extern Res RootCreateFmt(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
mps_fmt_scan_t scan,

View file

@ -791,7 +791,7 @@ typedef struct mps_arena_s {
Bool emergency; /* garbage collect in emergency mode? */
Addr *stackAtArenaEnter; /* NULL or top of client stack, in the thread */
Word *stackAtArenaEnter; /* NULL or top of client stack, in the thread */
/* that then entered the MPS. */
Sig sig;

View file

@ -362,6 +362,7 @@ enum {
RootTABLE,
RootTABLE_MASKED,
RootREG,
RootREG_MASKED,
RootFMT,
RootLIMIT
};

View file

@ -672,6 +672,10 @@ extern mps_res_t mps_root_create_fmt(mps_root_t *, mps_arena_t,
extern mps_res_t mps_root_create_reg(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t, mps_thr_t,
mps_reg_scan_t, void *, size_t);
extern mps_res_t mps_root_create_reg_masked(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t, mps_thr_t,
mps_word_t, mps_word_t,
void *);
extern void mps_root_destroy(mps_root_t);
extern mps_res_t mps_stack_scan_ambig(mps_ss_t, mps_thr_t,

View file

@ -1304,7 +1304,7 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena,
/* limit pointers. Be careful. */
res = RootCreateTable(&root, arena, rank, mode,
(Addr *)base, (Addr *)base + size);
(Word *)base, (Word *)base + size);
ArenaLeave(arena);
@ -1335,7 +1335,7 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o,
/* See .root.table-size. */
res = RootCreateTableMasked(&root, arena, rank, mode,
(Addr *)base, (Addr *)base + size,
(Word *)base, (Word *)base + size,
mask);
ArenaLeave(arena);
@ -1401,6 +1401,37 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena,
}
mps_res_t mps_root_create_reg_masked(mps_root_t *mps_root_o, mps_arena_t arena,
mps_rank_t mps_rank, mps_rm_t mps_rm,
mps_thr_t thread, mps_word_t mask,
mps_word_t pattern, void *reg_scan_p)
{
Rank rank = (Rank)mps_rank;
Root root;
Res res;
ArenaEnter(arena);
AVER(mps_root_o != NULL);
AVER(reg_scan_p != NULL); /* stackBot */
AVER(AddrIsAligned(reg_scan_p, sizeof(Word)));
AVER(rank == mps_rank_ambig());
AVER(mps_rm == (mps_rm_t)0);
AVER((~mask & pattern) == 0);
/* See .root-mode. */
res = RootCreateRegMasked(&root, arena, rank, thread,
mask, pattern, (Addr)reg_scan_p);
ArenaLeave(arena);
if (res != ResOK)
return (mps_res_t)res;
*mps_root_o = (mps_root_t)root;
return MPS_RES_OK;
}
/* mps_stack_scan_ambig -- scan the thread state ambiguously
*
* See .reg-scan. */
@ -1410,7 +1441,7 @@ mps_res_t mps_stack_scan_ambig(mps_ss_t mps_ss,
{
ScanState ss = PARENT(ScanStateStruct, ss_s, mps_ss);
UNUSED(s);
return ThreadScan(ss, thread, p);
return ThreadScan(ss, thread, (Word *)p, sizeof(mps_word_t) - 1, 0);
}

View file

@ -38,17 +38,19 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
Word mask, Word pattern)
{
Res res;
/* This scans the root registers (.context.regroots). It also unnecessarily
scans the rest of the context. The optimisation to scan only relevant
parts would be machine dependent. */
res = TraceScanAreaTagged(
res = TraceScanAreaMasked(
ss,
(Addr *)mfc->ucontext,
(Addr *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext)))
(Word *)mfc->ucontext,
(Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))),
mask, pattern
);
return res;

View file

@ -101,7 +101,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
Word mask, Word pattern)
{
mcontext_t *mc;
Res res;
@ -110,9 +111,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
unnecessarily scans the rest of the context. The optimisation
to scan only relevant parts would be machine dependent. */
mc = &mfc->ucontext->uc_mcontext;
res = TraceScanAreaTagged(ss,
(Addr *)mc,
(Addr *)((char *)mc + sizeof(*mc)));
res = TraceScanAreaMasked(ss,
(Word *)mc,
(Word *)((char *)mc + sizeof(*mc)),
mask, pattern);
return res;
}

View file

@ -96,7 +96,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
Word mask, Word pattern)
{
x86_thread_state32_t *mc;
Res res;
@ -105,9 +106,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
unnecessarily scans the rest of the context. The optimisation
to scan only relevant parts would be machine dependent. */
mc = mfc->threadState;
res = TraceScanAreaTagged(ss,
(Addr *)mc,
(Addr *)((char *)mc + sizeof(*mc)));
res = TraceScanAreaMasked(ss,
(Word *)mc,
(Word *)((char *)mc + sizeof(*mc)),
mask, pattern);
return res;
}

View file

@ -32,17 +32,19 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
Word mask, Word pattern)
{
Res res;
/* This scans the root registers (.context.regroots). It also unnecessarily
scans the rest of the context. The optimisation to scan only relevant
parts would be machine dependent. */
res = TraceScanAreaTagged(
res = TraceScanAreaMasked(
ss,
(Addr *)mfc->ucontext,
(Addr *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext)))
(Word *)mfc->ucontext,
(Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))),
mask, pattern
);
return res;

View file

@ -105,7 +105,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
Word mask, Word pattern)
{
mcontext_t *mc;
Res res;
@ -115,8 +116,9 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
to scan only relevant parts would be machine dependent. */
mc = &mfc->ucontext->uc_mcontext;
res = TraceScanAreaTagged(ss,
(Addr *)mc,
(Addr *)((char *)mc + sizeof(*mc)));
(Word *)mc,
(Word *)((char *)mc + sizeof(*mc)),
mask, pattern);
return res;
}

View file

@ -99,7 +99,8 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
Word mask, Word pattern)
{
x86_thread_state64_t *mc;
Res res;
@ -108,9 +109,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
unnecessarily scans the rest of the context. The optimisation
to scan only relevant parts would be machine dependent. */
mc = mfc->threadState;
res = TraceScanAreaTagged(ss,
(Addr *)mc,
(Addr *)((char *)mc + sizeof(*mc)));
res = TraceScanAreaMasked(ss,
(Word *)mc,
(Word *)((char *)mc + sizeof(*mc)),
mask, pattern);
return res;
}

View file

@ -30,7 +30,8 @@ extern void ProtSync(Arena arena);
extern Bool ProtCanStepInstruction(MutatorFaultContext context);
extern Res ProtStepInstruction(MutatorFaultContext context);
extern Addr MutatorFaultContextSP(MutatorFaultContext mfc);
extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc);
extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
Word mask, Word pattern);
#endif /* prot_h */

View file

@ -38,13 +38,14 @@ typedef struct RootStruct {
size_t s; /* environment for scan */
} fun;
struct {
Addr *base; /* beginning of table */
Addr *limit; /* one off end of table */
Word *base; /* beginning of table */
Word *limit; /* one off end of table */
} table;
struct {
Addr *base; /* beginning of table */
Addr *limit; /* one off end of table */
Word *base; /* beginning of table */
Word *limit; /* one off end of table */
Word mask; /* tag mask for scanning */
Word pattern; /* tag pattern for scanning */
} tableMasked;
struct {
mps_reg_scan_t scan; /* function for scanning registers */
@ -52,6 +53,12 @@ typedef struct RootStruct {
void *p; /* passed to scan */
size_t s; /* passed to scan */
} reg;
struct {
Thread thread; /* passed to scan */
Word mask; /* tag mask for scanning */
Word pattern; /* tag pattern for scanning */
Word *stackBot; /* bottom of stack */
} regMasked;
struct {
mps_fmt_scan_t scan; /* format-like scanner */
Addr base, limit; /* passed to scan */
@ -67,7 +74,8 @@ typedef struct RootStruct {
Bool RootVarCheck(RootVar rootVar)
{
CHECKL(rootVar == RootTABLE || rootVar == RootTABLE_MASKED
|| rootVar == RootFUN || rootVar == RootFMT || rootVar == RootREG);
|| rootVar == RootFUN || rootVar == RootFMT || rootVar == RootREG
|| rootVar == RootREG_MASKED);
UNUSED(rootVar);
return TRUE;
}
@ -112,7 +120,7 @@ Bool RootCheck(Root root)
case RootTABLE_MASKED:
CHECKL(root->the.tableMasked.base != 0);
CHECKL(root->the.tableMasked.base < root->the.tableMasked.limit);
/* Can't check anything about the mask. */
CHECKL((~root->the.tableMasked.mask & root->the.tableMasked.pattern) == 0);
break;
case RootFUN:
@ -122,6 +130,13 @@ Bool RootCheck(Root root)
case RootREG:
CHECKL(root->the.reg.scan != NULL);
CHECKD_NOSIG(Thread, root->the.reg.thread); /* <design/check/#hidden-type> */
/* Can't check anything about p or s. */
break;
case RootREG_MASKED:
CHECKD_NOSIG(Thread, root->the.regMasked.thread); /* <design/check/#hidden-type> */
CHECKL((~root->the.regMasked.mask & root->the.regMasked.pattern) == 0);
/* Can't check anything about stackBot. */
break;
case RootFMT:
@ -254,7 +269,7 @@ static Res rootCreateProtectable(Root *rootReturn, Arena arena,
}
Res RootCreateTable(Root *rootReturn, Arena arena,
Rank rank, RootMode mode, Addr *base, Addr *limit)
Rank rank, RootMode mode, Word *base, Word *limit)
{
Res res;
union RootUnion theUnion;
@ -276,7 +291,7 @@ Res RootCreateTable(Root *rootReturn, Arena arena,
}
Res RootCreateTableMasked(Root *rootReturn, Arena arena,
Rank rank, RootMode mode, Addr *base, Addr *limit,
Rank rank, RootMode mode, Word *base, Word *limit,
Word mask)
{
union RootUnion theUnion;
@ -291,6 +306,7 @@ Res RootCreateTableMasked(Root *rootReturn, Arena arena,
theUnion.tableMasked.base = base;
theUnion.tableMasked.limit = limit;
theUnion.tableMasked.mask = mask;
theUnion.tableMasked.pattern = 0;
return rootCreateProtectable(rootReturn, arena, rank, mode, RootTABLE_MASKED,
(Addr)base, (Addr)limit, &theUnion);
@ -317,6 +333,28 @@ Res RootCreateReg(Root *rootReturn, Arena arena,
return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG, &theUnion);
}
Res RootCreateRegMasked(Root *rootReturn, Arena arena,
Rank rank, Thread thread,
Word mask, Word pattern, Addr stackBot)
{
union RootUnion theUnion;
AVER(rootReturn != NULL);
AVERT(Arena, arena);
AVERT(Rank, rank);
AVERT(Thread, thread);
AVER(ThreadArena(thread) == arena);
AVER((~mask & pattern) == 0);
theUnion.regMasked.thread = thread;
theUnion.regMasked.mask = mask;
theUnion.regMasked.pattern = pattern;
theUnion.regMasked.stackBot = stackBot;
return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG_MASKED,
&theUnion);
}
/* RootCreateFmt -- create root from block of formatted objects
*
* .fmt.no-align-check: Note that we don't check the alignment of base
@ -481,7 +519,8 @@ Res RootScan(ScanState ss, Root root)
res = TraceScanAreaMasked(ss,
root->the.tableMasked.base,
root->the.tableMasked.limit,
root->the.tableMasked.mask);
root->the.tableMasked.mask,
root->the.tableMasked.pattern);
ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit);
if (res != ResOK)
goto failScan;
@ -500,6 +539,15 @@ Res RootScan(ScanState ss, Root root)
goto failScan;
break;
case RootREG_MASKED:
res = ThreadScan(ss, root->the.regMasked.thread,
root->the.regMasked.stackBot,
root->the.regMasked.mask,
root->the.regMasked.pattern);
if (res != ResOK)
goto failScan;
break;
case RootFMT:
res = (*root->the.fmt.scan)(&ss->ss_s, root->the.fmt.base, root->the.fmt.limit);
ss->scannedSize += AddrOffset(root->the.fmt.base, root->the.fmt.limit);

View file

@ -24,10 +24,8 @@ SRCID(ss, "$Id$");
* scanning.
*/
Res StackScanInner(ScanState ss,
Addr *stackBot,
Addr *stackTop,
Count nSavedRegs)
Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop,
Count nSavedRegs, Word mask, Word pattern)
{
Arena arena;
Res res;
@ -49,14 +47,16 @@ Res StackScanInner(ScanState ss,
if (arena->stackAtArenaEnter != NULL) {
AVER(stackTop < arena->stackAtArenaEnter);
AVER(arena->stackAtArenaEnter < stackBot);
res = TraceScanAreaTagged(ss, stackTop, stackTop + nSavedRegs);
res = TraceScanAreaMasked(ss, stackTop, stackTop + nSavedRegs,
mask, pattern);
if (res != ResOK)
return res;
res = TraceScanAreaTagged(ss, arena->stackAtArenaEnter, stackBot);
res = TraceScanAreaMasked(ss, arena->stackAtArenaEnter, stackBot,
mask, pattern);
if (res != ResOK)
return res;
} else {
res = TraceScanAreaTagged(ss, stackTop, stackBot);
res = TraceScanAreaMasked(ss, stackTop, stackBot, mask, pattern);
if (res != ResOK)
return res;
}

View file

@ -32,13 +32,9 @@
* stack itself.
*/
extern Res StackScan(ScanState ss, Addr *stackBot);
extern Res StackScanInner(ScanState ss,
Addr *stackBot,
Addr *stackTop,
Count nSavedRegs);
extern Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern);
extern Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop,
Count nSavedRegs, Word mask, Word pattern);
#endif /* ss_h */

View file

@ -21,21 +21,22 @@
SRCID(ssan, "$Id$");
Res StackScan(ScanState ss, Addr *stackBot)
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
jmp_buf jb;
void *stackTop = &jb;
Word *stackTop = (Word *)&jb;
/* .assume.stack: This implementation assumes that the stack grows
* downwards, so that the address of the jmp_buf is the limit of the
* part of the stack that needs to be scanned. (StackScanInner makes
* the same assumption.)
*/
AVER(stackTop < (void *)stackBot);
AVER(stackTop < stackBot);
(void)setjmp(jb);
return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Addr*));
return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Word*),
mask, pattern);
}

View file

@ -49,9 +49,9 @@ SRCID(ssixi3, "$Id$");
#define ASMV(x) __asm__ volatile (x)
Res StackScan(ScanState ss, Addr *stackBot)
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
Addr calleeSaveRegs[4];
Word calleeSaveRegs[4];
/* .assume.asm.stack */
/* Store the callee save registers on the stack so they get scanned
@ -62,7 +62,8 @@ Res StackScan(ScanState ss, Addr *stackBot)
ASMV("mov %%edi, %0" : "=m" (calleeSaveRegs[2]));
ASMV("mov %%ebp, %0" : "=m" (calleeSaveRegs[3]));
return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs));
return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs),
mask, pattern);
}

View file

@ -47,9 +47,9 @@ SRCID(ssixi6, "$Id$");
#define ASMV(x) __asm__ volatile (x)
Res StackScan(ScanState ss, Addr *stackBot)
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
Addr calleeSaveRegs[6];
Word calleeSaveRegs[6];
/* .assume.asm.stack */
/* Store the callee save registers on the stack so they get scanned
@ -62,7 +62,8 @@ Res StackScan(ScanState ss, Addr *stackBot)
ASMV("mov %%r14, %0" : "=m" (calleeSaveRegs[4]));
ASMV("mov %%r15, %0" : "=m" (calleeSaveRegs[5]));
return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs));
return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs),
mask, pattern);
}

View file

@ -22,7 +22,7 @@
SRCID(ssw3i3mv, "$Id$");
Res StackScan(ScanState ss, Addr *stackBot)
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
jmp_buf jb;
@ -33,16 +33,17 @@ Res StackScan(ScanState ss, Addr *stackBot)
/* These checks will just serve to warn us at compile-time if the
setjmp.h header changes to indicate that the registers we want aren't
saved any more. */
AVER(sizeof(((_JUMP_BUFFER *)jb)->Edi) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Esi) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Ebx) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Edi) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Esi) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Ebx) == sizeof(Word));
/* Ensure that the callee-save registers will be found by
StackScanInner when it's passed the address of the Ebx field. */
AVER(offsetof(_JUMP_BUFFER, Edi) == offsetof(_JUMP_BUFFER, Ebx) + 4);
AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8);
return StackScanInner(ss, stackBot, (Addr *)&((_JUMP_BUFFER *)jb)->Ebx, 3);
return StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3,
mask, pattern);
}
/* C. COPYRIGHT AND LICENSE

View file

@ -46,7 +46,7 @@ typedef struct __JUMP_BUFFER {
} _JUMP_BUFFER;
Res StackScan(ScanState ss, Addr *stackBot)
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
jmp_buf jb;
@ -58,7 +58,8 @@ Res StackScan(ScanState ss, Addr *stackBot)
AVER(offsetof(_JUMP_BUFFER, Edi) == offsetof(_JUMP_BUFFER, Ebx) + 4);
AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8);
return StackScanInner(ss, stackBot, (Addr *)&((_JUMP_BUFFER *)jb)->Ebx, 3);
return StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Ebx, 3,
mask, pattern);
}

View file

@ -30,7 +30,7 @@
SRCID(ssw3i6mv, "$Id$");
Res StackScan(ScanState ss, Addr *stackBot)
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
jmp_buf jb;
@ -41,13 +41,13 @@ Res StackScan(ScanState ss, Addr *stackBot)
/* These checks will just serve to warn us at compile-time if the
setjmp.h header changes to indicate that the registers we want aren't
saved any more. */
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R15) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R15) == sizeof(Word));
/* The layout of the jmp_buf forces us to harmlessly scan Rsp as well. */
AVER(offsetof(_JUMP_BUFFER, Rsp) == offsetof(_JUMP_BUFFER, Rbx) + 8);
@ -59,7 +59,8 @@ Res StackScan(ScanState ss, Addr *stackBot)
AVER(offsetof(_JUMP_BUFFER, R14) == offsetof(_JUMP_BUFFER, Rbx) + 56);
AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64);
return StackScanInner(ss, stackBot, (Addr *)&((_JUMP_BUFFER *)jb)->Rbx, 9);
return StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Rbx, 9,
mask, pattern);
}
/* C. COPYRIGHT AND LICENSE

View file

@ -68,7 +68,7 @@ typedef struct _JUMP_BUFFER {
} _JUMP_BUFFER;
Res StackScan(ScanState ss, Addr *stackBot)
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
{
jmp_buf jb;
@ -79,13 +79,13 @@ Res StackScan(ScanState ss, Addr *stackBot)
/* These checks will just serve to warn us at compile-time if the
setjmp.h header changes to indicate that the registers we want aren't
saved any more. */
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R15) == sizeof(Addr));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Word));
AVER(sizeof(((_JUMP_BUFFER *)jb)->R15) == sizeof(Word));
/* The layout of the jmp_buf forces us to harmlessly scan Rsp as well. */
AVER(offsetof(_JUMP_BUFFER, Rsp) == offsetof(_JUMP_BUFFER, Rbx) + 8);
@ -97,7 +97,8 @@ Res StackScan(ScanState ss, Addr *stackBot)
AVER(offsetof(_JUMP_BUFFER, R14) == offsetof(_JUMP_BUFFER, Rbx) + 56);
AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64);
return StackScanInner(ss, stackBot, (Addr *)&((_JUMP_BUFFER *)jb)->Rbx, 9);
return StackScanInner(ss, stackBot, (Word *)&((_JUMP_BUFFER *)jb)->Rbx, 9,
mask, pattern);
}

View file

@ -67,7 +67,8 @@ extern Thread ThreadRingThread(Ring threadRing);
extern Arena ThreadArena(Thread thread);
extern Res ThreadScan(ScanState ss, Thread thread, void *stackBot);
extern Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
Word mask, Word pattern);
#endif /* th_h */

View file

@ -115,10 +115,11 @@ Arena ThreadArena(Thread thread)
}
Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
Word mask, Word pattern)
{
UNUSED(thread);
return StackScan(ss, stackBot);
return StackScan(ss, stackBot, mask, pattern);
}

View file

@ -222,7 +222,8 @@ Arena ThreadArena(Thread thread)
/* ThreadScan -- scan the state of a thread (stack and regs) */
Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
Word mask, Word pattern)
{
pthread_t self;
Res res;
@ -231,12 +232,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
self = pthread_self();
if(pthread_equal(self, thread->id)) {
/* scan this thread's stack */
res = StackScan(ss, stackBot);
res = StackScan(ss, stackBot, mask, pattern);
if(res != ResOK)
return res;
} else {
MutatorFaultContext mfc;
Addr *stackBase, *stackLimit, stackPtr;
Word *stackBase, *stackLimit;
Addr stackPtr;
mfc = thread->mfc;
if(mfc == NULL) {
@ -248,20 +250,20 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
stackPtr = MutatorFaultContextSP(mfc);
/* .stack.align */
stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
stackLimit = (Addr *)stackBot;
stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
stackLimit = stackBot;
if (stackBase >= stackLimit)
return ResOK; /* .stack.below-bottom */
/* scan stack inclusive of current sp and exclusive of
* stackBot (.stack.full-descend)
*/
res = TraceScanAreaTagged(ss, stackBase, stackLimit);
res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
if(res != ResOK)
return res;
/* scan the registers in the mutator fault context */
res = MutatorFaultContextScan(ss, mfc);
res = MutatorFaultContextScan(ss, mfc, mask, pattern);
if(res != ResOK)
return res;
}

View file

@ -67,7 +67,8 @@
SRCID(thw3i3, "$Id$");
Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
Word mask, Word pattern)
{
DWORD id;
Res res;
@ -77,7 +78,8 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
if(id != thread->id) { /* .thread.id */
CONTEXT context;
BOOL success;
Addr *stackBase, *stackLimit, stackPtr;
Word *stackBase, *stackLimit;
Addr stackPtr;
/* scan stack and register roots in other threads */
@ -95,15 +97,15 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
stackPtr = (Addr)context.Esp; /* .i3.sp */
/* .stack.align */
stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
stackLimit = (Addr *)stackBot;
stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
stackLimit = stackBot;
if (stackBase >= stackLimit)
return ResOK; /* .stack.below-bottom */
/* scan stack inclusive of current sp and exclusive of
* stackBot (.stack.full-descend)
*/
res = TraceScanAreaTagged(ss, stackBase, stackLimit);
res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
if(res != ResOK)
return res;
@ -112,13 +114,14 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
* unnecessarily scans the rest of the context. The optimisation
* to scan only relevant parts would be machine dependent.
*/
res = TraceScanAreaTagged(ss, (Addr *)&context,
(Addr *)((char *)&context + sizeof(CONTEXT)));
res = TraceScanAreaMasked(ss, (Word *)&context,
(Word *)((char *)&context + sizeof(CONTEXT)),
mask, pattern);
if(res != ResOK)
return res;
} else { /* scan this thread's stack */
res = StackScan(ss, stackBot);
res = StackScan(ss, stackBot, mask, pattern);
if(res != ResOK)
return res;
}

View file

@ -67,7 +67,8 @@
SRCID(thw3i6, "$Id$");
Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
Word mask, Word pattern)
{
DWORD id;
Res res;
@ -77,7 +78,8 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
if(id != thread->id) { /* .thread.id */
CONTEXT context;
BOOL success;
Addr *stackBase, *stackLimit, stackPtr;
Word *stackBase, *stackLimit;
Addr stackPtr;
/* scan stack and register roots in other threads */
@ -95,15 +97,15 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
stackPtr = (Addr)context.Rsp; /* .i6.sp */
/* .stack.align */
stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
stackLimit = (Addr *)stackBot;
stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
stackLimit = stackBot;
if (stackBase >= stackLimit)
return ResOK; /* .stack.below-bottom */
/* scan stack inclusive of current sp and exclusive of
* stackBot (.stack.full-descend)
*/
res = TraceScanAreaTagged(ss, stackBase, stackLimit);
res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
if(res != ResOK)
return res;
@ -112,13 +114,14 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
* unnecessarily scans the rest of the context. The optimisation
* to scan only relevant parts would be machine dependent.
*/
res = TraceScanAreaTagged(ss, (Addr *)&context,
(Addr *)((char *)&context + sizeof(CONTEXT)));
res = TraceScanAreaMasked(ss, (Word *)&context,
(Word *)((char *)&context + sizeof(CONTEXT)),
mask, pattern);
if(res != ResOK)
return res;
} else { /* scan this thread's stack */
res = StackScan(ss, stackBot);
res = StackScan(ss, stackBot, mask, pattern);
if(res != ResOK)
return res;
}

View file

@ -189,7 +189,8 @@ Arena ThreadArena(Thread thread)
#include "prmcxc.h"
Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
Res ThreadScan(ScanState ss, Thread thread, Word *stackBot,
Word mask, Word pattern)
{
mach_port_t self;
Res res;
@ -199,13 +200,14 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
AVER(MACH_PORT_VALID(self));
if (thread->port == self) {
/* scan this thread's stack */
res = StackScan(ss, stackBot);
res = StackScan(ss, stackBot, mask, pattern);
if(res != ResOK)
return res;
} else {
MutatorFaultContextStruct mfcStruct;
THREAD_STATE_S threadState;
Addr *stackBase, *stackLimit, stackPtr;
Word *stackBase, *stackLimit;
Addr stackPtr;
mach_msg_type_number_t count;
kern_return_t kern_return;
@ -227,20 +229,20 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
stackPtr = MutatorFaultContextSP(&mfcStruct);
/* .stack.align */
stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
stackLimit = (Addr *)stackBot;
stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
stackLimit = stackBot;
if (stackBase >= stackLimit)
return ResOK; /* .stack.below-bottom */
/* scan stack inclusive of current sp and exclusive of
* stackBot (.stack.full-descend)
*/
res = TraceScanAreaTagged(ss, stackBase, stackLimit);
res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
if(res != ResOK)
return res;
/* scan the registers in the mutator fault context */
res = MutatorFaultContextScan(ss, &mfcStruct);
res = MutatorFaultContextScan(ss, &mfcStruct, mask, pattern);
if(res != ResOK)
return res;
}

View file

@ -1425,11 +1425,10 @@ void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena,
* [base, limit). I.e., it calls Fix on all words from base up to
* limit, inclusive of base and exclusive of limit. */
Res TraceScanArea(ScanState ss, Addr *base, Addr *limit)
Res TraceScanArea(ScanState ss, Word *base, Word *limit)
{
Res res;
Addr *p;
Ref ref;
Word word, *p;
AVER(base != NULL);
AVER(limit != NULL);
@ -1442,10 +1441,10 @@ Res TraceScanArea(ScanState ss, Addr *base, Addr *limit)
loop:
if (p >= limit)
goto out;
ref = *p++;
if(!TRACE_FIX1(ss, ref))
word = *p++;
if(!TRACE_FIX1(ss, (Ref)word))
goto loop;
res = TRACE_FIX2(ss, p-1);
res = TRACE_FIX2(ss, (Ref *)(p-1));
if(res == ResOK)
goto loop;
return res;
@ -1457,43 +1456,21 @@ Res TraceScanArea(ScanState ss, Addr *base, Addr *limit)
}
/* TraceScanAreaTagged -- scan contiguous area of tagged references
*
* .tagging: This is as TraceScanArea except words are only fixed they are
* tagged as zero according to the alignment of a Word.
*
* See also PoolSingleAccess <code/poolabs.c#.tagging>.
*
* TODO: Generalise the handling of tags so that pools can decide how
* their objects are tagged. This may use the user defined format
* to describe how tags are done */
Res TraceScanAreaTagged(ScanState ss, Addr *base, Addr *limit)
{
Word mask;
/* NOTE: An optimisation that maybe worth considering is setting some of the
* top bits in the mask as an early catch of addresses outside the arena.
* This might help slightly on 64-bit windows. However these are picked up
* soon afterwards by later checks. The bottom bits are more important
* to check as we ignore them in AMCFix, so the non-reference could
* otherwise end up pinning an object. */
mask = sizeof(Word) - 1;
AVER(WordIsP2(mask + 1));
return TraceScanAreaMasked(ss, base, limit, mask);
}
/* TraceScanAreaMasked -- scan contiguous area of filtered references
*
* This is as TraceScanArea except words are only fixed if they are zero
* when masked with a mask. */
* This is as TraceScanArea except words are only fixed if they have
* the given value when masked with a mask.
*
* This has ATTRIBUTE_NO_SANITIZE_ADDRESS otherwise Clang's address
* sanitizer will think we have run off the end of an array.
*/
ATTRIBUTE_NO_SANITIZE_ADDRESS
Res TraceScanAreaMasked(ScanState ss, Addr *base, Addr *limit, Word mask)
Res TraceScanAreaMasked(ScanState ss, Word *base, Word *limit, Word mask,
Word pattern)
{
Res res;
Addr *p;
Ref ref;
Word word, *p;
AVERT(ScanState, ss);
AVER(base != NULL);
@ -1507,12 +1484,12 @@ Res TraceScanAreaMasked(ScanState ss, Addr *base, Addr *limit, Word mask)
loop:
if (p >= limit)
goto out;
ref = *p++;
if (((Word)ref & mask)
!= 0) goto loop;
if (!TRACE_FIX1(ss, ref))
word = *p++;
if ((word & mask) != pattern)
goto loop;
res = TRACE_FIX2(ss, p-1);
if (!TRACE_FIX1(ss, (Ref)word))
goto loop;
res = TRACE_FIX2(ss, (Ref *)(p-1));
if(res == ResOK)
goto loop;
return res;

View file

@ -17,6 +17,10 @@ New features
specifying the minimum size of the memory segments that the pool
requests from the :term:`arena`.
#. New function :c:func:`mps_root_create_reg_masked` applies a mask
and pattern test to all words in registers and on the stack when
scanning them. This supports tagged references in these locations.
Interface changes
.................

View file

@ -393,10 +393,12 @@ Root interface
The registered root description persists until it is destroyed by
calling :c:func:`mps_root_destroy`.
.. c:function:: mps_res_t mps_root_create_reg(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_reg_scan_t reg_scan, void *p, size_t s)
Register a :term:`root` that consists of the :term:`references`
fixed in a :term:`thread's <thread>` stack by a scanning function.
fixed in a :term:`thread's <thread>` registers and stack by a
scanning function.
``root_o`` points to a location that will hold the address of the
new root description.
@ -427,7 +429,10 @@ Root interface
It is not supported for :term:`client programs` to pass their
own scanning functions to this function. The built-in MPS
function :c:func:`mps_stack_scan_ambig` must be used.
function :c:func:`mps_stack_scan_ambig` must be used. In this
case the ``p`` argument must be a pointer into the thread's
stack, as described for :c:func:`mps_root_create_reg_masked`
below, and the ``s`` argument is ignored.
This function is intended as a hook should we ever need to
allow client-specific extension or customization of stack and
@ -483,11 +488,14 @@ Root interface
It scans all integer registers and everything on the stack of the
thread given, and can therefore only be used with :term:`ambiguous
roots`. It only scans locations that are at, or higher on the
stack (that is, more recently added), the stack bottom that was
passed to :c:func:`mps_thread_reg`. References are assumed to be
represented as machine words, and are required to be
4-byte-aligned; unaligned values are ignored.
roots`. It scans locations that are more recently added than the
stack bottom that was passed in the ``p`` argument to
:c:func:`mps_root_create_reg`.
References are assumed to be represented as machine words, and are
required to be word-aligned; unaligned values are ignored. If
references are tagged, use :c:func:`mps_root_create_reg_masked`
instead.
.. note::
@ -496,6 +504,63 @@ Root interface
and in some cases on the compiler.
.. c:function:: mps_res_t mps_root_create_reg_masked(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_word_t mask, mps_word_t pattern, void *stack)
Register a :term:`root` that consists of the :term:`references` in
a :term:`thread's <thread>` registers and stack that match a
binary pattern.
``root_o`` points to a location that will hold the address of the
new root description.
``arena`` is the arena.
``rank`` is the :term:`rank` of references in the root.
``rm`` is the :term:`root mode`.
``thr`` is the thread.
``mask`` is an arbitrary mask that is applied to each word in the
thread's registers and stack.
``pattern`` is an arbitrary pattern; any word that is unequal to
this (after masking with ``mask``) is not considered to be a
reference.
``stack`` is a pointer into the thread's stack. On platforms where
the stack grows downwards (currently, all supported platforms),
locations below this address will be scanned.
Returns :c:macro:`MPS_RES_OK` if the root was registered
successfully, :c:macro:`MPS_RES_MEMORY` if the new root
description could not be allocated, or another :term:`result code`
if there was another error.
The registered root description persists until it is destroyed by
calling :c:func:`mps_root_destroy`.
.. warning::
A risk of using tagged pointers in registers and on the stack
is that in some circumstances, an optimizing compiler might
optimize away the tagged pointer, keeping only the untagged
version of the pointer. In this situation the pointer would be
ignored and if it was the last reference to the object the MPS
might incorrectly determine that it was dead.
You can avoid this risk by setting ``mask`` and ``pattern`` to
zero: in this case all words in registers and on the stack are
scanned, leading to possible additional scanning and retention.
.. note::
An optimization that may be worth considering is setting some
of the top bits in ``mask`` so that addresses that cannot be
allocated by the MPS are rejected quickly. This requires
expertise with the platform's virtual memory interface.
.. c:function:: mps_res_t mps_root_create_table(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_addr_t *base, size_t count)
Register a :term:`root` that consists of a vector of