diff --git a/mps/code/check.h b/mps/code/check.h index 7b9da23ae84..32a455bde87 100644 --- a/mps/code/check.h +++ b/mps/code/check.h @@ -56,6 +56,10 @@ mps_lib_assert_fail(MPS_FILE, __LINE__, (condstring)); \ END +#define ASSERTP(cond, condstring, dflt) \ + ((cond) ? (dflt) : \ + mps_lib_assert_fail_expr(MPS_FILE, __LINE__, condstring, dflt)) + #define ASSERT_ISTYPE(type, val) (type ## Check(val)) #define ASSERT_TYPECHECK(type, val) \ ASSERT(ASSERT_ISTYPE(type, val), "TypeCheck " #type ": " #val) @@ -109,17 +113,27 @@ extern unsigned CheckLevel; #endif -/* AVER, AVERT -- MPM assertions +/* AVER, AVERT, AVERC, AVERP -- MPM assertions * - * AVER and AVERT are used to assert conditions in the code. AVER checks - * an expression. AVERT checks that a value is of the correct type and - * may perform consistency checks on the value. + * AVER and friends are used to assert conditions in the code. * - * AVER and AVERT are on by default, and check conditions even in "hot" - * varieties intended to work in production. To avoid the cost of a check - * in critical parts of the code, use AVER_CRITICAL and AVERT_CRITICAL, - * but only when you've *proved* that this makes a difference to performance - * that affects requirements. + * AVER checks an expression. + * + * AVERT checks that a value is of the correct type and may perform + * consistency checks on the value by calling a check function. + * + * AVERC checks that a value is of the correct class (including + * subclasses) and may perform consistency checks on the value by + * calling a check function. + * + * AVERP checks an expression but is itself a void * expression, and + * so can be used in expression macros. + * + * AVER etc. are on by default, and check conditions even in "hot" + * varieties intended to work in production. To avoid the cost of a + * check in critical parts of the code, use AVER_CRITICAL etc., but + * only when you've *proved* that this makes a difference to + * performance that affects requirements. */ #if defined(AVER_AND_CHECK_NONE) @@ -127,12 +141,14 @@ extern unsigned CheckLevel; #define AVER(cond) DISCARD(cond) #define AVERT(type, val) DISCARD(ASSERT_ISTYPE(type, val)) #define AVERC(class, val) DISCARD(ASSERT_ISCLASS(class, val)) +#define AVERP(cond, dflt) (DISCARD_EXP(cond), dflt) #else #define AVER(cond) ASSERT(cond, #cond) #define AVERT ASSERT_TYPECHECK #define AVERC ASSERT_CLASSCHECK +#define AVERP(cond, dflt) ASSERTP(cond, #cond, dflt) #endif @@ -141,12 +157,14 @@ extern unsigned CheckLevel; #define AVER_CRITICAL(cond) ASSERT(cond, #cond) #define AVERT_CRITICAL ASSERT_TYPECHECK #define AVERC_CRITICAL ASSERT_CLASSCHECK +#define AVERP_CRITICAL(cond, dflt) ASSERTP(cond, #cond, dflt) #else #define AVER_CRITICAL DISCARD #define AVERT_CRITICAL(type, val) DISCARD(ASSERT_ISTYPE(type, val)) #define AVERC_CRITICAL(class, val) DISCARD(ASSERT_ISCLASS(class, val)) +#define AVERP_CRITICAL(cond, dflt) (DISCARD_EXP(cond), dflt) #endif diff --git a/mps/code/misc.h b/mps/code/misc.h index 9b22522558a..f43df0e8804 100644 --- a/mps/code/misc.h +++ b/mps/code/misc.h @@ -125,6 +125,15 @@ typedef const struct SrcIdStruct { END +/* DISCARD_EXP -- discard an expression, as an expression + * + * Like DISCARD, except that it is itself an expression yielding zero + * (the most ambiguous expression). + */ + +#define DISCARD_EXP(expr) (sizeof((expr)!=0), 0) + + /* DISCARD_STAT -- discards a statement, but checks syntax * * The argument is a statement; the expansion followed by a semicolon diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 92340793895..7b6c1ad1859 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -1534,7 +1534,7 @@ static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) return ResOK; } - amc = MustBeA(AMCZPool, pool); /* FIXME: CRITICAL */ + amc = MustBeA_CRITICAL(AMCZPool, pool); AVERT_CRITICAL(AMC, amc); format = pool->format; headerSize = format->headerSize; @@ -1745,7 +1745,7 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg) */ static void AMCReclaim(Pool pool, Trace trace, Seg seg) { - AMC amc = MustBeA(AMCZPool, pool); /* FIXME: CRITICAL */ + AMC amc = MustBeA_CRITICAL(AMCZPool, pool); amcGen gen; AVERT_CRITICAL(Trace, trace); diff --git a/mps/code/protocol.h b/mps/code/protocol.h index 9c509e81e14..f2165ff72af 100644 --- a/mps/code/protocol.h +++ b/mps/code/protocol.h @@ -206,9 +206,6 @@ extern void InstFinish(Inst inst); /* IsA, CouldBeA, MustBeA -- coerce instances safely - * - * FIXME: Enumerate TypeIds to avoid call to ensure method and - * subclass test. * * FIXME: Wrap mps_lib_assert_fail_expr in check.h so that it is * elided from some varieties. @@ -222,14 +219,16 @@ extern void InstFinish(Inst inst); #define IsA(_class, inst) \ IsSubclass(CouldBeA(Inst, inst)->class, _class) -#define MustBeA(_class, inst) \ +#define IsNonNullAndA(_class, inst) \ ((inst) != NULL && \ CouldBeA(Inst, inst)->class != NULL && \ - IsA(_class, inst) ? \ - CouldBeA(_class, inst) : \ - CouldBeA(_class, mps_lib_assert_fail_expr(MPS_FILE, __LINE__, \ - "MustBeA " #_class ": " #inst, \ - inst))) + IsA(_class, inst)) + +#define MustBeA(_class, inst) \ + CouldBeA(_class, AVERP(IsNonNullAndA(_class, inst), inst)) + +#define MustBeA_CRITICAL(_class, inst) \ + CouldBeA(_class, AVERP_CRITICAL(IsNonNullAndA(_class, inst), inst)) /* ClassOf* -- get the class of an instance */