Bug 784608 (part 3) - Remove FunctionBox::node. r=jimb.
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 22 Aug 2012 17:25:55 -0700
changeset 105539 52cf0f9db2f9fcbcafe5789aff9947f9b9b864f0
parent 105538 fdc5717ca867d86c5bcd32a897a33f5a342ee867
child 105540 12cca7e45cce0bf1c3de730d4e4a8c9e1de6d94c
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersjimb
bugs784608
milestone17.0a1
Bug 784608 (part 3) - Remove FunctionBox::node. r=jimb.
js/src/frontend/ParseNode.cpp
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SharedContext.h
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -49,21 +49,17 @@ ParseNode::become(ParseNode *pn2)
     pn_arity = pn2->pn_arity;
     pn_parens = pn2->pn_parens;
     pn_u = pn2->pn_u;
 
     /*
      * If any pointers are pointing to pn2, change them to point to this
      * instead, since pn2 will be cleared and probably recycled.
      */
-    if (this->isKind(PNK_FUNCTION) && isArity(PN_FUNC)) {
-        /* Function node: fix up the pn_funbox->node back-pointer. */
-        JS_ASSERT(pn_funbox->node == pn2);
-        pn_funbox->node = this;
-    } else if (pn_arity == PN_LIST && !pn_head) {
+    if (pn_arity == PN_LIST && !pn_head) {
         /* Empty list: fix up the pn_tail pointer. */
         JS_ASSERT(pn_count == 0);
         JS_ASSERT(pn_tail == &pn2->pn_head);
         pn_tail = &pn_head;
     }
 
     pn2->clear();
 }
@@ -254,34 +250,16 @@ PushNodeChildren(ParseNode *pn, NodeStac
  * Prepare |pn| to be mutated in place into a new kind of node. Recycle all
  * |pn|'s recyclable children (but not |pn| itself!), and disconnect it from
  * metadata structures (the function box tree).
  */
 void
 ParseNodeAllocator::prepareNodeForMutation(ParseNode *pn)
 {
     if (!pn->isArity(PN_NULLARY)) {
-        if (pn->isArity(PN_FUNC)) {
-            /*
-             * Since this node could be turned into anything, we can't
-             * ensure it won't be subsequently recycled, so we must
-             * disconnect it from the funbox tree entirely.
-             *
-             * Note that pn_funbox may legitimately be NULL. functionDef
-             * applies MakeDefIntoUse to definition nodes, which can come
-             * from prior iterations of the big loop in compileScript. In
-             * such cases, the defn nodes have been visited by the recycler
-             * (but not actually recycled!), and their funbox pointers
-             * cleared. But it's fine to mutate them into uses of some new
-             * definition.
-             */
-            if (pn->pn_funbox)
-                pn->pn_funbox->node = NULL;
-        }
-
         /* Put |pn|'s children (but not |pn| itself) on a work stack. */
         NodeStack stack;
         PushNodeChildren(pn, &stack);
         /*
          * For each node on the work stack, push its children on the work stack,
          * and free the node if we can.
          */
         while (!stack.empty()) {
@@ -472,17 +450,17 @@ CloneParseTree(ParseNode *opn, Parser *p
     pn->setDefn(opn->isDefn());
     pn->setUsed(opn->isUsed());
 
     switch (pn->getArity()) {
 #define NULLCHECK(e)    JS_BEGIN_MACRO if (!(e)) return NULL; JS_END_MACRO
 
       case PN_FUNC:
         NULLCHECK(pn->pn_funbox =
-                  parser->newFunctionBox(opn->pn_funbox->object, pn, pc, opn->pn_funbox->strictModeState));
+                  parser->newFunctionBox(opn->pn_funbox->object, pc, opn->pn_funbox->strictModeState));
         NULLCHECK(pn->pn_body = CloneParseTree(opn->pn_body, parser));
         pn->pn_cookie = opn->pn_cookie;
         pn->pn_dflags = opn->pn_dflags;
         pn->pn_blockid = opn->pn_blockid;
         break;
 
       case PN_LIST:
         pn->makeEmpty();
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -382,20 +382,19 @@ Parser::newObjectBox(JSObject *obj)
         return NULL;
     }
 
     traceListHead = objbox;
 
     return objbox;
 }
 
-FunctionBox::FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseNode *fn, ParseContext *pc,
+FunctionBox::FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseContext *pc,
                          StrictMode::StrictModeState sms)
   : ObjectBox(traceListHead, obj),
-    node(fn),
     siblings(pc->functionList),
     kids(NULL),
     parent(pc->sc->inFunction() ? pc->sc->funbox() : NULL),
     bindings(),
     bufStart(0),
     bufEnd(0),
     ndefaults(0),
     strictModeState(sms),
@@ -410,31 +409,30 @@ FunctionBox::FunctionBox(ObjectBox* trac
             if (scope->isWith())
                 inWith = true;
             scope = scope->enclosingScope();
         }
     }
 }
 
 FunctionBox *
