Bug 977371 - Allow more than 2^20 blockids (r=jorendorff)
authorLuke Wagner <luke@mozilla.com>
Thu, 27 Feb 2014 11:31:31 -0600
changeset 170977 efa6f63f06b9a9c005db190d81d3b54f57608e85
parent 170976 c483fb963fe112b54c30230a69b9b1a89a7b55b1
child 170978 c95f331f043df4c2c9396f685826cdd07d12810d
push id40360
push userlwagner@mozilla.com
push dateThu, 27 Feb 2014 17:34:13 +0000
treeherdermozilla-inbound@efa6f63f06b9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs977371
milestone30.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 977371 - Allow more than 2^20 blockids (r=jorendorff)
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/jit-test/tests/basic/testBug773108.js
js/src/tests/js1_8_5/regress/regress-610026.js
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -490,28 +490,36 @@ class ParseNode
     /* Boolean attributes. */
     bool isInParens() const                { return pn_parens; }
     void setInParens(bool enabled)         { pn_parens = enabled; }
     bool isUsed() const                    { return pn_used; }
     void setUsed(bool enabled)             { pn_used = enabled; }
     bool isDefn() const                    { return pn_defn; }
     void setDefn(bool enabled)             { pn_defn = enabled; }
 
+    static const unsigned NumDefinitionFlagBits = 10;
+    static const unsigned NumListFlagBits = 10;
+    static const unsigned NumBlockIdBits = 22;
+    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) */
 
     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:12,      /* extra flags, see below */
-                        blockid:20;     /* see name variant below */
+            uint32_t    xflags:NumListFlagBits, /* see PNX_* below */
+                        blockid:NumBlockIdBits; /* see name variant below */
         } list;
         struct {                        /* ternary: if, for(;;), ?: */
             ParseNode   *kid1;          /* condition, discriminant, etc. */
             ParseNode   *kid2;          /* then-part, case list, etc. */
             ParseNode   *kid3;          /* else-part, default case, etc. */
         } ternary;
         struct {                        /* two kids if binary */
             ParseNode   *left;
@@ -536,19 +544,19 @@ class ParseNode
                 ParseNode   *expr;      /* module or function body, var
                                            initializer, argument default, or
                                            base object of PNK_DOT */
                 Definition  *lexdef;    /* lexical definition for this use */
             };
             UpvarCookie cookie;         /* upvar cookie with absolute frame
                                            level (not relative skip), possibly
                                            in current frame */
