summaryrefslogtreecommitdiffstats
path: root/dom/bindings
diff options
context:
space:
mode:
Diffstat (limited to 'dom/bindings')
-rw-r--r--dom/bindings/BindingUtils.cpp8
-rw-r--r--dom/bindings/BindingUtils.h3
-rw-r--r--dom/bindings/Codegen.py15
-rw-r--r--dom/bindings/moz.build8
-rw-r--r--dom/bindings/nsIScriptError.idl135
-rw-r--r--dom/bindings/nsScriptError.cpp438
-rw-r--r--dom/bindings/nsScriptError.h109
-rw-r--r--dom/bindings/nsScriptErrorWithStack.cpp120
8 files changed, 815 insertions, 21 deletions
diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
index 8d2bdaac6..a26fc4422 100644
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1184,14 +1184,6 @@ GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
}
bool
-UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp)
-{
- JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
- args.rval().set(args.thisv());
- return true;
-}
-
-bool
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
{
return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h
index a3ec70f47..5cab835b3 100644
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2045,9 +2045,6 @@ GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
}
bool
-UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp);
-
-bool
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
bool
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index 74acb5918..d7d700a96 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2390,11 +2390,10 @@ class MethodDefiner(PropertyDefiner):
# Synthesize our valueOf method
self.regular.append({
"name": 'valueOf',
- "nativeName": "UnforgeableValueOf",
+ "selfHostedName": "Object_valueOf",
"methodInfo": False,
"length": 0,
- "flags": "JSPROP_ENUMERATE", # readonly/permanent added
- # automatically.
+ "flags": "0", # readonly/permanent added automatically.
"condition": MemberCondition()
})
@@ -3456,19 +3455,15 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties, failureCode,
"nsContentUtils::ThreadsafeIsCallerChrome()"))
if descriptor.interface.getExtendedAttribute("Unforgeable"):
- # We do our undefined toJSON and toPrimitive here, not as a regular
- # property because we don't have a concept of value props anywhere in
- # IDL.
+ # We do our undefined toPrimitive here, not as a regular property
+ # because we don't have a concept of value props anywhere in IDL.
unforgeables.append(CGGeneric(fill(
"""
JS::RootedId toPrimitive(aCx,
SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::toPrimitive)));
if (!JS_DefinePropertyById(aCx, ${holderName}, toPrimitive,
JS::UndefinedHandleValue,
- JSPROP_READONLY | JSPROP_PERMANENT) ||
- !JS_DefineProperty(aCx, ${holderName}, "toJSON",
- JS::UndefinedHandleValue,
- JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
+ JSPROP_READONLY | JSPROP_PERMANENT)) {
$*{failureCode}
}
""",
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..8436361a8
--- /dev/null
+++ b/dom/bindings/nsIScriptError.idl
@@ -0,0 +1,135 @@
+/* -*- 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 "nsIArray.idl"
+#include "nsIConsoleMessage.idl"
+
+%{C++
+#include "nsStringGlue.h" // for nsDependentCString
+%}
+
+[scriptable, uuid(e8933fc9-c302-4e12-a55b-4f88611d9c6c)]
+interface nsIScriptErrorNote : nsISupports
+{
+ readonly attribute AString errorMessage;
+ readonly attribute AString sourceName;
+ readonly attribute uint32_t lineNumber;
+ readonly attribute uint32_t columnNumber;
+
+ AUTF8String toString();
+};
+
+[scriptable, uuid(63eb4d3e-7d99-4150-b4f3-11314f9d82a9)]
+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;
+
+ readonly attribute nsIArray notes;
+
+ 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..9248d1a31
--- /dev/null
+++ b/dom/bindings/nsScriptError.cpp
@@ -0,0 +1,438 @@
+/* -*- 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 "nsIMutableArray.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::AddNote(nsIScriptErrorNote* note)
+{
+ mNotes.AppendObject(note);
+}
+
+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);
+}
+
+static void
+AssignSourceNameHelper(nsString& aSourceNameDest, const nsAString& aSourceNameSrc)
+{
+ if (aSourceNameSrc.IsEmpty())
+ return;
+
+ aSourceNameDest.Assign(aSourceNameSrc);
+
+ nsCOMPtr<nsIURI> uri;
+ nsAutoCString pass;
+ if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), aSourceNameSrc)) &&
+ NS_SUCCEEDED(uri->GetPassword(pass)) &&
+ !pass.IsEmpty())
+ {
+ nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri = do_QueryInterface(uri);
+
+ nsAutoCString loc;
+ if (safeUri && NS_SUCCEEDED(safeUri->GetSensitiveInfoHiddenSpec(loc)))
+ aSourceNameDest.Assign(NS_ConvertUTF8toUTF16(loc));
+ }
+}
+
+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);
+ AssignSourceNameHelper(mSourceName, sourceName);
+ 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;
+}
+
+static nsresult
+ToStringHelper(const char* aSeverity, const nsString& aMessage,
+ const nsString& aSourceName, const nsString* aSourceLine,
+ uint32_t aLineNumber, uint32_t aColumnNumber,
+ 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\"]";
+
+ char* temp;
+ char* tempMessage = nullptr;
+ char* tempSourceName = nullptr;
+ char* tempSourceLine = nullptr;
+
+ if (!aMessage.IsEmpty())
+ tempMessage = ToNewUTF8String(aMessage);
+ if (!aSourceName.IsEmpty())
+ // Use at most 512 characters from mSourceName.
+ tempSourceName = ToNewUTF8String(StringHead(aSourceName, 512));
+ if (aSourceLine && !aSourceLine->IsEmpty())
+ // Use at most 512 characters from mSourceLine.
+ tempSourceLine = ToNewUTF8String(StringHead(*aSourceLine, 512));
+
+ if (nullptr != tempSourceName && nullptr != tempSourceLine) {
+ temp = JS_smprintf(format0,
+ aSeverity,
+ tempMessage,
+ tempSourceName,
+ aLineNumber,
+ aColumnNumber,
+ tempSourceLine);
+ } else if (!aSourceName.IsEmpty()) {
+ temp = JS_smprintf(format1,
+ aSeverity,
+ tempMessage,
+ tempSourceName,
+ aLineNumber);
+ } else {
+ temp = JS_smprintf(format2,
+ aSeverity,
+ 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::ToString(nsACString& /*UTF8*/ aResult)
+{
+ static const char error[] = "JavaScript Error";
+ static const char warning[] = "JavaScript Warning";
+
+ const char* severity = !(mFlags & JSREPORT_WARNING) ? error : warning;
+
+ return ToStringHelper(severity, mMessage, mSourceName, &mSourceLine,
+ mLineNumber, mColumnNumber, aResult);
+}
+
+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_IMETHODIMP
+nsScriptErrorBase::GetNotes(nsIArray** aNotes)
+{
+ nsresult rv = NS_OK;
+ nsCOMPtr<nsIMutableArray> array =
+ do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t len = mNotes.Length();
+ for (uint32_t i = 0; i < len; i++)
+ array->AppendElement(mNotes[i], false);
+ array.forget(aNotes);
+
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError)
+
+nsScriptErrorNote::nsScriptErrorNote()
+ : mMessage(),
+ mSourceName(),
+ mLineNumber(0),
+ mColumnNumber(0)
+{
+}
+
+nsScriptErrorNote::~nsScriptErrorNote() {}
+
+void
+nsScriptErrorNote::Init(const nsAString& message,
+ const nsAString& sourceName,
+ uint32_t lineNumber,
+ uint32_t columnNumber)
+{
+ mMessage.Assign(message);
+ AssignSourceNameHelper(mSourceName, sourceName);
+ mLineNumber = lineNumber;
+ mColumnNumber = columnNumber;
+}
+
+// nsIScriptErrorNote methods
+NS_IMETHODIMP
+nsScriptErrorNote::GetErrorMessage(nsAString& aResult) {
+ aResult.Assign(mMessage);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorNote::GetSourceName(nsAString& aResult) {
+ aResult.Assign(mSourceName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorNote::GetLineNumber(uint32_t* result) {
+ *result = mLineNumber;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorNote::GetColumnNumber(uint32_t* result) {
+ *result = mColumnNumber;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorNote::ToString(nsACString& /*UTF8*/ aResult)
+{
+ return ToStringHelper("JavaScript Note", mMessage, mSourceName, nullptr,
+ mLineNumber, mColumnNumber, aResult);
+}
+
+NS_IMPL_ISUPPORTS(nsScriptErrorNote, nsIScriptErrorNote)
diff --git a/dom/bindings/nsScriptError.h b/dom/bindings/nsScriptError.h
new file mode 100644
index 000000000..b8049d0a0
--- /dev/null
+++ b/dom/bindings/nsScriptError.h
@@ -0,0 +1,109 @@
+/* -*- 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"
+
+class nsScriptErrorNote final : public nsIScriptErrorNote {
+ public:
+ nsScriptErrorNote();
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSISCRIPTERRORNOTE
+
+ void Init(const nsAString& message, const nsAString& sourceName,
+ uint32_t lineNumber, uint32_t columnNumber);
+
+ private:
+ virtual ~nsScriptErrorNote();
+
+ nsString mMessage;
+ nsString mSourceName;
+ nsString mSourceLine;
+ uint32_t mLineNumber;
+ uint32_t mColumnNumber;
+};
+
+// Definition of nsScriptError..
+class nsScriptErrorBase : public nsIScriptError {
+public:
+ nsScriptErrorBase();
+
+ NS_DECL_NSICONSOLEMESSAGE
+ NS_DECL_NSISCRIPTERROR
+
+ void AddNote(nsIScriptErrorNote* note);
+
+protected:
+ virtual ~nsScriptErrorBase();
+
+ void
+ InitializeOnMainThread();
+
+ nsCOMArray<nsIScriptErrorNote> mNotes;
+ 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;
+}