diff --git a/js/xpconnect/src/nsScriptErrorWithStack.cpp b/js/xpconnect/src/nsScriptErrorWithStack.cpp index a5717bbc8b95..670a5275aab4 100644 --- a/js/xpconnect/src/nsScriptErrorWithStack.cpp +++ b/js/xpconnect/src/nsScriptErrorWithStack.cpp @@ -16,6 +16,28 @@ #include "nsGlobalWindow.h" #include "nsCycleCollectionParticipant.h" + +namespace { + +static nsCString +FormatStackString(JSContext* cx, HandleObject aStack) { + JS::RootedString formattedStack(cx); + + if (!JS::BuildStackString(cx, aStack, &formattedStack)) { + return nsCString(); + } + + nsAutoJSString stackJSString; + if (!stackJSString.init(cx, formattedStack)) { + return nsCString(); + } + + return NS_ConvertUTF16toUTF8(stackJSString.get()); +} + +} + + NS_IMPL_CYCLE_COLLECTION_CLASS(nsScriptErrorWithStack) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsScriptErrorWithStack) @@ -67,3 +89,31 @@ nsScriptErrorWithStack::GetStack(JS::MutableHandleValue aStack) { aStack.setObjectOrNull(mStack); return NS_OK; } + +NS_IMETHODIMP +nsScriptErrorWithStack::ToString(nsACString& /*UTF8*/ aResult) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsCString message; + nsresult rv = nsScriptErrorBase::ToString(message); + NS_ENSURE_SUCCESS(rv, rv); + + if (!mStack) { + aResult.Assign(message); + return NS_OK; + } + + AutoJSAPI jsapi; + if (!jsapi.Init(mStack)) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + RootedObject stack(cx, mStack); + nsCString stackString = FormatStackString(cx, stack); + nsCString combined = message + NS_LITERAL_CSTRING("\n") + stackString; + aResult.Assign(combined); + + return NS_OK; +} diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 5febaf8c139e..0b521c219779 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -3029,6 +3029,7 @@ public: const char* category) override; NS_IMETHOD GetStack(JS::MutableHandleValue) override; + NS_IMETHOD ToString(nsACString& aResult) override; private: virtual ~nsScriptErrorWithStack();