mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-06 00:51:51 +00:00
LibJS: Skip allocating locals for arguments that allowed to be local
This allows us to get rid of instructions that move arguments to locals and allocate smaller JS::Value vector in ExecutionContext by reusing slots that were already allocated for arguments. With this change for following function: ```js function f(x, y) { return x + y; } ``` we now produce following bytecode: ``` [ 0] 0: Add dst:reg6, lhs:arg0, rhs:arg1 [ 10] Return value:reg6 ``` instead of: ``` [ 0] 0: GetArgument 0, dst:x~1 [ 10] GetArgument 1, dst:y~0 [ 20] Add dst:reg6, lhs:x~1, rhs:y~0 [ 30] Return value:reg6 ```
This commit is contained in:
parent
3f04d18ef7
commit
2d732b2251
Notes:
github-actions[bot]
2025-04-26 09:03:23 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: 2d732b2251
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4481
6 changed files with 102 additions and 39 deletions
|
@ -58,7 +58,7 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
|
|||
Optional<Operand> dst;
|
||||
auto local_var_index = function.shared_data().m_local_variables_names.find_first_index("arguments"_fly_string);
|
||||
if (local_var_index.has_value())
|
||||
dst = local(local_var_index.value());
|
||||
dst = local(Identifier::Local::variable(local_var_index.value()));
|
||||
|
||||
if (function.is_strict_mode() || !function.has_simple_parameter_list()) {
|
||||
emit<Op::CreateArguments>(dst, Op::CreateArguments::Kind::Unmapped, function.is_strict_mode());
|
||||
|
@ -77,11 +77,8 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
|
|||
auto& if_undefined_block = make_block();
|
||||
auto& if_not_undefined_block = make_block();
|
||||
|
||||
auto argument_reg = allocate_register();
|
||||
emit<Op::Mov>(argument_reg.operand(), Operand { Operand::Type::Argument, param_index });
|
||||
|
||||
emit<Op::JumpUndefined>(
|
||||
argument_reg.operand(),
|
||||
Operand { Operand::Type::Argument, param_index },
|
||||
Label { if_undefined_block },
|
||||
Label { if_not_undefined_block });
|
||||
|
||||
|
@ -95,9 +92,7 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
|
|||
|
||||
if (auto const* identifier = parameter.binding.get_pointer<NonnullRefPtr<Identifier const>>(); identifier) {
|
||||
if ((*identifier)->is_local()) {
|
||||
auto local_variable_index = (*identifier)->local_variable_index();
|
||||
emit<Op::Mov>(local(local_variable_index), Operand { Operand::Type::Argument, param_index });
|
||||
set_local_initialized((*identifier)->local_variable_index());
|
||||
set_local_initialized((*identifier)->local_index());
|
||||
} else {
|
||||
auto id = intern_identifier((*identifier)->string());
|
||||
if (function.shared_data().m_has_duplicates) {
|
||||
|
@ -122,7 +117,7 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
|
|||
for (auto const& variable_to_initialize : function.shared_data().m_var_names_to_initialize_binding) {
|
||||
auto const& id = variable_to_initialize.identifier;
|
||||
if (id.is_local()) {
|
||||
emit<Op::Mov>(local(id.local_variable_index()), add_constant(js_undefined()));
|
||||
emit<Op::Mov>(local(id.local_index()), add_constant(js_undefined()));
|
||||
} else {
|
||||
auto intern_id = intern_identifier(id.string());
|
||||
emit<Op::CreateVariable>(intern_id, Op::EnvironmentMode::Var, false);
|
||||
|
@ -153,14 +148,14 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
|
|||
emit<Op::Mov>(initial_value, add_constant(js_undefined()));
|
||||
} else {
|
||||
if (id.is_local()) {
|
||||
emit<Op::Mov>(initial_value, local(id.local_variable_index()));
|
||||
emit<Op::Mov>(initial_value, local(id.local_index()));
|
||||
} else {
|
||||
emit<Op::GetBinding>(initial_value, intern_identifier(id.string()));
|
||||
}
|
||||
}
|
||||
|
||||
if (id.is_local()) {
|
||||
emit<Op::Mov>(local(id.local_variable_index()), initial_value);
|
||||
emit<Op::Mov>(local(id.local_index()), initial_value);
|
||||
} else {
|
||||
auto intern_id = intern_identifier(id.string());
|
||||
emit<Op::CreateVariable>(intern_id, Op::EnvironmentMode::Var, false);
|
||||
|
@ -204,7 +199,7 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
|
|||
for (auto const& declaration : function.shared_data().m_functions_to_initialize) {
|
||||
auto const& identifier = *declaration.name_identifier();
|
||||
if (identifier.is_local()) {
|
||||
auto local_index = identifier.local_variable_index();
|
||||
auto local_index = identifier.local_index();
|
||||
emit<Op::NewFunction>(local(local_index), declaration, OptionalNone {});
|
||||
set_local_initialized(local_index);
|
||||
} else {
|
||||
|
@ -516,9 +511,11 @@ void Generator::free_register(Register reg)
|
|||
m_free_registers.append(reg);
|
||||
}
|
||||
|
||||
ScopedOperand Generator::local(u32 local_index)
|
||||
ScopedOperand Generator::local(Identifier::Local const& local)
|
||||
{
|
||||
return ScopedOperand { *this, Operand { Operand::Type::Local, static_cast<u32>(local_index) } };
|
||||
if (local.is_variable())
|
||||
return ScopedOperand { *this, Operand { Operand::Type::Local, static_cast<u32>(local.index) } };
|
||||
return ScopedOperand { *this, Operand { Operand::Type::Argument, static_cast<u32>(local.index) } };
|
||||
}
|
||||
|
||||
Generator::SourceLocationScope::SourceLocationScope(Generator& generator, ASTNode const& node)
|
||||
|
@ -880,11 +877,12 @@ CodeGenerationErrorOr<Optional<ScopedOperand>> Generator::emit_delete_reference(
|
|||
void Generator::emit_set_variable(JS::Identifier const& identifier, ScopedOperand value, Bytecode::Op::BindingInitializationMode initialization_mode, Bytecode::Op::EnvironmentMode environment_mode)
|
||||
{
|
||||
if (identifier.is_local()) {
|
||||
if (value.operand().is_local() && value.operand().index() == identifier.local_variable_index()) {
|
||||
auto local_index = identifier.local_index();
|
||||
if (value.operand().is_local() && local_index.is_variable() && value.operand().index() == local_index.index) {
|
||||
// Moving a local to itself is a no-op.
|
||||
return;
|
||||
}
|
||||
emit<Bytecode::Op::Mov>(local(identifier.local_variable_index()), value);
|
||||
emit<Bytecode::Op::Mov>(local(local_index), value);
|
||||
} else {
|
||||
auto identifier_index = intern_identifier(identifier.string());
|
||||
if (environment_mode == Bytecode::Op::EnvironmentMode::Lexical) {
|
||||
|
@ -1186,9 +1184,24 @@ bool Generator::is_local_initialized(u32 local_index) const
|
|||
return m_initialized_locals.find(local_index) != m_initialized_locals.end();
|
||||
}
|
||||
|
||||
void Generator::set_local_initialized(u32 local_index)
|
||||
bool Generator::is_local_initialized(Identifier::Local const& local) const
|
||||
{
|
||||
m_initialized_locals.set(local_index);
|
||||
if (local.is_variable())
|
||||
return m_initialized_locals.find(local.index) != m_initialized_locals.end();
|
||||
if (local.is_argument())
|
||||
return m_initialized_arguments.find(local.index) != m_initialized_arguments.end();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Generator::set_local_initialized(Identifier::Local const& local)
|
||||
{
|
||||
if (local.is_variable()) {
|
||||
m_initialized_locals.set(local.index);
|
||||
} else if (local.is_argument()) {
|
||||
m_initialized_arguments.set(local.index);
|
||||
} else {
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
ScopedOperand Generator::get_this(Optional<ScopedOperand> preferred_dst)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue