zubbers/vm/
disassembler.rs1use super::*;
2use gc::trace::{ Trace, Tracer };
3use colored::Colorize;
4
5pub struct Disassembler<'c> {
6 offset: usize,
7 line: usize,
8 chunk: &'c Chunk,
9 heap: &'c Heap<Object>,
10}
11
12impl<'c> Disassembler<'c> {
13 pub fn new(chunk: &'c Chunk, heap: &'c Heap<Object>) -> Self {
14 Disassembler {
15 offset: 0,
16 line: 0,
17 chunk,
18 heap,
19 }
20 }
21
22 pub fn disassemble(mut self) {
23 let bytes = self.chunk.as_ref();
24
25 println!();
26 let name = format!("== {} ==", self.chunk.name());
27 eprint!("{}", name.cyan());
28
29 while self.offset < bytes.len() {
30 self.disassemble_instruction();
31 }
32
33 println!();
34 }
35
36 fn disassemble_instruction(&mut self) {
37 let line = self.chunk.line(self.offset);
38 if self.line == line {
39 } else {
40 self.line = line;
41 }
42 let inst = self.read_byte();
43 println!();
44 let off = format!("{:04} | ", self.offset);
45
46 eprint!("{}", off.blue());
47 decode_op!(inst, self);
48 }
49
50 fn constant(&mut self, idx: u8) {
51 let val = self.chunk.get_constant(idx);
52 eprint!("CONSTANT\t{}\t{:?}", idx, val);
53 }
54
55 fn ret(&self) { eprint!("RETURN"); }
56 fn print(&self) { eprint!("PRINT"); }
57 fn add(&self) { eprint!("ADD"); }
58 fn sub(&self) { eprint!("SUB"); }
59 fn mul(&self) { eprint!("MUL"); }
60 fn rem(&self) { eprint!("REM"); }
61 fn pow(&self) { eprint!("POW"); }
62 fn div(&self) { eprint!("DIV"); }
63 fn neg(&self) { eprint!("NEG"); }
64 fn not(&self) { eprint!("NOT"); }
65 fn eq(&self) { eprint!("EQ"); }
66 fn gt(&self) { eprint!("GT"); }
67 fn lt(&self) { eprint!("LT"); }
68 fn pop(&self) { eprint!("POP"); }
69
70 fn list(&mut self) {
71 eprint!("LIST");
72 self.read_byte();
73 }
74
75 fn index(&mut self) {}
76
77 fn dict(&mut self) {
78 eprint!("DICT");
79 self.read_byte();
80 }
81
82 fn set_element(&mut self) {
83 eprint!("SET_ELEMENT")
84 }
85
86
87 fn jmp(&mut self) {
88 let offset = self.offset - 1;
89 let ip = self.read_u16();
90 eprint!("JUMP\t{} -> {}", offset, ip);
91 }
92
93 fn jze(&mut self) {
94 let offset = self.offset - 1;
95 let ip = self.read_u16();
96 eprint!("JUMP_IF_FALSE\t{} -> {}", offset, ip);
97 }
98
99 fn op_loop(&mut self) {
100 let sub = self.read_u16() as usize;
101 eprint!("LOOP\t{} -> {}", self.offset, self.offset - sub);
102 }
103
104 fn get_global(&mut self) {
105 let val = self.read_constant();
106 eprint!("GET_GLOBAL\t{}", val.with_heap(self.heap));
107 }
108
109 fn set_global(&mut self) {
110 let val = self.read_constant();
111 eprint!("SET_GLOBAL\t{}", val.with_heap(self.heap));
112 }
113
114 fn define_global(&mut self) {
115 let name = self.read_constant();
116 eprint!("DEFINE_GLOBAL\t{}", name.with_heap(self.heap));
117 }
118
119 fn get_local(&mut self) {
120 let val = self.read_byte();
121 eprint!("GET_LOCAL\t{}", val);
122 }
123
124 fn set_local(&mut self) {
125 let val = self.read_byte();
126 eprint!("SET_LOCAL\t{}", val);
127 }
128
129 fn immediate(&mut self) {
130 self.offset += 8;
131 let b1 = self.chunk.get(self.offset - 8) as u64;
132 let b2 = self.chunk.get(self.offset - 7) as u64;
133 let b3 = self.chunk.get(self.offset - 6) as u64;
134 let b4 = self.chunk.get(self.offset - 5) as u64;
135 let b5 = self.chunk.get(self.offset - 4) as u64;
136 let b6 = self.chunk.get(self.offset - 3) as u64;
137 let b7 = self.chunk.get(self.offset - 2) as u64;
138 let b8 = self.chunk.get(self.offset - 1) as u64;
139 let raw = b1 +
140 (b2 << 8) +
141 (b3 << 16) +
142 (b4 << 24) +
143 (b5 << 32) +
144 (b6 << 40) +
145 (b7 << 48) +
146 (b8 << 56);
147 let val = unsafe { Value::from_raw(raw) };
148 eprint!("FLOAT\t{}", val.with_heap(self.heap));
149 }
150
151 fn imm_nil(&self) {
152 eprint!("NIL");
153 }
154
155 fn imm_true(&self) {
156 eprint!("TRUE");
157 }
158
159 fn imm_false(&self) {
160 eprint!("FALSE");
161 }
162
163 fn call(&self, arity: u8) {
164 eprint!("CALL_{}", arity);
165 }
166
167 fn invoke(&mut self, arity: u8) {
168 let idx = self.read_byte();
169 let val = self.chunk.get_constant(idx).expect("invalid constant segment index");
170 eprint!("INVOKE_{} {}", arity, val.with_heap(&self.heap));
171 }
172
173 fn close_upvalue(&self) {
174 eprint!("CLOSE_UPVALUE");
175 }
176
177 fn get_upvalue(&mut self) {
178 let index = self.read_byte();
179 eprint!("GET_UPVALUE\t{}", index);
180 }
181
182 fn set_upvalue(&mut self) {
183 let index = self.read_byte();
184 eprint!("SET_UPVALE\t{}", index);
185 }
186
187 fn closure(&mut self) {
188 let val = self.read_constant();
189 let count = val
190 .as_object()
191 .and_then(|o| self.heap.get(o))
192 .and_then(|o| o.as_function())
193 .expect("closure argument to be a function")
194 .upvalue_count();
195
196 print!("CLOSURE\t{} ", val.with_heap(self.heap));
197 println!();
198
199 if let Variant::Obj(cl) = val.with_heap(self.heap).item.decode() {
200 unsafe {
201 let closure = cl.get_unchecked().as_function().unwrap();
202
203 let dis = Disassembler::new(closure.chunk(), &self.heap);
204 dis.disassemble()
205 }
206 }
207
208 for _ in 0..count {
209 let _is_local = self.read_byte() > 0;
210 let _index = self.read_byte();
211 }
212 }
213
214 fn class(&mut self, idx: u8) {
215 let val = self.chunk.get_constant(idx).expect("invalid constant segment index");
216 let methods = self.read_byte();
217 eprint!("CLASS\t{}\t{}\t({} method(s))", idx, val.with_heap(&self.heap), methods);
218 }
219
220 fn get_property(&mut self) {
221 let idx = self.read_byte();
222 let val = self.chunk.get_constant(idx).expect("invalid constant segment index");
223 eprint!("GET_PROPERTY\t{}\t{}", idx, val.with_heap(&self.heap));
224 }
225
226 fn set_property(&mut self) {
227 let idx = self.read_byte();
228 let val = self.chunk.get_constant(idx).expect("invalid constant segment index");
229 eprint!("SET_PROPERTY\t{}\t{}", idx, val.with_heap(&self.heap));
230 }
231
232 fn read_byte(&mut self) -> u8 {
233 self.offset += 1;
234 self.chunk.as_ref()[self.offset - 1]
235 }
236
237 fn read_u16(&mut self) -> u16 {
238 self.offset += 2;
239 let lo = self.chunk.get(self.offset - 2) as u16;
240 let hi = self.chunk.get(self.offset - 1) as u16;
241 lo + (hi << 8)
242 }
243
244 fn read_constant(&mut self) -> Value {
245 let idx = self.read_byte();
246 *self.chunk.get_constant(idx).expect("invalid constant segment index")
247 }
248}