1 | // |
2 | // m3_parse.c |
3 | // |
4 | // Created by Steven Massey on 4/19/19. |
5 | // Copyright © 2019 Steven Massey. All rights reserved. |
6 | // |
7 | |
8 | #include "m3_env.h" |
9 | #include "m3_compile.h" |
10 | #include "m3_exception.h" |
11 | #include "m3_info.h" |
12 | |
13 | |
14 | M3Result ParseType_Table (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
15 | { |
16 | M3Result result = m3Err_none; |
17 | |
18 | return result; |
19 | } |
20 | |
21 | |
22 | M3Result ParseType_Memory (M3MemoryInfo * o_memory, bytes_t * io_bytes, cbytes_t i_end) |
23 | { |
24 | M3Result result = m3Err_none; |
25 | |
26 | u8 flag; |
27 | |
28 | _ (ReadLEB_u7 (& flag, io_bytes, i_end)); // really a u1 |
29 | _ (ReadLEB_u32 (& o_memory->initPages, io_bytes, i_end)); |
30 | |
31 | o_memory->maxPages = 0; |
32 | if (flag) |
33 | _ (ReadLEB_u32 (& o_memory->maxPages, io_bytes, i_end)); |
34 | |
35 | _catch: return result; |
36 | } |
37 | |
38 | |
39 | M3Result ParseSection_Type (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
40 | { |
41 | IM3FuncType ftype = NULL; |
42 | |
43 | _try { |
44 | u32 numTypes; |
45 | _ (ReadLEB_u32 (& numTypes, & i_bytes, i_end)); m3log (parse, "** Type [%d]" , numTypes); |
46 | |
47 | _throwif("too many types" , numTypes > d_m3MaxSaneTypesCount); |
48 | |
49 | if (numTypes) |
50 | { |
51 | // table of IM3FuncType (that point to the actual M3FuncType struct in the Environment) |
52 | io_module->funcTypes = m3_AllocArray (IM3FuncType, numTypes); |
53 | _throwifnull (io_module->funcTypes); |
54 | io_module->numFuncTypes = numTypes; |
55 | |
56 | for (u32 i = 0; i < numTypes; ++i) |
57 | { |
58 | i8 form; |
59 | _ (ReadLEB_i7 (& form, & i_bytes, i_end)); |
60 | _throwif (m3Err_wasmMalformed, form != -32); // for Wasm MVP |
61 | |
62 | u32 numArgs; |
63 | _ (ReadLEB_u32 (& numArgs, & i_bytes, i_end)); |
64 | |
65 | _throwif (m3Err_tooManyArgsRets, numArgs > d_m3MaxSaneFunctionArgRetCount); |
66 | #if defined(M3_COMPILER_MSVC) |
67 | u8 argTypes [d_m3MaxSaneFunctionArgRetCount]; |
68 | #else |
69 | u8 argTypes[numArgs+1]; // make ubsan happy |
70 | #endif |
71 | for (u32 a = 0; a < numArgs; ++a) |
72 | { |
73 | i8 wasmType; |
74 | u8 argType; |
75 | _ (ReadLEB_i7 (& wasmType, & i_bytes, i_end)); |
76 | _ (NormalizeType (& argType, wasmType)); |
77 | |
78 | argTypes[a] = argType; |
79 | } |
80 | |
81 | u32 numRets; |
82 | _ (ReadLEB_u32 (& numRets, & i_bytes, i_end)); |
83 | _throwif (m3Err_tooManyArgsRets, (u64)(numRets) + numArgs > d_m3MaxSaneFunctionArgRetCount); |
84 | |
85 | _ (AllocFuncType (& ftype, numRets + numArgs)); |
86 | ftype->numArgs = numArgs; |
87 | ftype->numRets = numRets; |
88 | |
89 | for (u32 r = 0; r < numRets; ++r) |
90 | { |
91 | i8 wasmType; |
92 | u8 retType; |
93 | _ (ReadLEB_i7 (& wasmType, & i_bytes, i_end)); |
94 | _ (NormalizeType (& retType, wasmType)); |
95 | |
96 | ftype->types[r] = retType; |
97 | } |
98 | memcpy (ftype->types + numRets, argTypes, numArgs); m3log (parse, " type %2d: %s" , i, SPrintFuncTypeSignature (ftype)); |
99 | |
100 | Environment_AddFuncType (io_module->environment, & ftype); |
101 | io_module->funcTypes [i] = ftype; |
102 | ftype = NULL; // ownership transferred to environment |
103 | } |
104 | } |
105 | |
106 | } _catch: |
107 | |
108 | if (result) |
109 | { |
110 | m3_Free (ftype); |
111 | // FIX: M3FuncTypes in the table are leaked |
112 | m3_Free (io_module->funcTypes); |
113 | io_module->numFuncTypes = 0; |
114 | } |
115 | |
116 | return result; |
117 | } |
118 | |
119 | |
120 | M3Result ParseSection_Function (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
121 | { |
122 | M3Result result = m3Err_none; |
123 | |
124 | u32 numFunctions; |
125 | _ (ReadLEB_u32 (& numFunctions, & i_bytes, i_end)); m3log (parse, "** Function [%d]" , numFunctions); |
126 | |
127 | _throwif("too many functions" , numFunctions > d_m3MaxSaneFunctionsCount); |
128 | |
129 | _ (Module_PreallocFunctions(io_module, io_module->numFunctions + numFunctions)); |
130 | |
131 | for (u32 i = 0; i < numFunctions; ++i) |
132 | { |
133 | u32 funcTypeIndex; |
134 | _ (ReadLEB_u32 (& funcTypeIndex, & i_bytes, i_end)); |
135 | |
136 | _ (Module_AddFunction (io_module, funcTypeIndex, NULL /* import info */)); |
137 | } |
138 | |
139 | _catch: return result; |
140 | } |
141 | |
142 | |
143 | M3Result ParseSection_Import (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
144 | { |
145 | M3Result result = m3Err_none; |
146 | |
147 | M3ImportInfo import = { NULL, NULL }, clearImport = { NULL, NULL }; |
148 | |
149 | u32 numImports; |
150 | _ (ReadLEB_u32 (& numImports, & i_bytes, i_end)); m3log (parse, "** Import [%d]" , numImports); |
151 | |
152 | _throwif("too many imports" , numImports > d_m3MaxSaneImportsCount); |
153 | |
154 | // Most imports are functions, so we won't waste much space anyway (if any) |
155 | _ (Module_PreallocFunctions(io_module, numImports)); |
156 | |
157 | for (u32 i = 0; i < numImports; ++i) |
158 | { |
159 | u8 importKind; |
160 | |
161 | _ (Read_utf8 (& import.moduleUtf8, & i_bytes, i_end)); |
162 | _ (Read_utf8 (& import.fieldUtf8, & i_bytes, i_end)); |
163 | _ (Read_u8 (& importKind, & i_bytes, i_end)); m3log (parse, " kind: %d '%s.%s' " , |
164 | (u32) importKind, import.moduleUtf8, import.fieldUtf8); |
165 | switch (importKind) |
166 | { |
167 | case d_externalKind_function: |
168 | { |
169 | u32 typeIndex; |
170 | _ (ReadLEB_u32 (& typeIndex, & i_bytes, i_end)) |
171 | |
172 | _ (Module_AddFunction (io_module, typeIndex, & import)) |
173 | import = clearImport; |
174 | |
175 | io_module->numFuncImports++; |
176 | } |
177 | break; |
178 | |
179 | case d_externalKind_table: |
180 | // result = ParseType_Table (& i_bytes, i_end); |
181 | break; |
182 | |
183 | case d_externalKind_memory: |
184 | { |
185 | _ (ParseType_Memory (& io_module->memoryInfo, & i_bytes, i_end)); |
186 | io_module->memoryImported = true; |
187 | } |
188 | break; |
189 | |
190 | case d_externalKind_global: |
191 | { |
192 | i8 waType; |
193 | u8 type, isMutable; |
194 | |
195 | _ (ReadLEB_i7 (& waType, & i_bytes, i_end)); |
196 | _ (NormalizeType (& type, waType)); |
197 | _ (ReadLEB_u7 (& isMutable, & i_bytes, i_end)); m3log (parse, " global: %s mutable=%d" , c_waTypes [type], (u32) isMutable); |
198 | |
199 | IM3Global global; |
200 | _ (Module_AddGlobal (io_module, & global, type, isMutable, true /* isImport */)); |
201 | global->import = import; |
202 | import = clearImport; |
203 | } |
204 | break; |
205 | |
206 | default: |
207 | _throw (m3Err_wasmMalformed); |
208 | } |
209 | |
210 | FreeImportInfo (& import); |
211 | } |
212 | |
213 | _catch: |
214 | |
215 | FreeImportInfo (& import); |
216 | |
217 | return result; |
218 | } |
219 | |
220 | |
221 | M3Result ParseSection_Export (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
222 | { |
223 | M3Result result = m3Err_none; |
224 | const char * utf8 = NULL; |
225 | |
226 | u32 numExports; |
227 | _ (ReadLEB_u32 (& numExports, & i_bytes, i_end)); m3log (parse, "** Export [%d]" , numExports); |
228 | |
229 | _throwif("too many exports" , numExports > d_m3MaxSaneExportsCount); |
230 | |
231 | for (u32 i = 0; i < numExports; ++i) |
232 | { |
233 | u8 exportKind; |
234 | u32 index; |
235 | |
236 | _ (Read_utf8 (& utf8, & i_bytes, i_end)); |
237 | _ (Read_u8 (& exportKind, & i_bytes, i_end)); |
238 | _ (ReadLEB_u32 (& index, & i_bytes, i_end)); m3log (parse, " index: %3d; kind: %d; export: '%s'; " , index, (u32) exportKind, utf8); |
239 | |
240 | if (exportKind == d_externalKind_function) |
241 | { |
242 | _throwif(m3Err_wasmMalformed, index >= io_module->numFunctions); |
243 | IM3Function func = &(io_module->functions [index]); |
244 | if (func->numNames < d_m3MaxDuplicateFunctionImpl) |
245 | { |
246 | func->names[func->numNames++] = utf8; |
247 | utf8 = NULL; // ownership transferred to M3Function |
248 | } |
249 | } |
250 | else if (exportKind == d_externalKind_global) |
251 | { |
252 | _throwif(m3Err_wasmMalformed, index >= io_module->numGlobals); |
253 | IM3Global global = &(io_module->globals [index]); |
254 | m3_Free (global->name); |
255 | global->name = utf8; |
256 | utf8 = NULL; // ownership transferred to M3Global |
257 | } |
258 | |
259 | m3_Free (utf8); |
260 | } |
261 | |
262 | _catch: |
263 | m3_Free (utf8); |
264 | return result; |
265 | } |
266 | |
267 | |
268 | M3Result ParseSection_Start (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
269 | { |
270 | M3Result result = m3Err_none; |
271 | |
272 | u32 startFuncIndex; |
273 | _ (ReadLEB_u32 (& startFuncIndex, & i_bytes, i_end)); m3log (parse, "** Start Function: %d" , startFuncIndex); |
274 | |
275 | if (startFuncIndex < io_module->numFunctions) |
276 | { |
277 | io_module->startFunction = startFuncIndex; |
278 | } |
279 | else result = "start function index out of bounds" ; |
280 | |
281 | _catch: return result; |
282 | } |
283 | |
284 | |
285 | M3Result Parse_InitExpr (M3Module * io_module, bytes_t * io_bytes, cbytes_t i_end) |
286 | { |
287 | M3Result result = m3Err_none; |
288 | |
289 | // this doesn't generate code pages. just walks the wasm bytecode to find the end |
290 | |
291 | #if defined(d_m3PreferStaticAlloc) |
292 | static M3Compilation compilation; |
293 | #else |
294 | M3Compilation compilation; |
295 | #endif |
296 | compilation = (M3Compilation){ .runtime = NULL, .module = io_module, .wasm = * io_bytes, .wasmEnd = i_end }; |
297 | |
298 | result = CompileBlockStatements (& compilation); |
299 | |
300 | * io_bytes = compilation.wasm; |
301 | |
302 | return result; |
303 | } |
304 | |
305 | |
306 | M3Result ParseSection_Element (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
307 | { |
308 | M3Result result = m3Err_none; |
309 | |
310 | u32 numSegments; |
311 | _ (ReadLEB_u32 (& numSegments, & i_bytes, i_end)); m3log (parse, "** Element [%d]" , numSegments); |
312 | |
313 | _throwif ("too many element segments" , numSegments > d_m3MaxSaneElementSegments); |
314 | |
315 | io_module->elementSection = i_bytes; |
316 | io_module->elementSectionEnd = i_end; |
317 | io_module->numElementSegments = numSegments; |
318 | |
319 | _catch: return result; |
320 | } |
321 | |
322 | |
323 | M3Result ParseSection_Code (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
324 | { |
325 | M3Result result; |
326 | |
327 | u32 numFunctions; |
328 | _ (ReadLEB_u32 (& numFunctions, & i_bytes, i_end)); m3log (parse, "** Code [%d]" , numFunctions); |
329 | |
330 | if (numFunctions != io_module->numFunctions - io_module->numFuncImports) |
331 | { |
332 | _throw ("mismatched function count in code section" ); |
333 | } |
334 | |
335 | for (u32 f = 0; f < numFunctions; ++f) |
336 | { |
337 | const u8 * start = i_bytes; |
338 | |
339 | u32 size; |
340 | _ (ReadLEB_u32 (& size, & i_bytes, i_end)); |
341 | |
342 | if (size) |
343 | { |
344 | const u8 * ptr = i_bytes; |
345 | i_bytes += size; |
346 | |
347 | if (i_bytes <= i_end) |
348 | { |
349 | /* |
350 | u32 numLocalBlocks; |
351 | _ (ReadLEB_u32 (& numLocalBlocks, & ptr, i_end)); m3log (parse, " code size: %-4d", size); |
352 | |
353 | u32 numLocals = 0; |
354 | |
355 | for (u32 l = 0; l < numLocalBlocks; ++l) |
356 | { |
357 | u32 varCount; |
358 | i8 wasmType; |
359 | u8 normalType; |
360 | |
361 | _ (ReadLEB_u32 (& varCount, & ptr, i_end)); |
362 | _ (ReadLEB_i7 (& wasmType, & ptr, i_end)); |
363 | _ (NormalizeType (& normalType, wasmType)); |
364 | |
365 | numLocals += varCount; m3log (parse, " %2d locals; type: '%s'", varCount, c_waTypes [normalType]); |
366 | } |
367 | */ |
368 | |
369 | IM3Function func = Module_GetFunction (io_module, f + io_module->numFuncImports); |
370 | |
371 | func->module = io_module; |
372 | func->wasm = start; |
373 | func->wasmEnd = i_bytes; |
374 | //func->ownsWasmCode = io_module->hasWasmCodeCopy; |
375 | // func->numLocals = numLocals; |
376 | } |
377 | else _throw (m3Err_wasmSectionOverrun); |
378 | } |
379 | } |
380 | |
381 | _catch: |
382 | |
383 | if (not result and i_bytes != i_end) |
384 | result = m3Err_wasmSectionUnderrun; |
385 | |
386 | return result; |
387 | } |
388 | |
389 | |
390 | M3Result ParseSection_Data (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
391 | { |
392 | M3Result result = m3Err_none; |
393 | |
394 | u32 numDataSegments; |
395 | _ (ReadLEB_u32 (& numDataSegments, & i_bytes, i_end)); m3log (parse, "** Data [%d]" , numDataSegments); |
396 | |
397 | _throwif("too many data segments" , numDataSegments > d_m3MaxSaneDataSegments); |
398 | |
399 | io_module->dataSegments = m3_AllocArray (M3DataSegment, numDataSegments); |
400 | _throwifnull(io_module->dataSegments); |
401 | io_module->numDataSegments = numDataSegments; |
402 | |
403 | for (u32 i = 0; i < numDataSegments; ++i) |
404 | { |
405 | M3DataSegment * segment = & io_module->dataSegments [i]; |
406 | |
407 | _ (ReadLEB_u32 (& segment->memoryRegion, & i_bytes, i_end)); |
408 | |
409 | segment->initExpr = i_bytes; |
410 | _ (Parse_InitExpr (io_module, & i_bytes, i_end)); |
411 | segment->initExprSize = (u32) (i_bytes - segment->initExpr); |
412 | |
413 | _throwif (m3Err_wasmMissingInitExpr, segment->initExprSize <= 1); |
414 | |
415 | _ (ReadLEB_u32 (& segment->size, & i_bytes, i_end)); |
416 | segment->data = i_bytes; m3log (parse, " segment [%u] memory: %u; expr-size: %d; size: %d" , |
417 | i, segment->memoryRegion, segment->initExprSize, segment->size); |
418 | i_bytes += segment->size; |
419 | |
420 | _throwif("data segment underflow" , i_bytes > i_end); |
421 | } |
422 | |
423 | _catch: |
424 | |
425 | return result; |
426 | } |
427 | |
428 | |
429 | M3Result ParseSection_Memory (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
430 | { |
431 | M3Result result = m3Err_none; |
432 | |
433 | // TODO: MVP; assert no memory imported |
434 | |
435 | u32 numMemories; |
436 | _ (ReadLEB_u32 (& numMemories, & i_bytes, i_end)); m3log (parse, "** Memory [%d]" , numMemories); |
437 | |
438 | _throwif (m3Err_tooManyMemorySections, numMemories != 1); |
439 | |
440 | ParseType_Memory (& io_module->memoryInfo, & i_bytes, i_end); |
441 | |
442 | _catch: return result; |
443 | } |
444 | |
445 | |
446 | M3Result ParseSection_Global (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
447 | { |
448 | M3Result result = m3Err_none; |
449 | |
450 | u32 numGlobals; |
451 | _ (ReadLEB_u32 (& numGlobals, & i_bytes, i_end)); m3log (parse, "** Global [%d]" , numGlobals); |
452 | |
453 | _throwif("too many globals" , numGlobals > d_m3MaxSaneGlobalsCount); |
454 | |
455 | for (u32 i = 0; i < numGlobals; ++i) |
456 | { |
457 | i8 waType; |
458 | u8 type, isMutable; |
459 | |
460 | _ (ReadLEB_i7 (& waType, & i_bytes, i_end)); |
461 | _ (NormalizeType (& type, waType)); |
462 | _ (ReadLEB_u7 (& isMutable, & i_bytes, i_end)); m3log (parse, " global: [%d] %s mutable: %d" , i, c_waTypes [type], (u32) isMutable); |
463 | |
464 | IM3Global global; |
465 | _ (Module_AddGlobal (io_module, & global, type, isMutable, false /* isImport */)); |
466 | |
467 | global->initExpr = i_bytes; |
468 | _ (Parse_InitExpr (io_module, & i_bytes, i_end)); |
469 | global->initExprSize = (u32) (i_bytes - global->initExpr); |
470 | |
471 | _throwif (m3Err_wasmMissingInitExpr, global->initExprSize <= 1); |
472 | } |
473 | |
474 | _catch: return result; |
475 | } |
476 | |
477 | |
478 | M3Result ParseSection_Name (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
479 | { |
480 | M3Result result; |
481 | |
482 | cstr_t name; |
483 | |
484 | while (i_bytes < i_end) |
485 | { |
486 | u8 nameType; |
487 | u32 payloadLength; |
488 | |
489 | _ (ReadLEB_u7 (& nameType, & i_bytes, i_end)); |
490 | _ (ReadLEB_u32 (& payloadLength, & i_bytes, i_end)); |
491 | |
492 | bytes_t start = i_bytes; |
493 | if (nameType == 1) |
494 | { |
495 | u32 numNames; |
496 | _ (ReadLEB_u32 (& numNames, & i_bytes, i_end)); |
497 | |
498 | _throwif("too many names" , numNames > d_m3MaxSaneFunctionsCount); |
499 | |
500 | for (u32 i = 0; i < numNames; ++i) |
501 | { |
502 | u32 index; |
503 | _ (ReadLEB_u32 (& index, & i_bytes, i_end)); |
504 | _ (Read_utf8 (& name, & i_bytes, i_end)); |
505 | |
506 | if (index < io_module->numFunctions) |
507 | { |
508 | IM3Function func = &(io_module->functions [index]); |
509 | if (func->numNames == 0) |
510 | { |
511 | func->names[0] = name; m3log (parse, " naming function%5d: %s" , index, name); |
512 | func->numNames = 1; |
513 | name = NULL; // transfer ownership |
514 | } |
515 | // else m3log (parse, "prenamed: %s", io_module->functions [index].name); |
516 | } |
517 | |
518 | m3_Free (name); |
519 | } |
520 | } |
521 | |
522 | i_bytes = start + payloadLength; |
523 | } |
524 | |
525 | _catch: return result; |
526 | } |
527 | |
528 | |
529 | M3Result ParseSection_Custom (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
530 | { |
531 | M3Result result; |
532 | |
533 | cstr_t name; |
534 | _ (Read_utf8 (& name, & i_bytes, i_end)); |
535 | m3log (parse, "** Custom: '%s'" , name); |
536 | if (strcmp (name, "name" ) == 0) { |
537 | _ (ParseSection_Name(io_module, i_bytes, i_end)); |
538 | } else if (io_module->environment->customSectionHandler) { |
539 | _ (io_module->environment->customSectionHandler(io_module, name, i_bytes, i_end)); |
540 | } |
541 | |
542 | m3_Free (name); |
543 | |
544 | _catch: return result; |
545 | } |
546 | |
547 | |
548 | M3Result ParseModuleSection (M3Module * o_module, u8 i_sectionType, bytes_t i_bytes, u32 i_numBytes) |
549 | { |
550 | M3Result result = m3Err_none; |
551 | |
552 | typedef M3Result (* M3Parser) (M3Module *, bytes_t, cbytes_t); |
553 | |
554 | static M3Parser s_parsers [] = |
555 | { |
556 | ParseSection_Custom, // 0 |
557 | ParseSection_Type, // 1 |
558 | ParseSection_Import, // 2 |
559 | ParseSection_Function, // 3 |
560 | NULL, // 4: TODO Table |
561 | ParseSection_Memory, // 5 |
562 | ParseSection_Global, // 6 |
563 | ParseSection_Export, // 7 |
564 | ParseSection_Start, // 8 |
565 | ParseSection_Element, // 9 |
566 | ParseSection_Code, // 10 |
567 | ParseSection_Data, // 11 |
568 | NULL, // 12: TODO DataCount |
569 | }; |
570 | |
571 | M3Parser parser = NULL; |
572 | |
573 | if (i_sectionType <= 12) |
574 | parser = s_parsers [i_sectionType]; |
575 | |
576 | if (parser) |
577 | { |
578 | cbytes_t end = i_bytes + i_numBytes; |
579 | result = parser (o_module, i_bytes, end); |
580 | } |
581 | else |
582 | { |
583 | m3log (parse, " skipped section type: %d" , (u32) i_sectionType); |
584 | } |
585 | |
586 | return result; |
587 | } |
588 | |
589 | |
590 | M3Result m3_ParseModule (IM3Environment i_environment, IM3Module * o_module, cbytes_t i_bytes, u32 i_numBytes) |
591 | { |
592 | IM3Module module; m3log (parse, "load module: %d bytes" , i_numBytes); |
593 | _try { |
594 | module = m3_AllocStruct (M3Module); |
595 | _throwifnull (module); |
596 | module->name = ".unnamed" ; m3log (parse, "load module: %d bytes" , i_numBytes); |
597 | module->startFunction = -1; |
598 | //module->hasWasmCodeCopy = false; |
599 | module->environment = i_environment; |
600 | |
601 | const u8 * pos = i_bytes; |
602 | const u8 * end = pos + i_numBytes; |
603 | |
604 | module->wasmStart = pos; |
605 | module->wasmEnd = end; |
606 | |
607 | u32 magic, version; |
608 | _ (Read_u32 (& magic, & pos, end)); |
609 | _ (Read_u32 (& version, & pos, end)); |
610 | |
611 | _throwif (m3Err_wasmMalformed, magic != 0x6d736100); |
612 | _throwif (m3Err_incompatibleWasmVersion, version != 1); |
613 | |
614 | static const u8 sectionsOrder[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 10, 11, 0 }; // 0 is a placeholder |
615 | u8 expectedSection = 0; |
616 | |
617 | while (pos < end) |
618 | { |
619 | u8 section; |
620 | _ (ReadLEB_u7 (& section, & pos, end)); |
621 | |
622 | if (section != 0) { |
623 | // Ensure sections appear only once and in order |
624 | while (sectionsOrder[expectedSection++] != section) { |
625 | _throwif(m3Err_misorderedWasmSection, expectedSection >= 12); |
626 | } |
627 | } |
628 | |
629 | u32 sectionLength; |
630 | _ (ReadLEB_u32 (& sectionLength, & pos, end)); |
631 | _throwif(m3Err_wasmMalformed, pos + sectionLength > end); |
632 | |
633 | _ (ParseModuleSection (module, section, pos, sectionLength)); |
634 | |
635 | pos += sectionLength; |
636 | } |
637 | |
638 | } _catch: |
639 | |
640 | if (result) |
641 | { |
642 | m3_FreeModule (module); |
643 | module = NULL; |
644 | } |
645 | |
646 | * o_module = module; |
647 | |
648 | return result; |
649 | } |
650 | |