Bug 583083 - Use the '//# sourceURL=display.js' directive's filename in Error.prototype.stack; r=shu
authorNick Fitzgerald <fitzgen@gmail.com>
Wed, 15 Oct 2014 18:42:00 +0200
changeset 210632 3dbe5e1f6a7d
parent 210631 b845c0769a85
child 210633 c4d577ba087a
push id50505
push usercbook@mozilla.com
push date2014-10-16 07:44 +0000
treeherdermozilla-inbound@9cdce80d5092 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu
bugs583083
milestone36.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 583083 - Use the '//# sourceURL=display.js' directive's filename in Error.prototype.stack; r=shu
js/src/jit-test/tests/basic/display-url-in-stack-trace.js
js/src/jsexn.cpp
js/src/vm/Stack.cpp
js/src/vm/Stack.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/display-url-in-stack-trace.js
@@ -0,0 +1,27 @@
+eval(`
+  function a() {
+    return b();
+  }
+  //# sourceURL=source-a.js
+`);
+
+eval(`
+  function b() {
+    return c();
+  }
+  //# sourceURL=source-b.js
+`);
+
+eval(`
+  function c() {
+    return Error().stack;
+  }
+  //# sourceURL=source-c.js
+`);
+
+let filenames = a().split(/\n/)
+                   .map(f => f.slice(f.indexOf("@") + 1, f.indexOf(":")));
+print(filenames.join("\n"));
+assertEq(filenames[0], "source-c.js");
+assertEq(filenames[1], "source-b.js");
+assertEq(filenames[2], "source-a.js");
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -284,21 +284,27 @@ js::ComputeStackString(JSContext *cx)
             if (atom && !sb.append(atom))
                 return nullptr;
 
             /* Next a @ separating function name from source location. */
             if (!sb.append('@'))
                 return nullptr;
 
             /* Now the filename. */
-            const char *cfilename = i.scriptFilename();
-            if (!cfilename)
-                cfilename = "";
-            if (!sb.append(cfilename, strlen(cfilename)))
-                return nullptr;
+
+            /* First, try the `//# sourceURL=some-display-url.js` directive. */
+            if (const char16_t *display = i.scriptDisplayURL()) {
+                if (!sb.append(display, js_strlen(display)))
+                    return nullptr;
+            }
+            /* Second, try the actual filename. */
+            else if (const char *filename = i.scriptFilename()) {
+                if (!sb.append(filename, strlen(filename)))
+                    return nullptr;
+            }
 
             uint32_t column = 0;
             uint32_t line = i.computeLine(&column);
             // Now the line number
             if (!sb.append(':') || !NumberValueToStringBuffer(cx, NumberValue(line), sb))
                 return nullptr;
 
             // Finally, : followed by the column number (1-based, as in other browsers)
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -952,16 +952,23 @@ FrameIter::scriptFilename() const
         return script()->filename();
       case ASMJS:
         return data_.activations_->asAsmJS()->module().scriptSource()->filename();
     }
 
     MOZ_CRASH("Unexpected state");
 }
 
+const char16_t *
+FrameIter::scriptDisplayURL() const
+{
+    ScriptSource *ss = scriptSource();
+    return ss->hasDisplayURL() ? ss->displayURL() : nullptr;
+}
+
 unsigned
 FrameIter::computeLine(uint32_t *column) const
 {
     switch (data_.state_) {
       case DONE:
         break;
       case INTERP:
       case JIT:
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1639,22 +1639,19 @@ class FrameIter
 
     bool isFunctionFrame() const;
     bool isGlobalFrame() const;
     bool isEvalFrame() const;
     bool isNonEvalFunctionFrame() const;
     bool isGeneratorFrame() const;
     bool hasArgs() const { return isNonEvalFunctionFrame(); }
 
-    /*
-     * Get an abstract frame pointer dispatching to either an interpreter,
-     * baseline, or rematerialized optimized frame.
-     */
     ScriptSource *scriptSource() const;
     const char *scriptFilename() const;
+    const char16_t *scriptDisplayURL() const;
     unsigned computeLine(uint32_t *column = nullptr) const;
     JSAtom *functionDisplayAtom() const;
     bool mutedErrors() const;
 
     bool hasScript() const { return !isAsmJS(); }
 
     // -----------------------------------------------------------
     // The following functions can only be called when hasScript()