/src/wasm3/source/m3_module.c
Line | Count | Source |
1 | | // |
2 | | // m3_module.c |
3 | | // |
4 | | // Created by Steven Massey on 5/7/19. |
5 | | // Copyright © 2019 Steven Massey. All rights reserved. |
6 | | // |
7 | | |
8 | | #include "m3_env.h" |
9 | | #include "m3_exception.h" |
10 | | |
11 | | |
12 | | void Module_FreeFunctions (IM3Module i_module) |
13 | 33.5k | { |
14 | 65.3k | for (u32 i = 0; i < i_module->numFunctions; ++i) { |
15 | 31.7k | IM3Function func = &i_module->functions[i]; |
16 | 31.7k | Function_Release(func); |
17 | 31.7k | } |
18 | 33.5k | } |
19 | | |
20 | | |
21 | | void m3_FreeModule (IM3Module i_module) |
22 | 33.5k | { |
23 | 33.5k | if (i_module) { |
24 | 33.5k | m3log(module, "freeing module: %s (funcs: %d; segments: %d)", |
25 | 33.5k | i_module->name, i_module->numFunctions, i_module->numDataSegments); |
26 | | |
27 | 33.5k | Module_FreeFunctions(i_module); |
28 | | |
29 | 33.5k | m3_Free(i_module->functions); |
30 | | //m3_Free (i_module->imports); |
31 | 33.5k | m3_Free(i_module->funcTypes); |
32 | 33.5k | m3_Free(i_module->dataSegments); |
33 | | |
34 | 35.7k | for (u32 i = 0; i < i_module->numTables; ++i) { |
35 | 2.18k | IM3Table table = i_module->tables[i]; |
36 | | |
37 | | // a slot may point at a table another module owns; that module |
38 | | // frees it |
39 | 2.18k | if (not table or table->owner != i_module) { |
40 | 0 | continue; |
41 | 0 | } |
42 | | |
43 | 2.18k | if (table->elements and i_module->runtime) { |
44 | 831 | i_module->runtime->tableElementsUsed -= table->size; |
45 | 831 | } |
46 | 2.18k | m3_Free(table->elements); |
47 | 2.18k | FreeImportInfo(&table->import); |
48 | 2.18k | m3_Free(table); |
49 | 2.18k | } |
50 | 33.5k | m3_Free(i_module->tables); |
51 | | |
52 | 221M | for (u32 i = 0; i < i_module->numElementSegments; ++i) { |
53 | 221M | m3_Free(i_module->elementSegments[i].resolved); |
54 | 221M | } |
55 | 33.5k | m3_Free(i_module->elementSegments); |
56 | 33.5k | m3_Free(i_module->declaredFuncs); |
57 | | |
58 | 35.0k | for (u32 i = 0; i < i_module->numGlobals; ++i) { |
59 | 1.49k | FreeImportInfo(&(i_module->globals[i].import)); |
60 | 1.49k | } |
61 | 33.5k | m3_Free(i_module->globals); |
62 | | |
63 | 33.5k | #if d_m3HasExceptionHandling || d_m3HasStackSwitching |
64 | 34.4k | for (u32 i = 0; i < i_module->numTags; ++i) { |
65 | 914 | FreeImportInfo(&(i_module->tags[i].import)); |
66 | 914 | } |
67 | 33.5k | m3_Free(i_module->tags); |
68 | 33.5k | #endif |
69 | | |
70 | 42.2k | for (u32 i = 0; i < i_module->numMemories; ++i) { |
71 | 8.63k | IM3Memory memory = i_module->memories[i]; |
72 | | |
73 | | // a slot may point at a memory another module owns; that module |
74 | | // frees it |
75 | 8.63k | if (not memory or memory->owner != i_module) { |
76 | 0 | continue; |
77 | 0 | } |
78 | | |
79 | 8.63k | FreeMemoryBlock(memory); |
80 | 8.63k | FreeImportInfo(&memory->import); |
81 | 8.63k | m3_Free(memory); |
82 | 8.63k | } |
83 | 33.5k | m3_Free(i_module->memories); |
84 | 33.5k | FreeMemoryBlock(&i_module->emptyMemory); |
85 | | |
86 | 34.1k | for (u32 i = 0; i < i_module->numExports; ++i) { |
87 | 569 | m3_Free(i_module->exports[i].name); |
88 | 569 | } |
89 | 33.5k | m3_Free(i_module->exports); |
90 | | |
91 | 33.5k | #if d_m3HasSnapshots |
92 | 33.5k | M3EmbeddedSnapshot* snap = i_module->snapshots; |
93 | 34.3k | while (snap) { |
94 | 818 | M3EmbeddedSnapshot* next = snap->next; |
95 | 818 | m3_Free(snap->name); |
96 | 818 | m3_Free(snap); |
97 | 818 | snap = next; |
98 | 818 | } |
99 | 33.5k | #endif |
100 | | |
101 | 33.5k | m3_Free(i_module); |
102 | 33.5k | } |
103 | 33.5k | } |
104 | | |
105 | | |
106 | | // Supplies the value of an imported global. Unlike m3_SetGlobal this ignores |
107 | | // mutability: the import's mutability governs what the wasm code may do with it, |
108 | | // not whether the host may provide it in the first place. |
109 | | M3Result m3_LinkGlobal (IM3Module io_module, |
110 | | const char* const i_moduleName, |
111 | | const char* const i_globalName, |
112 | | const IM3TaggedValue i_value) |
113 | 0 | { |
114 | 0 | M3Result result = m3Err_globalLookupFailed; |
115 | |
|
116 | 0 | for (u32 i = 0; i < io_module->numGlobals; ++i) { |
117 | 0 | IM3Global g = &io_module->globals[i]; |
118 | |
|
119 | 0 | if (not (g->import.moduleUtf8 and g->import.fieldUtf8)) { |
120 | 0 | continue; |
121 | 0 | } |
122 | | |
123 | 0 | if (strcmp(g->import.moduleUtf8, i_moduleName) != 0 or |
124 | 0 | strcmp(g->import.fieldUtf8, i_globalName) != 0) { |
125 | 0 | continue; |
126 | 0 | } |
127 | | |
128 | 0 | if (g->type != i_value->type) { |
129 | 0 | return m3Err_globalTypeMismatch; |
130 | 0 | } |
131 | | |
132 | 0 | switch (i_value->type) { |
133 | 0 | case c_m3Type_i32: g->i32Value = i_value->value.i32; break; |
134 | 0 | case c_m3Type_i64: g->i64Value = i_value->value.i64; break; |
135 | 0 | #if d_m3HasFloat |
136 | 0 | case c_m3Type_f32: g->f32Value = i_value->value.f32; break; |
137 | 0 | case c_m3Type_f64: g->f64Value = i_value->value.f64; break; |
138 | 0 | #endif |
139 | 0 | default: return m3Err_invalidTypeId; |
140 | 0 | } |
141 | | |
142 | 0 | result = m3Err_none; |
143 | 0 | } |
144 | | |
145 | 0 | return result; |
146 | 0 | } |
147 | | |
148 | | |
149 | | // The function count is final by the time anything can declare a reference: |
150 | | // imports and the function section both precede the global, export and element |
151 | | // sections, and those in turn precede the code section. |
152 | | M3Result Module_DeclareFunction (IM3Module io_module, u32 i_index) |
153 | 480 | { |
154 | 480 | M3Result result = m3Err_none; |
155 | | |
156 | 480 | if (i_index >= io_module->numFunctions) { |
157 | 0 | return "function index out of range"; |
158 | 0 | } |
159 | | |
160 | 480 | if (not io_module->declaredFuncs) { |
161 | 95 | io_module->declaredFuncs = m3_AllocArray(u8, (io_module->numFunctions + 7) / 8); |
162 | 95 | _throwifnull(io_module->declaredFuncs); |
163 | 95 | } |
164 | | |
165 | 480 | io_module->declaredFuncs[i_index / 8] |= (u8)(1u << (i_index % 8)); |
166 | | |
167 | 480 | _catch: return result; |
168 | 480 | } |
169 | | |
170 | | |
171 | | bool Module_IsFunctionDeclared (IM3Module i_module, u32 i_index) |
172 | 231 | { |
173 | 231 | if (not i_module->declaredFuncs or i_index >= i_module->numFunctions) { |
174 | 1 | return false; |
175 | 1 | } |
176 | | |
177 | 230 | return (i_module->declaredFuncs[i_index / 8] & (1u << (i_index % 8))) != 0; |
178 | 231 | } |
179 | | |
180 | | |
181 | | // Appends an entry to the module's memory index space. The M3Memory is |
182 | | // allocated separately from the index so that another module importing it can |
183 | | // hold the same pointer. |
184 | | M3Result Module_AddMemory (IM3Module io_module, IM3Memory* o_memory, const M3MemoryInfo* i_info, bool i_isImported) |
185 | 8.63k | { |
186 | 8.63k | IM3Memory memory = NULL; |
187 | 8.63k | _try { |
188 | 8.63k | u32 index = io_module->numMemories; |
189 | | |
190 | 8.63k | memory = m3_AllocStruct(M3Memory); |
191 | 8.63k | _throwifnull(memory); |
192 | | |
193 | 8.63k | io_module->memories = m3_ReallocArray(IM3Memory, io_module->memories, index + 1, index); |
194 | 8.63k | _throwifnull(io_module->memories); |
195 | | |
196 | 8.63k | memory->owner = io_module; |
197 | 8.63k | memory->imported = i_isImported; |
198 | 8.63k | memory->initPages = i_info->initPages; |
199 | 8.63k | memory->maxPages = i_info->maxPages; |
200 | 8.63k | memory->pageSize = i_info->pageSize; |
201 | 8.63k | memory->hasMax = i_info->hasMax; |
202 | 8.63k | memory->isMemory64 = i_info->isMemory64; |
203 | 8.63k | memory->isShared = i_info->isShared; |
204 | | |
205 | 8.63k | io_module->memories[index] = memory; |
206 | 8.63k | io_module->numMemories = index + 1; |
207 | | |
208 | 8.63k | if (o_memory) { |
209 | 730 | *o_memory = memory; |
210 | 730 | } |
211 | | |
212 | 8.63k | return result; |
213 | | |
214 | 8.63k | } _catch: |
215 | 0 | m3_Free(memory); |
216 | 0 | return result; |
217 | 8.63k | } |
218 | | |
219 | | |
220 | | // Appends an entry to the module's table index space. Allocated separately from |
221 | | // the index, like a memory, so another module importing it can hold the same |
222 | | // pointer. |
223 | | M3Result Module_AddTable (IM3Module io_module, IM3Table* o_table, const M3TableInfo* i_info, bool i_isImported) |
224 | 2.18k | { |
225 | 2.18k | IM3Table table = NULL; |
226 | 2.18k | _try { |
227 | 2.18k | u32 index = io_module->numTables; |
228 | | |
229 | 2.18k | table = m3_AllocStruct(M3Table); |
230 | 2.18k | _throwifnull(table); |
231 | | |
232 | 2.18k | io_module->tables = m3_ReallocArray(IM3Table, io_module->tables, index + 1, index); |
233 | 2.18k | _throwifnull(io_module->tables); |
234 | | |
235 | 2.18k | table->owner = io_module; |
236 | 2.18k | table->imported = i_isImported; |
237 | 2.18k | table->type = i_info->elemType; |
238 | 2.18k | table->size = i_info->initSize; |
239 | 2.18k | table->initSize = i_info->initSize; |
240 | 2.18k | table->maxSize = i_info->maxSize; |
241 | 2.18k | table->hasMax = i_info->hasMax; |
242 | 2.18k | table->isTable64 = i_info->isTable64; |
243 | | |
244 | 2.18k | io_module->tables[index] = table; |
245 | 2.18k | io_module->numTables = index + 1; |
246 | | |
247 | 2.18k | if (o_table) { |
248 | 981 | *o_table = table; |
249 | 981 | } |
250 | | |
251 | 2.18k | return result; |
252 | | |
253 | 2.18k | } _catch: |
254 | 0 | m3_Free(table); |
255 | 0 | return result; |
256 | 2.18k | } |
257 | | |
258 | | |
259 | | #if d_m3HasExceptionHandling || d_m3HasStackSwitching |
260 | | |
261 | | M3Result Module_AddTag (IM3Module io_module, IM3Tag* o_tag, IM3FuncType i_type, bool i_isImported) |
262 | 914 | { |
263 | 914 | _try { |
264 | 914 | u32 index = io_module->numTags++; |
265 | | |
266 | 914 | io_module->tags = m3_ReallocArray(M3Tag, io_module->tags, io_module->numTags, index); |
267 | 914 | _throwifnull(io_module->tags); |
268 | 914 | M3Tag* tag = &io_module->tags[index]; |
269 | | |
270 | 914 | tag->type = i_type; |
271 | 914 | tag->imported = i_isImported; |
272 | 914 | tag->resolved = NULL; |
273 | 914 | memset(&tag->import, 0, sizeof(tag->import)); |
274 | | |
275 | 914 | if (o_tag) { |
276 | 415 | *o_tag = tag; |
277 | 415 | } |
278 | | |
279 | 914 | } _catch: |
280 | 914 | return result; |
281 | 914 | } |
282 | | |
283 | | #endif // d_m3HasExceptionHandling || d_m3HasStackSwitching |
284 | | |
285 | | |
286 | | #if d_m3HasStackSwitching |
287 | | |
288 | | // The continuation type a spelled-out reference names. Reference types carry |
289 | | // the canonical index, and the module's own type space is where a name for it |
290 | | // can be found again - which switch needs, because the type of the peer it |
291 | | // suspends into is only written down as the last parameter of the type it |
292 | | // switches to. |
293 | | IM3FuncType Module_ContTypeOfRef (IM3Module i_module, m3type_t i_refType) |
294 | 0 | { |
295 | 0 | if (not IsSpelledRefType(i_refType)) { |
296 | 0 | return NULL; |
297 | 0 | } |
298 | | |
299 | 0 | u32 heap = HeapTypeOf(i_refType); |
300 | |
|
301 | 0 | if (heap == d_m3Type_heapAbstract) { |
302 | 0 | return NULL; |
303 | 0 | } |
304 | | |
305 | 0 | for (u32 i = 0; i < i_module->numFuncTypes; ++i) { |
306 | 0 | IM3FuncType ftype = i_module->funcTypes[i]; |
307 | |
|
308 | 0 | if (ftype and ftype->isContinuation and ftype->canonicalIndex == heap) { |
309 | 0 | return ftype; |
310 | 0 | } |
311 | 0 | } |
312 | | |
313 | 0 | return NULL; |
314 | 0 | } |
315 | | |
316 | | #endif // d_m3HasStackSwitching |
317 | | |
318 | | |
319 | | M3Result Module_AddGlobal (IM3Module io_module, IM3Global* o_global, m3type_t i_type, bool i_mutable, bool i_isImported) |
320 | 1.49k | { |
321 | 1.49k | _try { |
322 | 1.49k | u32 index = io_module->numGlobals++; |
323 | | |
324 | 1.49k | io_module->globals = m3_ReallocArray(M3Global, io_module->globals, io_module->numGlobals, index); |
325 | 1.49k | _throwifnull(io_module->globals); |
326 | 1.49k | M3Global* global = &io_module->globals[index]; |
327 | | |
328 | 1.49k | global->type = i_type; |
329 | 1.49k | global->imported = i_isImported; |
330 | 1.49k | global->isMutable = i_mutable; |
331 | | |
332 | 1.49k | if (o_global) { |
333 | 1.49k | *o_global = global; |
334 | 1.49k | } |
335 | | |
336 | 1.49k | } _catch: |
337 | 1.49k | return result; |
338 | 1.49k | } |
339 | | |
340 | | M3Result Module_PreallocFunctions (IM3Module io_module, u32 i_totalFunctions) |
341 | 60.5k | { |
342 | 60.5k | _try { |
343 | 60.5k | if (i_totalFunctions > io_module->allFunctions) { |
344 | 28.7k | io_module->functions = m3_ReallocArray(M3Function, io_module->functions, i_totalFunctions, io_module->allFunctions); |
345 | 28.7k | io_module->allFunctions = i_totalFunctions; |
346 | 28.7k | _throwifnull(io_module->functions); |
347 | 28.7k | } |
348 | 60.5k | } _catch: |
349 | 60.5k | return result; |
350 | 60.5k | } |
351 | | |
352 | | M3Result Module_AddFunction (IM3Module io_module, u32 i_typeIndex, IM3ImportInfo i_importInfo) |
353 | 31.7k | { |
354 | 31.7k | _try { |
355 | | |
356 | 31.7k | u32 index = io_module->numFunctions++; |
357 | 31.7k | _ (Module_PreallocFunctions(io_module, io_module->numFunctions)); |
358 | | |
359 | 31.7k | _throwif("type sig index out of bounds", i_typeIndex >= io_module->numFuncTypes); |
360 | | |
361 | 31.6k | IM3FuncType ft = io_module->funcTypes[i_typeIndex]; |
362 | | |
363 | 31.6k | IM3Function func = Module_GetFunction(io_module, index); |
364 | 31.6k | func->funcType = ft; |
365 | 31.6k | func->module = io_module; // an import has no body, but still belongs to this module |
366 | | |
367 | | #ifdef DEBUG |
368 | | func->index = index; |
369 | | #endif |
370 | | |
371 | 31.6k | if (i_importInfo and func->numNames == 0) { |
372 | 3.41k | func->import = *i_importInfo; |
373 | 3.41k | func->names[0] = i_importInfo->fieldUtf8; |
374 | 3.41k | func->numNames = 1; |
375 | 3.41k | } |
376 | | |
377 | 31.6k | m3log(module, " added function: %3d; sig: %d", index, i_typeIndex); |
378 | | |
379 | 31.7k | } _catch: |
380 | 31.7k | return result; |
381 | 31.6k | } |
382 | | |
383 | | #ifdef DEBUG |
384 | | void Module_GenerateNames (IM3Module i_module) |
385 | | { |
386 | | for (u32 i = 0; i < i_module->numFunctions; ++i) { |
387 | | IM3Function func = &i_module->functions[i]; |
388 | | |
389 | | if (func->numNames == 0) { |
390 | | char* buff = m3_AllocArray(char, 16); |
391 | | snprintf(buff, 16, "$func%d", i); |
392 | | func->names[0] = buff; |
393 | | func->numNames = 1; |
394 | | } |
395 | | } |
396 | | } |
397 | | #endif |
398 | | |
399 | | IM3Function Module_GetFunction (IM3Module i_module, u32 i_functionIndex) |
400 | 77.1k | { |
401 | 77.1k | IM3Function func = NULL; |
402 | | |
403 | 77.1k | if (i_functionIndex < i_module->numFunctions) { |
404 | 77.1k | func = &i_module->functions[i_functionIndex]; |
405 | | //func->module = i_module; |
406 | 77.1k | } |
407 | | |
408 | 77.1k | return func; |
409 | 77.1k | } |
410 | | |
411 | | |
412 | | const char* m3_GetModuleName (IM3Module i_module) |
413 | 0 | { |
414 | 0 | if (!i_module || !i_module->name) { |
415 | 0 | return ".unnamed"; |
416 | 0 | } |
417 | | |
418 | 0 | return i_module->name; |
419 | 0 | } |
420 | | |
421 | | void m3_SetModuleName (IM3Module i_module, const char* name) |
422 | 0 | { |
423 | 0 | if (i_module) { |
424 | 0 | i_module->name = name; |
425 | 0 | } |
426 | 0 | } |
427 | | |
428 | | IM3Runtime m3_GetModuleRuntime (IM3Module i_module) |
429 | 0 | { |
430 | 0 | return i_module ? i_module->runtime : NULL; |
431 | 0 | } |