2012-05-05 18:15:11 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
|
|
|
/* vim: set ts=2 sw=2 et tw=79: */
|
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A struct for tracking exceptions that need to be thrown to JS.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef mozilla_ErrorResult_h
|
|
|
|
#define mozilla_ErrorResult_h
|
|
|
|
|
2012-11-06 15:23:14 -08:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
2013-04-30 07:04:52 -07:00
|
|
|
#include "js/Value.h"
|
2012-05-05 18:15:11 -07:00
|
|
|
#include "nscore.h"
|
2013-07-31 01:12:46 -07:00
|
|
|
#include "nsStringGlue.h"
|
2012-08-23 21:08:08 -07:00
|
|
|
#include "mozilla/Assertions.h"
|
2012-05-05 18:15:11 -07:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2012-11-06 15:23:14 -08:00
|
|
|
namespace dom {
|
|
|
|
|
|
|
|
enum ErrNum {
|
|
|
|
#define MSG_DEF(_name, _argc, _str) \
|
|
|
|
_name,
|
|
|
|
#include "mozilla/dom/Errors.msg"
|
|
|
|
#undef MSG_DEF
|
|
|
|
Err_Limit
|
|
|
|
};
|
|
|
|
|
2013-08-21 23:34:48 -07:00
|
|
|
bool
|
|
|
|
ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...);
|
|
|
|
|
2012-11-06 15:23:14 -08:00
|
|
|
} // namespace dom
|
|
|
|
|
2012-05-05 18:15:11 -07:00
|
|
|
class ErrorResult {
|
|
|
|
public:
|
|
|
|
ErrorResult() {
|
|
|
|
mResult = NS_OK;
|
2014-01-03 20:21:13 -08:00
|
|
|
|
2013-02-19 08:54:40 -08:00
|
|
|
#ifdef DEBUG
|
2014-01-03 20:21:13 -08:00
|
|
|
// ErrorResult is extremely performance-sensitive code, where literally
|
|
|
|
// every machine instruction matters. Initialize mMessage only to suppress
|
|
|
|
// a debug-only warning from gcc 4.6.
|
|
|
|
mMessage = nullptr;
|
2013-02-19 08:54:40 -08:00
|
|
|
mMightHaveUnreportedJSException = false;
|
|
|
|
#endif
|
2012-05-05 18:15:11 -07:00
|
|
|
}
|
2013-02-19 08:54:40 -08:00
|
|
|
|
2012-11-06 15:23:14 -08:00
|
|
|
#ifdef DEBUG
|
|
|
|
~ErrorResult() {
|
|
|
|
MOZ_ASSERT_IF(IsTypeError(), !mMessage);
|
2013-02-19 08:54:40 -08:00
|
|
|
MOZ_ASSERT(!mMightHaveUnreportedJSException);
|
2012-11-06 15:23:14 -08:00
|
|
|
}
|
|
|
|
#endif
|
2012-05-05 18:15:11 -07:00
|
|
|
|
|
|
|
void Throw(nsresult rv) {
|
|
|
|
MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success");
|
2012-11-06 15:23:14 -08:00
|
|
|
MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
|
|
|
|
MOZ_ASSERT(!IsTypeError(), "Don't overwite TypeError");
|
2013-02-19 08:54:40 -08:00
|
|
|
MOZ_ASSERT(rv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()");
|
|
|
|
MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
|
2013-07-04 06:24:49 -07:00
|
|
|
MOZ_ASSERT(rv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()");
|
|
|
|
MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error");
|
2012-05-05 18:15:11 -07:00
|
|
|
mResult = rv;
|
|
|
|
}
|
|
|
|
|
2012-11-06 15:23:14 -08:00
|
|
|
void ThrowTypeError(const dom::ErrNum errorNumber, ...);
|
|
|
|
void ReportTypeError(JSContext* cx);
|
2013-02-19 05:30:28 -08:00
|
|
|
void ClearMessage();
|
2012-11-06 15:23:14 -08:00
|
|
|
bool IsTypeError() const { return ErrorCode() == NS_ERROR_TYPE_ERR; }
|
|
|
|
|
2013-02-19 08:54:40 -08:00
|
|
|
// Facilities for throwing a preexisting JS exception value via this
|
|
|
|
// ErrorResult. The contract is that any code which might end up calling
|
|
|
|
// ThrowJSException() must call MightThrowJSException() even if no exception
|
2013-09-03 05:01:53 -07:00
|
|
|
// is being thrown. Code that would call ReportJSException* or
|
2013-06-11 18:41:21 -07:00
|
|
|
// StealJSException as needed must first call WouldReportJSException even if
|
|
|
|
// this ErrorResult has not failed.
|
2014-03-05 05:32:27 -08:00
|
|
|
//
|
|
|
|
// The exn argument to ThrowJSException can be in any compartment. It does
|
|
|
|
// not have to be in the compartment of cx. If someone later uses it, they
|
|
|
|
// will wrap it into whatever compartment they're working in, as needed.
|
2013-04-11 11:31:06 -07:00
|
|
|
void ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn);
|
2013-02-19 08:54:40 -08:00
|
|
|
void ReportJSException(JSContext* cx);
|
2013-09-03 05:01:53 -07:00
|
|
|
// Used to implement throwing exceptions from the JS implementation of
|
|
|
|
// bindings to callers of the binding.
|
|
|
|
void ReportJSExceptionFromJSImplementation(JSContext* aCx);
|
2013-02-19 08:54:40 -08:00
|
|
|
bool IsJSException() const { return ErrorCode() == NS_ERROR_DOM_JS_EXCEPTION; }
|
2013-06-11 18:41:21 -07:00
|
|
|
|
2013-07-04 06:24:49 -07:00
|
|
|
void ThrowNotEnoughArgsError() { mResult = NS_ERROR_XPC_NOT_ENOUGH_ARGS; }
|
|
|
|
void ReportNotEnoughArgsError(JSContext* cx,
|
|
|
|
const char* ifaceName,
|
|
|
|
const char* memberName);
|
|
|
|
bool IsNotEnoughArgsError() const { return ErrorCode() == NS_ERROR_XPC_NOT_ENOUGH_ARGS; }
|
|
|
|
|
2013-06-11 18:41:21 -07:00
|
|
|
// StealJSException steals the JS Exception from the object. This method must
|
|
|
|
// be called only if IsJSException() returns true. This method also resets the
|
2015-01-15 14:39:02 -08:00
|
|
|
// ErrorCode() to NS_OK. The value will be ensured to be sanitized wrt to the
|
|
|
|
// current compartment of cx if it happens to be a DOMException.
|
2013-06-11 18:41:21 -07:00
|
|
|
void StealJSException(JSContext* cx, JS::MutableHandle<JS::Value> value);
|
|
|
|
|
2013-02-19 08:54:40 -08:00
|
|
|
void MOZ_ALWAYS_INLINE MightThrowJSException()
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
mMightHaveUnreportedJSException = true;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
void MOZ_ALWAYS_INLINE WouldReportJSException()
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
mMightHaveUnreportedJSException = false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-05-05 18:15:11 -07:00
|
|
|
// In the future, we can add overloads of Throw that take more
|
|
|
|
// interesting things, like strings or DOM exception types or
|
|
|
|
// something if desired.
|
|
|
|
|
|
|
|
// Backwards-compat to make conversion simpler. We don't call
|
|
|
|
// Throw() here because people can easily pass success codes to
|
|
|
|
// this.
|
|
|
|
void operator=(nsresult rv) {
|
2012-11-06 15:23:14 -08:00
|
|
|
MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
|
|
|
|
MOZ_ASSERT(!IsTypeError(), "Don't overwite TypeError");
|
2013-02-19 08:54:40 -08:00
|
|
|
MOZ_ASSERT(rv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()");
|
|
|
|
MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
|
2013-07-04 06:24:49 -07:00
|
|
|
MOZ_ASSERT(rv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()");
|
|
|
|
MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error");
|
2012-05-05 18:15:11 -07:00
|
|
|
mResult = rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Failed() const {
|
|
|
|
return NS_FAILED(mResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult ErrorCode() const {
|
|
|
|
return mResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsresult mResult;
|
2012-11-06 15:23:14 -08:00
|
|
|
struct Message;
|
2013-02-19 08:54:40 -08:00
|
|
|
// mMessage is set by ThrowTypeError and cleared (and deallocatd) by
|
|
|
|
// ReportTypeError.
|
|
|
|
// mJSException is set (and rooted) by ThrowJSException and unrooted
|
|
|
|
// by ReportJSException.
|
|
|
|
union {
|
|
|
|
Message* mMessage; // valid when IsTypeError()
|
|
|
|
JS::Value mJSException; // valid when IsJSException()
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Used to keep track of codepaths that might throw JS exceptions,
|
|
|
|
// for assertion purposes.
|
|
|
|
bool mMightHaveUnreportedJSException;
|
|
|
|
#endif
|
2012-05-15 11:23:29 -07:00
|
|
|
|
|
|
|
// Not to be implemented, to make sure people always pass this by
|
|
|
|
// reference, not by value.
|
2015-01-06 15:35:02 -08:00
|
|
|
ErrorResult(const ErrorResult&) = delete;
|
2012-05-05 18:15:11 -07:00
|
|
|
};
|
|
|
|
|
2013-07-31 01:12:46 -07:00
|
|
|
/******************************************************************************
|
|
|
|
** Macros for checking results
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#define ENSURE_SUCCESS(res, ret) \
|
|
|
|
do { \
|
|
|
|
if (res.Failed()) { \
|
|
|
|
nsCString msg; \
|
|
|
|
msg.AppendPrintf("ENSURE_SUCCESS(%s, %s) failed with " \
|
|
|
|
"result 0x%X", #res, #ret, res.ErrorCode()); \
|
|
|
|
NS_WARNING(msg.get()); \
|
|
|
|
return ret; \
|
|
|
|
} \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define ENSURE_SUCCESS_VOID(res) \
|
|
|
|
do { \
|
|
|
|
if (res.Failed()) { \
|
|
|
|
nsCString msg; \
|
|
|
|
msg.AppendPrintf("ENSURE_SUCCESS_VOID(%s) failed with " \
|
|
|
|
"result 0x%X", #res, res.ErrorCode()); \
|
|
|
|
NS_WARNING(msg.get()); \
|
|
|
|
return; \
|
|
|
|
} \
|
|
|
|
} while(0)
|
|
|
|
|
2012-05-05 18:15:11 -07:00
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif /* mozilla_ErrorResult_h */
|