-            uint32_t    dflags:12,      /* definition/use flags, see below */
-                        blockid:20;     /* block number, for subset dominance
-                                           computation */
+            uint32_t    dflags:NumDefinitionFlagBits, /* see PND_* below */
+                        blockid:NumBlockIdBits;  /* block number, for subset dominance
+                                                    computation */
         } name;
         struct {
             double      value;          /* aligned numeric literal value */
             DecimalPoint decimalPoint;  /* Whether the number has a decimal point */
         } number;
         class {
             friend class LoopControlStatement;
             PropertyName     *label;    /* target of break/continue statement */
@@ -638,48 +646,52 @@ class ParseNode
     Definition *maybeLexDef() { return pn_used ? lexdef() : nullptr; }
 
     Definition *resolve();
 
 /* PN_CODE and PN_NAME pn_dflags bits. */
 #define PND_LET                 0x01    /* let (block-scoped) binding */
 #define PND_CONST               0x02    /* const binding (orthogonal to let) */
 #define PND_ASSIGNED            0x04    /* set if ever LHS of assignment */
-#define PND_PLACEHOLDER         0x10    /* placeholder definition for lexdep */
-#define PND_BOUND               0x20    /* bound to a stack or global slot */
-#define PND_DEOPTIMIZED         0x40    /* former pn_used name node, pn_lexdef
+#define PND_PLACEHOLDER         0x08    /* placeholder definition for lexdep */
+#define PND_BOUND               0x10    /* bound to a stack or global slot */
+#define PND_DEOPTIMIZED         0x20    /* former pn_used name node, pn_lexdef
                                            still valid, but this use no longer
                                            optimizable via an upvar opcode */
-#define PND_CLOSED              0x80    /* variable is closed over */
-#define PND_DEFAULT            0x100    /* definition is an arg with a default */
-#define PND_IMPLICITARGUMENTS  0x200    /* the definition is a placeholder for
+#define PND_CLOSED              0x40    /* variable is closed over */
+#define PND_DEFAULT             0x80    /* definition is an arg with a default */
+#define PND_IMPLICITARGUMENTS  0x100    /* the definition is a placeholder for
                                            'arguments' that has been converted
                                            into a definition after the function
                                            body has been parsed. */
-#define PND_EMITTEDFUNCTION    0x400    /* hoisted function that was emitted */
+#define PND_EMITTEDFUNCTION    0x200    /* hoisted function that was emitted */
+
+    static_assert(PND_EMITTEDFUNCTION < (1 << NumDefinitionFlagBits), "Not enough bits");
 
 /* Flags to propagate from uses to definition. */
 #define PND_USE2DEF_FLAGS (PND_ASSIGNED | PND_CLOSED)
 
 /* PN_LIST pn_xflags bits. */
-#define PNX_POPVAR      0x04            /* PNK_VAR or PNK_CONST last result
+#define PNX_POPVAR      0x01            /* PNK_VAR or PNK_CONST last result
                                            needs popping */
-#define PNX_GROUPINIT   0x08            /* var [a, b] = [c, d]; unit list */
-#define PNX_FUNCDEFS    0x10            /* contains top-level function statements */
-#define PNX_SETCALL     0x20            /* call expression in lvalue context */
-#define PNX_DESTRUCT    0x40            /* destructuring special cases:
+#define PNX_GROUPINIT   0x02            /* var [a, b] = [c, d]; unit list */
+#define PNX_FUNCDEFS    0x04            /* contains top-level function statements */
+#define PNX_SETCALL     0x08            /* call expression in lvalue context */
+#define PNX_DESTRUCT    0x10            /* destructuring special cases:
                                            1. shorthand syntax used, at present
                                               object destructuring ({x,y}) only;
                                            2. code evaluating destructuring
                                               arguments occurs before function
                                               body */
-#define PNX_SPECIALARRAYINIT 0x80       /* one or more of
+#define PNX_SPECIALARRAYINIT 0x20       /* one or more of
                                            1. array initialiser has holes
                                            2. array initializer has spread node */
-#define PNX_NONCONST   0x100            /* initialiser has non-constants */
+#define PNX_NONCONST    0x40            /* initialiser has non-constants */
+
+    static_assert(PNX_NONCONST < (1 << NumListFlagBits), "Not enough bits");
 
     unsigned frameLevel() const {
         JS_ASSERT(pn_arity == PN_CODE || pn_arity == PN_NAME);
         return pn_cookie.level();
     }
 
     uint32_t frameSlot() const {
         JS_ASSERT(pn_arity == PN_CODE || pn_arity == PN_NAME);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -60,25 +60,27 @@ typedef Handle<NestedScopeObject*> Handl
 #define MUST_MATCH_TOKEN(tt, errno)                                                         \
     JS_BEGIN_MACRO                                                                          \
         if (tokenStream.getToken() != tt) {                                                 \
             report(ParseError, false, null(), errno);                                       \
             return null();                                                                  \
         }                                                                                   \
     JS_END_MACRO
 
+static const unsigned BlockIdLimit = 1 << ParseNode::NumBlockIdBits;
+
 template <typename ParseHandler>
 bool
 GenerateBlockId(TokenStream &ts, ParseContext<ParseHandler> *pc, uint32_t &blockid)
 {
-    if (pc->blockidGen == JS_BIT(20)) {
+    if (pc->blockidGen == BlockIdLimit) {
         ts.reportError(JSMSG_NEED_DIET, "program");
         return false;
     }
-    JS_ASSERT(pc->blockidGen < JS_BIT(20));
+    JS_ASSERT(pc->blockidGen < BlockIdLimit);
     blockid = pc->blockidGen++;
     return true;
 }
 
 template bool
 GenerateBlockId(TokenStream &ts, ParseContext<SyntaxParseHandler> *pc, uint32_t &blockid);
 
 template bool
@@ -5820,17 +5822,17 @@ BumpStaticLevel(TokenStream &ts, ParseNo
     return pn->pn_cookie.set(ts, level, pn->pn_cookie.slot());
 }
 
 template <typename ParseHandler>
 static bool
 AdjustBlockId(TokenStream &ts, ParseNode *pn, unsigned adjust, ParseContext<ParseHandler> *pc)
 {
     JS_ASSERT(pn->isArity(PN_LIST) || pn->isArity(PN_CODE) || pn->isArity(PN_NAME));
-    if (JS_BIT(20) - pn->pn_blockid <= adjust + 1) {
+    if (BlockIdLimit - pn->pn_blockid <= adjust + 1) {
         ts.reportError(JSMSG_NEED_DIET, "program");
         return false;
     }
     pn->pn_blockid += adjust;
     if (pn->pn_blockid >= pc->blockidGen)
         pc->blockidGen = pn->pn_blockid + 1;
     return true;
 }
--- a/js/src/jit-test/tests/basic/testBug773108.js
+++ b/js/src/jit-test/tests/basic/testBug773108.js
@@ -1,10 +1,11 @@
 // |jit-test| error:InternalError
 
 Function("\
 for each(l in[(let(c)([])\
 for each(l in[]))(let(c)w for(u in[]))(let(u)w for(l in[]))(let(c)w for(u in[]))\
 (let(u)w for each(l in[]))(let(c)w for(u in[]))(let(u)w for(l in[]))(let(c)w for(u in[]))\
+(let(u)w for each(l in[]))(let(c)w for(u in[]))(let(u)w for(l in[]))(let(c)w for(u in[]))\
 (let(l)w for(l in[]))(let(u)w for(l in['']))(let(c)w for(u in[]))(let(u)w for(l in[]))\
 (let(c)w for(l in[]))(let(l)w for(l in[]))(let(c)w for(l in[]))(let(u)w for(l in[]))\
 (let(c)w for(l in[]))(let(u)w for each(l in[x]))(let(w,x)w for(u in[]))]){}\
 ")
--- a/js/src/tests/js1_8_5/regress/regress-610026.js
+++ b/js/src/tests/js1_8_5/regress/regress-610026.js
@@ -7,17 +7,17 @@
 var expect = "pass";
 var actual;
 
 /*
  * We hardcode here that GenerateBlockId limits a program to 2^20 blocks. Start
  * with 2^19 blocks, then test 2^20 - 1 blocks, finally test the limit.
  */
 var s = "{}";
-for (var i = 0; i < 19; i++)
+for (var i = 0; i < 21; i++)
     s += s;
 
 try {
     eval(s);
     actual = "pass";
 } catch (e) {
     actual = "fail: " + e;
 }