Bug 928971 - Consistently test for whether functions will be run once closures, r=luke.
authorBrian Hackett <bhackett1024@gmail.com>
Mon, 21 Oct 2013 10:01:47 -0600
changeset 151494 d2b4e498b5aaf98aa027cfe4205740240e490721
parent 151493 cbaa108583eef5bbfb261bbe79ef787879d7b082
child 151495 38d2cbc118684c9a3afa3c6ef6eaacdcca91e9ae
push id25498
push userkwierso@gmail.com
push dateTue, 22 Oct 2013 00:29:50 +0000
treeherdermozilla-central@4503553be6de [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs928971
milestone27.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 928971 - Consistently test for whether functions will be run once closures, r=luke.
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2618,16 +2618,32 @@ EmitSwitch(ExclusiveContext *cx, Bytecod
     if (pn->pn_right->isKind(PNK_LEXICALSCOPE))
         EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObjCount);
 #endif
 
     return true;
 }
 
 bool
+BytecodeEmitter::isRunOnceLambda()
+{
+    // The run once lambda flags set by the parser are approximate, and we look
+    // at properties of the function itself before deciding to emit a function
+    // as a run once lambda.
+
+    if (!(parent && parent->emittingRunOnceLambda) && !lazyRunOnceLambda)
+        return false;
+
+    FunctionBox *funbox = sc->asFunctionBox();
+    return !funbox->argumentsHasLocalBinding() &&
+           !funbox->isGenerator() &&
+           !funbox->function()->name();
+}
+
+bool
 frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *body)
 {
     /*
      * The decompiler has assumptions about what may occur immediately after
      * script->main (e.g., in the case of destructuring params). Thus, put the
      * following ops into the range [script->code, script->main). Note:
      * execution starts from script->code, so this has no semantic effect.
      */
@@ -2662,21 +2678,17 @@ frontend::EmitFunctionScript(ExclusiveCo
         bce->switchToMain();
     }
 
     /*
      * Emit a prologue for run-once scripts which will deoptimize JIT code if
      * the script ends up running multiple times via foo.caller related
      * shenanigans.
      */
-    bool runOnce =
-        bce->isRunOnceLambda() &&
-        !funbox->argumentsHasLocalBinding() &&
-        !funbox->isGenerator() &&
-        !funbox->function()->name();
+    bool runOnce = bce->isRunOnceLambda();
     if (runOnce) {
         bce->switchToProlog();
         if (Emit1(cx, bce, JSOP_RUNONCE) < 0)
             return false;
         bce->switchToMain();
     }
 
     if (!EmitTree(cx, bce, body))
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -122,19 +122,17 @@ struct BytecodeEmitter
 
     bool            emittingForInit:1;  /* true while emitting init expr of for; exclude 'in' */
 
     bool            emittingRunOnceLambda:1; /* true while emitting a lambda which is only
                                                 expected to run once. */
     bool            lazyRunOnceLambda:1; /* true while lazily emitting a script for
                                           * a lambda which is only expected to run once. */
 
-    bool isRunOnceLambda() {
-        return (parent && parent->emittingRunOnceLambda) || lazyRunOnceLambda;
-    }
+    bool isRunOnceLambda();
 
     bool            insideEval:1;       /* True if compiling an eval-expression or a function
                                            nested inside an eval. */
 
     const bool      hasGlobalScope:1;   /* frontend::CompileScript's scope chain is the
                                            global object */
 
     enum EmitterMode {