Created
June 28, 2021 21:18
-
-
Save awesomekling/36b624f04838498dfd948da907348664 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 1a71df350909560a375a8d7c4632f41a042ae42a | |
Author: Andreas Kling <kling@serenityos.org> | |
Date: Mon Jun 28 21:19:25 2021 +0200 | |
WIP arg map | |
diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp | |
index b9441a6e4..89928f6d4 100644 | |
--- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp | |
+++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp | |
@@ -235,13 +235,10 @@ Object* create_unmapped_arguments_object(GlobalObject& global_object, Vector<Val | |
} | |
// 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&) | |
+Object* create_mapped_arguments_object(GlobalObject& global_object, FunctionObject& function, Vector<FunctionNode::Parameter> const& formals, Vector<Value> const& arguments, EnvironmentRecord& environment) | |
{ | |
- // 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); | |
+ auto* object = vm.heap().allocate<ArgumentsObject>(global_object, global_object, environment); | |
if (vm.exception()) | |
return nullptr; | |
@@ -254,11 +251,51 @@ Object* create_mapped_arguments_object(GlobalObject& global_object, FunctionObje | |
object->indexed_properties().append(argument); | |
// 16. Perform ! DefinePropertyOrThrow(obj, "length", PropertyDescriptor { [[Value]]: 𝔽(len), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }). | |
- auto length = arguments.size(); | |
+ VERIFY(arguments.size() <= NumericLimits<i32>::max()); | |
+ i32 const length = static_cast<i32>(arguments.size()); | |
object->define_property(vm.names.length, Value(length), Attribute::Writable | Attribute::Configurable); | |
if (vm.exception()) | |
return nullptr; | |
+ // 17. Let mappedNames be a new empty List. | |
+ HashTable<FlyString> mapped_names; | |
+ | |
+ // 18. Set index to numberOfParameters - 1. | |
+ // 19. Repeat, while index ≥ 0, | |
+ VERIFY(formals.size() <= NumericLimits<i32>::max()); | |
+ for (i32 index = static_cast<i32>(formals.size()) - 1; index >= 0; --index) { | |
+ // a. Let name be parameterNames[index]. | |
+ auto name = formals[index].binding.get<FlyString>(); | |
+ | |
+ // b. If name is not an element of mappedNames, then | |
+ if (mapped_names.contains(name)) | |
+ continue; | |
+ | |
+ // i. Add name as an element of the list mappedNames. | |
+ mapped_names.set(name); | |
+ | |
+ // ii. If index < len, then | |
+ if (index < length) { | |
+ // 1. Let g be MakeArgGetter(name, env). | |
+ // 2. Let p be MakeArgSetter(name, env). | |
+ // 3. Perform map.[[DefineOwnProperty]](! ToString(𝔽(index)), PropertyDescriptor { [[Set]]: p, [[Get]]: g, [[Enumerable]]: false, [[Configurable]]: true }). | |
+ object->parameter_map().define_native_accessor( | |
+ String::number(index), | |
+ [environment = &environment, name](VM&, GlobalObject&) -> Value { | |
+ auto variable = environment->get_from_environment_record(name); | |
+ if (!variable.has_value()) | |
+ return {}; | |
+ return variable->value; | |
+ }, | |
+ [environment = &environment, name](VM& vm, GlobalObject&) { | |
+ auto value = vm.argument(0); | |
+ environment->put_into_environment_record(name, Variable { value, DeclarationKind::Var }); | |
+ return js_undefined(); | |
+ }, | |
+ Attribute::Configurable); | |
+ } | |
+ } | |
+ | |
// 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); | |
diff --git a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp | |
index 1d81384a5..6cb7451c2 100644 | |
--- a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp | |
+++ b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp | |
@@ -9,18 +9,58 @@ | |
namespace JS { | |
-ArgumentsObject::ArgumentsObject(GlobalObject& global_object) | |
+ArgumentsObject::ArgumentsObject(GlobalObject& global_object, EnvironmentRecord& environment) | |
: Object(*global_object.object_prototype()) | |
+ , m_environment(environment) | |
{ | |
} | |
void ArgumentsObject::initialize(GlobalObject& global_object) | |
{ | |
Base::initialize(global_object); | |
+ m_parameter_map = Object::create(global_object, nullptr); | |
} | |
ArgumentsObject::~ArgumentsObject() | |
{ | |
} | |
+void ArgumentsObject::visit_edges(Cell::Visitor& visitor) | |
+{ | |
+ Base::visit_edges(visitor); | |
+ visitor.visit(&m_environment); | |
+ visitor.visit(m_parameter_map); | |
+} | |
+ | |
+// 10.4.4.3 [[Get]] ( P, Receiver ), https://tc39.es/ecma262/#sec-arguments-exotic-objects-get-p-receiver | |
+Value ArgumentsObject::get_by_index(u32 property_index, AllowSideEffects allow_side_effects) const | |
+{ | |
+ VERIFY(m_parameter_map); | |
+ bool is_mapped = m_parameter_map->has_own_property(property_index); | |
+ if (!is_mapped) | |
+ return Base::get_by_index(property_index, allow_side_effects); | |
+ return m_parameter_map->get(property_index, {}, allow_side_effects); | |
+} | |
+ | |
+// 10.4.4.4 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-arguments-exotic-objects-set-p-v-receiver | |
+bool ArgumentsObject::put_by_index(u32 property_index, Value value) | |
+{ | |
+ VERIFY(m_parameter_map); | |
+ bool is_mapped = m_parameter_map->has_own_property(property_index); | |
+ if (!is_mapped) | |
+ return Base::put(property_index, value); | |
+ return m_parameter_map->put(property_index, value, {}); | |
+} | |
+ | |
+// 10.4.4.5 [[Delete]] ( P ), https://tc39.es/ecma262/#sec-arguments-exotic-objects-delete-p | |
+bool ArgumentsObject::delete_property(PropertyName const& name, bool force_throw_exception) | |
+{ | |
+ VERIFY(m_parameter_map); | |
+ bool is_mapped = m_parameter_map->has_own_property(name); | |
+ bool result = Base::delete_property(name, force_throw_exception); | |
+ if (result && is_mapped) | |
+ m_parameter_map->delete_property(name, force_throw_exception); | |
+ return result; | |
+} | |
+ | |
} | |
diff --git a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h | |
index 9fc9bfb91..aaecf9290 100644 | |
--- a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h | |
+++ b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h | |
@@ -6,6 +6,7 @@ | |
#pragma once | |
+#include <LibJS/Runtime/EnvironmentRecord.h> | |
#include <LibJS/Runtime/Object.h> | |
namespace JS { | |
@@ -14,10 +15,25 @@ class ArgumentsObject final : public Object { | |
JS_OBJECT(ArgumentsObject, Object); | |
public: | |
- explicit ArgumentsObject(GlobalObject&); | |
+ explicit ArgumentsObject(GlobalObject&, EnvironmentRecord&); | |
virtual void initialize(GlobalObject&) override; | |
virtual ~ArgumentsObject() override; | |
+ | |
+ EnvironmentRecord& environment() { return m_environment; } | |
+ | |
+ virtual Value get_by_index(u32 property_index, AllowSideEffects) const override; | |
+ virtual bool put_by_index(u32 property_index, Value) override; | |
+ virtual bool delete_property(PropertyName const&, bool force_throw_exception) override; | |
+ | |
+ // [[ParameterMap]] | |
+ Object& parameter_map() { return *m_parameter_map; } | |
+ | |
+private: | |
+ virtual void visit_edges(Cell::Visitor&) override; | |
+ | |
+ EnvironmentRecord& m_environment; | |
+ Object* m_parameter_map { nullptr }; | |
}; | |
} | |
diff --git a/Userland/Libraries/LibJS/Runtime/Object.cpp b/Userland/Libraries/LibJS/Runtime/Object.cpp | |
index bc71c2ef3..27c163a20 100644 | |
--- a/Userland/Libraries/LibJS/Runtime/Object.cpp | |
+++ b/Userland/Libraries/LibJS/Runtime/Object.cpp | |
@@ -559,7 +559,9 @@ bool Object::define_native_accessor(PropertyName const& property_name, Function< | |
{ | |
auto& vm = this->vm(); | |
String formatted_property_name; | |
- if (property_name.is_string()) { | |
+ if (property_name.is_number()) { | |
+ formatted_property_name = property_name.to_string(); | |
+ } else if (property_name.is_string()) { | |
formatted_property_name = property_name.as_string(); | |
} else { | |
formatted_property_name = String::formatted("[{}]", property_name.as_symbol()->description()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment