Bug 1690340 - Part 4: Insert the "Page Source" before the "Extensions for Developers...
[gecko.git] / js / public / Result.h
blobcfd68a927cacfbdc7882b1bf9a5d252a6e4c544c
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * [SMDOC] JS::Result
10 * `Result` is used as the return type of many SpiderMonkey functions that
11 * can either succeed or fail. See "/mfbt/Result.h".
14 * ## Which return type to use
16 * `Result` is for return values. Obviously, if you're writing a function that
17 * can't fail, don't use Result. Otherwise:
19 * JS::Result<> - function can fail, doesn't return anything on success
20 * (defaults to `JS::Result<JS::Ok, JS::Error>`)
21 * JS::Result<JS::Ok, JS::OOM> - like JS::Result<>, but fails only on OOM
23 * JS::Result<Data> - function can fail, returns Data on success
24 * JS::Result<Data, JS::OOM> - returns Data, fails only on OOM
26 * mozilla::GenericErrorResult<JS::Error> - always fails
28 * That last type is like a Result with no success type. It's used for
29 * functions like `js::ReportNotFunction` that always return an error
30 * result. `GenericErrorResult<E>` implicitly converts to `Result<V, E>`,
31 * regardless of V.
34 * ## Checking Results when your return type is Result
36 * When you call a function that returns a `Result`, use the `MOZ_TRY` macro to
37 * check for errors:
39 * MOZ_TRY(DefenestrateObject(cx, obj));
41 * If `DefenestrateObject` returns a success result, `MOZ_TRY` is done, and
42 * control flows to the next statement. If `DefenestrateObject` returns an
43 * error result, `MOZ_TRY` will immediately return it, propagating the error to
44 * your caller. It's kind of like exceptions, but more explicit -- you can see
45 * in the code exactly where errors can happen.
47 * You can do a tail call instead of using `MOZ_TRY`:
49 * return DefenestrateObject(cx, obj);
51 * Indicate success with `return Ok();`.
53 * If the function returns a value on success, use `MOZ_TRY_VAR` to get it:
55 * RootedValue thrug(cx);
56 * MOZ_TRY_VAR(thrug, GetObjectThrug(cx, obj));
58 * This behaves the same as `MOZ_TRY` on error. On success, the success
59 * value of `GetObjectThrug(cx, obj)` is assigned to the variable `thrug`.
62 * ## Checking Results when your return type is not Result
64 * This header defines alternatives to MOZ_TRY and MOZ_TRY_VAR for when you
65 * need to call a `Result` function from a function that uses false or nullptr
66 * to indicate errors:
68 * JS_TRY_OR_RETURN_FALSE(cx, DefenestrateObject(cx, obj));
69 * JS_TRY_VAR_OR_RETURN_FALSE(cx, v, GetObjectThrug(cx, obj));
71 * JS_TRY_OR_RETURN_NULL(cx, DefenestrateObject(cx, obj));
72 * JS_TRY_VAR_OR_RETURN_NULL(cx, v, GetObjectThrug(cx, obj));
74 * When TRY is not what you want, because you need to do some cleanup or
75 * recovery on error, use this idiom:
77 * if (!cx->resultToBool(expr_that_is_a_Result)) {
78 * ... your recovery code here ...
79 * }
81 * In place of a tail call, you can use one of these methods:
83 * return cx->resultToBool(expr); // false on error
84 * return cx->resultToPtr(expr); // null on error
86 * Once we are using `Result` everywhere, including in public APIs, all of
87 * these will go away.
90 * ## GC safety
92 * When a function returns a `JS::Result<JSObject*>`, it is the program's
93 * responsibility to check for errors and root the object before continuing:
95 * RootedObject wrapper(cx);
96 * MOZ_TRY_VAR(wrapper, Enwrapify(cx, thing));
98 * This is ideal. On error, there is no object to root; on success, the
99 * assignment to wrapper roots it. GC safety is ensured.
101 * `Result` has methods .isOk(), .isErr(), .unwrap(), and .unwrapErr(), but if
102 * you're actually using them, it's possible to create a GC hazard. The static
103 * analysis will catch it if so, but that's hardly convenient. So try to stick
104 * to the idioms shown above.
107 * ## Future directions
109 * At present, JS::Error and JS::OOM are empty structs. The plan is to make them
110 * GC things that contain the actual error information (including the exception
111 * value and a saved stack).
113 * The long-term plan is to remove JS_IsExceptionPending and
114 * JS_GetPendingException in favor of JS::Error. Exception state will no longer
115 * exist.
118 #ifndef js_Result_h
119 #define js_Result_h
121 #include "mozilla/Result.h"
124 * Evaluate the boolean expression expr. If it's true, do nothing.
125 * If it's false, return an error result.
127 #define JS_TRY_BOOL_TO_RESULT(cx, expr) \
128 do { \
129 bool ok_ = (expr); \
130 if (!ok_) return (cx)->boolToResult(ok_); \
131 } while (0)
134 * JS_TRY_OR_RETURN_FALSE(cx, expr) runs expr to compute a Result value.
135 * On success, nothing happens; on error, it returns false immediately.
137 * Implementation note: this involves cx because this may eventually
138 * do the work of setting a pending exception or reporting OOM.
140 #define JS_TRY_OR_RETURN_FALSE(cx, expr) \
141 do { \
142 auto tmpResult_ = (expr); \
143 if (tmpResult_.isErr()) return (cx)->resultToBool(tmpResult_); \
144 } while (0)
147 * Like JS_TRY_OR_RETURN_FALSE, but returning nullptr on error,
148 * rather than false.
150 #define JS_TRY_OR_RETURN_NULL(cx, expr) \
151 do { \
152 auto tmpResult_ = (expr); \
153 if (tmpResult_.isErr()) { \
154 MOZ_ALWAYS_FALSE((cx)->resultToBool(tmpResult_)); \
155 return nullptr; \
157 } while (0)
159 #define JS_TRY_VAR_OR_RETURN_FALSE(cx, target, expr) \
160 do { \
161 auto tmpResult_ = (expr); \
162 if (tmpResult_.isErr()) return (cx)->resultToBool(tmpResult_); \
163 (target) = tmpResult_.unwrap(); \
164 } while (0)
166 #define JS_TRY_VAR_OR_RETURN_NULL(cx, target, expr) \
167 do { \
168 auto tmpResult_ = (expr); \
169 if (tmpResult_.isErr()) { \
170 MOZ_ALWAYS_FALSE((cx)->resultToBool(tmpResult_)); \
171 return nullptr; \
173 (target) = tmpResult_.unwrap(); \
174 } while (0)
176 namespace JS {
178 using mozilla::Ok;
180 template <typename T>
181 struct UnusedZero;
184 * Type representing a JS error or exception. At the moment this only
185 * "represents" an error in a rather abstract way.
187 struct Error {
188 // Since we claim UnusedZero<Error>::value and HasFreeLSB<Error>::value ==
189 // true below, we must only use positive even enum values.
190 enum class ErrorKind : uintptr_t { Unspecified = 2, OOM = 4 };
192 const ErrorKind kind = ErrorKind::Unspecified;
194 Error() = default;
196 protected:
197 friend struct UnusedZero<Error>;
199 constexpr MOZ_IMPLICIT Error(ErrorKind aKind) : kind(aKind) {}
202 struct OOM : Error {
203 constexpr OOM() : Error(ErrorKind::OOM) {}
205 protected:
206 friend struct UnusedZero<OOM>;
208 using Error::Error;
211 template <typename T>
212 struct UnusedZero {
213 using StorageType = std::underlying_type_t<Error::ErrorKind>;
215 static constexpr bool value = true;
216 static constexpr StorageType nullValue = 0;
218 static constexpr void AssertValid(StorageType aValue) {}
219 static constexpr T Inspect(const StorageType& aValue) {
220 return static_cast<Error::ErrorKind>(aValue);
222 static constexpr T Unwrap(StorageType aValue) {
223 return static_cast<Error::ErrorKind>(aValue);
225 static constexpr StorageType Store(T aValue) {
226 return static_cast<StorageType>(aValue.kind);
230 } // namespace JS
232 namespace mozilla::detail {
234 template <>
235 struct UnusedZero<JS::Error> : JS::UnusedZero<JS::Error> {};
237 template <>
238 struct UnusedZero<JS::OOM> : JS::UnusedZero<JS::OOM> {};
240 template <>
241 struct HasFreeLSB<JS::Error> {
242 static const bool value = true;
245 template <>
246 struct HasFreeLSB<JS::OOM> {
247 static const bool value = true;
249 } // namespace mozilla::detail
251 namespace JS {
254 * `Result` is intended to be the return type of JSAPI calls and internal
255 * functions that can run JS code or allocate memory from the JS GC heap. Such
256 * functions can:
258 * - succeed, possibly returning a value;
260 * - fail with a JS exception (out-of-memory falls in this category); or
262 * - fail because JS execution was terminated, which occurs when e.g. a
263 * user kills a script from the "slow script" UI. This is also how we
264 * unwind the stack when the debugger forces the current function to
265 * return. JS `catch` blocks can't catch this kind of failure,
266 * and JS `finally` blocks don't execute.
268 template <typename V = Ok, typename E = Error>
269 using Result = mozilla::Result<V, E>;
271 static_assert(sizeof(Result<>) == sizeof(uintptr_t),
272 "Result<> should be pointer-sized");
274 static_assert(sizeof(Result<int*, Error>) == sizeof(uintptr_t),
275 "Result<V*, Error> should be pointer-sized");
277 } // namespace JS
279 #endif // js_Result_h