/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 | 8.30k | Expect<void> Loader::loadSegment(AST::TableSegment &TabSeg) { |
11 | | // Check whether the first byte is the reftype in table type. |
12 | 8.30k | EXPECTED_TRY(uint8_t CheckByte, FMgr.peekByte().map_error([this](auto E) { |
13 | 8.28k | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Table); |
14 | 8.28k | })); |
15 | | |
16 | 8.28k | if (CheckByte == 0x40U) { |
17 | | // Table segment case is for FunctionReferences proposal. |
18 | 798 | 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 | 798 | FMgr.readByte(); |
24 | | |
25 | | // Check the second byte. |
26 | 798 | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error([this](auto E) { |
27 | 792 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Table); |
28 | 792 | })); |
29 | 792 | if (B != 0x00U) { |
30 | 6 | return logLoadError(ErrCode::Value::MalformedTable, FMgr.getLastOffset(), |
31 | 6 | ASTNodeAttr::Seg_Table); |
32 | 6 | } |
33 | | |
34 | | // Read the table type. |
35 | 786 | EXPECTED_TRY(loadType(TabSeg.getTableType()).map_error([](auto E) { |
36 | 780 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
37 | 780 | return E; |
38 | 780 | })); |
39 | | |
40 | | // Read the expression. |
41 | 780 | EXPECTED_TRY(loadExpression(TabSeg.getExpr()).map_error([](auto E) { |
42 | 780 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
43 | 780 | return E; |
44 | 780 | })); |
45 | 7.48k | } else { |
46 | | // The table type case. |
47 | 7.48k | EXPECTED_TRY(loadType(TabSeg.getTableType()).map_error([](auto E) { |
48 | 7.48k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
49 | 7.48k | return E; |
50 | 7.48k | })); |
51 | 7.48k | } |
52 | | |
53 | 8.10k | return {}; |
54 | 8.28k | } |
55 | | |
56 | | // Load binary of GlobalSegment node. See "include/loader/loader.h". |
57 | 4.72k | Expect<void> Loader::loadSegment(AST::GlobalSegment &GlobSeg) { |
58 | 4.72k | return Expect<void>{} |
59 | 4.72k | .and_then([this, &GlobSeg]() { |
60 | | // Read global type node. |
61 | 4.72k | return loadType(GlobSeg.getGlobalType()); |
62 | 4.72k | }) |
63 | 4.72k | .and_then([this, &GlobSeg]() { |
64 | | // Read the expression. |
65 | 4.59k | return loadExpression(GlobSeg.getExpr()); |
66 | 4.59k | }) |
67 | 4.72k | .map_error([](auto E) { |
68 | 998 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Global)); |
69 | 998 | return E; |
70 | 998 | }); |
71 | 4.72k | } |
72 | | |
73 | | // Load binary of ElementSegment node. See "include/loader/loader.h". |
74 | 16.8k | Expect<void> Loader::loadSegment(AST::ElementSegment &ElemSeg) { |
75 | 16.8k | auto ReportError = [this](auto E) { |
76 | 143 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Element); |
77 | 143 | }; |
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 | 16.8k | uint32_t Check = 0; |
102 | 16.8k | if (unlikely(!Conf.hasProposal(Proposal::BulkMemoryOperations) && |
103 | 16.8k | !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 | 16.8k | } else { |
110 | 16.8k | EXPECTED_TRY(Check, FMgr.readU32().map_error(ReportError)); |
111 | 16.8k | } |
112 | | |
113 | | // Check the prefix byte. |
114 | 16.8k | switch (Check) { |
115 | 6.49k | case 0x00: |
116 | 9.34k | case 0x02: |
117 | 11.5k | case 0x04: |
118 | 12.2k | case 0x06: |
119 | 12.2k | ElemSeg.setMode(AST::ElementSegment::ElemMode::Active); |
120 | 12.2k | break; |
121 | | |
122 | 815 | case 0x01: |
123 | 2.88k | case 0x05: |
124 | 2.88k | ElemSeg.setMode(AST::ElementSegment::ElemMode::Passive); |
125 | 2.88k | break; |
126 | | |
127 | 1.29k | case 0x03: |
128 | 1.60k | case 0x07: |
129 | 1.60k | ElemSeg.setMode(AST::ElementSegment::ElemMode::Declarative); |
130 | 1.60k | break; |
131 | | |
132 | 96 | default: |
133 | | // TODO: Correct the error code once there's spec test. |
134 | 96 | return logLoadError(ErrCode::Value::IllegalGrammar, FMgr.getLastOffset(), |
135 | 96 | ASTNodeAttr::Seg_Element); |
136 | 16.8k | } |
137 | | |
138 | | // Read the table index. |
139 | 16.7k | ElemSeg.setIdx(0); |
140 | 16.7k | switch (Check) { |
141 | 2.84k | case 0x02: |
142 | 3.51k | case 0x06: |
143 | 3.51k | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto Idx) { |
144 | 3.50k | ElemSeg.setIdx(Idx); |
145 | 3.50k | })); |
146 | 3.50k | break; |
147 | | |
148 | 13.2k | default: |
149 | 13.2k | break; |
150 | 16.7k | } |
151 | | |
152 | | // Read the expression. |
153 | 16.7k | switch (Check) { |
154 | 6.49k | case 0x00: |
155 | 9.34k | case 0x02: |
156 | 11.5k | case 0x04: |
157 | 12.2k | case 0x06: |
158 | 12.2k | EXPECTED_TRY(loadExpression(ElemSeg.getExpr()).map_error([](auto E) { |
159 | 9.15k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); |
160 | 9.15k | return E; |
161 | 9.15k | })); |
162 | 9.15k | break; |
163 | | |
164 | 9.15k | default: |
165 | 4.48k | break; |
166 | 16.7k | } |
167 | | |
168 | | // Read element kind and init function indices. |
169 | 13.6k | switch (Check) { |
170 | 815 | case 0x01: |
171 | 3.60k | case 0x02: |
172 | 4.89k | case 0x03: |
173 | 4.89k | EXPECTED_TRY(FMgr.readByte() |
174 | 4.86k | .and_then([&](auto B) -> Expect<void> { |
175 | 4.86k | if (B != 0x00U) { |
176 | 4.86k | return Unexpect(ErrCode::Value::ExpectedZeroByte); |
177 | 4.86k | }; |
178 | 4.86k | return {}; |
179 | 4.86k | }) |
180 | 4.86k | .map_error(ReportError)); |
181 | 4.86k | [[fallthrough]]; |
182 | | |
183 | 8.78k | case 0x00: { |
184 | 8.78k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
185 | 548k | for (uint32_t I = 0; I < VecCnt; ++I) { |
186 | | // For each element in vec(funcidx), make expr(ref.func idx end). |
187 | 540k | ElemSeg.getInitExprs().emplace_back(); |
188 | 540k | AST::Instruction RefFunc(OpCode::Ref__func); |
189 | 540k | AST::Instruction End(OpCode::End); |
190 | 540k | EXPECTED_TRY(loadInstruction(RefFunc).map_error([](auto E) { |
191 | 540k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); |
192 | 540k | return E; |
193 | 540k | })); |
194 | 540k | ElemSeg.getInitExprs().back().getInstrs().emplace_back( |
195 | 540k | std::move(RefFunc)); |
196 | 540k | ElemSeg.getInitExprs().back().getInstrs().emplace_back(std::move(End)); |
197 | 540k | } |
198 | 8.64k | break; |
199 | 8.71k | } |
200 | 8.64k | default: |
201 | 4.83k | break; |
202 | 13.6k | } |
203 | | |
204 | | // Set the default reference type. |
205 | 13.4k | if (Check == 0x04) { |
206 | 1.84k | ElemSeg.setRefType(TypeCode::FuncRef); |
207 | 11.6k | } else { |
208 | 11.6k | ElemSeg.setRefType(ValType(TypeCode::Ref, TypeCode::FuncRef)); |
209 | 11.6k | } |
210 | | |
211 | | // Read the reference type and init expressions. |
212 | 13.4k | switch (Check) { |
213 | 2.06k | case 0x05: |
214 | 2.67k | case 0x06: |
215 | 2.98k | case 0x07: { |
216 | | // The AST node information is handled. |
217 | 2.98k | EXPECTED_TRY(auto Type, loadRefType(ASTNodeAttr::Seg_Element)); |
218 | 2.97k | ElemSeg.setRefType(Type); |
219 | 2.97k | [[fallthrough]]; |
220 | 2.97k | } |
221 | 4.82k | case 0x04: { |
222 | 4.82k | return loadVec<AST::ElementSegment>( |
223 | 5.41k | ElemSeg.getInitExprs(), [this](AST::Expression &Expr) -> Expect<void> { |
224 | 5.41k | return loadExpression(Expr); |
225 | 5.41k | }); |
226 | 2.97k | } |
227 | | |
228 | 8.64k | default: |
229 | 8.64k | break; |
230 | 13.4k | } |
231 | | |
232 | 8.64k | return {}; |
233 | 13.4k | } |
234 | | |
235 | | // Load binary of CodeSegment node. See "include/loader/loader.h". |
236 | 31.9k | Expect<void> Loader::loadSegment(AST::CodeSegment &CodeSeg) { |
237 | 31.9k | auto ReportError = [this](auto E) { |
238 | 93 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Code); |
239 | 93 | }; |
240 | | |
241 | | // Read the code segment size. |
242 | 31.9k | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto S) { |
243 | 31.9k | CodeSeg.setSegSize(S); |
244 | 31.9k | })); |
245 | 31.9k | auto ExprSizeBound = FMgr.getOffset() + CodeSeg.getSegSize(); |
246 | | |
247 | | // Read the vector of local variable counts and types. |
248 | 31.9k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
249 | 31.9k | CodeSeg.getLocals().clear(); |
250 | 31.9k | CodeSeg.getLocals().reserve(VecCnt); |
251 | 31.9k | uint32_t TotalLocalCnt = 0; |
252 | 64.2k | for (uint32_t I = 0; I < VecCnt; ++I) { |
253 | 32.5k | EXPECTED_TRY(uint32_t LocalCnt, FMgr.readU32().map_error(ReportError)); |
254 | | // Total local variables should not exceed 2^32. Capped at 2^26. |
255 | 32.4k | if (UINT32_C(67108864) - TotalLocalCnt < LocalCnt) { |
256 | 22 | return logLoadError(ErrCode::Value::TooManyLocals, FMgr.getLastOffset(), |
257 | 22 | ASTNodeAttr::Seg_Code); |
258 | 22 | } |
259 | 32.4k | TotalLocalCnt += LocalCnt; |
260 | | // Read the value type. |
261 | | // The AST node information is handled. |
262 | 32.4k | EXPECTED_TRY(ValType LocalType, loadValType(ASTNodeAttr::Seg_Code)); |
263 | 32.3k | CodeSeg.getLocals().push_back(std::make_pair(LocalCnt, LocalType)); |
264 | 32.3k | } |
265 | | |
266 | 31.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 | 31.7k | } else { |
271 | | // Read function body with expected expression size. |
272 | 31.7k | EXPECTED_TRY( |
273 | 31.7k | loadExpression(CodeSeg.getExpr(), ExprSizeBound).map_error([](auto E) { |
274 | 31.7k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Code)); |
275 | 31.7k | return E; |
276 | 31.7k | })); |
277 | 31.7k | } |
278 | | |
279 | 30.0k | return {}; |
280 | 31.7k | } |
281 | | |
282 | | // Load binary of DataSegment node. See "include/loader/loader.h". |
283 | 10.5k | Expect<void> Loader::loadSegment(AST::DataSegment &DataSeg) { |
284 | 10.5k | auto ReportError = [this](auto E) { |
285 | 95 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Data); |
286 | 95 | }; |
287 | 10.5k | DataSeg.setMode(AST::DataSegment::DataMode::Passive); |
288 | 10.5k | 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 | 10.5k | EXPECTED_TRY(uint32_t Check, FMgr.readU32().map_error(ReportError)); |
305 | | // Check > 0 cases are for BulkMemoryOperations or ReferenceTypes proposal. |
306 | 10.5k | 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 | 10.5k | switch (Check) { |
314 | 942 | case 0x02: // 0x02 memidx expr vec(byte) , Active |
315 | | // Read target memory index. |
316 | 942 | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto Idx) { |
317 | 937 | DataSeg.setIdx(Idx); |
318 | 937 | })); |
319 | 937 | [[fallthrough]]; |
320 | | |
321 | 4.97k | case 0x00: // 0x00 expr vec(byte) , Active |
322 | | // Read the offset expression. |
323 | 4.97k | EXPECTED_TRY(loadExpression(DataSeg.getExpr()).map_error([](auto E) { |
324 | 2.34k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Data)); |
325 | 2.34k | return E; |
326 | 2.34k | })); |
327 | 2.34k | DataSeg.setMode(AST::DataSegment::DataMode::Active); |
328 | 2.34k | [[fallthrough]]; |
329 | | |
330 | 7.82k | case 0x01: // 0x01 vec(byte) , Passive |
331 | 7.82k | { |
332 | | // Read initialization data. |
333 | 7.82k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
334 | 7.75k | EXPECTED_TRY(FMgr.readBytes(VecCnt).map_error(ReportError).map([&](auto V) { |
335 | 7.75k | DataSeg.getData() = std::move(V); |
336 | 7.75k | })); |
337 | 7.75k | break; |
338 | 7.75k | } |
339 | 7.75k | default: |
340 | | // TODO: Correct the error code once there's spec test. |
341 | 102 | return logLoadError(ErrCode::Value::IllegalGrammar, FMgr.getLastOffset(), |
342 | 102 | ASTNodeAttr::Seg_Data); |
343 | 10.5k | } |
344 | 7.75k | return {}; |
345 | 10.5k | } |
346 | | |
347 | | } // namespace Loader |
348 | | } // namespace WasmEdge |