swamp_code_gen/
disasm.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use source_map_cache::SourceMapWrapper;
6use source_map_node::FileId;
7use std::fmt;
8use std::fmt::Write;
9use swamp_vm_debug_info::DebugInfo;
10use swamp_vm_disasm::disasm_instructions_color;
11use swamp_vm_types::types::{VariableRegister, VmType, show_frame_memory, write_basic_type};
12use swamp_vm_types::{BinaryInstruction, FrameMemoryAddress, InstructionRange};
13
14#[must_use]
15pub const fn is_valid_file_id(file_id: FileId) -> bool {
16    file_id != 0 && file_id != 0xffff
17}
18pub fn show_parameters_and_variables(
19    return_type: &VmType,
20    variables: &[VariableRegister],
21    f: &mut dyn Write,
22) -> Result<(), fmt::Error> {
23    if !return_type.is_scalar() {
24        writeln!(f, "{}: {}", tinter::blue("r0"), &return_type,)?;
25        write_basic_type(&return_type.basic_type, FrameMemoryAddress(0), f, 0)?;
26        writeln!(f)?;
27    }
28
29    for variable_register in variables {
30        writeln!(
31            f,
32            "var{}: ({}): {} {}",
33            tinter::yellow(format!("{}", variable_register.unique_id_in_function)),
34            tinter::magenta(variable_register),
35            variable_register.register.ty,
36            variable_register.register.comment
37        )?;
38    }
39
40    Ok(())
41}
42
43/// # Panics
44///
45#[must_use]
46pub fn disasm_function(
47    return_type: &VmType,
48    instructions: &[BinaryInstruction],
49    range: &InstructionRange,
50    debug_info: &DebugInfo,
51    source_map_wrapper: &SourceMapWrapper,
52    use_color: bool,
53) -> String {
54    let mut header_output = String::new();
55
56    let info = debug_info.fetch(range.start.0 as usize).unwrap();
57
58    show_frame_memory(
59        &info.function_debug_info.frame_memory,
60        &mut header_output,
61        use_color,
62    )
63    .unwrap();
64
65    show_parameters_and_variables(
66        return_type,
67        &info.function_debug_info.frame_memory.variable_registers,
68        &mut header_output,
69    )
70    .expect("should work");
71
72    let asm = disasm_instructions_color(
73        instructions,
74        range,
75        debug_info,
76        source_map_wrapper,
77        use_color,
78    );
79
80    format!("{header_output}\n{asm}",)
81}
82
83pub fn disasm_whole_program(
84    debug_info: &DebugInfo,
85    source_map_wrapper: &SourceMapWrapper,
86    instructions: &[BinaryInstruction],
87    use_color: bool,
88) {
89    let mut current_ip: u32 = 0;
90
91    while current_ip < (instructions.len() - 1) as u32 {
92        if let Some(debug_info_for_pc) = debug_info.fetch(current_ip as usize) {
93            // log to stdout since this is a feature "asked" by the user
94            println!(
95                "{} ==========================================================================",
96                debug_info_for_pc.function_debug_info.name
97            );
98            let end_ip = current_ip + debug_info_for_pc.function_debug_info.ip_range.count.0;
99            //let instructions_slice = &instructions[current_ip as usize..end_ip as usize];
100
101            let output_string = disasm_function(
102                &debug_info_for_pc.function_debug_info.return_type,
103                instructions,
104                &debug_info_for_pc.function_debug_info.ip_range,
105                debug_info,
106                source_map_wrapper,
107                use_color,
108            );
109            println!("{output_string}"); // log to stdout since this is a feature "asked" by the user
110            current_ip = end_ip;
111        } else {
112            panic!("instruction pointer that is not covered")
113        }
114    }
115}