Bug 1214013 - Remove funky Maybe<ParseContext> logic in BytecodeCompiler. (r=efaust)
authorShu-yu Guo <shu@rfrn.org>
Thu, 15 Oct 2015 00:36:34 -0700
changeset 303018 5523aa3a43234cdb4d1de146b33af5d4ba52c3a1
parent 303017 b2bec3b2d9e8364129154358859d66cc78442c33
child 303019 34e67379114cdef288267e3319cf61123e0fe826
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1214013
milestone44.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 1214013 - Remove funky Maybe<ParseContext> logic in BytecodeCompiler. (r=efaust)
js/src/asmjs/AsmJSValidate.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -6347,18 +6347,17 @@ ParseFunction(ModuleValidator& m, ParseN
     AsmJSParseContext* outerpc = m.parser().pc;
 
     Directives directives(outerpc);
     FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator);
     if (!funbox)
         return false;
 
     Directives newDirectives = directives;
-    AsmJSParseContext funpc(&m.parser(), outerpc, fn, funbox, &newDirectives,
-                            /* blockScopeDepth = */ 0);
+    AsmJSParseContext funpc(&m.parser(), outerpc, fn, funbox, &newDirectives);
     if (!funpc.init(m.parser()))
         return false;
 
     if (!m.parser().functionArgsAndBodyGeneric(InAllowed, YieldIsName, fn, fun, Statement)) {
         if (tokenStream.hadError() || directives == newDirectives)
             return false;
 
         return m.fail(fn, "encountered new directive in function");
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -72,24 +72,19 @@ class MOZ_STACK_CLASS BytecodeCompiler
     bool createParser();
     bool createSourceAndParser();
     bool createScript(bool savedCallerFun = false);
     bool createEmitter(SharedContext* sharedContext, HandleScript evalCaller = nullptr,
                        bool insideNonGlobalEval = false);
     bool isEvalCompilationUnit();
     bool isNonGlobalEvalCompilationUnit();
     bool isNonSyntacticCompilationUnit();
-    bool createParseContext(Maybe<ParseContext<FullParseHandler>>& parseContext,
-                            SharedContext& globalsc, uint32_t blockScopeDepth = 0);
-    bool saveCallerFun(HandleScript evalCaller, ParseContext<FullParseHandler>& parseContext);
-    bool handleStatementParseFailure(HandleObject scopeChain, HandleScript evalCaller,
-                                     Maybe<ParseContext<FullParseHandler>>& parseContext,
-                                     SharedContext& globalsc);
+    bool saveCallerFun(HandleScript evalCaller);
     bool handleParseFailure(const Directives& newDirectives);
-    bool prepareAndEmitTree(ParseNode** pn, ParseContext<FullParseHandler>& pc);
+    bool prepareAndEmitTree(ParseNode** pn);
     bool checkArgumentsWithinEval(JSContext* cx, HandleFunction fun);
     bool maybeCheckEvalFreeVariables(HandleScript evalCaller, HandleObject scopeChain,
                                      ParseContext<FullParseHandler>& pc);
     bool maybeSetDisplayURL(TokenStream& tokenStream);
     bool maybeSetSourceMap(TokenStream& tokenStream);
     bool maybeSetSourceMapFromOptions();
     bool emitFinalReturn();
     bool initGlobalOrEvalBindings(ParseContext<FullParseHandler>& pc);
@@ -296,78 +291,39 @@ BytecodeCompiler::isNonGlobalEvalCompila
 
 bool
 BytecodeCompiler::isNonSyntacticCompilationUnit()
 {
     return enclosingStaticScope->is<StaticNonSyntacticScopeObjects>();
 }
 
 bool
-BytecodeCompiler::createParseContext(Maybe<ParseContext<FullParseHandler>>& parseContext,
-                                     SharedContext& globalsc, uint32_t blockScopeDepth)
-{
-    parseContext.emplace(parser.ptr(), (GenericParseContext*) nullptr, (ParseNode*) nullptr,
-                         &globalsc, (Directives*) nullptr, blockScopeDepth);
-    return parseContext->init(*parser);
-}
-
-bool
-BytecodeCompiler::saveCallerFun(HandleScript evalCaller,
-                                ParseContext<FullParseHandler>& parseContext)
+BytecodeCompiler::saveCallerFun(HandleScript evalCaller)
 {
     /*
      * An eval script in a caller frame needs to have its enclosing
      * function captured in case it refers to an upvar, and someone
      * wishes to decompile it while it's running.
      *
      * This ends up as script->objects()->vector[0] in the compiled script.
      */
     RootedFunction fun(cx, evalCaller->functionOrCallerFunction());
     MOZ_ASSERT_IF(fun->strict(), options.strictOption);
     Directives directives(/* strict = */ options.strictOption);
-    ObjectBox* funbox = parser->newFunctionBox(/* fn = */ nullptr, fun, &parseContext,
-                                              directives, fun->generatorKind());
+    ObjectBox* funbox = parser->newFunctionBox(/* fn = */ nullptr, fun,
+                                               directives, fun->generatorKind(),
+                                               enclosingStaticScope);
     if (!funbox)
         return false;
 
     emitter->objectList.add(funbox);
     return true;
 }
 
 bool
-BytecodeCompiler::handleStatementParseFailure(HandleObject scopeChain, HandleScript evalCaller,
-                                              Maybe<ParseContext<FullParseHandler>>& parseContext,
-                                              SharedContext& globalsc)
-{
-    if (!parser->hadAbortedSyntaxParse())
-        return false;
-
-    // Parsing inner functions lazily may lead the parser into an
-    // unrecoverable state and may require starting over on the top
-    // level statement. Restart the parse; syntax parsing has
-    // already been disabled for the parser and the result will not
-    // be ambiguous.
-    parser->clearAbortedSyntaxParse();
-    parser->tokenStream.seek(startPosition);
-    parser->blockScopes.clear();
-
-    // Destroying the parse context will destroy its free
-    // variables, so check if any deoptimization is needed.
-    if (!maybeCheckEvalFreeVariables(evalCaller, scopeChain, parseContext.ref()))
-        return false;
-
-    parseContext.reset();
-    if (!createParseContext(parseContext, globalsc, script->bindings.numBlockScoped()))
-        return false;
-
-    MOZ_ASSERT(parser->pc == parseContext.ptr());
-    return true;
-}
-
-bool
 BytecodeCompiler::handleParseFailure(const Directives& newDirectives)
 {
     if (parser->hadAbortedSyntaxParse()) {
         // Hit some unrecoverable ambiguity during an inner syntax parse.
         // Syntax parsing has now been disabled in the parser, so retry
         // the parse.
         parser->clearAbortedSyntaxParse();
     } else if (parser->tokenStream.hadError() || directives == newDirectives) {
@@ -379,23 +335,18 @@ BytecodeCompiler::handleParseFailure(con
     // Assignment must be monotonic to prevent reparsing iloops
     MOZ_ASSERT_IF(directives.strict(), newDirectives.strict());
     MOZ_ASSERT_IF(directives.asmJS(), newDirectives.asmJS());
     directives = newDirectives;
     return true;
 }
 
 bool
-BytecodeCompiler::prepareAndEmitTree(ParseNode** ppn, ParseContext<FullParseHandler>& pc)
+BytecodeCompiler::prepareAndEmitTree(ParseNode** ppn)
 {
-    // Accumulate the maximum block scope depth, so that emitTree can assert
-    // when emitting JSOP_GETLOCAL that the local is indeed within the fixed
-    // part of the stack frame.
-    script->bindings.updateNumBlockScoped(pc.blockScopeDepth);
-
     if (!FoldConstants(cx, ppn, parser.ptr()) ||
         !NameFunctions(cx, *ppn) ||
         !emitter->updateLocalsToFrameSlots() ||
         !emitter->emitTree(*ppn))
     {
         return false;
     }
 
@@ -546,49 +497,53 @@ BytecodeCompiler::compileScript(HandleOb
     bool savedCallerFun = evalCaller && evalCaller->functionOrCallerFunction();
     if (!createScript(savedCallerFun))
         return nullptr;
 
     GlobalSharedContext globalsc(cx, enclosingStaticScope, directives, options.extraWarningsOption);
     if (!createEmitter(&globalsc, evalCaller, isNonGlobalEvalCompilationUnit()))
         return nullptr;
 
-    // Syntax parsing may cause us to restart processing of top level
-    // statements in the script. Use Maybe<> so that the parse context can be
-    // reset when this occurs.
-    //
-    // WARNING: ParseContext contains instances of Rooted and may be
-    // reset(). Do not make any new Rooted instances below this point to avoid
-    // violating the Rooted LIFO invariant.
-    Maybe<ParseContext<FullParseHandler>> pc;
-    if (!createParseContext(pc, globalsc))
-        return nullptr;
-
-    if (savedCallerFun && !saveCallerFun(evalCaller, pc.ref()))
+    if (savedCallerFun && !saveCallerFun(evalCaller))
         return nullptr;
 
-    {
-        ParseNode* pn;
-        do {
-            pn = isEvalCompilationUnit() ? parser->evalBody() : parser->globalBody();
-            if (!pn && !handleStatementParseFailure(scopeChain, evalCaller, pc, globalsc))
-                return nullptr;
-        } while (!pn);
-
-        if (!prepareAndEmitTree(&pn, *pc))
+    for (;;) {
+        ParseContext<FullParseHandler> pc(parser.ptr(),
+                                          /* parent = */ nullptr,
+                                          /* maybeFunction = */ nullptr,
+                                          &globalsc,
+                                          /* newDirectives = */ nullptr);
+        if (!pc.init(*parser))
             return nullptr;
 
-        if (!initGlobalOrEvalBindings(*pc))
+        ParseNode* pn;
+        if (isEvalCompilationUnit())
+            pn = parser->evalBody();
+        else
+            pn = parser->globalBody();
+
+        // Successfully parsed. Emit the script.
+        if (pn) {
+            if (!initGlobalOrEvalBindings(pc))
+                return nullptr;
+            if (!maybeCheckEvalFreeVariables(evalCaller, scopeChain, pc))
+                return nullptr;
+            if (!prepareAndEmitTree(&pn))
+                return nullptr;
+            parser->handler.freeTree(pn);
+
+            break;
+        }
+
+        // Maybe we aborted a syntax parse. See if we can try again.
+        if (!handleParseFailure(directives))
             return nullptr;
-
-        parser->handler.freeTree(pn);
     }
 
-    if (!maybeCheckEvalFreeVariables(evalCaller, scopeChain, *pc) ||
-        !maybeSetDisplayURL(parser->tokenStream) ||
+    if (!maybeSetDisplayURL(parser->tokenStream) ||
         !maybeSetSourceMap(parser->tokenStream) ||
         !maybeSetSourceMapFromOptions() ||
         !emitFinalReturn() ||
         !JSScript::fullyInitFromEmitter(cx, script, emitter.ptr()))
     {
         return nullptr;
     }
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -827,18 +827,17 @@ Parser<ParseHandler>::parse()
      *   an object lock before it finishes generating bytecode into a script
      *   protected from the GC by a root or a stack frame reference.
      */
     Rooted<ScopeObject*> staticLexical(context, &context->global()->lexicalScope().staticBlock());
     Directives directives(options().strictOption);
     GlobalSharedContext globalsc(context, staticLexical, directives,
                                  options().extraWarningsOption);
     ParseContext<ParseHandler> globalpc(this, /* parent = */ nullptr, ParseHandler::null(),
-                                        &globalsc, /* newDirectives = */ nullptr,
-                                        /* blockScopeDepth = */ 0);
+                                        &globalsc, /* newDirectives = */ nullptr);
     if (!globalpc.init(*this))
         return null();
 
     Node pn = statements(YieldIsName);
     if (pn) {
         TokenKind tt;
         if (!tokenStream.getToken(&tt, TokenStream::Operand))
             return null();
@@ -905,17 +904,17 @@ Parser<ParseHandler>::standaloneModule(H
     if (!mn)
         return null();
 
     ModuleBox* modulebox = newModuleBox(mn, module);
     if (!modulebox)
         return null();
     handler.setModuleBox(mn, modulebox);
 
-    ParseContext<FullParseHandler> modulepc(this, pc, mn, modulebox, nullptr, 0);
+    ParseContext<FullParseHandler> modulepc(this, pc, mn, modulebox, nullptr);
     if (!modulepc.init(*this))
         return null();
 
     ParseNode* pn = statements(YieldIsKeyword);
     if (!pn)
         return null();
 
     pn->pn_blockid = modulepc.blockid();
@@ -1034,18 +1033,17 @@ Parser<FullParseHandler>::standaloneFunc
 
     FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind,
                                          enclosingStaticScope);
     if (!funbox)
         return null();
     funbox->length = fun->nargs() - fun->hasRest();
     handler.setFunctionBox(fn, funbox);
 
-    ParseContext<FullParseHandler> funpc(this, pc, fn, funbox, newDirectives,
-                                         /* blockScopeDepth = */ 0);
+    ParseContext<FullParseHandler> funpc(this, pc, fn, funbox, newDirectives);
     if (!funpc.init(*this))
         return null();
 
     for (unsigned i = 0; i < formals.length(); i++) {
         if (!defineArg(fn, formals[i]))
             return null();
     }
 
@@ -2657,18 +2655,17 @@ Parser<FullParseHandler>::functionArgsAn
         {
             // Move the syntax parser to the current position in the stream.
             TokenStream::Position position(keepAtoms);
             tokenStream.tell(&position);
             if (!parser->tokenStream.seek(position, tokenStream))
                 return false;
 
             ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(),
-                                                   funbox, newDirectives,
-                                                   /* blockScopeDepth = */ 0);
+                                                   funbox, newDirectives);
             if (!funpc.init(*parser))
                 return false;
 
             if (!parser->functionArgsAndBodyGeneric(inHandling, yieldHandling,
                                                     SyntaxParseHandler::NodeGeneric, fun, kind))
             {
                 if (parser->hadAbortedSyntaxParse()) {
                     // Try again with a full parse.
@@ -2695,18 +2692,17 @@ Parser<FullParseHandler>::functionArgsAn
         pn->pn_blockid = outerpc->blockid();
         PropagateTransitiveParseFlags(funbox, outerpc->sc);
         return true;
     } while (false);
 
     blockScopes.resize(oldBlockScopesLength);
 
     // Continue doing a full parse for this inner function.
-    ParseContext<FullParseHandler> funpc(this, pc, pn, funbox, newDirectives,
-                                         /* blockScopeDepth = */ 0);
+    ParseContext<FullParseHandler> funpc(this, pc, pn, funbox, newDirectives);
     if (!funpc.init(*this))
         return false;
 
     if (!functionArgsAndBodyGeneric(inHandling, yieldHandling, pn, fun, kind))
         return false;
 
     if (!leaveFunction(pn, outerpc, kind))
         return false;
@@ -2734,18 +2730,17 @@ Parser<SyntaxParseHandler>::functionArgs
     ParseContext<SyntaxParseHandler>* outerpc = pc;
 
     // Create box for fun->object early to protect against last-ditch GC.
     FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
     if (!funbox)
         return false;
 
     // Initialize early for possible flags mutation via destructuringExpr.
-    ParseContext<SyntaxParseHandler> funpc(this, pc, handler.null(), funbox, newDirectives,
-                                           /* blockScopeDepth = */ 0);
+    ParseContext<SyntaxParseHandler> funpc(this, pc, handler.null(), funbox, newDirectives);
     if (!funpc.init(*this))
         return false;
 
     YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
     if (!functionArgsAndBodyGeneric(inHandling, yieldHandling, pn, fun, kind))
         return false;
 
     if (!leaveFunction(pn, outerpc, kind))
@@ -2799,17 +2794,17 @@ Parser<FullParseHandler>::standaloneLazy
         return null();
     funbox->length = fun->nargs() - fun->hasRest();
 
     if (fun->lazyScript()->isDerivedClassConstructor())
         funbox->setDerivedClassConstructor();
 
     Directives newDirectives = directives;
     ParseContext<FullParseHandler> funpc(this, /* parent = */ nullptr, pn, funbox,
-                                         &newDirectives, /* blockScopeDepth = */ 0);
+                                         &newDirectives);
     if (!funpc.init(*this))
         return null();
 
     YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
     FunctionSyntaxKind syntaxKind = Statement;
     if (fun->isClassConstructor())
         syntaxKind = ClassConstructor;
     else if (fun->isMethod())
@@ -8115,18 +8110,17 @@ Parser<ParseHandler>::generatorComprehen
 
     // Create box for fun->object early to root it.
     Directives directives(/* strict = */ outerpc->sc->strict());
     FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind);
     if (!genFunbox)
         return null();
 
     ParseContext<ParseHandler> genpc(this, outerpc, genfn, genFunbox,
-                                     /* newDirectives = */ nullptr,
-                                     /* blockScopeDepth = */ 0);
+                                     /* newDirectives = */ nullptr);
     if (!genpc.init(*this))
         return null();
 
     /*
      * We assume conservatively that any deoptimization flags in pc->sc
      * come from the kid. So we propagate these flags into genfn. For code
      * simplicity we also do not detect if the flags were only set in the
      * kid and could be removed from pc->sc.
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -254,24 +254,23 @@ struct MOZ_STACK_CLASS ParseContext : pu
     // later.
     //
     // The comments atop checkDestructuring explain the distinction between
     // assignment-like and declaration-like destructuring patterns, and why
     // they need to be treated differently.
     bool            inDeclDestructuring:1;
 
     ParseContext(Parser<ParseHandler>* prs, GenericParseContext* parent,
-                 Node maybeFunction, SharedContext* sc, Directives* newDirectives,
-                 uint32_t blockScopeDepth)
+                 Node maybeFunction, SharedContext* sc, Directives* newDirectives)
       : GenericParseContext(parent, sc),
         bodyid(0),           // initialized in init()
         stmtStack(prs->context),
         maybeFunction(maybeFunction),
         lastYieldOffset(NoYieldOffset),
-        blockScopeDepth(blockScopeDepth),
+        blockScopeDepth(0),
         blockNode(ParseHandler::null()),
         decls_(prs->context, prs->alloc),
         args_(prs->context),
         vars_(prs->context),
         bodyLevelLexicals_(prs->context),
         parserPC(&prs->pc),
         oldpc(prs->pc),
         lexdeps(prs->context),