Bug 979865 - Part 2: Internally rename JS1.8 comprehensions as "legacy" r=jorendorff
authorAndy Wingo <wingo@igalia.com>
Fri, 07 Mar 2014 22:01:13 +0100
changeset 190828 f0fc695a395dabacfb0bdf86135110f84e500995
parent 190827 aab169fa66bea2e1a701ea6460fe7e9f6b5d39e1
child 190829 f4216dc177e48775dc50e629f7d156592cf3677a
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs979865
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 979865 - Part 2: Internally rename JS1.8 comprehensions as "legacy" r=jorendorff
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1396,17 +1396,17 @@ Parser<FullParseHandler>::leaveFunction(
              *
              * Without loss of generality or correctness, we allow a dn to
              * be in inner and outer lexdeps, since the purpose of lexdeps
              * is one-pass coordination of name use and definition across
              * functions, and if different dn's are used we'll merge lists
              * when leaving the inner function.
              *
              * The dn == outer_dn case arises with generator expressions
-             * (see CompExprTransplanter::transplant, the PN_CODE/PN_NAME
+             * (see LegacyCompExprTransplanter::transplant, the PN_CODE/PN_NAME
              * case), and nowhere else, currently.
              */
             if (dn != outer_dn) {
                 if (ParseNode *pnu = dn->dn_uses) {
                     while (true) {
                         pnu->pn_lexdef = outer_dn;
                         if (!pnu->pn_link)
                             break;
@@ -5756,64 +5756,64 @@ Parser<ParseHandler>::unaryExpr()
                                     pn);
         }
         return pn;
     }
     MOZ_ASSUME_UNREACHABLE("unaryExpr");
 }
 
 /*
- * A dedicated helper for transplanting the comprehension expression E in
+ * A dedicated helper for transplanting the legacy comprehension expression E in
  *
- *   [E for (V in I)]   // array comprehension
- *   (E for (V in I))   // generator expression
+ *   [E for (V in I)]   // legacy array comprehension
+ *   (E for (V in I))   // legacy generator expression
  *
  * from its initial location in the AST, on the left of the 'for', to its final
  * position on the right. To avoid a separate pass we do this by adjusting the
  * blockids and name binding links that were established when E was parsed.
  *
- * A generator expression desugars like so:
+ * A legacy generator expression desugars like so:
  *
  *   (E for (V in I)) => (function () { for (var V in I) yield E; })()
  *
  * so the transplanter must adjust static level as well as blockid. E's source
  * coordinates in root->pn_pos are critical to deciding which binding links to
  * preserve and which to cut.
  *
  * NB: This is not a general tree transplanter -- it knows in particular that
  * the one or more bindings induced by V have not yet been created.
  */
-class CompExprTransplanter
+class LegacyCompExprTransplanter
 {
     ParseNode       *root;
     Parser<FullParseHandler> *parser;
     ParseContext<FullParseHandler> *outerpc;
     GeneratorKind   comprehensionKind;
     unsigned        adjust;
     HashSet<Definition *> visitedImplicitArguments;
 
   public:
-    CompExprTransplanter(ParseNode *pn, Parser<FullParseHandler> *parser,
-                         ParseContext<FullParseHandler> *outerpc,
-                         GeneratorKind kind, unsigned adj)
+    LegacyCompExprTransplanter(ParseNode *pn, Parser<FullParseHandler> *parser,
+                               ParseContext<FullParseHandler> *outerpc,
+                               GeneratorKind kind, unsigned adj)
       : root(pn), parser(parser), outerpc(outerpc), comprehensionKind(kind), adjust(adj),
         visitedImplicitArguments(parser->context)
     {}
 
     bool init() {
         return visitedImplicitArguments.init();
     }
 
     bool transplant(ParseNode *pn);
 };
 
 /*
- * Any definitions nested within the comprehension expression of a generator
- * expression must move "down" one static level, which of course increases the
- * upvar-frame-skip count.
+ * Any definitions nested within the legacy comprehension expression of a
+ * generator expression must move "down" one static level, which of course
+ * increases the upvar-frame-skip count.
  */
 template <typename ParseHandler>
 static bool
 BumpStaticLevel(TokenStream &ts, ParseNode *pn, ParseContext<ParseHandler> *pc)
 {
     if (pn->pn_cookie.isFree())
         return true;
 
@@ -5833,17 +5833,17 @@ AdjustBlockId(TokenStream &ts, ParseNode
     }
     pn->pn_blockid += adjust;
     if (pn->pn_blockid >= pc->blockidGen)
         pc->blockidGen = pn->pn_blockid + 1;
     return true;
 }
 
 bool
-CompExprTransplanter::transplant(ParseNode *pn)
+LegacyCompExprTransplanter::transplant(ParseNode *pn)
 {
     ParseContext<FullParseHandler> *pc = parser->pc;
 
     bool isGenexp = comprehensionKind != NotGenerator;
 
     if (!pn)
         return true;
 
@@ -5895,21 +5895,21 @@ CompExprTransplanter::transplant(ParseNo
             JS_ASSERT(pn->pn_cookie.isFree());
 
             Definition *dn = pn->pn_lexdef;
             JS_ASSERT(dn->isDefn());
 
             /*
              * Adjust the definition's block id only if it is a placeholder not
              * to the left of the root node, and if pn is the last use visited
-             * in the comprehension expression (to avoid adjusting the blockid
-             * multiple times).
+             * in the legacy comprehension expression (to avoid adjusting the
+             * blockid multiple times).
              *
-             * Non-placeholder definitions within the comprehension expression
-             * will be visited further below.
+             * Non-placeholder definitions within the legacy comprehension
+             * expression will be visited further below.
              */
             if (dn->isPlaceholder() && dn->pn_pos >= root->pn_pos && dn->dn_uses == pn) {
                 if (isGenexp && !BumpStaticLevel(parser->tokenStream, dn, pc))
                     return false;
                 if (!AdjustBlockId(parser->tokenStream, dn, adjust, pc))
                     return false;
             }
 
@@ -5920,20 +5920,20 @@ CompExprTransplanter::transplant(ParseNo
 #endif
             if (isGenexp && !dn->isOp(JSOP_CALLEE)) {
                 JS_ASSERT(!pc->decls().lookupFirst(atom));
 
                 if (dn->pn_pos < root->pn_pos) {
                     /*
                      * The variable originally appeared to be a use of a
                      * definition or placeholder outside the generator, but now
-                     * we know it is scoped within the comprehension tail's
-                     * clauses. Make it (along with any other uses within the
-                     * generator) a use of a new placeholder in the generator's
-                     * lexdeps.
+                     * we know it is scoped within the legacy comprehension
+                     * tail's clauses. Make it (along with any other uses within
+                     * the generator) a use of a new placeholder in the
+                     * generator's lexdeps.
                      */
                     Definition *dn2 = parser->handler.newPlaceholder(atom, parser->pc->blockid(),
                                                                      parser->pos());
                     if (!dn2)
                         return false;
                     dn2->pn_pos = root->pn_pos;
 
                     /*
@@ -5993,56 +5993,56 @@ CompExprTransplanter::transplant(ParseNo
 
       case PN_NULLARY:
         /* Nothing. */
         break;
     }
     return true;
 }
 
-// Parsing JS1.7-style comprehensions is terrible: we parse the head expression
-// as if it's part of a comma expression, then when we see the "for" we
-// transplant the parsed expression into the inside of a constructed
+// Parsing legacy (JS1.7-style) comprehensions is terrible: we parse the head
+// expression as if it's part of a comma expression, then when we see the "for"
+// we transplant the parsed expression into the inside of a constructed
 // for-of/for-in/for-each tail.  Transplanting an already-parsed expression is
-// tricky, but the CompExprTransplanter handles most of that.
+// tricky, but the LegacyCompExprTransplanter handles most of that.
 //
 // The one remaining thing to patch up is the block scope depth.  We need to
 // compute the maximum block scope depth of a function, so we know how much
 // space to reserve in the fixed part of a stack frame.  Normally this is done
 // whenever we leave a statement, via AccumulateBlockScopeDepth.  However if the
 // head has a let expression, we need to re-assign that depth to the tail of the
 // comprehension.
 //
 // Thing is, we don't actually know what that depth is, because the only
 // information we keep is the maximum nested depth within a statement, so we
 // just conservatively propagate the maximum nested depth from the top statement
 // to the comprehension tail.
 //
 template <typename ParseHandler>
 static unsigned
-ComprehensionHeadBlockScopeDepth(ParseContext<ParseHandler> *pc)
+LegacyComprehensionHeadBlockScopeDepth(ParseContext<ParseHandler> *pc)
 {
     return pc->topStmt ? pc->topStmt->innerBlockScopeDepth : pc->blockScopeDepth;
 }
 
 /*
  * Starting from a |for| keyword after the first array initialiser element or
  * an expression in an open parenthesis, parse the tail of the comprehension
  * or generator expression signified by this |for| keyword in context.
  *
  * Return null on failure, else return the top-most parse node for the array
  * comprehension or generator expression, with a unary node as the body of the
  * (possibly nested) for-loop, initialized by |kind, op, kid|.
  */
 template <>
 ParseNode *
-Parser<FullParseHandler>::comprehensionTail(ParseNode *bodyStmt, unsigned blockid,
-                                            GeneratorKind comprehensionKind,
-                                            ParseContext<FullParseHandler> *outerpc,
-                                            unsigned innerBlockScopeDepth)
+Parser<FullParseHandler>::legacyComprehensionTail(ParseNode *bodyStmt, unsigned blockid,
+                                                  GeneratorKind comprehensionKind,
+                                                  ParseContext<FullParseHandler> *outerpc,
+                                                  unsigned innerBlockScopeDepth)
 {
     /*
      * If we saw any inner functions while processing the generator expression
      * then they may have upvars referring to the let vars in this generator
      * which were not correctly processed. Bail out and start over without
      * allowing lazy parsing.
      */
     if (handler.syntaxParser) {
@@ -6097,17 +6097,17 @@ Parser<FullParseHandler>::comprehensionT
         JS_ASSERT(adjust < blockid);
         adjust = blockid - adjust;
     }
 
     handler.setBeginPosition(pn, bodyStmt);
 
     pnp = &pn->pn_expr;
 
-    CompExprTransplanter transplanter(bodyStmt, this, outerpc, comprehensionKind, adjust);
+    LegacyCompExprTransplanter transplanter(bodyStmt, this, outerpc, comprehensionKind, adjust);
     if (!transplanter.init())
         return null();
 
     if (!transplanter.transplant(bodyStmt))
         return null();
 
     JS_ASSERT(pc->staticScope && pc->staticScope == pn->pn_objbox->object);
     data.initLet(HoistVars, pc->staticScope->as<StaticBlockObject>(), JSMSG_ARRAY_INIT_TOO_BIG);
@@ -6265,73 +6265,73 @@ Parser<FullParseHandler>::comprehensionT
 
     handler.setEndPosition(pn, pos().end);
 
     return pn;
 }
 
 template <>
 ParseNode*
-Parser<FullParseHandler>::arrayComprehension(ParseNode *array)
+Parser<FullParseHandler>::legacyArrayComprehension(ParseNode *array)
 {
     array->setKind(PNK_ARRAYCOMP);
 
     // Remove the single element from array's linked list, leaving us with an
     // empty array literal and a comprehension expression.
     JS_ASSERT(array->pn_count == 1);
     ParseNode *bodyExpr = array->last();
     array->pn_count = 0;
     array->pn_tail = &array->pn_head;
     *array->pn_tail = nullptr;
 
     ParseNode *arrayPush = handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH,
                                             bodyExpr->pn_pos.begin, bodyExpr);
     if (!arrayPush)
         return null();
 
-    ParseNode *comp = comprehensionTail(arrayPush, array->pn_blockid, NotGenerator,
-                                        nullptr, ComprehensionHeadBlockScopeDepth(pc));
+    ParseNode *comp = legacyComprehensionTail(arrayPush, array->pn_blockid, NotGenerator,
+                                              nullptr, LegacyComprehensionHeadBlockScopeDepth(pc));
     if (!comp)
         return null();
 
     MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION);
 
     TokenPos p = handler.getPosition(array);
     p.end = pos().end;
     return handler.newArrayComprehension(comp, array->pn_blockid, p);
 }
 
 template <>
 SyntaxParseHandler::Node
-Parser<SyntaxParseHandler>::arrayComprehension(Node array)
+Parser<SyntaxParseHandler>::legacyArrayComprehension(Node array)
 {
     abortIfSyntaxParser();
     return null();
 }
 
 #if JS_HAS_GENERATOR_EXPRS
 
 /*
  * Starting from a |for| keyword after an expression, parse the comprehension
  * tail completing this generator expression. Wrap the expression at kid in a
  * generator function that is immediately called to evaluate to the generator
- * iterator that is the value of this generator expression.
+ * iterator that is the value of this legacy generator expression.
  *
  * |kid| must be the expression before the |for| keyword; we return an
  * application of a generator function that includes the |for| loops and
  * |if| guards, with |kid| as the operand of a |yield| expression as the
  * innermost loop body.
  *
  * Note how unlike Python, we do not evaluate the expression to the right of
  * the first |in| in the chain of |for| heads. Instead, a generator expression
  * is merely sugar for a generator function expression and its application.
  */
 template <>
 ParseNode *
-Parser<FullParseHandler>::generatorExpr(ParseNode *kid)
+Parser<FullParseHandler>::legacyGeneratorExpr(ParseNode *kid)
 {
     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
 
     /* Create a |yield| node for |kid|. */
     ParseNode *yieldExpr = handler.newUnary(PNK_YIELD, JSOP_NOP, kid->pn_pos.begin, kid);
     if (!yieldExpr)
         return null();
     yieldExpr->setInParens(true);
@@ -6379,18 +6379,19 @@ Parser<FullParseHandler>::generatorExpr(
         genFunbox->anyCxFlags = outerpc->sc->anyCxFlags;
         if (outerpc->sc->isFunctionBox())
             genFunbox->funCxFlags = outerpc->sc->asFunctionBox()->funCxFlags;
 
         JS_ASSERT(genFunbox->isLegacyGenerator());
         genFunbox->inGenexpLambda = true;
         genfn->pn_blockid = genpc.bodyid;
 
-        ParseNode *body = comprehensionTail(yieldStmt, outerpc->blockid(), LegacyGenerator, outerpc,
-                                            ComprehensionHeadBlockScopeDepth(outerpc));
+        ParseNode *body = legacyComprehensionTail(yieldStmt, outerpc->blockid(), LegacyGenerator,
+                                                  outerpc,
+                                                  LegacyComprehensionHeadBlockScopeDepth(outerpc));
         if (!body)
             return null();
         JS_ASSERT(!genfn->pn_body);
         genfn->pn_body = body;
         genfn->pn_pos.begin = body->pn_pos.begin;
         genfn->pn_pos.end = body->pn_pos.end;
 
         if (!leaveFunction(genfn, outerpc))
@@ -6407,17 +6408,17 @@ Parser<FullParseHandler>::generatorExpr(
     result->setOp(JSOP_CALL);
     result->pn_pos.begin = genfn->pn_pos.begin;
     result->initList(genfn);
     return result;
 }
 
 template <>
 SyntaxParseHandler::Node
-Parser<SyntaxParseHandler>::generatorExpr(Node kid)
+Parser<SyntaxParseHandler>::legacyGeneratorExpr(Node kid)
 {
     JS_ALWAYS_FALSE(abortIfSyntaxParser());
     return SyntaxParseHandler::NodeFailure;
 }
 
 static const char js_generator_str[] = "generator";
 
 #endif /* JS_HAS_GENERATOR_EXPRS */
@@ -6473,17 +6474,17 @@ Parser<ParseHandler>::argumentList(Node 
         }
 #if JS_HAS_GENERATOR_EXPRS
         if (!spread && tokenStream.matchToken(TOK_FOR)) {
             if (pc->lastYieldOffset != startYieldOffset) {
                 reportWithOffset(ParseError, false, pc->lastYieldOffset,
                                  JSMSG_BAD_GENEXP_BODY, js_yield_str);
                 return false;
             }
-            argNode = generatorExpr(argNode);
+            argNode = legacyGeneratorExpr(argNode);
             if (!argNode)
                 return false;
             if (!arg0 || tokenStream.peekToken() == TOK_COMMA) {
                 report(ParseError, false, argNode, JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
                 return false;
             }
         }
 #endif
@@ -6731,35 +6732,35 @@ Parser<ParseHandler>::arrayInitializer()
                 }
             }
         }
 
         /*
          * At this point, (index == 0 && missingTrailingComma) implies one
          * element initialiser was parsed.
          *
-         * An array comprehension of the form:
+         * A legacy array comprehension of the form:
          *
          *   [i * j for (i in o) for (j in p) if (i != j)]
          *
          * translates to roughly the following let expression:
          *
          *   let (array = new Array, i, j) {
          *     for (i in o) let {
          *       for (j in p)
          *         if (i != j)
          *           array.push(i * j)
          *     }
          *     array
          *   }
          *
-         * where array is a nameless block-local variable. The "roughly"
-         * means that an implementation may optimize away the array.push.
-         * An array comprehension opens exactly one block scope, no matter
-         * how many for heads it contains.
+         * where array is a nameless block-local variable. The "roughly" means
+         * that an implementation may optimize away the array.push.  A legacy
+         * array comprehension opens exactly one block scope, no matter how many
+         * for heads it contains.
          *
          * Each let () {...} or for (let ...) ... compiles to:
          *
          *   JSOP_PUSHN <N>            // Push space for block-scoped locals.
          *   (JSOP_PUSHBLOCKSCOPE <O>) // If a local is aliased, push on scope
          *                             // chain.
          *   ...
          *   JSOP_DEBUGLEAVEBLOCK      // Invalidate any DebugScope proxies.
@@ -6769,22 +6770,22 @@ Parser<ParseHandler>::arrayInitializer()
          * where <o> is a literal object representing the block scope,
          * with <n> properties, naming each var declared in the block.
          *
          * Each var declaration in a let-block binds a name in <o> at compile
          * time. A block-local var is accessed by the JSOP_GETLOCAL and
          * JSOP_SETLOCAL ops. These ops have an immediate operand, the local
          * slot's stack index from fp->spbase.
          *
-         * The array comprehension iteration step, array.push(i * j) in
-         * the example above, is done by <i * j>; JSOP_ARRAYPUSH <array>,
-         * where <array> is the index of array's stack slot.
+         * The legacy array comprehension iteration step, array.push(i * j) in
+         * the example above, is done by <i * j>; JSOP_ARRAYPUSH <array>, where
+         * <array> is the index of array's stack slot.
          */
         if (index == 0 && !spread && tokenStream.matchToken(TOK_FOR) && missingTrailingComma)
-            return arrayComprehension(literal);
+            return legacyArrayComprehension(literal);
 
         MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST);
     }
     handler.setEndPosition(literal, pos().end);
     return literal;
 }
 
 static JSAtom*
