/* * Copyright (c) 2021-2024, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include namespace JS::Bytecode { Generator::Generator() : m_string_table(make()) , m_identifier_table(make()) , m_regex_table(make()) { } CodeGenerationErrorOr> Generator::generate(VM& vm, ASTNode const& node, ReadonlySpan parameters, FunctionKind enclosing_function_kind) { Generator generator; for (auto const& parameter : parameters) { if (auto const* identifier = parameter.binding.get_pointer>(); identifier && (*identifier)->is_local()) { generator.set_local_initialized((*identifier)->local_variable_index()); } } generator.switch_to_basic_block(generator.make_block()); SourceLocationScope scope(generator, node); generator.m_enclosing_function_kind = enclosing_function_kind; if (generator.is_in_generator_or_async_function()) { // Immediately yield with no value. auto& start_block = generator.make_block(); generator.emit(Label { start_block }, generator.add_constant(js_undefined())); generator.switch_to_basic_block(start_block); // NOTE: This doesn't have to handle received throw/return completions, as GeneratorObject::resume_abrupt // will not enter the generator from the SuspendedStart state and immediately completes the generator. } auto last_value = TRY(node.generate_bytecode(generator)); if (!generator.current_block().is_terminated() && last_value.has_value()) { generator.emit(last_value.value()); } if (generator.is_in_generator_or_async_function()) { // Terminate all unterminated blocks with yield return for (auto& block : generator.m_root_basic_blocks) { if (block->is_terminated()) continue; generator.switch_to_basic_block(*block); generator.emit(nullptr, generator.add_constant(js_undefined())); } } bool is_strict_mode = false; if (is(node)) is_strict_mode = static_cast(node).is_strict_mode(); else if (is(node)) is_strict_mode = static_cast(node).in_strict_mode(); else if (is(node)) is_strict_mode = static_cast(node).is_strict_mode(); else if (is(node)) is_strict_mode = static_cast(node).is_strict_mode(); auto executable = vm.heap().allocate_without_realm( move(generator.m_identifier_table), move(generator.m_string_table), move(generator.m_regex_table), move(generator.m_constants), node.source_code(), generator.m_next_property_lookup_cache, generator.m_next_global_variable_cache, generator.m_next_environment_variable_cache, generator.m_next_register, move(generator.m_root_basic_blocks), is_strict_mode); return executable; } void Generator::grow(size_t additional_size) { VERIFY(m_current_basic_block); m_current_basic_block->grow(additional_size); } Register Generator::allocate_register() { VERIFY(m_next_register != NumericLimits::max()); return Register { m_next_register++ }; } Generator::SourceLocationScope::SourceLocationScope(Generator& generator, ASTNode const& node) : m_generator(generator) , m_previous_node(m_generator.m_current_ast_node) { m_generator.m_current_ast_node = &node; } Generator::SourceLocationScope::~SourceLocationScope() { m_generator.m_current_ast_node = m_previous_node; } Generator::UnwindContext::UnwindContext(Generator& generator, Optional