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/. */
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>`,
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
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`.
64 * When a function returns a `JS::Result<JSObject*>`, it is the program's
65 * responsibility to check for errors and root the object before continuing:
67 * RootedObject wrapper(cx);
68 * MOZ_TRY_VAR(wrapper, Enwrapify(cx, thing));
70 * This is ideal. On error, there is no object to root; on success, the
71 * assignment to wrapper roots it. GC safety is ensured.
73 * `Result` has methods .isOk(), .isErr(), .unwrap(), and .unwrapErr(), but if
74 * you're actually using them, it's possible to create a GC hazard. The static
75 * analysis will catch it if so, but that's hardly convenient. So try to stick
76 * to the idioms shown above.
79 * ## Future directions
81 * At present, JS::Error and JS::OOM are empty structs. The plan is to make them
82 * GC things that contain the actual error information (including the exception
83 * value and a saved stack).
85 * The long-term plan is to remove JS_IsExceptionPending and
86 * JS_GetPendingException in favor of JS::Error. Exception state will no longer
93 #include "mozilla/Result.h"
103 * Type representing a JS error or exception. At the moment this only
104 * "represents" an error in a rather abstract way.
107 // Since we claim UnusedZero<Error>::value and HasFreeLSB<Error>::value ==
108 // true below, we must only use positive even enum values.
109 enum class ErrorKind
: uintptr_t { Unspecified
= 2, OOM
= 4 };
111 const ErrorKind kind
= ErrorKind::Unspecified
;
116 friend struct UnusedZero
<Error
>;
118 constexpr MOZ_IMPLICIT
Error(ErrorKind aKind
) : kind(aKind
) {}
122 constexpr OOM() : Error(ErrorKind::OOM
) {}
125 friend struct UnusedZero
<OOM
>;
130 template <typename T
>
132 using StorageType
= std::underlying_type_t
<Error::ErrorKind
>;
134 static constexpr bool value
= true;
135 static constexpr StorageType nullValue
= 0;
137 static constexpr void AssertValid(StorageType aValue
) {}
138 static constexpr T
Inspect(const StorageType
& aValue
) {
139 return static_cast<Error::ErrorKind
>(aValue
);
141 static constexpr T
Unwrap(StorageType aValue
) {
142 return static_cast<Error::ErrorKind
>(aValue
);
144 static constexpr StorageType
Store(T aValue
) {
145 return static_cast<StorageType
>(aValue
.kind
);
151 namespace mozilla::detail
{
154 struct UnusedZero
<JS::Error
> : JS::UnusedZero
<JS::Error
> {};
157 struct UnusedZero
<JS::OOM
> : JS::UnusedZero
<JS::OOM
> {};
160 struct HasFreeLSB
<JS::Error
> {
161 static const bool value
= true;
165 struct HasFreeLSB
<JS::OOM
> {
166 static const bool value
= true;
168 } // namespace mozilla::detail
173 * `Result` is intended to be the return type of JSAPI calls and internal
174 * functions that can run JS code or allocate memory from the JS GC heap. Such
177 * - succeed, possibly returning a value;
179 * - fail with a JS exception (out-of-memory falls in this category); or
181 * - fail because JS execution was terminated, which occurs when e.g. a
182 * user kills a script from the "slow script" UI. This is also how we
183 * unwind the stack when the debugger forces the current function to
184 * return. JS `catch` blocks can't catch this kind of failure,
185 * and JS `finally` blocks don't execute.
187 template <typename V
= Ok
, typename E
= Error
>
188 using Result
= mozilla::Result
<V
, E
>;
190 static_assert(sizeof(Result
<>) == sizeof(uintptr_t),
191 "Result<> should be pointer-sized");
193 static_assert(sizeof(Result
<int*, Error
>) == sizeof(uintptr_t),
194 "Result<V*, Error> should be pointer-sized");
198 #endif // js_Result_h