Bug 583083 - Use the '//# sourceURL=display.js' directive's filename in Error.prototype.stack; r=shu
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()