Bug 712939 - Replace a bunch of JS_STATIC_ASSERTs with static_assert. r=jandem
authorJeff Walden <jwalden@mit.edu>
Wed, 22 Oct 2014 15:17:38 -0700
changeset 237129 c8cdf92b78f5e44dc404358f5178e33b7e9262f8
parent 237128 408e9201cebb5a13756b9fd0958b8933918760fc
child 237130 2afd2caa8f743b458dba4538ba57025128059541
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs712939
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 712939 - Replace a bunch of JS_STATIC_ASSERTs with static_assert. r=jandem
js/public/Class.h
js/public/HashTable.h
js/src/builtin/MapObject.cpp
js/src/ds/FixedSizeHash.h
js/src/ds/InlineMap.h
js/src/ds/LifoAlloc.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -524,31 +524,46 @@ struct Class
 
     bool isDOMClass() const {
         return flags & JSCLASS_IS_DOMJSCLASS;
     }
 
     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)
 {
     return (const JSClass *)c;
 }
 
 static MOZ_ALWAYS_INLINE const Class *
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -531,21 +531,24 @@ class HashSet
 // hash to improve key distribution.
 template <typename Key, size_t zeroBits>
 struct PointerHasher
 {
     typedef Key Lookup;
     static HashNumber hash(const Lookup &l) {
         MOZ_ASSERT(!JS::IsPoisonedPtr(l));
         size_t word = reinterpret_cast<size_t>(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
     }
     static bool match(const Key &k, const Lookup &l) {
         MOZ_ASSERT(!JS::IsPoisonedPtr(k));
         MOZ_ASSERT(!JS::IsPoisonedPtr(l));
         return k == l;
     }
@@ -582,31 +585,33 @@ struct DefaultHasher<T *> : PointerHashe
 {};
 
 // For doubles, we can xor the two uint32s.
 template <>
 struct DefaultHasher<double>
 {
     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<uint64_t>(d);
         return HashNumber(u ^ (u >> 32));
     }
     static bool match(double lhs, double rhs) {
         return mozilla::BitwiseCast<uint64_t>(lhs) == mozilla::BitwiseCast<uint64_t>(rhs);
     }
 };
 
 template <>
 struct DefaultHasher<float>
 {
     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<uint32_t>(f));
     }
     static bool match(float lhs, float rhs) {
         return mozilla::BitwiseCast<uint32_t>(lhs) == mozilla::BitwiseCast<uint32_t>(rhs);
     }
 };
 
 /*****************************************************************************/
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -1297,17 +1297,18 @@ MapObject::extract(CallReceiver call)
 }
 
 bool
 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;
 }
 
 bool
 MapObject::size(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1827,17 +1828,18 @@ SetObject::extract(CallReceiver call)
 }
 
 bool
 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;
 }
 
 bool
 SetObject::size(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/ds/FixedSizeHash.h
+++ b/js/src/ds/FixedSizeHash.h
@@ -38,23 +38,24 @@ template <class T, class HashPolicy, siz
 class FixedSizeHashSet
 {
     T entries[Capacity];
     uint32_t lastOperations[Capacity];
     uint32_t numOperations;
 
     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]));
     }
 
     bool lookup(const Lookup &lookup, T *pentry)
     {
         size_t bucket;
         if (lookupReference(lookup, &bucket)) {
             *pentry = entries[bucket];
--- a/js/src/ds/InlineMap.h
+++ b/js/src/ds/InlineMap.h
@@ -37,19 +37,18 @@ class InlineMap
     typedef typename WordMap::AddPtr    WordMapAddPtr;
     typedef typename WordMap::Range     WordMapRange;
 
     size_t          inlNext;
     size_t          inlCount;
     InlineElem      inl[InlineElems];
     WordMap         map;
 
-    void checkStaticInvariants() {
-        JS_STATIC_ASSERT(ZeroIsReserved<K>::result);
-    }
+    static_assert(ZeroIsReserved<K>::result,
+                  "zero as tombstone requires that zero keys be invalid");
 
     bool usingMap() const {
         return inlNext > InlineElems;
     }
 
     bool switchToMap() {
         MOZ_ASSERT(inlNext == InlineElems);
 
@@ -76,20 +75,17 @@ class InlineMap
     bool switchAndAdd(const K &key, const V &value) {
         if (!switchToMap())
             return false;
 
         return map.putNew(key, value);
     }
 
   public:
-    explicit InlineMap()
-      : inlNext(0), inlCount(0) {
-        checkStaticInvariants(); /* Force the template to instantiate the static invariants. */
-    }
+    explicit InlineMap() : inlNext(0), inlCount(0) { }
 
     class Entry
     {
         friend class InlineMap;
         const K &key_;
         V &value_;
 
         Entry(const K &key, V &value) : key_(key), value_(value) {}
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -298,17 +298,19 @@ class LifoAlloc
             return false;
         if (latestBefore)
             latest = latestBefore;
         return true;
     }
 
     template <typename T>
     T *newArray(size_t count) {
-        JS_STATIC_ASSERT(mozilla::IsPod<T>::value);
+        static_assert(mozilla::IsPod<T>::value,
+                      "T must be POD so that constructors (and destructors, "
+                      "when the LifoAlloc is freed) need not be called");
         return newArrayUninitialized<T>(count);
     }
 
     // Create an array with uninitialized elements of type |T|.
     // The caller is responsible for initialization.
     template <typename T>
     T *newArrayUninitialized(size_t count) {
         if (count & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * JS bytecode generation.
  */
 
 #include "frontend/BytecodeEmitter.h"
 
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/UniquePtr.h"
 
 #include <string.h>
 
 #include "jsapi.h"
@@ -339,17 +340,18 @@ static const char * const statementName[
     "do loop",               /* DO_LOOP */
     "for loop",              /* FOR_LOOP */
     "for/in loop",           /* FOR_IN_LOOP */
     "for/of loop",           /* FOR_OF_LOOP */
     "while loop",            /* WHILE_LOOP */
     "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)
 {
     if (!topStmt)
         return js_script_str;
     return statementName[topStmt->type];
 }
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -10,25 +10,16 @@
 
 #include "jscntxtinlines.h"
 
 using namespace js;
 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()
 {
     MOZ_ASSERT(isArity(PN_LIST));
     ParseNode **tail;
     uint32_t count = 0;
     if (pn_head) {
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -521,17 +521,31 @@ class ParseNode
     static_assert(NumDefinitionFlagBits == NumListFlagBits,
                   "Assumed below to achieve consistent blockid offset");
     static_assert(NumDefinitionFlagBits + NumBlockIdBits <= 32,
                   "This is supposed to fit in a single uint32_t");
 
     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 */
             ParseNode   *head;          /* first node in list */
             ParseNode   **tail;         /* ptr to ptr to last node in list */
             uint32_t    count;          /* number of nodes in list */
             uint32_t    xflags:NumListFlagBits, /* see PNX_* below */
                         blockid:NumBlockIdBits; /* see name variant below */
@@ -1388,18 +1402,16 @@ void DumpParseTree(ParseNode *pn, int in
  * Thus if a later var x is parsed in the outer function satisfying an earlier
  * inner function's use of x, we will remove dn from pc->lexdeps and re-use it
  * as the new definition node in the outer function's parse tree.
  *
  * When the compiler unwinds from the outermost pc, pc->lexdeps contains the
  * 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 {
         MOZ_ASSERT(isDefn());
         return pn_cookie.isFree();
     }
 
     enum Kind { MISSING = 0, VAR, CONST, LET, ARG, NAMED_LAMBDA, PLACEHOLDER };