/src/WasmEdge/lib/loader/ast/component/component_canonical.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 | 68.9k | Expect<void> Loader::loadCanonical(AST::Component::Canonical &C) { |
10 | 68.9k | auto ReportError = [this](auto E) { |
11 | 337 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical); |
12 | 337 | }; component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonical(WasmEdge::AST::Component::Canonical&)::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const Line | Count | Source | 10 | 242 | auto ReportError = [this](auto E) { | 11 | 242 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical); | 12 | 242 | }; |
component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonical(WasmEdge::AST::Component::Canonical&)::$_0::operator()<WasmEdge::ErrCode::Value>(WasmEdge::ErrCode::Value) const Line | Count | Source | 10 | 95 | auto ReportError = [this](auto E) { | 11 | 95 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical); | 12 | 95 | }; |
|
13 | | // canon ::= 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx> |
14 | | // => (canon lift f opts type-index-space[ft]) |
15 | | // | 0x01 0x00 f:<funcidx> opts:<opts> |
16 | | // => (canon lower f opts (core func)) |
17 | | // | 0x02 rt:<typeidx> => (canon resource.new rt (core func)) |
18 | | // | 0x03 rt:<typeidx> => (canon resource.drop rt (core func)) |
19 | | // | 0x04 rt:<typeidx> => (canon resource.rep rt (core func)) |
20 | | // | 0x09 rs:<resultlist> opts:<opts> |
21 | | // => (canon task.return rs opts (core func)) ๐ |
22 | | // | 0x05 => (canon task.cancel (core func)) ๐ |
23 | | // | 0x0a t:<core:valtype> i:<u32> |
24 | | // => (canon context.get t i (core func)) ๐ |
25 | | // | 0x0b t:<core:valtype> i:<u32> |
26 | | // => (canon context.set t i (core func)) ๐ |
27 | | // | 0x0c cancel?:<cancel?> |
28 | | // => (canon thread.yield cancel? (core func)) ๐ |
29 | | // | 0x06 async?:<async?> |
30 | | // => (canon subtask.cancel async? (core func)) ๐ |
31 | | // | 0x0d => (canon subtask.drop (core func)) ๐ |
32 | | // | 0x0e t:<typeidx> => (canon stream.new t (core func)) ๐ |
33 | | // | 0x0f t:<typeidx> opts:<opts> |
34 | | // => (canon stream.read t opts (core func)) ๐ |
35 | | // | 0x10 t:<typeidx> opts:<opts> |
36 | | // => (canon stream.write t opts (core func)) ๐ |
37 | | // | 0x11 t:<typeidx> async?:<async?> |
38 | | // => (canon stream.cancel-read t async? (core func)) ๐ |
39 | | // | 0x12 t:<typeidx> async?:<async?> |
40 | | // => (canon stream.cancel-write t async? (core func)) ๐ |
41 | | // | 0x13 t:<typeidx> |
42 | | // => (canon stream.drop-readable t (core func)) ๐ |
43 | | // | 0x14 t:<typeidx> |
44 | | // => (canon stream.drop-writable t (core func)) ๐ |
45 | | // | 0x15 t:<typeidx> => (canon future.new t (core func)) ๐ |
46 | | // | 0x16 t:<typeidx> opts:<opts> |
47 | | // => (canon future.read t opts (core func)) ๐ |
48 | | // | 0x17 t:<typeidx> opts:<opts> |
49 | | // => (canon future.write t opts (core func)) ๐ |
50 | | // | 0x18 t:<typeidx> async?:<async?> |
51 | | // => (canon future.cancel-read t async? (core func)) ๐ |
52 | | // | 0x19 t:<typeidx> async?:<async?> |
53 | | // => (canon future.cancel-write t async? (core func)) ๐ |
54 | | // | 0x1a t:<typeidx> |
55 | | // => (canon future.drop-readable t (core func)) ๐ |
56 | | // | 0x1b t:<typeidx> |
57 | | // => (canon future.drop-writable t (core func)) ๐ |
58 | | // | 0x1c opts:<opts> => (canon error-context.new opts (core func)) ๐ |
59 | | // | 0x1d opts:<opts> |
60 | | // => (canon error-context.debug-message opts (core func)) ๐ |
61 | | // | 0x1e => (canon error-context.drop (core func)) ๐ |
62 | | // | 0x1f => (canon waitable-set.new (core func)) ๐ |
63 | | // | 0x20 cancel?:<cancel?> m:<core:memoryidx> |
64 | | // => (canon waitable-set.wait cancel? (memory m) (core func)) ๐ |
65 | | // | 0x21 cancel?:<cancel?> m:<core:memoryidx> |
66 | | // => (canon waitable-set.poll cancel? (memory m) (core func)) ๐ |
67 | | // | 0x22 => (canon waitable-set.drop (core func)) ๐ |
68 | | // | 0x23 => (canon waitable.join (core func)) ๐ |
69 | | // | 0x24 => (canon backpressure.inc (core func)) ๐ |
70 | | // | 0x25 => (canon backpressure.dec (core func)) ๐ |
71 | | // | 0x26 => (canon thread.index (core func)) ๐งต |
72 | | // | 0x27 ft:<core:typeidx> tbl:<core:tableidx> |
73 | | // => (canon thread.new-indirect ft tbl (core func)) ๐งต |
74 | | // | 0x28 => (canon thread.resume-later (core func)) ๐งต |
75 | | // | 0x29 cancel?:<cancel?> |
76 | | // => (canon thread.suspend cancel? (core func)) ๐งต |
77 | | // | 0x2a cancel?:<cancel?> |
78 | | // => (canon thread.suspend-then-resume cancel? (core func)) ๐งต |
79 | | // | 0x2b cancel?:<cancel?> |
80 | | // => (canon thread.yield-then-resume cancel? (core func)) ๐งต |
81 | | // | 0x2c cancel?:<cancel?> |
82 | | // => (canon thread.suspend-then-promote cancel? (core func)) ๐งต |
83 | | // | 0x2d cancel?:<cancel?> |
84 | | // => (canon thread.yield-then-promote cancel? (core func)) ๐งต |
85 | | // | 0x40 shared?:<sh?> ft:<core:typeidx> |
86 | | // => (canon thread.spawn-ref shared? ft (core func)) ๐งตโก |
87 | | // | 0x41 shared?:<sh?> ft:<core:typeidx> tbl:<core:tableidx> |
88 | | // => (canon thread.spawn-indirect shared? ft tbl (core func)) ๐งตโก |
89 | | // | 0x42 shared?:<sh?> |
90 | | // => (canon thread.available-parallelism shared? (core func)) ๐งตโก |
91 | | // async? ::= 0x00 => ฯต |
92 | | // | 0x01 => async |
93 | | // cancel? ::= 0x00 => ฯต |
94 | | // | 0x01 => cancellable |
95 | | // sh? ::= 0x00 => ฯต |
96 | | // | 0x01 => shared ๐งตโก |
97 | | |
98 | | // Helper: load the async? / cancel? immediate. They share one encoding. |
99 | 68.9k | auto LoadFlagImm = [this, &ReportError, &C]() -> Expect<void> { |
100 | 4.18k | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError)); |
101 | 4.15k | if (B == 0x00) { |
102 | 3.43k | C.setFlagImmediate(false); |
103 | 3.43k | } else if (B == 0x01) { |
104 | 710 | C.setFlagImmediate(true); |
105 | 710 | } else { |
106 | 17 | return ReportError(ErrCode::Value::MalformedCanonical); |
107 | 17 | } |
108 | 4.14k | return {}; |
109 | 4.15k | }; |
110 | | |
111 | | // Helper: load the ๐งตโก shared? flag. |
112 | 68.9k | auto LoadShared = [this, &ReportError]() -> Expect<void> { |
113 | 449 | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError)); |
114 | 448 | if (B > 0x01) { |
115 | 12 | return ReportError(ErrCode::Value::MalformedCanonical); |
116 | 12 | } |
117 | 436 | return {}; |
118 | 448 | }; |
119 | | |
120 | | // Helper: load opts (vec of canonopt). |
121 | 68.9k | auto LoadOpts = [this, &C]() -> Expect<void> { |
122 | 16.6k | std::vector<AST::Component::CanonOpt> Opts; |
123 | 16.6k | EXPECTED_TRY(loadVec<AST::Component::Canonical>( |
124 | 16.4k | Opts, [this](AST::Component::CanonOpt &Opt) { |
125 | 16.4k | return loadCanonicalOption(Opt); |
126 | 16.4k | })); |
127 | 16.4k | C.setOptions(std::move(Opts)); |
128 | 16.4k | return {}; |
129 | 16.6k | }; |
130 | | |
131 | 68.9k | EXPECTED_TRY(uint8_t Flag, FMgr.readByte().map_error(ReportError)); |
132 | 68.8k | auto Code = static_cast<ComponentCanonOpCode>(Flag); |
133 | 68.8k | switch (Code) { |
134 | | |
135 | | // 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx> |
136 | 10.8k | case ComponentCanonOpCode::Lift: { |
137 | 10.8k | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError)); |
138 | 10.8k | if (unlikely(B != 0x00)) { |
139 | 24 | return ReportError(ErrCode::Value::MalformedCanonical); |
140 | 24 | } |
141 | 21.6k | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
142 | 21.6k | C.setIndex(Idx); |
143 | 21.6k | EXPECTED_TRY(LoadOpts()); |
144 | 10.7k | EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError)); |
145 | 10.7k | C.setTargetIndex(TypeIdx); |
146 | 10.7k | break; |
147 | 10.7k | } |
148 | | |
149 | | // 0x01 0x00 f:<funcidx> opts:<opts> |
150 | 2.46k | case ComponentCanonOpCode::Lower: { |
151 | 2.46k | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError)); |
152 | 2.46k | if (unlikely(B != 0x00)) { |
153 | 10 | return ReportError(ErrCode::Value::MalformedCanonical); |
154 | 10 | } |
155 | 4.90k | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
156 | 4.90k | C.setIndex(Idx); |
157 | 4.90k | EXPECTED_TRY(LoadOpts()); |
158 | 2.43k | break; |
159 | 4.90k | } |
160 | | |
161 | | // typeidx-only opcodes |
162 | 2.43k | case ComponentCanonOpCode::Resource__new: |
163 | 739 | case ComponentCanonOpCode::Resource__drop: |
164 | 1.05k | case ComponentCanonOpCode::Resource__rep: |
165 | 1.37k | case ComponentCanonOpCode::Stream__new: |
166 | 1.70k | case ComponentCanonOpCode::Stream__drop_readable: |
167 | 2.57k | case ComponentCanonOpCode::Stream__drop_writable: |
168 | 37.1k | case ComponentCanonOpCode::Future__new: |
169 | 37.5k | case ComponentCanonOpCode::Future__drop_readable: |
170 | 39.0k | case ComponentCanonOpCode::Future__drop_writable: { |
171 | 39.0k | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
172 | 38.9k | C.setIndex(Idx); |
173 | 38.9k | break; |
174 | 39.0k | } |
175 | | |
176 | | // no-arg opcodes |
177 | 263 | case ComponentCanonOpCode::Backpressure__inc: |
178 | 745 | case ComponentCanonOpCode::Backpressure__dec: |
179 | 1.20k | case ComponentCanonOpCode::Thread__index: |
180 | 1.42k | case ComponentCanonOpCode::Thread__resume_later: |
181 | 1.79k | case ComponentCanonOpCode::Task__cancel: |
182 | 2.81k | case ComponentCanonOpCode::Subtask__drop: |
183 | 3.30k | case ComponentCanonOpCode::Error_context__drop: |
184 | 3.76k | case ComponentCanonOpCode::Waitable_set__new: |
185 | 4.07k | case ComponentCanonOpCode::Waitable_set__drop: |
186 | 4.69k | case ComponentCanonOpCode::Waitable__join: |
187 | 4.69k | break; |
188 | | |
189 | | // 0x09 rs:<resultlist> opts:<opts> |
190 | 1.76k | case ComponentCanonOpCode::Task__return: { |
191 | | // Load resultlist (same encoding as functype resultlist). |
192 | 1.76k | EXPECTED_TRY(uint8_t RFlag, FMgr.readByte().map_error(ReportError)); |
193 | 1.75k | switch (RFlag) { |
194 | 1.31k | case 0x00: { |
195 | 1.31k | ComponentValType VT; |
196 | 1.31k | EXPECTED_TRY(loadType(VT).map_error([](auto E) { |
197 | 1.30k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Canonical)); |
198 | 1.30k | return E; |
199 | 1.30k | })); |
200 | 1.30k | C.setResultList(VT); |
201 | 1.30k | break; |
202 | 1.31k | } |
203 | 443 | case 0x01: { |
204 | 443 | std::vector<AST::Component::LabelValType> ResultList; |
205 | 443 | EXPECTED_TRY(loadVec<AST::Component::Canonical>( |
206 | 394 | ResultList, |
207 | 394 | [this](AST::Component::LabelValType &LV) { return loadType(LV); })); |
208 | 394 | C.setResultList(std::move(ResultList)); |
209 | 394 | break; |
210 | 443 | } |
211 | 2 | default: |
212 | 2 | return ReportError(ErrCode::Value::MalformedCanonical); |
213 | 1.75k | } |
214 | 1.70k | EXPECTED_TRY(LoadOpts()); |
215 | 1.67k | break; |
216 | 1.70k | } |
217 | | |
218 | | // 0x0a t:<core:valtype> i:<u32> and 0x0b t:<core:valtype> i:<u32> |
219 | 2.19k | case ComponentCanonOpCode::Context__get: |
220 | 3.15k | case ComponentCanonOpCode::Context__set: { |
221 | 3.15k | EXPECTED_TRY(ValType T, loadValType(ASTNodeAttr::Comp_Canonical)); |
222 | 3.14k | C.setContextType(T); |
223 | 3.14k | EXPECTED_TRY(uint32_t Val, FMgr.readU32().map_error(ReportError)); |
224 | 3.14k | C.setConstVal(Val); |
225 | 3.14k | break; |
226 | 3.14k | } |
227 | | |
228 | | // async?/cancel?-only opcodes |
229 | 175 | case ComponentCanonOpCode::Yield: |
230 | 489 | case ComponentCanonOpCode::Subtask__cancel: |
231 | 1.24k | case ComponentCanonOpCode::Thread__suspend: |
232 | 1.34k | case ComponentCanonOpCode::Thread__suspend_then_resume: |
233 | 1.89k | case ComponentCanonOpCode::Thread__yield_then_resume: |
234 | 2.26k | case ComponentCanonOpCode::Thread__suspend_then_promote: |
235 | 2.37k | case ComponentCanonOpCode::Thread__yield_then_promote: { |
236 | 2.37k | EXPECTED_TRY(LoadFlagImm()); |
237 | 2.34k | break; |
238 | 2.37k | } |
239 | | |
240 | | // typeidx + opts opcodes |
241 | 2.34k | case ComponentCanonOpCode::Stream__read: |
242 | 1.04k | case ComponentCanonOpCode::Stream__write: |
243 | 1.36k | case ComponentCanonOpCode::Future__read: |
244 | 1.48k | case ComponentCanonOpCode::Future__write: { |
245 | 1.48k | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
246 | 1.47k | C.setIndex(Idx); |
247 | 1.47k | EXPECTED_TRY(LoadOpts()); |
248 | 1.44k | break; |
249 | 1.47k | } |
250 | | |
251 | | // typeidx + async? opcodes |
252 | 1.44k | case ComponentCanonOpCode::Stream__cancel_read: |
253 | 987 | case ComponentCanonOpCode::Stream__cancel_write: |
254 | 1.21k | case ComponentCanonOpCode::Future__cancel_read: |
255 | 1.60k | case ComponentCanonOpCode::Future__cancel_write: { |
256 | 1.60k | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
257 | 1.58k | C.setIndex(Idx); |
258 | 1.58k | EXPECTED_TRY(LoadFlagImm()); |
259 | 1.58k | break; |
260 | 1.58k | } |
261 | | |
262 | | // opts-only opcodes |
263 | 1.58k | case ComponentCanonOpCode::Error_context__new: |
264 | 216 | case ComponentCanonOpCode::Error_context__debug_message: { |
265 | 216 | EXPECTED_TRY(LoadOpts()); |
266 | 185 | break; |
267 | 216 | } |
268 | | |
269 | | // async? + memidx opcodes |
270 | 185 | case ComponentCanonOpCode::Waitable_set__wait: |
271 | 224 | case ComponentCanonOpCode::Waitable_set__poll: { |
272 | 224 | EXPECTED_TRY(LoadFlagImm()); |
273 | 213 | EXPECTED_TRY(uint32_t MemIdx, FMgr.readU32().map_error(ReportError)); |
274 | 208 | C.setIndex(MemIdx); |
275 | 208 | break; |
276 | 213 | } |
277 | | |
278 | | // 0x27 ft:<core:typeidx> tbl:<core:tableidx> |
279 | 499 | case ComponentCanonOpCode::Thread__new_indirect: { |
280 | 499 | EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError)); |
281 | 497 | C.setIndex(TypeIdx); |
282 | 497 | EXPECTED_TRY(uint32_t TblIdx, FMgr.readU32().map_error(ReportError)); |
283 | 495 | C.setTargetIndex(TblIdx); |
284 | 495 | break; |
285 | 497 | } |
286 | | |
287 | | // ๐งตโก shared?-prefixed opcodes. The flag is parsed but not kept, because |
288 | | // these built-ins belong to shared-everything-threads and are not |
289 | | // instantiated. |
290 | 78 | case ComponentCanonOpCode::Thread__spawn_ref: { |
291 | 78 | EXPECTED_TRY(LoadShared()); |
292 | 75 | EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError)); |
293 | 72 | C.setIndex(TypeIdx); |
294 | 72 | break; |
295 | 75 | } |
296 | 80 | case ComponentCanonOpCode::Thread__spawn_indirect: { |
297 | 80 | EXPECTED_TRY(LoadShared()); |
298 | 152 | EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError)); |
299 | 152 | C.setIndex(TypeIdx); |
300 | 152 | EXPECTED_TRY(uint32_t TblIdx, FMgr.readU32().map_error(ReportError)); |
301 | 74 | C.setTargetIndex(TblIdx); |
302 | 74 | break; |
303 | 152 | } |
304 | 291 | case ComponentCanonOpCode::Thread__available_parallelism: |
305 | 291 | EXPECTED_TRY(LoadShared()); |
306 | 284 | break; |
307 | | |
308 | 284 | default: |
309 | 30 | return ReportError(ErrCode::Value::MalformedCanonical); |
310 | 68.8k | } |
311 | 68.3k | C.setOpCode(Code); |
312 | 68.3k | return {}; |
313 | 68.8k | } |
314 | | |
315 | 7.64k | Expect<void> Loader::loadCanonicalOption(AST::Component::CanonOpt &Opt) { |
316 | 7.64k | auto ReportError = [this](auto E) { |
317 | 100 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt); |
318 | 100 | }; component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonicalOption(WasmEdge::AST::Component::CanonOpt&)::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const Line | Count | Source | 316 | 48 | auto ReportError = [this](auto E) { | 317 | 48 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt); | 318 | 48 | }; |
component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonicalOption(WasmEdge::AST::Component::CanonOpt&)::$_0::operator()<WasmEdge::ErrCode::Value>(WasmEdge::ErrCode::Value) const Line | Count | Source | 316 | 52 | auto ReportError = [this](auto E) { | 317 | 52 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt); | 318 | 52 | }; |
|
319 | | // canonopt ::= 0x00 => string-encoding=utf8 |
320 | | // | 0x01 => string-encoding=utf16 |
321 | | // | 0x02 => string-encoding=latin1+utf16 |
322 | | // | 0x03 m:<core:memidx> => (memory m) |
323 | | // | 0x04 f:<core:funcidx> => (realloc f) |
324 | | // | 0x05 f:<core:funcidx> => (post-return f) |
325 | | // | 0x06 => async ๐ |
326 | | // | 0x07 f:<core:funcidx> => (callback f) ๐ |
327 | | |
328 | 7.64k | EXPECTED_TRY(uint8_t Flag, FMgr.readByte().map_error(ReportError)); |
329 | 7.61k | const auto Code = static_cast<ComponentCanonOptCode>(Flag); |
330 | 7.61k | switch (Code) { |
331 | 3.91k | case ComponentCanonOptCode::Encode_UTF8: |
332 | 5.16k | case ComponentCanonOptCode::Encode_UTF16: |
333 | 5.80k | case ComponentCanonOptCode::Encode_Latin1: |
334 | 6.16k | case ComponentCanonOptCode::Async: |
335 | 6.16k | break; |
336 | 297 | case ComponentCanonOptCode::Memory: |
337 | 609 | case ComponentCanonOptCode::Realloc: |
338 | 1.15k | case ComponentCanonOptCode::PostReturn: |
339 | 1.40k | case ComponentCanonOptCode::Callback: { |
340 | 1.40k | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
341 | 1.38k | Opt.setIndex(Idx); |
342 | 1.38k | break; |
343 | 1.40k | } |
344 | 52 | default: |
345 | 52 | return ReportError(ErrCode::Value::UnknownCanonicalOption); |
346 | 7.61k | } |
347 | 7.54k | Opt.setCode(Code); |
348 | 7.54k | return {}; |
349 | 7.61k | } |
350 | | |
351 | | } // namespace Loader |
352 | | } // namespace WasmEdge |