@@ -7153,17 +7154,17 @@ Parser<ParseHandler>::parenExpr(bool *ge
                              JSMSG_BAD_GENEXP_BODY, js_yield_str);
             return null();
         }
         if (handler.isOperationWithoutParens(pn, PNK_COMMA)) {
             report(ParseError, false, null(),
                    JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
             return null();
         }
-        pn = generatorExpr(pn);
+        pn = legacyGeneratorExpr(pn);
         if (!pn)
             return null();
         handler.setBeginPosition(pn, begin);
         if (genexp) {
             if (tokenStream.getToken() != TOK_RP) {
                 report(ParseError, false, null(),
                        JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
                 return null();
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -299,19 +299,16 @@ Directives::Directives(ParseContext<Pars
     asmJS_(parent->useAsmOrInsideUseAsm())
 {}
 
 template <typename ParseHandler>
 struct BindData;
 
 class CompExprTransplanter;
 
-template <typename ParseHandler>
-class GenexpGuard;
-
 enum LetContext { LetExpresion, LetStatement };
 enum VarContext { HoistVars, DontHoistVars };
 enum FunctionType { Getter, Setter, Normal };
 
 template <typename ParseHandler>
 class Parser : private AutoGCRooter, public StrictModeGetter
 {
   public:
@@ -538,21 +535,23 @@ class Parser : private AutoGCRooter, pub
     bool functionArgsAndBody(Node pn, HandleFunction fun,
                              FunctionType type, FunctionSyntaxKind kind,
                              GeneratorKind generatorKind,
                              Directives inheritedDirectives, Directives *newDirectives);
 
     Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin);
 
     Node condition();
-    Node comprehensionTail(Node kid, unsigned blockid, GeneratorKind comprehensionKind,
-                           ParseContext<ParseHandler> *outerpc,
-                           unsigned innerBlockScopeDepth);
-    Node arrayComprehension(Node array);
-    Node generatorExpr(Node kid);
+
+    Node legacyComprehensionTail(Node kid, unsigned blockid, GeneratorKind comprehensionKind,
+                                 ParseContext<ParseHandler> *outerpc,
+                                 unsigned innerBlockScopeDepth);
+    Node legacyArrayComprehension(Node array);
+    Node legacyGeneratorExpr(Node kid);
+
     bool argumentList(Node listNode, bool *isSpread);
     Node letBlock(LetContext letContext);
     Node destructuringExpr(BindData<ParseHandler> *data, TokenKind tt);
 
     Node identifierName();
 
     bool matchLabel(MutableHandle<PropertyName*> label);
 
@@ -638,18 +637,17 @@ class Parser : private AutoGCRooter, pub
     // This function may only be called from within Parser::asmJS before
     // parsing any tokens. It returns the canonical offset to be used as the
     // start of the asm.js module. We use the offset in the char buffer
     // immediately after the "use asm" processing directive statement (which
     // includes any semicolons or newlines that end the statement).
     uint32_t offsetOfCurrentAsmJSModule() const { return tokenStream.currentToken().pos.end; }
   private:
 
-    friend class CompExprTransplanter;
-    friend class GenexpGuard<ParseHandler>;
+    friend class LegacyCompExprTransplanter;
     friend struct BindData<ParseHandler>;
 };
 
 /* Declare some required template specializations. */
 
 template <>
 bool
 Parser<FullParseHandler>::checkAndMarkAsAssignmentLhs(ParseNode *pn, AssignmentFlavor flavor);