-Parser::newFunctionBox(JSObject *obj, ParseNode *fn, ParseContext *pc,
-                       StrictMode::StrictModeState sms)
+Parser::newFunctionBox(JSObject *obj, ParseContext *pc, StrictMode::StrictModeState sms)
 {
     JS_ASSERT(obj && !IsPoisonedPtr(obj));
     JS_ASSERT(obj->isFunction());
 
     /*
      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
      * arenas containing the entries must be alive until we are done with
      * scanning, parsing and code generation for the whole script or top-level
      * function.
      */
     FunctionBox *funbox =
-        context->tempLifoAlloc().new_<FunctionBox>(traceListHead, obj, fn, pc, sms);
+        context->tempLifoAlloc().new_<FunctionBox>(traceListHead, obj, pc, sms);
     if (!funbox) {
         js_ReportOutOfMemory(context);
         return NULL;
     }
 
     traceListHead = pc->functionList = funbox;
 
     return funbox;
@@ -1305,17 +1303,17 @@ BindDestructuringArg(JSContext *cx, Bind
     if (!CheckStrictBinding(cx, parser, name, data->pn))
         return false;
 
     return pc->define(cx, name, data->pn, Definition::VAR);
 }
 #endif /* JS_HAS_DESTRUCTURING */
 
 bool
-Parser::functionArguments(ParseNode **listp, bool &hasRest)
+Parser::functionArguments(ParseNode **listp, ParseNode* funcpn, bool &hasRest)
 {
     if (tokenStream.getToken() != TOK_LP) {
         reportError(NULL, JSMSG_PAREN_BEFORE_FORMAL);
         return false;
     }
 
     FunctionBox *funbox = pc->sc->funbox();
     funbox->bufStart = tokenStream.offsetOfToken(tokenStream.currentToken());
@@ -1323,17 +1321,16 @@ Parser::functionArguments(ParseNode **li
     hasRest = false;
 
     ParseNode *argsbody = ListNode::create(PNK_ARGSBODY, this);
     if (!argsbody)
         return false;
     argsbody->setOp(JSOP_NOP);
     argsbody->makeEmpty();
 
-    ParseNode *funcpn = funbox->node;
     funcpn->pn_body = argsbody;
 
     if (!tokenStream.matchToken(TOK_RP)) {
         bool hasDefaults = false;
         Definition *duplicatedArg = NULL;
         bool destructuringArg = false;
 #if JS_HAS_DESTRUCTURING
         ParseNode *list = NULL;
@@ -1584,30 +1581,30 @@ Parser::functionDef(HandlePropertyName f
     if (!fun)
         return NULL;
 
     // Inherit strictness if neeeded.
     StrictMode::StrictModeState sms = (outerpc->sc->strictModeState == StrictMode::STRICT) ?
         StrictMode::STRICT : StrictMode::UNKNOWN;
 
     // Create box for fun->object early to protect against last-ditch GC.
-    FunctionBox *funbox = newFunctionBox(fun, pn, outerpc, sms);
+    FunctionBox *funbox = newFunctionBox(fun, outerpc, sms);
     if (!funbox)
         return NULL;
 
     /* Initialize early for possible flags mutation via destructuringExpr. */
     SharedContext funsc(context, /* scopeChain = */ NULL, fun, funbox, sms);
     ParseContext funpc(this, &funsc, outerpc->staticLevel + 1, outerpc->blockidGen);
     if (!funpc.init())
         return NULL;
 
     /* Now parse formal argument list and compute fun->nargs. */
     ParseNode *prelude = NULL;
     bool hasRest;
-    if (!functionArguments(&prelude, hasRest))
+    if (!functionArguments(&prelude, pn, hasRest))
         return NULL;
 
     fun->setArgCount(funpc.numArgs());
     if (funbox->ndefaults)
         fun->setHasDefaults();
     if (hasRest)
         fun->setHasRest();
 
@@ -5312,17 +5309,17 @@ Parser::generatorExpr(ParseNode *kid)
     {
         ParseContext *outerpc = pc;
 
         RootedFunction fun(context, newFunction(outerpc, /* atom = */ NULL, Expression));
         if (!fun)
             return NULL;
 
         /* Create box for fun->object early to protect against last-ditch GC. */
-        FunctionBox *funbox = newFunctionBox(fun, genfn, outerpc, outerpc->sc->strictModeState);
+        FunctionBox *funbox = newFunctionBox(fun, outerpc, outerpc->sc->strictModeState);
         if (!funbox)
             return NULL;
 
         SharedContext gensc(context, /* scopeChain = */ NULL, fun, funbox, outerpc->sc->strictModeState);
         ParseContext genpc(this, &gensc, outerpc->staticLevel + 1, outerpc->blockidGen);
         if (!genpc.init())
             return NULL;
 
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -295,18 +295,17 @@ struct Parser : private AutoGCRooter
 #endif
 
     /*
      * Allocate a new parsed object or function container from
      * cx->tempLifoAlloc.
      */
     ObjectBox *newObjectBox(JSObject *obj);
 
-    FunctionBox *newFunctionBox(JSObject *obj, ParseNode *fn, ParseContext *pc,
-                                StrictMode::StrictModeState sms);
+    FunctionBox *newFunctionBox(JSObject *obj, ParseContext *pc, StrictMode::StrictModeState sms);
 
     /*
      * Create a new function object given parse context (pc) and a name (which
      * is optional if this is a function expression).
      */
     JSFunction *newFunction(ParseContext *pc, JSAtom *atom, FunctionSyntaxKind kind);
 
     void trace(JSTracer *trc);
@@ -419,17 +418,17 @@ struct Parser : private AutoGCRooter
     ParseNode *memberExpr(bool allowCallSyntax);
     ParseNode *primaryExpr(TokenKind tt, bool afterDoubleDot);
     ParseNode *parenExpr(bool *genexp = NULL);
 
     /*
      * Additional JS parsers.
      */
     enum FunctionType { Getter, Setter, Normal };
-    bool functionArguments(ParseNode **list, bool &hasRest);
+    bool functionArguments(ParseNode **list, ParseNode *funcpn, bool &hasRest);
 
     ParseNode *functionDef(HandlePropertyName name, FunctionType type, FunctionSyntaxKind kind);
 
     ParseNode *unaryOpExpr(ParseNodeKind kind, JSOp op);
 
     ParseNode *condition();
     ParseNode *comprehensionTail(ParseNode *kid, unsigned blockid, bool isGenexp,
                                  ParseNodeKind kind = PNK_SEMI, JSOp op = JSOP_NOP);
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -286,32 +286,31 @@ struct StmtInfoBase {
 
     bool isTrying() const {
         return STMT_TRY <= type && type <= STMT_SUBROUTINE;
     }
 };
 
 struct FunctionBox : public ObjectBox
 {
-    ParseNode       *node;
     FunctionBox     *siblings;
     FunctionBox     *kids;
     FunctionBox     *parent;
     Bindings        bindings;               /* bindings for this function */
     size_t          bufStart;
     size_t          bufEnd;
     uint16_t        ndefaults;
     StrictMode::StrictModeState strictModeState;
     bool            inWith:1;               /* some enclosing scope is a with-statement
                                                or E4X filter-expression */
     bool            inGenexpLambda:1;       /* lambda from generator expression */
 
     ContextFlags    cxFlags;
 
-    FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseNode *fn, ParseContext *pc,
+    FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseContext *pc,
                 StrictMode::StrictModeState sms);
 
     bool funIsGenerator()        const { return cxFlags.funIsGenerator; }
     bool funHasExtensibleScope() const { return cxFlags.funHasExtensibleScope; }
 
     JSFunction *function() const { return (JSFunction *) object; }
 
     /*