Skip to content

Instantly share code, notes, and snippets.

@awesomekling
Created June 28, 2021 21:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save awesomekling/36b624f04838498dfd948da907348664 to your computer and use it in GitHub Desktop.
Save awesomekling/36b624f04838498dfd948da907348664 to your computer and use it in GitHub Desktop.
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