1use crate::ast::ExprType;
20use crate::bytecode::{self, Opcode, opcode_of};
21use crate::compiler::SymbolKey;
22use crate::mem::ConstantDatum;
23use crate::reader::LineCol;
24use std::collections::HashMap;
25
26pub(crate) fn format_instr(instr: u32) -> String {
30 match opcode_of(instr) {
31 Opcode::AddDouble => bytecode::format_add_double(instr),
32 Opcode::AddInteger => bytecode::format_add_integer(instr),
33 Opcode::Alloc => bytecode::format_alloc(instr),
34 Opcode::AllocArray => bytecode::format_alloc_array(instr),
35 Opcode::BitwiseAnd => bytecode::format_bitwise_and(instr),
36 Opcode::BitwiseNot => bytecode::format_bitwise_not(instr),
37 Opcode::BitwiseOr => bytecode::format_bitwise_or(instr),
38 Opcode::BitwiseXor => bytecode::format_bitwise_xor(instr),
39 Opcode::Call => bytecode::format_call(instr),
40 Opcode::Concat => bytecode::format_concat(instr),
41 Opcode::DivideDouble => bytecode::format_divide_double(instr),
42 Opcode::DivideInteger => bytecode::format_divide_integer(instr),
43 Opcode::DoubleToInteger => bytecode::format_double_to_integer(instr),
44 Opcode::EqualBoolean => bytecode::format_equal_boolean(instr),
45 Opcode::EqualDouble => bytecode::format_equal_double(instr),
46 Opcode::EqualInteger => bytecode::format_equal_integer(instr),
47 Opcode::EqualText => bytecode::format_equal_text(instr),
48 Opcode::Eof => bytecode::format_eof(instr),
49 Opcode::End => bytecode::format_end(instr),
50 Opcode::Gosub => bytecode::format_gosub(instr),
51 Opcode::GreaterDouble => bytecode::format_greater_double(instr),
52 Opcode::GreaterEqualDouble => bytecode::format_greater_equal_double(instr),
53 Opcode::GreaterEqualInteger => bytecode::format_greater_equal_integer(instr),
54 Opcode::GreaterEqualText => bytecode::format_greater_equal_text(instr),
55 Opcode::GreaterInteger => bytecode::format_greater_integer(instr),
56 Opcode::GreaterText => bytecode::format_greater_text(instr),
57 Opcode::IntegerToDouble => bytecode::format_integer_to_double(instr),
58 Opcode::Jump => bytecode::format_jump(instr),
59 Opcode::JumpIfFalse => bytecode::format_jump_if_false(instr),
60 Opcode::LessDouble => bytecode::format_less_double(instr),
61 Opcode::LessEqualDouble => bytecode::format_less_equal_double(instr),
62 Opcode::LessEqualInteger => bytecode::format_less_equal_integer(instr),
63 Opcode::LessEqualText => bytecode::format_less_equal_text(instr),
64 Opcode::LessInteger => bytecode::format_less_integer(instr),
65 Opcode::LessText => bytecode::format_less_text(instr),
66 Opcode::LoadArray => bytecode::format_load_array(instr),
67 Opcode::LoadConstant => bytecode::format_load_constant(instr),
68 Opcode::LoadInteger => bytecode::format_load_integer(instr),
69 Opcode::LoadRegisterPointer => bytecode::format_load_register_ptr(instr),
70 Opcode::ModuloDouble => bytecode::format_modulo_double(instr),
71 Opcode::ModuloInteger => bytecode::format_modulo_integer(instr),
72 Opcode::Move => bytecode::format_move(instr),
73 Opcode::MultiplyDouble => bytecode::format_multiply_double(instr),
74 Opcode::MultiplyInteger => bytecode::format_multiply_integer(instr),
75 Opcode::NegateDouble => bytecode::format_negate_double(instr),
76 Opcode::NegateInteger => bytecode::format_negate_integer(instr),
77 Opcode::NotEqualBoolean => bytecode::format_not_equal_boolean(instr),
78 Opcode::NotEqualDouble => bytecode::format_not_equal_double(instr),
79 Opcode::NotEqualInteger => bytecode::format_not_equal_integer(instr),
80 Opcode::NotEqualText => bytecode::format_not_equal_text(instr),
81 Opcode::Nop => bytecode::format_nop(instr),
82 Opcode::PowerDouble => bytecode::format_power_double(instr),
83 Opcode::PowerInteger => bytecode::format_power_integer(instr),
84 Opcode::Return => bytecode::format_return(instr),
85 Opcode::SetErrorHandler => bytecode::format_set_error_handler(instr),
86 Opcode::ShiftLeft => bytecode::format_shift_left(instr),
87 Opcode::ShiftRight => bytecode::format_shift_right(instr),
88 Opcode::StoreArray => bytecode::format_store_array(instr),
89 Opcode::SubtractDouble => bytecode::format_subtract_double(instr),
90 Opcode::SubtractInteger => bytecode::format_subtract_integer(instr),
91 Opcode::Upcall => bytecode::format_upcall(instr),
92 Opcode::UpcallAsync => bytecode::format_upcall_async(instr),
93 }
94}
95
96#[derive(Clone, Debug, Eq, PartialEq)]
98pub(crate) struct GlobalVarInfo {
99 pub(crate) reg: u8,
101
102 pub(crate) subtype: ExprType,
104
105 pub(crate) ndims: usize,
107}
108
109#[derive(Clone, Debug, Eq, PartialEq)]
111pub(crate) struct InstrMetadata {
112 pub(crate) linecol: LineCol,
114
115 pub(crate) is_stmt_start: bool,
117
118 pub(crate) arg_linecols: Vec<LineCol>,
123}
124
125#[derive(Default)]
127pub struct DebugInfo {
128 pub(crate) instrs: Vec<InstrMetadata>,
130
131 pub(crate) callables: HashMap<usize, (SymbolKey, bool)>,
134
135 pub(crate) global_vars: HashMap<SymbolKey, GlobalVarInfo>,
140
141 pub(crate) program_vars: HashMap<SymbolKey, GlobalVarInfo>,
146}
147
148pub(crate) struct ImageDelta {
150 pub(crate) code: Vec<u32>,
152
153 pub(crate) upcalls: Vec<SymbolKey>,
155
156 pub(crate) constants: Vec<ConstantDatum>,
158
159 pub(crate) data: Vec<Option<ConstantDatum>>,
161
162 pub(crate) instrs: Vec<InstrMetadata>,
164
165 pub(crate) callables: HashMap<usize, (SymbolKey, bool)>,
167
168 pub(crate) global_vars: HashMap<SymbolKey, GlobalVarInfo>,
170
171 pub(crate) program_vars: HashMap<SymbolKey, GlobalVarInfo>,
173}
174
175pub struct Image {
179 pub(crate) code: Vec<u32>,
181
182 pub(crate) upcalls: Vec<SymbolKey>,
184
185 pub(crate) constants: Vec<ConstantDatum>,
187
188 pub(crate) data: Vec<Option<ConstantDatum>>,
190
191 pub(crate) debug_info: DebugInfo,
193
194 _internal: (),
196}
197
198impl Default for Image {
199 fn default() -> Self {
200 Self::new(
201 vec![
202 bytecode::make_eof(),
205 ],
206 vec![],
207 vec![],
208 vec![],
209 DebugInfo {
210 instrs: vec![InstrMetadata {
211 linecol: LineCol { line: 0, col: 0 },
212 is_stmt_start: true,
213 arg_linecols: vec![],
214 }],
215 callables: HashMap::default(),
216 global_vars: HashMap::default(),
217 program_vars: HashMap::default(),
218 },
219 )
220 }
221}
222
223impl Image {
224 pub(crate) fn new(
225 code: Vec<u32>,
226 upcalls: Vec<SymbolKey>,
227 constants: Vec<ConstantDatum>,
228 data: Vec<Option<ConstantDatum>>,
229 debug_info: DebugInfo,
230 ) -> Self {
231 debug_assert!(!code.is_empty(), "Compiler must ensure the image is not empty");
232 debug_assert_eq!(code.len(), debug_info.instrs.len());
233 Self { code, upcalls, constants, data, debug_info, _internal: () }
234 }
235
236 pub(crate) fn append(&mut self, delta: ImageDelta) {
238 debug_assert_eq!(self.code.last().copied(), Some(bytecode::make_eof()));
239 debug_assert_eq!(self.debug_info.instrs.len(), self.code.len());
240 debug_assert_eq!(delta.code.len(), delta.instrs.len());
241 debug_assert_eq!(delta.code.last().copied(), Some(bytecode::make_eof()));
242
243 self.code.pop();
244 self.debug_info.instrs.pop();
245
246 self.code.extend(delta.code);
247 self.upcalls.extend(delta.upcalls);
248 self.constants.extend(delta.constants);
249 self.data.extend(delta.data);
250 self.debug_info.instrs.extend(delta.instrs);
251 self.debug_info.callables = delta.callables;
252 self.debug_info.global_vars = delta.global_vars;
253 self.debug_info.program_vars = delta.program_vars;
254 }
255
256 pub fn disasm(&self) -> Vec<String> {
258 let mut lines = Vec::with_capacity(self.code.len());
259
260 for ((i, instr), meta) in
261 self.code.iter().copied().enumerate().zip(self.debug_info.instrs.iter())
262 {
263 let pos = meta.linecol;
264 if let Some((key, is_start)) = self.debug_info.callables.get(&i) {
265 if *is_start {
266 lines.push("".to_owned());
267 lines.push(format!(";; {} (BEGIN)", key));
268 } else {
269 lines.push(format!(";; {} (END)", key));
270 lines.push("".to_owned());
271 }
272 }
273
274 let mut line = format!("{:04}: {}", i, format_instr(instr));
275
276 while line.len() < 40 {
277 line.push(' ');
278 }
279 line.push_str(&format!("; {}", pos));
280
281 match opcode_of(instr) {
282 Opcode::Call => {
283 let (_reg, target) = bytecode::parse_call(instr);
284 let target = usize::from(target);
285 let (name, _is_start) = self
286 .debug_info
287 .callables
288 .get(&target)
289 .expect("All CALL targets must be defined");
290 line.push_str(&format!(", {}", name))
291 }
292
293 Opcode::Upcall => {
294 let (index, _first_reg) = bytecode::parse_upcall(instr);
295 let name = &self.upcalls[usize::from(index)];
296 line.push_str(&format!(", {}", name))
297 }
298
299 Opcode::LoadConstant => {
300 let (_reg, index) = bytecode::parse_load_constant(instr);
301 let constant = &self.constants[usize::from(index)];
302 line.push_str(&format!(", {}", constant.as_disassembly()))
303 }
304
305 Opcode::UpcallAsync => {
306 let (index, _first_reg) = bytecode::parse_upcall_async(instr);
307 let name = &self.upcalls[usize::from(index)];
308 line.push_str(&format!(", {}", name))
309 }
310
311 _ => (),
312 }
313
314 lines.push(line);
315 }
316
317 lines
318 }
319}