/src/WasmEdge/lib/loader/ast/segment.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | #include "loader/loader.h" |
5 | | |
6 | | namespace WasmEdge { |
7 | | namespace Loader { |
8 | | |
9 | | // Load binary of TableSegment node. See "include/loader/loader.h". |
10 | 2.57k | Expect<void> Loader::loadSegment(AST::TableSegment &TabSeg) { |
11 | | // Check whether the first byte is the reftype in table type. |
12 | 2.57k | EXPECTED_TRY(uint8_t CheckByte, FMgr.peekByte().map_error([this](auto E) { |
13 | 2.55k | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Table); |
14 | 2.55k | })); |
15 | | |
16 | 2.55k | if (CheckByte == 0x40U) { |
17 | | // Table segment case is for FunctionReferences proposal. |
18 | 319 | if (!Conf.hasProposal(Proposal::FunctionReferences)) { |
19 | 0 | return logNeedProposal(ErrCode::Value::MalformedTable, |
20 | 0 | Proposal::FunctionReferences, FMgr.getLastOffset(), |
21 | 0 | ASTNodeAttr::Seg_Table); |
22 | 0 | } |
23 | 319 | FMgr.readByte(); |
24 | | |
25 | | // Check the second byte. |
26 | 319 | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error([this](auto E) { |
27 | 313 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Table); |
28 | 313 | })); |
29 | 313 | if (B != 0x00U) { |
30 | 10 | return logLoadError(ErrCode::Value::MalformedTable, FMgr.getLastOffset(), |
31 | 10 | ASTNodeAttr::Seg_Table); |
32 | 10 | } |
33 | | |
34 | | // Read the table type. |
35 | 303 | EXPECTED_TRY(loadType(TabSeg.getTableType()).map_error([](auto E) { |
36 | 294 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
37 | 294 | return E; |
38 | 294 | })); |
39 | | |
40 | | // Read the expression. |
41 | 294 | EXPECTED_TRY(loadExpression(TabSeg.getExpr()).map_error([](auto E) { |
42 | 294 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
43 | 294 | return E; |
44 | 294 | })); |
45 | 2.23k | } else { |
46 | | // The table type case. |
47 | 2.23k | EXPECTED_TRY(loadType(TabSeg.getTableType()).map_error([](auto E) { |
48 | 2.23k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
49 | 2.23k | return E; |
50 | 2.23k | })); |
51 | 2.23k | } |
52 | | |
53 | 2.31k | return {}; |
54 | 2.55k | } |
55 | | |
56 | | // Load binary of GlobalSegment node. See "include/loader/loader.h". |
57 | 3.01k | Expect<void> Loader::loadSegment(AST::GlobalSegment &GlobSeg) { |
58 | 3.01k | return Expect<void>{} |
59 | 3.01k | .and_then([this, &GlobSeg]() { |
60 | | // Read global type node. |
61 | 3.01k | return loadType(GlobSeg.getGlobalType()); |
62 | 3.01k | }) |
63 | 3.01k | .and_then([this, &GlobSeg]() { |
64 | | // Read the expression. |
65 | 2.88k | return loadExpression(GlobSeg.getExpr()); |
66 | 2.88k | }) |
67 | 3.01k | .map_error([](auto E) { |
68 | 1.54k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Global)); |
69 | 1.54k | return E; |
70 | 1.54k | }); |
71 | 3.01k | } |
72 | | |
73 | | // Load binary of ElementSegment node. See "include/loader/loader.h". |
74 | 11.5k | Expect<void> Loader::loadSegment(AST::ElementSegment &ElemSeg) { |
75 | 11.5k | auto ReportError = [this](auto E) { |
76 | 163 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Element); |
77 | 163 | }; |
78 | | |
79 | | // Element segment binary format: |
80 | | // --------------------------------------------------------------------------- |
81 | | // Mode | TableIdx | OffExpr | ElemKind | RefType | vec(FuncIdx) | vec(expr) |
82 | | // ------|----------|---------|----------|---------|--------------|----------- |
83 | | // 0 | | v | | | v | |
84 | | // 1 | | | v | | v | |
85 | | // 2 | v | v | v | | v | |
86 | | // 3 | | | v | | v | |
87 | | // 4 | | v | | | | v |
88 | | // 5 | | | | v | | v |
89 | | // 6 | v | v | | v | | v |
90 | | // 7 | | | | v | | v |
91 | | // --------------------------------------------------------------------------- |
92 | | // Mode: element initial integer, u32 |
93 | | // TableIdx: target table index, u32 |
94 | | // OffExpr: init offset expression, expr |
95 | | // ElemKind: byte 0x00, ref.func |
96 | | // RefType: reference type, RefType |
97 | | // vec(FuncIdx): function index vector, vec(u32) |
98 | | // vec(expr): reference init list, vec(expr) |
99 | | |
100 | | // Read the checking byte. |
101 | 11.5k | uint32_t Check = 0; |
102 | 11.5k | if (unlikely(!Conf.hasProposal(Proposal::BulkMemoryOperations) && |
103 | 0 | !Conf.hasProposal(Proposal::ReferenceTypes))) { |
104 | | // Legacy for BulkMemoryOperations and ReferenceTypes proposals turned off. |
105 | | // Element segment binary format: TableIdx + OffExpr + vec(FuncIdx) |
106 | 0 | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto Idx) { |
107 | 0 | ElemSeg.setIdx(Idx); |
108 | 0 | })); |
109 | 11.5k | } else { |
110 | 11.5k | EXPECTED_TRY(Check, FMgr.readU32().map_error(ReportError)); |
111 | 11.5k | } |
112 | | |
113 | | // Check the prefix byte. |
114 | 11.5k | switch (Check) { |
115 | 5.91k | case 0x00: |
116 | 7.90k | case 0x02: |
117 | 9.63k | case 0x04: |
118 | 9.95k | case 0x06: |
119 | 9.95k | ElemSeg.setMode(AST::ElementSegment::ElemMode::Active); |
120 | 9.95k | break; |
121 | | |
122 | 676 | case 0x01: |
123 | 895 | case 0x05: |
124 | 895 | ElemSeg.setMode(AST::ElementSegment::ElemMode::Passive); |
125 | 895 | break; |
126 | | |
127 | 309 | case 0x03: |
128 | 559 | case 0x07: |
129 | 559 | ElemSeg.setMode(AST::ElementSegment::ElemMode::Declarative); |
130 | 559 | break; |
131 | | |
132 | 109 | default: |
133 | | // TODO: Correct the error code once there's spec test. |
134 | 109 | return logLoadError(ErrCode::Value::IllegalGrammar, FMgr.getLastOffset(), |
135 | 109 | ASTNodeAttr::Seg_Element); |
136 | 11.5k | } |
137 | | |
138 | | // Read the table index. |
139 | 11.4k | ElemSeg.setIdx(0); |
140 | 11.4k | switch (Check) { |
141 | 1.98k | case 0x02: |
142 | 2.30k | case 0x06: |
143 | 2.30k | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto Idx) { |
144 | 2.29k | ElemSeg.setIdx(Idx); |
145 | 2.29k | })); |
146 | 2.29k | break; |
147 | | |
148 | 9.10k | default: |
149 | 9.10k | break; |
150 | 11.4k | } |
151 | | |
152 | | // Read the expression. |
153 | 11.4k | switch (Check) { |
154 | 5.91k | case 0x00: |
155 | 7.89k | case 0x02: |
156 | 9.63k | case 0x04: |
157 | 9.94k | case 0x06: |
158 | 9.94k | EXPECTED_TRY(loadExpression(ElemSeg.getExpr()).map_error([](auto E) { |
159 | 6.94k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); |
160 | 6.94k | return E; |
161 | 6.94k | })); |
162 | 6.94k | break; |
163 | | |
164 | 6.94k | default: |
165 | 1.45k | break; |
166 | 11.4k | } |
167 | | |
168 | | // Read element kind and init function indices. |
169 | 8.40k | switch (Check) { |
170 | 676 | case 0x01: |
171 | 2.56k | case 0x02: |
172 | 2.86k | case 0x03: |
173 | 2.86k | EXPECTED_TRY(FMgr.readByte() |
174 | 2.83k | .and_then([&](auto B) -> Expect<void> { |
175 | 2.83k | if (B != 0x00U) { |
176 | 2.83k | return Unexpect(ErrCode::Value::ExpectedZeroByte); |
177 | 2.83k | }; |
178 | 2.83k | return {}; |
179 | 2.83k | }) |
180 | 2.83k | .map_error(ReportError)); |
181 | 2.83k | [[fallthrough]]; |
182 | | |
183 | 6.25k | case 0x00: { |
184 | 6.25k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
185 | 483k | for (uint32_t I = 0; I < VecCnt; ++I) { |
186 | | // For each element in vec(funcidx), make expr(ref.func idx end). |
187 | 477k | ElemSeg.getInitExprs().emplace_back(); |
188 | 477k | AST::Instruction RefFunc(OpCode::Ref__func); |
189 | 477k | AST::Instruction End(OpCode::End); |
190 | 477k | EXPECTED_TRY(loadInstruction(RefFunc).map_error([](auto E) { |
191 | 477k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); |
192 | 477k | return E; |
193 | 477k | })); |
194 | 477k | ElemSeg.getInitExprs().back().getInstrs().emplace_back( |
195 | 477k | std::move(RefFunc)); |
196 | 477k | ElemSeg.getInitExprs().back().getInstrs().emplace_back(std::move(End)); |
197 | 477k | } |
198 | 6.12k | break; |
199 | 6.17k | } |
200 | 6.12k | default: |
201 | 2.10k | break; |
202 | 8.40k | } |
203 | | |
204 | | // Set the default reference type. |
205 | 8.23k | if (Check == 0x04) { |
206 | 1.37k | ElemSeg.setRefType(TypeCode::FuncRef); |
207 | 6.85k | } else { |
208 | 6.85k | ElemSeg.setRefType(ValType(TypeCode::Ref, TypeCode::FuncRef)); |
209 | 6.85k | } |
210 | | |
211 | | // Read the reference type and init expressions. |
212 | 8.23k | switch (Check) { |
213 | 219 | case 0x05: |
214 | 486 | case 0x06: |
215 | 736 | case 0x07: { |
216 | | // The AST node information is handled. |
217 | 736 | EXPECTED_TRY(auto Type, loadRefType(ASTNodeAttr::Seg_Element)); |
218 | 719 | ElemSeg.setRefType(Type); |
219 | 719 | [[fallthrough]]; |
220 | 719 | } |
221 | 2.09k | case 0x04: { |
222 | 2.09k | return loadVec<AST::ElementSegment>( |
223 | 3.60k | ElemSeg.getInitExprs(), [this](AST::Expression &Expr) -> Expect<void> { |
224 | 3.60k | return loadExpression(Expr); |
225 | 3.60k | }); |
226 | 719 | } |
227 | | |
228 | 6.12k | default: |
229 | 6.12k | break; |
230 | 8.23k | } |
231 | | |
232 | 6.12k | return {}; |
233 | 8.23k | } |
234 | | |
235 | | // Load binary of CodeSegment node. See "include/loader/loader.h". |
236 | 20.0k | Expect<void> Loader::loadSegment(AST::CodeSegment &CodeSeg) { |
237 | 20.0k | auto ReportError = [this](auto E) { |
238 | 110 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Code); |
239 | 110 | }; |
240 | | |
241 | | // Read the code segment size. |
242 | 20.0k | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto S) { |
243 | 19.9k | CodeSeg.setSegSize(S); |
244 | 19.9k | })); |
245 | 19.9k | auto ExprSizeBound = FMgr.getOffset() + CodeSeg.getSegSize(); |
246 | | |
247 | | // Read the vector of local variable counts and types. |
248 | 19.9k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
249 | 19.9k | CodeSeg.getLocals().clear(); |
250 | 19.9k | CodeSeg.getLocals().reserve(VecCnt); |
251 | 19.9k | uint32_t TotalLocalCnt = 0; |
252 | 30.5k | for (uint32_t I = 0; I < VecCnt; ++I) { |
253 | 10.8k | EXPECTED_TRY(uint32_t LocalCnt, FMgr.readU32().map_error(ReportError)); |
254 | | // Total local variables should not exceed 2^32. Capped at 2^26. |
255 | 10.7k | if (UINT32_C(67108864) - TotalLocalCnt < LocalCnt) { |
256 | 23 | return logLoadError(ErrCode::Value::TooManyLocals, FMgr.getLastOffset(), |
257 | 23 | ASTNodeAttr::Seg_Code); |
258 | 23 | } |
259 | 10.7k | TotalLocalCnt += LocalCnt; |
260 | | // Read the value type. |
261 | | // The AST node information is handled. |
262 | 10.7k | EXPECTED_TRY(ValType LocalType, loadValType(ASTNodeAttr::Seg_Code)); |
263 | 10.6k | CodeSeg.getLocals().push_back(std::make_pair(LocalCnt, LocalType)); |
264 | 10.6k | } |
265 | | |
266 | 19.7k | if (Conf.getRuntimeConfigure().getRunMode() == RunMode::AOT && |
267 | 0 | WASMType != InputType::WASM) { |
268 | | // In AOT run mode with an AOT artifact, skip parsing the function body. |
269 | 0 | FMgr.seek(ExprSizeBound); |
270 | 19.7k | } else { |
271 | | // Read function body with expected expression size. |
272 | 19.7k | EXPECTED_TRY( |
273 | 19.7k | loadExpression(CodeSeg.getExpr(), ExprSizeBound).map_error([](auto E) { |
274 | 19.7k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Code)); |
275 | 19.7k | return E; |
276 | 19.7k | })); |
277 | 19.7k | } |
278 | | |
279 | 17.7k | return {}; |
280 | 19.7k | } |
281 | | |
282 | | // Load binary of DataSegment node. See "include/loader/loader.h". |
283 | 6.70k | Expect<void> Loader::loadSegment(AST::DataSegment &DataSeg) { |
284 | 6.70k | auto ReportError = [this](auto E) { |
285 | 112 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Data); |
286 | 112 | }; |
287 | 6.70k | DataSeg.setMode(AST::DataSegment::DataMode::Passive); |
288 | 6.70k | DataSeg.setIdx(0); |
289 | | |
290 | | // Data segment binary format: |
291 | | // ---------------------------------------- |
292 | | // Mode | MemoryIdx | OffExpr | vec(byte) |
293 | | // ------|-----------|---------|----------- |
294 | | // 0 | | v | v |
295 | | // 1 | | | v |
296 | | // 2 | v | v | v |
297 | | // ---------------------------------------- |
298 | | // Mode: data initial integer, u32 |
299 | | // MemoryIdx: target memory index, u32 |
300 | | // OffExpr: init offset expression, expr |
301 | | // vec(byte): init data, vec(u8) |
302 | | |
303 | | // Read the checking byte. |
304 | 6.70k | EXPECTED_TRY(uint32_t Check, FMgr.readU32().map_error(ReportError)); |
305 | | // Check > 0 cases are for BulkMemoryOperations or ReferenceTypes proposal. |
306 | 6.68k | if (Check > 0 && !Conf.hasProposal(Proposal::BulkMemoryOperations) && |
307 | 0 | !Conf.hasProposal(Proposal::ReferenceTypes)) { |
308 | 0 | return logNeedProposal(ErrCode::Value::ExpectedZeroByte, |
309 | 0 | Proposal::BulkMemoryOperations, FMgr.getLastOffset(), |
310 | 0 | ASTNodeAttr::Seg_Data); |
311 | 0 | } |
312 | | |
313 | 6.68k | switch (Check) { |
314 | 1.01k | case 0x02: // 0x02 memidx expr vec(byte) , Active |
315 | | // Read target memory index. |
316 | 1.01k | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto Idx) { |
317 | 1.01k | DataSeg.setIdx(Idx); |
318 | 1.01k | })); |
319 | 1.01k | [[fallthrough]]; |
320 | | |
321 | 4.57k | case 0x00: // 0x00 expr vec(byte) , Active |
322 | | // Read the offset expression. |
323 | 4.57k | EXPECTED_TRY(loadExpression(DataSeg.getExpr()).map_error([](auto E) { |
324 | 2.33k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Data)); |
325 | 2.33k | return E; |
326 | 2.33k | })); |
327 | 2.33k | DataSeg.setMode(AST::DataSegment::DataMode::Active); |
328 | 2.33k | [[fallthrough]]; |
329 | | |
330 | 4.35k | case 0x01: // 0x01 vec(byte) , Passive |
331 | 4.35k | { |
332 | | // Read initialization data. |
333 | 4.35k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
334 | 4.26k | EXPECTED_TRY(FMgr.readBytes(VecCnt).map_error(ReportError).map([&](auto V) { |
335 | 4.25k | DataSeg.getData() = std::move(V); |
336 | 4.25k | })); |
337 | 4.25k | break; |
338 | 4.26k | } |
339 | 4.25k | default: |
340 | | // TODO: Correct the error code once there's spec test. |
341 | 101 | return logLoadError(ErrCode::Value::IllegalGrammar, FMgr.getLastOffset(), |
342 | 101 | ASTNodeAttr::Seg_Data); |
343 | 6.68k | } |
344 | 4.25k | return {}; |
345 | 6.68k | } |
346 | | |
347 | | } // namespace Loader |
348 | | } // namespace WasmEdge |