Bug 887075 - Use original function when compiling lazy scripts, r=luke a=bajaj.
authorBrian Hackett <bhackett1024@gmail.com>
Fri, 26 Jul 2013 13:17:31 -0600
changeset 143704 39294d14e11111798c1f3311f05aa2c9da71287d
parent 143703 81a5eb02a7ee51e6a7e61f143da4634939ce452d
child 143705 2c84d35d5703d25a10c9a24e93e1b0dd038a94b3
push id4038
push userbhackett@mozilla.com
push dateFri, 26 Jul 2013 19:17:42 +0000
treeherdermozilla-aurora@39294d14e111 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke, bajaj
bugs887075
milestone24.0a2
Bug 887075 - Use original function when compiling lazy scripts, r=luke a=bajaj.
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/Parser.cpp
js/src/jsfun.cpp
js/src/jsscript.cpp
js/src/jsscript.h
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -334,35 +334,35 @@ frontend::CompileScript(JSContext *cx, H
 
     if (sct == &mysct && !sct->complete())
         return NULL;
 
     return script;
 }
 
 bool
-frontend::CompileLazyFunction(JSContext *cx, HandleFunction fun, LazyScript *lazy,
-                              const jschar *chars, size_t length)
+frontend::CompileLazyFunction(JSContext *cx, LazyScript *lazy, const jschar *chars, size_t length)
 {
-    JS_ASSERT(cx->compartment() == fun->compartment());
+    JS_ASSERT(cx->compartment() == lazy->function()->compartment());
 
     CompileOptions options(cx, lazy->version());
     options.setPrincipals(cx->compartment()->principals)
            .setOriginPrincipals(lazy->originPrincipals())
            .setFileAndLine(lazy->source()->filename(), lazy->lineno())
            .setColumn(lazy->column())
            .setCompileAndGo(true)
            .setNoScriptRval(false)
            .setSelfHostingMode(false);
 
     Parser<FullParseHandler> parser(cx, options, chars, length,
                                     /* foldConstants = */ true, NULL, lazy);
 
     uint32_t staticLevel = lazy->staticLevel(cx);
 
+    Rooted<JSFunction*> fun(cx, lazy->function());
     ParseNode *pn = parser.standaloneLazyFunction(fun, staticLevel, lazy->strict());
     if (!pn)
         return false;
 
     if (!NameFunctions(cx, pn))
         return false;
 
     RootedObject enclosingScope(cx, lazy->enclosingScope());
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -21,18 +21,17 @@ namespace frontend {
 
 JSScript *
 CompileScript(JSContext *cx, HandleObject scopeChain, HandleScript evalCaller,
               const CompileOptions &options, const jschar *chars, size_t length,
               JSString *source_ = NULL, unsigned staticLevel = 0,
               SourceCompressionToken *extraSct = NULL);
 
 bool
-CompileLazyFunction(JSContext *cx, HandleFunction fun, LazyScript *lazy,
-                    const jschar *chars, size_t length);
+CompileLazyFunction(JSContext *cx, LazyScript *lazy, const jschar *chars, size_t length);
 
 bool
 CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
                     const AutoNameVector &formals, const jschar *chars, size_t length,
                     bool isAsmJSRecompile = false);
 
 /*
  * True if str consists of an IdentifierStart character, followed by one or
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1999,17 +1999,18 @@ Parser<SyntaxParseHandler>::finishFuncti
     // still available.
 
     if (funbox->inWith)
         return abortIfSyntaxParser();
 
     size_t numFreeVariables = pc->lexdeps->count();
     size_t numInnerFunctions = pc->innerFunctions.length();
 
-    LazyScript *lazy = LazyScript::Create(context, numFreeVariables, numInnerFunctions, versionNumber(),
+    RootedFunction fun(context, funbox->function());
+    LazyScript *lazy = LazyScript::Create(context, fun, numFreeVariables, numInnerFunctions, versionNumber(),
                                           funbox->bufStart, funbox->bufEnd,
                                           funbox->startLine, funbox->startColumn);
     if (!lazy)
         return false;
 
     HeapPtrAtom *freeVariables = lazy->freeVariables();
     size_t i = 0;
     for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront())
@@ -2021,17 +2022,17 @@ Parser<SyntaxParseHandler>::finishFuncti
         innerFunctions[i].init(pc->innerFunctions[i]);
 
     if (pc->sc->strict)
         lazy->setStrict();
     if (funbox->usesArguments && funbox->usesApply)
         lazy->setUsesArgumentsAndApply();
     PropagateTransitiveParseFlags(funbox, lazy);
 
-    funbox->object->as<JSFunction>().initLazyScript(lazy);
+    fun->initLazyScript(lazy);
     return true;
 }
 
 template <>
 bool
 Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
                                               HandlePropertyName funName,
                                               size_t startOffset, FunctionType type,
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1066,16 +1066,26 @@ JSFunction::createScriptForLazilyInterpr
 
         if (script) {
             fun->initScript(script);
             return true;
         }
 
         fun->initScript(NULL);
 
+        if (fun != lazy->function()) {
+            script = lazy->function()->getOrCreateScript(cx);
+            if (!script) {
+                fun->initLazyScript(lazy);
+                return false;
+            }
+            fun->initScript(script);
+            return true;
+        }
+
         // Lazy script caching is only supported for leaf functions. If a
         // script with inner functions was returned by the cache, those inner
         // functions would be delazified when deep cloning the script, even if
         // they have never executed.
         //
         // Additionally, the lazy script cache is not used during incremental
         // GCs, to avoid resurrecting dead scripts after incremental sweeping
         // has started.
@@ -1115,17 +1125,17 @@ JSFunction::createScriptForLazilyInterpr
         if (!chars) {
             fun->initLazyScript(lazy);
             return false;
         }
 
         const jschar *lazyStart = chars + lazy->begin();
         size_t lazyLength = lazy->end() - lazy->begin();
 
-        if (!frontend::CompileLazyFunction(cx, fun, lazy, lazyStart, lazyLength)) {
+        if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength)) {
             fun->initLazyScript(lazy);
             return false;
         }
 
         script = fun->nonLazyScript();
 
         // Try to insert the newly compiled script into the lazy script cache.
         if (!lazy->numInnerFunctions()) {
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -2776,16 +2776,19 @@ JSScript::markChildren(JSTracer *trc)
 #ifdef JS_ION
     ion::TraceIonScripts(trc, this);
 #endif
 }
 
 void
 LazyScript::markChildren(JSTracer *trc)
 {
+    if (function_)
+        MarkObject(trc, &function_, "function");
+
     if (sourceObject_)
         MarkObject(trc, &sourceObject_, "sourceObject");
 
     if (enclosingScope_)
         MarkObject(trc, &enclosingScope_, "enclosingScope");
 
     if (script_)
         MarkScript(trc, &script_, "realScript");
@@ -2950,19 +2953,20 @@ JSScript::formalIsAliased(unsigned argSl
 }
 
 bool
 JSScript::formalLivesInArgumentsObject(unsigned argSlot)
 {
     return argsObjAliasesFormals() && !formalIsAliased(argSlot);
 }
 
-LazyScript::LazyScript(void *table, uint32_t numFreeVariables, uint32_t numInnerFunctions,
+LazyScript::LazyScript(JSFunction *fun, void *table, uint32_t numFreeVariables, uint32_t numInnerFunctions,
                        JSVersion version, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
   : script_(NULL),
+    function_(fun),
     enclosingScope_(NULL),
     sourceObject_(NULL),
     table_(table),
     originPrincipals_(NULL),
     version_(version),
     numFreeVariables_(numFreeVariables),
     numInnerFunctions_(numInnerFunctions),
     strict_(false),
@@ -3001,17 +3005,18 @@ LazyScript::setParent(JSObject *enclosin
 
 ScriptSourceObject *
 LazyScript::sourceObject() const
 {
     return sourceObject_ ? &sourceObject_->as<ScriptSourceObject>() : NULL;
 }
 
 /* static */ LazyScript *
-LazyScript::Create(JSContext *cx, uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version,
+LazyScript::Create(JSContext *cx, HandleFunction fun,
+                   uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version,
                    uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
 {
     JS_ASSERT(begin <= end);
 
     size_t bytes = (numFreeVariables * sizeof(HeapPtrAtom))
                  + (numInnerFunctions * sizeof(HeapPtrFunction));
 
     void *table = NULL;
@@ -3020,17 +3025,17 @@ LazyScript::Create(JSContext *cx, uint32
         if (!table)
             return NULL;
     }
 
     LazyScript *res = js_NewGCLazyScript(cx);
     if (!res)
         return NULL;
 
-    return new (res) LazyScript(table, numFreeVariables, numInnerFunctions, version,
+    return new (res) LazyScript(fun, table, numFreeVariables, numInnerFunctions, version,
                                 begin, end, lineno, column);
 }
 
 uint32_t
 LazyScript::staticLevel(JSContext *cx) const
 {
     for (StaticScopeIter ssi(cx, enclosingScope()); !ssi.done(); ssi++) {
         if (ssi.type() == StaticScopeIter::FUNCTION)
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1110,30 +1110,29 @@ struct SourceCompressionToken;
 // Information about a script which may be (or has been) lazily compiled to
 // bytecode from its source.
 class LazyScript : public js::gc::Cell
 {
     // If non-NULL, the script has been compiled and this is a forwarding
     // pointer to the result.
     HeapPtrScript script_;
 
+    // Original function with which the lazy script is associated.
+    HeapPtrFunction function_;
+
     // Function or block chain in which the script is nested, or NULL.
     HeapPtrObject enclosingScope_;
 
     // Source code object, or NULL if the script in which this is nested has
     // not been compiled yet.
     HeapPtrObject sourceObject_;
 
     // Heap allocated table with any free variables or inner functions.
     void *table_;
 
-#if JS_BITS_PER_WORD == 32
-    uint32_t padding;
-#endif
-
     // Assorted bits that should really be in ScriptSourceObject.
     JSPrincipals *originPrincipals_;
     uint32_t version_ : 8;
 
     uint32_t numFreeVariables_ : 24;
     uint32_t numInnerFunctions_ : 26;
 
     // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
@@ -1145,23 +1144,29 @@ class LazyScript : public js::gc::Cell
     uint32_t hasBeenCloned_:1;
 
     // Source location for the script.
     uint32_t begin_;
     uint32_t end_;
     uint32_t lineno_;
     uint32_t column_;
 
-    LazyScript(void *table, uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version,
+    LazyScript(JSFunction *fun, void *table,
+               uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version,
                uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column);
 
   public:
-    static LazyScript *Create(JSContext *cx, uint32_t numFreeVariables, uint32_t numInnerFunctions,
+    static LazyScript *Create(JSContext *cx, HandleFunction fun,
+                              uint32_t numFreeVariables, uint32_t numInnerFunctions,
                               JSVersion version, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column);
 
+    JSFunction *function() const {
+        return function_;
+    }
+
     void initScript(JSScript *script);
     JSScript *maybeScript() {
         return script_;
     }
 
     JSObject *enclosingScope() const {
         return enclosingScope_;
     }