1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 04:08:11 +00:00

LibJS: Use a Variant instead of two Optionals for ThrowCompletionOr

Comes with the usual benefit of saving some space on the stack, as well
as making a situation where both or neither Optionals hold a value
impossible.

The various unwrapping additions are required as we can no longer
construct a ThrowCompletionOr<T> from an Optional<T> - rightfully so.
This commit is contained in:
Linus Groh 2023-03-01 14:52:31 +00:00
parent e77503e49b
commit 8f1d13e73b
6 changed files with 26 additions and 27 deletions

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020-2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -184,7 +184,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from)
auto error = vm.throw_completion<TypeError>(ErrorType::ArrayMaxSize); auto error = vm.throw_completion<TypeError>(ErrorType::ArrayMaxSize);
// 2. Return ? IteratorClose(iteratorRecord, error). // 2. Return ? IteratorClose(iteratorRecord, error).
return TRY(iterator_close(vm, iterator, move(error))); return *TRY(iterator_close(vm, iterator, move(error)));
} }
// ii. Let Pk be ! ToString(𝔽(k)). // ii. Let Pk be ! ToString(𝔽(k)).
@ -214,7 +214,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from)
// 2. IfAbruptCloseIterator(mappedValue, iteratorRecord). // 2. IfAbruptCloseIterator(mappedValue, iteratorRecord).
if (mapped_value_or_error.is_error()) if (mapped_value_or_error.is_error())
return TRY(iterator_close(vm, iterator, mapped_value_or_error.release_error())); return *TRY(iterator_close(vm, iterator, mapped_value_or_error.release_error()));
mapped_value = mapped_value_or_error.release_value(); mapped_value = mapped_value_or_error.release_value();
} }
// vii. Else, let mappedValue be nextValue. // vii. Else, let mappedValue be nextValue.
@ -227,7 +227,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from)
// IfAbruptCloseIterator(defineStatus, iteratorRecord). // IfAbruptCloseIterator(defineStatus, iteratorRecord).
if (result_or_error.is_error()) if (result_or_error.is_error())
return TRY(iterator_close(vm, iterator, result_or_error.release_error())); return *TRY(iterator_close(vm, iterator, result_or_error.release_error()));
// x. Set k to k + 1. // x. Set k to k + 1.
} }

View file

@ -274,23 +274,23 @@ class [[nodiscard]] ThrowCompletionOr {
public: public:
ThrowCompletionOr() ThrowCompletionOr()
requires(IsSame<ValueType, Empty>) requires(IsSame<ValueType, Empty>)
: m_value(Empty {}) : m_value_or_throw_completion(Empty {})
{ {
} }
// Not `explicit` on purpose so that `return vm.throw_completion<Error>(...);` is possible. // Not `explicit` on purpose so that `return vm.throw_completion<Error>(...);` is possible.
ThrowCompletionOr(Completion throw_completion) ThrowCompletionOr(Completion throw_completion)
: m_throw_completion(move(throw_completion)) : m_value_or_throw_completion(move(throw_completion))
{ {
VERIFY(m_throw_completion->is_error()); VERIFY(m_value_or_throw_completion.template get<Completion>().is_error());
} }
// Not `explicit` on purpose so that `return value;` is possible. // Not `explicit` on purpose so that `return value;` is possible.
ThrowCompletionOr(ValueType value) ThrowCompletionOr(ValueType value)
: m_value(move(value)) : m_value_or_throw_completion(move(value))
{ {
if constexpr (IsSame<ValueType, Value>) if constexpr (IsSame<ValueType, Value>)
VERIFY(!m_value->is_empty()); VERIFY(!m_value_or_throw_completion.template get<ValueType>().is_empty());
} }
ThrowCompletionOr(ThrowCompletionOr const&) = default; ThrowCompletionOr(ThrowCompletionOr const&) = default;
@ -299,7 +299,7 @@ public:
ThrowCompletionOr& operator=(ThrowCompletionOr&&) = default; ThrowCompletionOr& operator=(ThrowCompletionOr&&) = default;
ThrowCompletionOr(OptionalNone value) ThrowCompletionOr(OptionalNone value)
: m_value(ValueType { value }) : m_value_or_throw_completion(ValueType { value })
{ {
} }
@ -309,28 +309,28 @@ public:
template<typename WrappedValueType> template<typename WrappedValueType>
ThrowCompletionOr(WrappedValueType const& value) ThrowCompletionOr(WrappedValueType const& value)
requires(!IsPOD<ValueType>) requires(!IsPOD<ValueType>)
: m_value(value) : m_value_or_throw_completion(ValueType { value })
{ {
} }
[[nodiscard]] bool is_throw_completion() const { return m_throw_completion.has_value(); } [[nodiscard]] bool is_throw_completion() const { return m_value_or_throw_completion.template has<Completion>(); }
Completion const& throw_completion() const { return *m_throw_completion; } Completion const& throw_completion() const { return m_value_or_throw_completion.template get<Completion>(); }
[[nodiscard]] bool has_value() const [[nodiscard]] bool has_value() const
requires(!IsSame<ValueType, Empty>) requires(!IsSame<ValueType, Empty>)
{ {
return m_value.has_value(); return m_value_or_throw_completion.template has<ValueType>();
} }
[[nodiscard]] ValueType const& value() const [[nodiscard]] ValueType const& value() const
requires(!IsSame<ValueType, Empty>) requires(!IsSame<ValueType, Empty>)
{ {
return *m_value; return m_value_or_throw_completion.template get<ValueType>();
} }
// These are for compatibility with the TRY() macro in AK. // These are for compatibility with the TRY() macro in AK.
[[nodiscard]] bool is_error() const { return m_throw_completion.has_value(); } [[nodiscard]] bool is_error() const { return m_value_or_throw_completion.template has<Completion>(); }
[[nodiscard]] ValueType release_value() { return m_value.release_value(); } [[nodiscard]] ValueType release_value() { return move(m_value_or_throw_completion.template get<ValueType>()); }
Completion release_error() { return m_throw_completion.release_value(); } Completion release_error() { return move(m_value_or_throw_completion.template get<Completion>()); }
ValueType release_allocated_value_but_fixme_should_propagate_errors() ValueType release_allocated_value_but_fixme_should_propagate_errors()
{ {
@ -339,8 +339,7 @@ public:
} }
private: private:
Optional<Completion> m_throw_completion; Variant<ValueType, Completion> m_value_or_throw_completion;
Optional<ValueType> m_value;
}; };
template<> template<>

