mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 17:47:36 +00:00
LibJS: Make accessing the current function's arguments cheaper
Instead of going through an environment record, make arguments of the currently executing function generate references via the argument index, which can later be resolved directly through the ExecutionContext.
This commit is contained in:
parent
da296ffd56
commit
12b283f32f
5 changed files with 207 additions and 4 deletions
|
@ -48,6 +48,31 @@ void Reference::put_value(GlobalObject& global_object, Value value)
|
|||
}
|
||||
|
||||
VERIFY(m_base_type == BaseType::Environment);
|
||||
|
||||
// Note: Optimisation, not from the spec.
|
||||
if (m_function_argument_index.has_value()) {
|
||||
// Note: Modifying this binding requires us to sync with the environment.
|
||||
if (!m_base_environment) {
|
||||
auto real_reference = global_object.vm().resolve_binding(m_name.as_string(), m_referenced_function_context->lexical_environment);
|
||||
m_base_environment = real_reference.m_base_environment;
|
||||
}
|
||||
|
||||
if (!global_object.vm().execution_context_stack().is_empty() && m_referenced_function_context == &global_object.vm().running_execution_context()) {
|
||||
auto& arguments = m_referenced_function_context->arguments;
|
||||
auto index = m_function_argument_index.value();
|
||||
if (arguments.size() > index) {
|
||||
arguments[index] = value;
|
||||
} else {
|
||||
arguments.ensure_capacity(index + 1);
|
||||
for (size_t i = arguments.size(); i < index; ++i)
|
||||
arguments.append(js_undefined());
|
||||
arguments.append(value);
|
||||
}
|
||||
m_base_environment->set_mutable_binding(global_object, name().as_string(), value, is_strict());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
VERIFY(m_base_environment);
|
||||
if (m_environment_coordinate.has_value())
|
||||
static_cast<DeclarativeEnvironment*>(m_base_environment)->set_mutable_binding_direct(global_object, m_environment_coordinate->index, value, m_strict);
|
||||
|
@ -80,6 +105,17 @@ Value Reference::get_value(GlobalObject& global_object) const
|
|||
}
|
||||
|
||||
VERIFY(m_base_type == BaseType::Environment);
|
||||
|
||||
// Note: Optimisation, not from the spec.
|
||||
if (m_function_argument_index.has_value()) {
|
||||
if (!global_object.vm().execution_context_stack().is_empty() && m_referenced_function_context == &global_object.vm().running_execution_context())
|
||||
return global_object.vm().argument(m_function_argument_index.value());
|
||||
if (!m_base_environment) {
|
||||
auto real_reference = global_object.vm().resolve_binding(m_name.as_string(), m_referenced_function_context->lexical_environment);
|
||||
m_base_environment = real_reference.m_base_environment;
|
||||
}
|
||||
}
|
||||
|
||||
VERIFY(m_base_environment);
|
||||
if (m_environment_coordinate.has_value())
|
||||
return static_cast<DeclarativeEnvironment*>(m_base_environment)->get_binding_value_direct(global_object, m_environment_coordinate->index, m_strict);
|
||||
|
@ -141,6 +177,12 @@ bool Reference::delete_(GlobalObject& global_object)
|
|||
|
||||
VERIFY(m_base_type == BaseType::Environment);
|
||||
|
||||
// Note: Optimisation, not from the spec.
|
||||
if (m_function_argument_index.has_value()) {
|
||||
// This is a direct reference to a function argument.
|
||||
return false;
|
||||
}
|
||||
|
||||
// c. Return ? base.DeleteBinding(ref.[[ReferencedName]]).
|
||||
return m_base_environment->delete_binding(global_object, m_name.as_string());
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <AK/String.h>
|
||||
#include <LibJS/Runtime/Environment.h>
|
||||
#include <LibJS/Runtime/EnvironmentCoordinate.h>
|
||||
#include <LibJS/Runtime/ExecutionContext.h>
|
||||
#include <LibJS/Runtime/PropertyName.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
|
@ -54,6 +55,28 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
Reference(FlyString referenced_name, size_t function_argument_index, bool strict = false, ExecutionContext* function_context = nullptr)
|
||||
: m_base_type(BaseType::Environment)
|
||||
, m_base_environment(nullptr)
|
||||
, m_name(move(referenced_name))
|
||||
, m_strict(strict)
|
||||
, m_environment_coordinate({})
|
||||
, m_function_argument_index(function_argument_index)
|
||||
, m_referenced_function_context(function_context)
|
||||
{
|
||||
}
|
||||
|
||||
Reference(Environment& base, FlyString referenced_name, size_t function_argument_index, bool strict = false, Optional<EnvironmentCoordinate> environment_coordinate = {}, ExecutionContext* function_context = nullptr)
|
||||
: m_base_type(BaseType::Environment)
|
||||
, m_base_environment(&base)
|
||||
, m_name(move(referenced_name))
|
||||
, m_strict(strict)
|
||||
, m_environment_coordinate(move(environment_coordinate))
|
||||
, m_function_argument_index(function_argument_index)
|
||||
, m_referenced_function_context(function_context)
|
||||
{
|
||||
}
|
||||
|
||||
Value base() const
|
||||
{
|
||||
VERIFY(m_base_type == BaseType::Value);
|
||||
|
@ -128,12 +151,14 @@ private:
|
|||
BaseType m_base_type { BaseType::Unresolvable };
|
||||
union {
|
||||
Value m_base_value {};
|
||||
Environment* m_base_environment;
|
||||
mutable Environment* m_base_environment;
|
||||
};
|
||||
PropertyName m_name;
|
||||
Value m_this_value;
|
||||
bool m_strict { false };
|
||||
Optional<EnvironmentCoordinate> m_environment_coordinate;
|
||||
Optional<size_t> m_function_argument_index;
|
||||
ExecutionContext* m_referenced_function_context { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue