Bug 980585 - Don't delazify lazy scripts whose outer functions couldn't be compiled. (r=bhackett)
authorShu-yu Guo <shu@rfrn.org>
Thu, 13 Mar 2014 18:41:46 -0700
changeset 173514 c261d5623b088c0116f43f8f8ab7d20d53fec50e
parent 173513 94f9ebdc6662676727bbdd1805abf756766cc05c
child 173515 17a33bb88521b4c62a25d871ddd567c3c969f9da
push id26407
push usercbook@mozilla.com
push dateFri, 14 Mar 2014 11:34:21 +0000
treeherdermozilla-central@0a5ec8ab99a2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs980585
milestone30.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 980585 - Don't delazify lazy scripts whose outer functions couldn't be compiled. (r=bhackett)
js/src/jit-test/tests/debug/bug980585.js
js/src/jscompartment.cpp
js/src/jsscript.cpp
js/src/jsscript.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug980585.js
@@ -0,0 +1,10 @@
+var g = newGlobal();
+var dbg = new Debugger(g);
+
+try {
+  g.eval("function f() { var array = ['a', 'b']; [1].map(function () {}); return {array}; }");
+} catch (e) {
+  // Ignore the syntax error.
+}
+
+dbg.findScripts();
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -716,26 +716,32 @@ AddInnerLazyFunctionsFromScript(JSScript
 
 static bool
 CreateLazyScriptsForCompartment(JSContext *cx)
 {
     AutoObjectVector lazyFunctions(cx);
 
     // Find all live lazy scripts in the compartment, and via them all root
     // lazy functions in the compartment: those which have not been compiled
-    // and which have a source object, indicating that their parent has been
-    // compiled.
+    // and which have a source object, indicating that they have a parent.
     for (gc::CellIter i(cx->zone(), gc::FINALIZE_LAZY_SCRIPT); !i.done(); i.next()) {
         LazyScript *lazy = i.get<LazyScript>();
         JSFunction *fun = lazy->functionNonDelazifying();
         if (fun->compartment() == cx->compartment() &&
             lazy->sourceObject() && !lazy->maybeScript())
         {
             MOZ_ASSERT(fun->isInterpretedLazy());
             MOZ_ASSERT(lazy == fun->lazyScriptOrNull());
+
+            // Only compile lazy scripts that in fact escaped to script. We
+            // are iterating GC things here, so we might see lazy scripts
+            // whose enclosing scripts were not successfully compiled.
+            if (lazy->hasUncompiledEnclosingScript())
+                continue;
+
             if (!lazyFunctions.append(fun))
                 return false;
         }
     }
 
     // Create scripts for each lazy function, updating the list of functions to
     // process with any newly exposed inner functions in created scripts.
     // A function cannot be delazified until its outer script exists.
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3668,16 +3668,34 @@ LazyScript::initRuntimeFields(uint64_t p
         uint64_t packed;
     };
 
     packed = packedFields;
     p_.hasBeenCloned = p.hasBeenCloned;
     p_.treatAsRunOnce = p.treatAsRunOnce;
 }
 
+bool
+LazyScript::hasUncompiledEnclosingScript() const
+{
+    // It can happen that we created lazy scripts while compiling an enclosing
+    // script, but we errored out while compiling that script. When we iterate
+    // over lazy script in a compartment, we might see lazy scripts that never
+    // escaped to script and should be ignored.
+    //
+    // If the enclosing scope is a function with a null script or has a script
+    // without code, it was not successfully compiled.
+
+    if (!enclosingScope() || !enclosingScope()->is<JSFunction>())
+        return false;
+
+    JSFunction &fun = enclosingScope()->as<JSFunction>();
+    return fun.isInterpreted() && (!fun.mutableScript() || !fun.nonLazyScript()->code());
+}
+
 uint32_t
 LazyScript::staticLevel(JSContext *cx) const
 {
     for (StaticScopeIter<NoGC> ssi(enclosingScope()); !ssi.done(); ssi++) {
         if (ssi.type() == StaticScopeIter<NoGC>::FUNCTION)
             return ssi.funScript()->staticLevel() + 1;
     }
     return 1;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1820,16 +1820,17 @@ class LazyScript : public gc::BarrieredC
     }
     uint32_t lineno() const {
         return lineno_;
     }
     uint32_t column() const {
         return column_;
     }
 
+    bool hasUncompiledEnclosingScript() const;
     uint32_t staticLevel(JSContext *cx) const;
 
     void markChildren(JSTracer *trc);
     void finalize(js::FreeOp *fop);
 
     static inline js::ThingRootKind rootKind() { return js::THING_ROOT_LAZY_SCRIPT; }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)