kaiju_core/
vm.rs

1#![allow(clippy::unused_io_amount)]
2
3use crate::assembly::DataType;
4use crate::error::*;
5use byteorder::{BigEndian, ReadBytesExt};
6use std::collections::HashMap;
7use std::fmt;
8use std::io::{Cursor, Read, Seek, SeekFrom};
9use std::mem::size_of;
10
11fn read_string(stream: &mut dyn Read) -> SimpleResult<String> {
12    let size = stream.read_u64::<BigEndian>()? as usize;
13    let mut bytes = vec![0; size];
14    stream.read(&mut bytes)?;
15    match String::from_utf8(bytes) {
16        Ok(s) => Ok(s),
17        Err(err) => Err(SimpleError::new(format!("{}", err))),
18    }
19}
20
21fn read_type(stream: &mut dyn Read) -> SimpleResult<Type> {
22    let mode = stream.read_u8()?;
23    match mode {
24        0 => {
25            let index = stream.read_u64::<BigEndian>()? as usize;
26            Ok(Type::Identifier(index))
27        }
28        1 => Ok(Type::Pointer(Box::new(read_type(stream)?))),
29        2 => {
30            let count = stream.read_u64::<BigEndian>()? as usize;
31            let mut types = vec![];
32            for _ in 0..count {
33                types.push(read_type(stream)?);
34            }
35            Ok(Type::Tuple(types))
36        }
37        _ => unreachable!(),
38    }
39}
40
41fn read_variable(stream: &mut dyn Read) -> SimpleResult<Variable> {
42    let index = stream.read_u64::<BigEndian>()? as usize;
43    let typeid = read_type(stream)?;
44    let size = stream.read_u64::<BigEndian>()? as usize;
45    let offset = {
46        if stream.read_u8()? > 0 {
47            Some(stream.read_u64::<BigEndian>()? as usize)
48        } else {
49            None
50        }
51    };
52    Ok(Variable {
53        index,
54        typeid,
55        size,
56        offset,
57    })
58}
59
60#[derive(Debug, Clone)]
61pub enum Data {
62    None,
63    I8(i8),
64    U8(u8),
65    I16(i16),
66    U16(u16),
67    I32(i32),
68    U32(u32),
69    I64(i64),
70    U64(u64),
71    F32(f32),
72    F64(f64),
73    Isize(isize),
74    Usize(usize),
75    String(String),
76}
77
78#[derive(Debug, Clone)]
79pub enum Type {
80    Identifier(usize),
81    Pointer(Box<Type>),
82    Tuple(Vec<Type>),
83}
84
85#[derive(Debug, Clone)]
86pub struct Struct {
87    index: usize,
88    fields: Vec<StructField>,
89    size: usize,
90    export: bool,
91}
92
93impl Struct {
94    #[inline]
95    pub fn index(&self) -> usize {
96        self.index
97    }
98
99    #[inline]
100    pub fn fields(&self) -> &[StructField] {
101        &self.fields
102    }
103
104    #[inline]
105    pub fn size(&self) -> usize {
106        self.size
107    }
108
109    #[inline]
110    pub fn export(&self) -> bool {
111        self.export
112    }
113}
114
115#[derive(Debug, Clone)]
116pub struct StructField {
117    typeid: Type,
118    offset: usize,
119    size: usize,
120}
121
122impl StructField {
123    #[inline]
124    pub fn typeid(&self) -> &Type {
125        &self.typeid
126    }
127
128    #[inline]
129    pub fn offset(&self) -> usize {
130        self.offset
131    }
132
133    #[inline]
134    pub fn size(&self) -> usize {
135        self.size
136    }
137}
138
139#[derive(Debug, Clone)]
140pub struct Function {
141    index: usize,
142    params: Vec<Variable>,
143    typeid: Option<Type>,
144    locals: Vec<Variable>,
145    external: Option<(String, String)>,
146    export: bool,
147}
148
149impl Function {
150    #[inline]
151    pub fn index(&self) -> usize {
152        self.index
153    }
154
155    #[inline]
156    pub fn params(&self) -> &[Variable] {
157        &self.params
158    }
159
160    #[inline]
161    pub fn typeid(&self) -> &Option<Type> {
162        &self.typeid
163    }
164
165    #[inline]
166    pub fn locals(&self) -> &[Variable] {
167        &self.locals
168    }
169
170    #[inline]
171    pub fn external(&self) -> &Option<(String, String)> {
172        &self.external
173    }
174
175    #[inline]
176    pub fn export(&self) -> bool {
177        self.export
178    }
179}
180
181#[derive(Clone)]
182pub struct FunctionBody {
183    labels: HashMap<String, usize>,
184    code: Vec<u8>,
185}
186
187impl fmt::Debug for FunctionBody {
188    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189        f.debug_struct("FunctionBody")
190            .field("labels", &self.labels)
191            .field("code", &format!("[...; {}]", self.code.len()))
192            .finish()
193    }
194}
195
196impl FunctionBody {
197    #[inline]
198    pub fn labels(&self) -> &HashMap<String, usize> {
199        &self.labels
200    }
201
202    #[inline]
203    pub fn code(&self) -> &[u8] {
204        &self.code
205    }
206}
207
208#[derive(Debug, Clone)]
209pub struct Variable {
210    index: usize,
211    typeid: Type,
212    size: usize,
213    offset: Option<usize>,
214}
215
216impl Variable {
217    #[inline]
218    pub fn index(&self) -> usize {
219        self.index
220    }
221
222    #[inline]
223    pub fn typeid(&self) -> &Type {
224        &self.typeid
225    }
226
227    #[inline]
228    pub fn size(&self) -> usize {
229        self.size
230    }
231
232    #[inline]
233    pub fn offset(&self) -> &Option<usize> {
234        &self.offset
235    }
236}
237
238#[derive(Clone)]
239pub struct VmAssembly {
240    export_structs: HashMap<String, usize>,
241    export_functions: HashMap<String, usize>,
242    structs: Vec<Struct>,
243    functions: Vec<Function>,
244    data: Vec<Data>,
245    globals_size: usize,
246    ops: Vec<String>,
247    bodies: Vec<FunctionBody>,
248}
249
250impl fmt::Debug for VmAssembly {
251    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252        f.debug_struct("VmAssembly")
253            .field("export_structs", &self.export_structs)
254            .field("export_functions", &self.export_functions)
255            .field("structs", &self.structs)
256            .field("functions", &self.functions)
257            .field("data", &format!("[...; {}]", self.data.len()))
258            .field("globals_size", &self.globals_size)
259            .field("ops", &self.ops)
260            .field("bodies", &self.bodies)
261            .finish()
262    }
263}
264
265impl VmAssembly {
266    #[allow(clippy::new_ret_no_self)]
267    pub fn new(bytes: Vec<u8>) -> SimpleResult<Self> {
268        let mut stream = Cursor::new(bytes);
269        let mut magic = [0; 4];
270        stream.read(&mut magic)?;
271        match magic {
272            [0x4b, 0x4a, 0x50, 1] => Self::new_v1(stream),
273            _ => Err(SimpleError::new(format!(
274                "Trying to run assembly with unsupported version: {}",
275                magic[3]
276            ))),
277        }
278    }
279
280    fn new_v1(mut stream: Cursor<Vec<u8>>) -> SimpleResult<Self> {
281        let export_structs = {
282            let _size = stream.read_u64::<BigEndian>()?;
283            let count = stream.read_u64::<BigEndian>()?;
284            let mut result = HashMap::new();
285            for _ in 0..count {
286                let index = stream.read_u64::<BigEndian>()? as usize;
287                let id = read_string(&mut stream)?;
288                result.insert(id, index);
289            }
290            result
291        };
292        let export_functions = {
293            let _size = stream.read_u64::<BigEndian>()?;
294            let count = stream.read_u64::<BigEndian>()?;
295            let mut result = HashMap::new();
296            for _ in 0..count {
297                let index = stream.read_u64::<BigEndian>()? as usize;
298                let id = read_string(&mut stream)?;
299                result.insert(id, index);
300            }
301            result
302        };
303        let structs = {
304            let size = stream.read_u64::<BigEndian>()? as i64;
305            let count = stream.read_u64::<BigEndian>()? as usize;
306            stream.seek(SeekFrom::Current(size))?;
307            let mut result = vec![];
308            for _ in 0..count {
309                let index = stream.read_u64::<BigEndian>()? as usize;
310                let fields = {
311                    let mut result = vec![];
312                    let count = stream.read_u64::<BigEndian>()? as usize;
313                    for _ in 0..count {
314                        let typeid = read_type(&mut stream)?;
315                        let offset = stream.read_u64::<BigEndian>()? as usize;
316                        let size = stream.read_u64::<BigEndian>()? as usize;
317                        result.push(StructField {
318                            typeid,
319                            offset,
320                            size,
321                        });
322                    }
323                    result
324                };
325                let size = stream.read_u64::<BigEndian>()? as usize;
326                let export = stream.read_u8()? > 0;
327                result.push(Struct {
328                    index,
329                    fields,
330                    size,
331                    export,
332                });
333            }
334            result
335        };
336        let functions = {
337            let size = stream.read_u64::<BigEndian>()? as i64;
338            let count = stream.read_u64::<BigEndian>()? as usize;
339            stream.seek(SeekFrom::Current(size))?;
340            let mut result = vec![];
341            for _ in 0..count {
342                let index = stream.read_u64::<BigEndian>()? as usize;
343                let params = {
344                    let mut result = vec![];
345                    let count = stream.read_u64::<BigEndian>()? as usize;
346                    for _ in 0..count {
347                        result.push(read_variable(&mut stream)?);
348                    }
349                    result
350                };
351                let typeid = if stream.read_u8()? > 0 {
352                    Some(read_type(&mut stream)?)
353                } else {
354                    None
355                };
356                let locals = {
357                    let mut result = vec![];
358                    let count = stream.read_u64::<BigEndian>()? as usize;
359                    for _ in 0..count {
360                        result.push(read_variable(&mut stream)?);
361                    }
362                    result
363                };
364                let external = if stream.read_u8()? > 0 {
365                    let m = read_string(&mut stream)?;
366                    let f = read_string(&mut stream)?;
367                    Some((m, f))
368                } else {
369                    None
370                };
371                let export = stream.read_u8()? > 0;
372                result.push(Function {
373                    index,
374                    params,
375                    typeid,
376                    locals,
377                    external,
378                    export,
379                });
380            }
381            result
382        };
383        let data = {
384            let _size = stream.read_u64::<BigEndian>()? as usize;
385            let count = stream.read_u64::<BigEndian>()? as usize;
386            let mut result = vec![];
387            for _ in 0..count {
388                let t = DataType::from(stream.read_u8()?);
389                match t {
390                    DataType::Unknown => (),
391                    DataType::I8 => result.push(Data::I8(stream.read_i8()?)),
392                    DataType::U8 => result.push(Data::U8(stream.read_u8()?)),
393                    DataType::I16 => result.push(Data::I16(stream.read_i16::<BigEndian>()?)),
394                    DataType::U16 => result.push(Data::U16(stream.read_u16::<BigEndian>()?)),
395                    DataType::I32 => result.push(Data::I32(stream.read_i32::<BigEndian>()?)),
396                    DataType::U32 => result.push(Data::U32(stream.read_u32::<BigEndian>()?)),
397                    DataType::I64 => result.push(Data::I64(stream.read_i64::<BigEndian>()?)),
398                    DataType::U64 => result.push(Data::U64(stream.read_u64::<BigEndian>()?)),
399                    DataType::F32 => result.push(Data::F32(stream.read_f32::<BigEndian>()?)),
400                    DataType::F64 => result.push(Data::F64(stream.read_f64::<BigEndian>()?)),
401                    DataType::Isize => result.push(Data::Isize(
402                        stream.read_int::<BigEndian>(size_of::<isize>())? as isize,
403                    )),
404                    DataType::Usize => result.push(Data::Usize(
405                        stream.read_uint::<BigEndian>(size_of::<usize>())? as usize,
406                    )),
407                    DataType::StringU8 => result.push(Data::String(read_string(&mut stream)?)),
408                }
409            }
410            result
411        };
412        let globals_size = stream.read_u64::<BigEndian>()? as usize;
413        let ops = {
414            let _size = stream.read_u64::<BigEndian>()? as usize;
415            let count = stream.read_u64::<BigEndian>()? as usize;
416            let mut result = vec![];
417            for _ in 0..count {
418                result.push(read_string(&mut stream)?);
419            }
420            result
421        };
422        let bodies = {
423            let size = stream.read_u64::<BigEndian>()? as i64;
424            let count = stream.read_u64::<BigEndian>()? as usize;
425            stream.seek(SeekFrom::Current(size))?;
426            let mut result = vec![];
427            for _ in 0..count {
428                let _size = stream.read_u64::<BigEndian>()? as usize;
429                let labels = {
430                    let mut result = HashMap::new();
431                    let _size = stream.read_u64::<BigEndian>()? as usize;
432                    let count = stream.read_u64::<BigEndian>()? as usize;
433                    for _ in 0..count {
434                        let id = read_string(&mut stream)?;
435                        let address = stream.read_u64::<BigEndian>()? as usize;
436                        result.insert(id, address);
437                    }
438                    result
439                };
440                let code = {
441                    let size = stream.read_u64::<BigEndian>()? as usize;
442                    let _count = stream.read_u64::<BigEndian>()? as usize;
443                    let mut result = vec![0; size];
444                    stream.read(&mut result)?;
445                    result
446                };
447                result.push(FunctionBody { labels, code });
448            }
449            result
450        };
451        Ok(Self {
452            export_structs,
453            export_functions,
454            structs,
455            functions,
456            data,
457            globals_size,
458            ops,
459            bodies,
460        })
461    }
462
463    #[inline]
464    pub fn export_structs(&self) -> &HashMap<String, usize> {
465        &self.export_structs
466    }
467
468    #[inline]
469    pub fn export_functions(&self) -> &HashMap<String, usize> {
470        &self.export_functions
471    }
472
473    #[inline]
474    pub fn structs(&self) -> &[Struct] {
475        &self.structs
476    }
477
478    #[inline]
479    pub fn functions(&self) -> &[Function] {
480        &self.functions
481    }
482
483    #[inline]
484    pub fn data(&self) -> &[Data] {
485        &self.data
486    }
487
488    #[inline]
489    pub fn globals_size(&self) -> usize {
490        self.globals_size
491    }
492
493    #[inline]
494    pub fn ops_map(&self) -> &[String] {
495        &self.ops
496    }
497
498    #[inline]
499    pub fn functions_code(&self) -> &[FunctionBody] {
500        &self.bodies
501    }
502
503    #[inline]
504    pub fn struct_by_id(&self, id: &str) -> Option<&Struct> {
505        if let Some(i) = self.export_structs.get(id) {
506            Some(&self.structs[*i])
507        } else {
508            None
509        }
510    }
511
512    #[inline]
513    pub fn function_by_id(&self, id: &str) -> Option<&Function> {
514        if let Some(i) = self.export_functions.get(id) {
515            Some(&self.functions[*i])
516        } else {
517            None
518        }
519    }
520
521    #[inline]
522    pub fn function_body_by_id(&self, id: &str) -> Option<&FunctionBody> {
523        if let Some(i) = self.export_functions.get(id) {
524            Some(&self.bodies[*i])
525        } else {
526            None
527        }
528    }
529
530    #[inline]
531    pub fn struct_by_index(&self, index: usize) -> Option<&Struct> {
532        if let Some(s) = self.structs.get(index) {
533            Some(s)
534        } else {
535            None
536        }
537    }
538
539    #[inline]
540    pub fn function_by_index(&self, index: usize) -> Option<&Function> {
541        if let Some(f) = self.functions.get(index) {
542            Some(f)
543        } else {
544            None
545        }
546    }
547
548    #[inline]
549    pub fn function_body_by_index(&self, index: usize) -> Option<&FunctionBody> {
550        if let Some(f) = self.bodies.get(index) {
551            Some(f)
552        } else {
553            None
554        }
555    }
556
557    #[inline]
558    pub fn type_size(&self, typeid: &Type) -> usize {
559        match typeid {
560            Type::Identifier(i) => self.structs[*i].size(),
561            Type::Pointer(_) => size_of::<usize>(),
562            Type::Tuple(t) => t.iter().map(|t| self.type_size(t)).sum(),
563        }
564    }
565}