mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-06 16:19:23 +00:00
LibJS: Allow using local variable for catch parameters
Local variables are faster to access and if all catch parameters are locals we can skip lexical environment allocation.
This commit is contained in:
parent
0f14c70252
commit
7932091e02
Notes:
github-actions[bot]
2025-04-22 19:58:29 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: 7932091e02
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4421
Reviewed-by: https://github.com/gmta
3 changed files with 49 additions and 28 deletions
|
@ -105,21 +105,25 @@ public:
|
|||
return scope_pusher;
|
||||
}
|
||||
|
||||
static ScopePusher catch_scope(Parser& parser, RefPtr<BindingPattern const> const& pattern, RefPtr<Identifier const> const& parameter)
|
||||
static ScopePusher catch_scope(Parser& parser)
|
||||
{
|
||||
return ScopePusher(parser, nullptr, ScopeLevel::NotTopLevel, ScopeType::Catch);
|
||||
}
|
||||
|
||||
void add_catch_parameter(RefPtr<BindingPattern const> const& pattern, RefPtr<Identifier const> const& parameter)
|
||||
{
|
||||
ScopePusher scope_pusher(parser, nullptr, ScopeLevel::NotTopLevel, ScopeType::Catch);
|
||||
if (pattern) {
|
||||
// NOTE: Nothing in the callback throws an exception.
|
||||
MUST(pattern->for_each_bound_identifier([&](auto const& identifier) {
|
||||
scope_pusher.m_forbidden_var_names.set(identifier.string());
|
||||
scope_pusher.m_bound_names.set(identifier.string());
|
||||
m_forbidden_var_names.set(identifier.string());
|
||||
m_bound_names.set(identifier.string());
|
||||
m_catch_parameter_names.set(identifier.string());
|
||||
}));
|
||||
} else if (parameter) {
|
||||
scope_pusher.m_var_names.set(parameter->string());
|
||||
scope_pusher.m_bound_names.set(parameter->string());
|
||||
m_var_names.set(parameter->string());
|
||||
m_bound_names.set(parameter->string());
|
||||
m_catch_parameter_names.set(parameter->string());
|
||||
}
|
||||
|
||||
return scope_pusher;
|
||||
}
|
||||
|
||||
static ScopePusher static_init_block_scope(Parser& parser, ScopeNode& node)
|
||||
|
@ -289,12 +293,6 @@ public:
|
|||
auto const& identifier_group_name = it.key;
|
||||
auto& identifier_group = it.value;
|
||||
|
||||
if (m_parser.m_state.in_catch_parameter_context) {
|
||||
// NOTE: The parser currently cannot determine if an identifier captured by a function belongs to the environment created by a catch parameter.
|
||||
// As a result, any identifiers used inside the catch parameter are not considered as candidates for optimization in local or global variable access.
|
||||
continue;
|
||||
}
|
||||
|
||||
bool scope_has_declaration = false;
|
||||
if (is_top_level() && m_var_names.contains(identifier_group_name))
|
||||
scope_has_declaration = true;
|
||||
|
@ -304,13 +302,16 @@ public:
|
|||
if (m_type == ScopeType::Function && !m_is_arrow_function && identifier_group_name == "arguments"sv)
|
||||
scope_has_declaration = true;
|
||||
|
||||
if (m_type == ScopeType::Catch && m_catch_parameter_names.contains(identifier_group_name))
|
||||
scope_has_declaration = true;
|
||||
|
||||
bool hoistable_function_declaration = false;
|
||||
for (auto const& function_declaration : m_functions_to_hoist) {
|
||||
if (function_declaration->name() == identifier_group_name)
|
||||
hoistable_function_declaration = true;
|
||||
}
|
||||
|
||||
if ((m_type == ScopeType::ClassDeclaration || m_type == ScopeType::Catch) && m_bound_names.contains(identifier_group_name)) {
|
||||
if (m_type == ScopeType::ClassDeclaration && m_bound_names.contains(identifier_group_name)) {
|
||||
// NOTE: Currently, the parser cannot recognize that assigning a named function expression creates a scope with a binding for the function name.
|
||||
// As a result, function names are not considered as candidates for optimization in global variable access.
|
||||
continue;
|
||||
|
@ -321,8 +322,8 @@ public:
|
|||
identifier_group.might_be_variable_in_lexical_scope_in_named_function_assignment = true;
|
||||
}
|
||||
|
||||
if (m_type == ScopeType::ClassDeclaration || m_type == ScopeType::Catch) {
|
||||
// NOTE: Class declaration and catch scopes do not have own ScopeNode hence can't contain declaration of any variable
|
||||
if (m_type == ScopeType::ClassDeclaration) {
|
||||
// NOTE: Class declaration doesn't not have own ScopeNode hence can't contain declaration of any variable
|
||||
scope_has_declaration = false;
|
||||
}
|
||||
|
||||
|
@ -494,6 +495,7 @@ private:
|
|||
HashTable<FlyString> m_lexical_names;
|
||||
HashTable<FlyString> m_var_names;
|
||||
HashTable<FlyString> m_function_names;
|
||||
HashTable<FlyString> m_catch_parameter_names;
|
||||
|
||||
HashTable<FlyString> m_forbidden_lexical_names;
|
||||
HashTable<FlyString> m_forbidden_var_names;
|
||||
|
@ -3777,11 +3779,12 @@ NonnullRefPtr<CatchClause const> Parser::parse_catch_clause()
|
|||
auto rule_start = push_start();
|
||||
consume(TokenType::Catch);
|
||||
|
||||
ScopePusher catch_scope = ScopePusher::catch_scope(*this);
|
||||
|
||||
RefPtr<Identifier const> parameter;
|
||||
RefPtr<BindingPattern const> pattern_parameter;
|
||||
auto should_expect_parameter = false;
|
||||
if (match(TokenType::ParenOpen)) {
|
||||
TemporaryChange catch_parameter_context_change { m_state.in_catch_parameter_context, true };
|
||||
should_expect_parameter = true;
|
||||
consume();
|
||||
if (match_identifier_name()
|
||||
|
@ -3814,7 +3817,8 @@ NonnullRefPtr<CatchClause const> Parser::parse_catch_clause()
|
|||
bound_names.set(parameter->string());
|
||||
}
|
||||
|
||||
ScopePusher catch_scope = ScopePusher::catch_scope(*this, pattern_parameter, parameter);
|
||||
catch_scope.add_catch_parameter(pattern_parameter, parameter);
|
||||
|
||||
auto body = parse_block_statement();
|
||||
|
||||
// NOTE: Nothing in the callback throws an exception.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue