summaryrefslogtreecommitdiffstats
path: root/dom/bindings
diff options
context:
space:
mode:
authorGaming4JC <g4jc@hyperbola.info>2019-06-16 09:48:07 -0400
committerGaming4JC <g4jc@hyperbola.info>2019-07-18 22:38:33 -0400
commit4a82fdad87107d369df20da0a4a0987b1bd821fd (patch)
tree5cb6304fa72e89cd2a0394fed77dfed33e51d8f4 /dom/bindings
parentd7fbf2a9df8904d495c4c86e6f575d44185eae1b (diff)
downloadUXP-4a82fdad87107d369df20da0a4a0987b1bd821fd.tar
UXP-4a82fdad87107d369df20da0a4a0987b1bd821fd.tar.gz
UXP-4a82fdad87107d369df20da0a4a0987b1bd821fd.tar.lz
UXP-4a82fdad87107d369df20da0a4a0987b1bd821fd.tar.xz
UXP-4a82fdad87107d369df20da0a4a0987b1bd821fd.zip
1332245 - Move nsScriptError from js/xpconnect to dom/bindings.
Diffstat (limited to 'dom/bindings')
-rw-r--r--dom/bindings/moz.build8
-rw-r--r--dom/bindings/nsIScriptError.idl122
-rw-r--r--dom/bindings/nsScriptError.cpp345
-rw-r--r--dom/bindings/nsScriptError.h86
-rw-r--r--dom/bindings/nsScriptErrorWithStack.cpp120
5 files changed, 681 insertions, 0 deletions
diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build
index 043b3c494..ed8a4d37e 100644
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -6,6 +6,12 @@
TEST_DIRS += ['test']
+XPIDL_SOURCES += [
+ 'nsIScriptError.idl'
+]
+
+XPIDL_MODULE = 'dom_bindings'
+
EXPORTS.ipc += [
'ErrorIPCUtils.h',
]
@@ -91,6 +97,8 @@ UNIFIED_SOURCES += [
'DOMJSProxyHandler.cpp',
'Exceptions.cpp',
'IterableIterator.cpp',
+ 'nsScriptError.cpp',
+ 'nsScriptErrorWithStack.cpp',
'SimpleGlobalObject.cpp',
'ToJSValue.cpp',
'WebIDLGlobalNameHash.cpp',
diff --git a/dom/bindings/nsIScriptError.idl b/dom/bindings/nsIScriptError.idl
new file mode 100644
index 000000000..468ca682f
--- /dev/null
+++ b/dom/bindings/nsIScriptError.idl
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * nsIConsoleMessage subclass for representing JavaScript errors and warnings.
+ */
+
+
+#include "nsISupports.idl"
+#include "nsIConsoleMessage.idl"
+
+%{C++
+#include "nsStringGlue.h" // for nsDependentCString
+%}
+
+[scriptable, uuid(361be358-76f0-47aa-b37b-6ad833599e8d)]
+interface nsIScriptError : nsIConsoleMessage
+{
+ /** pseudo-flag for default case */
+ const unsigned long errorFlag = 0x0;
+
+ /** message is warning */
+ const unsigned long warningFlag = 0x1;
+
+ /** exception was thrown for this case - exception-aware hosts can ignore */
+ const unsigned long exceptionFlag = 0x2;
+
+ // XXX check how strict is implemented these days.
+ /** error or warning is due to strict option */
+ const unsigned long strictFlag = 0x4;
+
+ /** just a log message */
+ const unsigned long infoFlag = 0x8;
+
+ /**
+ * The error message without any context/line number information.
+ *
+ * @note nsIConsoleMessage.message will return the error formatted
+ * with file/line information.
+ */
+ readonly attribute AString errorMessage;
+
+ readonly attribute AString sourceName;
+ readonly attribute AString sourceLine;
+ readonly attribute uint32_t lineNumber;
+ readonly attribute uint32_t columnNumber;
+ readonly attribute uint32_t flags;
+
+ /**
+ * Categories I know about -
+ * XUL javascript
+ * content javascript (both of these from nsDocShell, currently)
+ * system javascript (errors in JS components and other system JS)
+ */
+ readonly attribute string category;
+
+ /* Get the window id this was initialized with. Zero will be
+ returned if init() was used instead of initWithWindowID(). */
+ readonly attribute unsigned long long outerWindowID;
+
+ /* Get the inner window id this was initialized with. Zero will be
+ returned if init() was used instead of initWithWindowID(). */
+ readonly attribute unsigned long long innerWindowID;
+
+ readonly attribute boolean isFromPrivateWindow;
+
+ attribute jsval stack;
+
+ /**
+ * The name of a template string, as found in js.msg, associated with the
+ * error message.
+ */
+ attribute AString errorMessageName;
+
+
+ void init(in AString message,
+ in AString sourceName,
+ in AString sourceLine,
+ in uint32_t lineNumber,
+ in uint32_t columnNumber,
+ in uint32_t flags,
+ in string category);
+
+ /* This should be called instead of nsIScriptError.init to
+ initialize with a window id. The window id should be for the
+ inner window associated with this error. */
+ void initWithWindowID(in AString message,
+ in AString sourceName,
+ in AString sourceLine,
+ in uint32_t lineNumber,
+ in uint32_t columnNumber,
+ in uint32_t flags,
+ in ACString category,
+ in unsigned long long innerWindowID);
+%{C++
+ // This overload allows passing a literal string for category.
+ template<uint32_t N>
+ nsresult InitWithWindowID(const nsAString& message,
+ const nsAString& sourceName,
+ const nsAString& sourceLine,
+ uint32_t lineNumber,
+ uint32_t columnNumber,
+ uint32_t flags,
+ const char (&c)[N],
+ uint64_t aInnerWindowID)
+ {
+ nsDependentCString category(c, N - 1);
+ return InitWithWindowID(message, sourceName, sourceLine, lineNumber,
+ columnNumber, flags, category, aInnerWindowID);
+ }
+%}
+
+};
+
+%{ C++
+#define NS_SCRIPTERROR_CID \
+{ 0x1950539a, 0x90f0, 0x4d22, { 0xb5, 0xaf, 0x71, 0x32, 0x9c, 0x68, 0xfa, 0x35 }}
+
+#define NS_SCRIPTERROR_CONTRACTID "@mozilla.org/scripterror;1"
+%}
diff --git a/dom/bindings/nsScriptError.cpp b/dom/bindings/nsScriptError.cpp
new file mode 100644
index 000000000..686b0f7fc
--- /dev/null
+++ b/dom/bindings/nsScriptError.cpp
@@ -0,0 +1,345 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * nsIScriptError implementation.
+ */
+
+#include "nsScriptError.h"
+#include "jsprf.h"
+#include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
+#include "nsGlobalWindow.h"
+#include "nsNetUtil.h"
+#include "nsPIDOMWindow.h"
+#include "nsILoadContext.h"
+#include "nsIDocShell.h"
+#include "nsIScriptError.h"
+#include "nsISensitiveInfoHiddenURI.h"
+
+static_assert(nsIScriptError::errorFlag == JSREPORT_ERROR &&
+ nsIScriptError::warningFlag == JSREPORT_WARNING &&
+ nsIScriptError::exceptionFlag == JSREPORT_EXCEPTION &&
+ nsIScriptError::strictFlag == JSREPORT_STRICT &&
+ nsIScriptError::infoFlag == JSREPORT_USER_1,
+ "flags should be consistent");
+
+nsScriptErrorBase::nsScriptErrorBase()
+ : mMessage(),
+ mMessageName(),
+ mSourceName(),
+ mLineNumber(0),
+ mSourceLine(),
+ mColumnNumber(0),
+ mFlags(0),
+ mCategory(),
+ mOuterWindowID(0),
+ mInnerWindowID(0),
+ mTimeStamp(0),
+ mInitializedOnMainThread(false),
+ mIsFromPrivateWindow(false)
+{
+}
+
+nsScriptErrorBase::~nsScriptErrorBase() {}
+
+void
+nsScriptErrorBase::InitializeOnMainThread()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!mInitializedOnMainThread);
+
+ if (mInnerWindowID) {
+ nsGlobalWindow* window =
+ nsGlobalWindow::GetInnerWindowWithId(mInnerWindowID);
+ if (window) {
+ nsPIDOMWindowOuter* outer = window->GetOuterWindow();
+ if (outer)
+ mOuterWindowID = outer->WindowID();
+
+ nsIDocShell* docShell = window->GetDocShell();
+ nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
+
+ if (loadContext) {
+ // Never mark exceptions from chrome windows as having come from
+ // private windows, since we always want them to be reported.
+ nsIPrincipal* winPrincipal = window->GetPrincipal();
+ mIsFromPrivateWindow = loadContext->UsePrivateBrowsing() &&
+ !nsContentUtils::IsSystemPrincipal(winPrincipal);
+ }
+ }
+ }
+
+ mInitializedOnMainThread = true;
+}
+
+// nsIConsoleMessage methods
+NS_IMETHODIMP
+nsScriptErrorBase::GetMessageMoz(char16_t** result) {
+ nsresult rv;
+
+ nsAutoCString message;
+ rv = ToString(message);
+ if (NS_FAILED(rv))
+ return rv;
+
+ *result = UTF8ToNewUnicode(message);
+ if (!*result)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetLogLevel(uint32_t* aLogLevel)
+{
+ if (mFlags & (uint32_t)nsIScriptError::infoFlag) {
+ *aLogLevel = nsIConsoleMessage::info;
+ } else if (mFlags & (uint32_t)nsIScriptError::warningFlag) {
+ *aLogLevel = nsIConsoleMessage::warn;
+ } else {
+ *aLogLevel = nsIConsoleMessage::error;
+ }
+ return NS_OK;
+}
+
+// nsIScriptError methods
+NS_IMETHODIMP
+nsScriptErrorBase::GetErrorMessage(nsAString& aResult) {
+ aResult.Assign(mMessage);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetSourceName(nsAString& aResult) {
+ aResult.Assign(mSourceName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetSourceLine(nsAString& aResult) {
+ aResult.Assign(mSourceLine);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetLineNumber(uint32_t* result) {
+ *result = mLineNumber;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetColumnNumber(uint32_t* result) {
+ *result = mColumnNumber;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetFlags(uint32_t* result) {
+ *result = mFlags;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetCategory(char** result) {
+ *result = ToNewCString(mCategory);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetStack(JS::MutableHandleValue aStack) {
+ aStack.setUndefined();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::SetStack(JS::HandleValue aStack) {
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetErrorMessageName(nsAString& aErrorMessageName) {
+ aErrorMessageName = mMessageName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::SetErrorMessageName(const nsAString& aErrorMessageName) {
+ mMessageName = aErrorMessageName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::Init(const nsAString& message,
+ const nsAString& sourceName,
+ const nsAString& sourceLine,
+ uint32_t lineNumber,
+ uint32_t columnNumber,
+ uint32_t flags,
+ const char* category)
+{
+ return InitWithWindowID(message, sourceName, sourceLine, lineNumber,
+ columnNumber, flags,
+ category ? nsDependentCString(category)
+ : EmptyCString(),
+ 0);
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::InitWithWindowID(const nsAString& message,
+ const nsAString& sourceName,
+ const nsAString& sourceLine,
+ uint32_t lineNumber,
+ uint32_t columnNumber,
+ uint32_t flags,
+ const nsACString& category,
+ uint64_t aInnerWindowID)
+{
+ mMessage.Assign(message);
+
+ if (!sourceName.IsEmpty()) {
+ mSourceName.Assign(sourceName);
+
+ nsCOMPtr<nsIURI> uri;
+ nsAutoCString pass;
+ if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), sourceName)) &&
+ NS_SUCCEEDED(uri->GetPassword(pass)) &&
+ !pass.IsEmpty()) {
+ nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri =
+ do_QueryInterface(uri);
+
+ nsAutoCString loc;
+ if (safeUri &&
+ NS_SUCCEEDED(safeUri->GetSensitiveInfoHiddenSpec(loc))) {
+ mSourceName.Assign(NS_ConvertUTF8toUTF16(loc));
+ }
+ }
+ }
+
+ mLineNumber = lineNumber;
+ mSourceLine.Assign(sourceLine);
+ mColumnNumber = columnNumber;
+ mFlags = flags;
+ mCategory = category;
+ mTimeStamp = JS_Now() / 1000;
+ mInnerWindowID = aInnerWindowID;
+
+ if (aInnerWindowID && NS_IsMainThread()) {
+ InitializeOnMainThread();
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult)
+{
+ static const char format0[] =
+ "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]";
+ static const char format1[] =
+ "[%s: \"%s\" {file: \"%s\" line: %d}]";
+ static const char format2[] =
+ "[%s: \"%s\"]";
+
+ static const char error[] = "JavaScript Error";
+ static const char warning[] = "JavaScript Warning";
+
+ const char* severity = !(mFlags & JSREPORT_WARNING) ? error : warning;
+
+ char* temp;
+ char* tempMessage = nullptr;
+ char* tempSourceName = nullptr;
+ char* tempSourceLine = nullptr;
+
+ if (!mMessage.IsEmpty())
+ tempMessage = ToNewUTF8String(mMessage);
+ if (!mSourceName.IsEmpty())
+ // Use at most 512 characters from mSourceName.
+ tempSourceName = ToNewUTF8String(StringHead(mSourceName, 512));
+ if (!mSourceLine.IsEmpty())
+ // Use at most 512 characters from mSourceLine.
+ tempSourceLine = ToNewUTF8String(StringHead(mSourceLine, 512));
+
+ if (nullptr != tempSourceName && nullptr != tempSourceLine)
+ temp = JS_smprintf(format0,
+ severity,
+ tempMessage,
+ tempSourceName,
+ mLineNumber,
+ mColumnNumber,
+ tempSourceLine);
+ else if (!mSourceName.IsEmpty())
+ temp = JS_smprintf(format1,
+ severity,
+ tempMessage,
+ tempSourceName,
+ mLineNumber);
+ else
+ temp = JS_smprintf(format2,
+ severity,
+ tempMessage);
+
+ if (nullptr != tempMessage)
+ free(tempMessage);
+ if (nullptr != tempSourceName)
+ free(tempSourceName);
+ if (nullptr != tempSourceLine)
+ free(tempSourceLine);
+
+ if (!temp)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ aResult.Assign(temp);
+ JS_smprintf_free(temp);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetOuterWindowID(uint64_t* aOuterWindowID)
+{
+ NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread,
+ "This can't be safely determined off the main thread, "
+ "returning an inaccurate value!");
+
+ if (!mInitializedOnMainThread && NS_IsMainThread()) {
+ InitializeOnMainThread();
+ }
+
+ *aOuterWindowID = mOuterWindowID;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetInnerWindowID(uint64_t* aInnerWindowID)
+{
+ *aInnerWindowID = mInnerWindowID;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetTimeStamp(int64_t* aTimeStamp)
+{
+ *aTimeStamp = mTimeStamp;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow)
+{
+ NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread,
+ "This can't be safely determined off the main thread, "
+ "returning an inaccurate value!");
+
+ if (!mInitializedOnMainThread && NS_IsMainThread()) {
+ InitializeOnMainThread();
+ }
+
+ *aIsFromPrivateWindow = mIsFromPrivateWindow;
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError)
diff --git a/dom/bindings/nsScriptError.h b/dom/bindings/nsScriptError.h
new file mode 100644
index 000000000..da59e3082
--- /dev/null
+++ b/dom/bindings/nsScriptError.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_nsScriptError_h
+#define mozilla_dom_nsScriptError_h
+
+#include "mozilla/Atomics.h"
+
+#include <stdint.h>
+
+#include "jsapi.h"
+#include "js/RootingAPI.h"
+
+#include "nsIScriptError.h"
+#include "nsString.h"
+
+// Definition of nsScriptError..
+class nsScriptErrorBase : public nsIScriptError {
+public:
+ nsScriptErrorBase();
+
+ NS_DECL_NSICONSOLEMESSAGE
+ NS_DECL_NSISCRIPTERROR
+
+protected:
+ virtual ~nsScriptErrorBase();
+
+ void
+ InitializeOnMainThread();
+
+ nsString mMessage;
+ nsString mMessageName;
+ nsString mSourceName;
+ uint32_t mLineNumber;
+ nsString mSourceLine;
+ uint32_t mColumnNumber;
+ uint32_t mFlags;
+ nsCString mCategory;
+ // mOuterWindowID is set on the main thread from InitializeOnMainThread().
+ uint64_t mOuterWindowID;
+ uint64_t mInnerWindowID;
+ int64_t mTimeStamp;
+ // mInitializedOnMainThread and mIsFromPrivateWindow are set on the main
+ // thread from InitializeOnMainThread().
+ mozilla::Atomic<bool> mInitializedOnMainThread;
+ bool mIsFromPrivateWindow;
+};
+
+class nsScriptError final : public nsScriptErrorBase {
+public:
+ nsScriptError() {}
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+private:
+ virtual ~nsScriptError() {}
+};
+
+class nsScriptErrorWithStack : public nsScriptErrorBase {
+public:
+ explicit nsScriptErrorWithStack(JS::HandleObject);
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsScriptErrorWithStack)
+
+ NS_IMETHOD Init(const nsAString& message,
+ const nsAString& sourceName,
+ const nsAString& sourceLine,
+ uint32_t lineNumber,
+ uint32_t columnNumber,
+ uint32_t flags,
+ const char* category) override;
+
+ NS_IMETHOD GetStack(JS::MutableHandleValue) override;
+ NS_IMETHOD ToString(nsACString& aResult) override;
+
+private:
+ virtual ~nsScriptErrorWithStack();
+ // Complete stackframe where the error happened.
+ // Must be SavedFrame object.
+ JS::Heap<JSObject*> mStack;
+};
+
+#endif /* mozilla_dom_nsScriptError_h */
diff --git a/dom/bindings/nsScriptErrorWithStack.cpp b/dom/bindings/nsScriptErrorWithStack.cpp
new file mode 100644
index 000000000..74c00999f
--- /dev/null
+++ b/dom/bindings/nsScriptErrorWithStack.cpp
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * nsScriptErrorWithStack implementation.
+ * a main-thread-only, cycle-collected subclass of nsScriptErrorBase
+ * that can store a SavedFrame stack trace object.
+ */
+
+#include "nsScriptError.h"
+#include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/dom/ScriptSettings.h"
+#include "nsGlobalWindow.h"
+#include "nsCycleCollectionParticipant.h"
+
+using namespace mozilla::dom;
+
+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)
+ tmp->mStack = nullptr;
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsScriptErrorWithStack)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsScriptErrorWithStack)
+ NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStack)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsScriptErrorWithStack)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsScriptErrorWithStack)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScriptErrorWithStack)
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+ NS_INTERFACE_MAP_ENTRY(nsIConsoleMessage)
+ NS_INTERFACE_MAP_ENTRY(nsIScriptError)
+NS_INTERFACE_MAP_END
+
+nsScriptErrorWithStack::nsScriptErrorWithStack(JS::HandleObject aStack)
+ : mStack(aStack)
+{
+ MOZ_ASSERT(NS_IsMainThread(), "You can't use this class on workers.");
+ mozilla::HoldJSObjects(this);
+}
+
+nsScriptErrorWithStack::~nsScriptErrorWithStack() {
+ mozilla::DropJSObjects(this);
+}
+
+NS_IMETHODIMP
+nsScriptErrorWithStack::Init(const nsAString& message,
+ const nsAString& sourceName,
+ const nsAString& sourceLine,
+ uint32_t lineNumber,
+ uint32_t columnNumber,
+ uint32_t flags,
+ const char* category)
+{
+ MOZ_CRASH("nsScriptErrorWithStack requires to be initialized with a document, by using InitWithWindowID");
+}
+
+NS_IMETHODIMP
+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;
+}