From 39554f3787eae7e52094cab16a966e62f00dea22 Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Sat, 12 Jun 2021 05:28:30 +0300 Subject: LibJS: Add the WeakMap built-in object --- Userland/Libraries/LibJS/CMakeLists.txt | 3 + Userland/Libraries/LibJS/Forward.h | 1 + Userland/Libraries/LibJS/Runtime/GlobalObject.cpp | 3 + Userland/Libraries/LibJS/Runtime/WeakMap.cpp | 32 ++++++++++ Userland/Libraries/LibJS/Runtime/WeakMap.h | 36 +++++++++++ .../Libraries/LibJS/Runtime/WeakMapConstructor.cpp | 74 ++++++++++++++++++++++ .../Libraries/LibJS/Runtime/WeakMapConstructor.h | 28 ++++++++ .../Libraries/LibJS/Runtime/WeakMapPrototype.cpp | 41 ++++++++++++ .../Libraries/LibJS/Runtime/WeakMapPrototype.h | 25 ++++++++ 9 files changed, 243 insertions(+) create mode 100644 Userland/Libraries/LibJS/Runtime/WeakMap.cpp create mode 100644 Userland/Libraries/LibJS/Runtime/WeakMap.h create mode 100644 Userland/Libraries/LibJS/Runtime/WeakMapConstructor.cpp create mode 100644 Userland/Libraries/LibJS/Runtime/WeakMapConstructor.h create mode 100644 Userland/Libraries/LibJS/Runtime/WeakMapPrototype.cpp create mode 100644 Userland/Libraries/LibJS/Runtime/WeakMapPrototype.h (limited to 'Userland') diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt index 533d663f78..8ad3f792d3 100644 --- a/Userland/Libraries/LibJS/CMakeLists.txt +++ b/Userland/Libraries/LibJS/CMakeLists.txt @@ -101,6 +101,9 @@ set(SOURCES Runtime/TypedArrayPrototype.cpp Runtime/VM.cpp Runtime/Value.cpp + Runtime/WeakMap.cpp + Runtime/WeakMapConstructor.cpp + Runtime/WeakMapPrototype.cpp Runtime/WeakSet.cpp Runtime/WeakSetConstructor.cpp Runtime/WeakSetPrototype.cpp diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h index 1ef0423fb0..b3ad3fd32b 100644 --- a/Userland/Libraries/LibJS/Forward.h +++ b/Userland/Libraries/LibJS/Forward.h @@ -41,6 +41,7 @@ __JS_ENUMERATE(Set, set, SetPrototype, SetConstructor, void) \ __JS_ENUMERATE(StringObject, string, StringPrototype, StringConstructor, void) \ __JS_ENUMERATE(SymbolObject, symbol, SymbolPrototype, SymbolConstructor, void) \ + __JS_ENUMERATE(WeakMap, weak_map, WeakMapPrototype, WeakMapConstructor, void) \ __JS_ENUMERATE(WeakSet, weak_set, WeakSetPrototype, WeakSetConstructor, void) #define JS_ENUMERATE_NATIVE_OBJECTS \ diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp index 6a7bd4ff7a..246cbc25ec 100644 --- a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -62,6 +62,8 @@ #include #include #include +#include +#include #include #include @@ -154,6 +156,7 @@ void GlobalObject::initialize_global_object() add_constructor(vm.names.Set, m_set_constructor, m_set_prototype); add_constructor(vm.names.String, m_string_constructor, m_string_prototype); add_constructor(vm.names.Symbol, m_symbol_constructor, m_symbol_prototype); + add_constructor(vm.names.WeakMap, m_weak_map_constructor, m_weak_map_prototype); add_constructor(vm.names.WeakSet, m_weak_set_constructor, m_weak_set_prototype); initialize_constructor(vm.names.TypedArray, m_typed_array_constructor, m_typed_array_prototype); diff --git a/Userland/Libraries/LibJS/Runtime/WeakMap.cpp b/Userland/Libraries/LibJS/Runtime/WeakMap.cpp new file mode 100644 index 0000000000..00cff84e51 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/WeakMap.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021, Idan Horowitz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace JS { + +WeakMap* WeakMap::create(GlobalObject& global_object) +{ + return global_object.heap().allocate(global_object, *global_object.weak_map_prototype()); +} + +WeakMap::WeakMap(Object& prototype) + : Object(prototype) + , WeakContainer(heap()) +{ +} + +WeakMap::~WeakMap() +{ +} + +void WeakMap::remove_sweeped_cells(Badge, Vector& cells) +{ + for (auto* cell : cells) + m_values.remove(cell); +} + +} diff --git a/Userland/Libraries/LibJS/Runtime/WeakMap.h b/Userland/Libraries/LibJS/Runtime/WeakMap.h new file mode 100644 index 0000000000..e067327978 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/WeakMap.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021, Idan Horowitz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace JS { + +class WeakMap final + : public Object + , public WeakContainer { + JS_OBJECT(WeakMap, Object); + +public: + static WeakMap* create(GlobalObject&); + + explicit WeakMap(Object& prototype); + virtual ~WeakMap() override; + + HashMap const& values() const { return m_values; }; + HashMap& values() { return m_values; }; + + virtual void remove_sweeped_cells(Badge, Vector&) override; + +private: + HashMap m_values; // This stores Cell pointers instead of Object pointers to aide with sweeping +}; + +} diff --git a/Userland/Libraries/LibJS/Runtime/WeakMapConstructor.cpp b/Userland/Libraries/LibJS/Runtime/WeakMapConstructor.cpp new file mode 100644 index 0000000000..5ef3121fb7 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/WeakMapConstructor.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021, Idan Horowitz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +namespace JS { + +WeakMapConstructor::WeakMapConstructor(GlobalObject& global_object) + : NativeFunction(vm().names.WeakMap, *global_object.function_prototype()) +{ +} + +void WeakMapConstructor::initialize(GlobalObject& global_object) +{ + auto& vm = this->vm(); + NativeFunction::initialize(global_object); + define_property(vm.names.prototype, global_object.weak_map_prototype(), 0); + define_property(vm.names.length, Value(0), Attribute::Configurable); +} + +WeakMapConstructor::~WeakMapConstructor() +{ +} + +Value WeakMapConstructor::call() +{ + auto& vm = this->vm(); + vm.throw_exception(global_object(), ErrorType::ConstructorWithoutNew, vm.names.WeakMap); + return {}; +} + +Value WeakMapConstructor::construct(Function&) +{ + auto& vm = this->vm(); + if (vm.argument(0).is_nullish()) + return WeakMap::create(global_object()); + + auto* weak_map = WeakMap::create(global_object()); + auto adder = weak_map->get(vm.names.set); + if (vm.exception()) + return {}; + if (!adder.is_function()) { + vm.throw_exception(global_object(), ErrorType::NotAFunction, "'set' property of WeakMap"); + return {}; + } + get_iterator_values(global_object(), vm.argument(0), [&](Value iterator_value) { + if (vm.exception()) + return IterationDecision::Break; + if (!iterator_value.is_object()) { + vm.throw_exception(global_object(), ErrorType::NotAnObject, String::formatted("Iterator value {}", iterator_value.to_string_without_side_effects())); + return IterationDecision::Break; + } + auto key = iterator_value.as_object().get(0); + if (vm.exception()) + return IterationDecision::Break; + auto value = iterator_value.as_object().get(1); + if (vm.exception()) + return IterationDecision::Break; + (void)vm.call(adder.as_function(), Value(weak_map), key, value); + return vm.exception() ? IterationDecision::Break : IterationDecision::Continue; + }); + if (vm.exception()) + return {}; + return weak_map; +} + +} diff --git a/Userland/Libraries/LibJS/Runtime/WeakMapConstructor.h b/Userland/Libraries/LibJS/Runtime/WeakMapConstructor.h new file mode 100644 index 0000000000..42d47eadad --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/WeakMapConstructor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021, Idan Horowitz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace JS { + +class WeakMapConstructor final : public NativeFunction { + JS_OBJECT(WeakMapConstructor, NativeFunction); + +public: + explicit WeakMapConstructor(GlobalObject&); + virtual void initialize(GlobalObject&) override; + virtual ~WeakMapConstructor() override; + + virtual Value call() override; + virtual Value construct(Function&) override; + +private: + virtual bool has_constructor() const override { return true; } +}; + +} diff --git a/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.cpp b/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.cpp new file mode 100644 index 0000000000..892b1c14b6 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021, Idan Horowitz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace JS { + +WeakMapPrototype::WeakMapPrototype(GlobalObject& global_object) + : Object(*global_object.object_prototype()) +{ +} + +void WeakMapPrototype::initialize(GlobalObject& global_object) +{ + auto& vm = this->vm(); + Object::initialize(global_object); + + define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.WeakMap), Attribute::Configurable); +} + +WeakMapPrototype::~WeakMapPrototype() +{ +} + +WeakMap* WeakMapPrototype::typed_this(VM& vm, GlobalObject& global_object) +{ + auto* this_object = vm.this_value(global_object).to_object(global_object); + if (!this_object) + return {}; + if (!is(this_object)) { + vm.throw_exception(global_object, ErrorType::NotA, "WeakMap"); + return nullptr; + } + return static_cast(this_object); +} + +} diff --git a/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.h b/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.h new file mode 100644 index 0000000000..267ddeb689 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021, Idan Horowitz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace JS { + +class WeakMapPrototype final : public Object { + JS_OBJECT(WeakMapPrototype, Object); + +public: + WeakMapPrototype(GlobalObject&); + virtual void initialize(GlobalObject&) override; + virtual ~WeakMapPrototype() override; + +private: + static WeakMap* typed_this(VM&, GlobalObject&); +}; + +} -- cgit v1.2.3