dom/bindings/ErrorResult.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/bindings/ErrorResult.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,192 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
     1.5 +/* vim: set ts=2 sw=2 et tw=79: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/**
    1.11 + * A struct for tracking exceptions that need to be thrown to JS.
    1.12 + */
    1.13 +
    1.14 +#ifndef mozilla_ErrorResult_h
    1.15 +#define mozilla_ErrorResult_h
    1.16 +
    1.17 +#include <stdarg.h>
    1.18 +
    1.19 +#include "js/Value.h"
    1.20 +#include "nscore.h"
    1.21 +#include "nsStringGlue.h"
    1.22 +#include "mozilla/Assertions.h"
    1.23 +
    1.24 +namespace mozilla {
    1.25 +
    1.26 +namespace dom {
    1.27 +
    1.28 +enum ErrNum {
    1.29 +#define MSG_DEF(_name, _argc, _str) \
    1.30 +  _name,
    1.31 +#include "mozilla/dom/Errors.msg"
    1.32 +#undef MSG_DEF
    1.33 +  Err_Limit
    1.34 +};
    1.35 +
    1.36 +bool
    1.37 +ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...);
    1.38 +
    1.39 +} // namespace dom
    1.40 +
    1.41 +class ErrorResult {
    1.42 +public:
    1.43 +  ErrorResult() {
    1.44 +    mResult = NS_OK;
    1.45 +
    1.46 +#ifdef DEBUG
    1.47 +    // ErrorResult is extremely performance-sensitive code, where literally
    1.48 +    // every machine instruction matters. Initialize mMessage only to suppress
    1.49 +    // a debug-only warning from gcc 4.6.
    1.50 +    mMessage = nullptr;
    1.51 +    mMightHaveUnreportedJSException = false;
    1.52 +#endif
    1.53 +  }
    1.54 +
    1.55 +#ifdef DEBUG
    1.56 +  ~ErrorResult() {
    1.57 +    MOZ_ASSERT_IF(IsTypeError(), !mMessage);
    1.58 +    MOZ_ASSERT(!mMightHaveUnreportedJSException);
    1.59 +  }
    1.60 +#endif
    1.61 +
    1.62 +  void Throw(nsresult rv) {
    1.63 +    MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success");
    1.64 +    MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
    1.65 +    MOZ_ASSERT(!IsTypeError(), "Don't overwite TypeError");
    1.66 +    MOZ_ASSERT(rv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()");
    1.67 +    MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
    1.68 +    MOZ_ASSERT(rv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()");
    1.69 +    MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error");
    1.70 +    mResult = rv;
    1.71 +  }
    1.72 +
    1.73 +  void ThrowTypeError(const dom::ErrNum errorNumber, ...);
    1.74 +  void ReportTypeError(JSContext* cx);
    1.75 +  void ClearMessage();
    1.76 +  bool IsTypeError() const { return ErrorCode() == NS_ERROR_TYPE_ERR; }
    1.77 +
    1.78 +  // Facilities for throwing a preexisting JS exception value via this
    1.79 +  // ErrorResult.  The contract is that any code which might end up calling
    1.80 +  // ThrowJSException() must call MightThrowJSException() even if no exception
    1.81 +  // is being thrown.  Code that would call ReportJSException* or
    1.82 +  // StealJSException as needed must first call WouldReportJSException even if
    1.83 +  // this ErrorResult has not failed.
    1.84 +  //
    1.85 +  // The exn argument to ThrowJSException can be in any compartment.  It does
    1.86 +  // not have to be in the compartment of cx.  If someone later uses it, they
    1.87 +  // will wrap it into whatever compartment they're working in, as needed.
    1.88 +  void ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn);
    1.89 +  void ReportJSException(JSContext* cx);
    1.90 +  // Used to implement throwing exceptions from the JS implementation of
    1.91 +  // bindings to callers of the binding.
    1.92 +  void ReportJSExceptionFromJSImplementation(JSContext* aCx);
    1.93 +  bool IsJSException() const { return ErrorCode() == NS_ERROR_DOM_JS_EXCEPTION; }
    1.94 +
    1.95 +  void ThrowNotEnoughArgsError() { mResult = NS_ERROR_XPC_NOT_ENOUGH_ARGS; }
    1.96 +  void ReportNotEnoughArgsError(JSContext* cx,
    1.97 +                                const char* ifaceName,
    1.98 +                                const char* memberName);
    1.99 +  bool IsNotEnoughArgsError() const { return ErrorCode() == NS_ERROR_XPC_NOT_ENOUGH_ARGS; }
   1.100 +
   1.101 +  // StealJSException steals the JS Exception from the object. This method must
   1.102 +  // be called only if IsJSException() returns true. This method also resets the
   1.103 +  // ErrorCode() to NS_OK.
   1.104 +  void StealJSException(JSContext* cx, JS::MutableHandle<JS::Value> value);
   1.105 +
   1.106 +  void MOZ_ALWAYS_INLINE MightThrowJSException()
   1.107 +  {
   1.108 +#ifdef DEBUG
   1.109 +    mMightHaveUnreportedJSException = true;
   1.110 +#endif
   1.111 +  }
   1.112 +  void MOZ_ALWAYS_INLINE WouldReportJSException()
   1.113 +  {
   1.114 +#ifdef DEBUG
   1.115 +    mMightHaveUnreportedJSException = false;
   1.116 +#endif
   1.117 +  }
   1.118 +
   1.119 +  // In the future, we can add overloads of Throw that take more
   1.120 +  // interesting things, like strings or DOM exception types or
   1.121 +  // something if desired.
   1.122 +
   1.123 +  // Backwards-compat to make conversion simpler.  We don't call
   1.124 +  // Throw() here because people can easily pass success codes to
   1.125 +  // this.
   1.126 +  void operator=(nsresult rv) {
   1.127 +    MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
   1.128 +    MOZ_ASSERT(!IsTypeError(), "Don't overwite TypeError");
   1.129 +    MOZ_ASSERT(rv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()");
   1.130 +    MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
   1.131 +    MOZ_ASSERT(rv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()");
   1.132 +    MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error");
   1.133 +    mResult = rv;
   1.134 +  }
   1.135 +
   1.136 +  bool Failed() const {
   1.137 +    return NS_FAILED(mResult);
   1.138 +  }
   1.139 +
   1.140 +  nsresult ErrorCode() const {
   1.141 +    return mResult;
   1.142 +  }
   1.143 +
   1.144 +private:
   1.145 +  nsresult mResult;
   1.146 +  struct Message;
   1.147 +  // mMessage is set by ThrowTypeError and cleared (and deallocatd) by
   1.148 +  // ReportTypeError.
   1.149 +  // mJSException is set (and rooted) by ThrowJSException and unrooted
   1.150 +  // by ReportJSException.
   1.151 +  union {
   1.152 +    Message* mMessage; // valid when IsTypeError()
   1.153 +    JS::Value mJSException; // valid when IsJSException()
   1.154 +  };
   1.155 +
   1.156 +#ifdef DEBUG
   1.157 +  // Used to keep track of codepaths that might throw JS exceptions,
   1.158 +  // for assertion purposes.
   1.159 +  bool mMightHaveUnreportedJSException;
   1.160 +#endif
   1.161 +
   1.162 +  // Not to be implemented, to make sure people always pass this by
   1.163 +  // reference, not by value.
   1.164 +  ErrorResult(const ErrorResult&) MOZ_DELETE;
   1.165 +};
   1.166 +
   1.167 +/******************************************************************************
   1.168 + ** Macros for checking results
   1.169 + ******************************************************************************/
   1.170 +
   1.171 +#define ENSURE_SUCCESS(res, ret)                                          \
   1.172 +  do {                                                                    \
   1.173 +    if (res.Failed()) {                                                   \
   1.174 +      nsCString msg;                                                      \
   1.175 +      msg.AppendPrintf("ENSURE_SUCCESS(%s, %s) failed with "              \
   1.176 +                       "result 0x%X", #res, #ret, res.ErrorCode());       \
   1.177 +      NS_WARNING(msg.get());                                              \
   1.178 +      return ret;                                                         \
   1.179 +    }                                                                     \
   1.180 +  } while(0)
   1.181 +
   1.182 +#define ENSURE_SUCCESS_VOID(res)                                          \
   1.183 +  do {                                                                    \
   1.184 +    if (res.Failed()) {                                                   \
   1.185 +      nsCString msg;                                                      \
   1.186 +      msg.AppendPrintf("ENSURE_SUCCESS_VOID(%s) failed with "             \
   1.187 +                       "result 0x%X", #res, res.ErrorCode());             \
   1.188 +      NS_WARNING(msg.get());                                              \
   1.189 +      return;                                                             \
   1.190 +    }                                                                     \
   1.191 +  } while(0)
   1.192 +
   1.193 +} // namespace mozilla
   1.194 +
   1.195 +#endif /* mozilla_ErrorResult_h */

mercurial