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 */