mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 19:37:34 +00:00
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`.
This commit is contained in:
parent
a55cf08ef9
commit
2d4eb40f59
8 changed files with 95 additions and 10 deletions
|
@ -26,6 +26,7 @@ set(SOURCES
|
||||||
Runtime/AggregateError.cpp
|
Runtime/AggregateError.cpp
|
||||||
Runtime/AggregateErrorConstructor.cpp
|
Runtime/AggregateErrorConstructor.cpp
|
||||||
Runtime/AggregateErrorPrototype.cpp
|
Runtime/AggregateErrorPrototype.cpp
|
||||||
|
Runtime/ArgumentsObject.cpp
|
||||||
Runtime/Array.cpp
|
Runtime/Array.cpp
|
||||||
Runtime/ArrayBuffer.cpp
|
Runtime/ArrayBuffer.cpp
|
||||||
Runtime/ArrayBufferConstructor.cpp
|
Runtime/ArrayBufferConstructor.cpp
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <LibJS/Interpreter.h>
|
#include <LibJS/Interpreter.h>
|
||||||
#include <LibJS/Parser.h>
|
#include <LibJS/Parser.h>
|
||||||
#include <LibJS/Runtime/AbstractOperations.h>
|
#include <LibJS/Runtime/AbstractOperations.h>
|
||||||
|
#include <LibJS/Runtime/ArgumentsObject.h>
|
||||||
#include <LibJS/Runtime/Array.h>
|
#include <LibJS/Runtime/Array.h>
|
||||||
#include <LibJS/Runtime/ArrayPrototype.h>
|
#include <LibJS/Runtime/ArrayPrototype.h>
|
||||||
#include <LibJS/Runtime/BoundFunction.h>
|
#include <LibJS/Runtime/BoundFunction.h>
|
||||||
|
@ -214,6 +215,9 @@ Object* create_unmapped_arguments_object(GlobalObject& global_object, Vector<Val
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return nullptr;
|
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 }).
|
// 4. Perform DefinePropertyOrThrow(obj, "length", PropertyDescriptor { [[Value]]: 𝔽(len), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
|
||||||
auto length = arguments.size();
|
auto length = arguments.size();
|
||||||
object->define_property(vm.names.length, Value(length), Attribute::Writable | Attribute::Configurable);
|
object->define_property(vm.names.length, Value(length), Attribute::Writable | Attribute::Configurable);
|
||||||
|
@ -222,9 +226,6 @@ 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);
|
object->define_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 }).
|
// 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);
|
object->define_accessor(vm.names.callee, global_object.throw_type_error_function(), global_object.throw_type_error_function(), 0);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
|
@ -233,4 +234,40 @@ Object* create_unmapped_arguments_object(GlobalObject& global_object, Vector<Val
|
||||||
return object;
|
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);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
|
#include <LibJS/AST.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
#include <LibJS/Runtime/GlobalObject.h>
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
@ -24,6 +25,7 @@ FunctionObject* species_constructor(GlobalObject&, Object const&, FunctionObject
|
||||||
GlobalObject* get_function_realm(GlobalObject&, FunctionObject const&);
|
GlobalObject* get_function_realm(GlobalObject&, FunctionObject const&);
|
||||||
Object* get_prototype_from_constructor(GlobalObject&, FunctionObject const& constructor, Object* (GlobalObject::*intrinsic_default_prototype)());
|
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_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 {
|
enum class CallerMode {
|
||||||
Strict,
|
Strict,
|
||||||
|
|
26
Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp
Normal file
26
Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp
Normal file
|
@ -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()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
Userland/Libraries/LibJS/Runtime/ArgumentsObject.h
Normal file
23
Userland/Libraries/LibJS/Runtime/ArgumentsObject.h
Normal file
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -108,6 +108,7 @@ public:
|
||||||
virtual bool is_global_object() const { return false; }
|
virtual bool is_global_object() const { return false; }
|
||||||
virtual bool is_proxy_object() const { return false; }
|
virtual bool is_proxy_object() const { return false; }
|
||||||
virtual bool is_native_function() 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
|
// B.3.7 The [[IsHTMLDDA]] Internal Slot, https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot
|
||||||
virtual bool is_htmldda() const { return false; }
|
virtual bool is_htmldda() const { return false; }
|
||||||
|
|
|
@ -41,6 +41,7 @@ protected:
|
||||||
virtual bool is_strict_mode() const final { return m_is_strict; }
|
virtual bool is_strict_mode() const final { return m_is_strict; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
virtual bool is_ordinary_function_object() const { return true; }
|
||||||
virtual FunctionEnvironmentRecord* create_environment_record(FunctionObject&) override;
|
virtual FunctionEnvironmentRecord* create_environment_record(FunctionObject&) override;
|
||||||
virtual void visit_edges(Visitor&) override;
|
virtual void visit_edges(Visitor&) override;
|
||||||
|
|
||||||
|
|
|
@ -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()) {
|
if (context.function->is_strict_mode() || !context.function->has_simple_parameter_list()) {
|
||||||
context.arguments_object = create_unmapped_arguments_object(global_object, context.arguments);
|
context.arguments_object = create_unmapped_arguments_object(global_object, context.arguments);
|
||||||
} else {
|
} else {
|
||||||
// FIXME: This code path is completely ad-hoc.
|
context.arguments_object = create_mapped_arguments_object(global_object, *context.function, verify_cast<OrdinaryFunctionObject>(context.function)->parameters(), context.arguments, *lexical_environment());
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return context.arguments_object;
|
return context.arguments_object;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue