Bug 887075 - Use original function when compiling lazy scripts, r=luke.
authorBrian Hackett <bhackett1024@gmail.com>
Mon, 15 Jul 2013 14:53:13 -0600
changeset 138579 1ef79950f0ab9fac1d7a3af3854b0c68c00d1d65
parent 138578 6127dd6a6038cf2dd64ce493fc72e1f28ae589fd
child 138580 8511cdf640e8a1866690c64170255b5784c7bb5f
push id24961
push useremorley@mozilla.com
push dateTue, 16 Jul 2013 08:58:21 +0000
treeherdermozilla-central@41ed26826acb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs887075
milestone25.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 887075 - Use original function when compiling lazy scripts, r=luke.
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
@@ -353,35 +353,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, &cx->tempLifoAlloc(), 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
@@ -2020,17 +2020,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())
@@ -2042,17 +2043,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
@@ -1070,16 +1070,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.
@@ -1119,17 +1129,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
@@ -2787,16 +2787,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");
@@ -2961,19 +2964,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),
@@ -3012,18 +3016,18 @@ LazyScript::setParent(JSObject *enclosin
 
 ScriptSourceObject *
 LazyScript::sourceObject() const
 {
     return sourceObject_ ? &sourceObject_->as<ScriptSourceObject>() : NULL;
 }
 
 /* static */ LazyScript *
-LazyScript::Create(ExclusiveContext *cx, uint32_t numFreeVariables, uint32_t numInnerFunctions,
-                   JSVersion version,
+LazyScript::Create(ExclusiveContext *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;
@@ -3032,17 +3036,17 @@ LazyScript::Create(ExclusiveContext *cx,
         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
@@ -1119,30 +1119,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.
@@ -1154,25 +1153,30 @@ 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(ExclusiveContext *cx,
+    static LazyScript *Create(ExclusiveContext *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_;
     }