ladybird/Userland/Libraries/LibJS/Runtime/ProxyConstructor.cpp
Timothy Flynn 2692db8699 LibJS+Everywhere: Allow Cell::initialize overrides to throw OOM errors
Note that as of this commit, there aren't any such throwers, and the
call site in Heap::allocate will drop exceptions on the floor. This
commit only serves to change the declaration of the overrides, make sure
they return an empty value, and to propagate OOM errors frm their base
initialize invocations.
2023-01-29 00:02:45 +00:00

104 lines
3.8 KiB
C++

/*
* Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/ProxyConstructor.h>
#include <LibJS/Runtime/ProxyObject.h>
namespace JS {
// 10.5.14 ProxyCreate ( target, handler ), https://tc39.es/ecma262/#sec-proxycreate
static ThrowCompletionOr<ProxyObject*> proxy_create(VM& vm, Value target, Value handler)
{
auto& realm = *vm.current_realm();
if (!target.is_object())
return vm.throw_completion<TypeError>(ErrorType::ProxyConstructorBadType, "target", target.to_string_without_side_effects());
if (!handler.is_object())
return vm.throw_completion<TypeError>(ErrorType::ProxyConstructorBadType, "handler", handler.to_string_without_side_effects());
return ProxyObject::create(realm, target.as_object(), handler.as_object()).ptr();
}
ProxyConstructor::ProxyConstructor(Realm& realm)
: NativeFunction(realm.vm().names.Proxy.as_string(), *realm.intrinsics().function_prototype())
{
}
ThrowCompletionOr<void> ProxyConstructor::initialize(Realm& realm)
{
auto& vm = this->vm();
MUST_OR_THROW_OOM(NativeFunction::initialize(realm));
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(realm, vm.names.revocable, revocable, 2, attr);
define_direct_property(vm.names.length, Value(2), Attribute::Configurable);
return {};
}
// 28.2.1.1 Proxy ( target, handler ), https://tc39.es/ecma262/#sec-proxy-target-handler
ThrowCompletionOr<Value> ProxyConstructor::call()
{
auto& vm = this->vm();
return vm.throw_completion<TypeError>(ErrorType::ConstructorWithoutNew, vm.names.Proxy);
}
// 28.2.1.1 Proxy ( target, handler ), https://tc39.es/ecma262/#sec-proxy-target-handler
ThrowCompletionOr<NonnullGCPtr<Object>> ProxyConstructor::construct(FunctionObject&)
{
auto& vm = this->vm();
return *TRY(proxy_create(vm, vm.argument(0), vm.argument(1)));
}
// 28.2.2.1 Proxy.revocable ( target, handler ), https://tc39.es/ecma262/#sec-proxy.revocable
JS_DEFINE_NATIVE_FUNCTION(ProxyConstructor::revocable)
{
auto& realm = *vm.current_realm();
// 1. Let p be ? ProxyCreate(target, handler).
auto* proxy = TRY(proxy_create(vm, vm.argument(0), vm.argument(1)));
// 2. Let revokerClosure be a new Abstract Closure with no parameters that captures nothing and performs the following steps when called:
auto revoker_closure = [proxy_handle = make_handle(proxy)](auto&) -> ThrowCompletionOr<Value> {
// a. Let F be the active function object.
// b. Let p be F.[[RevocableProxy]].
auto& proxy = const_cast<ProxyObject&>(*proxy_handle.cell());
// c. If p is null, return undefined.
if (proxy.is_revoked())
return js_undefined();
// d. Set F.[[RevocableProxy]] to null.
// e. Assert: p is a Proxy object.
// f. Set p.[[ProxyTarget]] to null.
// g. Set p.[[ProxyHandler]] to null.
proxy.revoke();
// h. Return undefined.
return js_undefined();
};
// 3. Let revoker be CreateBuiltinFunction(revokerClosure, 0, "", « [[RevocableProxy]] »).
// 4. Set revoker.[[RevocableProxy]] to p.
auto revoker = NativeFunction::create(realm, move(revoker_closure), 0, "");
// 5. Let result be OrdinaryObjectCreate(%Object.prototype%).
auto result = Object::create(realm, realm.intrinsics().object_prototype());
// 6. Perform ! CreateDataPropertyOrThrow(result, "proxy", p).
MUST(result->create_data_property_or_throw(vm.names.proxy, proxy));
// 7. Perform ! CreateDataPropertyOrThrow(result, "revoke", revoker).
MUST(result->create_data_property_or_throw(vm.names.revoke, revoker));
// 8. Return result.
return result;
}
}