1use std::cmp::Ordering;
2
3use crate::opcodes::*;
4use crate::{Interned, VMError, VMResult, Value};
5
6#[macro_use]
7pub mod disassemble;
8
9#[derive(Clone, Debug)]
10pub struct Chunk {
11 pub code: Vec<u8>,
12 pub file_name: &'static str,
13 start_line: u32,
14 last_line: u32,
15 line_numbers: Vec<u8>,
16 pub constants: Vec<Value>,
17 pub jump_table: Vec<u32>,
18 pub captures: Option<Vec<u32>>,
19 pub input_regs: usize,
21 pub extra_regs: usize,
23 pub args: u16,
24 pub opt_args: u16,
25 pub rest: bool,
26
27 pub dbg_args: Option<Vec<Interned>>,
28}
29
30impl Chunk {
31 pub fn new(file_name: &'static str, start_line: u32) -> Self {
32 Chunk {
33 code: Vec::new(),
34 file_name,
35 start_line,
36 last_line: start_line,
37 line_numbers: Vec::new(),
38 constants: Vec::new(),
39 jump_table: Vec::new(),
40 captures: None,
41 input_regs: 0,
42 extra_regs: 0,
43 args: 0,
44 opt_args: 0,
45 rest: false,
46 dbg_args: None,
47 }
48 }
49
50 fn encode_operand(&mut self, op: u16, wide: bool) {
51 if wide {
52 self.code.push(((op & 0xFF00) >> 8) as u8);
53 }
54 self.code.push((op & 0x00FF) as u8);
55 }
56
57 fn encode_line_number(&mut self, offsets: u8, line_number: Option<u32>) -> VMResult<()> {
58 let line_number = if let Some(ln) = line_number {
59 ln
60 } else {
61 self.last_line
62 };
63 match line_number.cmp(&self.last_line) {
64 Ordering::Equal => {
65 if let Some(line) = self.line_numbers.pop() {
66 if (line & 0x40) == 0 {
67 let current_offsets: u16 = (line & 0x3f) as u16;
68 if current_offsets + offsets as u16 > 0x3f {
69 self.line_numbers.push(0x3f);
70 self.line_numbers
71 .push((offsets - (0x3f - current_offsets) as u8) | (line & 0x80));
72 } else {
73 self.line_numbers
74 .push((current_offsets as u8 + offsets) | (line & 0x80));
75 }
76 } else {
77 self.line_numbers.push(line);
78 self.line_numbers.push(offsets);
79 }
80 } else {
81 self.line_numbers.push(offsets);
82 }
83 Ok(())
84 }
85 Ordering::Less => Err(VMError::new_chunk("Line numbers can not go backwards!")),
86 Ordering::Greater => {
87 let mut delta = line_number - self.last_line;
88 while delta > 1 {
89 if delta > 0x3f {
90 self.line_numbers.push(0x7f); delta -= 0x3f;
92 } else {
93 self.line_numbers.push((delta - 1) as u8 | 0x40);
94 delta = 0;
95 }
96 }
97 self.last_line = line_number;
98 self.line_numbers.push(offsets | 0x80);
99 Ok(())
100 }
101 }
102 }
103
104 pub fn offset_to_line(&self, offset: usize) -> Option<u32> {
105 let mut line = self.start_line;
106 let mut current: usize = 0;
107 for o in &self.line_numbers {
108 if (o & 0x40) > 0 {
109 line += (o & 0x3f) as u32;
110 } else {
111 current += (o & 0x3f) as usize;
112 }
113 if (o & 0x80) > 0 {
114 line += 1;
115 }
116 if offset < current {
117 return Some(line);
118 }
119 }
120 None
121 }
122
123 pub fn line_to_offset(&self, line: u32) -> Option<usize> {
124 if line > self.last_line {
125 return None;
126 }
127 let mut current_line = self.start_line;
128 let mut offset: usize = 0;
129 for o in &self.line_numbers {
130 if (o & 0x80) > 0 {
131 current_line += 1;
132 }
133 if current_line == line {
134 return Some(offset);
135 }
136 if (o & 0x40) > 0 {
137 current_line += (o & 0x3f) as u32;
138 } else {
139 offset += (o & 0x3f) as usize;
140 }
141 }
142 None
143 }
144
145 pub fn add_constant(&mut self, value: Value) -> usize {
146 for (i, c) in self.constants.iter().enumerate() {
147 if *c == value {
148 return i;
149 }
150 }
151 self.constants.push(value);
152 self.constants.len() - 1
153 }
154
155 pub fn add_jump(&mut self, offset: u32) -> usize {
156 self.jump_table.push(offset);
162 self.jump_table.len() - 1
163 }
164
165 pub fn update_jump(&mut self, jmp: usize, offset: u32) {
166 self.jump_table[jmp] = offset;
167 }
168
169 pub fn encode0(&mut self, op_code: OpCode, line_number: Option<u32>) -> VMResult<()> {
170 self.encode_line_number(1, line_number)?;
171 self.code.push(op_code);
172 Ok(())
173 }
174
175 pub fn encode1(&mut self, opcode: OpCode, op1: u16, line_number: Option<u32>) -> VMResult<()> {
176 let mut bytes: u8 = 2;
177 let mut wide = false;
178 if op1 > u8::MAX as u16 {
179 wide = true;
180 bytes = 3;
181 self.encode_line_number(1, line_number)?;
182 self.code.push(WIDE);
183 }
184
185 self.encode_line_number(bytes, line_number)?;
186 self.code.push(opcode);
187 self.encode_operand(op1, wide);
188
189 Ok(())
190 }
191
192 pub fn encode2(
193 &mut self,
194 opcode: OpCode,
195 op1: u16,
196 op2: u16,
197 line_number: Option<u32>,
198 ) -> VMResult<()> {
199 let mut bytes: u8 = 3;
200 let mut wide = false;
201 if op1 > u8::MAX as u16 || op2 > u8::MAX as u16 {
202 wide = true;
203 bytes = 5;
204 self.encode_line_number(1, line_number)?;
205 self.code.push(WIDE);
206 }
207
208 self.encode_line_number(bytes, line_number)?;
209 self.code.push(opcode);
210 self.encode_operand(op1, wide);
211 self.encode_operand(op2, wide);
212
213 Ok(())
214 }
215
216 pub fn encode_def(
217 &mut self,
218 reg: u16,
219 global: u32,
220 line_number: Option<u32>,
221 is_defv: bool,
222 ) -> VMResult<()> {
223 let mut bytes: u8 = 4;
224 let mut wide = false;
225 if reg > u8::MAX as u16 || global > u16::MAX as u32 {
226 wide = true;
227 bytes = 7;
228 self.encode_line_number(1, line_number)?;
229 self.code.push(WIDE);
230 }
231
232 self.encode_line_number(bytes, line_number)?;
233 if is_defv {
234 self.code.push(DEFV);
235 } else {
236 self.code.push(DEF);
237 }
238 self.encode_operand(reg, wide);
239 if wide {
240 self.code.push(((global & 0xFF00_0000) >> 24) as u8);
241 self.code.push(((global & 0x00FF_0000) >> 16) as u8);
242 }
243 self.code.push(((global & 0x0000_FF00) >> 8) as u8);
244 self.code.push((global & 0x0000_00FF) as u8);
245
246 Ok(())
247 }
248
249 pub fn encode_refi(&mut self, reg: u16, global: u32, line_number: Option<u32>) -> VMResult<()> {
250 let mut bytes: u8 = 4;
251 let mut wide = false;
252 if reg > u8::MAX as u16 || global > u16::MAX as u32 {
253 wide = true;
254 bytes = 7;
255 self.encode_line_number(1, line_number)?;
256 self.code.push(WIDE);
257 }
258
259 self.encode_line_number(bytes, line_number)?;
260 self.code.push(REFI);
261 self.encode_operand(reg, wide);
262 if wide {
263 self.code.push(((global & 0xFF00_0000) >> 24) as u8);
264 self.code.push(((global & 0x00FF_0000) >> 16) as u8);
265 }
266 self.code.push(((global & 0x0000_FF00) >> 8) as u8);
267 self.code.push((global & 0x0000_00FF) as u8);
268
269 Ok(())
270 }
271
272 pub fn encode_callg(
273 &mut self,
274 global: u32,
275 num_args: u16,
276 first_reg: u16,
277 line_number: Option<u32>,
278 ) -> VMResult<()> {
279 let mut bytes: u8 = 5;
280 let mut wide = false;
281 if num_args > u8::MAX as u16 || first_reg > u8::MAX as u16 || global > u16::MAX as u32 {
282 wide = true;
283 bytes = 9;
284 self.encode_line_number(1, line_number)?;
285 self.code.push(WIDE);
286 }
287
288 self.encode_line_number(bytes, line_number)?;
289 self.code.push(CALLG);
290 if wide {
291 self.code.push(((global & 0xFF00_0000) >> 24) as u8);
292 self.code.push(((global & 0x00FF_0000) >> 16) as u8);
293 }
294 self.code.push(((global & 0x0000_FF00) >> 8) as u8);
295 self.code.push((global & 0x0000_00FF) as u8);
296 self.encode_operand(num_args, wide);
297 self.encode_operand(first_reg, wide);
298
299 Ok(())
300 }
301
302 pub fn encode_tcallg(
303 &mut self,
304 global: u32,
305 num_args: u16,
306 line_number: Option<u32>,
307 ) -> VMResult<()> {
308 let mut bytes: u8 = 4;
309 let mut wide = false;
310 if num_args > u8::MAX as u16 || global > u16::MAX as u32 {
311 wide = true;
312 bytes = 7;
313 self.encode_line_number(1, line_number)?;
314 self.code.push(WIDE);
315 }
316
317 self.encode_line_number(bytes, line_number)?;
318 self.code.push(TCALLG);
319 if wide {
320 self.code.push(((global & 0xFF00_0000) >> 24) as u8);
321 self.code.push(((global & 0x00FF_0000) >> 16) as u8);
322 }
323 self.code.push(((global & 0x0000_FF00) >> 8) as u8);
324 self.code.push((global & 0x0000_00FF) as u8);
325 self.encode_operand(num_args, wide);
326
327 Ok(())
328 }
329
330 pub fn encode3(
331 &mut self,
332 opcode: OpCode,
333 op1: u16,
334 op2: u16,
335 op3: u16,
336 line_number: Option<u32>,
337 ) -> VMResult<()> {
338 let mut bytes: u8 = 4;
339 let mut wide = false;
340 if op1 > u8::MAX as u16 || op2 > u8::MAX as u16 || op3 > u8::MAX as u16 {
341 wide = true;
342 bytes = 7;
343 self.encode_line_number(1, line_number)?;
344 self.code.push(WIDE);
345 }
346
347 self.encode_line_number(bytes, line_number)?;
348 self.code.push(opcode);
349 self.encode_operand(op1, wide);
350 self.encode_operand(op2, wide);
351 self.encode_operand(op3, wide);
352
353 Ok(())
354 }
355}
356
357#[cfg(test)]
358mod tests {
359 use super::*;
360
361 #[test]
362 fn test_encode0() {
363 let mut chunk = Chunk::new("no_file", 0);
364 chunk.encode0(RET, Some(1)).unwrap();
365 chunk.encode0(CAR, None).unwrap();
366 chunk.encode0(RET, None).unwrap();
367 let mut code = chunk.code.iter();
368
369 assert!(*code.next().unwrap() == RET);
370 assert!(*code.next().unwrap() == CAR);
371 assert!(*code.next().unwrap() == RET);
372 assert!(code.next().is_none());
373 }
374
375 #[test]
376 fn test_encode1() {
377 let mut chunk = Chunk::new("no_file", 0);
378 chunk.encode1(CAR, 0, Some(1)).unwrap();
379 chunk.encode1(CAR, 128, None).unwrap();
380 chunk.encode1(CAR, 255, None).unwrap();
381 chunk.encode1(CAR, 256, None).unwrap();
382 chunk.encode1(CAR, 256, None).unwrap();
383 chunk.encode1(CAR, u16::MAX, None).unwrap();
384 let mut code = chunk.code.iter();
385
386 assert!(*code.next().unwrap() == CAR);
387 assert!(*code.next().unwrap() == 0);
388
389 assert!(*code.next().unwrap() == CAR);
390 assert!(*code.next().unwrap() == 128);
391
392 assert!(*code.next().unwrap() == CAR);
393 assert!(*code.next().unwrap() == 255);
394
395 assert!(*code.next().unwrap() == WIDE);
396 assert!(*code.next().unwrap() == CAR);
397 assert!(decode_chunk_u16!(code).unwrap() == 256);
398
399 assert!(*code.next().unwrap() == WIDE);
400 assert!(*code.next().unwrap() == CAR);
401 assert!(decode_chunk_u16!(code).unwrap() == 256);
402
403 assert!(*code.next().unwrap() == WIDE);
404 assert!(*code.next().unwrap() == CAR);
405 assert!(decode_chunk_u16!(code).unwrap() == u16::MAX);
406 }
407
408 #[test]
409 fn test_encode2() {
410 let mut chunk = Chunk::new("no_file", 0);
411 chunk.encode2(MOV, 0, 0, Some(1)).unwrap();
412 chunk.encode2(MOV, 128, 128, None).unwrap();
413 chunk.encode2(MOV, 255, 255, None).unwrap();
414 chunk.encode2(MOV, 256, 256, None).unwrap();
415 chunk.encode2(MOV, 2, 256, None).unwrap();
416 chunk.encode2(MOV, 256, 1, None).unwrap();
417 chunk.encode2(MOV, 257, 257, None).unwrap();
418 chunk.encode2(MOV, u16::MAX, u16::MAX, None).unwrap();
419 let mut code = chunk.code.iter();
420
421 assert!(*code.next().unwrap() == MOV);
422 assert!(*code.next().unwrap() == 0);
423 assert!(*code.next().unwrap() == 0);
424
425 assert!(*code.next().unwrap() == MOV);
426 assert!(*code.next().unwrap() == 128);
427 assert!(*code.next().unwrap() == 128);
428
429 assert!(*code.next().unwrap() == MOV);
430 assert!(*code.next().unwrap() == 255);
431 assert!(*code.next().unwrap() == 255);
432
433 assert!(*code.next().unwrap() == WIDE);
434 assert!(*code.next().unwrap() == MOV);
435 assert!(decode_chunk_u16!(code).unwrap() == 256);
436 assert!(decode_chunk_u16!(code).unwrap() == 256);
437
438 assert!(*code.next().unwrap() == WIDE);
439 assert!(*code.next().unwrap() == MOV);
440 assert!(decode_chunk_u16!(code).unwrap() == 2);
441 assert!(decode_chunk_u16!(code).unwrap() == 256);
442
443 assert!(*code.next().unwrap() == WIDE);
444 assert!(*code.next().unwrap() == MOV);
445 assert!(decode_chunk_u16!(code).unwrap() == 256);
446 assert!(decode_chunk_u16!(code).unwrap() == 1);
447
448 assert!(*code.next().unwrap() == WIDE);
449 assert!(*code.next().unwrap() == MOV);
450 assert!(decode_chunk_u16!(code).unwrap() == 257);
451 assert!(decode_chunk_u16!(code).unwrap() == 257);
452
453 assert!(*code.next().unwrap() == WIDE);
454 assert!(*code.next().unwrap() == MOV);
455 assert!(decode_chunk_u16!(code).unwrap() == u16::MAX);
456 assert!(decode_chunk_u16!(code).unwrap() == u16::MAX);
457 }
458
459 #[test]
460 fn test_encode3() {
461 let mut chunk = Chunk::new("no_file", 0);
462 chunk.encode3(CONS, 0, 0, 0, Some(1)).unwrap();
463 chunk.encode3(CONS, 128, 128, 128, None).unwrap();
464 chunk.encode3(CONS, 255, 255, 255, None).unwrap();
465 chunk.encode3(CONS, 256, 256, 256, None).unwrap();
466 chunk.encode3(CONS, 2, 256, 256, None).unwrap();
467 chunk.encode3(CONS, 256, 1, 1, None).unwrap();
468 chunk.encode3(CONS, 257, 257, 257, None).unwrap();
469 chunk
470 .encode3(CONS, u16::MAX, u16::MAX, u16::MAX, Some(1))
471 .unwrap();
472 let mut code = chunk.code.iter();
473
474 assert!(*code.next().unwrap() == CONS);
475 assert!(*code.next().unwrap() == 0);
476 assert!(*code.next().unwrap() == 0);
477 assert!(*code.next().unwrap() == 0);
478
479 assert!(*code.next().unwrap() == CONS);
480 assert!(*code.next().unwrap() == 128);
481 assert!(*code.next().unwrap() == 128);
482 assert!(*code.next().unwrap() == 128);
483
484 assert!(*code.next().unwrap() == CONS);
485 assert!(*code.next().unwrap() == 255);
486 assert!(*code.next().unwrap() == 255);
487 assert!(*code.next().unwrap() == 255);
488
489 assert!(*code.next().unwrap() == WIDE);
490 assert!(*code.next().unwrap() == CONS);
491 assert!(decode_chunk_u16!(code).unwrap() == 256);
492 assert!(decode_chunk_u16!(code).unwrap() == 256);
493 assert!(decode_chunk_u16!(code).unwrap() == 256);
494
495 assert!(*code.next().unwrap() == WIDE);
496 assert!(*code.next().unwrap() == CONS);
497 assert!(decode_chunk_u16!(code).unwrap() == 2);
498 assert!(decode_chunk_u16!(code).unwrap() == 256);
499 assert!(decode_chunk_u16!(code).unwrap() == 256);
500
501 assert!(*code.next().unwrap() == WIDE);
502 assert!(*code.next().unwrap() == CONS);
503 assert!(decode_chunk_u16!(code).unwrap() == 256);
504 assert!(decode_chunk_u16!(code).unwrap() == 1);
505 assert!(decode_chunk_u16!(code).unwrap() == 1);
506
507 assert!(*code.next().unwrap() == WIDE);
508 assert!(*code.next().unwrap() == CONS);
509 assert!(decode_chunk_u16!(code).unwrap() == 257);
510 assert!(decode_chunk_u16!(code).unwrap() == 257);
511 assert!(decode_chunk_u16!(code).unwrap() == 257);
512
513 assert!(*code.next().unwrap() == WIDE);
514 assert!(*code.next().unwrap() == CONS);
515 assert!(decode_chunk_u16!(code).unwrap() == u16::MAX);
516 assert!(decode_chunk_u16!(code).unwrap() == u16::MAX);
517 assert!(decode_chunk_u16!(code).unwrap() == u16::MAX);
518 }
519
520 #[test]
521 fn test_line_numbers() {
522 let mut chunk = Chunk::new("no_file", 1);
523 chunk.encode2(MOV, 1, 2, Some(1)).unwrap();
524 chunk.encode2(MOV, 1, 2, Some(2)).unwrap();
525 chunk.encode2(MOV, 1, 2, Some(3)).unwrap();
526 chunk.encode2(MOV, 1, 2, Some(4)).unwrap();
527 chunk.encode2(MOV, 1, 2, Some(4)).unwrap();
528 chunk.encode2(MOV, 1, 2, Some(30)).unwrap();
529 chunk.encode2(MOV, 1, 2, Some(200)).unwrap();
530 assert!(chunk.offset_to_line(0).unwrap() == 1);
531 assert!(chunk.offset_to_line(1).unwrap() == 1);
532 assert!(chunk.offset_to_line(2).unwrap() == 1);
533
534 assert_eq!(chunk.offset_to_line(3).unwrap(), 2);
535 assert_eq!(chunk.offset_to_line(4).unwrap(), 2);
536 assert_eq!(chunk.offset_to_line(5).unwrap(), 2);
537
538 assert!(chunk.offset_to_line(6).unwrap() == 3);
539 assert!(chunk.offset_to_line(7).unwrap() == 3);
540 assert!(chunk.offset_to_line(8).unwrap() == 3);
541
542 assert!(chunk.offset_to_line(9).unwrap() == 4);
543 assert!(chunk.offset_to_line(10).unwrap() == 4);
544 assert!(chunk.offset_to_line(11).unwrap() == 4);
545
546 assert!(chunk.offset_to_line(12).unwrap() == 4);
547 assert!(chunk.offset_to_line(13).unwrap() == 4);
548 assert!(chunk.offset_to_line(14).unwrap() == 4);
549
550 assert!(chunk.offset_to_line(15).unwrap() == 30);
551 assert!(chunk.offset_to_line(16).unwrap() == 30);
552 assert!(chunk.offset_to_line(17).unwrap() == 30);
553
554 assert_eq!(chunk.offset_to_line(18).unwrap(), 200);
555 assert_eq!(chunk.offset_to_line(19).unwrap(), 200);
556 assert_eq!(chunk.offset_to_line(20).unwrap(), 200);
557
558 assert_eq!(chunk.line_to_offset(1).unwrap(), 0);
559 assert_eq!(chunk.line_to_offset(2).unwrap(), 3);
560 assert_eq!(chunk.line_to_offset(3).unwrap(), 6);
561 assert_eq!(chunk.line_to_offset(4).unwrap(), 9);
562 assert_eq!(chunk.line_to_offset(30).unwrap(), 15);
563 assert_eq!(chunk.line_to_offset(200).unwrap(), 18);
564 assert!(chunk.line_to_offset(15).is_none());
565 assert!(chunk.line_to_offset(0).is_none());
566 assert!(chunk.line_to_offset(201).is_none());
567 assert!(chunk.line_to_offset(101).is_none());
568 assert!(chunk.encode0(RET, Some(1)).is_err());
569 }
570}