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_isa::BinaryInstruction;
12use swamp_vm_types::types::{show_frame_memory, write_basic_type, VariableRegister, VmType};
13use swamp_vm_types::{FrameMemoryAddress, InstructionRange};
14
15#[must_use]
16pub const fn is_valid_file_id(file_id: FileId) -> bool {
17    file_id != 0 && file_id != 0xffff
18}
19pub fn show_parameters_and_variables(
20    return_type: &VmType,
21    variables: &[VariableRegister],
22    f: &mut dyn Write,
23    use_color: bool,
24) -> Result<(), fmt::Error> {
25    if use_color {
26        if !return_type.is_scalar() {
27            writeln!(f, "{}: {}", tinter::blue("r0"), &return_type, )?;
28            write_basic_type(&return_type.basic_type, FrameMemoryAddress(0), f, 0)?;
29            writeln!(f)?;
30        }
31
32        for variable_register in variables {
33            writeln!(
34                f,
35                "var {}: ({}): {} {}",
36                tinter::yellow(format!("{}", variable_register.unique_id_in_function)),
37                tinter::magenta(variable_register),
38                variable_register.register.ty,
39                variable_register.register.comment
40            )?;
41        }
42    } else {
43        if !return_type.is_scalar() {
44            writeln!(f, "{}: {}", "r0", &return_type, )?;
45            write_basic_type(&return_type.basic_type, FrameMemoryAddress(0), f, 0)?;
46            writeln!(f)?;
47        }
48
49        for variable_register in variables {
50            writeln!(
51                f,
52                "var {}: ({}): {} {}",
53                format!("{}", variable_register.unique_id_in_function),
54                variable_register,
55                variable_register.register.ty,
56                variable_register.register.comment
57            )?;
58        }
59    }
60
61    Ok(())
62}
63
64/// # Panics
65///
66#[must_use]
67pub fn disasm_function(
68    return_type: &VmType,
69    instructions: &[BinaryInstruction],
70    range: &InstructionRange,
71    debug_info: &DebugInfo,
72    source_map_wrapper: &SourceMapWrapper,
73    use_color: bool,
74) -> String {
75    let mut header_output = String::new();
76
77    let info = debug_info.fetch(range.start.0 as usize).unwrap();
78
79    show_frame_memory(
80        &info.function_debug_info.frame_memory,
81        &mut header_output,
82        use_color,
83    )
84        .unwrap();
85
86    show_parameters_and_variables(
87        return_type,
88        &info.function_debug_info.frame_memory.variable_registers,
89        &mut header_output,
90        use_color,
91    )
92        .expect("should work");
93
94    let asm = disasm_instructions_color(
95        instructions,
96        range,
97        debug_info,
98        source_map_wrapper,
99        use_color,
100    );
101
102    format!("{header_output}\n{asm}", )
103}
104
105pub fn disasm_whole_program(
106    debug_info: &DebugInfo,
107    source_map_wrapper: &SourceMapWrapper,
108    instructions: &[BinaryInstruction],
109    use_color: bool,
110) {
111    let mut current_ip: u32 = 0;
112
113    while current_ip < (instructions.len() - 1) as u32 {
114        if let Some(debug_info_for_pc) = debug_info.fetch(current_ip as usize) {
115            // log to stdout since this is a feature "asked" by the user
116            println!(
117                "{} ==========================================================================",
118                debug_info_for_pc.function_debug_info.name
119            );
120            let end_ip = current_ip + debug_info_for_pc.function_debug_info.ip_range.count.0;
121            //let instructions_slice = &instructions[current_ip as usize..end_ip as usize];
122
123            let output_string = disasm_function(
124                &debug_info_for_pc.function_debug_info.return_type,
125                instructions,
126                &debug_info_for_pc.function_debug_info.ip_range,
127                debug_info,
128                source_map_wrapper,
129                use_color,
130            );
131            println!("{output_string}"); // log to stdout since this is a feature "asked" by the user
132            current_ip = end_ip;
133        } else {
134            panic!("instruction pointer that is not covered")
135        }
136    }
137}