1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright 2022 The Goscript Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

use crate::value::*;
#[cfg(feature = "serde_borsh")]
use borsh::{maybestd::io::Result, maybestd::io::Write, BorshDeserialize, BorshSerialize};
#[cfg(feature = "serde_borsh")]
use go_parser::PiggyVecKey;
use go_parser::{piggy_key_type, PiggyVec};

#[cfg(feature = "serde_borsh")]
macro_rules! impl_borsh_for_key {
    ($key:ident) => {
        impl BorshSerialize for $key {
            fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
                self.as_usize().serialize(writer)
            }
        }

        impl BorshDeserialize for $key {
            fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> Result<Self> {
                let i: usize = usize::deserialize_reader(reader)?;
                Ok(i.into())
            }
        }
    };
}

piggy_key_type! {
    pub struct MetadataKey;
    pub struct FunctionKey;
    pub struct PackageKey;
}

#[cfg(feature = "serde_borsh")]
impl_borsh_for_key!(MetadataKey);
#[cfg(feature = "serde_borsh")]
impl_borsh_for_key!(FunctionKey);
#[cfg(feature = "serde_borsh")]
impl_borsh_for_key!(PackageKey);

pub type MetadataObjs = PiggyVec<MetadataKey, MetadataType>;
pub type FunctionObjs = PiggyVec<FunctionKey, FunctionObj>;
pub type PackageObjs = PiggyVec<PackageKey, PackageObj>;

pub struct VMObjects {
    pub metas: MetadataObjs,
    pub functions: FunctionObjs,
    pub packages: PackageObjs,
    pub prim_meta: PrimitiveMeta,
    pub(crate) arr_slice_caller: Box<ArrCaller>,
}

impl VMObjects {
    pub fn new() -> VMObjects {
        const CAP: usize = 16;
        let mut metas = PiggyVec::with_capacity(CAP);
        let prim_meta = PrimitiveMeta::new(&mut metas);
        VMObjects {
            metas,
            functions: PiggyVec::with_capacity(CAP),
            packages: PiggyVec::with_capacity(CAP),
            prim_meta,
            arr_slice_caller: Box::new(ArrCaller::new()),
        }
    }

    pub fn with_components(
        mut metas: MetadataObjs,
        functions: FunctionObjs,
        packages: PackageObjs,
    ) -> VMObjects {
        let prim_meta = PrimitiveMeta::new(&mut metas);
        VMObjects {
            metas,
            functions,
            packages,
            prim_meta,
            arr_slice_caller: Box::new(ArrCaller::new()),
        }
    }
}

#[cfg(feature = "serde_borsh")]
impl BorshSerialize for VMObjects {
    fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
        self.metas.serialize(writer)?;
        self.functions.serialize(writer)?;
        self.packages.serialize(writer)
    }
}

#[cfg(feature = "serde_borsh")]
impl BorshDeserialize for VMObjects {
    fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> Result<Self> {
        let metas = MetadataObjs::deserialize_reader(reader)?.into();
        let functions = FunctionObjs::deserialize_reader(reader)?.into();
        let packages = PackageObjs::deserialize_reader(reader)?.into();
        Ok(Self::with_components(metas, functions, packages))
    }
}

#[cfg_attr(feature = "serde_borsh", derive(BorshDeserialize, BorshSerialize))]
pub struct Bytecode {
    pub objects: VMObjects,
    pub consts: Vec<GosValue>,
    /// For calling method via interfaces
    pub ifaces: Vec<(Meta, Vec<Binding4Runtime>)>,
    /// For embedded fields of structs
    pub indices: Vec<Vec<OpIndex>>,
    pub entry: FunctionKey,
    pub main_pkg: PackageKey,
    /// Optional, for debug info
    pub file_set: Option<go_parser::FileSet>,
}

impl Bytecode {
    pub fn new(
        objects: VMObjects,
        consts: Vec<GosValue>,
        ifaces: Vec<(Meta, Vec<IfaceBinding>)>,
        indices: Vec<Vec<OpIndex>>,
        entry: FunctionKey,
        main_pkg: PackageKey,
        file_set: Option<go_parser::FileSet>,
    ) -> Bytecode {
        let ifaces = ifaces
            .into_iter()
            .map(|(ms, binding)| {
                let binding = binding.into_iter().map(|x| x.into()).collect();
                (ms, binding)
            })
            .collect();
        Bytecode {
            objects,
            consts,
            ifaces,
            indices,
            entry,
            main_pkg,
            file_set,
        }
    }

    pub fn with_components(
        metas: MetadataObjs,
        functions: FunctionObjs,
        packages: PackageObjs,
        consts: Vec<GosValue>,
        ifaces: Vec<(Meta, Vec<Binding4Runtime>)>,
        indices: Vec<Vec<OpIndex>>,
        entry: FunctionKey,
        main_pkg: PackageKey,
        file_set: Option<go_parser::FileSet>,
    ) -> Bytecode {
        let objects = VMObjects::with_components(metas, functions, packages);
        Bytecode {
            objects,
            consts,
            ifaces,
            indices,
            entry,
            main_pkg,
            file_set,
        }
    }
}