Completion.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <AK/DeprecatedFlyString.h>
  9. #include <AK/Optional.h>
  10. #include <AK/Try.h>
  11. #include <AK/TypeCasts.h>
  12. #include <AK/Variant.h>
  13. #include <LibJS/Runtime/ErrorTypes.h>
  14. #include <LibJS/Runtime/Value.h>
  15. namespace JS {
  16. #define TRY_OR_THROW_OOM(vm, expression) \
  17. ({ \
  18. /* Ignore -Wshadow to allow nesting the macro. */ \
  19. AK_IGNORE_DIAGNOSTIC("-Wshadow", \
  20. auto&& _temporary_result = (expression)); \
  21. if (_temporary_result.is_error()) { \
  22. VERIFY(_temporary_result.error().code() == ENOMEM); \
  23. return (vm).throw_completion<JS::InternalError>((vm).error_message(::JS::VM::ErrorMessage::OutOfMemory)); \
  24. } \
  25. static_assert(!::AK::Detail::IsLvalueReference<decltype(_temporary_result.release_value())>, \
  26. "Do not return a reference from a fallible expression"); \
  27. _temporary_result.release_value(); \
  28. })
  29. #define MUST_OR_THROW_OOM(expression) \
  30. ({ \
  31. /* Ignore -Wshadow to allow nesting the macro. */ \
  32. AK_IGNORE_DIAGNOSTIC("-Wshadow", \
  33. auto&& _temporary_result = (expression)); \
  34. if (_temporary_result.is_error()) { \
  35. auto _completion = _temporary_result.release_error(); \
  36. \
  37. /* We can't explicitly check for OOM because InternalError does not store the ErrorType */ \
  38. VERIFY(_completion.value().has_value()); \
  39. VERIFY(_completion.value()->is_object()); \
  40. VERIFY(::AK::is<JS::InternalError>(_completion.value()->as_object())); \
  41. \
  42. return _completion; \
  43. } \
  44. static_assert(!::AK::Detail::IsLvalueReference<decltype(_temporary_result.release_value())>, \
  45. "Do not return a reference from a fallible expression"); \
  46. _temporary_result.release_value(); \
  47. })
  48. // 6.2.3 The Completion Record Specification Type, https://tc39.es/ecma262/#sec-completion-record-specification-type
  49. class [[nodiscard]] Completion {
  50. public:
  51. enum class Type {
  52. Empty,
  53. Normal,
  54. Break,
  55. Continue,
  56. Return,
  57. Throw,
  58. };
  59. ALWAYS_INLINE Completion(Type type, Optional<Value> value)
  60. : m_type(type)
  61. , m_value(move(value))
  62. {
  63. VERIFY(type != Type::Empty);
  64. if (m_value.has_value())
  65. VERIFY(!m_value->is_empty());
  66. }
  67. Completion(ThrowCompletionOr<Value> const&);
  68. // 5.2.3.1 Implicit Completion Values, https://tc39.es/ecma262/#sec-implicit-completion-values
  69. // Not `explicit` on purpose.
  70. ALWAYS_INLINE Completion(Value value)
  71. : Completion(Type::Normal, value)
  72. {
  73. }
  74. ALWAYS_INLINE Completion(Optional<Value> value)
  75. : Completion(Type::Normal, move(value))
  76. {
  77. }
  78. ALWAYS_INLINE Completion()
  79. : Completion(js_undefined())
  80. {
  81. }
  82. Completion(Completion const&) = default;
  83. Completion& operator=(Completion const&) = default;
  84. Completion(Completion&&) = default;
  85. Completion& operator=(Completion&&) = default;
  86. [[nodiscard]] Type type() const
  87. {
  88. VERIFY(m_type != Type::Empty);
  89. return m_type;
  90. }
  91. [[nodiscard]] Optional<Value>& value() { return m_value; }
  92. [[nodiscard]] Optional<Value> const& value() const { return m_value; }
  93. // "abrupt completion refers to any completion with a [[Type]] value other than normal"
  94. [[nodiscard]] bool is_abrupt() const { return m_type != Type::Normal; }
  95. // These are for compatibility with the TRY() macro in AK.
  96. [[nodiscard]] bool is_error() const { return m_type == Type::Throw; }
  97. [[nodiscard]] Optional<Value> release_value() { return move(m_value); }
  98. Completion release_error()
  99. {
  100. VERIFY(is_error());
  101. VERIFY(m_value.has_value());
  102. return { m_type, release_value() };
  103. }
  104. // 6.2.3.4 UpdateEmpty ( completionRecord, value ), https://tc39.es/ecma262/#sec-updateempty
  105. Completion update_empty(Optional<Value> value) const
  106. {
  107. // 1. Assert: If completionRecord.[[Type]] is either return or throw, then completionRecord.[[Value]] is not empty.
  108. if (m_type == Type::Return || m_type == Type::Throw)
  109. VERIFY(m_value.has_value());
  110. // 2. If completionRecord.[[Value]] is not empty, return ? completionRecord.
  111. if (m_value.has_value())
  112. return *this;
  113. // 3. Return Completion Record { [[Type]]: completionRecord.[[Type]], [[Value]]: value, [[Target]]: completionRecord.[[Target]] }.
  114. return { m_type, move(value) };
  115. }
  116. private:
  117. class EmptyTag {
  118. };
  119. friend AK::Optional<Completion>;
  120. Completion(EmptyTag)
  121. : m_type(Type::Empty)
  122. {
  123. }
  124. bool is_empty() const
  125. {
  126. return m_type == Type::Empty;
  127. }
  128. Type m_type { Type::Normal }; // [[Type]]
  129. Optional<Value> m_value; // [[Value]]
  130. // NOTE: We don't need the [[Target]] slot since control flow is handled in bytecode.
  131. };
  132. }
  133. namespace AK {
  134. template<>
  135. class Optional<JS::Completion> {
  136. template<typename U>
  137. friend class Optional;
  138. public:
  139. using ValueType = JS::Completion;
  140. Optional() = default;
  141. Optional(Optional<JS::Completion> const& other)
  142. {
  143. if (other.has_value())
  144. m_value = other.m_value;
  145. }
  146. Optional(Optional&& other)
  147. : m_value(move(other.m_value))
  148. {
  149. }
  150. template<typename U = JS::Completion>
  151. explicit(!IsConvertible<U&&, JS::Completion>) Optional(U&& value)
  152. requires(!IsSame<RemoveCVReference<U>, Optional<JS::Completion>> && IsConstructible<JS::Completion, U &&>)
  153. : m_value(forward<U>(value))
  154. {
  155. }
  156. Optional& operator=(Optional const& other)
  157. {
  158. if (this != &other) {
  159. clear();
  160. m_value = other.m_value;
  161. }
  162. return *this;
  163. }
  164. Optional& operator=(Optional&& other)
  165. {
  166. if (this != &other) {
  167. clear();
  168. m_value = other.m_value;
  169. }
  170. return *this;
  171. }
  172. void clear()
  173. {
  174. m_value = JS::Completion(JS::Completion::EmptyTag {});
  175. }
  176. [[nodiscard]] bool has_value() const
  177. {
  178. return !m_value.is_empty();
  179. }
  180. [[nodiscard]] JS::Completion& value() &
  181. {
  182. VERIFY(has_value());
  183. return m_value;
  184. }
  185. [[nodiscard]] JS::Completion const& value() const&
  186. {
  187. VERIFY(has_value());
  188. return m_value;
  189. }
  190. [[nodiscard]] JS::Completion value() &&
  191. {
  192. return release_value();
  193. }
  194. [[nodiscard]] JS::Completion release_value()
  195. {
  196. VERIFY(has_value());
  197. JS::Completion released_value = m_value;
  198. clear();
  199. return released_value;
  200. }
  201. JS::Completion value_or(JS::Completion const& fallback) const&
  202. {
  203. if (has_value())
  204. return value();
  205. return fallback;
  206. }
  207. [[nodiscard]] JS::Completion value_or(JS::Completion&& fallback) &&
  208. {
  209. if (has_value())
  210. return value();
  211. return fallback;
  212. }
  213. JS::Completion const& operator*() const { return value(); }
  214. JS::Completion& operator*() { return value(); }
  215. JS::Completion const* operator->() const { return &value(); }
  216. JS::Completion* operator->() { return &value(); }
  217. private:
  218. JS::Completion m_value { JS::Completion::EmptyTag {} };
  219. };
  220. }
  221. namespace JS {
  222. template<typename ValueType>
  223. requires(!IsLvalueReference<ValueType>)
  224. class [[nodiscard]] ThrowCompletionOr {
  225. public:
  226. ALWAYS_INLINE ThrowCompletionOr()
  227. requires(IsSame<ValueType, Empty>)
  228. : m_value_or_throw_completion(Empty {})
  229. {
  230. }
  231. // Not `explicit` on purpose so that `return vm.throw_completion<Error>(...);` is possible.
  232. ALWAYS_INLINE ThrowCompletionOr(Completion throw_completion)
  233. : m_value_or_throw_completion(move(throw_completion))
  234. {
  235. VERIFY(m_value_or_throw_completion.template get<Completion>().is_error());
  236. }
  237. // Not `explicit` on purpose so that `return value;` is possible.
  238. ALWAYS_INLINE ThrowCompletionOr(ValueType value)
  239. : m_value_or_throw_completion(move(value))
  240. {
  241. if constexpr (IsSame<ValueType, Value>)
  242. VERIFY(!m_value_or_throw_completion.template get<ValueType>().is_empty());
  243. }
  244. ALWAYS_INLINE ThrowCompletionOr(ThrowCompletionOr const&) = default;
  245. ALWAYS_INLINE ThrowCompletionOr& operator=(ThrowCompletionOr const&) = default;
  246. ALWAYS_INLINE ThrowCompletionOr(ThrowCompletionOr&&) = default;
  247. ALWAYS_INLINE ThrowCompletionOr& operator=(ThrowCompletionOr&&) = default;
  248. ALWAYS_INLINE ThrowCompletionOr(OptionalNone value)
  249. : m_value_or_throw_completion(ValueType { value })
  250. {
  251. }
  252. // Allows implicit construction of ThrowCompletionOr<T> from a type U if T(U) is a supported constructor.
  253. // Most commonly: Value from Object* or similar, so we can omit the curly braces from "return { TRY(...) };".
  254. // Disabled for POD types to avoid weird conversion shenanigans.
  255. template<typename WrappedValueType>
  256. ALWAYS_INLINE ThrowCompletionOr(WrappedValueType&& value)
  257. requires(!IsPOD<ValueType>)
  258. : m_value_or_throw_completion(ValueType { value })
  259. {
  260. }
  261. [[nodiscard]] bool is_throw_completion() const { return m_value_or_throw_completion.template has<Completion>(); }
  262. Completion const& throw_completion() const { return m_value_or_throw_completion.template get<Completion>(); }
  263. [[nodiscard]] bool has_value() const
  264. requires(!IsSame<ValueType, Empty>)
  265. {
  266. return m_value_or_throw_completion.template has<ValueType>();
  267. }
  268. [[nodiscard]] ValueType const& value() const
  269. requires(!IsSame<ValueType, Empty>)
  270. {
  271. return m_value_or_throw_completion.template get<ValueType>();
  272. }
  273. // These are for compatibility with the TRY() macro in AK.
  274. [[nodiscard]] bool is_error() const { return m_value_or_throw_completion.template has<Completion>(); }
  275. [[nodiscard]] ValueType release_value() { return move(m_value_or_throw_completion.template get<ValueType>()); }
  276. Completion release_error() { return move(m_value_or_throw_completion.template get<Completion>()); }
  277. ValueType release_allocated_value_but_fixme_should_propagate_errors()
  278. {
  279. VERIFY(!is_error());
  280. return release_value();
  281. }
  282. private:
  283. Variant<ValueType, Completion> m_value_or_throw_completion;
  284. };
  285. template<>
  286. class [[nodiscard]] ThrowCompletionOr<void> : public ThrowCompletionOr<Empty> {
  287. public:
  288. using ThrowCompletionOr<Empty>::ThrowCompletionOr;
  289. };
  290. ThrowCompletionOr<Value> await(VM&, Value);
  291. // 6.2.4.1 NormalCompletion ( value ), https://tc39.es/ecma262/#sec-normalcompletion
  292. inline Completion normal_completion(Optional<Value> value)
  293. {
  294. // 1. Return Completion Record { [[Type]]: normal, [[Value]]: value, [[Target]]: empty }.
  295. return { Completion::Type::Normal, move(value) };
  296. }
  297. // 6.2.4.2 ThrowCompletion ( value ), https://tc39.es/ecma262/#sec-throwcompletion
  298. Completion throw_completion(Value);
  299. }