Bug 976536 - Fix JSFunction::existingScript returning NULL in some cases. r=till
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 19 Apr 2014 13:45:59 +0200
changeset 197813 fd7c870fa960e558890bf4a34e8c71f1f0a93fb0
parent 197812 db431ea44a1a8846230aedf0d2d19d47e7eda46f
child 197819 9c542915cc4c075b2e7e02d249c4b2e48c1c7413
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs976536
milestone31.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 976536 - Fix JSFunction::existingScript returning NULL in some cases. r=till
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
@@ -1334,36 +1334,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);
 
     RootedScript topCaller(cx);
     jsbytecode *topCallerPC = nullptr;
 
     while (true) {
         MOZ_ASSERT(snapIter.instruction()->isResumePoint());
 
@@ -1395,17 +1395,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();
 
         // Save top caller info for adjusting SPS frames later.
         if (!topCaller) {
             JS_ASSERT(frameNo == 0);
             topCaller = caller;
             topCallerPC = callerPC;
         }
 
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -1647,17 +1647,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();
         MOZ_ASSERT(script_->hasBaselineScript());
 
         pc_ = script_->offsetToPC(si_.pcOffset());
     }
 
     // The first time we do not know the number of frames, we only settle on the
     // last frame, and update the number of frames based on the number of
     // iteration that we have done.
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -263,40 +263,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);
         }