Bug 1165486 - Detect with scopes at parse time using the static scope chain for non-function scripts. Also cache static scope properties on SharedGlobalContext. (r=efaust)
authorShu-yu Guo <shu@rfrn.org>
Sun, 21 Jun 2015 11:49:58 -0700
changeset 280717 63b4dd8b552eeb71b5111e646f750fe549455f17
parent 280716 1c9b3671def48c26edb06cf58e0de2e3db406da7
child 280718 43b82c9c8a9f746e088d13159fb7a97bb05d0766
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1165486
milestone41.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 1165486 - Detect with scopes at parse time using the static scope chain for non-function scripts. Also cache static scope properties on SharedGlobalContext. (r=efaust)
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/Parser.cpp
js/src/frontend/SharedContext.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2351,23 +2351,24 @@ bool
 BytecodeEmitter::checkRunOnceContext()
 {
     return checkSingletonContext() || (!isInLoop() && isRunOnceLambda());
 }
 
 bool
 BytecodeEmitter::needsImplicitThis()
 {
-    if (sc->isFunctionBox() && sc->asFunctionBox()->inWith)
+    if (sc->inWith())
         return true;
 
     for (StmtInfoBCE* stmt = topStmt; stmt; stmt = stmt->down) {
         if (stmt->type == STMT_WITH)
             return true;
     }
+
     return false;
 }
 
 void
 BytecodeEmitter::tellDebuggerAboutCompiledScript(ExclusiveContext* cx)
 {
     // Note: when parsing off thread the resulting scripts need to be handed to
     // the debugger after rejoining to the main thread.
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -591,63 +591,63 @@ FunctionBox::FunctionBox(ExclusiveContex
                          bool extraWarnings, GeneratorKind generatorKind)
   : ObjectBox(fun, traceListHead),
     SharedContext(cx, directives, extraWarnings),
     bindings(),
     bufStart(0),
     bufEnd(0),
     length(0),
     generatorKindBits_(GeneratorKindAsBits(generatorKind)),
-    inWith(false),                  // initialized below
+    inWith_(false),                  // initialized below
     inGenexpLambda(false),
     hasDestructuringArgs(false),
     useAsm(false),
     insideUseAsm(outerpc && outerpc->useAsmOrInsideUseAsm()),
     usesArguments(false),
     usesApply(false),
     usesThis(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());
 
     if (!outerpc) {
-        inWith = false;
+        inWith_ = false;
 
     } else if (outerpc->parsingWith) {
         // This covers cases that don't involve eval().  For example:
         //
         //   with (o) { (function() { g(); })(); }
         //
         // In this case, |outerpc| corresponds to global code, and
         // outerpc->parsingWith is true.
-        inWith = true;
+        inWith_ = true;
 
     } else if (outerpc->sc->isFunctionBox()) {
         // This is like the above case, but for more deeply nested functions.
         // For example:
         //
         //   with (o) { eval("(function() { (function() { g(); })(); })();"); } }
         //
         // In this case, the inner anonymous function needs to inherit the
         // setting of |inWith| from the outer one.
         FunctionBox* parent = outerpc->sc->asFunctionBox();
-        if (parent && parent->inWith)
-            inWith = true;
+        if (parent && parent->inWith())
+            inWith_ = true;
     } else {
         // This is like the above case, but when inside eval.
         //
         // For example:
         //
         //   with(o) { eval("(function() { g(); })();"); }
         //
         // In this case, the static scope chain tells us the presence of with.
-        inWith = outerpc->sc->asGlobalSharedContext()->inWith();
+        inWith_ = outerpc->sc->inWith();
     }
 }
 
 template <typename ParseHandler>
 FunctionBox*
 Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, ParseContext<ParseHandler>* outerpc,
                                      Directives inheritedDirectives, GeneratorKind generatorKind)
 {
@@ -2236,17 +2236,17 @@ template <>
 bool
 Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox* funbox,
                                                      Node body)
 {
     // The LazyScript for a lazily parsed function needs to be constructed
     // while its ParseContext and associated lexdeps and inner functions are
     // still available.
 
-    if (funbox->inWith)
+    if (funbox->inWith())
         return abortIfSyntaxParser();
 
     size_t numFreeVariables = pc->lexdeps->count();
     size_t numInnerFunctions = pc->innerFunctions.length();
 
     RootedFunction fun(context, funbox->function());
     LazyScript* lazy = LazyScript::CreateRaw(context, fun, numFreeVariables, numInnerFunctions,
                                              versionNumber(), funbox->bufStart, funbox->bufEnd,
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -232,16 +232,17 @@ class SharedContext
         return atom == context->names().dotGenerator || atom == context->names().dotGenRVal;
     }
 
     enum class AllowedSyntax {
         NewTarget,
         SuperProperty
     };
     virtual bool allowSyntax(AllowedSyntax allowed) const = 0;
+    virtual bool inWith() const = 0;
 
   protected:
     static bool FunctionAllowsSyntax(JSFunction* func, AllowedSyntax allowed)
     {
         MOZ_ASSERT(!func->isArrow());
 
         switch (allowed) {
           case AllowedSyntax::NewTarget:
@@ -254,61 +255,79 @@ class SharedContext
         MOZ_CRASH("Unknown AllowedSyntax query");
     }
 };
 
 class GlobalSharedContext : public SharedContext
 {
   private:
     Handle<ScopeObject*> topStaticScope_;
+    bool allowNewTarget_;
+    bool allowSuperProperty_;
+    bool inWith_;
 
-  public:
-    GlobalSharedContext(ExclusiveContext* cx,
-                        Directives directives, Handle<ScopeObject*> topStaticScope,
-                        bool extraWarnings)
-      : SharedContext(cx, directives, extraWarnings),
-        topStaticScope_(topStaticScope)
-    {}
-
-    ObjectBox* toObjectBox() { return nullptr; }
-    HandleObject topStaticScope() const { return topStaticScope_; }
-
-    bool allowSyntax(AllowedSyntax allowed) const {
+    bool computeAllowSyntax(AllowedSyntax allowed) const {
         StaticScopeIter<CanGC> it(context, topStaticScope_);
         for (; !it.done(); it++) {
             if (it.type() == StaticScopeIter<CanGC>::Function &&
                 !it.fun().isArrow())
             {
                 return FunctionAllowsSyntax(&it.fun(), allowed);
             }
         }
         return false;
     }
 
-    bool inWith() const {
+    bool computeInWith() const {
         for (StaticScopeIter<CanGC> it(context, topStaticScope_); !it.done(); it++) {
             if (it.type() == StaticScopeIter<CanGC>::With)
                 return true;
         }
         return false;
     }
+
+  public:
+    GlobalSharedContext(ExclusiveContext* cx,
+                        Directives directives, Handle<ScopeObject*> topStaticScope,
+                        bool extraWarnings)
+      : SharedContext(cx, directives, extraWarnings),
+        topStaticScope_(topStaticScope),
+        allowNewTarget_(computeAllowSyntax(AllowedSyntax::NewTarget)),
+        allowSuperProperty_(computeAllowSyntax(AllowedSyntax::SuperProperty)),
+        inWith_(computeInWith())
+    {}
+
+    ObjectBox* toObjectBox() override { return nullptr; }
+    HandleObject topStaticScope() const { return topStaticScope_; }
+    bool allowSyntax(AllowedSyntax allowSyntax) const override {
+        switch (allowSyntax) {
+          case AllowedSyntax::NewTarget:
+            // Any function supports new.target
+            return allowNewTarget_;
+          case AllowedSyntax::SuperProperty:
+            return allowSuperProperty_;
+          default:;
+        }
+        MOZ_CRASH("Unknown AllowedSyntax query");
+    }
+    bool inWith() const override { return inWith_; }
 };
 
 class FunctionBox : public ObjectBox, public SharedContext
 {
   public:
     Bindings        bindings;               /* bindings for this function */
     uint32_t        bufStart;
     uint32_t        bufEnd;
     uint32_t        startLine;
     uint32_t        startColumn;
     uint16_t        length;
 
     uint8_t         generatorKindBits_;     /* The GeneratorKind of this function. */
-    bool            inWith:1;               /* some enclosing scope is a with-statement */
+    bool            inWith_:1;              /* some enclosing scope is a with-statement */
     bool            inGenexpLambda:1;       /* lambda from generator expression */
     bool            hasDestructuringArgs:1; /* arguments list contains destructuring expression */
     bool            useAsm:1;               /* see useAsmOrInsideUseAsm */
     bool            insideUseAsm:1;         /* see useAsmOrInsideUseAsm */
 
     // Fields for use in heuristics.
     bool            usesArguments:1;  /* contains a free use of 'arguments' */
     bool            usesApply:1;      /* contains an f.apply() call */
@@ -316,17 +335,17 @@ class FunctionBox : public ObjectBox, pu
 
     FunctionContextFlags funCxFlags;
 
     template <typename ParseHandler>
     FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun,
                 ParseContext<ParseHandler>* pc, Directives directives,
                 bool extraWarnings, GeneratorKind generatorKind);
 
-    ObjectBox* toObjectBox() { return this; }
+    ObjectBox* toObjectBox() override { return this; }
     JSFunction* function() const { return &object->as<JSFunction>(); }
 
     GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
     bool isGenerator() const { return generatorKind() != NotGenerator; }
     bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
     bool isStarGenerator() const { return generatorKind() == StarGenerator; }
 
     void setGeneratorKind(GeneratorKind kind) {
@@ -380,19 +399,23 @@ class FunctionBox : public ObjectBox, pu
         // Note: this should be kept in sync with JSFunction::isHeavyweight().
         return bindings.hasAnyAliasedBindings() ||
                hasExtensibleScope() ||
                needsDeclEnvObject() ||
                needsHomeObject()    ||
                isGenerator();
     }
 
-    bool allowSyntax(AllowedSyntax allowed) const {
+    bool allowSyntax(AllowedSyntax allowed) const override {
         return FunctionAllowsSyntax(function(), allowed);
     }
+
+    bool inWith() const override {
+        return inWith_;
+    }
 };
 
 inline FunctionBox*
 SharedContext::asFunctionBox()
 {
     MOZ_ASSERT(isFunctionBox());
     return static_cast<FunctionBox*>(this);
 }