1#![deny(warnings)]
2
3pub mod file;
4pub mod varint;
5pub mod verify;
6
7#[derive(Debug)]
8pub enum EncError {
9 Io(io::Error),
10}
11
12impl From<io::Error> for EncError {
13 fn from(value: io::Error) -> Self {
14 Self::Io(value)
15 }
16}
17
18pub type EncResult<T> = result::Result<T, EncError>;
19
20#[derive(Debug)]
21pub enum DecError {
22 InvalidOpcode(usize),
23 Truncated(usize),
24 IntegerOverflow(usize),
25 Io(io::Error),
26}
27
28impl From<io::Error> for DecError {
29 fn from(value: io::Error) -> Self {
30 Self::Io(value)
31 }
32}
33
34type DecResult<T> = result::Result<T, DecError>;
35
36#[derive(Debug)]
37pub enum Error {
38 FileSizeLimit,
39 InvalidHeader,
40 TrailingJunk(usize),
41 BinTabLimit,
42 DebugBinTabLimit,
43 InvalidUtf8InDebugBinTab,
44 SymTabLimit,
45 ConstTabLimit,
46 PackTabLimit,
47 UnpackTabLimit,
48 PackLimit(usize),
49 StackSlotLimit(usize),
50 CodeLimit(usize),
51 CertLimit(usize),
52 EmptyCode(usize),
53 FuncTabLimit,
54 FuncTabEmpty,
55 FuncDebugTabWrongSize,
56 SourceMapEmpty(usize),
57 SourceMapLimit(usize),
58 SourceMapOffsetBounds(usize, usize),
59 SourceMapLineBounds(usize, usize),
60 SourceMapLineDeltaZero(usize, usize),
61 InvalidStrInSymTab(usize),
62 InvalidStrInConstTab(usize),
63 InvalidBinInConstTab(usize),
64 InvalidSymInConstTab(usize),
65 InvalidSymInPackTab(usize, usize),
66 InvalidSymInUnpackTab(usize, usize),
67 UnpackLimit(usize),
68 InvalidConstInUnpackTab(usize, usize),
69 ConstKeyInFunctionParam(usize, usize),
70 InvalidUnpackInFuncTab(usize),
71 InvalidStrInFuncDebugTab(usize),
72 InvalidStrInSourceMap(usize, usize),
73 InvalidModuleName,
74 Verify(verify::Error),
75 Malformed(Box<dyn error::Error>),
76 Io(io::Error),
77}
78
79impl Display for Error {
80 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
81 use Error::*;
82
83 match self {
84 FileSizeLimit => write!(f, "bytecode file size limit exceeded"),
85 InvalidHeader => write!(f, "invalid file header"),
86 TrailingJunk(offset) => write!(f, "trailing junk in bytecode file at offset {offset}"),
87 BinTabLimit => write!(f, "binary table exceeds size limit"),
88 DebugBinTabLimit => write!(f, "debug binary table exceeds size limit"),
89 InvalidUtf8InDebugBinTab => write!(f, "debug binary table contains invalid UTF-8"),
90 SymTabLimit => write!(f, "symbol table exceeds size limit"),
91 ConstTabLimit => write!(f, "constant table exceeds size limit"),
92 PackTabLimit => write!(f, "pack table exceeds size limit"),
93 UnpackTabLimit => write!(f, "unpack table exceeds size limit"),
94 UnpackLimit(index) => {
95 write!(f, "unpack exceeds size limit at unpack table index {index}")
96 }
97 PackLimit(index) => write!(f, "pack exceeds size limit at pack table index {index}"),
98 StackSlotLimit(index) => write!(
99 f,
100 "stack frame slots exceed size limit at function table index {index}"
101 ),
102 CodeLimit(index) => {
103 write!(f, "code exceeds size limit at function table index {index}")
104 }
105 CertLimit(index) => {
106 write!(
107 f,
108 "certificate exceeds size limit at function table index {index}"
109 )
110 }
111 EmptyCode(index) => write!(f, "code is empty at function table index {index}"),
112 FuncTabLimit => write!(f, "function table exceeds size limit"),
113 FuncTabEmpty => write!(f, "function table is empty"),
114 FuncDebugTabWrongSize => write!(
115 f,
116 "function debug table is neither empty nor the size of the function table"
117 ),
118 InvalidStrInSymTab(index) => {
119 write!(f, "invalid string in symbol table at index {index}")
120 }
121 InvalidStrInConstTab(index) => {
122 write!(f, "invalid string in constant table at index {index}")
123 }
124 InvalidBinInConstTab(index) => {
125 write!(f, "invalid binary data in constant table at index {index}")
126 }
127 InvalidSymInConstTab(index) => {
128 write!(f, "invalid symbol index in constant table at index {index}")
129 }
130 InvalidSymInPackTab(index, arg) => {
131 write!(
132 f,
133 "invalid symbol in pack table at index {index} argument #{arg}"
134 )
135 }
136 InvalidSymInUnpackTab(index, key) => {
137 write!(
138 f,
139 "invalid symbol in unpack table at index {index} key #{key}"
140 )
141 }
142 InvalidConstInUnpackTab(index, key) => {
143 write!(
144 f,
145 "invalid constant in unpack table at index {index} key #{key}"
146 )
147 }
148 ConstKeyInFunctionParam(table_entry, key) => {
149 write!(
150 f,
151 "constant key in function parameter unpack signature (table entry {table_entry}, key {key})"
152 )
153 }
154 InvalidUnpackInFuncTab(index) => {
155 write!(
156 f,
157 "invalid unpack table offset in function table table at index {index}"
158 )
159 }
160 InvalidStrInFuncDebugTab(index) => {
161 write!(f, "invalid string in function debug table at index {index}")
162 }
163 InvalidStrInSourceMap(func, index) => {
164 write!(
165 f,
166 "invalid string in source map for function #{func} at index {index}"
167 )
168 }
169 SourceMapEmpty(index) => write!(f, "empty source map for function #{index}"),
170 SourceMapLimit(index) => {
171 write!(f, "source map size limit exceeded for function #{index}")
172 }
173 SourceMapOffsetBounds(func, index) => {
174 write!(
175 f,
176 "source map offset out of bounds for function #{func} at index {index}"
177 )
178 }
179 SourceMapLineBounds(func, index) => {
180 write!(
181 f,
182 "source map line out of bounds for function #{func} at index {index}"
183 )
184 }
185 SourceMapLineDeltaZero(func, index) => {
186 write!(
187 f,
188 "redundant source map line for function #{func} at index {index}"
189 )
190 }
191 InvalidModuleName => write!(f, "invalid module name in bytecode"),
192 Verify(err) => write!(f, "verification failed: {err}"),
193 Malformed(error) => error.fmt(f),
194 Io(error) => error.fmt(f),
195 }
196 }
197}
198
199impl error::Error for Error {}
200
201impl From<verify::Error> for Error {
202 fn from(value: verify::Error) -> Self {
203 Self::Verify(value)
204 }
205}
206
207impl From<io::Error> for Error {
208 fn from(value: io::Error) -> Self {
209 Self::Io(value)
210 }
211}
212
213impl From<postcard::Error> for Error {
214 fn from(value: postcard::Error) -> Self {
215 Self::Malformed(Box::new(value))
216 }
217}
218
219pub type Result<T> = result::Result<T, Error>;
220
221use serde::{Deserialize, Serialize};
222
223use std::{
224 error,
225 fmt::{self, Display, Formatter},
226 io,
227 marker::PhantomData,
228 mem,
229 ptr::NonNull,
230 result, slice,
231};
232
233use varint::{IVar, UVar};
234
235pub(crate) mod limit {
236 const KIB: usize = 1024;
238 const MIB: usize = 1024 * KIB;
239 const FEW: usize = 1 << 12;
240 const SOME: usize = 1 << 16;
241 const PLENTY: usize = 1 << 20;
242 pub(crate) const FUNC_SIZE: usize = 256 * KIB;
244 pub(crate) const CERT_ENTRIES: usize = SOME;
246 pub(crate) const FUNC_TAB_ENTRIES: usize = PLENTY;
247 pub(crate) const FUNC_FRAME_SLOTS: usize = SOME;
249 pub(crate) const SOURCE_MAP_ENTRIES: usize = SOME;
250 pub(crate) const UPVAR_TOTAL: usize = FEW;
252 pub(crate) const SYMBOL_TAB_ENTRIES: usize = PLENTY;
253 pub(crate) const CONST_TAB_ENTRIES: usize = PLENTY;
254 pub(crate) const PACK_TAB_ENTRIES: usize = PLENTY;
255 pub(crate) const UNPACK_TAB_ENTRIES: usize = PLENTY;
256 pub(crate) const PACK_ENTRIES: usize = FEW;
257 pub(crate) const UNPACK_ENTRIES: usize = FEW;
258 pub(crate) const STRING_LENGTH: usize = MIB;
259 pub(crate) const BIN_TAB_SIZE: usize = 100 * MIB;
260 pub(crate) const DEBUG_BIN_TAB_SIZE: usize = 100 * MIB;
261 pub(crate) const BYTECODE_FILE_SIZE: usize = 100 * MIB;
262}
263
264#[repr(usize)]
265pub enum Builtin {
266 Import,
267 Array,
268 Dict,
269 Iter,
270 ConcatStr,
271 ConcatArg,
272 Args,
273 ClassCreate,
274 Guard,
275 Throw,
276 ConcatBin,
277 _LEN,
278}
279
280pub mod builtin {
281 use super::Builtin::*;
282 pub const IMPORT: usize = Import as usize;
283 pub const ARRAY: usize = Array as usize;
284 pub const DICT: usize = Dict as usize;
285 pub const ITER: usize = Iter as usize;
286 pub const CONCAT_STR: usize = ConcatStr as usize;
287 pub const CONCAT_ARG: usize = ConcatArg as usize;
288 pub const ARGS: usize = Args as usize;
289 pub const CLASS_CREATE: usize = ClassCreate as usize;
290 pub const GUARD: usize = Guard as usize;
291 pub const THROW: usize = Throw as usize;
292 pub const CONCAT_BIN: usize = ConcatBin as usize;
293}
294
295pub const BUILTINS: [&str; Builtin::_LEN as usize] = [
296 "import",
297 "array",
298 "dict",
299 "iter",
300 "concat_str",
301 "concat_arg",
302 "args",
303 "class_create",
304 "guard",
305 "throw",
306 "concat_bin",
307];
308
309trait Encode {
310 fn encode(&self, w: &mut impl io::Write) -> EncResult<()>;
311}
312
313trait Decode: Sized {
314 fn decode<R: io::Read + io::Seek>(r: &mut R) -> DecResult<Self>;
315}
316
317trait UnsafeDecode: Sized {
318 unsafe fn decode(r: &mut NonNull<u8>) -> Self;
319}
320
321#[derive(PartialEq, Eq, Debug, Clone, Copy)]
322#[repr(u8)]
323pub enum Opcode {
324 Add = 1,
325 Call, MethodCall, Builtin, Div,
329 Ediv,
330 Dup,
331 Swap,
332 LoadConst, LoadLocal, LoadUpvar, Get, Set, Index,
338 Assign,
339 Mod,
340 Mul,
341 Neg,
342 Not,
343 BitNot,
344 BitAnd,
345 BitOr,
346 BitXor,
347 Pop,
348 Eq,
349 Ne,
350 Gt,
351 Lt,
352 Gte,
353 Lte,
354 StoreLocal, StoreUpvar, Sub,
357 PushUpvars, PopUpvars,
359 Close, Ret,
361 Branch, BranchTrue, BranchFalse, Reify, Next,
366 Unpack, NlGuard, NlBranch, }
370
371#[derive(Debug, Clone, Copy)]
373pub enum Inst {
374 Add,
375 Call(usize),
376 MethodCall(usize, usize),
377 Builtin(usize, usize),
378 Div,
379 Ediv,
380 Dup,
381 Swap(usize, usize),
382 LoadConst(usize),
383 LoadLocal(usize),
384 LoadUpvar(usize, usize),
385 Get(usize),
386 Set(usize),
387 Index,
388 Assign,
389 Mod,
390 Mul,
391 Neg,
392 Not,
393 BitNot,
394 BitAnd,
395 BitOr,
396 BitXor,
397 Pop,
398 Eq,
399 Ne,
400 Gt,
401 Lt,
402 Gte,
403 Lte,
404 StoreLocal(usize),
405 StoreUpvar(usize, usize),
406 Sub,
407 PushUpvars(usize),
408 PopUpvars,
409 Close(usize),
410 Ret,
411 Branch(isize),
412 BranchTrue(isize),
413 BranchFalse(isize),
414 Reify(usize),
415 Next,
416 Unpack(usize),
417 NlGuard(usize),
418 NlBranch(usize, usize),
419}
420
421#[cfg(feature = "debug")]
422impl Display for Inst {
423 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
424 use Inst::*;
425
426 match self {
427 Pop => write!(f, "pop"),
428 Dup => write!(f, "dup"),
429 Swap(i, j) => write!(f, "swap {i} {j}"),
430 Add => write!(f, "add"),
431 Sub => write!(f, "sub"),
432 Mul => write!(f, "mul"),
433 Div => write!(f, "div"),
434 Ediv => write!(f, "ediv"),
435 Mod => write!(f, "mod"),
436 Eq => write!(f, "eq"),
437 Ne => write!(f, "ne"),
438 Gt => write!(f, "gt"),
439 Lt => write!(f, "lt"),
440 Gte => write!(f, "gte"),
441 Lte => write!(f, "lte"),
442 Neg => write!(f, "neg"),
443 Not => write!(f, "not"),
444 BitNot => write!(f, "bnot"),
445 BitAnd => write!(f, "band"),
446 BitOr => write!(f, "bor"),
447 BitXor => write!(f, "bxor"),
448 Ret => write!(f, "ret"),
449 LoadConst(id) => write!(f, "ldc #{id}"),
450 Get(id) => write!(f, "get #{id}"),
451 Set(id) => write!(f, "set #{id}"),
452 Index => write!(f, "indx"),
453 Assign => write!(f, "assn"),
454 Call(id) => write!(f, "call #{id}"),
455 MethodCall(sym, sig) => write!(f, "mcll #{sym} #{sig}"),
456 Builtin(idx, sig) => write!(
457 f,
458 "bltn #{idx}({}) #{sig}",
459 BUILTINS.get(*idx).unwrap_or(&"INVALID")
460 ),
461 LoadLocal(idx) => write!(f, "ldl #{idx}"),
462 StoreLocal(idx) => write!(f, "stl #{idx}"),
463 LoadUpvar(idx, depth) => write!(f, "ldu #{idx},{depth}"),
464 StoreUpvar(idx, depth) => write!(f, "stu #{idx},{depth}"),
465 PushUpvars(count) => write!(f, "pshu #{count}"),
466 PopUpvars => write!(f, "popu"),
467 Close(id) => write!(f, "cls #{id}"),
468 Branch(ofs) => write!(f, "br {ofs}"),
469 BranchTrue(ofs) => write!(f, "brt {ofs}"),
470 BranchFalse(ofs) => write!(f, "brf {ofs}"),
471 Reify(id) => write!(f, "rfy #{id}"),
472 Next => write!(f, "next"),
473 Unpack(id) => write!(f, "unpk #{id}"),
474 NlGuard(id) => write!(f, "nlgd #{id}"),
475 NlBranch(depth, indicator) => write!(f, "nlbr {depth},{indicator}"),
476 }
477 }
478}
479
480impl Encode for Opcode {
481 fn encode(&self, w: &mut impl io::Write) -> EncResult<()> {
482 let val = *self as u8;
483 w.write_all(slice::from_ref(&val))?;
484 Ok(())
485 }
486}
487
488impl Decode for Opcode {
489 fn decode<R: io::Read + io::Seek>(r: &mut R) -> DecResult<Self> {
490 use Opcode::*;
491
492 const TABLE: [Option<Opcode>; 256] = const {
493 let table = [
494 None,
495 Some(Add),
496 Some(Call),
497 Some(MethodCall),
498 Some(Builtin),
499 Some(Div),
500 Some(Ediv),
501 Some(Dup),
502 Some(Swap),
503 Some(LoadConst),
504 Some(LoadLocal),
505 Some(LoadUpvar),
506 Some(Get),
507 Some(Set),
508 Some(Index),
509 Some(Assign),
510 Some(Mod),
511 Some(Mul),
512 Some(Neg),
513 Some(Not),
514 Some(BitNot),
515 Some(BitAnd),
516 Some(BitOr),
517 Some(BitXor),
518 Some(Pop),
519 Some(Eq),
520 Some(Ne),
521 Some(Gt),
522 Some(Lt),
523 Some(Gte),
524 Some(Lte),
525 Some(StoreLocal),
526 Some(StoreUpvar),
527 Some(Sub),
528 Some(PushUpvars),
529 Some(PopUpvars),
530 Some(Close),
531 Some(Ret),
532 Some(Branch),
533 Some(BranchTrue),
534 Some(BranchFalse),
535 Some(Reify),
536 Some(Next),
537 Some(Unpack),
538 Some(NlGuard),
539 Some(NlBranch),
540 None,
542 None,
543 None,
544 None,
545 None,
546 None,
547 None,
548 None,
549 None,
550 None,
551 None,
552 None,
553 None,
554 None,
555 None,
556 None,
557 None,
558 None,
559 None,
560 None,
561 None,
562 None,
563 None,
564 None,
565 None,
566 None,
567 None,
568 None,
569 None,
570 None,
571 None,
572 None,
573 None,
574 None,
575 None,
576 None,
577 None,
578 None,
579 None,
580 None,
581 None,
582 None,
583 None,
584 None,
585 None,
586 None,
587 None,
588 None,
589 None,
590 None,
591 None,
592 None,
593 None,
594 None,
595 None,
596 None,
597 None,
598 None,
599 None,
600 None,
601 None,
602 None,
603 None,
604 None,
605 None,
606 None,
607 None,
608 None,
609 None,
610 None,
611 None,
612 None,
613 None,
614 None,
615 None,
616 None,
617 None,
618 None,
619 None,
620 None,
621 None,
622 None,
623 None,
624 None,
625 None,
626 None,
627 None,
628 None,
629 None,
630 None,
631 None,
632 None,
633 None,
634 None,
635 None,
636 None,
637 None,
638 None,
639 None,
640 None,
641 None,
642 None,
643 None,
644 None,
645 None,
646 None,
647 None,
648 None,
649 None,
650 None,
651 None,
652 None,
653 None,
654 None,
655 None,
656 None,
657 None,
658 None,
659 None,
660 None,
661 None,
662 None,
663 None,
664 None,
665 None,
666 None,
667 None,
668 None,
669 None,
670 None,
671 None,
672 None,
673 None,
674 None,
675 None,
676 None,
677 None,
678 None,
679 None,
680 None,
681 None,
682 None,
683 None,
684 None,
685 None,
686 None,
687 None,
688 None,
689 None,
690 None,
691 None,
692 None,
693 None,
694 None,
695 None,
696 None,
697 None,
698 None,
699 None,
700 None,
701 None,
702 None,
703 None,
704 None,
705 None,
706 None,
707 None,
708 None,
709 None,
710 None,
711 None,
712 None,
713 None,
714 None,
715 None,
716 None,
717 None,
718 None,
719 None,
720 None,
721 None,
722 None,
723 None,
724 None,
725 None,
726 None,
727 None,
728 None,
729 None,
730 None,
731 None,
732 None,
733 None,
734 None,
735 None,
736 None,
737 None,
738 None,
739 None,
740 None,
741 None,
742 None,
743 None,
744 None,
745 None,
746 None,
747 None,
748 None,
749 None,
750 None,
751 ];
752 if size_of_val(&table) != 256 {
753 panic!("reality is broken")
754 }
755 table
756 };
757
758 let mut val = 0;
759
760 let offset = r.stream_position()?.try_into().unwrap();
761 r.read_exact(slice::from_mut(&mut val))?;
762 TABLE[val as usize].ok_or(DecError::InvalidOpcode(offset))
763 }
764}
765
766impl Inst {
767 pub fn write<W: io::Write>(&self, w: &mut InstEncoder<W>) -> EncResult<()> {
768 use Inst::*;
769
770 match self {
771 Add => w.opcode(Opcode::Add),
772 Div => w.opcode(Opcode::Div),
773 Ediv => w.opcode(Opcode::Ediv),
774 Mod => w.opcode(Opcode::Mod),
775 Mul => w.opcode(Opcode::Mul),
776 Neg => w.opcode(Opcode::Neg),
777 Not => w.opcode(Opcode::Not),
778 BitNot => w.opcode(Opcode::BitNot),
779 BitAnd => w.opcode(Opcode::BitAnd),
780 BitOr => w.opcode(Opcode::BitOr),
781 BitXor => w.opcode(Opcode::BitXor),
782 Pop => w.opcode(Opcode::Pop),
783 Eq => w.opcode(Opcode::Eq),
784 Ne => w.opcode(Opcode::Ne),
785 Gt => w.opcode(Opcode::Gt),
786 Lt => w.opcode(Opcode::Lt),
787 Gte => w.opcode(Opcode::Gte),
788 Lte => w.opcode(Opcode::Lte),
789 Dup => w.opcode(Opcode::Dup),
790 Swap(i, j) => {
791 w.opcode(Opcode::Swap)?;
792 w.usize(*i)?;
793 w.usize(*j)
794 }
795 Sub => w.opcode(Opcode::Sub),
796 PopUpvars => w.opcode(Opcode::PopUpvars),
797 Ret => w.opcode(Opcode::Ret),
798 Call(id) => {
799 w.opcode(Opcode::Call)?;
800 w.usize(*id)
801 }
802 MethodCall(sym, sig) => {
803 w.opcode(Opcode::MethodCall)?;
804 w.usize(*sym)?;
805 w.usize(*sig)
806 }
807 Builtin(idx, sig) => {
808 w.opcode(Opcode::Builtin)?;
809 w.usize(*idx)?;
810 w.usize(*sig)
811 }
812 LoadConst(id) => {
813 w.opcode(Opcode::LoadConst)?;
814 w.usize(*id)
815 }
816 LoadLocal(idx) => {
817 w.opcode(Opcode::LoadLocal)?;
818 w.usize(*idx)
819 }
820 LoadUpvar(idx, depth) => {
821 w.opcode(Opcode::LoadUpvar)?;
822 w.usize(*idx)?;
823 w.usize(*depth)
824 }
825 StoreLocal(id) => {
826 w.opcode(Opcode::StoreLocal)?;
827 w.usize(*id)
828 }
829 StoreUpvar(idx, depth) => {
830 w.opcode(Opcode::StoreUpvar)?;
831 w.usize(*idx)?;
832 w.usize(*depth)
833 }
834 Get(id) => {
835 w.opcode(Opcode::Get)?;
836 w.usize(*id)
837 }
838 Set(id) => {
839 w.opcode(Opcode::Set)?;
840 w.usize(*id)
841 }
842 Index => w.opcode(Opcode::Index),
843 Assign => w.opcode(Opcode::Assign),
844 PushUpvars(count) => {
845 w.opcode(Opcode::PushUpvars)?;
846 w.usize(*count)
847 }
848 Close(id) => {
849 w.opcode(Opcode::Close)?;
850 w.usize(*id)
851 }
852 Branch(target) => {
853 w.opcode(Opcode::Branch)?;
854 w.isize(*target)
855 }
856 BranchTrue(target) => {
857 w.opcode(Opcode::BranchTrue)?;
858 w.isize(*target)
859 }
860 BranchFalse(target) => {
861 w.opcode(Opcode::BranchFalse)?;
862 w.isize(*target)
863 }
864 Reify(id) => {
865 w.opcode(Opcode::Reify)?;
866 w.usize(*id)
867 }
868 Next => w.opcode(Opcode::Next),
869 Unpack(id) => {
870 w.opcode(Opcode::Unpack)?;
871 w.usize(*id)
872 }
873 NlGuard(id) => {
874 w.opcode(Opcode::NlGuard)?;
875 w.usize(*id)
876 }
877 NlBranch(depth, indicator) => {
878 w.opcode(Opcode::NlBranch)?;
879 w.usize(*depth)?;
880 w.usize(*indicator)
881 }
882 }
883 }
884}
885
886impl Encode for Inst {
887 fn encode(&self, w: &mut impl io::Write) -> EncResult<()> {
888 let mut write = InstEncoder::new(w);
889 self.write(&mut write)
890 }
891}
892
893pub struct InstEncoder<W: io::Write>(W);
894
895impl<W: io::Write> InstEncoder<W> {
896 pub fn new(write: W) -> Self {
897 Self(write)
898 }
899
900 pub fn opcode(&mut self, op: Opcode) -> EncResult<()> {
901 op.encode(&mut self.0)
902 }
903
904 pub fn uvar(&mut self, val: UVar) -> EncResult<()> {
905 val.encode(&mut self.0)
906 }
907
908 pub fn ivar(&mut self, val: IVar) -> EncResult<()> {
909 val.encode(&mut self.0)
910 }
911
912 pub fn usize(&mut self, val: usize) -> EncResult<()> {
913 self.uvar(val.try_into().expect("uvar not large enough for usize?!"))
914 }
915
916 pub fn isize(&mut self, val: isize) -> EncResult<()> {
917 self.ivar(val.try_into().expect("ivar not large enough for isize?!"))
918 }
919}
920
921impl<W: io::Write + io::Seek> InstEncoder<W> {
922 pub fn offset(&mut self) -> io::Result<usize> {
923 self.0
924 .stream_position()?
925 .try_into()
926 .map_err(|_| io::Error::other("instruction stream too long"))
927 }
928}
929
930pub struct InstDecoder<R: io::Read>(R);
931
932impl<R: io::Read + io::Seek> InstDecoder<R> {
933 pub fn new(read: R) -> Self {
934 Self(read)
935 }
936
937 pub fn opcode(&mut self) -> DecResult<Opcode> {
938 Decode::decode(&mut self.0)
939 }
940
941 pub fn uvar(&mut self) -> DecResult<UVar> {
942 let offset = self.offset()?;
943 Decode::decode(&mut self.0).map_err(|e| match e {
944 DecError::Io(e) => match e.kind() {
945 io::ErrorKind::UnexpectedEof => DecError::Truncated(offset),
946 _ => DecError::Io(e),
947 },
948 e => e,
949 })
950 }
951
952 pub fn ivar(&mut self) -> DecResult<IVar> {
953 let offset = self.offset()?;
954 Decode::decode(&mut self.0).map_err(|e| match e {
955 DecError::Io(e) => match e.kind() {
956 io::ErrorKind::UnexpectedEof => DecError::Truncated(offset),
957 _ => DecError::Io(e),
958 },
959 e => e,
960 })
961 }
962
963 pub fn usize(&mut self) -> DecResult<usize> {
964 let offset = self.offset()?;
965 self.uvar()
966 .and_then(|v| v.try_into().map_err(|_| DecError::IntegerOverflow(offset)))
967 }
968
969 pub fn isize(&mut self) -> DecResult<isize> {
970 let offset = self.offset()?;
971 self.ivar()
972 .and_then(|v| v.try_into().map_err(|_| DecError::IntegerOverflow(offset)))
973 }
974
975 pub fn offset(&mut self) -> io::Result<usize> {
976 self.0
977 .stream_position()?
978 .try_into()
979 .map_err(|_| io::Error::other("instruction stream too long"))
980 }
981
982 pub fn with_offsets(self) -> WithOffsets<R> {
983 WithOffsets(self)
984 }
985}
986
987impl<R: io::Read + io::Seek> Iterator for InstDecoder<R> {
988 type Item = DecResult<Inst>;
989
990 fn next(&mut self) -> Option<Self::Item> {
991 use Opcode::*;
992
993 let op = match self.opcode() {
994 Ok(op) => op,
995 Err(DecError::Io(e)) => {
996 match e.kind() {
997 io::ErrorKind::UnexpectedEof => return None,
999 _ => return Some(Err(DecError::Io(e))),
1000 }
1001 }
1002 Err(err) => return Some(Err(err)),
1003 };
1004 Some((|| {
1005 Ok(match op {
1006 Add => Inst::Add,
1007 Call => Inst::Call(self.usize()?),
1008 MethodCall => Inst::MethodCall(self.usize()?, self.usize()?),
1009 Builtin => Inst::Builtin(self.usize()?, self.usize()?),
1010 Div => Inst::Div,
1011 Ediv => Inst::Ediv,
1012 Dup => Inst::Dup,
1013 Swap => Inst::Swap(self.usize()?, self.usize()?),
1014 LoadConst => Inst::LoadConst(self.usize()?),
1015 LoadLocal => Inst::LoadLocal(self.usize()?),
1016 LoadUpvar => Inst::LoadUpvar(self.usize()?, self.usize()?),
1017 Get => Inst::Get(self.usize()?),
1018 Set => Inst::Set(self.usize()?),
1019 Index => Inst::Index,
1020 Assign => Inst::Assign,
1021 Mod => Inst::Mod,
1022 Mul => Inst::Mul,
1023 Neg => Inst::Neg,
1024 Not => Inst::Not,
1025 BitNot => Inst::BitNot,
1026 BitOr => Inst::BitOr,
1027 BitAnd => Inst::BitAnd,
1028 BitXor => Inst::BitXor,
1029 Pop => Inst::Pop,
1030 Eq => Inst::Eq,
1031 Ne => Inst::Ne,
1032 Gt => Inst::Gt,
1033 Lt => Inst::Lt,
1034 Gte => Inst::Gte,
1035 Lte => Inst::Lte,
1036 StoreLocal => Inst::StoreLocal(self.usize()?),
1037 StoreUpvar => Inst::StoreUpvar(self.usize()?, self.usize()?),
1038 Sub => Inst::Sub,
1039 PushUpvars => Inst::PushUpvars(self.usize()?),
1040 PopUpvars => Inst::PopUpvars,
1041 Close => Inst::Close(self.usize()?),
1042 Ret => Inst::Ret,
1043 Branch => Inst::Branch(self.isize()?),
1044 BranchTrue => Inst::BranchTrue(self.isize()?),
1045 BranchFalse => Inst::BranchFalse(self.isize()?),
1046 Reify => Inst::Reify(self.usize()?),
1047 Next => Inst::Next,
1048 Unpack => Inst::Unpack(self.usize()?),
1049 NlGuard => Inst::NlGuard(self.usize()?),
1050 NlBranch => Inst::NlBranch(self.usize()?, self.usize()?),
1051 })
1052 })())
1053 }
1054}
1055
1056pub struct InstOffsets {
1057 pub before: usize,
1058 pub inst: Inst,
1059 pub after: usize,
1060}
1061
1062pub struct WithOffsets<R: io::Read + io::Seek>(InstDecoder<R>);
1063
1064impl<R: io::Read + io::Seek> Iterator for WithOffsets<R> {
1065 type Item = DecResult<InstOffsets>;
1066
1067 fn next(&mut self) -> Option<Self::Item> {
1068 let pre = match self.0.offset() {
1069 Ok(offset) => offset,
1070 Err(err) => return Some(Err(err.into())),
1071 };
1072 let next = self.0.next();
1073 let post = match self.0.offset() {
1074 Ok(offset) => offset,
1075 Err(err) => return Some(Err(err.into())),
1076 };
1077 next.map(|item| {
1078 item.map(|inst| InstOffsets {
1079 before: pre,
1080 inst,
1081 after: post,
1082 })
1083 })
1084 }
1085}
1086
1087pub struct UnsafeInstDecoder<'a> {
1091 start: NonNull<u8>,
1092 pc: NonNull<u8>,
1093 phantom: PhantomData<&'a [u8]>,
1094}
1095
1096impl<'a> UnsafeInstDecoder<'a> {
1097 pub fn new(bytecode: &'a [u8]) -> Self {
1098 let pc = unsafe { NonNull::new_unchecked(bytecode.as_ptr() as *mut u8) };
1099 Self {
1100 start: pc,
1101 pc,
1102 phantom: PhantomData,
1103 }
1104 }
1105
1106 pub unsafe fn opcode(&mut self) -> Opcode {
1109 unsafe {
1110 let op = *self.pc.as_ptr();
1111 self.pc = self.pc.add(1);
1112 mem::transmute::<u8, Opcode>(op)
1113 }
1114 }
1115
1116 pub unsafe fn uvar(&mut self) -> UVar {
1119 unsafe { UnsafeDecode::decode(&mut self.pc) }
1120 }
1121
1122 pub unsafe fn ivar(&mut self) -> IVar {
1125 unsafe { UnsafeDecode::decode(&mut self.pc) }
1126 }
1127
1128 pub unsafe fn usize(&mut self) -> usize {
1131 unsafe { self.uvar() as usize }
1132 }
1133
1134 pub unsafe fn isize(&mut self) -> isize {
1137 unsafe { self.ivar() as isize }
1138 }
1139
1140 pub unsafe fn seek(&mut self, offset: isize) {
1143 unsafe { self.pc = self.pc.offset(offset) }
1144 }
1145
1146 pub fn offset(&self) -> usize {
1147 self.pc.addr().get() - self.start.addr().get()
1148 }
1149}
1150
1151pub trait Phase: Sized {
1152 type Bytes;
1153}
1154
1155#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
1156pub enum Arg {
1157 Value,
1158 Pack,
1159 Key(usize),
1160}
1161
1162#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
1163pub enum Variadic {
1164 None,
1166 Discard,
1168 Capture,
1170}
1171
1172#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
1173pub struct Func<P: Phase> {
1174 pub sig: usize,
1176 pub locals: usize,
1177 pub upvars: Vec<usize>,
1178 pub bytecode: P::Bytes,
1179}
1180
1181#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
1182pub(crate) enum LocalState {
1183 Invalid,
1184 Value,
1185}
1186
1187#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
1188pub(crate) struct BlockState {
1189 operands: usize,
1190 locals: Vec<LocalState>,
1191 upvars: Vec<usize>,
1192}
1193
1194#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Default)]
1195pub struct Certificate {
1196 pub max_operand_depth: usize,
1197 pub(crate) blocks: Vec<(usize, BlockState)>,
1198}