/src/WasmEdge/include/loader/serialize.h
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | //===-- wasmedge/loader/serialize.h - Serializer class definition ---------===// |
5 | | // |
6 | | // Part of the WasmEdge Project. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | /// |
10 | | /// \file |
11 | | /// This file contains the declaration of the Serializer class, which serializes |
12 | | /// a validated AST Module into its canonical encoding. |
13 | | /// |
14 | | //===----------------------------------------------------------------------===// |
15 | | #pragma once |
16 | | |
17 | | #include "ast/module.h" |
18 | | #include "common/errcode.h" |
19 | | |
20 | | #include <cstring> |
21 | | #include <type_traits> |
22 | | #include <vector> |
23 | | |
24 | | namespace WasmEdge { |
25 | | namespace Loader { |
26 | | |
27 | | class Serializer { |
28 | | public: |
29 | | Serializer() noexcept = default; |
30 | | ~Serializer() noexcept = default; |
31 | | |
32 | | /// Serialize a WASM module. |
33 | | Expect<std::vector<uint8_t>> |
34 | | serializeModule(const AST::Module &Mod) const noexcept; |
35 | | |
36 | | /// \name Serialize functions for WASM sections. |
37 | | /// @{ |
38 | | void serializeSection(const AST::CustomSection &Sec, |
39 | | std::vector<uint8_t> &OutVec) const noexcept; |
40 | | void serializeSection(const AST::TypeSection &Sec, |
41 | | std::vector<uint8_t> &OutVec) const noexcept; |
42 | | void serializeSection(const AST::ImportSection &Sec, |
43 | | std::vector<uint8_t> &OutVec) const noexcept; |
44 | | void serializeSection(const AST::FunctionSection &Sec, |
45 | | std::vector<uint8_t> &OutVec) const noexcept; |
46 | | void serializeSection(const AST::TableSection &Sec, |
47 | | std::vector<uint8_t> &OutVec) const noexcept; |
48 | | void serializeSection(const AST::MemorySection &Sec, |
49 | | std::vector<uint8_t> &OutVec) const noexcept; |
50 | | void serializeSection(const AST::GlobalSection &Sec, |
51 | | std::vector<uint8_t> &OutVec) const noexcept; |
52 | | void serializeSection(const AST::ExportSection &Sec, |
53 | | std::vector<uint8_t> &OutVec) const noexcept; |
54 | | void serializeSection(const AST::StartSection &Sec, |
55 | | std::vector<uint8_t> &OutVec) const noexcept; |
56 | | void serializeSection(const AST::ElementSection &Sec, |
57 | | std::vector<uint8_t> &OutVec) const noexcept; |
58 | | void serializeSection(const AST::CodeSection &Sec, |
59 | | std::vector<uint8_t> &OutVec) const noexcept; |
60 | | void serializeSection(const AST::DataSection &Sec, |
61 | | std::vector<uint8_t> &OutVec) const noexcept; |
62 | | void serializeSection(const AST::DataCountSection &Sec, |
63 | | std::vector<uint8_t> &OutVec) const noexcept; |
64 | | void serializeSection(const AST::TagSection &Sec, |
65 | | std::vector<uint8_t> &OutVec) const noexcept; |
66 | | /// @} |
67 | | |
68 | 0 | void serializeU32(uint32_t Num, std::vector<uint8_t> &OutVec) const noexcept { |
69 | 0 | serializeUN<uint32_t, 32>(Num, OutVec, OutVec.end()); |
70 | 0 | } |
71 | 0 | void serializeS32(int32_t Num, std::vector<uint8_t> &OutVec) const noexcept { |
72 | 0 | serializeSN<int32_t, 32>(Num, OutVec); |
73 | 0 | } |
74 | 0 | void serializeS64(int64_t Num, std::vector<uint8_t> &OutVec) const noexcept { |
75 | 0 | serializeSN<int64_t, 64>(Num, OutVec); |
76 | 0 | } |
77 | 0 | void serializeF32(float Num, std::vector<uint8_t> &OutVec) const noexcept { |
78 | 0 | serializeFN<float, uint32_t>(Num, OutVec); |
79 | 0 | } |
80 | 0 | void serializeF64(double Num, std::vector<uint8_t> &OutVec) const noexcept { |
81 | 0 | serializeFN<double, uint64_t>(Num, OutVec); |
82 | 0 | } |
83 | | |
84 | | private: |
85 | | /// \name Serialize functions for the other nodes of AST. |
86 | | /// @{ |
87 | | void serializeSegment(const AST::TableSegment &Seg, |
88 | | std::vector<uint8_t> &OutVec) const noexcept; |
89 | | void serializeSegment(const AST::GlobalSegment &Seg, |
90 | | std::vector<uint8_t> &OutVec) const noexcept; |
91 | | void serializeSegment(const AST::ElementSegment &Seg, |
92 | | std::vector<uint8_t> &OutVec) const noexcept; |
93 | | void serializeSegment(const AST::CodeSegment &Seg, |
94 | | std::vector<uint8_t> &OutVec) const noexcept; |
95 | | void serializeSegment(const AST::DataSegment &Seg, |
96 | | std::vector<uint8_t> &OutVec) const noexcept; |
97 | | void serializeDesc(const AST::ImportDesc &Desc, |
98 | | std::vector<uint8_t> &OutVec) const noexcept; |
99 | | void serializeDesc(const AST::ExportDesc &Desc, |
100 | | std::vector<uint8_t> &OutVec) const noexcept; |
101 | | void serializeHeapType(const ValType &Type, |
102 | | std::vector<uint8_t> &OutVec) const noexcept; |
103 | | void serializeRefType(const ValType &Type, |
104 | | std::vector<uint8_t> &OutVec) const noexcept; |
105 | | void serializeValType(const ValType &Type, |
106 | | std::vector<uint8_t> &OutVec) const noexcept; |
107 | | void serializeLimit(const AST::Limit &Lim, |
108 | | std::vector<uint8_t> &OutVec) const noexcept; |
109 | | void serializeType(const AST::SubType &SType, |
110 | | std::vector<uint8_t> &OutVec) const noexcept; |
111 | | void serializeType(const AST::FunctionType &Type, |
112 | | std::vector<uint8_t> &OutVec) const noexcept; |
113 | | void serializeType(const AST::TableType &Type, |
114 | | std::vector<uint8_t> &OutVec) const noexcept; |
115 | | void serializeType(const AST::MemoryType &Type, |
116 | | std::vector<uint8_t> &OutVec) const noexcept; |
117 | | void serializeType(const AST::GlobalType &Type, |
118 | | std::vector<uint8_t> &OutVec) const noexcept; |
119 | | void serializeType(const AST::FieldType &Type, |
120 | | std::vector<uint8_t> &OutVec) const noexcept; |
121 | | void serializeType(const AST::TagType &Type, |
122 | | std::vector<uint8_t> &OutVec) const noexcept; |
123 | | void serializeExpression(const AST::Expression &Expr, |
124 | | std::vector<uint8_t> &OutVec) const noexcept; |
125 | | void serializeInstruction(const AST::Instruction &Instr, |
126 | | std::vector<uint8_t> &OutVec) const noexcept; |
127 | | /// @} |
128 | | |
129 | | /// \name Helper functions |
130 | | /// @{ |
131 | | template <typename NumType, size_t N> |
132 | | void serializeUN(NumType Num, std::vector<uint8_t> &OutVec, |
133 | 0 | std::vector<uint8_t>::iterator It) const noexcept { |
134 | 0 | uint8_t Buf[N / 7 + 1]; |
135 | 0 | uint32_t Len = 0; |
136 | 0 | do { |
137 | 0 | uint8_t X = std::make_unsigned_t<NumType>(Num) & 0x7FU; |
138 | 0 | Num >>= 7; |
139 | 0 | if (Num) { |
140 | 0 | X |= 0x80U; |
141 | 0 | } |
142 | 0 | Buf[Len] = X; |
143 | 0 | Len++; |
144 | 0 | } while (Num); |
145 | 0 | OutVec.insert(It, Buf, Buf + Len); |
146 | 0 | } Unexecuted instantiation: void WasmEdge::Loader::Serializer::serializeUN<unsigned int, 32ul>(unsigned int, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, std::__1::__wrap_iter<unsigned char*>) const Unexecuted instantiation: void WasmEdge::Loader::Serializer::serializeUN<unsigned long, 64ul>(unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, std::__1::__wrap_iter<unsigned char*>) const |
147 | | |
148 | | void serializeU32(uint32_t Num, std::vector<uint8_t> &OutVec, |
149 | 0 | std::vector<uint8_t>::iterator It) const noexcept { |
150 | 0 | serializeUN<uint32_t, 32>(Num, OutVec, It); |
151 | 0 | } |
152 | | void serializeU64(uint64_t Num, std::vector<uint8_t> &OutVec, |
153 | 0 | std::vector<uint8_t>::iterator It) const noexcept { |
154 | 0 | serializeUN<uint64_t, 64>(Num, OutVec, It); |
155 | 0 | } |
156 | 0 | void serializeU64(uint64_t Num, std::vector<uint8_t> &OutVec) const noexcept { |
157 | 0 | serializeUN<uint64_t, 64>(Num, OutVec, OutVec.end()); |
158 | 0 | } |
159 | | |
160 | | template <typename NumType, size_t N> |
161 | 0 | void serializeSN(NumType Num, std::vector<uint8_t> &OutVec) const noexcept { |
162 | 0 | uint8_t Buf[N / 7 + 1]; |
163 | 0 | uint32_t Len = 0; |
164 | 0 | bool More = true; |
165 | 0 | while (More) { |
166 | 0 | uint8_t X = static_cast<std::make_unsigned_t<NumType>>(Num) & 0x7FU; |
167 | 0 | Num >>= 7; |
168 | 0 | if ((Num == 0 && !(X & 0x40)) || (Num == -1 && X & 0x40)) { |
169 | 0 | More = false; |
170 | 0 | } else { |
171 | 0 | X |= 0x80; |
172 | 0 | } |
173 | 0 | Buf[Len] = X; |
174 | 0 | Len++; |
175 | 0 | } |
176 | 0 | OutVec.insert(OutVec.end(), Buf, Buf + Len); |
177 | 0 | } Unexecuted instantiation: void WasmEdge::Loader::Serializer::serializeSN<int, 32ul>(int, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const Unexecuted instantiation: void WasmEdge::Loader::Serializer::serializeSN<long, 64ul>(long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const Unexecuted instantiation: void WasmEdge::Loader::Serializer::serializeSN<long, 33ul>(long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const |
178 | | |
179 | 0 | void serializeS33(int64_t Num, std::vector<uint8_t> &OutVec) const noexcept { |
180 | 0 | serializeSN<int64_t, 33>(Num, OutVec); |
181 | 0 | } |
182 | | |
183 | | template <typename NumType, typename IntType> |
184 | | typename std::enable_if_t< |
185 | | sizeof(NumType) == sizeof(IntType) && std::is_integral_v<IntType>, void> |
186 | 0 | serializeFN(NumType Num, std::vector<uint8_t> &OutVec) const noexcept { |
187 | 0 | std::make_unsigned_t<IntType> Buf = 0; |
188 | 0 | std::memcpy(&Buf, &Num, sizeof(NumType)); |
189 | | // Force conversion into little endian. |
190 | 0 | for (uint32_t I = 0; I < sizeof(NumType); I++) { |
191 | 0 | OutVec.push_back(static_cast<uint8_t>(Buf & 0xFFU)); |
192 | 0 | Buf = Buf >> 8; |
193 | 0 | } |
194 | 0 | } Unexecuted instantiation: _ZNK8WasmEdge6Loader10Serializer11serializeFNIfjEENSt3__19enable_ifIXaaeqstT_stT0_sr3stdE13is_integral_vIS6_EEvE4typeES5_RNS3_6vectorIhNS3_9allocatorIhEEEE Unexecuted instantiation: _ZNK8WasmEdge6Loader10Serializer11serializeFNIdmEENSt3__19enable_ifIXaaeqstT_stT0_sr3stdE13is_integral_vIS6_EEvE4typeES5_RNS3_6vectorIhNS3_9allocatorIhEEEE |
195 | | |
196 | | template <typename T, typename L> |
197 | | void serializeSectionContent(const T &Sec, uint8_t Code, |
198 | | std::vector<uint8_t> &OutVec, |
199 | 0 | L &&Func) const noexcept { |
200 | | // Section: section_id + size:u32 + content. |
201 | 0 | auto Content = Sec.getContent(); |
202 | 0 | if (Content.size()) { |
203 | 0 | assuming(Content.size() <= UINT32_MAX); |
204 | | // Section ID. |
205 | 0 | OutVec.push_back(Code); |
206 | 0 | auto OrgSize = OutVec.size(); |
207 | | // Content: vec(T). |
208 | 0 | serializeU32(static_cast<uint32_t>(Content.size()), OutVec); |
209 | 0 | for (const auto &Item : Content) { |
210 | 0 | Func(Item, OutVec); |
211 | 0 | } |
212 | | // Backward insert the section size. |
213 | 0 | serializeU32(static_cast<uint32_t>(OutVec.size() - OrgSize), OutVec, |
214 | 0 | std::next(OutVec.begin(), static_cast<ptrdiff_t>(OrgSize))); |
215 | 0 | } |
216 | 0 | } Unexecuted instantiation: serial_section.cpp:void WasmEdge::Loader::Serializer::serializeSectionContent<WasmEdge::AST::ImportSection, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::ImportSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0>(WasmEdge::AST::ImportSection const&, unsigned char, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::ImportSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0&&) const Unexecuted instantiation: serial_section.cpp:void WasmEdge::Loader::Serializer::serializeSectionContent<WasmEdge::AST::FunctionSection, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::FunctionSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0>(WasmEdge::AST::FunctionSection const&, unsigned char, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::FunctionSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0&&) const Unexecuted instantiation: serial_section.cpp:void WasmEdge::Loader::Serializer::serializeSectionContent<WasmEdge::AST::TableSection, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::TableSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0>(WasmEdge::AST::TableSection const&, unsigned char, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::TableSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0&&) const Unexecuted instantiation: serial_section.cpp:void WasmEdge::Loader::Serializer::serializeSectionContent<WasmEdge::AST::MemorySection, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::MemorySection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0>(WasmEdge::AST::MemorySection const&, unsigned char, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::MemorySection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0&&) const Unexecuted instantiation: serial_section.cpp:void WasmEdge::Loader::Serializer::serializeSectionContent<WasmEdge::AST::GlobalSection, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::GlobalSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0>(WasmEdge::AST::GlobalSection const&, unsigned char, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::GlobalSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0&&) const Unexecuted instantiation: serial_section.cpp:void WasmEdge::Loader::Serializer::serializeSectionContent<WasmEdge::AST::ExportSection, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::ExportSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0>(WasmEdge::AST::ExportSection const&, unsigned char, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::ExportSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0&&) const Unexecuted instantiation: serial_section.cpp:void WasmEdge::Loader::Serializer::serializeSectionContent<WasmEdge::AST::ElementSection, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::ElementSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0>(WasmEdge::AST::ElementSection const&, unsigned char, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::ElementSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0&&) const Unexecuted instantiation: serial_section.cpp:void WasmEdge::Loader::Serializer::serializeSectionContent<WasmEdge::AST::CodeSection, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::CodeSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0>(WasmEdge::AST::CodeSection const&, unsigned char, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::CodeSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0&&) const Unexecuted instantiation: serial_section.cpp:void WasmEdge::Loader::Serializer::serializeSectionContent<WasmEdge::AST::DataSection, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::DataSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0>(WasmEdge::AST::DataSection const&, unsigned char, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::DataSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0&&) const Unexecuted instantiation: serial_section.cpp:void WasmEdge::Loader::Serializer::serializeSectionContent<WasmEdge::AST::TagSection, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::TagSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0>(WasmEdge::AST::TagSection const&, unsigned char, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, WasmEdge::Loader::Serializer::serializeSection(WasmEdge::AST::TagSection const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&) const::$_0&&) const |
217 | | /// @} |
218 | | }; |
219 | | |
220 | | } // namespace Loader |
221 | | } // namespace WasmEdge |