rune/runtime/unit/
byte_code.rs

1use core::mem::size_of;
2
3#[cfg(feature = "byte-code")]
4use musli::storage;
5#[cfg(feature = "musli")]
6use musli::{Decode, Encode};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate as rune;
11use crate::alloc::prelude::*;
12use crate::alloc::{self, Vec};
13use crate::runtime::unit::{BadInstruction, BadJump, EncodeError, UnitEncoder, UnitStorage};
14use crate::runtime::Inst;
15
16/// Unit stored as byte code, which is a more compact representation than
17/// `ArrayUnit`, but takes more time to execute since it needs to be decoded as
18/// it's being executed.
19#[derive(Debug, TryClone, Default)]
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21#[cfg_attr(feature = "musli", derive(Decode, Encode))]
22pub struct ByteCodeUnit {
23    /// The instructions contained in the source file.
24    #[cfg_attr(feature = "musli", musli(bytes))]
25    bytes: Vec<u8>,
26    /// Known jump offsets.
27    offsets: Vec<usize>,
28}
29
30/// Iterator for [`ByteCodeUnit`].
31pub struct ByteCodeUnitIter<'a> {
32    address: &'a [u8],
33    len: usize,
34}
35
36impl Iterator for ByteCodeUnitIter<'_> {
37    type Item = (usize, Inst);
38
39    #[inline]
40    fn next(&mut self) -> Option<Self::Item> {
41        if self.address.is_empty() {
42            return None;
43        }
44
45        let ip = self.len.checked_sub(self.address.len())?;
46        let inst = storage::decode(self.address).ok()?;
47        Some((ip, inst))
48    }
49}
50
51impl UnitEncoder for ByteCodeUnit {
52    #[inline]
53    fn offset(&self) -> usize {
54        self.bytes.len()
55    }
56
57    #[inline]
58    fn encode(&mut self, inst: Inst) -> Result<(), EncodeError> {
59        storage::to_writer(&mut self.bytes, &inst)?;
60        Ok(())
61    }
62
63    #[inline]
64    fn extend_offsets(&mut self, extra: usize) -> alloc::Result<usize> {
65        let base = self.offsets.len();
66        self.offsets.try_extend((0..extra).map(|_| 0))?;
67        Ok(base)
68    }
69
70    #[inline]
71    fn mark_offset(&mut self, index: usize) {
72        if let Some(o) = self.offsets.get_mut(index) {
73            *o = self.bytes.len();
74        }
75    }
76
77    #[inline]
78    fn label_jump(&self, base: usize, _: usize, jump: usize) -> usize {
79        base.wrapping_add(jump)
80    }
81}
82
83impl UnitStorage for ByteCodeUnit {
84    type Iter<'this> = ByteCodeUnitIter<'this>;
85
86    #[inline]
87    fn end(&self) -> usize {
88        self.bytes.len()
89    }
90
91    #[inline]
92    fn bytes(&self) -> usize {
93        self.bytes
94            .len()
95            .wrapping_add(self.offsets.len().wrapping_mul(size_of::<usize>()))
96    }
97
98    #[inline]
99    fn iter(&self) -> Self::Iter<'_> {
100        ByteCodeUnitIter {
101            address: &self.bytes[..],
102            len: self.bytes.len(),
103        }
104    }
105
106    fn get(&self, ip: usize) -> Result<Option<(Inst, usize)>, BadInstruction> {
107        let Some(bytes) = self.bytes.get(ip..) else {
108            return Ok(None);
109        };
110
111        let start = bytes.as_ptr();
112        let inst: Inst = storage::decode(bytes).map_err(|_| BadInstruction { ip })?;
113        let len = (bytes.as_ptr() as usize).wrapping_sub(start as usize);
114        Ok(Some((inst, len)))
115    }
116
117    #[inline]
118    fn translate(&self, jump: usize) -> Result<usize, BadJump> {
119        let Some(&offset) = self.offsets.get(jump) else {
120            return Err(BadJump { jump });
121        };
122
123        Ok(offset)
124    }
125}