/src/WasmEdge/lib/loader/ast/segment.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: 2019-2024 Second State INC |
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 | 501 | Expect<void> Loader::loadSegment(AST::TableSegment &TabSeg) { |
11 | | // Check the first byte is the reftype in table type or not. |
12 | 501 | EXPECTED_TRY(uint8_t CheckByte, FMgr.peekByte().map_error([this](auto E) { |
13 | 494 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Table); |
14 | 494 | })); |
15 | | |
16 | 494 | if (CheckByte == 0x40U) { |
17 | | // Table segment case is for FunctionReferences proposal. |
18 | 1 | if (!Conf.hasProposal(Proposal::FunctionReferences)) { |
19 | 1 | return logNeedProposal(ErrCode::Value::MalformedTable, |
20 | 1 | Proposal::FunctionReferences, FMgr.getLastOffset(), |
21 | 1 | ASTNodeAttr::Seg_Table); |
22 | 1 | } |
23 | 0 | FMgr.readByte(); |
24 | | |
25 | | // Check the second byte. |
26 | 0 | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error([this](auto E) { |
27 | 0 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Table); |
28 | 0 | })); |
29 | 0 | if (B != 0x00U) { |
30 | 0 | return logLoadError(ErrCode::Value::MalformedTable, FMgr.getLastOffset(), |
31 | 0 | ASTNodeAttr::Seg_Table); |
32 | 0 | } |
33 | | |
34 | | // Read the table type. |
35 | 0 | EXPECTED_TRY(loadType(TabSeg.getTableType()).map_error([](auto E) { |
36 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
37 | 0 | return E; |
38 | 0 | })); |
39 | | |
40 | | // Read the expression. |
41 | 0 | EXPECTED_TRY(loadExpression(TabSeg.getExpr()).map_error([](auto E) { |
42 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
43 | 0 | return E; |
44 | 0 | })); |
45 | 493 | } else { |
46 | | // The table type case. |
47 | 493 | EXPECTED_TRY(loadType(TabSeg.getTableType()).map_error([](auto E) { |
48 | 493 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
49 | 493 | return E; |
50 | 493 | })); |
51 | 493 | } |
52 | | |
53 | 458 | return {}; |
54 | 494 | } |
55 | | |
56 | | // Load binary of GlobalSegment node. See "include/loader/loader.h". |
57 | 738 | Expect<void> Loader::loadSegment(AST::GlobalSegment &GlobSeg) { |
58 | 738 | return Expect<void>{} |
59 | 738 | .and_then([this, &GlobSeg]() { |
60 | | // Read global type node. |
61 | 738 | return loadType(GlobSeg.getGlobalType()); |
62 | 738 | }) |
63 | 738 | .and_then([this, &GlobSeg]() { |
64 | | // Read the expression. |
65 | 710 | return loadExpression(GlobSeg.getExpr()); |
66 | 710 | }) |
67 | 738 | .map_error([](auto E) { |
68 | 280 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Global)); |
69 | 280 | return E; |
70 | 280 | }); |
71 | 738 | } |
72 | | |
73 | | // Load binary of ElementSegment node. See "include/loader/loader.h". |
74 | 5.73k | Expect<void> Loader::loadSegment(AST::ElementSegment &ElemSeg) { |
75 | 5.73k | auto ReportError = [this](auto E) { |
76 | 70 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Element); |
77 | 70 | }; |
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 | 5.73k | uint32_t Check = 0; |
102 | 5.73k | if (unlikely(!Conf.hasProposal(Proposal::BulkMemoryOperations) && |
103 | 5.73k | !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 | 5.73k | } else { |
110 | 5.73k | EXPECTED_TRY(Check, FMgr.readU32().map_error(ReportError)); |
111 | 5.72k | } |
112 | | |
113 | | // Check the prefix byte. |
114 | 5.72k | switch (Check) { |
115 | 2.39k | case 0x00: |
116 | 3.35k | case 0x02: |
117 | 4.39k | case 0x04: |
118 | 4.54k | case 0x06: |
119 | 4.54k | ElemSeg.setMode(AST::ElementSegment::ElemMode::Active); |
120 | 4.54k | break; |
121 | | |
122 | 760 | case 0x01: |
123 | 834 | case 0x05: |
124 | 834 | ElemSeg.setMode(AST::ElementSegment::ElemMode::Passive); |
125 | 834 | break; |
126 | | |
127 | 201 | case 0x03: |
128 | 307 | case 0x07: |
129 | 307 | ElemSeg.setMode(AST::ElementSegment::ElemMode::Declarative); |
130 | 307 | break; |
131 | | |
132 | 40 | default: |
133 | | // TODO: Correctness the error code once there's spec test. |
134 | 40 | return logLoadError(ErrCode::Value::IllegalGrammar, FMgr.getLastOffset(), |
135 | 40 | ASTNodeAttr::Seg_Element); |
136 | 5.72k | } |
137 | | |
138 | | // Read the table index. |
139 | 5.68k | ElemSeg.setIdx(0); |
140 | 5.68k | switch (Check) { |
141 | 955 | case 0x02: |
142 | 1.10k | case 0x06: |
143 | 1.10k | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto Idx) { |
144 | 1.09k | ElemSeg.setIdx(Idx); |
145 | 1.09k | })); |
146 | 1.09k | break; |
147 | | |
148 | 4.57k | default: |
149 | 4.57k | break; |
150 | 5.68k | } |
151 | | |
152 | | // Read the expression. |
153 | 5.67k | switch (Check) { |
154 | 2.39k | case 0x00: |
155 | 3.35k | case 0x02: |
156 | 4.39k | case 0x04: |
157 | 4.53k | case 0x06: |
158 | 4.53k | EXPECTED_TRY(loadExpression(ElemSeg.getExpr()).map_error([](auto E) { |
159 | 3.70k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); |
160 | 3.70k | return E; |
161 | 3.70k | })); |
162 | 3.70k | break; |
163 | | |
164 | 3.70k | default: |
165 | 1.14k | break; |
166 | 5.67k | } |
167 | | |
168 | | // Read element kind and init function indices. |
169 | 4.84k | switch (Check) { |
170 | 760 | case 0x01: |
171 | 1.69k | case 0x02: |
172 | 1.89k | case 0x03: |
173 | 1.89k | EXPECTED_TRY(FMgr.readByte() |
174 | 1.88k | .and_then([&](auto B) -> Expect<void> { |
175 | 1.88k | if (B != 0x00U) { |
176 | 1.88k | return Unexpect(ErrCode::Value::ExpectedZeroByte); |
177 | 1.88k | }; |
178 | 1.88k | return {}; |
179 | 1.88k | }) |
180 | 1.88k | .map_error(ReportError)); |
181 | 1.88k | [[fallthrough]]; |
182 | | |
183 | 3.71k | case 0x00: { |
184 | 3.71k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
185 | 14.8k | for (uint32_t I = 0; I < VecCnt; ++I) { |
186 | | // For each element in vec(funcidx), make expr(ref.func idx end). |
187 | 11.1k | ElemSeg.getInitExprs().emplace_back(); |
188 | 11.1k | AST::Instruction RefFunc(OpCode::Ref__func); |
189 | 11.1k | AST::Instruction End(OpCode::End); |
190 | 11.1k | EXPECTED_TRY(loadInstruction(RefFunc).map_error([](auto E) { |
191 | 11.1k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); |
192 | 11.1k | return E; |
193 | 11.1k | })); |
194 | 11.1k | ElemSeg.getInitExprs().back().getInstrs().emplace_back( |
195 | 11.1k | std::move(RefFunc)); |
196 | 11.1k | ElemSeg.getInitExprs().back().getInstrs().emplace_back(std::move(End)); |
197 | 11.1k | } |
198 | 3.65k | break; |
199 | 3.66k | } |
200 | 3.65k | default: |
201 | 1.11k | break; |
202 | 4.84k | } |
203 | | |
204 | | // Set the default reference type. |
205 | 4.77k | if (Check == 0x04) { |
206 | 828 | ElemSeg.setRefType(TypeCode::FuncRef); |
207 | 3.94k | } else { |
208 | 3.94k | ElemSeg.setRefType(ValType(TypeCode::Ref, TypeCode::FuncRef)); |
209 | 3.94k | } |
210 | | |
211 | | // Read the reference type and init expressions. |
212 | 4.77k | switch (Check) { |
213 | 74 | case 0x05: |
214 | 184 | case 0x06: |
215 | 290 | case 0x07: { |
216 | | // The AST node information is handled. |
217 | 290 | EXPECTED_TRY(auto Type, loadRefType(ASTNodeAttr::Seg_Element)); |
218 | 283 | ElemSeg.setRefType(Type); |
219 | 283 | [[fallthrough]]; |
220 | 283 | } |
221 | 1.11k | case 0x04: { |
222 | 1.11k | return loadVec<AST::ElementSegment>( |
223 | 2.99k | ElemSeg.getInitExprs(), [this](AST::Expression &Expr) -> Expect<void> { |
224 | 2.99k | return loadExpression(Expr); |
225 | 2.99k | }); |
226 | 283 | } |
227 | | |
228 | 3.65k | default: |
229 | 3.65k | break; |
230 | 4.77k | } |
231 | | |
232 | 3.65k | return {}; |
233 | 4.77k | } |
234 | | |
235 | | // Load binary of CodeSegment node. See "include/loader/loader.h". |
236 | 17.5k | Expect<void> Loader::loadSegment(AST::CodeSegment &CodeSeg) { |
237 | 17.5k | auto ReportError = [this](auto E) { |
238 | 26 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Code); |
239 | 26 | }; |
240 | | |
241 | | // Read the code segment size. |
242 | 17.5k | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto S) { |
243 | 17.5k | CodeSeg.setSegSize(S); |
244 | 17.5k | })); |
245 | 17.5k | auto ExprSizeBound = FMgr.getOffset() + CodeSeg.getSegSize(); |
246 | | |
247 | | // Read the vector of local variable counts and types. |
248 | 17.5k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
249 | 17.5k | CodeSeg.getLocals().clear(); |
250 | 17.5k | CodeSeg.getLocals().reserve(VecCnt); |
251 | 17.5k | uint32_t TotalLocalCnt = 0; |
252 | 19.9k | for (uint32_t I = 0; I < VecCnt; ++I) { |
253 | 2.39k | EXPECTED_TRY(uint32_t LocalCnt, FMgr.readU32().map_error(ReportError)); |
254 | | // Total local variables should not more than 2^32. Capped at 2^26. |
255 | 2.39k | if (UINT32_C(67108864) - TotalLocalCnt < LocalCnt) { |
256 | 7 | return logLoadError(ErrCode::Value::TooManyLocals, FMgr.getLastOffset(), |
257 | 7 | ASTNodeAttr::Seg_Code); |
258 | 7 | } |
259 | 2.38k | TotalLocalCnt += LocalCnt; |
260 | | // Read the value type. |
261 | | // The AST node information is handled. |
262 | 2.38k | EXPECTED_TRY(ValType LocalType, loadValType(ASTNodeAttr::Seg_Code)); |
263 | 2.35k | CodeSeg.getLocals().push_back(std::make_pair(LocalCnt, LocalType)); |
264 | 2.35k | } |
265 | | |
266 | 17.5k | if (!Conf.getRuntimeConfigure().isForceInterpreter() && |
267 | 17.5k | WASMType != InputType::WASM) { |
268 | | // For the AOT mode and not force interpreter in configure, skip the |
269 | | // function body. |
270 | 0 | FMgr.seek(ExprSizeBound); |
271 | 17.5k | } else { |
272 | | // Read function body with expected expression size. |
273 | 17.5k | EXPECTED_TRY( |
274 | 17.5k | loadExpression(CodeSeg.getExpr(), ExprSizeBound).map_error([](auto E) { |
275 | 17.5k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Code)); |
276 | 17.5k | return E; |
277 | 17.5k | })); |
278 | 17.5k | } |
279 | | |
280 | 16.7k | return {}; |
281 | 17.5k | } |
282 | | |
283 | | // Load binary of DataSegment node. See "include/loader/loader.h". |
284 | 4.15k | Expect<void> Loader::loadSegment(AST::DataSegment &DataSeg) { |
285 | 4.15k | auto ReportError = [this](auto E) { |
286 | 27 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Data); |
287 | 27 | }; |
288 | 4.15k | DataSeg.setMode(AST::DataSegment::DataMode::Passive); |
289 | 4.15k | DataSeg.setIdx(0); |
290 | | |
291 | | // Data segment binary format: |
292 | | // ---------------------------------------- |
293 | | // Mode | MemoryIdx | OffExpr | vec(byte) |
294 | | // ------|-----------|---------|----------- |
295 | | // 0 | | v | v |
296 | | // 1 | | | v |
297 | | // 2 | v | v | v |
298 | | // ---------------------------------------- |
299 | | // Mode: data initial integer, u32 |
300 | | // MemoryIdx: target memory index, u32 |
301 | | // OffExpr: init offset expression, expr |
302 | | // vec(byte): init data, vec(u8) |
303 | | |
304 | | // Read the checking byte. |
305 | 4.15k | EXPECTED_TRY(uint32_t Check, FMgr.readU32().map_error(ReportError)); |
306 | | // Check > 0 cases are for BulkMemoryOperations or ReferenceTypes proposal. |
307 | 4.14k | if (Check > 0 && !Conf.hasProposal(Proposal::BulkMemoryOperations) && |
308 | 4.14k | !Conf.hasProposal(Proposal::ReferenceTypes)) { |
309 | 0 | return logNeedProposal(ErrCode::Value::ExpectedZeroByte, |
310 | 0 | Proposal::BulkMemoryOperations, FMgr.getLastOffset(), |
311 | 0 | ASTNodeAttr::Seg_Data); |
312 | 0 | } |
313 | | |
314 | 4.14k | switch (Check) { |
315 | 842 | case 0x02: // 0x02 memidx expr vec(byte) , Active |
316 | | // Read target memory index. |
317 | 842 | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto Idx) { |
318 | 840 | DataSeg.setIdx(Idx); |
319 | 840 | })); |
320 | 840 | [[fallthrough]]; |
321 | | |
322 | 2.96k | case 0x00: // 0x00 expr vec(byte) , Active |
323 | | // Read the offset expression. |
324 | 2.96k | EXPECTED_TRY(loadExpression(DataSeg.getExpr()).map_error([](auto E) { |
325 | 1.73k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Data)); |
326 | 1.73k | return E; |
327 | 1.73k | })); |
328 | 1.73k | DataSeg.setMode(AST::DataSegment::DataMode::Active); |
329 | 1.73k | [[fallthrough]]; |
330 | | |
331 | 2.88k | case 0x01: // 0x01 vec(byte) , Passive |
332 | 2.88k | { |
333 | | // Read initialization data. |
334 | 2.88k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
335 | 2.87k | EXPECTED_TRY(FMgr.readBytes(VecCnt).map_error(ReportError).map([&](auto V) { |
336 | 2.86k | DataSeg.getData() = std::move(V); |
337 | 2.86k | })); |
338 | 2.86k | break; |
339 | 2.87k | } |
340 | 2.86k | default: |
341 | | // TODO: Correctness the error code once there's spec test. |
342 | 30 | return logLoadError(ErrCode::Value::IllegalGrammar, FMgr.getLastOffset(), |
343 | 30 | ASTNodeAttr::Seg_Data); |
344 | 4.14k | } |
345 | 2.86k | return {}; |
346 | 4.14k | } |
347 | | |
348 | | } // namespace Loader |
349 | | } // namespace WasmEdge |