LibJS: Remove obsolete bytecode dump formatting helpers
The Rust bytecode dumper now formats exception handler labels, raw operands, builtins, labels, and registers. Remove the C++ dump-only formatters and flatten Operand to expose only the runtime value-array layout that C++ still observes.
This commit is contained in:
parent
7a6af95db3
commit
984d3033e9
9 changed files with 23 additions and 195 deletions
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Format.h>
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/Types.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
|
@ -45,20 +46,6 @@ enum class Builtin : u8 {
|
|||
__Count,
|
||||
};
|
||||
|
||||
static StringView builtin_name(Builtin value)
|
||||
{
|
||||
switch (value) {
|
||||
#define DEFINE_BUILTIN_CASE(name, snake_case_name, base, property, ...) \
|
||||
case Builtin::name: \
|
||||
return #base "." #property##sv;
|
||||
JS_ENUMERATE_BUILTINS(DEFINE_BUILTIN_CASE)
|
||||
#undef DEFINE_BUILTIN_CASE
|
||||
case Builtin::__Count:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
inline size_t builtin_argument_count(Builtin value)
|
||||
{
|
||||
switch (value) {
|
||||
|
|
@ -74,15 +61,3 @@ inline size_t builtin_argument_count(Builtin value)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<>
|
||||
struct Formatter<JS::Bytecode::Builtin> : Formatter<StringView> {
|
||||
ErrorOr<void> format(FormatBuilder& builder, JS::Bytecode::Builtin value)
|
||||
{
|
||||
return Formatter<StringView>::format(builder, builtin_name(value));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
#include <LibGC/Heap.h>
|
||||
#include <LibGC/HeapBlock.h>
|
||||
#include <LibJS/Bytecode/Executable.h>
|
||||
#include <LibJS/Bytecode/FormatOperand.h>
|
||||
#include <LibJS/Bytecode/Instruction.h>
|
||||
#include <LibJS/Bytecode/Op.h>
|
||||
#include <LibJS/Bytecode/RegexTable.h>
|
||||
|
|
@ -500,15 +499,6 @@ void Executable::dump() const
|
|||
output.append('\n');
|
||||
RustIntegration::dump_bytecode(output, *this);
|
||||
|
||||
if (!exception_handlers.is_empty()) {
|
||||
output.append("\nException handlers:\n"sv);
|
||||
for (auto const& handler : exception_handlers) {
|
||||
output.appendff(" [{:4x} .. {:4x}] => handler ", handler.start_offset, handler.end_offset);
|
||||
Label handler_label(static_cast<u32>(handler.handler_offset));
|
||||
output.appendff("{}\n", format_label(""sv, handler_label, *this));
|
||||
}
|
||||
}
|
||||
|
||||
output.append('\n');
|
||||
warnln("{}", output.string_view());
|
||||
}
|
||||
|
|
@ -693,16 +683,4 @@ SourceRange const& Executable::get_source_range(u32 program_counter)
|
|||
});
|
||||
}
|
||||
|
||||
Operand Executable::original_operand_from_raw(u32 raw) const
|
||||
{
|
||||
// NB: Layout is [registers | locals | constants | arguments]
|
||||
if (raw < number_of_registers)
|
||||
return Operand { Operand::Type::Register, raw };
|
||||
if (raw < registers_and_locals_count)
|
||||
return Operand { Operand::Type::Local, raw - local_index_base };
|
||||
if (raw < argument_index_base)
|
||||
return Operand { Operand::Type::Constant, raw - registers_and_locals_count };
|
||||
return Operand { Operand::Type::Argument, raw - argument_index_base };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -356,7 +356,6 @@ public:
|
|||
[[nodiscard]] SourceRange const& get_source_range(u32 program_counter);
|
||||
|
||||
void dump() const;
|
||||
[[nodiscard]] Operand original_operand_from_raw(u32) const;
|
||||
|
||||
virtual Cell const& owner_cell(Badge<GC::Heap>) const override { return *this; }
|
||||
virtual void remove_dead_cells(Badge<GC::Heap>) override;
|
||||
|
|
|
|||
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2025, Andreas Kling <andreas@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <LibJS/Bytecode/Executable.h>
|
||||
#include <LibJS/Bytecode/Operand.h>
|
||||
#include <LibJS/Bytecode/Register.h>
|
||||
#include <LibJS/Runtime/BigInt.h>
|
||||
#include <LibJS/Runtime/PrimitiveString.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
inline ByteString format_label(StringView name, Label const& label, Bytecode::Executable const& executable)
|
||||
{
|
||||
StringBuilder builder;
|
||||
if (!name.is_empty())
|
||||
builder.appendff("\033[32m{}\033[0m:", name);
|
||||
|
||||
auto address = label.address();
|
||||
if (auto basic_block_index = executable.basic_block_index_for_offset(address); basic_block_index.has_value()) {
|
||||
builder.appendff("\033[35mblock{}\033[0m", basic_block_index.value());
|
||||
return builder.to_byte_string();
|
||||
}
|
||||
builder.appendff("@{:x}", address);
|
||||
return builder.to_byte_string();
|
||||
}
|
||||
|
||||
inline ByteString format_operand(StringView name, Operand encoded_operand, Bytecode::Executable const& executable)
|
||||
{
|
||||
StringBuilder builder;
|
||||
if (!name.is_empty())
|
||||
builder.appendff("\033[32m{}\033[0m:", name);
|
||||
auto operand = executable.original_operand_from_raw(encoded_operand.raw());
|
||||
switch (operand.type()) {
|
||||
case Operand::Type::Register:
|
||||
if (operand.index() == Register::this_value().index()) {
|
||||
builder.appendff("\033[33mthis\033[0m");
|
||||
} else {
|
||||
builder.appendff("\033[33mreg{}\033[0m", operand.index());
|
||||
}
|
||||
break;
|
||||
case Operand::Type::Local:
|
||||
builder.appendff("\033[34m{}~{}\033[0m", executable.local_variable_names[operand.index()].name, operand.index());
|
||||
break;
|
||||
case Operand::Type::Argument:
|
||||
builder.appendff("\033[34marg{}\033[0m", operand.index());
|
||||
break;
|
||||
case Operand::Type::Constant: {
|
||||
builder.append("\033[36m"sv);
|
||||
auto value = executable.constants[operand.index()];
|
||||
if (value.is_special_empty_value())
|
||||
builder.append("<Empty>"sv);
|
||||
else if (value.is_boolean())
|
||||
builder.appendff("Bool({})", value.as_bool() ? "true"sv : "false"sv);
|
||||
else if (value.is_int32())
|
||||
builder.appendff("Int32({})", value.as_i32());
|
||||
else if (value.is_double())
|
||||
builder.appendff("Double({})", value.as_double());
|
||||
else if (value.is_bigint())
|
||||
builder.appendff("BigInt({})", MUST(value.as_bigint().to_string()));
|
||||
else if (value.is_string())
|
||||
builder.appendff("String(\"{}\")", value.as_string().utf8_string_view());
|
||||
else if (value.is_undefined())
|
||||
builder.append("Undefined"sv);
|
||||
else if (value.is_null())
|
||||
builder.append("Null"sv);
|
||||
else
|
||||
builder.appendff("Value: {}", value);
|
||||
builder.append("\033[0m"sv);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
return builder.to_byte_string();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -78,9 +78,4 @@ size_t Instruction::length() const
|
|||
#undef __BYTECODE_OP
|
||||
}
|
||||
|
||||
Operand::Operand(Register reg)
|
||||
: Operand(Type::Register, reg.index())
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Format.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
|
|
@ -26,11 +26,3 @@ private:
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct AK::Formatter<JS::Bytecode::Label> : AK::Formatter<FormatString> {
|
||||
ErrorOr<void> format(FormatBuilder& builder, JS::Bytecode::Label const& label)
|
||||
{
|
||||
return AK::Formatter<FormatString>::format(builder, "@{:x}"sv, label.address());
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,53 +13,17 @@ namespace JS::Bytecode {
|
|||
|
||||
class Operand {
|
||||
public:
|
||||
enum class Type {
|
||||
Register,
|
||||
Local,
|
||||
Constant,
|
||||
Argument,
|
||||
};
|
||||
|
||||
[[nodiscard]] bool operator==(Operand const&) const = default;
|
||||
|
||||
explicit Operand(Type type, u32 index)
|
||||
: m_raw(to_underlying(type) << 29 | index)
|
||||
{
|
||||
}
|
||||
|
||||
enum class ShouldMakeInvalid { Indeed };
|
||||
explicit Operand(ShouldMakeInvalid)
|
||||
: m_raw(0xffffffffu)
|
||||
{
|
||||
}
|
||||
|
||||
explicit Operand(Register);
|
||||
|
||||
static Operand from_raw(u32 raw)
|
||||
{
|
||||
Operand operand;
|
||||
operand.m_raw = raw;
|
||||
return operand;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_invalid() const { return m_raw == 0xffffffffu; }
|
||||
[[nodiscard]] bool is_register() const { return type() == Type::Register; }
|
||||
[[nodiscard]] bool is_local() const { return type() == Type::Local; }
|
||||
[[nodiscard]] bool is_constant() const { return type() == Type::Constant; }
|
||||
|
||||
[[nodiscard]] Type type() const { return static_cast<Type>((m_raw & 0xe0000000u) >> 29); }
|
||||
[[nodiscard]] u32 index() const { return m_raw & 0x1fffffff; }
|
||||
|
||||
[[nodiscard]] u32 raw() const { return m_raw; }
|
||||
|
||||
[[nodiscard]] Register as_register() const;
|
||||
|
||||
void offset_index_by(u32 offset)
|
||||
{
|
||||
m_raw &= 0x1fffffff;
|
||||
m_raw += offset;
|
||||
}
|
||||
|
||||
private:
|
||||
Operand() = default;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Format.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
|
|
@ -60,13 +60,3 @@ private:
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct AK::Formatter<JS::Bytecode::Register> : AK::Formatter<FormatString> {
|
||||
ErrorOr<void> format(FormatBuilder& builder, JS::Bytecode::Register const& value)
|
||||
{
|
||||
if (value.index() == JS::Bytecode::Register::accumulator_index)
|
||||
return builder.put_string("acc"sv);
|
||||
return AK::Formatter<FormatString>::format(builder, "${}"sv, value.index());
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -347,6 +347,23 @@ impl<'a> BytecodeDumper<'a> {
|
|||
}
|
||||
self.append("]");
|
||||
}
|
||||
|
||||
pub fn append_exception_handlers(&mut self, exception_handlers: &[FFIDumpExceptionHandler]) {
|
||||
if exception_handlers.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.append("\nException handlers:\n");
|
||||
for handler in exception_handlers {
|
||||
self.append(" [");
|
||||
self.append(&format!("{:4x}", handler.start_offset));
|
||||
self.append(" .. ");
|
||||
self.append(&format!("{:4x}", handler.end_offset));
|
||||
self.append("] => handler ");
|
||||
self.append_label("", handler.handler_offset as u32);
|
||||
self.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_basic_block_start_offsets(bytecode: &[u8], exception_handlers: &[FFIDumpExceptionHandler]) -> Vec<u32> {
|
||||
|
|
@ -459,5 +476,7 @@ pub unsafe extern "C" fn rust_dump_bytecode(
|
|||
at += instruction_length_from_bytes(bytecode[at], bytecode, at)
|
||||
.expect("validated bytecode should have valid instruction lengths");
|
||||
}
|
||||
|
||||
dumper.append_exception_handlers(exception_handlers);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue