Bug 1227035 - Tighten the check in ObjectGroup::useSingletonForClone a bit more. r=bhackett, a=lizzard
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 11 Mar 2016 15:21:16 +0100
changeset 323620 0371dd431b20709b0111b8dab2719f40ce066ffe
parent 323619 9238ffd09e62ad0c833a03ce4f907ccf9b337c64
child 323621 54836a65a622ddbefa6dd19b1a33168f392dab72
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett, lizzard
bugs1227035
milestone47.0a2
Bug 1227035 - Tighten the check in ObjectGroup::useSingletonForClone a bit more. r=bhackett, a=lizzard
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/Parser.cpp
js/src/frontend/SharedContext.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/vm/ObjectGroup.cpp
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -827,18 +827,18 @@ frontend::CompileLazyFunction(JSContext*
 
     Rooted<JSScript*> script(cx, JSScript::Create(cx, enclosingScope, false, options,
                                                   sourceObject, lazy->begin(), lazy->end()));
     if (!script)
         return false;
 
     script->bindings = pn->pn_funbox->bindings;
 
-    if (lazy->usesArgumentsApplyAndThis())
-        script->setUsesArgumentsApplyAndThis();
+    if (lazy->isLikelyConstructorWrapper())
+        script->setLikelyConstructorWrapper();
     if (lazy->hasBeenCloned())
         script->setHasBeenCloned();
 
     /*
      * We just pass false for insideNonGlobalEval and insideEval, because we
      * don't actually know whether we are or not.  The only consumer of those
      * booleans is TryConvertFreeName, and it has special machinery to avoid
      * doing bad things when a lazy function is inside eval.
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -6427,18 +6427,18 @@ BytecodeEmitter::emitFunction(ParseNode*
                                  insideNonGlobalEval, lineNum, emitterMode);
             if (!bce2.init())
                 return false;
 
             /* We measured the max scope depth when we parsed the function. */
             if (!bce2.emitFunctionScript(pn->pn_body))
                 return false;
 
-            if (funbox->usesArguments && funbox->usesApply && funbox->usesThis)
-                script->setUsesArgumentsApplyAndThis();
+            if (funbox->isLikelyConstructorWrapper())
+                script->setLikelyConstructorWrapper();
         }
         if (outersc->isFunctionBox())
             outersc->asFunctionBox()->function()->nonLazyScript()->setHasInnerFunctions(true);
     } else {
         MOZ_ASSERT(IsAsmJSModule(fun));
     }
 
     /* Make the function object a literal in the outer script's pool. */
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -783,16 +783,17 @@ FunctionBox::FunctionBox(ExclusiveContex
     inGenexpLambda(false),
     hasDestructuringArgs(false),
     useAsm(false),
     insideUseAsm(outerpc && outerpc->useAsmOrInsideUseAsm()),
     wasEmitted(false),
     usesArguments(false),
     usesApply(false),
     usesThis(false),
+    usesReturn(false),
     funCxFlags()
 {
     // Functions created at parse time may be set singleton after parsing and
     // baked into JIT code, so they must be allocated tenured. They are held by
     // the JSScript so cannot be collected during a minor GC anyway.
     MOZ_ASSERT(fun->isTenured());
 }
 
@@ -2879,18 +2880,18 @@ Parser<SyntaxParseHandler>::finishFuncti
 
     HeapPtrFunction* innerFunctions = lazy->innerFunctions();
     for (size_t i = 0; i < numInnerFunctions; i++)
         innerFunctions[i].init(pc->innerFunctions[i]);
 
     if (pc->sc->strict())
         lazy->setStrict();
     lazy->setGeneratorKind(funbox->generatorKind());
-    if (funbox->usesArguments && funbox->usesApply && funbox->usesThis)
-        lazy->setUsesArgumentsApplyAndThis();
+    if (funbox->isLikelyConstructorWrapper())
+        lazy->setLikelyConstructorWrapper();
     if (funbox->isDerivedClassConstructor())
         lazy->setIsDerivedClassConstructor();
     if (funbox->needsHomeObject())
         lazy->setNeedsHomeObject();
     PropagateTransitiveParseFlags(funbox, lazy);
 
     fun->initLazyScript(lazy);
     return true;
@@ -6500,16 +6501,17 @@ Parser<ParseHandler>::breakStatement(Yie
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_RETURN));
     uint32_t begin = pos().begin;
 
     MOZ_ASSERT(pc->sc->isFunctionBox());
+    pc->sc->asFunctionBox()->usesReturn = true;
 
     // Parse an optional operand.
     //
     // This is ugly, but we don't want to require a semicolon.
     Node exprNode;
     TokenKind tt = TOK_EOF;
     if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
         return null();
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -325,29 +325,34 @@ class FunctionBox : public ObjectBox, pu
     bool            useAsm:1;               /* see useAsmOrInsideUseAsm */
     bool            insideUseAsm:1;         /* see useAsmOrInsideUseAsm */
     bool            wasEmitted:1;           /* Bytecode has been emitted for this function. */
 
     // Fields for use in heuristics.
     bool            usesArguments:1;  /* contains a free use of 'arguments' */
     bool            usesApply:1;      /* contains an f.apply() call */
     bool            usesThis:1;       /* contains 'this' */
+    bool            usesReturn:1;     /* contains a 'return' statement */
 
     FunctionContextFlags funCxFlags;
 
     template <typename ParseHandler>
     FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun,
                 JSObject* enclosingStaticScope, ParseContext<ParseHandler>* pc,
                 Directives directives, bool extraWarnings, GeneratorKind generatorKind);
 
     ObjectBox* toObjectBox() override { return this; }
     JSFunction* function() const { return &object->as<JSFunction>(); }
     JSObject* staticScope() const override { return function(); }
     JSObject* enclosingStaticScope() const { return enclosingStaticScope_; }
 
