tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Result.h (6169B)


      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/. */
      6 
      7 /*
      8 * [SMDOC] JS::Result
      9 *
     10 * `Result` is used as the return type of many SpiderMonkey functions that
     11 * can either succeed or fail. See "/mfbt/Result.h".
     12 *
     13 *
     14 * ## Which return type to use
     15 *
     16 * `Result` is for return values. Obviously, if you're writing a function that
     17 * can't fail, don't use Result. Otherwise:
     18 *
     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
     22 *
     23 *     JS::Result<Data>  - function can fail, returns Data on success
     24 *     JS::Result<Data, JS::OOM>  - returns Data, fails only on OOM
     25 *
     26 *     mozilla::GenericErrorResult<JS::Error> - always fails
     27 *
     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.
     32 *
     33 *
     34 * ## Checking Results when your return type is Result
     35 *
     36 * When you call a function that returns a `Result`, use the `MOZ_TRY` macro to
     37 * check for errors:
     38 *
     39 *     MOZ_TRY(DefenestrateObject(cx, obj));
     40 *
     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.
     46 *
     47 * You can do a tail call instead of using `MOZ_TRY`:
     48 *
     49 *     return DefenestrateObject(cx, obj);
     50 *
     51 * Indicate success with `return Ok();`.
     52 *
     53 * If the function returns a value on success, use `MOZ_TRY` to get it:
     54 *
     55 *     RootedValue thrug(cx);
     56 *     thrug = MOZ_TRY(GetObjectThrug(cx, obj));
     57 *
     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`.
     60 *
     61 *
     62 * ## GC safety
     63 *
     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:
     66 *
     67 *     RootedObject wrapper(cx);
     68 *     wrapper = MOZ_TRY(Enwrapify(cx, thing));
     69 *
     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.
     72 *
     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.
     77 *
     78 *
     79 * ## Future directions
     80 *
     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).
     84 *
     85 * The long-term plan is to remove JS_IsExceptionPending and
     86 * JS_GetPendingException in favor of JS::Error. Exception state will no longer
     87 * exist.
     88 */
     89 
     90 #ifndef js_Result_h
     91 #define js_Result_h
     92 
     93 #include "mozilla/Result.h"
     94 
     95 namespace JS {
     96 
     97 using mozilla::Ok;
     98 
     99 template <typename T>
    100 struct UnusedZero;
    101 
    102 /**
    103 * Type representing a JS error or exception. At the moment this only
    104 * "represents" an error in a rather abstract way.
    105 */
    106 struct Error {
    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 };
    110 
    111  const ErrorKind kind = ErrorKind::Unspecified;
    112 
    113  Error() = default;
    114 
    115 protected:
    116  friend struct UnusedZero<Error>;
    117 
    118  constexpr MOZ_IMPLICIT Error(ErrorKind aKind) : kind(aKind) {}
    119 };
    120 
    121 struct OOM : Error {
    122  constexpr OOM() : Error(ErrorKind::OOM) {}
    123 
    124 protected:
    125  friend struct UnusedZero<OOM>;
    126 
    127  using Error::Error;
    128 };
    129 
    130 template <typename T>
    131 struct UnusedZero {
    132  using StorageType = std::underlying_type_t<Error::ErrorKind>;
    133 
    134  static constexpr bool value = true;
    135  static constexpr StorageType nullValue = 0;
    136 
    137  static constexpr void AssertValid(StorageType aValue) {}
    138  static constexpr T Inspect(const StorageType& aValue) {
    139    return static_cast<Error::ErrorKind>(aValue);
    140  }
    141  static constexpr T Unwrap(StorageType aValue) {
    142    return static_cast<Error::ErrorKind>(aValue);
    143  }
    144  static constexpr StorageType Store(T aValue) {
    145    return static_cast<StorageType>(aValue.kind);
    146  }
    147 };
    148 
    149 }  // namespace JS
    150 
    151 namespace mozilla::detail {
    152 
    153 template <>
    154 struct UnusedZero<JS::Error> : JS::UnusedZero<JS::Error> {};
    155 
    156 template <>
    157 struct UnusedZero<JS::OOM> : JS::UnusedZero<JS::OOM> {};
    158 
    159 template <>
    160 struct HasFreeLSB<JS::Error> {
    161  static const bool value = true;
    162 };
    163 
    164 template <>
    165 struct HasFreeLSB<JS::OOM> {
    166  static const bool value = true;
    167 };
    168 }  // namespace mozilla::detail
    169 
    170 namespace JS {
    171 
    172 /**
    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
    175 * functions can:
    176 *
    177 * -   succeed, possibly returning a value;
    178 *
    179 * -   fail with a JS exception (out-of-memory falls in this category); or
    180 *
    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.
    186 */
    187 template <typename V = Ok, typename E = Error>
    188 using Result = mozilla::Result<V, E>;
    189 
    190 static_assert(sizeof(Result<>) == sizeof(uintptr_t),
    191              "Result<> should be pointer-sized");
    192 
    193 static_assert(sizeof(Result<int*, Error>) == sizeof(uintptr_t),
    194              "Result<V*, Error> should be pointer-sized");
    195 
    196 }  // namespace JS
    197 
    198 #endif  // js_Result_h