mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 22:02:44 +00:00 
			
		
		
		
	LibJS: Use local variables for function declarations when possible
Previously, the usage of local variables was limited for all function declarations. This change relaxes the restriction and only prohibits locals for hoistable annexB declarations.
This commit is contained in:
		
							parent
							
								
									167495b87b
								
							
						
					
					
						commit
						8b6450842e
					
				
					 4 changed files with 36 additions and 26 deletions
				
			
		|  | @ -4769,8 +4769,12 @@ void ScopeNode::block_declaration_instantiation(VM& vm, Environment* environment | ||||||
|         if (is<FunctionDeclaration>(declaration)) { |         if (is<FunctionDeclaration>(declaration)) { | ||||||
|             auto& function_declaration = static_cast<FunctionDeclaration const&>(declaration); |             auto& function_declaration = static_cast<FunctionDeclaration const&>(declaration); | ||||||
|             auto function = ECMAScriptFunctionObject::create(realm, function_declaration.name(), function_declaration.source_text(), function_declaration.body(), function_declaration.parameters(), function_declaration.function_length(), function_declaration.local_variables_names(), environment, private_environment, function_declaration.kind(), function_declaration.is_strict_mode(), function_declaration.might_need_arguments_object(), function_declaration.contains_direct_call_to_eval()); |             auto function = ECMAScriptFunctionObject::create(realm, function_declaration.name(), function_declaration.source_text(), function_declaration.body(), function_declaration.parameters(), function_declaration.function_length(), function_declaration.local_variables_names(), environment, private_environment, function_declaration.kind(), function_declaration.is_strict_mode(), function_declaration.might_need_arguments_object(), function_declaration.contains_direct_call_to_eval()); | ||||||
|             VERIFY(is<DeclarativeEnvironment>(*environment)); |             if (vm.bytecode_interpreter_if_exists() && function_declaration.name_identifier()->is_local()) { | ||||||
|             static_cast<DeclarativeEnvironment&>(*environment).initialize_or_set_mutable_binding({}, vm, function_declaration.name(), function); |                 vm.running_execution_context().local_variables[function_declaration.name_identifier()->local_variable_index()] = function; | ||||||
|  |             } else { | ||||||
|  |                 VERIFY(is<DeclarativeEnvironment>(*environment)); | ||||||
|  |                 static_cast<DeclarativeEnvironment&>(*environment).initialize_or_set_mutable_binding({}, vm, function_declaration.name(), function); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     })); |     })); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -707,6 +707,7 @@ struct FunctionParameter { | ||||||
| class FunctionNode { | class FunctionNode { | ||||||
| public: | public: | ||||||
|     StringView name() const { return m_name ? m_name->string().view() : ""sv; } |     StringView name() const { return m_name ? m_name->string().view() : ""sv; } | ||||||
|  |     RefPtr<Identifier const> name_identifier() const { return m_name; } | ||||||
|     DeprecatedString const& source_text() const { return m_source_text; } |     DeprecatedString const& source_text() const { return m_source_text; } | ||||||
|     Statement const& body() const { return *m_body; } |     Statement const& body() const { return *m_body; } | ||||||
|     Vector<FunctionParameter> const& parameters() const { return m_parameters; } |     Vector<FunctionParameter> const& parameters() const { return m_parameters; } | ||||||
|  |  | ||||||
|  | @ -283,18 +283,6 @@ public: | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         for (size_t i = 0; i < m_functions_to_hoist.size(); i++) { |  | ||||||
|             auto const& function_declaration = m_functions_to_hoist[i]; |  | ||||||
|             if (m_lexical_names.contains(function_declaration->name()) || m_forbidden_var_names.contains(function_declaration->name())) |  | ||||||
|                 continue; |  | ||||||
|             if (is_top_level()) { |  | ||||||
|                 m_node->add_hoisted_function(move(m_functions_to_hoist[i])); |  | ||||||
|             } else { |  | ||||||
|                 if (!m_parent_scope->m_lexical_names.contains(function_declaration->name()) && !m_parent_scope->m_function_names.contains(function_declaration->name())) |  | ||||||
|                     m_parent_scope->m_functions_to_hoist.append(move(m_functions_to_hoist[i])); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         for (auto& it : m_identifier_groups) { |         for (auto& it : m_identifier_groups) { | ||||||
|             auto const& identifier_group_name = it.key; |             auto const& identifier_group_name = it.key; | ||||||
|             auto& identifier_group = it.value; |             auto& identifier_group = it.value; | ||||||
|  | @ -316,20 +304,21 @@ public: | ||||||
|                     scope_has_declaration = true; |                     scope_has_declaration = true; | ||||||
|             })); |             })); | ||||||
| 
 | 
 | ||||||
|             bool function_declaration = false; |  | ||||||
|             MUST(m_node->for_each_var_function_declaration_in_reverse_order([&](auto const& declaration) { |             MUST(m_node->for_each_var_function_declaration_in_reverse_order([&](auto const& declaration) { | ||||||
|                 if (declaration.name() == identifier_group_name) |                 if (declaration.name() == identifier_group_name) | ||||||
|                     function_declaration = true; |                     scope_has_declaration = true; | ||||||
|             })); |             })); | ||||||
|             MUST(m_node->for_each_lexical_function_declaration_in_reverse_order([&](auto const& declaration) { |             MUST(m_node->for_each_lexical_function_declaration_in_reverse_order([&](auto const& declaration) { | ||||||
|                 if (declaration.name() == identifier_group_name) |                 if (declaration.name() == identifier_group_name) | ||||||
|                     function_declaration = true; |                     scope_has_declaration = true; | ||||||
|             })); |  | ||||||
|             MUST(m_node->for_each_function_hoistable_with_annexB_extension([&](auto const& declaration) { |  | ||||||
|                 if (declaration.name() == identifier_group_name) |  | ||||||
|                     function_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_type == ScopeType::Catch) && m_bound_names.contains(identifier_group_name)) { | ||||||
|                 // NOTE: Currently class names and catch section parameters are not considered to become local variables
 |                 // NOTE: Currently class names and catch section parameters are not considered to become local variables
 | ||||||
|                 //       but this might be fixed in the future
 |                 //       but this might be fixed in the future
 | ||||||
|  | @ -346,7 +335,7 @@ public: | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (scope_has_declaration) { |             if (scope_has_declaration) { | ||||||
|                 if (function_declaration) |                 if (hoistable_function_declaration) | ||||||
|                     continue; |                     continue; | ||||||
| 
 | 
 | ||||||
|                 if (!identifier_group.captured_by_nested_function) { |                 if (!identifier_group.captured_by_nested_function) { | ||||||
|  | @ -377,6 +366,18 @@ public: | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         for (size_t i = 0; i < m_functions_to_hoist.size(); i++) { | ||||||
|  |             auto const& function_declaration = m_functions_to_hoist[i]; | ||||||
|  |             if (m_lexical_names.contains(function_declaration->name()) || m_forbidden_var_names.contains(function_declaration->name())) | ||||||
|  |                 continue; | ||||||
|  |             if (is_top_level()) { | ||||||
|  |                 m_node->add_hoisted_function(move(m_functions_to_hoist[i])); | ||||||
|  |             } else { | ||||||
|  |                 if (!m_parent_scope->m_lexical_names.contains(function_declaration->name()) && !m_parent_scope->m_function_names.contains(function_declaration->name())) | ||||||
|  |                     m_parent_scope->m_functions_to_hoist.append(move(m_functions_to_hoist[i])); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         VERIFY(m_parser.m_state.current_scope_pusher == this); |         VERIFY(m_parser.m_state.current_scope_pusher == this); | ||||||
|         m_parser.m_state.current_scope_pusher = m_parent_scope; |         m_parser.m_state.current_scope_pusher = m_parent_scope; | ||||||
|     } |     } | ||||||
|  | @ -2799,15 +2800,15 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u16 parse_options, O | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (parse_options & FunctionNodeParseOptions::HasDefaultExportName) { |         if (parse_options & FunctionNodeParseOptions::HasDefaultExportName) { | ||||||
|             name = create_ast_node<Identifier const>( |             name = create_identifier_and_register_in_current_scope( | ||||||
|                 { m_source_code, rule_start.position(), position() }, |                 { m_source_code, rule_start.position(), position() }, | ||||||
|                 ExportStatement::local_name_for_default); |                 ExportStatement::local_name_for_default); | ||||||
|         } else if (FunctionNodeType::must_have_name() || match_identifier()) { |         } else if (FunctionNodeType::must_have_name() || match_identifier()) { | ||||||
|             name = create_ast_node<Identifier const>( |             name = create_identifier_and_register_in_current_scope( | ||||||
|                 { m_source_code, rule_start.position(), position() }, |                 { m_source_code, rule_start.position(), position() }, | ||||||
|                 consume_identifier().DeprecatedFlyString_value()); |                 consume_identifier().DeprecatedFlyString_value()); | ||||||
|         } else if (is_function_expression && (match(TokenType::Yield) || match(TokenType::Await))) { |         } else if (is_function_expression && (match(TokenType::Yield) || match(TokenType::Await))) { | ||||||
|             name = create_ast_node<Identifier const>( |             name = create_identifier_and_register_in_current_scope( | ||||||
|                 { m_source_code, rule_start.position(), position() }, |                 { m_source_code, rule_start.position(), position() }, | ||||||
|                 consume().DeprecatedFlyString_value()); |                 consume().DeprecatedFlyString_value()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -616,7 +616,11 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia | ||||||
|     auto private_environment = callee_context.private_environment; |     auto private_environment = callee_context.private_environment; | ||||||
|     for (auto& declaration : functions_to_initialize) { |     for (auto& declaration : functions_to_initialize) { | ||||||
|         auto function = ECMAScriptFunctionObject::create(realm, declaration.name(), declaration.source_text(), declaration.body(), declaration.parameters(), declaration.function_length(), declaration.local_variables_names(), lex_environment, private_environment, declaration.kind(), declaration.is_strict_mode(), declaration.might_need_arguments_object(), declaration.contains_direct_call_to_eval()); |         auto function = ECMAScriptFunctionObject::create(realm, declaration.name(), declaration.source_text(), declaration.body(), declaration.parameters(), declaration.function_length(), declaration.local_variables_names(), lex_environment, private_environment, declaration.kind(), declaration.is_strict_mode(), declaration.might_need_arguments_object(), declaration.contains_direct_call_to_eval()); | ||||||
|         MUST(var_environment->set_mutable_binding(vm, declaration.name(), function, false)); |         if ((vm.bytecode_interpreter_if_exists() || kind() == FunctionKind::Generator) && declaration.name_identifier()->is_local()) { | ||||||
|  |             callee_context.local_variables[declaration.name_identifier()->local_variable_index()] = function; | ||||||
|  |         } else { | ||||||
|  |             MUST(var_environment->set_mutable_binding(vm, declaration.name(), function, false)); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (is<DeclarativeEnvironment>(*lex_environment)) |     if (is<DeclarativeEnvironment>(*lex_environment)) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Aliaksandr Kalenik
						Aliaksandr Kalenik