Skip to main content

dolang_bytecode/
lib.rs

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    // Constants
237    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    // Maximum size of function bytecode
243    pub(crate) const FUNC_SIZE: usize = 256 * KIB;
244    // Maximum size of function certificate
245    pub(crate) const CERT_ENTRIES: usize = SOME;
246    pub(crate) const FUNC_TAB_ENTRIES: usize = PLENTY;
247    // Total frame slots (locals and operands) for a function
248    pub(crate) const FUNC_FRAME_SLOTS: usize = SOME;
249    pub(crate) const SOURCE_MAP_ENTRIES: usize = SOME;
250    // Maximum total upvars, summing over nested records
251    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,       // sig: uvar
326    MethodCall, // sym: uvar, sig: uvar
327    Builtin,    // idx: uvar, sig: uvar
328    Div,
329    Ediv,
330    Dup,
331    Swap,
332    LoadConst, // id: uvar
333    LoadLocal, // index: uvar
334    LoadUpvar, // index: uvar, depth: uvar
335    Get,       // sym: uvar
336    Set,       // sym: uvar
337    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, // index: uvar
355    StoreUpvar, // index: uvar, depth: uvar
356    Sub,
357    PushUpvars, // count: uvar
358    PopUpvars,
359    Close, // func: uvar
360    Ret,
361    Branch,      // offset: ivar
362    BranchTrue,  // offset: ivar
363    BranchFalse, // offset: ivar
364    Reify,       // pack: uvar
365    Next,
366    Unpack,   // unpack: uvar
367    NlGuard,  // func: uvar
368    NlBranch, // depth: uvar, indicator: uvar
369}
370
371// Decoded instruction
372#[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                // This is worse than anything
541                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                    // End of instruction stream
998                    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
1087/// All of the unsafe methods of this type depend on the bytecode being
1088/// previously validated and instructions being processed correctly.
1089/// It should not be used outside of the bytecode interpreter.
1090pub 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    /// # Safety
1107    /// Current offset must be in bounds and at valid opcode
1108    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    /// # Safety
1117    /// Current offset must at valid unsigned integer within bounds
1118    pub unsafe fn uvar(&mut self) -> UVar {
1119        unsafe { UnsafeDecode::decode(&mut self.pc) }
1120    }
1121
1122    /// # Safety
1123    /// Current offset must at valid signed integer within bounds
1124    pub unsafe fn ivar(&mut self) -> IVar {
1125        unsafe { UnsafeDecode::decode(&mut self.pc) }
1126    }
1127
1128    /// # Safety
1129    /// Current offset must at valid unsigned integer within bounds that fits in usize
1130    pub unsafe fn usize(&mut self) -> usize {
1131        unsafe { self.uvar() as usize }
1132    }
1133
1134    /// # Safety
1135    /// Current offset must at valid signed integer within bounds that fits in isize
1136    pub unsafe fn isize(&mut self) -> isize {
1137        unsafe { self.ivar() as isize }
1138    }
1139
1140    /// # Safety
1141    /// Target offset must be the start of an in-bounds instruction
1142    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    /// No rest parameter - strict validation, no extra args allowed
1165    None,
1166    /// Rest parameter without capture (...) - allow extra args but don't build iterator
1167    Discard,
1168    /// Rest parameter with capture (...name) - build iterator for remaining items
1169    Capture,
1170}
1171
1172#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
1173pub struct Func<P: Phase> {
1174    // Index in unpack table for function parameters
1175    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}