+    bool isLikelyConstructorWrapper() const {
+        return usesArguments && usesApply && usesThis && !usesReturn;
+    }
+
     GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
     bool isGenerator() const { return generatorKind() != NotGenerator; }
     bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
     bool isStarGenerator() const { return generatorKind() == StarGenerator; }
     bool isArrow() const { return function()->isArrow(); }
 
     void setGeneratorKind(GeneratorKind kind) {
         // A generator kind can be set at initialization, or when "yield" is
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -4350,17 +4350,17 @@ LazyScript::CreateRaw(ExclusiveContext* 
     p.version = version;
     p.numFreeVariables = numFreeVariables;
     p.numInnerFunctions = numInnerFunctions;
     p.generatorKindBits = GeneratorKindAsBits(NotGenerator);
     p.strict = false;
     p.bindingsAccessedDynamically = false;
     p.hasDebuggerStatement = false;
     p.hasDirectEval = false;
-    p.usesArgumentsApplyAndThis = false;
+    p.isLikelyConstructorWrapper = false;
     p.isDerivedClassConstructor = false;
     p.needsHomeObject = false;
 
     LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
     MOZ_ASSERT_IF(res, res->version() == version);
     return res;
 }
 
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1144,17 +1144,17 @@ class JSScript : public js::gc::TenuredC
 
     // Script came from eval(), and is still active.
     bool isActiveEval_:1;
 
     // Script came from eval(), and is in eval cache.
     bool isCachedEval_:1;
 
     // 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
-    bool usesArgumentsApplyAndThis_:1;
+    bool isLikelyConstructorWrapper_:1;
 
     // IonMonkey compilation hints.
     bool failedBoundsCheck_:1; /* script has had hoisted bounds checks fail */
     bool failedShapeGuard_:1; /* script has had hoisted shape guard fail */
     bool hadFrequentBailouts_:1;
     bool hadOverflowBailout_:1;
     bool uninlineable_:1;    /* explicitly marked as uninlineable */
 
@@ -1407,20 +1407,20 @@ class JSScript : public js::gc::TenuredC
     void uncacheForEval() {
         MOZ_ASSERT(isCachedEval() && !isActiveEval());
         isCachedEval_ = false;
         isActiveEval_ = true;
     }
 
     void setActiveEval() { isActiveEval_ = true; }
 
-    bool usesArgumentsApplyAndThis() const {
-        return usesArgumentsApplyAndThis_;
+    bool isLikelyConstructorWrapper() const {
+        return isLikelyConstructorWrapper_;
     }
-    void setUsesArgumentsApplyAndThis() { usesArgumentsApplyAndThis_ = true; }
+    void setLikelyConstructorWrapper() { isLikelyConstructorWrapper_ = true; }
 
     bool isGeneratorExp() const { return isGeneratorExp_; }
 
     bool failedBoundsCheck() const {
         return failedBoundsCheck_;
     }
     bool failedShapeGuard() const {
         return failedShapeGuard_;
@@ -2174,17 +2174,17 @@ class LazyScript : public gc::TenuredCel
 
         // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
         // If you add another boolean here, make sure to initialze it in
         // LazyScript::CreateRaw().
         uint32_t strict : 1;
         uint32_t bindingsAccessedDynamically : 1;
         uint32_t hasDebuggerStatement : 1;
         uint32_t hasDirectEval : 1;
-        uint32_t usesArgumentsApplyAndThis : 1;
+        uint32_t isLikelyConstructorWrapper : 1;
         uint32_t hasBeenCloned : 1;
         uint32_t treatAsRunOnce : 1;
         uint32_t isDerivedClassConstructor : 1;
         uint32_t needsHomeObject : 1;
     };
 
     union {
         PackedView p_;
@@ -2328,21 +2328,21 @@ class LazyScript : public gc::TenuredCel
 
     bool hasDirectEval() const {
         return p_.hasDirectEval;
     }
     void setHasDirectEval() {
         p_.hasDirectEval = true;
     }
 
-    bool usesArgumentsApplyAndThis() const {
-        return p_.usesArgumentsApplyAndThis;
+    bool isLikelyConstructorWrapper() const {
+        return p_.isLikelyConstructorWrapper;
     }
-    void setUsesArgumentsApplyAndThis() {
-        p_.usesArgumentsApplyAndThis = true;
+    void setLikelyConstructorWrapper() {
+        p_.isLikelyConstructorWrapper = true;
     }
 
     bool hasBeenCloned() const {
         return p_.hasBeenCloned;
     }
     void setHasBeenCloned() {
         p_.hasBeenCloned = true;
     }
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -144,22 +144,22 @@ ObjectGroup::useSingletonForClone(JSFunc
      * initialize method. We capture this, along with similar cases, by looking
      * for short scripts which use both .apply and arguments. For such scripts,
      * whenever creating a new instance of the function we both give that
      * instance a singleton type and clone the underlying script.
      */
 
     uint32_t begin, end;
     if (fun->hasScript()) {
-        if (!fun->nonLazyScript()->usesArgumentsApplyAndThis())
+        if (!fun->nonLazyScript()->isLikelyConstructorWrapper())
             return false;
         begin = fun->nonLazyScript()->sourceStart();
         end = fun->nonLazyScript()->sourceEnd();
     } else {
-        if (!fun->lazyScript()->usesArgumentsApplyAndThis())
+        if (!fun->lazyScript()->isLikelyConstructorWrapper())
             return false;
         begin = fun->lazyScript()->begin();
         end = fun->lazyScript()->end();
     }
 
     return end - begin <= 100;
 }