/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 | 580 | Expect<void> Loader::loadSegment(AST::TableSegment &TabSeg) { |
11 | | // Check the first byte is the reftype in table type or not. |
12 | 580 | EXPECTED_TRY(uint8_t CheckByte, FMgr.peekByte().map_error([this](auto E) { |
13 | 573 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Table); |
14 | 573 | })); |
15 | | |
16 | 573 | if (CheckByte == 0x40U) { |
17 | | // Table segment case is for FunctionReferences proposal. |
18 | 2 | if (!Conf.hasProposal(Proposal::FunctionReferences)) { |
19 | 2 | return logNeedProposal(ErrCode::Value::MalformedTable, |
20 | 2 | Proposal::FunctionReferences, FMgr.getLastOffset(), |
21 | 2 | ASTNodeAttr::Seg_Table); |
22 | 2 | } |
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 | 571 | } else { |
46 | | // The table type case. |
47 | 571 | EXPECTED_TRY(loadType(TabSeg.getTableType()).map_error([](auto E) { |
48 | 571 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
49 | 571 | return E; |
50 | 571 | })); |
51 | 571 | } |
52 | | |
53 | 520 | return {}; |
54 | 573 | } |
55 | | |
56 | | // Load binary of GlobalSegment node. See "include/loader/loader.h". |
57 | 926 | Expect<void> Loader::loadSegment(AST::GlobalSegment &GlobSeg) { |
58 | 926 | return Expect<void>{} |
59 | 926 | .and_then([this, &GlobSeg]() { |
60 | | // Read global type node. |
61 | 926 | return loadType(GlobSeg.getGlobalType()); |
62 | 926 | }) |
63 | 926 | .and_then([this, &GlobSeg]() { |
64 | | // Read the expression. |
65 | 885 | return loadExpression(GlobSeg.getExpr()); |
66 | 885 | }) |
67 | 926 | .map_error([](auto E) { |
68 | 429 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Global)); |
69 | 429 | return E; |
70 | 429 | }); |
71 | 926 | } |
72 | | |
73 | | // Load binary of ElementSegment node. See "include/loader/loader.h". |
74 | 6.27k | Expect<void> Loader::loadSegment(AST::ElementSegment &ElemSeg) { |
75 | 6.27k | auto ReportError = [this](auto E) { |
76 | 78 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Element); |
77 | 78 | }; |
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 | 6.27k | uint32_t Check = 0; |
102 | 6.27k | if (unlikely(!Conf.hasProposal(Proposal::BulkMemoryOperations) && |
103 | 6.27k | !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 | 6.27k | } else { |
110 | 6.27k | EXPECTED_TRY(Check, FMgr.readU32().map_error(ReportError)); |
111 | 6.26k | } |
112 | | |
113 | | // Check the prefix byte. |
114 | 6.26k | switch (Check) { |
115 | 2.68k | case 0x00: |
116 | 3.65k | case 0x02: |
117 | 4.75k | case 0x04: |
118 | 4.88k | case 0x06: |
119 | 4.88k | ElemSeg.setMode(AST::ElementSegment::ElemMode::Active); |
120 | 4.88k | break; |
121 | | |
122 | 899 | case 0x01: |
123 | 999 | case 0x05: |
124 | 999 | ElemSeg.setMode(AST::ElementSegment::ElemMode::Passive); |
125 | 999 | break; |
126 | | |
127 | 218 | case 0x03: |
128 | 336 | case 0x07: |
129 | 336 | ElemSeg.setMode(AST::ElementSegment::ElemMode::Declarative); |
130 | 336 | break; |
131 | | |
132 | 41 | default: |
133 | | // TODO: Correctness the error code once there's spec test. |
134 | 41 | return logLoadError(ErrCode::Value::IllegalGrammar, FMgr.getLastOffset(), |
135 | 41 | ASTNodeAttr::Seg_Element); |
136 | 6.26k | } |
137 | | |
138 | | // Read the table index. |
139 | 6.21k | ElemSeg.setIdx(0); |
140 | 6.21k | switch (Check) { |
141 | 969 | case 0x02: |
142 | 1.09k | case 0x06: |
143 | 1.09k | 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 | 5.12k | default: |
149 | 5.12k | break; |
150 | 6.21k | } |
151 | | |
152 | | // Read the expression. |
153 | 6.21k | switch (Check) { |
154 | 2.68k | case 0x00: |
155 | 3.64k | case 0x02: |
156 | 4.75k | case 0x04: |
157 | 4.87k | case 0x06: |
158 | 4.87k | EXPECTED_TRY(loadExpression(ElemSeg.getExpr()).map_error([](auto E) { |
159 | 3.97k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); |
160 | 3.97k | return E; |
161 | 3.97k | })); |
162 | 3.97k | break; |
163 | | |
164 | 3.97k | default: |
165 | 1.33k | break; |
166 | 6.21k | } |
167 | | |
168 | | // Read element kind and init function indices. |
169 | 5.30k | switch (Check) { |
170 | 899 | case 0x01: |
171 | 1.84k | case 0x02: |
172 | 2.06k | case 0x03: |
173 | 2.06k | EXPECTED_TRY(FMgr.readByte() |
174 | 2.04k | .and_then([&](auto B) -> Expect<void> { |
175 | 2.04k | if (B != 0x00U) { |
176 | 2.04k | return Unexpect(ErrCode::Value::ExpectedZeroByte); |
177 | 2.04k | }; |
178 | 2.04k | return {}; |
179 | 2.04k | }) |
180 | 2.04k | .map_error(ReportError)); |
181 | 2.04k | [[fallthrough]]; |
182 | | |
183 | 4.09k | case 0x00: { |
184 | 4.09k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
185 | 14.6k | for (uint32_t I = 0; I < VecCnt; ++I) { |
186 | | // For each element in vec(funcidx), make expr(ref.func idx end). |
187 | 10.6k | ElemSeg.getInitExprs().emplace_back(); |
188 | 10.6k | AST::Instruction RefFunc(OpCode::Ref__func); |
189 | 10.6k | AST::Instruction End(OpCode::End); |
190 | 10.6k | EXPECTED_TRY(loadInstruction(RefFunc).map_error([](auto E) { |
191 | 10.6k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); |
192 | 10.6k | return E; |
193 | 10.6k | })); |
194 | 10.6k | ElemSeg.getInitExprs().back().getInstrs().emplace_back( |
195 | 10.6k | std::move(RefFunc)); |
196 | 10.6k | ElemSeg.getInitExprs().back().getInstrs().emplace_back(std::move(End)); |
197 | 10.6k | } |
198 | 4.02k | break; |
199 | 4.04k | } |
200 | 4.02k | default: |
201 | 1.20k | break; |
202 | 5.30k | } |
203 | | |
204 | | // Set the default reference type. |
205 | 5.22k | if (Check == 0x04) { |
206 | 892 | ElemSeg.setRefType(TypeCode::FuncRef); |
207 | 4.33k | } else { |
208 | 4.33k | ElemSeg.setRefType(ValType(TypeCode::Ref, TypeCode::FuncRef)); |
209 | 4.33k | } |
210 | | |
211 | | // Read the reference type and init expressions. |
212 | 5.22k | switch (Check) { |
213 | 100 | case 0x05: |
214 | 191 | case 0x06: |
215 | 309 | case 0x07: { |
216 | | // The AST node information is handled. |
217 | 309 | EXPECTED_TRY(auto Type, loadRefType(ASTNodeAttr::Seg_Element)); |
218 | 296 | ElemSeg.setRefType(Type); |
219 | 296 | [[fallthrough]]; |
220 | 296 | } |
221 | 1.18k | case 0x04: { |
222 | 1.18k | return loadVec<AST::ElementSegment>( |
223 | 3.57k | ElemSeg.getInitExprs(), [this](AST::Expression &Expr) -> Expect<void> { |
224 | 3.57k | return loadExpression(Expr); |
225 | 3.57k | }); |
226 | 296 | } |
227 | | |
228 | 4.02k | default: |
229 | 4.02k | break; |
230 | 5.22k | } |
231 | | |
232 | 4.02k | return {}; |
233 | 5.22k | } |
234 | | |
235 | | // Load binary of CodeSegment node. See "include/loader/loader.h". |
236 | 22.4k | Expect<void> Loader::loadSegment(AST::CodeSegment &CodeSeg) { |
237 | 22.4k | auto ReportError = [this](auto E) { |
238 | 31 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Code); |
239 | 31 | }; |
240 | | |
241 | | // Read the code segment size. |
242 | 22.4k | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto S) { |
243 | 22.4k | CodeSeg.setSegSize(S); |
244 | 22.4k | })); |
245 | 22.4k | auto ExprSizeBound = FMgr.getOffset() + CodeSeg.getSegSize(); |
246 | | |
247 | | // Read the vector of local variable counts and types. |
248 | 22.4k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
249 | 22.3k | CodeSeg.getLocals().clear(); |
250 | 22.3k | CodeSeg.getLocals().reserve(VecCnt); |
251 | 22.3k | uint32_t TotalLocalCnt = 0; |
252 | 25.7k | for (uint32_t I = 0; I < VecCnt; ++I) { |
253 | 3.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 | 3.39k | if (UINT32_C(67108864) - TotalLocalCnt < LocalCnt) { |
256 | 9 | return logLoadError(ErrCode::Value::TooManyLocals, FMgr.getLastOffset(), |
257 | 9 | ASTNodeAttr::Seg_Code); |
258 | 9 | } |
259 | 3.38k | TotalLocalCnt += LocalCnt; |
260 | | // Read the value type. |
261 | | // The AST node information is handled. |
262 | 3.38k | EXPECTED_TRY(ValType LocalType, loadValType(ASTNodeAttr::Seg_Code)); |
263 | 3.33k | CodeSeg.getLocals().push_back(std::make_pair(LocalCnt, LocalType)); |
264 | 3.33k | } |
265 | | |
266 | 22.3k | if (!Conf.getRuntimeConfigure().isForceInterpreter() && |
267 | 22.3k | 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 | 22.3k | } else { |
272 | | // Read function body with expected expression size. |
273 | 22.3k | EXPECTED_TRY( |
274 | 22.3k | loadExpression(CodeSeg.getExpr(), ExprSizeBound).map_error([](auto E) { |
275 | 22.3k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Code)); |
276 | 22.3k | return E; |
277 | 22.3k | })); |
278 | 22.3k | } |
279 | | |
280 | 21.2k | return {}; |
281 | 22.3k | } |
282 | | |
283 | | // Load binary of DataSegment node. See "include/loader/loader.h". |
284 | 5.12k | Expect<void> Loader::loadSegment(AST::DataSegment &DataSeg) { |
285 | 5.12k | auto ReportError = [this](auto E) { |
286 | 31 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Data); |
287 | 31 | }; |
288 | 5.12k | DataSeg.setMode(AST::DataSegment::DataMode::Passive); |
289 | 5.12k | 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 | 5.12k | EXPECTED_TRY(uint32_t Check, FMgr.readU32().map_error(ReportError)); |
306 | | // Check > 0 cases are for BulkMemoryOperations or ReferenceTypes proposal. |
307 | 5.11k | if (Check > 0 && !Conf.hasProposal(Proposal::BulkMemoryOperations) && |
308 | 5.11k | !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 | 5.11k | switch (Check) { |
315 | 829 | case 0x02: // 0x02 memidx expr vec(byte) , Active |
316 | | // Read target memory index. |
317 | 829 | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto Idx) { |
318 | 825 | DataSeg.setIdx(Idx); |
319 | 825 | })); |
320 | 825 | [[fallthrough]]; |
321 | | |
322 | 3.08k | case 0x00: // 0x00 expr vec(byte) , Active |
323 | | // Read the offset expression. |
324 | 3.08k | EXPECTED_TRY(loadExpression(DataSeg.getExpr()).map_error([](auto E) { |
325 | 1.78k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Data)); |
326 | 1.78k | return E; |
327 | 1.78k | })); |
328 | 1.78k | DataSeg.setMode(AST::DataSegment::DataMode::Active); |
329 | 1.78k | [[fallthrough]]; |
330 | | |
331 | 3.77k | case 0x01: // 0x01 vec(byte) , Passive |
332 | 3.77k | { |
333 | | // Read initialization data. |
334 | 3.77k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
335 | 3.76k | EXPECTED_TRY(FMgr.readBytes(VecCnt).map_error(ReportError).map([&](auto V) { |
336 | 3.75k | DataSeg.getData() = std::move(V); |
337 | 3.75k | })); |
338 | 3.75k | break; |
339 | 3.76k | } |
340 | 3.75k | default: |
341 | | // TODO: Correctness the error code once there's spec test. |
342 | 37 | return logLoadError(ErrCode::Value::IllegalGrammar, FMgr.getLastOffset(), |
343 | 37 | ASTNodeAttr::Seg_Data); |
344 | 5.11k | } |
345 | 3.75k | return {}; |
346 | 5.11k | } |
347 | | |
348 | | } // namespace Loader |
349 | | } // namespace WasmEdge |