/* * Copyright (c) 2021-2024, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include namespace JS::Bytecode { GC_DEFINE_ALLOCATOR(Executable); Executable::Executable( Vector bytecode, NonnullOwnPtr identifier_table, NonnullOwnPtr string_table, NonnullOwnPtr regex_table, Vector constants, NonnullRefPtr source_code, size_t number_of_property_lookup_caches, size_t number_of_global_variable_caches, size_t number_of_registers, bool is_strict_mode) : bytecode(move(bytecode)) , string_table(move(string_table)) , identifier_table(move(identifier_table)) , regex_table(move(regex_table)) , constants(move(constants)) , source_code(move(source_code)) , number_of_registers(number_of_registers) , is_strict_mode(is_strict_mode) { property_lookup_caches.resize(number_of_property_lookup_caches); global_variable_caches.resize(number_of_global_variable_caches); } Executable::~Executable() = default; void Executable::dump() const { warnln("\033[37;1mJS bytecode executable\033[0m \"{}\"", name); InstructionStreamIterator it(bytecode, this); size_t basic_block_offset_index = 0; while (!it.at_end()) { bool print_basic_block_marker = false; if (basic_block_offset_index < basic_block_start_offsets.size() && it.offset() == basic_block_start_offsets[basic_block_offset_index]) { ++basic_block_offset_index; print_basic_block_marker = true; } StringBuilder builder; builder.appendff("[{:4x}] ", it.offset()); if (print_basic_block_marker) builder.appendff("{:4}: ", basic_block_offset_index - 1); else builder.append(" "sv); builder.append((*it).to_byte_string(*this)); warnln("{}", builder.string_view()); ++it; } if (!exception_handlers.is_empty()) { warnln(""); warnln("Exception handlers:"); for (auto& handlers : exception_handlers) { warnln(" from {:4x} to {:4x} handler {:4x} finalizer {:4x}", handlers.start_offset, handlers.end_offset, handlers.handler_offset.value_or(0), handlers.finalizer_offset.value_or(0)); } } warnln(""); } void Executable::visit_edges(Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(constants); } Optional Executable::exception_handlers_for_offset(size_t offset) const { for (auto& handlers : exception_handlers) { if (handlers.start_offset <= offset && offset < handlers.end_offset) return handlers; } return {}; } UnrealizedSourceRange Executable::source_range_at(size_t offset) const { if (offset >= bytecode.size()) return {}; auto it = InstructionStreamIterator(bytecode.span().slice(offset), this); VERIFY(!it.at_end()); auto mapping = source_map.get(offset); if (!mapping.has_value()) return {}; return UnrealizedSourceRange { .source_code = source_code, .start_offset = mapping->source_start_offset, .end_offset = mapping->source_end_offset, }; } }