mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-26 08:41:47 -07:00
Fixing bugs introduced by type puns passed through scanning methods, discovered by offsetting mps_ss_s from the beginning of scanstatestruct.
Adding a pseudo-target "find-puns" which, on FreeBSD mostly, prints useful warnings about strict aliasing rule violations. Fixing more strict aliasing rule violations found by the above. Copied from Perforce Change: 179358 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
6db2c18143
commit
dd039bfbdc
9 changed files with 60 additions and 41 deletions
|
|
@ -498,6 +498,18 @@ $(PFM)/$(VARIETY)/%:
|
|||
$(CC) $(CFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
|
||||
# Special targets for development
|
||||
|
||||
# Currently FreeBSD 7 GCC 4.2.1 is the best platform we have for warning
|
||||
# us about strict aliasing rule violations caused by type puns. This
|
||||
# target reveals them, and produces an assembler output file that can be
|
||||
# examined to see if they're actually dangerous. RB 2012-09-07
|
||||
|
||||
find-puns: phony
|
||||
{ echo '#include "mps.c"'; echo '#include "fmtdy.c"'; } | \
|
||||
gcc -S -fverbose-asm -ansi -pedantic -Wall -Wstrict-aliasing=2 -O3 -x c -o pun.s -
|
||||
|
||||
|
||||
# C. COPYRIGHT AND LICENSE
|
||||
#
|
||||
# Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
|
|
|
|||
|
|
@ -154,9 +154,13 @@ extern Res WriteF_v(mps_lib_FILE *stream, va_list args);
|
|||
extern Res WriteF_firstformat_v(mps_lib_FILE *stream,
|
||||
const char *firstformat, va_list args);
|
||||
|
||||
#if defined(DIAG_WITH_STREAM_AND_WRITEF)
|
||||
extern int Stream_fputc(int c, mps_lib_FILE *stream);
|
||||
extern int Stream_fputs(const char *s, mps_lib_FILE *stream);
|
||||
|
||||
#else
|
||||
#define Stream_fputc mps_lib_fputc
|
||||
#define Stream_fputs mps_lib_fputs
|
||||
#endif
|
||||
|
||||
|
||||
/* Miscellaneous support -- see <code/mpm.c> */
|
||||
|
|
@ -419,6 +423,8 @@ extern double TraceWorkFactor;
|
|||
ZoneSet SCANwhite = ScanStateWhite(ss); \
|
||||
RefSet SCANsummary = ScanStateUnfixedSummary(ss); \
|
||||
Word SCANt; \
|
||||
mps_addr_t SCANref; \
|
||||
Res SCANres; \
|
||||
{
|
||||
|
||||
/* Equivalent to <code/mps.h> MPS_FIX1 */
|
||||
|
|
@ -430,7 +436,17 @@ extern double TraceWorkFactor;
|
|||
|
||||
/* Equivalent to <code/mps.h> MPS_FIX2 */
|
||||
|
||||
#define TRACE_FIX2(ss, refIO) _mps_fix2((mps_ss_t)(ss), (mps_addr_t *)(refIO))
|
||||
/* TODO: The ref is copied to avoid breaking strict aliasing rules that could
|
||||
well affect optimised scan loops. This code could be improved by
|
||||
returning the fixed ref as a result and using longjmp to signal errors,
|
||||
and that might well improve all scan loops too. The problem is whether
|
||||
some embedded client platforms support longjmp. RB 2012-09-07 */
|
||||
|
||||
#define TRACE_FIX2(ss, refIO) \
|
||||
(SCANref = (mps_addr_t)*(refIO), \
|
||||
SCANres = _mps_fix2(&(ss)->ss_s, &SCANref), \
|
||||
*(refIO) = SCANref, \
|
||||
SCANres)
|
||||
|
||||
/* Equivalent to <code/mps.h> MPS_FIX */
|
||||
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ typedef struct TraceMessageStruct *TraceMessage; /* trace end */
|
|||
/* .fmt-methods: These methods must match those defined in the */
|
||||
/* MPS C Interface. (See <code/mps.h#fmt-methods>.) */
|
||||
|
||||
typedef Res (*FormatScanMethod)(ScanState ss, Addr base, Addr limit);
|
||||
typedef Res (*FormatScanMethod)(mps_ss_t ss, Addr base, Addr limit);
|
||||
typedef Addr (*FormatSkipMethod)(Addr object);
|
||||
typedef void (*FormatMoveMethod)(Addr object, Addr to);
|
||||
typedef Addr (*FormatIsMovedMethod)(Addr object);
|
||||
|
|
@ -259,8 +259,8 @@ typedef Addr (*FormatClassMethod)(Addr object);
|
|||
/* .root-methods: These methods must match those defined in the */
|
||||
/* MPS C Interface. (See <code/mps.h#root-methods>.) */
|
||||
|
||||
typedef Res (*RootScanMethod)(ScanState ss, void *p, size_t s);
|
||||
typedef Res (*RootScanRegMethod)(ScanState ss, Thread thread, void *p, size_t s);
|
||||
typedef Res (*RootScanMethod)(mps_ss_t ss, void *p, size_t s);
|
||||
typedef Res (*RootScanRegMethod)(mps_ss_t ss, Thread thread, void *p, size_t s);
|
||||
|
||||
|
||||
/* CONSTANTS */
|
||||
|
|
|
|||
|
|
@ -1453,7 +1453,7 @@ static Res amcScanNailedOnce(Bool *totalReturn, Bool *moreReturn,
|
|||
Addr q;
|
||||
q = (*format->skip)(p);
|
||||
if(amcNailGetMark(seg, p)) {
|
||||
res = (*format->scan)(ss, p, q);
|
||||
res = (*format->scan)(&ss->ss_s, p, q);
|
||||
if(res != ResOK) {
|
||||
*totalReturn = FALSE;
|
||||
*moreReturn = TRUE;
|
||||
|
|
@ -1476,7 +1476,7 @@ static Res amcScanNailedOnce(Bool *totalReturn, Bool *moreReturn,
|
|||
Addr q;
|
||||
q = (*format->skip)(p);
|
||||
if(amcNailGetMark(seg, p)) {
|
||||
res = (*format->scan)(ss, p, q);
|
||||
res = (*format->scan)(&ss->ss_s, p, q);
|
||||
if(res != ResOK) {
|
||||
*totalReturn = FALSE;
|
||||
*moreReturn = TRUE;
|
||||
|
|
@ -1601,7 +1601,7 @@ static Res AMCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
|
|||
*totalReturn = TRUE;
|
||||
return ResOK;
|
||||
}
|
||||
res = (*format->scan)(ss, base, limit);
|
||||
res = (*format->scan)(&ss->ss_s, base, limit);
|
||||
if(res != ResOK) {
|
||||
*totalReturn = FALSE;
|
||||
return res;
|
||||
|
|
@ -1615,7 +1615,7 @@ static Res AMCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
|
|||
AVER(SegBase(seg) <= base);
|
||||
AVER(base <= AddrAdd(SegLimit(seg), format->headerSize));
|
||||
if(base < limit) {
|
||||
res = (*format->scan)(ss, base, limit);
|
||||
res = (*format->scan)(&ss->ss_s, base, limit);
|
||||
if(res != ResOK) {
|
||||
*totalReturn = FALSE;
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -1237,7 +1237,7 @@ static Res amsScanObject(Seg seg, Index i, Addr p, Addr next, void *clos)
|
|||
|
||||
/* @@@@ This isn't quite right for multiple traces. */
|
||||
if (closure->scanAllObjects || AMS_IS_GREY(seg, i)) {
|
||||
res = (*format->scan)(closure->ss,
|
||||
res = (*format->scan)(&closure->ss->ss_s,
|
||||
AddrAdd(p, format->headerSize),
|
||||
AddrAdd(next, format->headerSize));
|
||||
if (res != ResOK)
|
||||
|
|
@ -1331,7 +1331,7 @@ Res AMSScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
|
|||
next = AddrAdd(p, alignment);
|
||||
}
|
||||
j = AMS_ADDR_INDEX(seg, next);
|
||||
res = (*format->scan)(ss, clientP, clientNext);
|
||||
res = (*format->scan)(&ss->ss_s, clientP, clientNext);
|
||||
if (res != ResOK) {
|
||||
/* <design/poolams/#marked.scan.fail> */
|
||||
amsseg->marksChanged = TRUE;
|
||||
|
|
|
|||
|
|
@ -820,7 +820,7 @@ static Res awlScanObject(Arena arena, AWL awl, ScanState ss,
|
|||
SegSetSummary(dependentSeg, RefSetUNIV);
|
||||
}
|
||||
|
||||
res = (*format->scan)(ss, base, limit);
|
||||
res = (*format->scan)(&ss->ss_s, base, limit);
|
||||
if (res == ResOK)
|
||||
ss->scannedSize += AddrOffset(base, limit);
|
||||
|
||||
|
|
|
|||
|
|
@ -516,7 +516,7 @@ static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
|
|||
}
|
||||
|
||||
if (base < limit) {
|
||||
res = (*format->scan)(ss, base, limit);
|
||||
res = (*format->scan)(&ss->ss_s, base, limit);
|
||||
if (res != ResOK) {
|
||||
*totalReturn = FALSE;
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -478,20 +478,20 @@ Res RootScan(ScanState ss, Root root)
|
|||
break;
|
||||
|
||||
case RootFUN:
|
||||
res = (*root->the.fun.scan)(ss, root->the.fun.p, root->the.fun.s);
|
||||
res = (*root->the.fun.scan)(&ss->ss_s, root->the.fun.p, root->the.fun.s);
|
||||
if (res != ResOK)
|
||||
goto failScan;
|
||||
break;
|
||||
|
||||
case RootREG:
|
||||
res = (*root->the.reg.scan)(ss, root->the.reg.thread,
|
||||
res = (*root->the.reg.scan)(&ss->ss_s, root->the.reg.thread,
|
||||
root->the.reg.p, root->the.reg.s);
|
||||
if (res != ResOK)
|
||||
goto failScan;
|
||||
break;
|
||||
|
||||
case RootFMT:
|
||||
res = (*root->the.fmt.scan)(ss, 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);
|
||||
if (res != ResOK)
|
||||
goto failScan;
|
||||
|
|
|
|||
|
|
@ -1295,26 +1295,31 @@ void TraceSegAccess(Arena arena, Seg seg, AccessSet mode)
|
|||
}
|
||||
|
||||
|
||||
/* TraceFix2 -- second stage of fixing a reference
|
||||
/* _mps_fix2 (a.k.a. "TraceFix") -- second stage of fixing a reference
|
||||
*
|
||||
* TraceFix is on the [critical path](../design/critical-path.txt). A
|
||||
* _mps_fix2 is on the [critical path](../design/critical-path.txt). A
|
||||
* one-instruction difference in the early parts of this code will have a
|
||||
* significant impact on overall run time. The priority is to eliminate
|
||||
* irrelevant references early and fast using the colour information stored
|
||||
* in the tract table.
|
||||
*
|
||||
* The name "TraceFix" is pervasive in the MPS and its documents to describe
|
||||
* this function. Optimisation and strict aliasing rules have meant that we
|
||||
* need to use the external name for it here.
|
||||
*/
|
||||
|
||||
static Res TraceFix2(ScanState ss, Ref *refIO)
|
||||
mps_res_t _mps_fix2(mps_ss_t mps_ss, mps_addr_t *mps_ref_io)
|
||||
{
|
||||
ScanState ss = PARENT(ScanStateStruct, ss_s, mps_ss);
|
||||
Ref ref;
|
||||
Tract tract;
|
||||
|
||||
/* Special AVER macros are used on the critical path. */
|
||||
/* See <design/trace/#fix.noaver> */
|
||||
AVERT_CRITICAL(ScanState, ss);
|
||||
AVER_CRITICAL(refIO != NULL);
|
||||
AVER_CRITICAL(mps_ref_io != NULL);
|
||||
|
||||
ref = *refIO;
|
||||
ref = (Ref)*mps_ref_io;
|
||||
|
||||
/* The zone test should already have been passed by MPS_FIX1 in mps.h. */
|
||||
AVER_CRITICAL(ZoneSetInter(ScanStateWhite(ss),
|
||||
|
|
@ -1322,7 +1327,7 @@ static Res TraceFix2(ScanState ss, Ref *refIO)
|
|||
ZoneSetEMPTY);
|
||||
|
||||
STATISTIC(++ss->fixRefCount);
|
||||
EVENT4(TraceFix, ss, refIO, ref, ss->rank);
|
||||
EVENT4(TraceFix, ss, mps_ref_io, ref, ss->rank);
|
||||
|
||||
TRACT_OF_ADDR(&tract, ss->arena, ref);
|
||||
if(tract) {
|
||||
|
|
@ -1336,7 +1341,7 @@ static Res TraceFix2(ScanState ss, Ref *refIO)
|
|||
EVENT1(TraceFixSeg, seg);
|
||||
EVENT0(TraceFixWhite);
|
||||
pool = TractPool(tract);
|
||||
res = (*ss->fix)(pool, ss, seg, refIO);
|
||||
res = (*ss->fix)(pool, ss, seg, &ref);
|
||||
if(res != ResOK) {
|
||||
/* PoolFixEmergency should never fail. */
|
||||
AVER_CRITICAL(ss->fix != PoolFixEmergency);
|
||||
|
|
@ -1347,7 +1352,7 @@ static Res TraceFix2(ScanState ss, Ref *refIO)
|
|||
* C: the code (here) already assumes this: it returns without
|
||||
* updating ss->fixedSummary. RHSK 2007-03-21.
|
||||
*/
|
||||
AVER(*refIO == ref);
|
||||
AVER(ref == (Ref)*mps_ref_io);
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1378,27 +1383,13 @@ static Res TraceFix2(ScanState ss, Ref *refIO)
|
|||
}
|
||||
|
||||
/* See <design/trace/#fix.fixed.all> */
|
||||
ss->fixedSummary = RefSetAdd(ss->arena, ss->fixedSummary, *refIO);
|
||||
|
||||
ss->fixedSummary = RefSetAdd(ss->arena, ss->fixedSummary, ref);
|
||||
|
||||
*mps_ref_io = (mps_addr_t)ref;
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* mps_fix2 -- external interface to TraceFix
|
||||
*
|
||||
* We rely on compiler inlining to make this equivalent to TraceFix, because
|
||||
* the name "TraceFix" is pervasive in the MPS. That's also why this
|
||||
* function is in trace.c and not mpsi.c.
|
||||
*/
|
||||
|
||||
mps_res_t _mps_fix2(mps_ss_t mps_ss, mps_addr_t *mps_ref_io)
|
||||
{
|
||||
ScanState ss = PARENT(ScanStateStruct, ss_s, mps_ss);
|
||||
Ref *refIO = (Ref *)mps_ref_io;
|
||||
return TraceFix2(ss, refIO);
|
||||
}
|
||||
|
||||
|
||||
/* traceScanSingleRefRes -- scan a single reference, with result code */
|
||||
|
||||
static Res traceScanSingleRefRes(TraceSet ts, Rank rank, Arena arena,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue