Bug 976536 - Fix JSFunction::existingScript returning NULL in some cases. r=till, a=sledru
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 19 Apr 2014 13:45:59 +0200
changeset 183807 a5688b606883
parent 183806 9208db873dbf
child 183808 02556a393ed8
push id3495
push userryanvm@gmail.com
push date2014-04-21 15:45 +0000
treeherdermozilla-beta@a5688b606883 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill, sledru
bugs976536
milestone29.0
Bug 976536 - Fix JSFunction::existingScript returning NULL in some cases. r=till, a=sledru
js/src/jit/BaselineBailouts.cpp
js/src/jit/IonFrames.cpp
js/src/jsfun.h
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1254,36 +1254,36 @@ jit::BailoutIonToBaseline(JSContext *cx,
     BaselineStackBuilder builder(iter, 1024);
     if (!builder.init())
         return BAILOUT_RETURN_FATAL_ERROR;
     IonSpew(IonSpew_BaselineBailouts, "  Incoming frame ptr = %p", builder.startFrame());
 
     SnapshotIterator snapIter(iter);
 
     RootedFunction callee(cx, iter.maybeCallee());
+    RootedScript scr(cx, iter.script());
     if (callee) {
         IonSpew(IonSpew_BaselineBailouts, "  Callee function (%s:%u)",
-                callee->existingScript()->filename(), callee->existingScript()->lineno());
+                scr->filename(), scr->lineno());
     } else {
         IonSpew(IonSpew_BaselineBailouts, "  No callee!");
     }
 
     if (iter.isConstructing())
         IonSpew(IonSpew_BaselineBailouts, "  Constructing!");
     else
         IonSpew(IonSpew_BaselineBailouts, "  Not constructing!");
 
     IonSpew(IonSpew_BaselineBailouts, "  Restoring frames:");
     size_t frameNo = 0;
 
     // Reconstruct baseline frames using the builder.
     RootedScript caller(cx);
     jsbytecode *callerPC = nullptr;
     RootedFunction fun(cx, callee);
-    RootedScript scr(cx, iter.script());
     AutoValueVector startFrameFormals(cx);
 
     while (true) {
 #if JS_TRACE_LOGGING
         if (frameNo > 0) {
             TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_START, scr);
             TraceLogging::defaultLogger()->log(TraceLogging::INFO_ENGINE_BASELINE);
         }
@@ -1311,17 +1311,17 @@ jit::BailoutIonToBaseline(JSContext *cx,
         if (handleException)
             break;
 
         JS_ASSERT(nextCallee);
         JS_ASSERT(callPC);
         caller = scr;
         callerPC = callPC;
         fun = nextCallee;
-        scr = fun->existingScript();
+        scr = fun->existingScriptForInlinedFunction();
         snapIter.nextFrame();
 
         frameNo++;
     }
     IonSpew(IonSpew_BaselineBailouts, "  Done restoring frames");
     BailoutKind bailoutKind = snapIter.bailoutKind();
 
     if (!startFrameFormals.empty()) {
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -1551,17 +1551,17 @@ InlineFrameIteratorMaybeGC<allowGC>::fin
 
         si_.nextFrame();
 
         callee_ = &funval.toObject().as<JSFunction>();
 
         // Inlined functions may be clones that still point to the lazy script
         // for the executed script, if they are clones. The actual script
         // exists though, just make sure the function points to it.
-        script_ = callee_->existingScript();
+        script_ = callee_->existingScriptForInlinedFunction();
 
         pc_ = script_->offsetToPC(si_.pcOffset());
     }
 
     framesRead_++;
 }
 template void InlineFrameIteratorMaybeGC<NoGC>::findNextFrame();
 template void InlineFrameIteratorMaybeGC<CanGC>::findNextFrame();
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -283,40 +283,46 @@ class JSFunction : public JSObject
     // source, or nullptr if the function is a clone of a self hosted function.
     //
     // There are several methods to get the script of an interpreted function:
     //
     // - For all interpreted functions, getOrCreateScript() will get the
     //   JSScript, delazifying the function if necessary. This is the safest to
     //   use, but has extra checks, requires a cx and may trigger a GC.
     //
-    // - For functions which may have a LazyScript but whose JSScript is known
-    //   to exist, existingScript() will get the script and delazify the
-    //   function if necessary.
+    // - For inlined functions which may have a LazyScript but whose JSScript
+    //   is known to exist, existingScriptForInlinedFunction() will get the
+    //   script and delazify the function if necessary.
     //
     // - For functions known to have a JSScript, nonLazyScript() will get it.
 
     JSScript *getOrCreateScript(JSContext *cx) {
         JS_ASSERT(isInterpreted());
         JS_ASSERT(cx);
         if (isInterpretedLazy()) {
             JS::RootedFunction self(cx, this);
             if (!createScriptForLazilyInterpretedFunction(cx, self))
                 return nullptr;
             return self->nonLazyScript();
         }
         return nonLazyScript();
     }
 
-    JSScript *existingScript() {
-        JS_ASSERT(isInterpreted());
+    JSScript *existingScriptForInlinedFunction() {
+        MOZ_ASSERT(isInterpreted());
         if (isInterpretedLazy()) {
+            // Get the script from the canonical function. Ion used the
+            // canonical function to inline the script and because it has
+            // Baseline code it has not been relazified. Note that we can't
+            // use lazyScript->script_ here as it may be null in some cases,
+            // see bug 976536.
             js::LazyScript *lazy = lazyScript();
-            JSScript *script = lazy->maybeScript();
-            JS_ASSERT(script);
+            JSFunction *fun = lazy->functionNonDelazifying();
+            MOZ_ASSERT(fun);
+            JSScript *script = fun->nonLazyScript();
 
             if (shadowZone()->needsBarrier())
                 js::LazyScript::writeBarrierPre(lazy);
 
             flags_ &= ~INTERPRETED_LAZY;
             flags_ |= INTERPRETED;
             initScript(script);
         }