summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-06-28 13:26:01 +0200
committerAndreas Kling <kling@serenityos.org>2021-06-28 16:52:20 +0200
commit2d4eb40f5951ff78d60470c9cc8f5d78d508ff6a (patch)
tree15f6ffbf7e50dad5215caf5a6b940abd19a4e2b5 /Userland
parenta55cf08ef92284954cfe3c64b98ea276c68a00c7 (diff)
downloadserenity-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.txt1
-rw-r--r--Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp41
-rw-r--r--Userland/Libraries/LibJS/Runtime/AbstractOperations.h2
-rw-r--r--Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp26
-rw-r--r--Userland/Libraries/LibJS/Runtime/ArgumentsObject.h23
-rw-r--r--Userland/Libraries/LibJS/Runtime/Object.h1
-rw-r--r--Userland/Libraries/LibJS/Runtime/OrdinaryFunctionObject.h1
-rw-r--r--Userland/Libraries/LibJS/Runtime/VM.cpp8
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;