go_vm/
bytecode.rs

1// Copyright 2022 The Goscript Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5use crate::value::*;
6#[cfg(feature = "serde_borsh")]
7use borsh::{maybestd::io::Result, maybestd::io::Write, BorshDeserialize, BorshSerialize};
8#[cfg(feature = "serde_borsh")]
9use go_parser::PiggyVecKey;
10use go_parser::{piggy_key_type, PiggyVec};
11
12#[cfg(feature = "serde_borsh")]
13macro_rules! impl_borsh_for_key {
14    ($key:ident) => {
15        impl BorshSerialize for $key {
16            fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
17                self.as_usize().serialize(writer)
18            }
19        }
20
21        impl BorshDeserialize for $key {
22            fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> Result<Self> {
23                let i: usize = usize::deserialize_reader(reader)?;
24                Ok(i.into())
25            }
26        }
27    };
28}
29
30piggy_key_type! {
31    pub struct MetadataKey;
32    pub struct FunctionKey;
33    pub struct PackageKey;
34}
35
36#[cfg(feature = "serde_borsh")]
37impl_borsh_for_key!(MetadataKey);
38#[cfg(feature = "serde_borsh")]
39impl_borsh_for_key!(FunctionKey);
40#[cfg(feature = "serde_borsh")]
41impl_borsh_for_key!(PackageKey);
42
43pub type MetadataObjs = PiggyVec<MetadataKey, MetadataType>;
44pub type FunctionObjs = PiggyVec<FunctionKey, FunctionObj>;
45pub type PackageObjs = PiggyVec<PackageKey, PackageObj>;
46
47pub struct VMObjects {
48    pub metas: MetadataObjs,
49    pub functions: FunctionObjs,
50    pub packages: PackageObjs,
51    pub prim_meta: PrimitiveMeta,
52    pub(crate) arr_slice_caller: Box<ArrCaller>,
53}
54
55impl VMObjects {
56    pub fn new() -> VMObjects {
57        const CAP: usize = 16;
58        let mut metas = PiggyVec::with_capacity(CAP);
59        let prim_meta = PrimitiveMeta::new(&mut metas);
60        VMObjects {
61            metas,
62            functions: PiggyVec::with_capacity(CAP),
63            packages: PiggyVec::with_capacity(CAP),
64            prim_meta,
65            arr_slice_caller: Box::new(ArrCaller::new()),
66        }
67    }
68
69    pub fn with_components(
70        mut metas: MetadataObjs,
71        functions: FunctionObjs,
72        packages: PackageObjs,
73    ) -> VMObjects {
74        let prim_meta = PrimitiveMeta::new(&mut metas);
75        VMObjects {
76            metas,
77            functions,
78            packages,
79            prim_meta,
80            arr_slice_caller: Box::new(ArrCaller::new()),
81        }
82    }
83}
84
85#[cfg(feature = "serde_borsh")]
86impl BorshSerialize for VMObjects {
87    fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
88        self.metas.serialize(writer)?;
89        self.functions.serialize(writer)?;
90        self.packages.serialize(writer)
91    }
92}
93
94#[cfg(feature = "serde_borsh")]
95impl BorshDeserialize for VMObjects {
96    fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> Result<Self> {
97        let metas = MetadataObjs::deserialize_reader(reader)?.into();
98        let functions = FunctionObjs::deserialize_reader(reader)?.into();
99        let packages = PackageObjs::deserialize_reader(reader)?.into();
100        Ok(Self::with_components(metas, functions, packages))
101    }
102}
103
104#[cfg_attr(feature = "serde_borsh", derive(BorshDeserialize, BorshSerialize))]
105pub struct Bytecode {
106    pub objects: VMObjects,
107    pub consts: Vec<GosValue>,
108    /// For calling method via interfaces
109    pub ifaces: Vec<(Meta, Vec<Binding4Runtime>)>,
110    /// For embedded fields of structs
111    pub indices: Vec<Vec<OpIndex>>,
112    pub entry: FunctionKey,
113    pub main_pkg: PackageKey,
114    /// Optional, for debug info
115    pub file_set: Option<go_parser::FileSet>,
116}
117
118impl Bytecode {
119    pub fn new(
120        objects: VMObjects,
121        consts: Vec<GosValue>,
122        ifaces: Vec<(Meta, Vec<IfaceBinding>)>,
123        indices: Vec<Vec<OpIndex>>,
124        entry: FunctionKey,
125        main_pkg: PackageKey,
126        file_set: Option<go_parser::FileSet>,
127    ) -> Bytecode {
128        let ifaces = ifaces
129            .into_iter()
130            .map(|(ms, binding)| {
131                let binding = binding.into_iter().map(|x| x.into()).collect();
132                (ms, binding)
133            })
134            .collect();
135        Bytecode {
136            objects,
137            consts,
138            ifaces,
139            indices,
140            entry,
141            main_pkg,
142            file_set,
143        }
144    }
145
146    pub fn with_components(
147        metas: MetadataObjs,
148        functions: FunctionObjs,
149        packages: PackageObjs,
150        consts: Vec<GosValue>,
151        ifaces: Vec<(Meta, Vec<Binding4Runtime>)>,
152        indices: Vec<Vec<OpIndex>>,
153        entry: FunctionKey,
154        main_pkg: PackageKey,
155        file_set: Option<go_parser::FileSet>,
156    ) -> Bytecode {
157        let objects = VMObjects::with_components(metas, functions, packages);
158        Bytecode {
159            objects,
160            consts,
161            ifaces,
162            indices,
163            entry,
164            main_pkg,
165            file_set,
166        }
167    }
168}