Backed out 3 changesets (bug 1409852) for build bustage and failing test_js_dev_error_interceptor.js. r=backout on a CLOSED TREE

Backed out changeset 06368bf1a32c (bug 1409852)
Backed out changeset 46fce9a2622d (bug 1409852)
Backed out changeset 649d7bdf80ad (bug 1409852)
This commit is contained in:
Csoregi Natalia 2017-12-21 15:31:27 +02:00
parent 41dde8eaf3
commit 9743e10556
16 changed files with 7 additions and 587 deletions

View File

@ -11,7 +11,6 @@
#include "mozilla/Base64.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/IdleDeadline.h"
#include "mozilla/dom/UnionTypes.h"
@ -434,32 +433,5 @@ ChromeUtils::IsOriginAttributesEqual(const dom::OriginAttributesDictionary& aA,
aA.mPrivateBrowsingId == aB.mPrivateBrowsingId;
}
#ifdef NIGHTLY_BUILD
/* static */ void
ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
JS::MutableHandleValue aRetval,
ErrorResult& aRv)
{
aRetval.setUndefined();
auto runtime = CycleCollectedJSRuntime::Get();
MOZ_ASSERT(runtime);
auto cx = aGlobal.Context();
if (!runtime->GetRecentDevError(cx, aRetval)) {
aRv.NoteJSContextException(cx);
return;
}
}
/* static */ void
ChromeUtils::ClearRecentJSDevError(GlobalObject&)
{
auto runtime = CycleCollectedJSRuntime::Get();
MOZ_ASSERT(runtime);
runtime->ClearRecentDevError();
}
#endif // NIGHTLY_BUILD
} // namespace dom
} // namespace mozilla

View File

@ -148,12 +148,6 @@ public:
IdleRequestCallback& callback,
const IdleRequestOptions& options,
ErrorResult& aRv);
static void GetRecentJSDevError(GlobalObject& aGlobal,
JS::MutableHandleValue aRetval,
ErrorResult& aRv);
static void ClearRecentJSDevError(GlobalObject& aGlobal);
};
} // namespace dom

View File

