ladybird/Libraries/LibJS/Runtime/PromiseResolvingElementFunctions.cpp
Andreas Kling b6bef6b688 Libraries: Use UTF-16 for JS-visible runtime strings
Produce JS-visible string results as UTF-16 at their source, including
numeric formatting, BigInt and BigFraction formatting, URI encoding,
console formatting, parser errors, regular expression errors, Intl and
Temporal records, LibUnicode locale boundaries, and LibWeb bindings.

Handle fractional radix formatting through the UTF-16 builder view.
2026-06-22 19:51:25 +02:00

219 lines
9.2 KiB
C++

/*
* Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/AggregateError.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/ExternalMemory.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseResolvingElementFunctions.h>
namespace JS {
GC_DEFINE_ALLOCATOR(RemainingElements);
GC_DEFINE_ALLOCATOR(PromiseValueList);
GC_DEFINE_ALLOCATOR(PromiseResolvingElementFunction);
GC_DEFINE_ALLOCATOR(PromiseAllResolveElementFunction);
GC_DEFINE_ALLOCATOR(PromiseAllSettledResolveElementFunction);
GC_DEFINE_ALLOCATOR(PromiseAllSettledRejectElementFunction);
GC_DEFINE_ALLOCATOR(PromiseAnyRejectElementFunction);
void PromiseValueList::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_values);
}
size_t PromiseValueList::external_memory_size() const
{
return vector_external_memory_size(m_values);
}
PromiseResolvingElementFunction::PromiseResolvingElementFunction(size_t index, PromiseValueList& values, GC::Ref<PromiseCapability const> capability, RemainingElements& remaining_elements, Object& prototype)
: NativeFunction(prototype)
, m_index(index)
, m_values(values)
, m_capability(capability)
, m_remaining_elements(remaining_elements)
{
}
void PromiseResolvingElementFunction::initialize(Realm& realm)
{
Base::initialize(realm);
define_direct_property(vm().names.length, Value(1), Attribute::Configurable);
}
ThrowCompletionOr<Value> PromiseResolvingElementFunction::call()
{
if (m_already_called)
return js_undefined();
m_already_called = true;
return resolve_element();
}
void PromiseResolvingElementFunction::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_values);
visitor.visit(m_capability);
visitor.visit(m_remaining_elements);
}
GC::Ref<PromiseAllResolveElementFunction> PromiseAllResolveElementFunction::create(Realm& realm, size_t index, PromiseValueList& values, GC::Ref<PromiseCapability const> capability, RemainingElements& remaining_elements)
{
return realm.create<PromiseAllResolveElementFunction>(index, values, capability, remaining_elements, realm.intrinsics().function_prototype());
}
PromiseAllResolveElementFunction::PromiseAllResolveElementFunction(size_t index, PromiseValueList& values, GC::Ref<PromiseCapability const> capability, RemainingElements& remaining_elements, Object& prototype)
: PromiseResolvingElementFunction(index, values, capability, remaining_elements, prototype)
{
}
ThrowCompletionOr<Value> PromiseAllResolveElementFunction::resolve_element()
{
auto& vm = this->vm();
auto& realm = *vm.current_realm();
// 8. Set values[index] to x.
m_values->values()[m_index] = vm.argument(0);
// 9. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
// 10. If remainingElementsCount.[[Value]] is 0, then
if (--m_remaining_elements->value == 0) {
// a. Let valuesArray be CreateArrayFromList(values).
auto values_array = Array::create_from(realm, m_values->values());
// b. Return ? Call(promiseCapability.[[Resolve]], undefined, « valuesArray »).
return JS::call(vm, *m_capability->resolve(), js_undefined(), values_array);
}
// 11. Return undefined.
return js_undefined();
}
GC::Ref<PromiseAllSettledResolveElementFunction> PromiseAllSettledResolveElementFunction::create(Realm& realm, size_t index, PromiseValueList& values, GC::Ref<PromiseCapability const> capability, RemainingElements& remaining_elements)
{
return realm.create<PromiseAllSettledResolveElementFunction>(index, values, capability, remaining_elements, realm.intrinsics().function_prototype());
}
PromiseAllSettledResolveElementFunction::PromiseAllSettledResolveElementFunction(size_t index, PromiseValueList& values, GC::Ref<PromiseCapability const> capability, RemainingElements& remaining_elements, Object& prototype)
: PromiseResolvingElementFunction(index, values, capability, remaining_elements, prototype)
{
}
ThrowCompletionOr<Value> PromiseAllSettledResolveElementFunction::resolve_element()
{
auto& vm = this->vm();
auto& realm = *vm.current_realm();
// 9. Let obj be OrdinaryObjectCreate(%Object.prototype%).
auto object = Object::create(realm, realm.intrinsics().object_prototype());
// 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "fulfilled").
MUST(object->create_data_property_or_throw(vm.names.status, PrimitiveString::create(vm, "fulfilled"_utf16_fly_string)));
// 11. Perform ! CreateDataPropertyOrThrow(obj, "value", x).
MUST(object->create_data_property_or_throw(vm.names.value, vm.argument(0)));
// 12. Set values[index] to obj.
m_values->values()[m_index] = object;
// 13. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
// 14. If remainingElementsCount.[[Value]] is 0, then
if (--m_remaining_elements->value == 0) {
// a. Let valuesArray be CreateArrayFromList(values).
auto values_array = Array::create_from(realm, m_values->values());
// b. Return ? Call(promiseCapability.[[Resolve]], undefined, « valuesArray »).
return JS::call(vm, *m_capability->resolve(), js_undefined(), values_array);
}
// 15. Return undefined.
return js_undefined();
}
GC::Ref<PromiseAllSettledRejectElementFunction> PromiseAllSettledRejectElementFunction::create(Realm& realm, size_t index, PromiseValueList& values, GC::Ref<PromiseCapability const> capability, RemainingElements& remaining_elements)
{
return realm.create<PromiseAllSettledRejectElementFunction>(index, values, capability, remaining_elements, realm.intrinsics().function_prototype());
}
PromiseAllSettledRejectElementFunction::PromiseAllSettledRejectElementFunction(size_t index, PromiseValueList& values, GC::Ref<PromiseCapability const> capability, RemainingElements& remaining_elements, Object& prototype)
: PromiseResolvingElementFunction(index, values, capability, remaining_elements, prototype)
{
}
ThrowCompletionOr<Value> PromiseAllSettledRejectElementFunction::resolve_element()
{
auto& vm = this->vm();
auto& realm = *vm.current_realm();
// 9. Let obj be OrdinaryObjectCreate(%Object.prototype%).
auto object = Object::create(realm, realm.intrinsics().object_prototype());
// 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "rejected").
MUST(object->create_data_property_or_throw(vm.names.status, PrimitiveString::create(vm, "rejected"_utf16_fly_string)));
// 11. Perform ! CreateDataPropertyOrThrow(obj, "reason", x).
MUST(object->create_data_property_or_throw(vm.names.reason, vm.argument(0)));
// 12. Set values[index] to obj.
m_values->values()[m_index] = object;
// 13. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
// 14. If remainingElementsCount.[[Value]] is 0, then
if (--m_remaining_elements->value == 0) {
// a. Let valuesArray be CreateArrayFromList(values).
auto values_array = Array::create_from(realm, m_values->values());
// b. Return ? Call(promiseCapability.[[Resolve]], undefined, « valuesArray »).
return JS::call(vm, *m_capability->resolve(), js_undefined(), values_array);
}
// 15. Return undefined.
return js_undefined();
}
GC::Ref<PromiseAnyRejectElementFunction> PromiseAnyRejectElementFunction::create(Realm& realm, size_t index, PromiseValueList& errors, GC::Ref<PromiseCapability const> capability, RemainingElements& remaining_elements)
{
return realm.create<PromiseAnyRejectElementFunction>(index, errors, capability, remaining_elements, realm.intrinsics().function_prototype());
}
PromiseAnyRejectElementFunction::PromiseAnyRejectElementFunction(size_t index, PromiseValueList& errors, GC::Ref<PromiseCapability const> capability, RemainingElements& remaining_elements, Object& prototype)
: PromiseResolvingElementFunction(index, errors, capability, remaining_elements, prototype)
{
}
ThrowCompletionOr<Value> PromiseAnyRejectElementFunction::resolve_element()
{
auto& vm = this->vm();
auto& realm = *vm.current_realm();
// 8. Set errors[index] to x.
m_values->values()[m_index] = vm.argument(0);
// 9. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
// 10. If remainingElementsCount.[[Value]] is 0, then
if (--m_remaining_elements->value == 0) {
// a. Let error be a newly created AggregateError object.
auto error = AggregateError::create(realm);
// b. Perform ! DefinePropertyOrThrow(error, "errors", PropertyDescriptor { [[Configurable]]: true, [[Enumerable]]: false, [[Writable]]: true, [[Value]]: CreateArrayFromList(errors) }).
auto errors_array = Array::create_from(realm, m_values->values());
PropertyDescriptor descriptor { .value = errors_array, .writable = true, .enumerable = false, .configurable = true };
MUST(error->define_property_or_throw(vm.names.errors, descriptor));
// c. Return ? Call(promiseCapability.[[Reject]], undefined, « error »).
return JS::call(vm, *m_capability->reject(), js_undefined(), error);
}
return js_undefined();
}
}