/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 | 1.44k | Expect<void> Loader::loadSegment(AST::TableSegment &TabSeg) { |
11 | | // Check whether the first byte is the reftype in table type. |
12 | 1.44k | EXPECTED_TRY(uint8_t CheckByte, FMgr.peekByte().map_error([this](auto E) { |
13 | 1.43k | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Table); |
14 | 1.43k | })); |
15 | | |
16 | 1.43k | if (CheckByte == 0x40U) { |
17 | | // Table segment case is for FunctionReferences proposal. |
18 | 88 | 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 | 88 | FMgr.readByte(); |
24 | | |
25 | | // Check the second byte. |
26 | 88 | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error([this](auto E) { |
27 | 87 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Table); |
28 | 87 | })); |
29 | 87 | if (B != 0x00U) { |
30 | 4 | return logLoadError(ErrCode::Value::MalformedTable, FMgr.getLastOffset(), |
31 | 4 | ASTNodeAttr::Seg_Table); |
32 | 4 | } |
33 | | |
34 | | // Read the table type. |
35 | 83 | EXPECTED_TRY(loadType(TabSeg.getTableType()).map_error([](auto E) { |
36 | 80 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
37 | 80 | return E; |
38 | 80 | })); |
39 | | |
40 | | // Read the expression. |
41 | 80 | EXPECTED_TRY(loadExpression(TabSeg.getExpr()).map_error([](auto E) { |
42 | 80 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
43 | 80 | return E; |
44 | 80 | })); |
45 | 1.34k | } else { |
46 | | // The table type case. |
47 | 1.34k | EXPECTED_TRY(loadType(TabSeg.getTableType()).map_error([](auto E) { |
48 | 1.34k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
49 | 1.34k | return E; |
50 | 1.34k | })); |
51 | 1.34k | } |
52 | | |
53 | 1.38k | return {}; |
54 | 1.43k | } |
55 | | |
56 | | // Load binary of GlobalSegment node. See "include/loader/loader.h". |
57 | 1.34k | Expect<void> Loader::loadSegment(AST::GlobalSegment &GlobSeg) { |
58 | 1.34k | return Expect<void>{} |
59 | 1.34k | .and_then([this, &GlobSeg]() { |
60 | | // Read global type node. |
61 | 1.34k | return loadType(GlobSeg.getGlobalType()); |
62 | 1.34k | }) |
63 | 1.34k | .and_then([this, &GlobSeg]() { |
64 | | // Read the expression. |
65 | 1.31k | return loadExpression(GlobSeg.getExpr()); |
66 | 1.31k | }) |
67 | 1.34k | .map_error([](auto E) { |
68 | 320 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Global)); |
69 | 320 | return E; |
70 | 320 | }); |
71 | 1.34k | } |
72 | | |
73 | | // Load binary of ElementSegment node. See "include/loader/loader.h". |
74 | 8.53k | Expect<void> Loader::loadSegment(AST::ElementSegment &ElemSeg) { |
75 | 8.53k | auto ReportError = [this](auto E) { |
76 | 77 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Element); |
77 | 77 | }; |
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 | 8.53k | uint32_t Check = 0; |
102 | 8.53k | 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 | 8.53k | } else { |
110 | 8.53k | EXPECTED_TRY(Check, FMgr.readU32().map_error(ReportError)); |
111 | 8.51k | } |
112 | | |
113 | | // Check the prefix byte. |
114 | 8.51k | switch (Check) { |
115 | 3.54k | case 0x00: |
116 | 5.57k | case 0x02: |
117 | 7.41k | case 0x04: |
118 | 7.53k | case 0x06: |
119 | 7.53k | ElemSeg.setMode(AST::ElementSegment::ElemMode::Active); |
120 | 7.53k | break; |
121 | | |
122 | 543 | case 0x01: |
123 | 622 | case 0x05: |
124 | 622 | ElemSeg.setMode(AST::ElementSegment::ElemMode::Passive); |
125 | 622 | break; |
126 | | |
127 | 215 | case 0x03: |
128 | 325 | case 0x07: |
129 | 325 | ElemSeg.setMode(AST::ElementSegment::ElemMode::Declarative); |
130 | 325 | break; |
131 | | |
132 | 35 | default: |
133 | | // TODO: Correct the error code once there's spec test. |
134 | 35 | return logLoadError(ErrCode::Value::IllegalGrammar, FMgr.getLastOffset(), |
135 | 35 | ASTNodeAttr::Seg_Element); |
136 | 8.51k | } |
137 | | |
138 | | // Read the table index. |
139 | 8.48k | ElemSeg.setIdx(0); |
140 | 8.48k | switch (Check) { |
141 | 2.02k | case 0x02: |
142 | 2.14k | case 0x06: |
143 | 2.14k | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto Idx) { |
144 | 2.14k | ElemSeg.setIdx(Idx); |
145 | 2.14k | })); |
146 | 2.14k | break; |
147 | | |
148 | 6.33k | default: |
149 | 6.33k | break; |
150 | 8.48k | } |
151 | | |
152 | | // Read the expression. |
153 | 8.47k | switch (Check) { |
154 | 3.54k | case 0x00: |
155 | 5.56k | case 0x02: |
156 | 7.40k | case 0x04: |
157 | 7.53k | case 0x06: |
158 | 7.53k | EXPECTED_TRY(loadExpression(ElemSeg.getExpr()).map_error([](auto E) { |
159 | 6.70k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); |
160 | 6.70k | return E; |
161 | 6.70k | })); |
162 | 6.70k | break; |
163 | | |
164 | 6.70k | default: |
165 | 947 | break; |
166 | 8.47k | } |
167 | | |
168 | | // Read element kind and init function indices. |
169 | 7.64k | switch (Check) { |
170 | 543 | case 0x01: |
171 | 2.54k | case 0x02: |
172 | 2.76k | case 0x03: |
173 | 2.76k | EXPECTED_TRY(FMgr.readByte() |
174 | 2.74k | .and_then([&](auto B) -> Expect<void> { |
175 | 2.74k | if (B != 0x00U) { |
176 | 2.74k | return Unexpect(ErrCode::Value::ExpectedZeroByte); |
177 | 2.74k | }; |
178 | 2.74k | return {}; |
179 | 2.74k | }) |
180 | 2.74k | .map_error(ReportError)); |
181 | 2.74k | [[fallthrough]]; |
182 | | |
183 | 5.73k | case 0x00: { |
184 | 5.73k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
185 | 16.7k | 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.0k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); |
192 | 11.0k | return E; |
193 | 11.0k | })); |
194 | 11.0k | ElemSeg.getInitExprs().back().getInstrs().emplace_back( |
195 | 11.0k | std::move(RefFunc)); |
196 | 11.0k | ElemSeg.getInitExprs().back().getInstrs().emplace_back(std::move(End)); |
197 | 11.0k | } |
198 | 5.67k | break; |
199 | 5.69k | } |
200 | 5.67k | default: |
201 | 1.89k | break; |
202 | 7.64k | } |
203 | | |
204 | | // Set the default reference type. |
205 | 7.57k | if (Check == 0x04) { |
206 | 1.61k | ElemSeg.setRefType(TypeCode::FuncRef); |
207 | 5.95k | } else { |
208 | 5.95k | ElemSeg.setRefType(ValType(TypeCode::Ref, TypeCode::FuncRef)); |
209 | 5.95k | } |
210 | | |
211 | | // Read the reference type and init expressions. |
212 | 7.57k | switch (Check) { |
213 | 79 | case 0x05: |
214 | 172 | case 0x06: |
215 | 282 | case 0x07: { |
216 | | // The AST node information is handled. |
217 | 282 | EXPECTED_TRY(auto Type, loadRefType(ASTNodeAttr::Seg_Element)); |
218 | 276 | ElemSeg.setRefType(Type); |
219 | 276 | [[fallthrough]]; |
220 | 276 | } |
221 | 1.89k | case 0x04: { |
222 | 1.89k | return loadVec<AST::ElementSegment>( |
223 | 3.34k | ElemSeg.getInitExprs(), [this](AST::Expression &Expr) -> Expect<void> { |
224 | 3.34k | return loadExpression(Expr); |
225 | 3.34k | }); |
226 | 276 | } |
227 | | |
228 | 5.67k | default: |
229 | 5.67k | break; |
230 | 7.57k | } |
231 | | |
232 | 5.67k | return {}; |
233 | 7.57k | } |
234 | | |
235 | | // Load binary of CodeSegment node. See "include/loader/loader.h". |
236 | 19.2k | Expect<void> Loader::loadSegment(AST::CodeSegment &CodeSeg) { |
237 | 19.2k | auto ReportError = [this](auto E) { |
238 | 36 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Code); |
239 | 36 | }; |
240 | | |
241 | | // Read the code segment size. |
242 | 19.2k | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto S) { |
243 | 19.2k | CodeSeg.setSegSize(S); |
244 | 19.2k | })); |
245 | 19.2k | auto ExprSizeBound = FMgr.getOffset() + CodeSeg.getSegSize(); |
246 | | |
247 | | // Read the vector of local variable counts and types. |
248 | 19.2k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
249 | 19.1k | CodeSeg.getLocals().clear(); |
250 | 19.1k | CodeSeg.getLocals().reserve(VecCnt); |
251 | 19.1k | uint32_t TotalLocalCnt = 0; |
252 | 22.6k | for (uint32_t I = 0; I < VecCnt; ++I) { |
253 | 3.51k | EXPECTED_TRY(uint32_t LocalCnt, FMgr.readU32().map_error(ReportError)); |
254 | | // Total local variables should not exceed 2^32. Capped at 2^26. |
255 | 3.50k | if (UINT32_C(67108864) - TotalLocalCnt < LocalCnt) { |
256 | 9 | return logLoadError(ErrCode::Value::TooManyLocals, FMgr.getLastOffset(), |
257 | 9 | ASTNodeAttr::Seg_Code); |
258 | 9 | } |
259 | 3.50k | TotalLocalCnt += LocalCnt; |
260 | | // Read the value type. |
261 | | // The AST node information is handled. |
262 | 3.50k | EXPECTED_TRY(ValType LocalType, loadValType(ASTNodeAttr::Seg_Code)); |
263 | 3.47k | CodeSeg.getLocals().push_back(std::make_pair(LocalCnt, LocalType)); |
264 | 3.47k | } |
265 | | |
266 | 19.1k | 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.1k | } else { |
271 | | // Read function body with expected expression size. |
272 | 19.1k | EXPECTED_TRY( |
273 | 19.1k | loadExpression(CodeSeg.getExpr(), ExprSizeBound).map_error([](auto E) { |
274 | 19.1k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Code)); |
275 | 19.1k | return E; |
276 | 19.1k | })); |
277 | 19.1k | } |
278 | | |
279 | 18.2k | return {}; |
280 | 19.1k | } |
281 | | |
282 | | // Load binary of DataSegment node. See "include/loader/loader.h". |
283 | 4.53k | Expect<void> Loader::loadSegment(AST::DataSegment &DataSeg) { |
284 | 4.53k | auto ReportError = [this](auto E) { |
285 | 37 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Seg_Data); |
286 | 37 | }; |
287 | 4.53k | DataSeg.setMode(AST::DataSegment::DataMode::Passive); |
288 | 4.53k | 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 | 4.53k | EXPECTED_TRY(uint32_t Check, FMgr.readU32().map_error(ReportError)); |
305 | | // Check > 0 cases are for BulkMemoryOperations or ReferenceTypes proposal. |
306 | 4.52k | 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 | 4.52k | switch (Check) { |
314 | 758 | case 0x02: // 0x02 memidx expr vec(byte) , Active |
315 | | // Read target memory index. |
316 | 758 | EXPECTED_TRY(FMgr.readU32().map_error(ReportError).map([&](auto Idx) { |
317 | 757 | DataSeg.setIdx(Idx); |
318 | 757 | })); |
319 | 757 | [[fallthrough]]; |
320 | | |
321 | 2.91k | case 0x00: // 0x00 expr vec(byte) , Active |
322 | | // Read the offset expression. |
323 | 2.91k | EXPECTED_TRY(loadExpression(DataSeg.getExpr()).map_error([](auto E) { |
324 | 1.65k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Data)); |
325 | 1.65k | return E; |
326 | 1.65k | })); |
327 | 1.65k | DataSeg.setMode(AST::DataSegment::DataMode::Active); |
328 | 1.65k | [[fallthrough]]; |
329 | | |
330 | 3.22k | case 0x01: // 0x01 vec(byte) , Passive |
331 | 3.22k | { |
332 | | // Read initialization data. |
333 | 3.22k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
334 | 3.20k | EXPECTED_TRY(FMgr.readBytes(VecCnt).map_error(ReportError).map([&](auto V) { |
335 | 3.19k | DataSeg.getData() = std::move(V); |
336 | 3.19k | })); |
337 | 3.19k | break; |
338 | 3.20k | } |
339 | 3.19k | default: |
340 | | // TODO: Correct the error code once there's spec test. |
341 | 34 | return logLoadError(ErrCode::Value::IllegalGrammar, FMgr.getLastOffset(), |
342 | 34 | ASTNodeAttr::Seg_Data); |
343 | 4.52k | } |
344 | 3.19k | return {}; |
345 | 4.52k | } |
346 | | |
347 | | } // namespace Loader |
348 | | } // namespace WasmEdge |