@ -10992,7 +10992,7 @@ template <prototypes::ID PrototypeID, class NativeType, typename T>
static Result<Ok, nsresult>
ExtractExceptionValues(JSContext* aCx,
JS::HandleObject aObj,
nsAString& aSourceSpecOut,
nsACString& aSourceSpecOut,
uint32_t* aLineOut,
uint32_t* aColumnOut,
nsString& aMessageOut)
@ -11000,8 +11000,10 @@ ExtractExceptionValues(JSContext* aCx,
RefPtr<T> exn;
MOZ_TRY((UnwrapObject<PrototypeID, NativeType>(aObj, exn)));
exn->GetFilename(aCx, aSourceSpecOut);
if (!aSourceSpecOut.IsEmpty()) {
nsAutoString filename;
exn->GetFilename(aCx, filename);
if (!filename.IsEmpty()) {
CopyUTF16toUTF8(filename, aSourceSpecOut);
*aLineOut = exn->LineNumber(aCx);
*aColumnOut = exn->ColumnNumber();
}
@ -11022,19 +11024,6 @@ nsContentUtils::ExtractErrorValues(JSContext* aCx,
uint32_t* aLineOut,
uint32_t* aColumnOut,
nsString& aMessageOut)
{
nsAutoString sourceSpec;
ExtractErrorValues(aCx, aValue, sourceSpec, aLineOut, aColumnOut, aMessageOut);
CopyUTF16toUTF8(sourceSpec, aSourceSpecOut);
}
/* static */ void
nsContentUtils::ExtractErrorValues(JSContext* aCx,
JS::Handle<JS::Value> aValue,
nsAString& aSourceSpecOut,
uint32_t* aLineOut,
uint32_t* aColumnOut,
nsString& aMessageOut)
{
MOZ_ASSERT(aLineOut);
MOZ_ASSERT(aColumnOut);
@ -11056,7 +11045,7 @@ nsContentUtils::ExtractErrorValues(JSContext* aCx,
0); // window ID
if (!report->mFileName.IsEmpty()) {
aSourceSpecOut = report->mFileName;
CopyUTF16toUTF8(report->mFileName, aSourceSpecOut);
*aLineOut = report->mLineNumber;
*aColumnOut = report->mColumn;
}

View File

@ -1134,14 +1134,6 @@ public:
static bool PrefetchPreloadEnabled(nsIDocShell* aDocShell);
static void
ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
nsAString& aSourceSpecOut, uint32_t *aLineOut,
uint32_t *aColumnOut, nsString& aMessageOut);
// Variant on `ExtractErrorValues` with a `nsACString`. This
// method is provided for backwards compatibility. Prefer the
// faster method above for your code.
static void
ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
nsACString& aSourceSpecOut, uint32_t *aLineOut,

View File

@ -1,57 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
"use strict";
function errors() {
return [
// The following two errors MUST NOT be captured.
new Error("This is an error: " + Math.random()),
new RangeError("This is a RangeError: " + Math.random()),
"This is a string: " + Math.random(),
null,
undefined,
Math.random(),
{},
// The following errors MUST be captured.
new TypeError("This is a TypeError: " + Math.random()),
new SyntaxError("This is a SyntaxError: " + Math.random()),
new ReferenceError("This is a ReferenceError: " + Math.random())
]
}
function isDeveloperError(e) {
if (e == null || typeof e != "object") {
return false;
}
return e.constructor == TypeError
|| e.constructor == SyntaxError
|| e.constructor == ReferenceError;
}
function run_test() {
ChromeUtils.clearRecentJSDevError();
Assert.equal(ChromeUtils.recentJSDevError, undefined);
for (let exn of errors()) {
ChromeUtils.clearRecentJSDevError();
try {
throw exn;
} catch (e) {
// Discard error.
}
do_print(`Threw "${exn}", logged "${ChromeUtils.recentJSDevError}`);
if (isDeveloperError(exn)) {
Assert.equal(ChromeUtils.recentJSDevError.message, "" + exn);
} else {
Assert.equal(ChromeUtils.recentJSDevError, undefined);
}
ChromeUtils.clearRecentJSDevError();
Assert.equal(ChromeUtils.recentJSDevError, undefined);
}
};

View File

@ -54,7 +54,4 @@ head = head_xml.js
[test_chromeutils_base64.js]
[test_generate_xpath.js]
head = head_xml.js
[test_js_dev_error_interceptor.js]
# This feature is implemented only in NIGHTLY.
run-if = nightly_build

View File

@ -89,40 +89,6 @@ namespace ChromeUtils {
ArrayBuffer base64URLDecode(ByteString string,
Base64URLDecodeOptions options);
#ifdef NIGHTLY_BUILD
/**
* If the chrome code has thrown a JavaScript Dev Error
* in the current JSRuntime. the first such error, or `undefined`
* otherwise.
*
* A JavaScript Dev Error is an exception thrown by JavaScript
* code that matches both conditions:
* - it was thrown by chrome code;
* - it is either a `ReferenceError`, a `TypeError` or a `SyntaxError`.
*
* Such errors are stored regardless of whether they have been
* caught.
*
* This mechanism is designed to help ensure that the code of
* Firefox is free from Dev Errors, even if they are accidentally
* caught by clients.
*
* The object returned is not an exception. It has fields:
* - DOMString stack
* - DOMString filename
* - DOMString lineNumber
* - DOMString message
*/
[Throws]
readonly attribute any recentJSDevError;
/**
* Reset `recentJSDevError` to `undefined` for the current JSRuntime.
*/
void clearRecentJSDevError();
#endif // NIGHTLY_BUILD
/**
* IF YOU ADD NEW METHODS HERE, MAKE SURE THEY ARE THREAD-SAFE.
*/

View File

@ -363,7 +363,6 @@ GENERATED_WEBIDL_FILES = [
]
PREPROCESSED_WEBIDL_FILES = [
'ChromeUtils.webidl',
'Navigator.webidl',
'Node.webidl',
'Window.webidl',
@ -426,6 +425,7 @@ WEBIDL_FILES = [
'CheckerboardReportService.webidl',
'ChildNode.webidl',
'ChromeNodeList.webidl',
'ChromeUtils.webidl',
'Client.webidl',
'Clients.webidl',
'ClipboardEvent.webidl',

View File

@ -137,13 +137,6 @@ if CONFIG['ENABLE_STREAMS']:
'testReadableStream.cpp',
]
if CONFIG['NIGHTLY_BUILD']:
# The Error interceptor only exists on Nightly.
UNIFIED_SOURCES += [
'testErrorInterceptor.cpp',
]
if CONFIG['JS_BUILD_BINAST'] and CONFIG['JS_STANDALONE']:
# Standalone builds leave the source directory untouched,
# which lets us run tests with the data files intact.

View File

@ -1,143 +0,0 @@
#include "jsapi.h"
#include "jsapi-tests/tests.h"
#include "vm/StringBuffer.h"
// Tests for JS_GetErrorInterceptorCallback and JS_SetErrorInterceptorCallback.
namespace {
const double EXN_VALUE = 3.14;
static JS::PersistentRootedString gLatestMessage;
// An interceptor that stores the error in `gLatestMessage`.
struct SimpleInterceptor: JSErrorInterceptor {
virtual void interceptError(JSContext* cx, const JS::Value& val) override {
js::StringBuffer buffer(cx);
if (!ValueToStringBuffer(cx, val, buffer))
MOZ_CRASH("Could not convert to string buffer");
gLatestMessage = buffer.finishString();
if (!gLatestMessage)
MOZ_CRASH("Could not convert to string");
}
};
bool equalStrings(JSContext* cx, JSString* a, JSString* b) {
int32_t result = 0;
if (!JS_CompareStrings(cx, a, b, &result))
MOZ_CRASH("Could not compare strings");
return result == 0;
}
}
BEGIN_TEST(testErrorInterceptor)
{
// Run the following snippets.
const char* SAMPLES[] = {
"throw new Error('I am an Error')\0",
"throw new TypeError('I am a TypeError')\0",
"throw new ReferenceError('I am a ReferenceError')\0",
"throw new SyntaxError('I am a SyntaxError')\0",
"throw 5\0",
"undefined[0]\0",
"foo[0]\0",
"b[\0",
};
// With the simpleInterceptor, we should end up with the following error:
const char* TO_STRING[] = {
"Error: I am an Error\0",
"TypeError: I am a TypeError\0",
"ReferenceError: I am a ReferenceError\0",
"SyntaxError: I am a SyntaxError\0",
"5\0",
"TypeError: undefined has no properties\0",
"ReferenceError: foo is not defined\0",
"SyntaxError: expected expression, got end of script\0",
};
MOZ_ASSERT(mozilla::ArrayLength(SAMPLES) == mozilla::ArrayLength(TO_STRING));
// Save original callback.
JSErrorInterceptor* original = JS_GetErrorInterceptorCallback(cx->runtime());
gLatestMessage.init(cx);
// Test without callback.
JS_SetErrorInterceptorCallback(cx->runtime(), nullptr);
CHECK(gLatestMessage == nullptr);
for (auto sample: SAMPLES) {
if (execDontReport(sample, __FILE__, __LINE__))
MOZ_CRASH("This sample should have failed");
CHECK(JS_IsExceptionPending(cx));
CHECK(gLatestMessage == nullptr);
JS_ClearPendingException(cx);
}
// Test with callback.
SimpleInterceptor simpleInterceptor;
JS_SetErrorInterceptorCallback(cx->runtime(), &simpleInterceptor);
// Test that we return the right callback.
CHECK_EQUAL(JS_GetErrorInterceptorCallback(cx->runtime()), &simpleInterceptor);
// This shouldn't cause any error.
EXEC("function bar() {}");
CHECK(gLatestMessage == nullptr);
// Test error throwing with a callback that succeeds.
for (size_t i = 0; i < mozilla::ArrayLength(SAMPLES); ++i) {
// This should cause the appropriate error.
if (execDontReport(SAMPLES[i], __FILE__, __LINE__))
MOZ_CRASH("This sample should have failed");
CHECK(JS_IsExceptionPending(cx));
// Check result of callback.
CHECK(gLatestMessage != nullptr);
CHECK(js::StringEqualsAscii(&gLatestMessage->asLinear(), TO_STRING[i]));
// Check the final error.
JS::RootedValue exn(cx);
CHECK(JS_GetPendingException(cx, &exn));
JS_ClearPendingException(cx);
js::StringBuffer buffer(cx);
CHECK(ValueToStringBuffer(cx, exn, buffer));
CHECK(equalStrings(cx, buffer.finishString(), gLatestMessage));
// Cleanup.
gLatestMessage = nullptr;
}
// Test again without callback.
JS_SetErrorInterceptorCallback(cx->runtime(), nullptr);
for (size_t i = 0; i < mozilla::ArrayLength(SAMPLES); ++i) {
if (execDontReport(SAMPLES[i], __FILE__, __LINE__))
MOZ_CRASH("This sample should have failed");
CHECK(JS_IsExceptionPending(cx));
// Check that the callback wasn't called.
CHECK(gLatestMessage == nullptr);
// Check the final error.
JS::RootedValue exn(cx);
CHECK(JS_GetPendingException(cx, &exn));
JS_ClearPendingException(cx);
js::StringBuffer buffer(cx);
CHECK(ValueToStringBuffer(cx, exn, buffer));
CHECK(js::StringEqualsAscii(buffer.finishString(), TO_STRING[i]));
// Cleanup.
gLatestMessage = nullptr;
}
// Cleanup
JS_SetErrorInterceptorCallback(cx->runtime(), original);
gLatestMessage = nullptr;
JS_ClearPendingException(cx);
return true;
}
END_TEST(testErrorInterceptor)

View File

@ -653,40 +653,6 @@ JS_SetCompartmentNameCallback(JSContext* cx, JSCompartmentNameCallback callback)
cx->runtime()->compartmentNameCallback = callback;
}
#if defined(NIGHTLY_BUILD)
JS_PUBLIC_API(void)
JS_SetErrorInterceptorCallback(JSRuntime* rt, JSErrorInterceptor* callback)
{
rt->errorInterception.interceptor = callback;
}
JS_PUBLIC_API(JSErrorInterceptor*)
JS_GetErrorInterceptorCallback(JSRuntime* rt)
{
return rt->errorInterception.interceptor;
}
JS_PUBLIC_API(Maybe<JSExnType>)
JS_GetErrorType(const JS::Value& val)
{
// All errors are objects.
if (!val.isObject())
return mozilla::Nothing();
const JSObject& obj = val.toObject();
// All errors are `ErrorObject`.
if (!obj.is<js::ErrorObject>()) {
// Not one of the primitive errors.
return mozilla::Nothing();
}
const js::ErrorObject& err = obj.as<js::ErrorObject>();
return mozilla::Some(err.type());
}
#endif // defined(NIGHTLY_BUILD)
JS_PUBLIC_API(void)
JS_SetWrapObjectCallbacks(JSContext* cx, const JSWrapObjectCallbacks* callbacks)
{

View File

@ -680,18 +680,6 @@ typedef void
using JSExternalStringSizeofCallback =
size_t (*)(JSString* str, mozilla::MallocSizeOf mallocSizeOf);
/**
* Callback used to intercept JavaScript errors.
*/
struct JSErrorInterceptor {
/**
* This method is called whenever an error has been raised from JS code.
*
* This method MUST be infallible.
*/
virtual void interceptError(JSContext* cx, const JS::Value& error) = 0;
};
/************************************************************************/
static MOZ_ALWAYS_INLINE JS::Value
@ -1339,33 +1327,6 @@ JS_SetWrapObjectCallbacks(JSContext* cx, const JSWrapObjectCallbacks* callbacks)
extern JS_PUBLIC_API(void)
JS_SetExternalStringSizeofCallback(JSContext* cx, JSExternalStringSizeofCallback callback);
#if defined(NIGHTLY_BUILD)
// Set a callback that will be called whenever an error
// is thrown in this runtime. This is designed as a mechanism
// for logging errors. Note that the VM makes no attempt to sanitize
// the contents of the error (so it may contain private data)
// or to sort out among errors (so it may not be the error you
// are interested in or for the component in which you are
// interested).
//
// If the callback sets a new error, this new error
// will replace the original error.
//
// May be `nullptr`.
extern JS_PUBLIC_API(void)
JS_SetErrorInterceptorCallback(JSRuntime*, JSErrorInterceptor* callback);
extern JS_PUBLIC_API(JSErrorInterceptor*)
JS_GetErrorInterceptorCallback(JSRuntime*);
// Examine a value to determine if it is one of the built-in Error types.
// If so, return the error type.
extern JS_PUBLIC_API(mozilla::Maybe<JSExnType>)
JS_GetErrorType(const JS::Value& val);
#endif // defined(NIGHTLY_BUILD)
extern JS_PUBLIC_API(void)
JS_SetCompartmentPrivate(JSCompartment* compartment, void* data);

View File

@ -434,31 +434,6 @@ JSContext::minorGC(JS::gcreason::Reason reason)
inline void
JSContext::setPendingException(const js::Value& v)
{
#if defined(NIGHTLY_BUILD)
do {
// Do not intercept exceptions if we are already
// in the exception interceptor. That would lead
// to infinite recursion.
if (this->runtime()->errorInterception.isExecuting)
break;
// Check whether we have an interceptor at all.
if (!this->runtime()->errorInterception.interceptor)
break;
// Make sure that we do not call the interceptor from within
// the interceptor.
this->runtime()->errorInterception.isExecuting = true;
// The interceptor must be infallible.
const mozilla::DebugOnly<bool> wasExceptionPending = this->isExceptionPending();
this->runtime()->errorInterception.interceptor->interceptError(this, v);
MOZ_ASSERT(wasExceptionPending == this->isExceptionPending());
this->runtime()->errorInterception.isExecuting = false;
} while (false);
#endif // defined(NIGHTLY_BUILD)
// overRecursed_ is set after the fact by ReportOverRecursed.
this->overRecursed_ = false;
this->throwing = true;

View File

@ -1081,30 +1081,6 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
void* wasmUnwindPC() const {
return wasmUnwindPC_;
}
public:
#if defined(NIGHTLY_BUILD)
// Support for informing the embedding of any error thrown.
// This mechanism is designed to let the embedding
// log/report/fail in case certain errors are thrown
// (e.g. SyntaxError, ReferenceError or TypeError
// in critical code).
struct ErrorInterceptionSupport {
ErrorInterceptionSupport()
: isExecuting(false)
, interceptor(nullptr)
{ }
// true if the error interceptor is currently executing,
// false otherwise. Used to avoid infinite loops.
bool isExecuting;
// if non-null, any call to `setPendingException`
// in this runtime will trigger the call to `interceptor`
JSErrorInterceptor* interceptor;
};
ErrorInterceptionSupport errorInterception;
#endif // defined(NIGHTLY_BUILD)
};
namespace js {

View File

@ -97,11 +97,6 @@
#include "nsThreadUtils.h"
#include "xpcpublic.h"
#ifdef NIGHTLY_BUILD
// For performance reasons, we make the JS Dev Error Interceptor a Nightly-only feature.
#define MOZ_JS_DEV_ERROR_INTERCEPTOR = 1
#endif // NIGHTLY_BUILD
using namespace mozilla;
using namespace mozilla::dom;
@ -561,18 +556,11 @@ CycleCollectedJSRuntime::CycleCollectedJSRuntime(JSContext* aCx)
js::SetScriptEnvironmentPreparer(aCx, &mEnvironmentPreparer);
JS::dbg::SetDebuggerMallocSizeOf(aCx, moz_malloc_size_of);
#ifdef MOZ_JS_DEV_ERROR_INTERCEPTOR
JS_SetErrorInterceptorCallback(mJSRuntime, &mErrorInterceptor);
#endif // MOZ_JS_DEV_ERROR_INTERCEPTOR
}
void
CycleCollectedJSRuntime::Shutdown(JSContext* cx)
{
#ifdef MOZ_JS_DEV_ERROR_INTERCEPTOR
mErrorInterceptor.Shutdown(mJSRuntime);
#endif // MOZ_JS_DEV_ERROR_INTERCEPTOR
JS_RemoveExtraGCRootsTracer(cx, TraceBlackJS, this);
JS_RemoveExtraGCRootsTracer(cx, TraceGrayJS, this);
#ifdef DEBUG
@ -582,9 +570,6 @@ CycleCollectedJSRuntime::Shutdown(JSContext* cx)
CycleCollectedJSRuntime::~CycleCollectedJSRuntime()
{
#ifdef MOZ_JS_DEV_ERROR_INTERCEPTOR
mErrorInterceptor.Shutdown(mJSRuntime);
#endif // MOZ_JS_DEV_ERROR_INTERCEPTOR
MOZ_COUNT_DTOR(CycleCollectedJSRuntime);
MOZ_ASSERT(!mDeferredFinalizerTable.Count());
MOZ_ASSERT(mShutdownCalled);
@ -1572,113 +1557,3 @@ CycleCollectedJSRuntime::Get()
}
return nullptr;
}
#ifdef MOZ_JS_DEV_ERROR_INTERCEPTOR
namespace js {
extern void DumpValue(const JS::Value& val);
}
void
CycleCollectedJSRuntime::ErrorInterceptor::Shutdown(JSRuntime* rt)
{
JS_SetErrorInterceptorCallback(rt, nullptr);
mThrownError.reset();
}
/* virtual */ void
CycleCollectedJSRuntime::ErrorInterceptor::interceptError(JSContext* cx, const JS::Value& exn)
{
if (mThrownError) {
// We already have an error, we don't need anything more.
return;
}
if (!nsContentUtils::ThreadsafeIsSystemCaller(cx)) {
// We are only interested in chrome code.
return;
}
const auto type = JS_GetErrorType(exn);
if (!type) {
// This is not one of the primitive error types.
return;
}
switch (*type) {
case JSExnType::JSEXN_REFERENCEERR:
case JSExnType::JSEXN_SYNTAXERR:
case JSExnType::JSEXN_TYPEERR:
break;
default:
// Not one of the errors we are interested in.
return;
}
// Now copy the details of the exception locally.
// While copying the details of an exception could be expensive, in most runs,
// this will be done at most once during the execution of the process, so the
// total cost should be reasonable.
JS::RootedValue value(cx, exn);
ErrorDetails details;
details.mType = *type;
// If `exn` isn't an exception object, `ExtractErrorValues` could end up calling
// `toString()`, which could in turn end up throwing an error. While this should
// work, we want to avoid that complex use case.
// Fortunately, we have already checked above that `exn` is an exception object,
// so nothing such should happen.
nsContentUtils::ExtractErrorValues(cx, value, details.mFilename, &details.mLine, &details.mColumn, details.mMessage);
nsAutoCString stack;
JS::UniqueChars buf = JS::FormatStackDump(cx, nullptr, /* showArgs = */ false, /* showLocals = */ false, /* showThisProps = */ false);
stack.Append(buf.get());
CopyUTF8toUTF16(buf.get(), details.mStack);
mThrownError.emplace(Move(details));
}
void
CycleCollectedJSRuntime::ClearRecentDevError()
{
mErrorInterceptor.mThrownError.reset();
}
bool
CycleCollectedJSRuntime::GetRecentDevError(JSContext*cx, JS::MutableHandle<JS::Value> error)
{
if (!mErrorInterceptor.mThrownError) {
return true;
}
// Create a copy of the exception.
JS::RootedObject obj(cx, JS_NewPlainObject(cx));
if (!obj) {
return false;
}
JS::RootedValue message(cx);
JS::RootedValue filename(cx);
JS::RootedValue stack(cx);
if (!ToJSValue(cx, mErrorInterceptor.mThrownError->mMessage, &message) ||
!ToJSValue(cx, mErrorInterceptor.mThrownError->mFilename, &filename) ||
!ToJSValue(cx, mErrorInterceptor.mThrownError->mStack, &stack)) {
return false;
}
// Build the object.
const auto FLAGS = JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT;
if (!JS_DefineProperty(cx, obj, "message", message, FLAGS) ||
!JS_DefineProperty(cx, obj, "fileName", filename, FLAGS) ||
!JS_DefineProperty(cx, obj, "lineNumber", mErrorInterceptor.mThrownError->mLine, FLAGS) ||
!JS_DefineProperty(cx, obj, "stack", stack, FLAGS)) {
return false;
}
// Pass the result.
error.setObject(*obj);
return true;
}
#endif // MOZ_JS_DEV_ERROR_INTERCEPTOR
#undef MOZ_JS_DEV_ERROR_INTERCEPTOR

View File

@ -328,11 +328,6 @@ public:
void AddContext(CycleCollectedJSContext* aContext);
void RemoveContext(CycleCollectedJSContext* aContext);
#ifdef NIGHTLY_BUILD
bool GetRecentDevError(JSContext* aContext, JS::MutableHandle<JS::Value> aError);
void ClearRecentDevError();
#endif // defined(NIGHTLY_BUILD)
private:
LinkedList<CycleCollectedJSContext> mContexts;
@ -377,37 +372,6 @@ private:
#ifdef DEBUG
bool mShutdownCalled;
#endif
#ifdef NIGHTLY_BUILD
// Implementation of the error interceptor.
// Built on nightly only to avoid any possible performance impact on release
struct ErrorInterceptor final : public JSErrorInterceptor {
virtual void interceptError(JSContext* cx, const JS::Value& val) override;
void Shutdown(JSRuntime* rt);
// Copy of the details of the exception.
// We store this rather than the exception itself to avoid dealing with complicated
// garbage-collection scenarios, e.g. a JSContext being killed while we still hold
// onto an exception thrown from it.
struct ErrorDetails {
nsString mFilename;
nsString mMessage;
nsString mStack;
JSExnType mType;
uint32_t mLine;
uint32_t mColumn;
};
// If we have encountered at least one developer error,
// the first error we have encountered. Otherwise, or
// if we have reset since the latest error, `None`.
Maybe<ErrorDetails> mThrownError;
};
ErrorInterceptor mErrorInterceptor;
#endif // defined(NIGHTLY_BUILD)
};
void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer);