diff --git a/Libraries/LibJS/Bytecode/Executable.cpp b/Libraries/LibJS/Bytecode/Executable.cpp index aee5c0afcf..c537b4b5ad 100644 --- a/Libraries/LibJS/Bytecode/Executable.cpp +++ b/Libraries/LibJS/Bytecode/Executable.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include namespace JS::Bytecode { @@ -490,31 +491,6 @@ static void dump_metadata(StringBuilder& output, Executable const& executable) } } -static void dump_bytecode(StringBuilder& output, Executable const& executable) -{ - auto constexpr magenta = "\033[35;1m"sv; - auto constexpr reset = "\033[0m"sv; - - InstructionStreamIterator it(executable.bytecode, &executable); - auto basic_block_start_offsets = collect_basic_block_start_offsets(executable); - - size_t basic_block_offset_index = 0; - - while (!it.at_end()) { - if (basic_block_offset_index < basic_block_start_offsets.size() - && it.offset() == basic_block_start_offsets[basic_block_offset_index]) { - if (basic_block_offset_index > 0) - output.append('\n'); - output.appendff("{}block{}{}:\n", magenta, basic_block_offset_index, reset); - ++basic_block_offset_index; - } - - output.appendff(" [{:4x}] {}\n", it.offset(), (*it).to_byte_string(executable)); - - ++it; - } -} - void Executable::dump() const { StringBuilder output; @@ -522,7 +498,7 @@ void Executable::dump() const dump_header(output, *this); dump_metadata(output, *this); output.append('\n'); - dump_bytecode(output, *this); + RustIntegration::dump_bytecode(output, *this); if (!exception_handlers.is_empty()) { output.append("\nException handlers:\n"sv); diff --git a/Libraries/LibJS/Bytecode/FormatOperand.h b/Libraries/LibJS/Bytecode/FormatOperand.h index 76f90d81bf..69fec72079 100644 --- a/Libraries/LibJS/Bytecode/FormatOperand.h +++ b/Libraries/LibJS/Bytecode/FormatOperand.h @@ -81,28 +81,4 @@ inline ByteString format_operand(StringView name, Operand encoded_operand, Bytec return builder.to_byte_string(); } -inline ByteString format_operand_list(StringView name, ReadonlySpan operands, Bytecode::Executable const& executable) -{ - StringBuilder builder; - if (!name.is_empty()) - builder.appendff("\033[32m{}\033[0m:[", name); - for (size_t i = 0; i < operands.size(); ++i) { - if (i != 0) - builder.append(", "sv); - builder.appendff("{}", format_operand(""sv, operands[i], executable)); - } - builder.append("]"sv); - return builder.to_byte_string(); -} - -inline ByteString format_value_list(StringView name, ReadonlySpan values) -{ - StringBuilder builder; - if (!name.is_empty()) - builder.appendff("\033[32m{}\033[0m:[", name); - builder.join(", "sv, values); - builder.append("]"sv); - return builder.to_byte_string(); -} - } diff --git a/Libraries/LibJS/Bytecode/Instruction.h b/Libraries/LibJS/Bytecode/Instruction.h index 7ec5675467..9ab25aafbb 100644 --- a/Libraries/LibJS/Bytecode/Instruction.h +++ b/Libraries/LibJS/Bytecode/Instruction.h @@ -80,7 +80,6 @@ public: Type type() const { return m_type; } size_t length() const; - ByteString to_byte_string(Bytecode::Executable const&) const; void visit_labels(Function visitor); void visit_operands(Function visitor); diff --git a/Libraries/LibJS/Bytecode/Interpreter.cpp b/Libraries/LibJS/Bytecode/Interpreter.cpp index 5663d00917..e5d1bb35ec 100644 --- a/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -313,19 +312,4 @@ ThrowCompletionOr VM::run_executable(ExecutionContext& context, Executabl return reg(Register::return_value()); } -ByteString Instruction::to_byte_string(Bytecode::Executable const& executable) const -{ -#define __BYTECODE_OP(op) \ - case Instruction::Type::op: \ - return static_cast(*this).to_byte_string_impl(executable); - - switch (type()) { - ENUMERATE_BYTECODE_OPS(__BYTECODE_OP) - default: - VERIFY_NOT_REACHED(); - } - -#undef __BYTECODE_OP -} - } diff --git a/Libraries/LibJS/Bytecode/Operand.h b/Libraries/LibJS/Bytecode/Operand.h index bd8d88bcf8..bf10ed3b6d 100644 --- a/Libraries/LibJS/Bytecode/Operand.h +++ b/Libraries/LibJS/Bytecode/Operand.h @@ -35,6 +35,13 @@ public: 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; } @@ -54,6 +61,8 @@ public: } private: + Operand() = default; + u32 m_raw { 0 }; }; diff --git a/Libraries/LibJS/Rust/build.rs b/Libraries/LibJS/Rust/build.rs index 85fc3781ec..18f0fefc3b 100644 --- a/Libraries/LibJS/Rust/build.rs +++ b/Libraries/LibJS/Rust/build.rs @@ -68,11 +68,31 @@ fn generate_rust_code(mut w: impl Write, ops: &[OpDef]) -> Result<(), Box Result<(), Box> { + writeln!(w, "pub fn instruction_is_terminator_from_opcode(opcode: u8) -> bool {{")?; + let terminators = ops + .iter() + .enumerate() + .filter(|(_, op)| op.is_terminator) + .map(|(i, _)| i.to_string()) + .collect::>(); + writeln!(w, " matches!(opcode, {})", terminators.join(" | "))?; + writeln!(w, "}}")?; + writeln!(w)?; + Ok(()) +} + fn generate_num_opcodes_const(mut w: impl Write, ops: &[OpDef]) -> Result<(), Box> { writeln!(w, "/// Number of distinct opcodes (the valid range for the type byte).")?; writeln!(w, "pub const NUM_OPCODES: u32 = {};", ops.len())?; @@ -153,6 +173,351 @@ fn generate_instruction_length_from_bytes(mut w: impl Write, ops: &[OpDef]) -> R Ok(()) } +fn read_expr_for_type(ty: &str, offset: usize) -> String { + match ty { + "bool" => format!("bytes[at + {offset}] != 0"), + "u32" + | "Completion::Type" + | "IteratorHint" + | "EnvironmentMode" + | "PutKind" + | "ArgumentsKind" + | "FunctionNamePrefix" + | "PropertyLookupCacheIndex" + | "GlobalVariableCacheIndex" + | "EnvironmentCoordinateCacheIndex" + | "TemplateObjectCacheIndex" + | "ObjectShapeCacheIndex" + | "ObjectPropertyIteratorCacheIndex" => { + format!("super::validator::read_u32(bytes, at + {offset})") + } + "u64" | "Value" => format!("super::validator::read_u64(bytes, at + {offset})"), + "Operand" => format!("Operand::from_raw(super::validator::read_u32(bytes, at + {offset}))"), + "Optional" => format!("Operand::optional_from_raw(super::validator::read_u32(bytes, at + {offset}))"), + "Label" => format!("Label(super::validator::read_u32(bytes, at + {offset}))"), + "Optional