mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:47:36 +00:00
LibJS: Convert NativeFunction callback to ThrowCompletionOr
This commit is contained in:
parent
20163c0584
commit
ca27e5eff5
13 changed files with 91 additions and 65 deletions
|
@ -201,8 +201,7 @@ void GlobalObject::initialize_global_object()
|
||||||
|
|
||||||
// 10.2.4.1 %ThrowTypeError% ( ), https://tc39.es/ecma262/#sec-%throwtypeerror%
|
// 10.2.4.1 %ThrowTypeError% ( ), https://tc39.es/ecma262/#sec-%throwtypeerror%
|
||||||
m_throw_type_error_function = NativeFunction::create(global_object(), {}, [](VM& vm, GlobalObject& global_object) {
|
m_throw_type_error_function = NativeFunction::create(global_object(), {}, [](VM& vm, GlobalObject& global_object) {
|
||||||
vm.throw_exception<TypeError>(global_object, ErrorType::RestrictedFunctionPropertiesAccess);
|
return vm.throw_completion<TypeError>(global_object, ErrorType::RestrictedFunctionPropertiesAccess);
|
||||||
return Value();
|
|
||||||
});
|
});
|
||||||
m_throw_type_error_function->define_direct_property(vm.names.length, Value(0), 0);
|
m_throw_type_error_function->define_direct_property(vm.names.length, Value(0), 0);
|
||||||
m_throw_type_error_function->define_direct_property(vm.names.name, js_string(vm, ""), 0);
|
m_throw_type_error_function->define_direct_property(vm.names.name, js_string(vm, ""), 0);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
NativeFunction* NativeFunction::create(GlobalObject& global_object, const FlyString& name, Function<Value(VM&, GlobalObject&)> function)
|
NativeFunction* NativeFunction::create(GlobalObject& global_object, const FlyString& name, Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)> function)
|
||||||
{
|
{
|
||||||
return global_object.heap().allocate<NativeFunction>(global_object, name, move(function), *global_object.function_prototype());
|
return global_object.heap().allocate<NativeFunction>(global_object, name, move(function), *global_object.function_prototype());
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ NativeFunction::NativeFunction(Object& prototype)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeFunction::NativeFunction(FlyString name, Function<Value(VM&, GlobalObject&)> native_function, Object& prototype)
|
NativeFunction::NativeFunction(FlyString name, Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)> native_function, Object& prototype)
|
||||||
: FunctionObject(prototype)
|
: FunctionObject(prototype)
|
||||||
, m_name(move(name))
|
, m_name(move(name))
|
||||||
, m_native_function(move(native_function))
|
, m_native_function(move(native_function))
|
||||||
|
@ -186,7 +186,7 @@ ThrowCompletionOr<Object*> NativeFunction::internal_construct(MarkedValueList ar
|
||||||
|
|
||||||
Value NativeFunction::call()
|
Value NativeFunction::call()
|
||||||
{
|
{
|
||||||
return m_native_function(vm(), global_object());
|
return TRY_OR_DISCARD(m_native_function(vm(), global_object()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Value NativeFunction::construct(FunctionObject&)
|
Value NativeFunction::construct(FunctionObject&)
|
||||||
|
|
|
@ -15,9 +15,9 @@ class NativeFunction : public FunctionObject {
|
||||||
JS_OBJECT(NativeFunction, FunctionObject);
|
JS_OBJECT(NativeFunction, FunctionObject);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static NativeFunction* create(GlobalObject&, const FlyString& name, Function<Value(VM&, GlobalObject&)>);
|
static NativeFunction* create(GlobalObject&, const FlyString& name, Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)>);
|
||||||
|
|
||||||
explicit NativeFunction(FlyString name, Function<Value(VM&, GlobalObject&)>, Object& prototype);
|
explicit NativeFunction(FlyString name, Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)>, Object& prototype);
|
||||||
virtual void initialize(GlobalObject&) override { }
|
virtual void initialize(GlobalObject&) override { }
|
||||||
virtual ~NativeFunction() override;
|
virtual ~NativeFunction() override;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ private:
|
||||||
virtual bool is_native_function() const final { return true; }
|
virtual bool is_native_function() const final { return true; }
|
||||||
|
|
||||||
FlyString m_name;
|
FlyString m_name;
|
||||||
Function<Value(VM&, GlobalObject&)> m_native_function;
|
Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)> m_native_function;
|
||||||
Realm* m_realm { nullptr };
|
Realm* m_realm { nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -951,6 +951,29 @@ void Object::set_prototype(Object* new_prototype)
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::define_native_accessor(PropertyName const& property_name, Function<Value(VM&, GlobalObject&)> getter, Function<Value(VM&, GlobalObject&)> setter, PropertyAttributes attribute)
|
void Object::define_native_accessor(PropertyName const& property_name, Function<Value(VM&, GlobalObject&)> getter, Function<Value(VM&, GlobalObject&)> setter, PropertyAttributes attribute)
|
||||||
|
{
|
||||||
|
Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)> completion_getter = {};
|
||||||
|
if (getter) {
|
||||||
|
completion_getter = [getter = move(getter)](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
|
||||||
|
auto result = getter(vm, global_object);
|
||||||
|
if (auto* exception = vm.exception())
|
||||||
|
return throw_completion(exception->value());
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)> completion_setter = {};
|
||||||
|
if (setter) {
|
||||||
|
completion_setter = [setter = move(setter)](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
|
||||||
|
auto result = setter(vm, global_object);
|
||||||
|
if (auto* exception = vm.exception())
|
||||||
|
return throw_completion(exception->value());
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
define_new_native_accessor(property_name, move(completion_getter), move(completion_setter), attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Object::define_new_native_accessor(PropertyName const& property_name, Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)> getter, Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)> setter, PropertyAttributes attribute)
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
String formatted_property_name;
|
String formatted_property_name;
|
||||||
|
@ -1017,6 +1040,17 @@ Value Object::get_without_side_effects(const PropertyName& property_name) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::define_native_function(PropertyName const& property_name, Function<Value(VM&, GlobalObject&)> native_function, i32 length, PropertyAttributes attribute)
|
void Object::define_native_function(PropertyName const& property_name, Function<Value(VM&, GlobalObject&)> native_function, i32 length, PropertyAttributes attribute)
|
||||||
|
{
|
||||||
|
auto completion_native_function = [native_function = move(native_function), property_name](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
|
||||||
|
auto result = native_function(vm, global_object);
|
||||||
|
if (auto* exception = vm.exception())
|
||||||
|
return throw_completion(exception->value());
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
define_new_native_function(property_name, move(completion_native_function), length, attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Object::define_new_native_function(PropertyName const& property_name, Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)> native_function, i32 length, PropertyAttributes attribute)
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
String function_name;
|
String function_name;
|
||||||
|
|
|
@ -128,9 +128,13 @@ public:
|
||||||
void define_direct_property(PropertyName const& property_name, Value value, PropertyAttributes attributes) { storage_set(property_name, { value, attributes }); };
|
void define_direct_property(PropertyName const& property_name, Value value, PropertyAttributes attributes) { storage_set(property_name, { value, attributes }); };
|
||||||
void define_direct_accessor(PropertyName const&, FunctionObject* getter, FunctionObject* setter, PropertyAttributes attributes);
|
void define_direct_accessor(PropertyName const&, FunctionObject* getter, FunctionObject* setter, PropertyAttributes attributes);
|
||||||
|
|
||||||
|
// Legacy methods - Remove once JS_DECLARE_OLD_NATIVE_FUNCTION is removed
|
||||||
void define_native_function(PropertyName const&, Function<Value(VM&, GlobalObject&)>, i32 length, PropertyAttributes attributes);
|
void define_native_function(PropertyName const&, Function<Value(VM&, GlobalObject&)>, i32 length, PropertyAttributes attributes);
|
||||||
void define_native_accessor(PropertyName const&, Function<Value(VM&, GlobalObject&)> getter, Function<Value(VM&, GlobalObject&)> setter, PropertyAttributes attributes);
|
void define_native_accessor(PropertyName const&, Function<Value(VM&, GlobalObject&)> getter, Function<Value(VM&, GlobalObject&)> setter, PropertyAttributes attributes);
|
||||||
|
|
||||||
|
void define_new_native_function(PropertyName const&, Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)>, i32 length, PropertyAttributes attributes);
|
||||||
|
void define_new_native_accessor(PropertyName const&, Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)> getter, Function<ThrowCompletionOr<Value>(VM&, GlobalObject&)> setter, PropertyAttributes attributes);
|
||||||
|
|
||||||
virtual bool is_function() const { return false; }
|
virtual bool is_function() const { return false; }
|
||||||
virtual bool is_typed_array() const { return false; }
|
virtual bool is_typed_array() const { return false; }
|
||||||
virtual bool is_string_object() const { return false; }
|
virtual bool is_string_object() const { return false; }
|
||||||
|
|
|
@ -72,7 +72,7 @@ static void set_iterator_record_complete(GlobalObject& global_object, Object& it
|
||||||
MUST(iterator_record.set(vm.names.done, Value(true), Object::ShouldThrowExceptions::No));
|
MUST(iterator_record.set(vm.names.done, Value(true), Object::ShouldThrowExceptions::No));
|
||||||
}
|
}
|
||||||
|
|
||||||
using EndOfElementsCallback = Function<Value(PromiseValueList&)>;
|
using EndOfElementsCallback = Function<ThrowCompletionOr<Value>(PromiseValueList&)>;
|
||||||
using InvokeElementFunctionCallback = Function<void(PromiseValueList&, RemainingElements&, Value, size_t)>;
|
using InvokeElementFunctionCallback = Function<void(PromiseValueList&, RemainingElements&, Value, size_t)>;
|
||||||
|
|
||||||
static Value perform_promise_common(GlobalObject& global_object, Object& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve, EndOfElementsCallback end_of_list, InvokeElementFunctionCallback invoke_element_function)
|
static Value perform_promise_common(GlobalObject& global_object, Object& iterator_record, Value constructor, PromiseCapability result_capability, Value promise_resolve, EndOfElementsCallback end_of_list, InvokeElementFunctionCallback invoke_element_function)
|
||||||
|
@ -99,7 +99,7 @@ static Value perform_promise_common(GlobalObject& global_object, Object& iterato
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (--remaining_elements_count->value == 0)
|
if (--remaining_elements_count->value == 0)
|
||||||
return end_of_list(*values);
|
return TRY_OR_DISCARD(end_of_list(*values));
|
||||||
return result_capability.promise;
|
return result_capability.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,14 +130,12 @@ static Value perform_promise_all(GlobalObject& global_object, Object& iterator_r
|
||||||
|
|
||||||
return perform_promise_common(
|
return perform_promise_common(
|
||||||
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
||||||
[&](PromiseValueList& values) -> Value {
|
[&](PromiseValueList& values) -> ThrowCompletionOr<Value> {
|
||||||
auto values_array = Array::create_from(global_object, values.values());
|
auto values_array = Array::create_from(global_object, values.values());
|
||||||
|
|
||||||
(void)vm.call(*result_capability.resolve, js_undefined(), values_array);
|
TRY(vm.call(*result_capability.resolve, js_undefined(), values_array));
|
||||||
if (vm.exception())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return result_capability.promise;
|
return Value(result_capability.promise);
|
||||||
},
|
},
|
||||||
[&](PromiseValueList& values, RemainingElements& remaining_elements_count, Value next_promise, size_t index) {
|
[&](PromiseValueList& values, RemainingElements& remaining_elements_count, Value next_promise, size_t index) {
|
||||||
auto* on_fulfilled = PromiseAllResolveElementFunction::create(global_object, index, values, result_capability, remaining_elements_count);
|
auto* on_fulfilled = PromiseAllResolveElementFunction::create(global_object, index, values, result_capability, remaining_elements_count);
|
||||||
|
@ -154,14 +152,12 @@ static Value perform_promise_all_settled(GlobalObject& global_object, Object& it
|
||||||
|
|
||||||
return perform_promise_common(
|
return perform_promise_common(
|
||||||
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
||||||
[&](PromiseValueList& values) -> Value {
|
[&](PromiseValueList& values) -> ThrowCompletionOr<Value> {
|
||||||
auto values_array = Array::create_from(global_object, values.values());
|
auto values_array = Array::create_from(global_object, values.values());
|
||||||
|
|
||||||
(void)vm.call(*result_capability.resolve, js_undefined(), values_array);
|
TRY(vm.call(*result_capability.resolve, js_undefined(), values_array));
|
||||||
if (vm.exception())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return result_capability.promise;
|
return Value(result_capability.promise);
|
||||||
},
|
},
|
||||||
[&](PromiseValueList& values, RemainingElements& remaining_elements_count, Value next_promise, size_t index) {
|
[&](PromiseValueList& values, RemainingElements& remaining_elements_count, Value next_promise, size_t index) {
|
||||||
auto* on_fulfilled = PromiseAllSettledResolveElementFunction::create(global_object, index, values, result_capability, remaining_elements_count);
|
auto* on_fulfilled = PromiseAllSettledResolveElementFunction::create(global_object, index, values, result_capability, remaining_elements_count);
|
||||||
|
@ -181,14 +177,14 @@ static Value perform_promise_any(GlobalObject& global_object, Object& iterator_r
|
||||||
|
|
||||||
return perform_promise_common(
|
return perform_promise_common(
|
||||||
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
||||||
[&](PromiseValueList& errors) -> Value {
|
[&](PromiseValueList& errors) -> ThrowCompletionOr<Value> {
|
||||||
auto errors_array = Array::create_from(global_object, errors.values());
|
auto errors_array = Array::create_from(global_object, errors.values());
|
||||||
|
|
||||||
auto* error = AggregateError::create(global_object);
|
auto* error = AggregateError::create(global_object);
|
||||||
MUST(error->define_property_or_throw(vm.names.errors, { .value = errors_array, .writable = true, .enumerable = false, .configurable = true }));
|
MUST(error->define_property_or_throw(vm.names.errors, { .value = errors_array, .writable = true, .enumerable = false, .configurable = true }));
|
||||||
|
|
||||||
vm.throw_exception(global_object, error);
|
vm.throw_exception(global_object, error);
|
||||||
return {};
|
return throw_completion(error);
|
||||||
},
|
},
|
||||||
[&](PromiseValueList& errors, RemainingElements& remaining_elements_count, Value next_promise, size_t index) {
|
[&](PromiseValueList& errors, RemainingElements& remaining_elements_count, Value next_promise, size_t index) {
|
||||||
auto* on_rejected = PromiseAnyRejectElementFunction::create(global_object, index, errors, result_capability, remaining_elements_count);
|
auto* on_rejected = PromiseAnyRejectElementFunction::create(global_object, index, errors, result_capability, remaining_elements_count);
|
||||||
|
@ -205,8 +201,8 @@ static Value perform_promise_race(GlobalObject& global_object, Object& iterator_
|
||||||
|
|
||||||
return perform_promise_common(
|
return perform_promise_common(
|
||||||
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
global_object, iterator_record, constructor, result_capability, promise_resolve,
|
||||||
[&](PromiseValueList&) -> Value {
|
[&](PromiseValueList&) -> ThrowCompletionOr<Value> {
|
||||||
return result_capability.promise;
|
return Value(result_capability.promise);
|
||||||
},
|
},
|
||||||
[&](PromiseValueList&, RemainingElements&, Value next_promise, size_t) {
|
[&](PromiseValueList&, RemainingElements&, Value next_promise, size_t) {
|
||||||
(void)next_promise.invoke(global_object, vm.names.then, result_capability.resolve, result_capability.reject);
|
(void)next_promise.invoke(global_object, vm.names.then, result_capability.resolve, result_capability.reject);
|
||||||
|
|
|
@ -69,35 +69,35 @@ JS_DEFINE_OLD_NATIVE_FUNCTION(PromisePrototype::finally)
|
||||||
catch_finally = on_finally;
|
catch_finally = on_finally;
|
||||||
} else {
|
} else {
|
||||||
// 27.2.5.3.1 Then Finally Functions, https://tc39.es/ecma262/#sec-thenfinallyfunctions
|
// 27.2.5.3.1 Then Finally Functions, https://tc39.es/ecma262/#sec-thenfinallyfunctions
|
||||||
auto* then_finally_function = NativeFunction::create(global_object, "", [constructor_handle = make_handle(constructor), on_finally_handle = make_handle(&on_finally.as_function())](auto& vm, auto& global_object) -> Value {
|
auto* then_finally_function = NativeFunction::create(global_object, "", [constructor_handle = make_handle(constructor), on_finally_handle = make_handle(&on_finally.as_function())](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
|
||||||
auto& constructor = const_cast<FunctionObject&>(*constructor_handle.cell());
|
auto& constructor = const_cast<FunctionObject&>(*constructor_handle.cell());
|
||||||
auto& on_finally = const_cast<FunctionObject&>(*on_finally_handle.cell());
|
auto& on_finally = const_cast<FunctionObject&>(*on_finally_handle.cell());
|
||||||
auto value = vm.argument(0);
|
auto value = vm.argument(0);
|
||||||
auto result = TRY_OR_DISCARD(vm.call(on_finally, js_undefined()));
|
auto result = TRY(vm.call(on_finally, js_undefined()));
|
||||||
auto* promise = promise_resolve(global_object, constructor, result);
|
auto* promise = promise_resolve(global_object, constructor, result);
|
||||||
if (vm.exception())
|
if (auto* exception = vm.exception())
|
||||||
return {};
|
return throw_completion(exception->value());
|
||||||
auto* value_thunk = NativeFunction::create(global_object, "", [value](auto&, auto&) -> Value {
|
auto* value_thunk = NativeFunction::create(global_object, "", [value](auto&, auto&) -> ThrowCompletionOr<Value> {
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
return TRY_OR_DISCARD(Value(promise).invoke(global_object, vm.names.then, value_thunk));
|
return TRY(Value(promise).invoke(global_object, vm.names.then, value_thunk));
|
||||||
});
|
});
|
||||||
then_finally_function->define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
then_finally_function->define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
||||||
|
|
||||||
// 27.2.5.3.2 Catch Finally Functions, https://tc39.es/ecma262/#sec-catchfinallyfunctions
|
// 27.2.5.3.2 Catch Finally Functions, https://tc39.es/ecma262/#sec-catchfinallyfunctions
|
||||||
auto* catch_finally_function = NativeFunction::create(global_object, "", [constructor_handle = make_handle(constructor), on_finally_handle = make_handle(&on_finally.as_function())](auto& vm, auto& global_object) -> Value {
|
auto* catch_finally_function = NativeFunction::create(global_object, "", [constructor_handle = make_handle(constructor), on_finally_handle = make_handle(&on_finally.as_function())](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
|
||||||
auto& constructor = const_cast<FunctionObject&>(*constructor_handle.cell());
|
auto& constructor = const_cast<FunctionObject&>(*constructor_handle.cell());
|
||||||
auto& on_finally = const_cast<FunctionObject&>(*on_finally_handle.cell());
|
auto& on_finally = const_cast<FunctionObject&>(*on_finally_handle.cell());
|
||||||
auto reason = vm.argument(0);
|
auto reason = vm.argument(0);
|
||||||
auto result = TRY_OR_DISCARD(vm.call(on_finally, js_undefined()));
|
auto result = TRY(vm.call(on_finally, js_undefined()));
|
||||||
auto* promise = promise_resolve(global_object, constructor, result);
|
auto* promise = promise_resolve(global_object, constructor, result);
|
||||||
if (vm.exception())
|
if (auto* exception = vm.exception())
|
||||||
return {};
|
return throw_completion(exception->value());
|
||||||
auto* thrower = NativeFunction::create(global_object, "", [reason](auto& vm, auto& global_object) -> Value {
|
auto* thrower = NativeFunction::create(global_object, "", [reason](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
|
||||||
vm.throw_exception(global_object, reason);
|
vm.throw_exception(global_object, reason);
|
||||||
return {};
|
return throw_completion(reason);
|
||||||
});
|
});
|
||||||
return TRY_OR_DISCARD(Value(promise).invoke(global_object, vm.names.then, thrower));
|
return TRY(Value(promise).invoke(global_object, vm.names.then, thrower));
|
||||||
});
|
});
|
||||||
catch_finally_function->define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
catch_finally_function->define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
||||||
|
|
||||||
|
|
|
@ -26,17 +26,15 @@ PromiseCapability new_promise_capability(GlobalObject& global_object, Value cons
|
||||||
} promise_capability_functions;
|
} promise_capability_functions;
|
||||||
|
|
||||||
// 27.2.1.5.1 GetCapabilitiesExecutor Functions, https://tc39.es/ecma262/#sec-getcapabilitiesexecutor-functions
|
// 27.2.1.5.1 GetCapabilitiesExecutor Functions, https://tc39.es/ecma262/#sec-getcapabilitiesexecutor-functions
|
||||||
auto* executor = NativeFunction::create(global_object, "", [&promise_capability_functions](auto& vm, auto& global_object) -> Value {
|
auto* executor = NativeFunction::create(global_object, "", [&promise_capability_functions](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
|
||||||
auto resolve = vm.argument(0);
|
auto resolve = vm.argument(0);
|
||||||
auto reject = vm.argument(1);
|
auto reject = vm.argument(1);
|
||||||
// No idea what other engines say here.
|
// No idea what other engines say here.
|
||||||
if (!promise_capability_functions.resolve.is_undefined()) {
|
if (!promise_capability_functions.resolve.is_undefined()) {
|
||||||
vm.template throw_exception<TypeError>(global_object, ErrorType::GetCapabilitiesExecutorCalledMultipleTimes);
|
return vm.template throw_completion<TypeError>(global_object, ErrorType::GetCapabilitiesExecutorCalledMultipleTimes);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
if (!promise_capability_functions.reject.is_undefined()) {
|
if (!promise_capability_functions.reject.is_undefined()) {
|
||||||
vm.template throw_exception<TypeError>(global_object, ErrorType::GetCapabilitiesExecutorCalledMultipleTimes);
|
return vm.template throw_completion<TypeError>(global_object, ErrorType::GetCapabilitiesExecutorCalledMultipleTimes);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
promise_capability_functions.resolve = resolve;
|
promise_capability_functions.resolve = resolve;
|
||||||
promise_capability_functions.reject = reject;
|
promise_capability_functions.reject = reject;
|
||||||
|
|
|
@ -32,7 +32,7 @@ void PromiseResolvingFunction::initialize(GlobalObject& global_object)
|
||||||
|
|
||||||
Value PromiseResolvingFunction::call()
|
Value PromiseResolvingFunction::call()
|
||||||
{
|
{
|
||||||
return m_native_function(vm(), global_object(), m_promise, m_already_resolved);
|
return TRY_OR_DISCARD(m_native_function(vm(), global_object(), m_promise, m_already_resolved));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PromiseResolvingFunction::visit_edges(Cell::Visitor& visitor)
|
void PromiseResolvingFunction::visit_edges(Cell::Visitor& visitor)
|
||||||
|
|
|
@ -25,7 +25,7 @@ class PromiseResolvingFunction final : public NativeFunction {
|
||||||
JS_OBJECT(PromiseResolvingFunction, NativeFunction);
|
JS_OBJECT(PromiseResolvingFunction, NativeFunction);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using FunctionType = Function<Value(VM&, GlobalObject&, Promise&, AlreadyResolved&)>;
|
using FunctionType = Function<ThrowCompletionOr<Value>(VM&, GlobalObject&, Promise&, AlreadyResolved&)>;
|
||||||
|
|
||||||
static PromiseResolvingFunction* create(GlobalObject&, Promise&, AlreadyResolved&, FunctionType);
|
static PromiseResolvingFunction* create(GlobalObject&, Promise&, AlreadyResolved&, FunctionType);
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ JS_DEFINE_OLD_NATIVE_FUNCTION(ProxyConstructor::revocable)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
// 28.2.2.1.1 Proxy Revocation Functions, https://tc39.es/ecma262/#sec-proxy-revocation-functions
|
// 28.2.2.1.1 Proxy Revocation Functions, https://tc39.es/ecma262/#sec-proxy-revocation-functions
|
||||||
auto* revoker = NativeFunction::create(global_object, "", [proxy_handle = make_handle(proxy)](auto&, auto&) -> Value {
|
auto* revoker = NativeFunction::create(global_object, "", [proxy_handle = make_handle(proxy)](auto&, auto&) -> ThrowCompletionOr<Value> {
|
||||||
auto& proxy = const_cast<ProxyObject&>(*proxy_handle.cell());
|
auto& proxy = const_cast<ProxyObject&>(*proxy_handle.cell());
|
||||||
if (proxy.is_revoked())
|
if (proxy.is_revoked())
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
|
|
|
@ -184,11 +184,11 @@ ThrowCompletionOr<Value> shadow_realm_import_value(GlobalObject& global_object,
|
||||||
|
|
||||||
// FinishDynamicImport, 5. Perform ! PerformPromiseThen(innerPromise, onFulfilled, onRejected).
|
// FinishDynamicImport, 5. Perform ! PerformPromiseThen(innerPromise, onFulfilled, onRejected).
|
||||||
promise->perform_then(
|
promise->perform_then(
|
||||||
NativeFunction::create(global_object, "", [](auto&, auto&) -> Value {
|
NativeFunction::create(global_object, "", [](auto&, auto&) -> ThrowCompletionOr<Value> {
|
||||||
// Not called because we hardcoded a rejection above.
|
// Not called because we hardcoded a rejection above.
|
||||||
TODO();
|
TODO();
|
||||||
}),
|
}),
|
||||||
NativeFunction::create(global_object, "", [reject = make_handle(inner_capability.reject)](auto& vm, auto& global_object) -> Value {
|
NativeFunction::create(global_object, "", [reject = make_handle(inner_capability.reject)](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
|
||||||
auto error = vm.argument(0);
|
auto error = vm.argument(0);
|
||||||
|
|
||||||
// a. Perform ! Call(promiseCapability.[[Reject]], undefined, « error »).
|
// a. Perform ! Call(promiseCapability.[[Reject]], undefined, « error »).
|
||||||
|
@ -214,7 +214,7 @@ ThrowCompletionOr<Value> shadow_realm_import_value(GlobalObject& global_object,
|
||||||
auto* on_fulfilled = NativeFunction::create(
|
auto* on_fulfilled = NativeFunction::create(
|
||||||
global_object,
|
global_object,
|
||||||
"",
|
"",
|
||||||
[string = move(export_name_string)](auto& vm, auto& global_object) -> Value {
|
[string = move(export_name_string)](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
|
||||||
// 1. Assert: exports is a module namespace exotic object.
|
// 1. Assert: exports is a module namespace exotic object.
|
||||||
auto& exports = vm.argument(0).as_object();
|
auto& exports = vm.argument(0).as_object();
|
||||||
|
|
||||||
|
@ -225,23 +225,21 @@ ThrowCompletionOr<Value> shadow_realm_import_value(GlobalObject& global_object,
|
||||||
// 4. Assert: Type(string) is String.
|
// 4. Assert: Type(string) is String.
|
||||||
|
|
||||||
// 5. Let hasOwn be ? HasOwnProperty(exports, string).
|
// 5. Let hasOwn be ? HasOwnProperty(exports, string).
|
||||||
auto has_own = TRY_OR_DISCARD(exports.has_own_property(string));
|
auto has_own = TRY(exports.has_own_property(string));
|
||||||
|
|
||||||
// 6. If hasOwn is false, throw a TypeError exception.
|
// 6. If hasOwn is false, throw a TypeError exception.
|
||||||
if (!has_own) {
|
if (!has_own)
|
||||||
vm.template throw_exception<TypeError>(global_object, ErrorType::MissingRequiredProperty, string);
|
return vm.template throw_completion<TypeError>(global_object, ErrorType::MissingRequiredProperty, string);
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 7. Let value be ? Get(exports, string).
|
// 7. Let value be ? Get(exports, string).
|
||||||
auto value = TRY_OR_DISCARD(exports.get(string));
|
auto value = TRY(exports.get(string));
|
||||||
|
|
||||||
// 8. Let realm be f.[[Realm]].
|
// 8. Let realm be f.[[Realm]].
|
||||||
auto* realm = function->realm();
|
auto* realm = function->realm();
|
||||||
VERIFY(realm);
|
VERIFY(realm);
|
||||||
|
|
||||||
// 9. Return ? GetWrappedValue(realm, value).
|
// 9. Return ? GetWrappedValue(realm, value).
|
||||||
return TRY_OR_DISCARD(get_wrapped_value(global_object, *realm, value));
|
return get_wrapped_value(global_object, *realm, value);
|
||||||
});
|
});
|
||||||
on_fulfilled->define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
on_fulfilled->define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
||||||
on_fulfilled->define_direct_property(vm.names.name, js_string(vm, String::empty()), Attribute::Configurable);
|
on_fulfilled->define_direct_property(vm.names.name, js_string(vm, String::empty()), Attribute::Configurable);
|
||||||
|
@ -252,9 +250,8 @@ ThrowCompletionOr<Value> shadow_realm_import_value(GlobalObject& global_object,
|
||||||
|
|
||||||
// NOTE: Even though the spec tells us to use %ThrowTypeError%, it's not observable if we actually do.
|
// NOTE: Even though the spec tells us to use %ThrowTypeError%, it's not observable if we actually do.
|
||||||
// Throw a nicer TypeError forwarding the import error message instead (we know the argument is an Error object).
|
// Throw a nicer TypeError forwarding the import error message instead (we know the argument is an Error object).
|
||||||
auto* throw_type_error = NativeFunction::create(global_object, {}, [](auto& vm, auto& global_object) -> Value {
|
auto* throw_type_error = NativeFunction::create(global_object, {}, [](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
|
||||||
vm.template throw_exception<TypeError>(global_object, vm.argument(0).as_object().get_without_side_effects(vm.names.message).as_string().string());
|
return vm.template throw_completion<TypeError>(global_object, vm.argument(0).as_object().get_without_side_effects(vm.names.message).as_string().string());
|
||||||
return {};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 17. Return ! PerformPromiseThen(innerCapability.[[Promise]], onFulfilled, callerRealm.[[Intrinsics]].[[%ThrowTypeError%]], promiseCapability).
|
// 17. Return ! PerformPromiseThen(innerCapability.[[Promise]], onFulfilled, callerRealm.[[Intrinsics]].[[%ThrowTypeError%]], promiseCapability).
|
||||||
|
|
|
@ -442,7 +442,7 @@ JS::NativeFunction* create_native_function(Wasm::FunctionAddress address, String
|
||||||
auto function = JS::NativeFunction::create(
|
auto function = JS::NativeFunction::create(
|
||||||
global_object,
|
global_object,
|
||||||
name,
|
name,
|
||||||
[address, type = type.release_value()](JS::VM& vm, JS::GlobalObject& global_object) -> JS::Value {
|
[address, type = type.release_value()](JS::VM& vm, JS::GlobalObject& global_object) -> JS::ThrowCompletionOr<JS::Value> {
|
||||||
Vector<Wasm::Value> values;
|
Vector<Wasm::Value> values;
|
||||||
values.ensure_capacity(type.parameters().size());
|
values.ensure_capacity(type.parameters().size());
|
||||||
|
|
||||||
|
@ -453,15 +453,13 @@ JS::NativeFunction* create_native_function(Wasm::FunctionAddress address, String
|
||||||
if (result.has_value())
|
if (result.has_value())
|
||||||
values.append(result.release_value());
|
values.append(result.release_value());
|
||||||
else
|
else
|
||||||
return {};
|
return JS::throw_completion(vm.exception()->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = WebAssemblyObject::s_abstract_machine.invoke(address, move(values));
|
auto result = WebAssemblyObject::s_abstract_machine.invoke(address, move(values));
|
||||||
// FIXME: Use the convoluted mapping of errors defined in the spec.
|
// FIXME: Use the convoluted mapping of errors defined in the spec.
|
||||||
if (result.is_trap()) {
|
if (result.is_trap())
|
||||||
vm.throw_exception<JS::TypeError>(global_object, String::formatted("Wasm execution trapped (WIP): {}", result.trap().reason));
|
return vm.throw_completion<JS::TypeError>(global_object, String::formatted("Wasm execution trapped (WIP): {}", result.trap().reason));
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.values().is_empty())
|
if (result.values().is_empty())
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
|
@ -473,7 +471,7 @@ JS::NativeFunction* create_native_function(Wasm::FunctionAddress address, String
|
||||||
for (auto& entry : result.values())
|
for (auto& entry : result.values())
|
||||||
result_values.append(to_js_value(entry, global_object));
|
result_values.append(to_js_value(entry, global_object));
|
||||||
|
|
||||||
return JS::Array::create_from(global_object, result_values);
|
return JS::Value(JS::Array::create_from(global_object, result_values));
|
||||||
});
|
});
|
||||||
|
|
||||||
WebAssemblyObject::s_global_cache.function_instances.set(address, function);
|
WebAssemblyObject::s_global_cache.function_instances.set(address, function);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue