LibJS: Move bytecode block counting to Rust

Use the Rust bytecode dumper's basic block collection logic for the
metadata block count. This removes the last C++ bytecode label walk and
lets us delete the generated C++ label and operand visitor helpers.
This commit is contained in:
Andreas Kling 2026-06-14 20:51:57 +02:00 committed by Andreas Kling
parent 984d3033e9
commit e5bcffc3d5
Notes: github-actions[bot] 2026-06-15 00:42:59 +00:00
8 changed files with 47 additions and 188 deletions

View file

@ -7,7 +7,6 @@
#include <AK/BinarySearch.h>
#include <AK/NeverDestroyed.h>
#include <AK/NumericLimits.h>
#include <AK/QuickSort.h>
#include <AK/StdLibExtras.h>
#include <LibGC/Heap.h>
#include <LibGC/HeapBlock.h>
@ -373,71 +372,6 @@ static void dump_header(StringBuilder& output, Executable const& executable)
output.append('\n');
}
static bool instruction_is_terminator(Instruction const& instruction)
{
#define __BYTECODE_OP(op) \
case Instruction::Type::op: \
return Op::op::IsTerminator;
switch (instruction.type()) {
ENUMERATE_BYTECODE_OPS(__BYTECODE_OP)
default:
VERIFY_NOT_REACHED();
}
#undef __BYTECODE_OP
}
static Vector<u32> collect_basic_block_start_offsets(Executable const& executable)
{
Vector<u32> offsets;
auto append_offset = [&](size_t offset) {
VERIFY(offset <= NumericLimits<u32>::max());
auto offset32 = static_cast<u32>(offset);
if (!offsets.contains_slow(offset32))
offsets.append(offset32);
};
auto append_instruction_offset = [&](size_t offset) {
if (offset < executable.bytecode.size())
append_offset(offset);
};
append_offset(0);
for (InstructionStreamIterator it(executable.bytecode, &executable); !it.at_end(); ++it) {
auto const& instruction = *it;
auto next_offset = it.offset() + instruction.length();
const_cast<Instruction&>(instruction).visit_labels([&](Label& label) {
append_offset(label.address());
});
if (instruction_is_terminator(instruction) && next_offset < executable.bytecode.size())
append_offset(next_offset);
}
for (auto const& handler : executable.exception_handlers) {
append_instruction_offset(handler.start_offset);
append_instruction_offset(handler.end_offset);
append_instruction_offset(handler.handler_offset);
}
quick_sort(offsets);
return offsets;
}
Optional<size_t> Executable::basic_block_index_for_offset(size_t offset) const
{
VERIFY(offset <= NumericLimits<u32>::max());
auto basic_block_start_offsets = collect_basic_block_start_offsets(*this);
size_t index = 0;
if (binary_search(basic_block_start_offsets, static_cast<u32>(offset), &index))
return index;
return {};
}
static void dump_metadata(StringBuilder& output, Executable const& executable)
{
auto constexpr green = "\033[32m"sv;
@ -447,7 +381,7 @@ static void dump_metadata(StringBuilder& output, Executable const& executable)
auto constexpr reset = "\033[0m"sv;
output.appendff(" {}Registers{}: {}\n", green, reset, executable.number_of_registers);
output.appendff(" {}Blocks{}: {}\n", green, reset, collect_basic_block_start_offsets(executable).size());
output.appendff(" {}Blocks{}: {}\n", green, reset, RustIntegration::count_bytecode_basic_blocks(executable));
if (!executable.local_variable_names.is_empty()) {
output.appendff(" {}Locals{}: ", green, reset);