diff --git a/js/public/Class.h b/js/public/Class.h index 669c89fa618e..27c1f26803e2 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -529,21 +529,36 @@ struct Class static size_t offsetOfFlags() { return offsetof(Class, flags); } }; -JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name)); -JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags)); -JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty)); -JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty)); -JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty)); -JS_STATIC_ASSERT(offsetof(JSClass, setProperty) == offsetof(Class, setProperty)); -JS_STATIC_ASSERT(offsetof(JSClass, enumerate) == offsetof(Class, enumerate)); -JS_STATIC_ASSERT(offsetof(JSClass, resolve) == offsetof(Class, resolve)); -JS_STATIC_ASSERT(offsetof(JSClass, convert) == offsetof(Class, convert)); -JS_STATIC_ASSERT(offsetof(JSClass, finalize) == offsetof(Class, finalize)); -JS_STATIC_ASSERT(offsetof(JSClass, call) == offsetof(Class, call)); -JS_STATIC_ASSERT(offsetof(JSClass, construct) == offsetof(Class, construct)); -JS_STATIC_ASSERT(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance)); -JS_STATIC_ASSERT(offsetof(JSClass, trace) == offsetof(Class, trace)); -JS_STATIC_ASSERT(sizeof(JSClass) == sizeof(Class)); +static_assert(offsetof(JSClass, name) == offsetof(Class, name), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, flags) == offsetof(Class, flags), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, addProperty) == offsetof(Class, addProperty), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, delProperty) == offsetof(Class, delProperty), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, getProperty) == offsetof(Class, getProperty), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, setProperty) == offsetof(Class, setProperty), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, enumerate) == offsetof(Class, enumerate), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, resolve) == offsetof(Class, resolve), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, convert) == offsetof(Class, convert), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, finalize) == offsetof(Class, finalize), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, call) == offsetof(Class, call), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, construct) == offsetof(Class, construct), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance), + "Class and JSClass must be consistent"); +static_assert(offsetof(JSClass, trace) == offsetof(Class, trace), + "Class and JSClass must be consistent"); +static_assert(sizeof(JSClass) == sizeof(Class), + "Class and JSClass must be consistent"); static MOZ_ALWAYS_INLINE const JSClass * Jsvalify(const Class *c) diff --git a/js/public/HashTable.h b/js/public/HashTable.h index 4ef0d138b153..c7b85224284d 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -536,11 +536,14 @@ struct PointerHasher static HashNumber hash(const Lookup &l) { MOZ_ASSERT(!JS::IsPoisonedPtr(l)); size_t word = reinterpret_cast(l) >> zeroBits; - JS_STATIC_ASSERT(sizeof(HashNumber) == 4); + static_assert(sizeof(HashNumber) == 4, + "subsequent code assumes a four-byte hash"); #if JS_BITS_PER_WORD == 32 return HashNumber(word); #else - JS_STATIC_ASSERT(sizeof word == 8); + static_assert(sizeof(word) == 8, + "unexpected word size, new hashing strategy required to " + "properly incorporate all bits"); return HashNumber((word >> 32) ^ word); #endif } @@ -587,7 +590,8 @@ struct DefaultHasher { typedef double Lookup; static HashNumber hash(double d) { - JS_STATIC_ASSERT(sizeof(HashNumber) == 4); + static_assert(sizeof(HashNumber) == 4, + "subsequent code assumes a four-byte hash"); uint64_t u = mozilla::BitwiseCast(d); return HashNumber(u ^ (u >> 32)); } @@ -601,7 +605,8 @@ struct DefaultHasher { typedef float Lookup; static HashNumber hash(float f) { - JS_STATIC_ASSERT(sizeof(HashNumber) == 4); + static_assert(sizeof(HashNumber) == 4, + "subsequent code assumes a four-byte hash"); return HashNumber(mozilla::BitwiseCast(f)); } static bool match(float lhs, float rhs) { diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 4b52fa80bf08..75647458f415 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -1302,7 +1302,8 @@ MapObject::size_impl(JSContext *cx, CallArgs args) MOZ_ASSERT(MapObject::is(args.thisv())); ValueMap &map = extract(args); - JS_STATIC_ASSERT(sizeof map.count() <= sizeof(uint32_t)); + static_assert(sizeof(map.count()) <= sizeof(uint32_t), + "map count must be precisely representable as a JS number"); args.rval().setNumber(map.count()); return true; } @@ -1832,7 +1833,8 @@ SetObject::size_impl(JSContext *cx, CallArgs args) MOZ_ASSERT(is(args.thisv())); ValueSet &set = extract(args); - JS_STATIC_ASSERT(sizeof set.count() <= sizeof(uint32_t)); + static_assert(sizeof(set.count()) <= sizeof(uint32_t), + "set count must be precisely representable as a JS number"); args.rval().setNumber(set.count()); return true; } diff --git a/js/src/ds/FixedSizeHash.h b/js/src/ds/FixedSizeHash.h index 9dc373010742..9301c4d4699b 100644 --- a/js/src/ds/FixedSizeHash.h +++ b/js/src/ds/FixedSizeHash.h @@ -43,13 +43,14 @@ class FixedSizeHashSet static const size_t NumHashes = HashPolicy::NumHashes; + static_assert(Capacity > 0, "an empty fixed-size hash set is meaningless"); + public: typedef typename HashPolicy::Lookup Lookup; FixedSizeHashSet() : entries(), lastOperations(), numOperations(0) { - JS_STATIC_ASSERT(Capacity > 0); MOZ_ASSERT(HashPolicy::isCleared(entries[0])); } diff --git a/js/src/ds/InlineMap.h b/js/src/ds/InlineMap.h index 04496faa1c0f..05c649b9a516 100644 --- a/js/src/ds/InlineMap.h +++ b/js/src/ds/InlineMap.h @@ -42,9 +42,8 @@ class InlineMap InlineElem inl[InlineElems]; WordMap map; - void checkStaticInvariants() { - JS_STATIC_ASSERT(ZeroIsReserved::result); - } + static_assert(ZeroIsReserved::result, + "zero as tombstone requires that zero keys be invalid"); bool usingMap() const { return inlNext > InlineElems; @@ -81,10 +80,7 @@ class InlineMap } public: - explicit InlineMap() - : inlNext(0), inlCount(0) { - checkStaticInvariants(); /* Force the template to instantiate the static invariants. */ - } + explicit InlineMap() : inlNext(0), inlCount(0) { } class Entry { diff --git a/js/src/ds/LifoAlloc.h b/js/src/ds/LifoAlloc.h index 0f06dcd9c2a1..de500c7e72e9 100644 --- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -303,7 +303,9 @@ class LifoAlloc template T *newArray(size_t count) { - JS_STATIC_ASSERT(mozilla::IsPod::value); + static_assert(mozilla::IsPod::value, + "T must be POD so that constructors (and destructors, " + "when the LifoAlloc is freed) need not be called"); return newArrayUninitialized(count); } diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 5877eb21f59e..b5567014c109 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -10,6 +10,7 @@ #include "frontend/BytecodeEmitter.h" +#include "mozilla/ArrayUtils.h" #include "mozilla/DebugOnly.h" #include "mozilla/FloatingPoint.h" #include "mozilla/PodOperations.h" @@ -344,7 +345,8 @@ static const char * const statementName[] = { "spread", /* SPREAD */ }; -JS_STATIC_ASSERT(JS_ARRAY_LENGTH(statementName) == STMT_LIMIT); +static_assert(MOZ_ARRAY_LENGTH(statementName) == STMT_LIMIT, + "statementName array and StmtType enum must be consistent"); static const char * StatementName(StmtInfoBCE *topStmt) diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 796a09c437f3..a51bc7b7af4e 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -15,15 +15,6 @@ using namespace js::frontend; using mozilla::IsFinite; -/* - * Asserts to verify assumptions behind pn_ macros. - */ -#define pn_offsetof(m) offsetof(ParseNode, m) - -JS_STATIC_ASSERT(pn_offsetof(pn_link) == pn_offsetof(dn_uses)); - -#undef pn_offsetof - #ifdef DEBUG void ParseNode::checkListConsistency() diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index dfefe5a4248a..2a4d73922290 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -526,7 +526,21 @@ class ParseNode TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ int32_t pn_offset; /* first generated bytecode offset */ ParseNode *pn_next; /* intrinsic link in parent PN_LIST */ - ParseNode *pn_link; /* def/use link (alignment freebie) */ + + /* + * Nodes that represent lexical bindings may, in addition to being + * ParseNodes, also be Definition nodes. (Definition is defined far below, + * with a lengthy comment that you should read.) Each binding has one + * canonical Definition; all uses of that definition are reached starting + * from dn_uses, then following subsequent pn_link pointers. + * + * The dn_uses chain elements are unordered. Any apparent ordering in some + * cases, will not be present in all others. + */ + union { + ParseNode *dn_uses; + ParseNode *pn_link; + }; union { struct { /* list of next-linked nodes */ @@ -1393,8 +1407,6 @@ void DumpParseTree(ParseNode *pn, int indent = 0); * definition nodes with use chains for all free variables. These are either * global variables or reference errors. */ -#define dn_uses pn_link - struct Definition : public ParseNode { bool isFreeVar() const {