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

LibJS: Move PromiseCapability into its own cpp/h file

This is not strictly connected to PromiseReaction in any way.
Preparation before doing some actual work on it :^)
This commit is contained in:
Linus Groh 2022-10-02 10:59:22 +01:00
parent 4986fa262c
commit c2326ec95a
25 changed files with 175 additions and 144 deletions

View file

@ -29,8 +29,8 @@
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/ObjectEnvironment.h>
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/Reference.h>
#include <LibJS/Runtime/RegExpObject.h>
#include <LibJS/Runtime/Shape.h>

View file

@ -155,6 +155,7 @@ set(SOURCES
Runtime/PrimitiveString.cpp
Runtime/PrivateEnvironment.cpp
Runtime/Promise.cpp
Runtime/PromiseCapability.cpp
Runtime/PromiseConstructor.cpp
Runtime/PromiseJobs.cpp
Runtime/PromisePrototype.cpp

View file

@ -5,8 +5,9 @@
*/
#include <LibJS/CyclicModule.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/VM.h>
namespace JS {

View file

@ -10,7 +10,7 @@
#include <LibJS/Forward.h>
#include <LibJS/Module.h>
#include <LibJS/Parser.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/PromiseCapability.h>
namespace JS {

View file

@ -9,8 +9,8 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
#include <LibJS/Runtime/Promise.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/PromiseReaction.h>
namespace JS {

View file

@ -7,7 +7,7 @@
#include <LibJS/Runtime/AsyncFunctionDriverWrapper.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/VM.h>
namespace JS {

View file

@ -7,7 +7,7 @@
#pragma once
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/PromiseCapability.h>
namespace JS {

View file

@ -6,12 +6,11 @@
*/
#include <AK/TypeCasts.h>
#include <LibCore/EventLoop.h>
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/Promise.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/VM.h>
#include <LibJS/Runtime/Value.h>

View file

@ -22,8 +22,8 @@
#include <LibJS/Runtime/GeneratorObject.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/Value.h>
namespace JS {

View file

@ -12,6 +12,7 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/JobCallback.h>
#include <LibJS/Runtime/Promise.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseJobs.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/PromiseResolvingFunction.h>

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/PromiseCapability.h>
namespace JS {
// 27.2.1.5 NewPromiseCapability ( C ), https://tc39.es/ecma262/#sec-newpromisecapability
ThrowCompletionOr<PromiseCapability> new_promise_capability(VM& vm, Value constructor)
{
auto& realm = *vm.current_realm();
// 1. If IsConstructor(C) is false, throw a TypeError exception.
if (!constructor.is_constructor())
return vm.throw_completion<TypeError>(ErrorType::NotAConstructor, constructor.to_string_without_side_effects());
// 2. NOTE: C is assumed to be a constructor function that supports the parameter conventions of the Promise constructor (see 27.2.3.1).
// 3. Let promiseCapability be the PromiseCapability Record { [[Promise]]: undefined, [[Resolve]]: undefined, [[Reject]]: undefined }.
// FIXME: This should not be stack-allocated, the executor function below can be captured and outlive it!
// See https://discord.com/channels/830522505605283862/886211697843531866/900081190621569154 for some discussion.
struct {
Value resolve { js_undefined() };
Value reject { js_undefined() };
} promise_capability_functions;
// 4. Let executorClosure be a new Abstract Closure with parameters (resolve, reject) that captures promiseCapability and performs the following steps when called:
auto executor_closure = [&promise_capability_functions](auto& vm) -> ThrowCompletionOr<Value> {
auto resolve = vm.argument(0);
auto reject = vm.argument(1);
// No idea what other engines say here.
// a. If promiseCapability.[[Resolve]] is not undefined, throw a TypeError exception.
if (!promise_capability_functions.resolve.is_undefined())
return vm.template throw_completion<TypeError>(ErrorType::GetCapabilitiesExecutorCalledMultipleTimes);
// b. If promiseCapability.[[Reject]] is not undefined, throw a TypeError exception.
if (!promise_capability_functions.reject.is_undefined())
return vm.template throw_completion<TypeError>(ErrorType::GetCapabilitiesExecutorCalledMultipleTimes);
// c. Set promiseCapability.[[Resolve]] to resolve.
promise_capability_functions.resolve = resolve;
// d. Set promiseCapability.[[Reject]] to reject.
promise_capability_functions.reject = reject;
// e. Return undefined.
return js_undefined();
};
// 5. Let executor be CreateBuiltinFunction(executorClosure, 2, "", « »).
auto* executor = NativeFunction::create(realm, move(executor_closure), 2, "");
// 6. Let promise be ? Construct(C, « executor »).
auto* promise = TRY(construct(vm, constructor.as_function(), executor));
// 7. If IsCallable(promiseCapability.[[Resolve]]) is false, throw a TypeError exception.
if (!promise_capability_functions.resolve.is_function())
return vm.throw_completion<TypeError>(ErrorType::NotAFunction, promise_capability_functions.resolve.to_string_without_side_effects());
// 8. If IsCallable(promiseCapability.[[Reject]]) is false, throw a TypeError exception.
if (!promise_capability_functions.reject.is_function())
return vm.throw_completion<TypeError>(ErrorType::NotAFunction, promise_capability_functions.reject.to_string_without_side_effects());
// 9. Set promiseCapability.[[Promise]] to promise.
// 10. Return promiseCapability.
return PromiseCapability {
promise,
&promise_capability_functions.resolve.as_function(),
&promise_capability_functions.reject.as_function(),
};
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Forward.h>
#include <LibJS/Forward.h>
#include <LibJS/Runtime/AbstractOperations.h>
namespace JS {
// 27.2.1.1 PromiseCapability Records, https://tc39.es/ecma262/#sec-promisecapability-records
struct PromiseCapability {
Object* promise { nullptr };
FunctionObject* resolve { nullptr };
FunctionObject* reject { nullptr };
};
// 27.2.1.1.1 IfAbruptRejectPromise ( value, capability ), https://tc39.es/ecma262/#sec-ifabruptrejectpromise
#define __TRY_OR_REJECT(vm, capability, expression, CALL_CHECK) \
({ \
auto _temporary_try_or_reject_result = (expression); \
/* 1. If value is an abrupt completion, then */ \
if (_temporary_try_or_reject_result.is_error()) { \
/* a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). */ \
CALL_CHECK(JS::call(vm, *capability.reject, js_undefined(), *_temporary_try_or_reject_result.release_error().value())); \
\
/* b. Return capability.[[Promise]]. */ \
return capability.promise; \
} \
\
/* 2. Else if value is a Completion Record, set value to value.[[Value]]. */ \
_temporary_try_or_reject_result.release_value(); \
})
#define TRY_OR_REJECT(vm, capability, expression) \
__TRY_OR_REJECT(vm, capability, expression, TRY)
#define TRY_OR_MUST_REJECT(vm, capability, expression) \
__TRY_OR_REJECT(vm, capability, expression, MUST)
// 27.2.1.1.1 IfAbruptRejectPromise ( value, capability ), https://tc39.es/ecma262/#sec-ifabruptrejectpromise
#define TRY_OR_REJECT_WITH_VALUE(vm, capability, expression) \
({ \
auto _temporary_try_or_reject_result = (expression); \
/* 1. If value is an abrupt completion, then */ \
if (_temporary_try_or_reject_result.is_error()) { \
/* a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). */ \
TRY(JS::call(vm, *capability.reject, js_undefined(), *_temporary_try_or_reject_result.release_error().value())); \
\
/* b. Return capability.[[Promise]]. */ \
return Value { capability.promise }; \
} \
\
/* 2. Else if value is a Completion Record, set value to value.[[Value]]. */ \
_temporary_try_or_reject_result.release_value(); \
})
// 27.2.1.5 NewPromiseCapability ( C ), https://tc39.es/ecma262/#sec-newpromisecapability
ThrowCompletionOr<PromiseCapability> new_promise_capability(VM& vm, Value constructor);
}

View file

@ -14,8 +14,8 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
#include <LibJS/Runtime/Promise.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/PromiseResolvingElementFunctions.h>
namespace JS {

View file

@ -10,6 +10,7 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/JobCallback.h>
#include <LibJS/Runtime/Promise.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseJobs.h>
#include <LibJS/Runtime/PromiseReaction.h>

View file

@ -10,9 +10,9 @@
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Promise.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/PromisePrototype.h>
#include <LibJS/Runtime/PromiseReaction.h>
namespace JS {

View file

@ -4,77 +4,15 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/VM.h>
namespace JS {
// 27.2.1.5 NewPromiseCapability ( C ), https://tc39.es/ecma262/#sec-newpromisecapability
ThrowCompletionOr<PromiseCapability> new_promise_capability(VM& vm, Value constructor)
PromiseReaction* PromiseReaction::create(VM& vm, Type type, Optional<PromiseCapability> capability, Optional<JobCallback> handler)
{
auto& realm = *vm.current_realm();
// 1. If IsConstructor(C) is false, throw a TypeError exception.
if (!constructor.is_constructor())
return vm.throw_completion<TypeError>(ErrorType::NotAConstructor, constructor.to_string_without_side_effects());
// 2. NOTE: C is assumed to be a constructor function that supports the parameter conventions of the Promise constructor (see 27.2.3.1).
// 3. Let promiseCapability be the PromiseCapability Record { [[Promise]]: undefined, [[Resolve]]: undefined, [[Reject]]: undefined }.
// FIXME: This should not be stack-allocated, the executor function below can be captured and outlive it!
// See https://discord.com/channels/830522505605283862/886211697843531866/900081190621569154 for some discussion.
struct {
Value resolve { js_undefined() };
Value reject { js_undefined() };
} promise_capability_functions;
// 4. Let executorClosure be a new Abstract Closure with parameters (resolve, reject) that captures promiseCapability and performs the following steps when called:
auto executor_closure = [&promise_capability_functions](auto& vm) -> ThrowCompletionOr<Value> {
auto resolve = vm.argument(0);
auto reject = vm.argument(1);
// No idea what other engines say here.
// a. If promiseCapability.[[Resolve]] is not undefined, throw a TypeError exception.
if (!promise_capability_functions.resolve.is_undefined())
return vm.template throw_completion<TypeError>(ErrorType::GetCapabilitiesExecutorCalledMultipleTimes);
// b. If promiseCapability.[[Reject]] is not undefined, throw a TypeError exception.
if (!promise_capability_functions.reject.is_undefined())
return vm.template throw_completion<TypeError>(ErrorType::GetCapabilitiesExecutorCalledMultipleTimes);
// c. Set promiseCapability.[[Resolve]] to resolve.
promise_capability_functions.resolve = resolve;
// d. Set promiseCapability.[[Reject]] to reject.
promise_capability_functions.reject = reject;
// e. Return undefined.
return js_undefined();
};
// 5. Let executor be CreateBuiltinFunction(executorClosure, 2, "", « »).
auto* executor = NativeFunction::create(realm, move(executor_closure), 2, "");
// 6. Let promise be ? Construct(C, « executor »).
auto* promise = TRY(construct(vm, constructor.as_function(), executor));
// 7. If IsCallable(promiseCapability.[[Resolve]]) is false, throw a TypeError exception.
if (!promise_capability_functions.resolve.is_function())
return vm.throw_completion<TypeError>(ErrorType::NotAFunction, promise_capability_functions.resolve.to_string_without_side_effects());
// 8. If IsCallable(promiseCapability.[[Reject]]) is false, throw a TypeError exception.
if (!promise_capability_functions.reject.is_function())
return vm.throw_completion<TypeError>(ErrorType::NotAFunction, promise_capability_functions.reject.to_string_without_side_effects());
// 9. Set promiseCapability.[[Promise]] to promise.
// 10. Return promiseCapability.
return PromiseCapability {
promise,
&promise_capability_functions.resolve.as_function(),
&promise_capability_functions.reject.as_function(),
};
return vm.heap().allocate_without_realm<PromiseReaction>(type, move(capability), move(handler));
}
PromiseReaction::PromiseReaction(Type type, Optional<PromiseCapability> capability, Optional<JobCallback> handler)

View file

@ -6,63 +6,13 @@
#pragma once
#include <AK/StringView.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <AK/Forward.h>
#include <LibJS/Forward.h>
#include <LibJS/Heap/Cell.h>
#include <LibJS/Runtime/JobCallback.h>
#include <LibJS/Runtime/VM.h>
namespace JS {
// 27.2.1.1 PromiseCapability Records, https://tc39.es/ecma262/#sec-promisecapability-records
struct PromiseCapability {
Object* promise { nullptr };
FunctionObject* resolve { nullptr };
FunctionObject* reject { nullptr };
};
// 27.2.1.1.1 IfAbruptRejectPromise ( value, capability ), https://tc39.es/ecma262/#sec-ifabruptrejectpromise
#define __TRY_OR_REJECT(vm, capability, expression, CALL_CHECK) \
({ \
auto _temporary_try_or_reject_result = (expression); \
/* 1. If value is an abrupt completion, then */ \
if (_temporary_try_or_reject_result.is_error()) { \
/* a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). */ \
CALL_CHECK(JS::call(vm, *capability.reject, js_undefined(), *_temporary_try_or_reject_result.release_error().value())); \
\
/* b. Return capability.[[Promise]]. */ \
return capability.promise; \
} \
\
/* 2. Else if value is a Completion Record, set value to value.[[Value]]. */ \
_temporary_try_or_reject_result.release_value(); \
})
#define TRY_OR_REJECT(vm, capability, expression) \
__TRY_OR_REJECT(vm, capability, expression, TRY)
#define TRY_OR_MUST_REJECT(vm, capability, expression) \
__TRY_OR_REJECT(vm, capability, expression, MUST)
// 27.2.1.1.1 IfAbruptRejectPromise ( value, capability ), https://tc39.es/ecma262/#sec-ifabruptrejectpromise
#define TRY_OR_REJECT_WITH_VALUE(vm, capability, expression) \
({ \
auto _temporary_try_or_reject_result = (expression); \
/* 1. If value is an abrupt completion, then */ \
if (_temporary_try_or_reject_result.is_error()) { \
/* a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). */ \
TRY(JS::call(vm, *capability.reject, js_undefined(), *_temporary_try_or_reject_result.release_error().value())); \
\
/* b. Return capability.[[Promise]]. */ \
return Value { capability.promise }; \
} \
\
/* 2. Else if value is a Completion Record, set value to value.[[Value]]. */ \
_temporary_try_or_reject_result.release_value(); \
})
// 27.2.1.5 NewPromiseCapability ( C ), https://tc39.es/ecma262/#sec-newpromisecapability
ThrowCompletionOr<PromiseCapability> new_promise_capability(VM& vm, Value constructor);
// 27.2.1.2 PromiseReaction Records, https://tc39.es/ecma262/#sec-promisereaction-records
class PromiseReaction final : public Cell {
JS_CELL(PromiseReaction, Cell);
@ -73,10 +23,7 @@ public:
Reject,
};
static PromiseReaction* create(VM& vm, Type type, Optional<PromiseCapability> capability, Optional<JobCallback> handler)
{
return vm.heap().allocate_without_realm<PromiseReaction>(type, capability, move(handler));
}
static PromiseReaction* create(VM& vm, Type type, Optional<PromiseCapability> capability, Optional<JobCallback> handler);
virtual ~PromiseReaction() = default;

View file

@ -8,7 +8,7 @@
#include <LibJS/Runtime/AggregateError.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseResolvingElementFunctions.h>
namespace JS {

View file

@ -8,7 +8,7 @@
#include <AK/StringView.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/PromiseCapability.h>
namespace JS {

View file

@ -12,8 +12,8 @@
#include <LibJS/Runtime/GlobalEnvironment.h>
#include <LibJS/Runtime/ModuleNamespaceObject.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/ShadowRealm.h>
#include <LibJS/Runtime/WrappedFunction.h>

View file

@ -20,10 +20,9 @@
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/FinalizationRegistry.h>
#include <LibJS/Runtime/FunctionEnvironment.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/Reference.h>
#include <LibJS/Runtime/Symbol.h>
#include <LibJS/Runtime/VM.h>

View file

@ -6,7 +6,7 @@
#include <LibJS/Runtime/ArrayBuffer.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/Fetch/Body.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
#include <LibWeb/WebIDL/Promise.h>

View file

@ -5,6 +5,7 @@
*/
#include <AK/Function.h>
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>

View file

@ -7,8 +7,6 @@
#pragma once
#include <LibJS/Forward.h>
#include <LibJS/Runtime/PromiseReaction.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/SafeFunction.h>
#include <LibWeb/Forward.h>