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:
parent
3e9433f28f
commit
edf30c06b4
31 changed files with 335 additions and 174 deletions
|
|
@ -472,10 +472,9 @@ extern double TraceWorkFactor;
|
||||||
} \
|
} \
|
||||||
END
|
END
|
||||||
|
|
||||||
extern Res TraceScanArea(ScanState ss, Addr *base, Addr *limit);
|
extern Res TraceScanArea(ScanState ss, Word *base, Word *limit);
|
||||||
extern Res TraceScanAreaTagged(ScanState ss, Addr *base, Addr *limit);
|
extern Res TraceScanAreaMasked(ScanState ss, Word *base, Word *limit,
|
||||||
extern Res TraceScanAreaMasked(ScanState ss,
|
Word mask, Word value);
|
||||||
Addr *base, Addr *limit, Word mask);
|
|
||||||
extern void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena,
|
extern void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena,
|
||||||
Seg seg, Ref *refIO);
|
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,
|
extern Res RootCreateTable(Root *rootReturn, Arena arena,
|
||||||
Rank rank, RootMode mode,
|
Rank rank, RootMode mode,
|
||||||
Addr *base, Addr *limit);
|
Word *base, Word *limit);
|
||||||
extern Res RootCreateTableMasked(Root *rootReturn, Arena arena,
|
extern Res RootCreateTableMasked(Root *rootReturn, Arena arena,
|
||||||
Rank rank, RootMode mode,
|
Rank rank, RootMode mode,
|
||||||
Addr *base, Addr *limit,
|
Word *base, Word *limit,
|
||||||
Word mask);
|
Word mask);
|
||||||
extern Res RootCreateReg(Root *rootReturn, Arena arena,
|
extern Res RootCreateReg(Root *rootReturn, Arena arena,
|
||||||
Rank rank, Thread thread,
|
Rank rank, Thread thread,
|
||||||
mps_reg_scan_t scan,
|
mps_reg_scan_t scan,
|
||||||
void *p, size_t s);
|
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,
|
extern Res RootCreateFmt(Root *rootReturn, Arena arena,
|
||||||
Rank rank, RootMode mode,
|
Rank rank, RootMode mode,
|
||||||
mps_fmt_scan_t scan,
|
mps_fmt_scan_t scan,
|
||||||
|
|
|
||||||
|
|
@ -791,7 +791,7 @@ typedef struct mps_arena_s {
|
||||||
|
|
||||||
Bool emergency; /* garbage collect in emergency mode? */
|
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. */
|
/* that then entered the MPS. */
|
||||||
|
|
||||||
Sig sig;
|
Sig sig;
|
||||||
|
|
|
||||||
|
|
@ -362,6 +362,7 @@ enum {
|
||||||
RootTABLE,
|
RootTABLE,
|
||||||
RootTABLE_MASKED,
|
RootTABLE_MASKED,
|
||||||
RootREG,
|
RootREG,
|
||||||
|
RootREG_MASKED,
|
||||||
RootFMT,
|
RootFMT,
|
||||||
RootLIMIT
|
RootLIMIT
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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,
|
extern mps_res_t mps_root_create_reg(mps_root_t *, mps_arena_t,
|
||||||
mps_rank_t, mps_rm_t, mps_thr_t,
|
mps_rank_t, mps_rm_t, mps_thr_t,
|
||||||
mps_reg_scan_t, void *, size_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 void mps_root_destroy(mps_root_t);
|
||||||
|
|
||||||
extern mps_res_t mps_stack_scan_ambig(mps_ss_t, mps_thr_t,
|
extern mps_res_t mps_stack_scan_ambig(mps_ss_t, mps_thr_t,
|
||||||
|
|
|
||||||
|
|
@ -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. */
|
/* limit pointers. Be careful. */
|
||||||
|
|
||||||
res = RootCreateTable(&root, arena, rank, mode,
|
res = RootCreateTable(&root, arena, rank, mode,
|
||||||
(Addr *)base, (Addr *)base + size);
|
(Word *)base, (Word *)base + size);
|
||||||
|
|
||||||
ArenaLeave(arena);
|
ArenaLeave(arena);
|
||||||
|
|
||||||
|
|
@ -1335,7 +1335,7 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o,
|
||||||
/* See .root.table-size. */
|
/* See .root.table-size. */
|
||||||
|
|
||||||
res = RootCreateTableMasked(&root, arena, rank, mode,
|
res = RootCreateTableMasked(&root, arena, rank, mode,
|
||||||
(Addr *)base, (Addr *)base + size,
|
(Word *)base, (Word *)base + size,
|
||||||
mask);
|
mask);
|
||||||
|
|
||||||
ArenaLeave(arena);
|
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
|
/* mps_stack_scan_ambig -- scan the thread state ambiguously
|
||||||
*
|
*
|
||||||
* See .reg-scan. */
|
* 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);
|
ScanState ss = PARENT(ScanStateStruct, ss_s, mps_ss);
|
||||||
UNUSED(s);
|
UNUSED(s);
|
||||||
return ThreadScan(ss, thread, p);
|
return ThreadScan(ss, thread, (Word *)p, sizeof(mps_word_t) - 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
Res res;
|
||||||
|
|
||||||
/* This scans the root registers (.context.regroots). It also unnecessarily
|
/* This scans the root registers (.context.regroots). It also unnecessarily
|
||||||
scans the rest of the context. The optimisation to scan only relevant
|
scans the rest of the context. The optimisation to scan only relevant
|
||||||
parts would be machine dependent. */
|
parts would be machine dependent. */
|
||||||
res = TraceScanAreaTagged(
|
res = TraceScanAreaMasked(
|
||||||
ss,
|
ss,
|
||||||
(Addr *)mfc->ucontext,
|
(Word *)mfc->ucontext,
|
||||||
(Addr *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext)))
|
(Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))),
|
||||||
|
mask, pattern
|
||||||
);
|
);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
mcontext_t *mc;
|
||||||
Res res;
|
Res res;
|
||||||
|
|
@ -110,9 +111,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
|
||||||
unnecessarily scans the rest of the context. The optimisation
|
unnecessarily scans the rest of the context. The optimisation
|
||||||
to scan only relevant parts would be machine dependent. */
|
to scan only relevant parts would be machine dependent. */
|
||||||
mc = &mfc->ucontext->uc_mcontext;
|
mc = &mfc->ucontext->uc_mcontext;
|
||||||
res = TraceScanAreaTagged(ss,
|
res = TraceScanAreaMasked(ss,
|
||||||
(Addr *)mc,
|
(Word *)mc,
|
||||||
(Addr *)((char *)mc + sizeof(*mc)));
|
(Word *)((char *)mc + sizeof(*mc)),
|
||||||
|
mask, pattern);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
x86_thread_state32_t *mc;
|
||||||
Res res;
|
Res res;
|
||||||
|
|
@ -105,9 +106,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
|
||||||
unnecessarily scans the rest of the context. The optimisation
|
unnecessarily scans the rest of the context. The optimisation
|
||||||
to scan only relevant parts would be machine dependent. */
|
to scan only relevant parts would be machine dependent. */
|
||||||
mc = mfc->threadState;
|
mc = mfc->threadState;
|
||||||
res = TraceScanAreaTagged(ss,
|
res = TraceScanAreaMasked(ss,
|
||||||
(Addr *)mc,
|
(Word *)mc,
|
||||||
(Addr *)((char *)mc + sizeof(*mc)));
|
(Word *)((char *)mc + sizeof(*mc)),
|
||||||
|
mask, pattern);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
Res res;
|
||||||
|
|
||||||
/* This scans the root registers (.context.regroots). It also unnecessarily
|
/* This scans the root registers (.context.regroots). It also unnecessarily
|
||||||
scans the rest of the context. The optimisation to scan only relevant
|
scans the rest of the context. The optimisation to scan only relevant
|
||||||
parts would be machine dependent. */
|
parts would be machine dependent. */
|
||||||
res = TraceScanAreaTagged(
|
res = TraceScanAreaMasked(
|
||||||
ss,
|
ss,
|
||||||
(Addr *)mfc->ucontext,
|
(Word *)mfc->ucontext,
|
||||||
(Addr *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext)))
|
(Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))),
|
||||||
|
mask, pattern
|
||||||
);
|
);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
mcontext_t *mc;
|
||||||
Res res;
|
Res res;
|
||||||
|
|
@ -115,8 +116,9 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
|
||||||
to scan only relevant parts would be machine dependent. */
|
to scan only relevant parts would be machine dependent. */
|
||||||
mc = &mfc->ucontext->uc_mcontext;
|
mc = &mfc->ucontext->uc_mcontext;
|
||||||
res = TraceScanAreaTagged(ss,
|
res = TraceScanAreaTagged(ss,
|
||||||
(Addr *)mc,
|
(Word *)mc,
|
||||||
(Addr *)((char *)mc + sizeof(*mc)));
|
(Word *)((char *)mc + sizeof(*mc)),
|
||||||
|
mask, pattern);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
x86_thread_state64_t *mc;
|
||||||
Res res;
|
Res res;
|
||||||
|
|
@ -108,9 +109,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
|
||||||
unnecessarily scans the rest of the context. The optimisation
|
unnecessarily scans the rest of the context. The optimisation
|
||||||
to scan only relevant parts would be machine dependent. */
|
to scan only relevant parts would be machine dependent. */
|
||||||
mc = mfc->threadState;
|
mc = mfc->threadState;
|
||||||
res = TraceScanAreaTagged(ss,
|
res = TraceScanAreaMasked(ss,
|
||||||
(Addr *)mc,
|
(Word *)mc,
|
||||||
(Addr *)((char *)mc + sizeof(*mc)));
|
(Word *)((char *)mc + sizeof(*mc)),
|
||||||
|
mask, pattern);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,8 @@ extern void ProtSync(Arena arena);
|
||||||
extern Bool ProtCanStepInstruction(MutatorFaultContext context);
|
extern Bool ProtCanStepInstruction(MutatorFaultContext context);
|
||||||
extern Res ProtStepInstruction(MutatorFaultContext context);
|
extern Res ProtStepInstruction(MutatorFaultContext context);
|
||||||
extern Addr MutatorFaultContextSP(MutatorFaultContext mfc);
|
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 */
|
#endif /* prot_h */
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,14 @@ typedef struct RootStruct {
|
||||||
size_t s; /* environment for scan */
|
size_t s; /* environment for scan */
|
||||||
} fun;
|
} fun;
|
||||||
struct {
|
struct {
|
||||||
Addr *base; /* beginning of table */
|
Word *base; /* beginning of table */
|
||||||
Addr *limit; /* one off end of table */
|
Word *limit; /* one off end of table */
|
||||||
} table;
|
} table;
|
||||||
struct {
|
struct {
|
||||||
Addr *base; /* beginning of table */
|
Word *base; /* beginning of table */
|
||||||
Addr *limit; /* one off end of table */
|
Word *limit; /* one off end of table */
|
||||||
Word mask; /* tag mask for scanning */
|
Word mask; /* tag mask for scanning */
|
||||||
|
Word pattern; /* tag pattern for scanning */
|
||||||
} tableMasked;
|
} tableMasked;
|
||||||
struct {
|
struct {
|
||||||
mps_reg_scan_t scan; /* function for scanning registers */
|
mps_reg_scan_t scan; /* function for scanning registers */
|
||||||
|
|
@ -52,6 +53,12 @@ typedef struct RootStruct {
|
||||||
void *p; /* passed to scan */
|
void *p; /* passed to scan */
|
||||||
size_t s; /* passed to scan */
|
size_t s; /* passed to scan */
|
||||||
} reg;
|
} 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 {
|
struct {
|
||||||
mps_fmt_scan_t scan; /* format-like scanner */
|
mps_fmt_scan_t scan; /* format-like scanner */
|
||||||
Addr base, limit; /* passed to scan */
|
Addr base, limit; /* passed to scan */
|
||||||
|
|
@ -67,7 +74,8 @@ typedef struct RootStruct {
|
||||||
Bool RootVarCheck(RootVar rootVar)
|
Bool RootVarCheck(RootVar rootVar)
|
||||||
{
|
{
|
||||||
CHECKL(rootVar == RootTABLE || rootVar == RootTABLE_MASKED
|
CHECKL(rootVar == RootTABLE || rootVar == RootTABLE_MASKED
|
||||||
|| rootVar == RootFUN || rootVar == RootFMT || rootVar == RootREG);
|
|| rootVar == RootFUN || rootVar == RootFMT || rootVar == RootREG
|
||||||
|
|| rootVar == RootREG_MASKED);
|
||||||
UNUSED(rootVar);
|
UNUSED(rootVar);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -112,7 +120,7 @@ Bool RootCheck(Root root)
|
||||||
case RootTABLE_MASKED:
|
case RootTABLE_MASKED:
|
||||||
CHECKL(root->the.tableMasked.base != 0);
|
CHECKL(root->the.tableMasked.base != 0);
|
||||||
CHECKL(root->the.tableMasked.base < root->the.tableMasked.limit);
|
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;
|
break;
|
||||||
|
|
||||||
case RootFUN:
|
case RootFUN:
|
||||||
|
|
@ -122,6 +130,13 @@ Bool RootCheck(Root root)
|
||||||
case RootREG:
|
case RootREG:
|
||||||
CHECKL(root->the.reg.scan != NULL);
|
CHECKL(root->the.reg.scan != NULL);
|
||||||
CHECKD_NOSIG(Thread, root->the.reg.thread); /* <design/check/#hidden-type> */
|
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;
|
break;
|
||||||
|
|
||||||
case RootFMT:
|
case RootFMT:
|
||||||
|
|
@ -254,7 +269,7 @@ static Res rootCreateProtectable(Root *rootReturn, Arena arena,
|
||||||
}
|
}
|
||||||
|
|
||||||
Res RootCreateTable(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;
|
Res res;
|
||||||
union RootUnion theUnion;
|
union RootUnion theUnion;
|
||||||
|
|
@ -276,7 +291,7 @@ Res RootCreateTable(Root *rootReturn, Arena arena,
|
||||||
}
|
}
|
||||||
|
|
||||||
Res RootCreateTableMasked(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)
|
Word mask)
|
||||||
{
|
{
|
||||||
union RootUnion theUnion;
|
union RootUnion theUnion;
|
||||||
|
|
@ -291,6 +306,7 @@ Res RootCreateTableMasked(Root *rootReturn, Arena arena,
|
||||||
theUnion.tableMasked.base = base;
|
theUnion.tableMasked.base = base;
|
||||||
theUnion.tableMasked.limit = limit;
|
theUnion.tableMasked.limit = limit;
|
||||||
theUnion.tableMasked.mask = mask;
|
theUnion.tableMasked.mask = mask;
|
||||||
|
theUnion.tableMasked.pattern = 0;
|
||||||
|
|
||||||
return rootCreateProtectable(rootReturn, arena, rank, mode, RootTABLE_MASKED,
|
return rootCreateProtectable(rootReturn, arena, rank, mode, RootTABLE_MASKED,
|
||||||
(Addr)base, (Addr)limit, &theUnion);
|
(Addr)base, (Addr)limit, &theUnion);
|
||||||
|
|
@ -317,6 +333,28 @@ Res RootCreateReg(Root *rootReturn, Arena arena,
|
||||||
return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG, &theUnion);
|
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
|
/* RootCreateFmt -- create root from block of formatted objects
|
||||||
*
|
*
|
||||||
* .fmt.no-align-check: Note that we don't check the alignment of base
|
* .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,
|
res = TraceScanAreaMasked(ss,
|
||||||
root->the.tableMasked.base,
|
root->the.tableMasked.base,
|
||||||
root->the.tableMasked.limit,
|
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);
|
ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit);
|
||||||
if (res != ResOK)
|
if (res != ResOK)
|
||||||
goto failScan;
|
goto failScan;
|
||||||
|
|
@ -500,6 +539,15 @@ Res RootScan(ScanState ss, Root root)
|
||||||
goto failScan;
|
goto failScan;
|
||||||
break;
|
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:
|
case RootFMT:
|
||||||
res = (*root->the.fmt.scan)(&ss->ss_s, root->the.fmt.base, root->the.fmt.limit);
|
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);
|
ss->scannedSize += AddrOffset(root->the.fmt.base, root->the.fmt.limit);
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,8 @@ SRCID(ss, "$Id$");
|
||||||
* scanning.
|
* scanning.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Res StackScanInner(ScanState ss,
|
Res StackScanInner(ScanState ss, Word *stackBot, Word *stackTop,
|
||||||
Addr *stackBot,
|
Count nSavedRegs, Word mask, Word pattern)
|
||||||
Addr *stackTop,
|
|
||||||
Count nSavedRegs)
|
|
||||||
{
|
{
|
||||||
Arena arena;
|
Arena arena;
|
||||||
Res res;
|
Res res;
|
||||||
|
|
@ -49,14 +47,16 @@ Res StackScanInner(ScanState ss,
|
||||||
if (arena->stackAtArenaEnter != NULL) {
|
if (arena->stackAtArenaEnter != NULL) {
|
||||||
AVER(stackTop < arena->stackAtArenaEnter);
|
AVER(stackTop < arena->stackAtArenaEnter);
|
||||||
AVER(arena->stackAtArenaEnter < stackBot);
|
AVER(arena->stackAtArenaEnter < stackBot);
|
||||||
res = TraceScanAreaTagged(ss, stackTop, stackTop + nSavedRegs);
|
res = TraceScanAreaMasked(ss, stackTop, stackTop + nSavedRegs,
|
||||||
|
mask, pattern);
|
||||||
if (res != ResOK)
|
if (res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
res = TraceScanAreaTagged(ss, arena->stackAtArenaEnter, stackBot);
|
res = TraceScanAreaMasked(ss, arena->stackAtArenaEnter, stackBot,
|
||||||
|
mask, pattern);
|
||||||
if (res != ResOK)
|
if (res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
res = TraceScanAreaTagged(ss, stackTop, stackBot);
|
res = TraceScanAreaMasked(ss, stackTop, stackBot, mask, pattern);
|
||||||
if (res != ResOK)
|
if (res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,9 @@
|
||||||
* stack itself.
|
* stack itself.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern Res StackScan(ScanState ss, Addr *stackBot);
|
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);
|
||||||
extern Res StackScanInner(ScanState ss,
|
|
||||||
Addr *stackBot,
|
|
||||||
Addr *stackTop,
|
|
||||||
Count nSavedRegs);
|
|
||||||
|
|
||||||
#endif /* ss_h */
|
#endif /* ss_h */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,21 +21,22 @@
|
||||||
SRCID(ssan, "$Id$");
|
SRCID(ssan, "$Id$");
|
||||||
|
|
||||||
|
|
||||||
Res StackScan(ScanState ss, Addr *stackBot)
|
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
|
||||||
{
|
{
|
||||||
jmp_buf jb;
|
jmp_buf jb;
|
||||||
void *stackTop = &jb;
|
Word *stackTop = (Word *)&jb;
|
||||||
|
|
||||||
/* .assume.stack: This implementation assumes that the stack grows
|
/* .assume.stack: This implementation assumes that the stack grows
|
||||||
* downwards, so that the address of the jmp_buf is the limit of the
|
* 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
|
* part of the stack that needs to be scanned. (StackScanInner makes
|
||||||
* the same assumption.)
|
* the same assumption.)
|
||||||
*/
|
*/
|
||||||
AVER(stackTop < (void *)stackBot);
|
AVER(stackTop < stackBot);
|
||||||
|
|
||||||
(void)setjmp(jb);
|
(void)setjmp(jb);
|
||||||
|
|
||||||
return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Addr*));
|
return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Word*),
|
||||||
|
mask, pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,9 @@ SRCID(ssixi3, "$Id$");
|
||||||
#define ASMV(x) __asm__ volatile (x)
|
#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 */
|
/* .assume.asm.stack */
|
||||||
/* Store the callee save registers on the stack so they get scanned
|
/* 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 %%edi, %0" : "=m" (calleeSaveRegs[2]));
|
||||||
ASMV("mov %%ebp, %0" : "=m" (calleeSaveRegs[3]));
|
ASMV("mov %%ebp, %0" : "=m" (calleeSaveRegs[3]));
|
||||||
|
|
||||||
return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs));
|
return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs),
|
||||||
|
mask, pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,9 @@ SRCID(ssixi6, "$Id$");
|
||||||
#define ASMV(x) __asm__ volatile (x)
|
#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 */
|
/* .assume.asm.stack */
|
||||||
/* Store the callee save registers on the stack so they get scanned
|
/* 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 %%r14, %0" : "=m" (calleeSaveRegs[4]));
|
||||||
ASMV("mov %%r15, %0" : "=m" (calleeSaveRegs[5]));
|
ASMV("mov %%r15, %0" : "=m" (calleeSaveRegs[5]));
|
||||||
|
|
||||||
return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs));
|
return StackScanInner(ss, stackBot, calleeSaveRegs, NELEMS(calleeSaveRegs),
|
||||||
|
mask, pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
SRCID(ssw3i3mv, "$Id$");
|
SRCID(ssw3i3mv, "$Id$");
|
||||||
|
|
||||||
|
|
||||||
Res StackScan(ScanState ss, Addr *stackBot)
|
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
|
||||||
{
|
{
|
||||||
jmp_buf jb;
|
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
|
/* 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
|
setjmp.h header changes to indicate that the registers we want aren't
|
||||||
saved any more. */
|
saved any more. */
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->Edi) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->Edi) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->Esi) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->Esi) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->Ebx) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->Ebx) == sizeof(Word));
|
||||||
|
|
||||||
/* Ensure that the callee-save registers will be found by
|
/* Ensure that the callee-save registers will be found by
|
||||||
StackScanInner when it's passed the address of the Ebx field. */
|
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, Edi) == offsetof(_JUMP_BUFFER, Ebx) + 4);
|
||||||
AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8);
|
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
|
/* C. COPYRIGHT AND LICENSE
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ typedef struct __JUMP_BUFFER {
|
||||||
} _JUMP_BUFFER;
|
} _JUMP_BUFFER;
|
||||||
|
|
||||||
|
|
||||||
Res StackScan(ScanState ss, Addr *stackBot)
|
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
|
||||||
{
|
{
|
||||||
jmp_buf jb;
|
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, Edi) == offsetof(_JUMP_BUFFER, Ebx) + 4);
|
||||||
AVER(offsetof(_JUMP_BUFFER, Esi) == offsetof(_JUMP_BUFFER, Ebx) + 8);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
SRCID(ssw3i6mv, "$Id$");
|
SRCID(ssw3i6mv, "$Id$");
|
||||||
|
|
||||||
|
|
||||||
Res StackScan(ScanState ss, Addr *stackBot)
|
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
|
||||||
{
|
{
|
||||||
jmp_buf jb;
|
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
|
/* 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
|
setjmp.h header changes to indicate that the registers we want aren't
|
||||||
saved any more. */
|
saved any more. */
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->R15) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->R15) == sizeof(Word));
|
||||||
|
|
||||||
/* The layout of the jmp_buf forces us to harmlessly scan Rsp as well. */
|
/* The layout of the jmp_buf forces us to harmlessly scan Rsp as well. */
|
||||||
AVER(offsetof(_JUMP_BUFFER, Rsp) == offsetof(_JUMP_BUFFER, Rbx) + 8);
|
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, R14) == offsetof(_JUMP_BUFFER, Rbx) + 56);
|
||||||
AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64);
|
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
|
/* C. COPYRIGHT AND LICENSE
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ typedef struct _JUMP_BUFFER {
|
||||||
} _JUMP_BUFFER;
|
} _JUMP_BUFFER;
|
||||||
|
|
||||||
|
|
||||||
Res StackScan(ScanState ss, Addr *stackBot)
|
Res StackScan(ScanState ss, Word *stackBot, Word mask, Word pattern)
|
||||||
{
|
{
|
||||||
jmp_buf jb;
|
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
|
/* 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
|
setjmp.h header changes to indicate that the registers we want aren't
|
||||||
saved any more. */
|
saved any more. */
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rdi) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rsi) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->Rbp) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->R12) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->R13) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->R14) == sizeof(Word));
|
||||||
AVER(sizeof(((_JUMP_BUFFER *)jb)->R15) == sizeof(Addr));
|
AVER(sizeof(((_JUMP_BUFFER *)jb)->R15) == sizeof(Word));
|
||||||
|
|
||||||
/* The layout of the jmp_buf forces us to harmlessly scan Rsp as well. */
|
/* The layout of the jmp_buf forces us to harmlessly scan Rsp as well. */
|
||||||
AVER(offsetof(_JUMP_BUFFER, Rsp) == offsetof(_JUMP_BUFFER, Rbx) + 8);
|
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, R14) == offsetof(_JUMP_BUFFER, Rbx) + 56);
|
||||||
AVER(offsetof(_JUMP_BUFFER, R15) == offsetof(_JUMP_BUFFER, Rbx) + 64);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,8 @@ extern Thread ThreadRingThread(Ring threadRing);
|
||||||
|
|
||||||
extern Arena ThreadArena(Thread thread);
|
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 */
|
#endif /* th_h */
|
||||||
|
|
|
||||||
|
|
@ -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);
|
UNUSED(thread);
|
||||||
return StackScan(ss, stackBot);
|
return StackScan(ss, stackBot, mask, pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,8 @@ Arena ThreadArena(Thread thread)
|
||||||
|
|
||||||
/* ThreadScan -- scan the state of a thread (stack and regs) */
|
/* 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;
|
pthread_t self;
|
||||||
Res res;
|
Res res;
|
||||||
|
|
@ -231,12 +232,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
||||||
self = pthread_self();
|
self = pthread_self();
|
||||||
if(pthread_equal(self, thread->id)) {
|
if(pthread_equal(self, thread->id)) {
|
||||||
/* scan this thread's stack */
|
/* scan this thread's stack */
|
||||||
res = StackScan(ss, stackBot);
|
res = StackScan(ss, stackBot, mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
MutatorFaultContext mfc;
|
MutatorFaultContext mfc;
|
||||||
Addr *stackBase, *stackLimit, stackPtr;
|
Word *stackBase, *stackLimit;
|
||||||
|
Addr stackPtr;
|
||||||
|
|
||||||
mfc = thread->mfc;
|
mfc = thread->mfc;
|
||||||
if(mfc == NULL) {
|
if(mfc == NULL) {
|
||||||
|
|
@ -248,20 +250,20 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
||||||
|
|
||||||
stackPtr = MutatorFaultContextSP(mfc);
|
stackPtr = MutatorFaultContextSP(mfc);
|
||||||
/* .stack.align */
|
/* .stack.align */
|
||||||
stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
|
stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
|
||||||
stackLimit = (Addr *)stackBot;
|
stackLimit = stackBot;
|
||||||
if (stackBase >= stackLimit)
|
if (stackBase >= stackLimit)
|
||||||
return ResOK; /* .stack.below-bottom */
|
return ResOK; /* .stack.below-bottom */
|
||||||
|
|
||||||
/* scan stack inclusive of current sp and exclusive of
|
/* scan stack inclusive of current sp and exclusive of
|
||||||
* stackBot (.stack.full-descend)
|
* stackBot (.stack.full-descend)
|
||||||
*/
|
*/
|
||||||
res = TraceScanAreaTagged(ss, stackBase, stackLimit);
|
res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* scan the registers in the mutator fault context */
|
/* scan the registers in the mutator fault context */
|
||||||
res = MutatorFaultContextScan(ss, mfc);
|
res = MutatorFaultContextScan(ss, mfc, mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,8 @@
|
||||||
SRCID(thw3i3, "$Id$");
|
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;
|
DWORD id;
|
||||||
Res res;
|
Res res;
|
||||||
|
|
@ -77,7 +78,8 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
||||||
if(id != thread->id) { /* .thread.id */
|
if(id != thread->id) { /* .thread.id */
|
||||||
CONTEXT context;
|
CONTEXT context;
|
||||||
BOOL success;
|
BOOL success;
|
||||||
Addr *stackBase, *stackLimit, stackPtr;
|
Word *stackBase, *stackLimit;
|
||||||
|
Addr stackPtr;
|
||||||
|
|
||||||
/* scan stack and register roots in other threads */
|
/* 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 */
|
stackPtr = (Addr)context.Esp; /* .i3.sp */
|
||||||
/* .stack.align */
|
/* .stack.align */
|
||||||
stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
|
stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
|
||||||
stackLimit = (Addr *)stackBot;
|
stackLimit = stackBot;
|
||||||
if (stackBase >= stackLimit)
|
if (stackBase >= stackLimit)
|
||||||
return ResOK; /* .stack.below-bottom */
|
return ResOK; /* .stack.below-bottom */
|
||||||
|
|
||||||
/* scan stack inclusive of current sp and exclusive of
|
/* scan stack inclusive of current sp and exclusive of
|
||||||
* stackBot (.stack.full-descend)
|
* stackBot (.stack.full-descend)
|
||||||
*/
|
*/
|
||||||
res = TraceScanAreaTagged(ss, stackBase, stackLimit);
|
res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
|
@ -112,13 +114,14 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
||||||
* unnecessarily scans the rest of the context. The optimisation
|
* unnecessarily scans the rest of the context. The optimisation
|
||||||
* to scan only relevant parts would be machine dependent.
|
* to scan only relevant parts would be machine dependent.
|
||||||
*/
|
*/
|
||||||
res = TraceScanAreaTagged(ss, (Addr *)&context,
|
res = TraceScanAreaMasked(ss, (Word *)&context,
|
||||||
(Addr *)((char *)&context + sizeof(CONTEXT)));
|
(Word *)((char *)&context + sizeof(CONTEXT)),
|
||||||
|
mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
} else { /* scan this thread's stack */
|
} else { /* scan this thread's stack */
|
||||||
res = StackScan(ss, stackBot);
|
res = StackScan(ss, stackBot, mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,8 @@
|
||||||
SRCID(thw3i6, "$Id$");
|
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;
|
DWORD id;
|
||||||
Res res;
|
Res res;
|
||||||
|
|
@ -77,7 +78,8 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
||||||
if(id != thread->id) { /* .thread.id */
|
if(id != thread->id) { /* .thread.id */
|
||||||
CONTEXT context;
|
CONTEXT context;
|
||||||
BOOL success;
|
BOOL success;
|
||||||
Addr *stackBase, *stackLimit, stackPtr;
|
Word *stackBase, *stackLimit;
|
||||||
|
Addr stackPtr;
|
||||||
|
|
||||||
/* scan stack and register roots in other threads */
|
/* 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 */
|
stackPtr = (Addr)context.Rsp; /* .i6.sp */
|
||||||
/* .stack.align */
|
/* .stack.align */
|
||||||
stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
|
stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
|
||||||
stackLimit = (Addr *)stackBot;
|
stackLimit = stackBot;
|
||||||
if (stackBase >= stackLimit)
|
if (stackBase >= stackLimit)
|
||||||
return ResOK; /* .stack.below-bottom */
|
return ResOK; /* .stack.below-bottom */
|
||||||
|
|
||||||
/* scan stack inclusive of current sp and exclusive of
|
/* scan stack inclusive of current sp and exclusive of
|
||||||
* stackBot (.stack.full-descend)
|
* stackBot (.stack.full-descend)
|
||||||
*/
|
*/
|
||||||
res = TraceScanAreaTagged(ss, stackBase, stackLimit);
|
res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
|
@ -112,13 +114,14 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
||||||
* unnecessarily scans the rest of the context. The optimisation
|
* unnecessarily scans the rest of the context. The optimisation
|
||||||
* to scan only relevant parts would be machine dependent.
|
* to scan only relevant parts would be machine dependent.
|
||||||
*/
|
*/
|
||||||
res = TraceScanAreaTagged(ss, (Addr *)&context,
|
res = TraceScanAreaMasked(ss, (Word *)&context,
|
||||||
(Addr *)((char *)&context + sizeof(CONTEXT)));
|
(Word *)((char *)&context + sizeof(CONTEXT)),
|
||||||
|
mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
} else { /* scan this thread's stack */
|
} else { /* scan this thread's stack */
|
||||||
res = StackScan(ss, stackBot);
|
res = StackScan(ss, stackBot, mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,8 @@ Arena ThreadArena(Thread thread)
|
||||||
|
|
||||||
#include "prmcxc.h"
|
#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;
|
mach_port_t self;
|
||||||
Res res;
|
Res res;
|
||||||
|
|
@ -199,13 +200,14 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
||||||
AVER(MACH_PORT_VALID(self));
|
AVER(MACH_PORT_VALID(self));
|
||||||
if (thread->port == self) {
|
if (thread->port == self) {
|
||||||
/* scan this thread's stack */
|
/* scan this thread's stack */
|
||||||
res = StackScan(ss, stackBot);
|
res = StackScan(ss, stackBot, mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
MutatorFaultContextStruct mfcStruct;
|
MutatorFaultContextStruct mfcStruct;
|
||||||
THREAD_STATE_S threadState;
|
THREAD_STATE_S threadState;
|
||||||
Addr *stackBase, *stackLimit, stackPtr;
|
Word *stackBase, *stackLimit;
|
||||||
|
Addr stackPtr;
|
||||||
mach_msg_type_number_t count;
|
mach_msg_type_number_t count;
|
||||||
kern_return_t kern_return;
|
kern_return_t kern_return;
|
||||||
|
|
||||||
|
|
@ -227,20 +229,20 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
||||||
|
|
||||||
stackPtr = MutatorFaultContextSP(&mfcStruct);
|
stackPtr = MutatorFaultContextSP(&mfcStruct);
|
||||||
/* .stack.align */
|
/* .stack.align */
|
||||||
stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
|
stackBase = (Word *)AddrAlignUp(stackPtr, sizeof(Addr));
|
||||||
stackLimit = (Addr *)stackBot;
|
stackLimit = stackBot;
|
||||||
if (stackBase >= stackLimit)
|
if (stackBase >= stackLimit)
|
||||||
return ResOK; /* .stack.below-bottom */
|
return ResOK; /* .stack.below-bottom */
|
||||||
|
|
||||||
/* scan stack inclusive of current sp and exclusive of
|
/* scan stack inclusive of current sp and exclusive of
|
||||||
* stackBot (.stack.full-descend)
|
* stackBot (.stack.full-descend)
|
||||||
*/
|
*/
|
||||||
res = TraceScanAreaTagged(ss, stackBase, stackLimit);
|
res = TraceScanAreaMasked(ss, stackBase, stackLimit, mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* scan the registers in the mutator fault context */
|
/* scan the registers in the mutator fault context */
|
||||||
res = MutatorFaultContextScan(ss, &mfcStruct);
|
res = MutatorFaultContextScan(ss, &mfcStruct, mask, pattern);
|
||||||
if(res != ResOK)
|
if(res != ResOK)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
* [base, limit). I.e., it calls Fix on all words from base up to
|
||||||
* limit, inclusive of base and exclusive of limit. */
|
* 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;
|
Res res;
|
||||||
Addr *p;
|
Word word, *p;
|
||||||
Ref ref;
|
|
||||||
|
|
||||||
AVER(base != NULL);
|
AVER(base != NULL);
|
||||||
AVER(limit != NULL);
|
AVER(limit != NULL);
|
||||||
|
|
@ -1442,10 +1441,10 @@ Res TraceScanArea(ScanState ss, Addr *base, Addr *limit)
|
||||||
loop:
|
loop:
|
||||||
if (p >= limit)
|
if (p >= limit)
|
||||||
goto out;
|
goto out;
|
||||||
ref = *p++;
|
word = *p++;
|
||||||
if(!TRACE_FIX1(ss, ref))
|
if(!TRACE_FIX1(ss, (Ref)word))
|
||||||
goto loop;
|
goto loop;
|
||||||
res = TRACE_FIX2(ss, p-1);
|
res = TRACE_FIX2(ss, (Ref *)(p-1));
|
||||||
if(res == ResOK)
|
if(res == ResOK)
|
||||||
goto loop;
|
goto loop;
|
||||||
return res;
|
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
|
/* TraceScanAreaMasked -- scan contiguous area of filtered references
|
||||||
*
|
*
|
||||||
* This is as TraceScanArea except words are only fixed if they are zero
|
* This is as TraceScanArea except words are only fixed if they have
|
||||||
* when masked with a mask. */
|
* 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
|
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;
|
Res res;
|
||||||
Addr *p;
|
Word word, *p;
|
||||||
Ref ref;
|
|
||||||
|
|
||||||
AVERT(ScanState, ss);
|
AVERT(ScanState, ss);
|
||||||
AVER(base != NULL);
|
AVER(base != NULL);
|
||||||
|
|
@ -1507,12 +1484,12 @@ Res TraceScanAreaMasked(ScanState ss, Addr *base, Addr *limit, Word mask)
|
||||||
loop:
|
loop:
|
||||||
if (p >= limit)
|
if (p >= limit)
|
||||||
goto out;
|
goto out;
|
||||||
ref = *p++;
|
word = *p++;
|
||||||
if (((Word)ref & mask)
|
if ((word & mask) != pattern)
|
||||||
!= 0) goto loop;
|
|
||||||
if (!TRACE_FIX1(ss, ref))
|
|
||||||
goto loop;
|
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)
|
if(res == ResOK)
|
||||||
goto loop;
|
goto loop;
|
||||||
return res;
|
return res;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@ New features
|
||||||
specifying the minimum size of the memory segments that the pool
|
specifying the minimum size of the memory segments that the pool
|
||||||
requests from the :term:`arena`.
|
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
|
Interface changes
|
||||||
.................
|
.................
|
||||||
|
|
|
||||||
|
|
@ -393,10 +393,12 @@ Root interface
|
||||||
The registered root description persists until it is destroyed by
|
The registered root description persists until it is destroyed by
|
||||||
calling :c:func:`mps_root_destroy`.
|
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)
|
.. 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`
|
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
|
``root_o`` points to a location that will hold the address of the
|
||||||
new root description.
|
new root description.
|
||||||
|
|
@ -427,7 +429,10 @@ Root interface
|
||||||
|
|
||||||
It is not supported for :term:`client programs` to pass their
|
It is not supported for :term:`client programs` to pass their
|
||||||
own scanning functions to this function. The built-in MPS
|
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
|
This function is intended as a hook should we ever need to
|
||||||
allow client-specific extension or customization of stack and
|
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
|
It scans all integer registers and everything on the stack of the
|
||||||
thread given, and can therefore only be used with :term:`ambiguous
|
thread given, and can therefore only be used with :term:`ambiguous
|
||||||
roots`. It only scans locations that are at, or higher on the
|
roots`. It scans locations that are more recently added than the
|
||||||
stack (that is, more recently added), the stack bottom that was
|
stack bottom that was passed in the ``p`` argument to
|
||||||
passed to :c:func:`mps_thread_reg`. References are assumed to be
|
:c:func:`mps_root_create_reg`.
|
||||||
represented as machine words, and are required to be
|
|
||||||
4-byte-aligned; unaligned values are ignored.
|
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::
|
.. note::
|
||||||
|
|
||||||
|
|
@ -496,6 +504,63 @@ Root interface
|
||||||
and in some cases on the compiler.
|
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)
|
.. 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
|
Register a :term:`root` that consists of a vector of
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue