/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 | 0 | Expect<void> Loader::loadCanonical(AST::Component::Canonical &C) { |
10 | 0 | auto ReportError = [this](auto E) { |
11 | 0 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_Canonical); |
12 | 0 | }; Unexecuted instantiation: component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonical(WasmEdge::AST::Component::Canonical&)::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const Unexecuted instantiation: component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonical(WasmEdge::AST::Component::Canonical&)::$_0::operator()<WasmEdge::ErrCode::Value>(WasmEdge::ErrCode::Value) const |
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 | | // | 0x07 rt:<typeidx> |
20 | | // => (canon resource.drop rt async (core func)) ๐ |
21 | | // | 0x04 rt:<typeidx> => (canon resource.rep rt (core func)) |
22 | | // | 0x08 => (canon backpressure.set (core func)) ๐ |
23 | | // | 0x09 rs:<resultlist> opts:<opts> |
24 | | // => (canon task.return rs opts (core func)) ๐ |
25 | | // | 0x05 => (canon task.cancel (core func)) ๐ |
26 | | // | 0x0a 0x7f i:<u32> => (canon context.get i32 i (core func)) ๐ |
27 | | // | 0x0b 0x7f i:<u32> => (canon context.set i32 i (core func)) ๐ |
28 | | // | 0x0c async?:<async>? => (canon yield async? (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 async? (core func)) ๐ |
39 | | // | 0x12 t:<typeidx> async?:<async?> |
40 | | // => (canon stream.cancel-write async? (core func)) ๐ |
41 | | // | 0x13 t:<typeidx> |
42 | | // => (canon stream.close-readable t (core func)) ๐ |
43 | | // | 0x14 t:<typeidx> |
44 | | // => (canon stream.close-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 async? (core func)) ๐ |
52 | | // | 0x19 t:<typeidx> async?:<async?> |
53 | | // => (canon future.cancel-write async? (core func)) ๐ |
54 | | // | 0x1a t:<typeidx> |
55 | | // => (canon future.close-readable t (core func)) ๐ |
56 | | // | 0x1b t:<typeidx> |
57 | | // => (canon future.close-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 async?:<async>? m:<core:memidx> |
64 | | // => (canon waitable-set.wait async? (memory m) (core func)) ๐ |
65 | | // | 0x21 async?:<async>? m:<core:memidx> |
66 | | // => (canon waitable-set.poll async? (memory m) (core func)) ๐ |
67 | | // | 0x22 => (canon waitable-set.drop (core func)) ๐ |
68 | | // | 0x23 => (canon waitable.join (core func)) ๐ |
69 | | // | 0x40 ft:<typeidx> => (canon thread.spawn_ref ft (core func)) ๐งต |
70 | | // | 0x41 ft:<typeidx> tbl:<core:tableidx> |
71 | | // => (canon thread.spawn_indirect ft tbl (core func)) ๐งต |
72 | | // | 0x42 => (canon thread.available_parallelism (core func)) ๐งต |
73 | | // async? ::= 0x00 => ฯต |
74 | | // | 0x01 => async |
75 | | |
76 | | // Helper: load async? flag. |
77 | 0 | auto LoadAsync = [this, &ReportError, &C]() -> Expect<void> { |
78 | 0 | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError)); |
79 | 0 | if (B == 0x00) { |
80 | 0 | C.setAsync(false); |
81 | 0 | } else if (B == 0x01) { |
82 | 0 | C.setAsync(true); |
83 | 0 | } else { |
84 | 0 | return ReportError(ErrCode::Value::MalformedCanonical); |
85 | 0 | } |
86 | 0 | return {}; |
87 | 0 | }; |
88 | | |
89 | | // Helper: load opts (vec of canonopt). |
90 | 0 | auto LoadOpts = [this, &C]() -> Expect<void> { |
91 | 0 | std::vector<AST::Component::CanonOpt> Opts; |
92 | 0 | EXPECTED_TRY(loadVec<AST::Component::Canonical>( |
93 | 0 | Opts, [this](AST::Component::CanonOpt &Opt) { |
94 | 0 | return loadCanonicalOption(Opt); |
95 | 0 | })); |
96 | 0 | C.setOptions(std::move(Opts)); |
97 | 0 | return {}; |
98 | 0 | }; |
99 | |
|
100 | 0 | EXPECTED_TRY(uint8_t Flag, FMgr.readByte().map_error(ReportError)); |
101 | 0 | auto Code = static_cast<ComponentCanonOpCode>(Flag); |
102 | 0 | switch (Code) { |
103 | | |
104 | | // 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx> |
105 | 0 | case ComponentCanonOpCode::Lift: { |
106 | 0 | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError)); |
107 | 0 | if (unlikely(B != 0x00)) { |
108 | 0 | return ReportError(ErrCode::Value::MalformedCanonical); |
109 | 0 | } |
110 | 0 | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
111 | 0 | C.setIndex(Idx); |
112 | 0 | EXPECTED_TRY(LoadOpts()); |
113 | 0 | EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError)); |
114 | 0 | C.setTargetIndex(TypeIdx); |
115 | 0 | break; |
116 | 0 | } |
117 | | |
118 | | // 0x01 0x00 f:<funcidx> opts:<opts> |
119 | 0 | case ComponentCanonOpCode::Lower: { |
120 | 0 | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError)); |
121 | 0 | if (unlikely(B != 0x00)) { |
122 | 0 | return ReportError(ErrCode::Value::MalformedCanonical); |
123 | 0 | } |
124 | 0 | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
125 | 0 | C.setIndex(Idx); |
126 | 0 | EXPECTED_TRY(LoadOpts()); |
127 | 0 | break; |
128 | 0 | } |
129 | | |
130 | | // typeidx-only opcodes |
131 | 0 | case ComponentCanonOpCode::Resource__new: |
132 | 0 | case ComponentCanonOpCode::Resource__drop: |
133 | 0 | case ComponentCanonOpCode::Resource__drop_async: |
134 | 0 | case ComponentCanonOpCode::Resource__rep: |
135 | 0 | case ComponentCanonOpCode::Stream__new: |
136 | 0 | case ComponentCanonOpCode::Stream__close_readable: |
137 | 0 | case ComponentCanonOpCode::Stream__close_writable: |
138 | 0 | case ComponentCanonOpCode::Future__new: |
139 | 0 | case ComponentCanonOpCode::Future__close_readable: |
140 | 0 | case ComponentCanonOpCode::Future__close_writable: |
141 | 0 | case ComponentCanonOpCode::Thread__spawn_ref: { |
142 | 0 | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
143 | 0 | C.setIndex(Idx); |
144 | 0 | break; |
145 | 0 | } |
146 | | |
147 | | // no-arg opcodes |
148 | 0 | case ComponentCanonOpCode::Backpressure__set: |
149 | 0 | case ComponentCanonOpCode::Task__cancel: |
150 | 0 | case ComponentCanonOpCode::Subtask__drop: |
151 | 0 | case ComponentCanonOpCode::Error_context__drop: |
152 | 0 | case ComponentCanonOpCode::Waitable_set__new: |
153 | 0 | case ComponentCanonOpCode::Waitable_set__drop: |
154 | 0 | case ComponentCanonOpCode::Waitable__join: |
155 | 0 | case ComponentCanonOpCode::Thread__available_parallelism: |
156 | 0 | break; |
157 | | |
158 | | // 0x09 rs:<resultlist> opts:<opts> |
159 | 0 | case ComponentCanonOpCode::Task__return: { |
160 | | // Load resultlist (same encoding as functype resultlist). |
161 | 0 | EXPECTED_TRY(uint8_t RFlag, FMgr.readByte().map_error(ReportError)); |
162 | 0 | switch (RFlag) { |
163 | 0 | case 0x00: { |
164 | 0 | ComponentValType VT; |
165 | 0 | EXPECTED_TRY(loadType(VT).map_error([](auto E) { |
166 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Canonical)); |
167 | 0 | return E; |
168 | 0 | })); |
169 | 0 | C.setResultList(VT); |
170 | 0 | break; |
171 | 0 | } |
172 | 0 | case 0x01: { |
173 | 0 | std::vector<AST::Component::LabelValType> ResultList; |
174 | 0 | EXPECTED_TRY(loadVec<AST::Component::Canonical>( |
175 | 0 | ResultList, |
176 | 0 | [this](AST::Component::LabelValType &LV) { return loadType(LV); })); |
177 | 0 | C.setResultList(std::move(ResultList)); |
178 | 0 | break; |
179 | 0 | } |
180 | 0 | default: |
181 | 0 | return ReportError(ErrCode::Value::MalformedCanonical); |
182 | 0 | } |
183 | 0 | EXPECTED_TRY(LoadOpts()); |
184 | 0 | break; |
185 | 0 | } |
186 | | |
187 | | // 0x0a 0x7f i:<u32> and 0x0b 0x7f i:<u32> |
188 | 0 | case ComponentCanonOpCode::Context__get: |
189 | 0 | case ComponentCanonOpCode::Context__set: { |
190 | 0 | EXPECTED_TRY(uint8_t B, FMgr.readByte().map_error(ReportError)); |
191 | 0 | if (unlikely(B != 0x7f)) { |
192 | 0 | return ReportError(ErrCode::Value::MalformedCanonical); |
193 | 0 | } |
194 | 0 | EXPECTED_TRY(uint32_t Val, FMgr.readU32().map_error(ReportError)); |
195 | 0 | C.setConstVal(Val); |
196 | 0 | break; |
197 | 0 | } |
198 | | |
199 | | // async?-only opcodes |
200 | 0 | case ComponentCanonOpCode::Yield: |
201 | 0 | case ComponentCanonOpCode::Subtask__cancel: { |
202 | 0 | EXPECTED_TRY(LoadAsync()); |
203 | 0 | break; |
204 | 0 | } |
205 | | |
206 | | // typeidx + opts opcodes |
207 | 0 | case ComponentCanonOpCode::Stream__read: |
208 | 0 | case ComponentCanonOpCode::Stream__write: |
209 | 0 | case ComponentCanonOpCode::Future__read: |
210 | 0 | case ComponentCanonOpCode::Future__write: { |
211 | 0 | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
212 | 0 | C.setIndex(Idx); |
213 | 0 | EXPECTED_TRY(LoadOpts()); |
214 | 0 | break; |
215 | 0 | } |
216 | | |
217 | | // typeidx + async? opcodes |
218 | 0 | case ComponentCanonOpCode::Stream__cancel_read: |
219 | 0 | case ComponentCanonOpCode::Stream__cancel_write: |
220 | 0 | case ComponentCanonOpCode::Future__cancel_read: |
221 | 0 | case ComponentCanonOpCode::Future__cancel_write: { |
222 | 0 | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
223 | 0 | C.setIndex(Idx); |
224 | 0 | EXPECTED_TRY(LoadAsync()); |
225 | 0 | break; |
226 | 0 | } |
227 | | |
228 | | // opts-only opcodes |
229 | 0 | case ComponentCanonOpCode::Error_context__new: |
230 | 0 | case ComponentCanonOpCode::Error_context__debug_message: { |
231 | 0 | EXPECTED_TRY(LoadOpts()); |
232 | 0 | break; |
233 | 0 | } |
234 | | |
235 | | // async? + memidx opcodes |
236 | 0 | case ComponentCanonOpCode::Waitable_set__wait: |
237 | 0 | case ComponentCanonOpCode::Waitable_set__poll: { |
238 | 0 | EXPECTED_TRY(LoadAsync()); |
239 | 0 | EXPECTED_TRY(uint32_t MemIdx, FMgr.readU32().map_error(ReportError)); |
240 | 0 | C.setIndex(MemIdx); |
241 | 0 | break; |
242 | 0 | } |
243 | | |
244 | | // 0x41 ft:<typeidx> tbl:<core:tableidx> |
245 | 0 | case ComponentCanonOpCode::Thread__spawn_indirect: { |
246 | 0 | EXPECTED_TRY(uint32_t TypeIdx, FMgr.readU32().map_error(ReportError)); |
247 | 0 | C.setIndex(TypeIdx); |
248 | 0 | EXPECTED_TRY(uint32_t TblIdx, FMgr.readU32().map_error(ReportError)); |
249 | 0 | C.setTargetIndex(TblIdx); |
250 | 0 | break; |
251 | 0 | } |
252 | | |
253 | 0 | default: |
254 | 0 | return ReportError(ErrCode::Value::MalformedCanonical); |
255 | 0 | } |
256 | 0 | C.setOpCode(Code); |
257 | 0 | return {}; |
258 | 0 | } |
259 | | |
260 | 0 | Expect<void> Loader::loadCanonicalOption(AST::Component::CanonOpt &Opt) { |
261 | 0 | auto ReportError = [this](auto E) { |
262 | 0 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Comp_CanonOpt); |
263 | 0 | }; Unexecuted instantiation: component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonicalOption(WasmEdge::AST::Component::CanonOpt&)::$_0::operator()<WasmEdge::ErrCode>(WasmEdge::ErrCode) const Unexecuted instantiation: component_canonical.cpp:auto WasmEdge::Loader::Loader::loadCanonicalOption(WasmEdge::AST::Component::CanonOpt&)::$_0::operator()<WasmEdge::ErrCode::Value>(WasmEdge::ErrCode::Value) const |
264 | | // canonopt ::= 0x00 => string-encoding=utf8 |
265 | | // | 0x01 => string-encoding=utf16 |
266 | | // | 0x02 => string-encoding=latin1+utf16 |
267 | | // | 0x03 m:<core:memidx> => (memory m) |
268 | | // | 0x04 f:<core:funcidx> => (realloc f) |
269 | | // | 0x05 f:<core:funcidx> => (post-return f) |
270 | | // | 0x06 => async ๐ |
271 | | // | 0x07 f:<core:funcidx> => (callback f) ๐ |
272 | | // | 0x08 => always-task-return ๐ |
273 | |
|
274 | 0 | EXPECTED_TRY(uint8_t Flag, FMgr.readByte().map_error(ReportError)); |
275 | 0 | switch (Flag) { |
276 | 0 | case 0x00: |
277 | 0 | case 0x01: |
278 | 0 | case 0x02: |
279 | 0 | case 0x06: |
280 | 0 | case 0x08: |
281 | 0 | break; |
282 | 0 | case 0x03: |
283 | 0 | case 0x04: |
284 | 0 | case 0x05: |
285 | 0 | case 0x07: { |
286 | 0 | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error(ReportError)); |
287 | 0 | Opt.setIndex(Idx); |
288 | 0 | break; |
289 | 0 | } |
290 | 0 | default: |
291 | 0 | return ReportError(ErrCode::Value::UnknownCanonicalOption); |
292 | 0 | } |
293 | 0 | Opt.setCode(static_cast<ComponentCanonOptCode>(Flag)); |
294 | 0 | return {}; |
295 | 0 | } |
296 | | |
297 | | } // namespace Loader |
298 | | } // namespace WasmEdge |