diff options
author | Andreas Kling <kling@serenityos.org> | 2021-06-28 13:26:01 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-28 16:52:20 +0200 |
commit | 2d4eb40f5951ff78d60470c9cc8f5d78d508ff6a (patch) | |
tree | 15f6ffbf7e50dad5215caf5a6b940abd19a4e2b5 /Userland | |
parent | a55cf08ef92284954cfe3c64b98ea276c68a00c7 (diff) | |
download | serenity-2d4eb40f5951ff78d60470c9cc8f5d78d508ff6a.zip |
LibJS: Add the CreateMappedArgumentsObject abstract operation
This patch adds a new ArgumentsObject class to represent what the spec
calls "Arguments Exotic Objects"
These are constructed by the new CreateMappedArgumentsObject when the
`arguments` identifier is resolved in a callee context.
The implementation is incomplete and doesn't yet support mapping of
the parameter variables to the indexed properties of `arguments`.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibJS/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp | 41 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/AbstractOperations.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp | 26 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/ArgumentsObject.h | 23 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/Object.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/OrdinaryFunctionObject.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/VM.cpp | 8 |
8 files changed, 94 insertions, 9 deletions
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 <LibJS/Interpreter.h> #include <LibJS/Parser.h> #include <LibJS/Runtime/AbstractOperations.h> +#include <LibJS/Runtime/ArgumentsObject.h> #include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/ArrayPrototype.h> #include <LibJS/Runtime/BoundFunction.h> @@ -214,6 +215,9 @@ Object* create_unmapped_arguments_object(GlobalObject& global_object, Vector<Val if (vm.exception()) return nullptr; + for (auto& argument : arguments) + object->indexed_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,11 +226,44 @@ Object* create_unmapped_arguments_object(GlobalObject& global_object, Vector<Val object->define_property(*vm.well_known_symbol_iterator(), global_object.array_prototype()->get(vm.names.values), Attribute::Writable | Attribute::Configurable); + // 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()) + return nullptr; + + return object; +} + +// 10.4.4.7 CreateMappedArgumentsObject ( func, formals, argumentsList, env ), https://tc39.es/ecma262/#sec-createmappedargumentsobject +Object* create_mapped_arguments_object(GlobalObject& global_object, FunctionObject& function, Vector<FunctionNode::Parameter> const& formals, Vector<Value> 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<ArgumentsObject>(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); - // 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); + // 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; 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 <AK/Forward.h> +#include <LibJS/AST.h> #include <LibJS/Forward.h> #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/Value.h> @@ -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<Value> const& arguments); +Object* create_mapped_arguments_object(GlobalObject&, FunctionObject&, Vector<FunctionNode::Parameter> const&, Vector<Value> 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 <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibJS/Runtime/ArgumentsObject.h> +#include <LibJS/Runtime/GlobalObject.h> + +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 <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <LibJS/Runtime/Object.h> + +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<OrdinaryFunctionObject>(context.function)->parameters(), context.arguments, *lexical_environment()); } } return context.arguments_object; |