diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt index be06dfe550..3a82706afd 100644 --- a/Userland/Libraries/LibJS/CMakeLists.txt +++ b/Userland/Libraries/LibJS/CMakeLists.txt @@ -26,6 +26,7 @@ set(SOURCES Runtime/AggregateError.cpp Runtime/AggregateErrorConstructor.cpp Runtime/AggregateErrorPrototype.cpp + Runtime/ArgumentsObject.cpp Runtime/Array.cpp Runtime/ArrayBuffer.cpp Runtime/ArrayBufferConstructor.cpp diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp index bf3b1f10cf..b9441a6e4a 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -214,6 +215,9 @@ Object* create_unmapped_arguments_object(GlobalObject& global_object, Vectorindexed_properties().append(argument); + // 4. Perform DefinePropertyOrThrow(obj, "length", PropertyDescriptor { [[Value]]: 𝔽(len), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }). auto length = arguments.size(); object->define_property(vm.names.length, Value(length), Attribute::Writable | Attribute::Configurable); @@ -222,9 +226,6 @@ Object* create_unmapped_arguments_object(GlobalObject& global_object, Vectordefine_property(*vm.well_known_symbol_iterator(), global_object.array_prototype()->get(vm.names.values), Attribute::Writable | Attribute::Configurable); - for (auto& argument : arguments) - object->indexed_properties().append(argument); - // 8. Perform ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor { [[Get]]: %ThrowTypeError%, [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, [[Configurable]]: false }). object->define_accessor(vm.names.callee, global_object.throw_type_error_function(), global_object.throw_type_error_function(), 0); if (vm.exception()) @@ -233,4 +234,40 @@ Object* create_unmapped_arguments_object(GlobalObject& global_object, Vector const& formals, Vector const& arguments, EnvironmentRecord&) +{ + // FIXME: This implementation is incomplete and doesn't support the actual identifier mappings yet. + (void)formals; + + auto& vm = global_object.vm(); + auto* object = vm.heap().allocate(global_object, global_object); + if (vm.exception()) + return nullptr; + + // 14. Let index be 0. + // 15. Repeat, while index < len, + // a. Let val be argumentsList[index]. + // b . Perform ! CreateDataPropertyOrThrow(obj, ! ToString(𝔽(index)), val). + // c. Set index to index + 1. + for (auto& argument : arguments) + object->indexed_properties().append(argument); + + // 16. Perform ! DefinePropertyOrThrow(obj, "length", PropertyDescriptor { [[Value]]: 𝔽(len), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }). + auto length = arguments.size(); + object->define_property(vm.names.length, Value(length), Attribute::Writable | Attribute::Configurable); + if (vm.exception()) + return nullptr; + + // 20. Perform ! DefinePropertyOrThrow(obj, @@iterator, PropertyDescriptor { [[Value]]: %Array.prototype.values%, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }). + object->define_property(*vm.well_known_symbol_iterator(), global_object.array_prototype()->get(vm.names.values), Attribute::Writable | Attribute::Configurable); + + // 21. Perform ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor { [[Value]]: func, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }). + object->define_property(vm.names.callee, Value(&function), Attribute::Writable | Attribute::Configurable); + if (vm.exception()) + return nullptr; + + return object; +} + } diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.h b/Userland/Libraries/LibJS/Runtime/AbstractOperations.h index d8279e28ca..ae5edb0602 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.h +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include #include @@ -24,6 +25,7 @@ FunctionObject* species_constructor(GlobalObject&, Object const&, FunctionObject GlobalObject* get_function_realm(GlobalObject&, FunctionObject const&); Object* get_prototype_from_constructor(GlobalObject&, FunctionObject const& constructor, Object* (GlobalObject::*intrinsic_default_prototype)()); Object* create_unmapped_arguments_object(GlobalObject&, Vector const& arguments); +Object* create_mapped_arguments_object(GlobalObject&, FunctionObject&, Vector const&, Vector const& arguments, EnvironmentRecord&); enum class CallerMode { Strict, diff --git a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp new file mode 100644 index 0000000000..1d81384a56 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace JS { + +ArgumentsObject::ArgumentsObject(GlobalObject& global_object) + : Object(*global_object.object_prototype()) +{ +} + +void ArgumentsObject::initialize(GlobalObject& global_object) +{ + Base::initialize(global_object); +} + +ArgumentsObject::~ArgumentsObject() +{ +} + +} diff --git a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h new file mode 100644 index 0000000000..9fc9bfb91e --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace JS { + +class ArgumentsObject final : public Object { + JS_OBJECT(ArgumentsObject, Object); + +public: + explicit ArgumentsObject(GlobalObject&); + + virtual void initialize(GlobalObject&) override; + virtual ~ArgumentsObject() override; +}; + +} diff --git a/Userland/Libraries/LibJS/Runtime/Object.h b/Userland/Libraries/LibJS/Runtime/Object.h index ea6b05ab37..c959f92cb0 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.h +++ b/Userland/Libraries/LibJS/Runtime/Object.h @@ -108,6 +108,7 @@ public: virtual bool is_global_object() const { return false; } virtual bool is_proxy_object() const { return false; } virtual bool is_native_function() const { return false; } + virtual bool is_ordinary_function_object() const { return false; } // B.3.7 The [[IsHTMLDDA]] Internal Slot, https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot virtual bool is_htmldda() const { return false; } diff --git a/Userland/Libraries/LibJS/Runtime/OrdinaryFunctionObject.h b/Userland/Libraries/LibJS/Runtime/OrdinaryFunctionObject.h index 53b1bcb73b..42929c3135 100644 --- a/Userland/Libraries/LibJS/Runtime/OrdinaryFunctionObject.h +++ b/Userland/Libraries/LibJS/Runtime/OrdinaryFunctionObject.h @@ -41,6 +41,7 @@ protected: virtual bool is_strict_mode() const final { return m_is_strict; } private: + virtual bool is_ordinary_function_object() const { return true; } virtual FunctionEnvironmentRecord* create_environment_record(FunctionObject&) override; virtual void visit_edges(Visitor&) override; diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp index 842fefe291..f79c8c6085 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.cpp +++ b/Userland/Libraries/LibJS/Runtime/VM.cpp @@ -372,13 +372,7 @@ Value VM::get_variable(const FlyString& name, GlobalObject& global_object) if (context.function->is_strict_mode() || !context.function->has_simple_parameter_list()) { context.arguments_object = create_unmapped_arguments_object(global_object, context.arguments); } else { - // FIXME: This code path is completely ad-hoc. - context.arguments_object = Array::create(global_object); - context.arguments_object->put(names.callee, context.function); - - for (auto argument : context.arguments) { - context.arguments_object->indexed_properties().append(argument); - } + context.arguments_object = create_mapped_arguments_object(global_object, *context.function, verify_cast(context.function)->parameters(), context.arguments, *lexical_environment()); } } return context.arguments_object;