Skip to content

Commit

Permalink
LibJS: Add DisposableStack{, Prototype, Constructor}
Browse files Browse the repository at this point in the history
Since the async parts of the spec are not stage 3 at this point we don't
add AsyncDisposableStack.
  • Loading branch information
davidot committed Jan 16, 2023
1 parent 2e955d8 commit 342a4d8
Show file tree
Hide file tree
Showing 22 changed files with 866 additions and 0 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Expand Up @@ -4,6 +4,7 @@ Userland/Libraries/LibJS/Tests/unicode-identifier-escape.js
Userland/Libraries/LibJS/Tests/modules/failing.mjs

# FIXME: Remove once prettier is updated to support using declarations.
Userland/Libraries/LibJS/Tests/builtins/DisposableStack/DisposableStack.prototype.@@dispose.js
Userland/Libraries/LibJS/Tests/modules/top-level-dispose.mjs
Userland/Libraries/LibJS/Tests/using-declaration.js
Userland/Libraries/LibJS/Tests/using-for-loops.js
3 changes: 3 additions & 0 deletions Userland/Libraries/LibJS/CMakeLists.txt
Expand Up @@ -75,6 +75,9 @@ set(SOURCES
Runtime/DateConstructor.cpp
Runtime/DatePrototype.cpp
Runtime/DeclarativeEnvironment.cpp
Runtime/DisposableStack.cpp
Runtime/DisposableStackConstructor.cpp
Runtime/DisposableStackPrototype.cpp
Runtime/ECMAScriptFunctionObject.cpp
Runtime/Environment.cpp
Runtime/Error.cpp
Expand Down
1 change: 1 addition & 0 deletions Userland/Libraries/LibJS/Forward.h
Expand Up @@ -27,6 +27,7 @@
__JS_ENUMERATE(BooleanObject, boolean, BooleanPrototype, BooleanConstructor, void) \
__JS_ENUMERATE(DataView, data_view, DataViewPrototype, DataViewConstructor, void) \
__JS_ENUMERATE(Date, date, DatePrototype, DateConstructor, void) \
__JS_ENUMERATE(DisposableStack, disposable_stack, DisposableStackPrototype, DisposableStackConstructor, void) \
__JS_ENUMERATE(Error, error, ErrorPrototype, ErrorConstructor, void) \
__JS_ENUMERATE(FinalizationRegistry, finalization_registry, FinalizationRegistryPrototype, FinalizationRegistryConstructor, void) \
__JS_ENUMERATE(FunctionObject, function, FunctionPrototype, FunctionConstructor, void) \
Expand Down
5 changes: 5 additions & 0 deletions Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
Expand Up @@ -65,6 +65,7 @@ namespace JS {
P(acos) \
P(acosh) \
P(add) \
P(adopt) \
P(all) \
P(allSettled) \
P(anchor) \
Expand Down Expand Up @@ -143,6 +144,7 @@ namespace JS {
P(debug) \
P(decodeURI) \
P(decodeURIComponent) \
P(defer) \
P(defineProperties) \
P(defineProperty) \
P(deleteProperty) \
Expand All @@ -151,6 +153,7 @@ namespace JS {
P(difference) \
P(direction) \
P(disambiguation) \
P(disposed) \
P(done) \
P(dotAll) \
P(encodeURI) \
Expand Down Expand Up @@ -365,6 +368,7 @@ namespace JS {
P(months) \
P(monthsDisplay) \
P(monthsInYear) \
P(move) \
P(multiline) \
P(name) \
P(nanosecond) \
Expand Down Expand Up @@ -555,6 +559,7 @@ namespace JS {
P(unshift) \
P(until) \
P(usage) \
P(use) \
P(useGrouping) \
P(value) \
P(valueOf) \
Expand Down
26 changes: 26 additions & 0 deletions Userland/Libraries/LibJS/Runtime/DisposableStack.cpp
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2022, David Tuin <davidot@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <LibJS/Runtime/DisposableStack.h>

namespace JS {

DisposableStack::DisposableStack(Vector<DisposableResource> stack, Object& prototype)
: Object(ConstructWithPrototypeTag::Tag, prototype)
, m_disposable_resource_stack(move(stack))
{
}

void DisposableStack::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
for (auto& resource : m_disposable_resource_stack) {
visitor.visit(resource.resource_value);
visitor.visit(resource.dispose_method);
}
}

}
40 changes: 40 additions & 0 deletions Userland/Libraries/LibJS/Runtime/DisposableStack.h
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2022, David Tuin <davidot@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Object.h>

namespace JS {

class DisposableStack final : public Object {
JS_OBJECT(DisposableStack, Object);

public:
virtual ~DisposableStack() override = default;

enum class DisposableState {
Pending,
Disposed
};

[[nodiscard]] DisposableState disposable_state() const { return m_state; }
Vector<DisposableResource> const& disposable_resource_stack() const { return m_disposable_resource_stack; }
Vector<DisposableResource>& disposable_resource_stack() { return m_disposable_resource_stack; }

void set_disposed() { m_state = DisposableState::Disposed; }

private:
DisposableStack(Vector<DisposableResource> stack, Object& prototype);

virtual void visit_edges(Visitor& visitor) override;

Vector<DisposableResource> m_disposable_resource_stack;
DisposableState m_state { DisposableState::Pending };
};

}
50 changes: 50 additions & 0 deletions Userland/Libraries/LibJS/Runtime/DisposableStackConstructor.cpp
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2022, David Tuin <davidot@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/DisposableStack.h>
#include <LibJS/Runtime/DisposableStackConstructor.h>

namespace JS {

DisposableStackConstructor::DisposableStackConstructor(Realm& realm)
: NativeFunction(realm.vm().names.DisposableStack.as_string(), *realm.intrinsics().function_prototype())
{
}

void DisposableStackConstructor::initialize(Realm& realm)
{
auto& vm = this->vm();
NativeFunction::initialize(realm);

// 26.2.2.1 DisposableStack.prototype, https://tc39.es/ecma262/#sec-finalization-registry.prototype
define_direct_property(vm.names.prototype, realm.intrinsics().disposable_stack_prototype(), 0);

define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
}

// 11.3.1.1 DisposableStack ( ), https://tc39.es/proposal-explicit-resource-management/#sec-disposablestack
ThrowCompletionOr<Value> DisposableStackConstructor::call()
{
auto& vm = this->vm();
return vm.throw_completion<TypeError>(ErrorType::ConstructorWithoutNew, vm.names.DisposableStack);
}

// 11.3.1.1 DisposableStack ( ), https://tc39.es/proposal-explicit-resource-management/#sec-disposablestack
ThrowCompletionOr<NonnullGCPtr<Object>> DisposableStackConstructor::construct(FunctionObject& new_target)
{
auto& vm = this->vm();

// NOTE: Step 1 is implemented in DisposableStackConstructor::call()

// 2. Let disposableStack be ? OrdinaryCreateFromConstructor(NewTarget, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposableResourceStack]] »).
// 3. Set disposableStack.[[DisposableState]] to pending.
// 4. Set disposableStack.[[DisposableResourceStack]] to a new empty List.
// 5. Return disposableStack.
return TRY(ordinary_create_from_constructor<DisposableStack>(vm, new_target, &Intrinsics::disposable_stack_prototype, Vector<DisposableResource> {}));
}

}
29 changes: 29 additions & 0 deletions Userland/Libraries/LibJS/Runtime/DisposableStackConstructor.h
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2022, David Tuin <davidot@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <LibJS/Runtime/NativeFunction.h>

namespace JS {

class DisposableStackConstructor final : public NativeFunction {
JS_OBJECT(DisposableStackConstructor, NativeFunction);

public:
virtual void initialize(Realm&) override;
virtual ~DisposableStackConstructor() override = default;

virtual ThrowCompletionOr<Value> call() override;
virtual ThrowCompletionOr<NonnullGCPtr<Object>> construct(FunctionObject&) override;

private:
explicit DisposableStackConstructor(Realm&);

virtual bool has_constructor() const override { return true; }
};

}

0 comments on commit 342a4d8

Please sign in to comment.