View file

@ -69,7 +69,7 @@ JS_DEFINE_NATIVE_FUNCTION(DisposableStackPrototype::dispose)
disposable_stack->set_disposed(); disposable_stack->set_disposed();
// 5. Return DisposeResources(disposableStack, NormalCompletion(undefined)). // 5. Return DisposeResources(disposableStack, NormalCompletion(undefined)).
return TRY(dispose_resources(vm, disposable_stack->disposable_resource_stack(), Completion { js_undefined() })); return *TRY(dispose_resources(vm, disposable_stack->disposable_resource_stack(), Completion { js_undefined() }));
} }
// 11.3.3.3 DisposableStack.prototype.use( value ), https://tc39.es/proposal-explicit-resource-management/#sec-disposablestack.prototype.use // 11.3.3.3 DisposableStack.prototype.use( value ), https://tc39.es/proposal-explicit-resource-management/#sec-disposablestack.prototype.use

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@serenityos.org> * Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@serenityos.org>
* Copyright (c) 2020-2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2023, Andreas Kling <kling@serenityos.org> * Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
@ -183,7 +183,7 @@ ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argu
// 8. If result.[[Type]] is return, return result.[[Value]]. // 8. If result.[[Type]] is return, return result.[[Value]].
if (result.type() == Completion::Type::Return) if (result.type() == Completion::Type::Return)
return result.value(); return *result.value();
// 9. ReturnIfAbrupt(result). // 9. ReturnIfAbrupt(result).
if (result.is_abrupt()) { if (result.is_abrupt()) {

View file

@ -558,7 +558,7 @@ JS_DEFINE_NATIVE_FUNCTION(CalendarPrototype::fields)
auto completion = vm.throw_completion<TypeError>(ErrorType::TemporalInvalidCalendarFieldValue, TRY_OR_THROW_OOM(vm, next_value.to_string_without_side_effects())); auto completion = vm.throw_completion<TypeError>(ErrorType::TemporalInvalidCalendarFieldValue, TRY_OR_THROW_OOM(vm, next_value.to_string_without_side_effects()));
// 2. Return ? IteratorClose(iteratorRecord, completion). // 2. Return ? IteratorClose(iteratorRecord, completion).
return TRY(iterator_close(vm, iterator_record, move(completion))); return *TRY(iterator_close(vm, iterator_record, move(completion)));
} }
auto next_value_string = TRY(next_value.as_string().utf8_string()); auto next_value_string = TRY(next_value.as_string().utf8_string());
@ -569,7 +569,7 @@ JS_DEFINE_NATIVE_FUNCTION(CalendarPrototype::fields)
auto completion = vm.throw_completion<RangeError>(ErrorType::TemporalDuplicateCalendarField, next_value_string); auto completion = vm.throw_completion<RangeError>(ErrorType::TemporalDuplicateCalendarField, next_value_string);
// 2. Return ? IteratorClose(iteratorRecord, completion). // 2. Return ? IteratorClose(iteratorRecord, completion).
return TRY(iterator_close(vm, iterator_record, move(completion))); return *TRY(iterator_close(vm, iterator_record, move(completion)));
} }
// iv. If nextValue is not one of "year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", then // iv. If nextValue is not one of "year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", then
@ -578,7 +578,7 @@ JS_DEFINE_NATIVE_FUNCTION(CalendarPrototype::fields)
auto completion = vm.throw_completion<RangeError>(ErrorType::TemporalInvalidCalendarFieldName, next_value_string); auto completion = vm.throw_completion<RangeError>(ErrorType::TemporalInvalidCalendarFieldName, next_value_string);
// 2. Return ? IteratorClose(iteratorRecord, completion). // 2. Return ? IteratorClose(iteratorRecord, completion).
return TRY(iterator_close(vm, iterator_record, move(completion))); return *TRY(iterator_close(vm, iterator_record, move(completion)));
} }
// v. Append nextValue to the end of the List fieldNames. // v. Append nextValue to the end of the List fieldNames.

View file

@ -186,7 +186,7 @@ JS::ThrowCompletionOr<JS::Value> cross_origin_get(JS::VM& vm, JS::Object const&
// 3. If IsDataDescriptor(desc) is true, then return desc.[[Value]]. // 3. If IsDataDescriptor(desc) is true, then return desc.[[Value]].
if (descriptor->is_data_descriptor()) if (descriptor->is_data_descriptor())
return descriptor->value; return *descriptor->value;
// 4. Assert: IsAccessorDescriptor(desc) is true. // 4. Assert: IsAccessorDescriptor(desc) is true.
VERIFY(descriptor->is_accessor_descriptor()); VERIFY(descriptor->is_accessor_descriptor());