From 15e2c78e9aa25d51affe6cdabcb61915ab1ddfbc Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 5 Apr 2025 16:05:52 +0200 Subject: [PATCH] LibJS: Shrink ThrowCompletionOr By specializing this template and using the special empty JS::Value as a marker for the `void` state, we shrink this very common class from 16 bytes to 8 bytes. This allows bytecode instruction handlers to return their result in a single 64-bit register, allowing tighter code generation. --- Libraries/LibJS/Runtime/Completion.h | 36 ++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/Libraries/LibJS/Runtime/Completion.h b/Libraries/LibJS/Runtime/Completion.h index 0650a7feb5b..7d8ca4f739b 100644 --- a/Libraries/LibJS/Runtime/Completion.h +++ b/Libraries/LibJS/Runtime/Completion.h @@ -298,9 +298,41 @@ private: }; template<> -class [[nodiscard]] ThrowCompletionOr : public ThrowCompletionOr { +class [[nodiscard]] ThrowCompletionOr { public: - using ThrowCompletionOr::ThrowCompletionOr; + ALWAYS_INLINE ThrowCompletionOr() + : m_value(js_special_empty_value()) + { + } + + ALWAYS_INLINE ThrowCompletionOr(Empty) + : m_value(js_special_empty_value()) + { + } + + // Not `explicit` on purpose so that `return vm.throw_completion(...);` is possible. + ALWAYS_INLINE ThrowCompletionOr(Completion throw_completion) + : m_value(throw_completion.release_error().value()) + { + } + + ALWAYS_INLINE ThrowCompletionOr(ThrowCompletionOr const&) = default; + ALWAYS_INLINE ThrowCompletionOr& operator=(ThrowCompletionOr const&) = default; + ALWAYS_INLINE ThrowCompletionOr(ThrowCompletionOr&&) = default; + ALWAYS_INLINE ThrowCompletionOr& operator=(ThrowCompletionOr&&) = default; + + [[nodiscard]] bool is_throw_completion() const { return !m_value.is_special_empty_value(); } + [[nodiscard]] Completion throw_completion() const { return error(); } + [[nodiscard]] Value error_value() const { return m_value; } + + // These are for compatibility with the TRY() macro in AK. + [[nodiscard]] bool is_error() const { return !m_value.is_special_empty_value(); } + Empty release_value() { return {}; } + Completion error() const { return Completion { Completion::Type::Throw, m_value }; } + Completion release_error() { return error(); } + +private: + Value m_value; }; ThrowCompletionOr await(VM&, Value);