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}