Coverage Report

Created: 2026-09-01 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
3.67k
{
14
10.7k
    for (u32 i = 0; i < i_module->numFunctions; ++i)
15
7.07k
    {
16
7.07k
        IM3Function func = & i_module->functions [i];
17
7.07k
        Function_Release (func);
18
7.07k
    }
19
3.67k
}
20
21
22
void  m3_FreeModule  (IM3Module i_module)
23
3.67k
{
24
3.67k
    if (i_module)
25
3.67k
    {
26
3.67k
        m3log (module, "freeing module: %s (funcs: %d; segments: %d)",
27
3.67k
               i_module->name, i_module->numFunctions, i_module->numDataSegments);
28
29
3.67k
        Module_FreeFunctions (i_module);
30
31
3.67k
        m3_Free (i_module->functions);
32
        //m3_Free (i_module->imports);
33
3.67k
        m3_Free (i_module->funcTypes);
34
3.67k
        m3_Free (i_module->dataSegments);
35
36
4.16k
        for (u32 i = 0; i < i_module->numTables; ++i)
37
492
        {
38
492
            IM3Table table = i_module->tables [i];
39
40
            // a slot may point at a table another module owns; that module
41
            // frees it
42
492
            if (not table or table->owner != i_module)
43
0
                continue;
44
45
492
            m3_Free (table->elements);
46
492
            m3_Free (table->exportName);
47
492
            FreeImportInfo (& table->import);
48
492
            m3_Free (table);
49
492
        }
50
3.67k
        m3_Free (i_module->tables);
51
52
8.09k
        for (u32 i = 0; i < i_module->numElementSegments; ++i)
53
4.42k
            m3_Free (i_module->elementSegments[i].resolved);
54
3.67k
        m3_Free (i_module->elementSegments);
55
3.67k
        m3_Free (i_module->declaredFuncs);
56
57
4.02k
        for (u32 i = 0; i < i_module->numGlobals; ++i)
58
347
        {
59
347
            m3_Free (i_module->globals[i].name);
60
347
            FreeImportInfo(&(i_module->globals[i].import));
61
347
        }
62
3.67k
        m3_Free (i_module->globals);
63
64
3.67k
#if d_m3HasExceptionHandling
65
4.45k
        for (u32 i = 0; i < i_module->numTags; ++i)
66
774
        {
67
774
            m3_Free (i_module->tags[i].name);
68
774
            FreeImportInfo(&(i_module->tags[i].import));
69
774
        }
70
3.67k
        m3_Free (i_module->tags);
71
3.67k
#endif
72
73
8.42k
        for (u32 i = 0; i < i_module->numMemories; ++i)
74
4.74k
        {
75
4.74k
            IM3Memory memory = i_module->memories [i];
76
77
            // a slot may point at a memory another module owns; that module
78
            // frees it
79
4.74k
            if (not memory or memory->owner != i_module)
80
0
                continue;
81
82
4.74k
            m3_Free (memory->mallocated);
83
4.74k
            m3_Free (memory->exportName);
84
4.74k
            FreeImportInfo (& memory->import);
85
4.74k
            m3_Free (memory);
86
4.74k
        }
87
3.67k
        m3_Free (i_module->memories);
88
3.67k
        m3_Free (i_module->emptyMemory.mallocated);
89
90
91
3.67k
        m3_Free (i_module);
92
3.67k
    }
93
3.67k
}
94
95
96
// Supplies the value of an imported global. Unlike m3_SetGlobal this ignores
97
// mutability: the import's mutability governs what the wasm code may do with it,
98
// not whether the host may provide it in the first place.
99
M3Result  m3_LinkGlobal  (IM3Module            io_module,
100
                          const char * const   i_moduleName,
101
                          const char * const   i_globalName,
102
                          const IM3TaggedValue i_value)
103
0
{
104
0
    M3Result result = m3Err_globalLookupFailed;
105
106
0
    for (u32 i = 0; i < io_module->numGlobals; ++i)
107
0
    {
108
0
        IM3Global g = & io_module->globals [i];
109
110
0
        if (not (g->import.moduleUtf8 and g->import.fieldUtf8))
111
0
            continue;
112
113
0
        if (strcmp (g->import.moduleUtf8, i_moduleName) != 0 or
114
0
            strcmp (g->import.fieldUtf8, i_globalName) != 0)
115
0
            continue;
116
117
0
        if (g->type != i_value->type)
118
0
            return m3Err_globalTypeMismatch;
119
120
0
        switch (i_value->type) {
121
0
        case c_m3Type_i32: g->i32Value = i_value->value.i32; break;
122
0
        case c_m3Type_i64: g->i64Value = i_value->value.i64; break;
123
0
# if d_m3HasFloat
124
0
        case c_m3Type_f32: g->f32Value = i_value->value.f32; break;
125
0
        case c_m3Type_f64: g->f64Value = i_value->value.f64; break;
126
0
# endif
127
0
        default: return m3Err_invalidTypeId;
128
0
        }
129
130
0
        result = m3Err_none;
131
0
    }
132
133
0
    return result;
134
0
}
135
136
137
// The function count is final by the time anything can declare a reference:
138
// imports and the function section both precede the global, export and element
139
// sections, and those in turn precede the code section.
140
M3Result  Module_DeclareFunction  (IM3Module io_module, u32 i_index)
141
101
{
142
101
    M3Result result = m3Err_none;
143
144
101
    if (i_index >= io_module->numFunctions)
145
0
        return "function index out of range";
146
147
101
    if (not io_module->declaredFuncs)
148
30
    {
149
30
        io_module->declaredFuncs = m3_AllocArray (u8, (io_module->numFunctions + 7) / 8);
150
30
        _throwifnull (io_module->declaredFuncs);
151
30
    }
152
153
101
    io_module->declaredFuncs [i_index / 8] |= (u8) (1u << (i_index % 8));
154
155
101
    _catch: return result;
156
101
}
157
158
159
bool  Module_IsFunctionDeclared  (IM3Module i_module, u32 i_index)
160
103
{
161
103
    if (not i_module->declaredFuncs or i_index >= i_module->numFunctions)
162
1
        return false;
163
164
102
    return (i_module->declaredFuncs [i_index / 8] & (1u << (i_index % 8))) != 0;
165
103
}
166
167
168
// Appends an entry to the module's memory index space. The M3Memory is
169
// allocated separately from the index so that another module importing it can
170
// hold the same pointer.
171
M3Result  Module_AddMemory  (IM3Module io_module, IM3Memory * o_memory, const M3MemoryInfo * i_info, bool i_isImported)
172
4.74k
{
173
4.74k
    IM3Memory memory = NULL;
174
4.74k
_try {
175
4.74k
    u32 index = io_module->numMemories;
176
177
4.74k
    memory = m3_AllocStruct (M3Memory);
178
4.74k
    _throwifnull (memory);
179
180
4.74k
    io_module->memories = m3_ReallocArray (IM3Memory, io_module->memories, index + 1, index);
181
4.74k
    _throwifnull (io_module->memories);
182
183
4.74k
    memory->owner      = io_module;
184
4.74k
    memory->imported   = i_isImported;
185
4.74k
    memory->initPages  = i_info->initPages;
186
4.74k
    memory->maxPages   = i_info->maxPages;
187
4.74k
    memory->pageSize   = i_info->pageSize;
188
4.74k
    memory->hasMax     = i_info->hasMax;
189
4.74k
    memory->isMemory64 = i_info->isMemory64;
190
191
4.74k
    io_module->memories [index] = memory;
192
4.74k
    io_module->numMemories = index + 1;
193
194
4.74k
    if (o_memory)
195
1.19k
        * o_memory = memory;
196
197
4.74k
    return result;
198
199
4.74k
} _catch:
200
0
    m3_Free (memory);
201
0
    return result;
202
4.74k
}
203
204
205
// Appends an entry to the module's table index space. Allocated separately from
206
// the index, like a memory, so another module importing it can hold the same
207
// pointer.
208
M3Result  Module_AddTable  (IM3Module io_module, IM3Table * o_table, const M3TableInfo * i_info, bool i_isImported)
209
492
{
210
492
    IM3Table table = NULL;
211
492
_try {
212
492
    u32 index = io_module->numTables;
213
214
492
    table = m3_AllocStruct (M3Table);
215
492
    _throwifnull (table);
216
217
492
    io_module->tables = m3_ReallocArray (IM3Table, io_module->tables, index + 1, index);
218
492
    _throwifnull (io_module->tables);
219
220
492
    table->owner     = io_module;
221
492
    table->imported  = i_isImported;
222
492
    table->type      = i_info->elemType;
223
492
    table->size      = i_info->initSize;
224
492
    table->initSize  = i_info->initSize;
225
492
    table->maxSize   = i_info->maxSize;
226
492
    table->hasMax    = i_info->hasMax;
227
492
    table->isTable64 = i_info->isTable64;
228
229
492
    io_module->tables [index] = table;
230
492
    io_module->numTables = index + 1;
231
232
492
    if (o_table)
233
175
        * o_table = table;
234
235
492
    return result;
236
237
492
} _catch:
238
0
    m3_Free (table);
239
0
    return result;
240
492
}
241
242
243
#if d_m3HasExceptionHandling
244
245
M3Result  Module_AddTag  (IM3Module io_module, IM3Tag * o_tag, IM3FuncType i_type, bool i_isImported)
246
774
{
247
774
_try {
248
774
    u32 index = io_module->numTags++;
249
774
    io_module->tags = m3_ReallocArray (M3Tag, io_module->tags, io_module->numTags, index);
250
774
    _throwifnull (io_module->tags);
251
774
    M3Tag * tag = & io_module->tags [index];
252
253
774
    tag->type = i_type;
254
774
    tag->imported = i_isImported;
255
256
774
    if (o_tag)
257
420
        * o_tag = tag;
258
259
774
} _catch:
260
774
    return result;
261
774
}
262
263
#endif // d_m3HasExceptionHandling
264
265
266
M3Result  Module_AddGlobal  (IM3Module io_module, IM3Global * o_global, m3type_t i_type, bool i_mutable, bool i_isImported)
267
347
{
268
347
_try {
269
347
    u32 index = io_module->numGlobals++;
270
347
    io_module->globals = m3_ReallocArray (M3Global, io_module->globals, io_module->numGlobals, index);
271
347
    _throwifnull (io_module->globals);
272
347
    M3Global * global = & io_module->globals [index];
273
274
347
    global->type = i_type;
275
347
    global->imported = i_isImported;
276
347
    global->isMutable = i_mutable;
277
278
347
    if (o_global)
279
347
        * o_global = global;
280
281
347
} _catch:
282
347
    return result;
283
347
}
284
285
M3Result  Module_PreallocFunctions  (IM3Module io_module, u32 i_totalFunctions)
286
10.8k
{
287
10.8k
_try {
288
10.8k
    if (i_totalFunctions > io_module->allFunctions) {
289
3.76k
        io_module->functions = m3_ReallocArray (M3Function, io_module->functions, i_totalFunctions, io_module->allFunctions);
290
3.76k
        io_module->allFunctions = i_totalFunctions;
291
3.76k
        _throwifnull (io_module->functions);
292
3.76k
    }
293
10.8k
} _catch:
294
10.8k
    return result;
295
10.8k
}
296
297
M3Result  Module_AddFunction  (IM3Module io_module, u32 i_typeIndex, IM3ImportInfo i_importInfo)
298
7.07k
{
299
7.07k
_try {
300
301
7.07k
    u32 index = io_module->numFunctions++;
302
7.07k
_   (Module_PreallocFunctions(io_module, io_module->numFunctions));
303
304
7.07k
    _throwif ("type sig index out of bounds", i_typeIndex >= io_module->numFuncTypes);
305
306
7.06k
    IM3FuncType ft = io_module->funcTypes [i_typeIndex];
307
308
7.06k
    IM3Function func = Module_GetFunction (io_module, index);
309
7.06k
    func->funcType = ft;
310
7.06k
    func->module = io_module;       // an import has no body, but still belongs to this module
311
312
#   ifdef DEBUG
313
    func->index = index;
314
#   endif
315
316
7.06k
    if (i_importInfo and func->numNames == 0)
317
3.43k
    {
318
3.43k
        func->import = * i_importInfo;
319
3.43k
        func->names[0] = i_importInfo->fieldUtf8;
320
3.43k
        func->numNames = 1;
321
3.43k
    }
322
323
7.06k
    m3log (module, "   added function: %3d; sig: %d", index, i_typeIndex);
324
325
7.07k
} _catch:
326
7.07k
    return result;
327
7.06k
}
328
329
#ifdef DEBUG
330
void  Module_GenerateNames  (IM3Module i_module)
331
{
332
    for (u32 i = 0; i < i_module->numFunctions; ++i)
333
    {
334
        IM3Function func = & i_module->functions [i];
335
336
        if (func->numNames == 0)
337
        {
338
            char* buff = m3_AllocArray(char, 16);
339
            snprintf(buff, 16, "$func%d", i);
340
            func->names[0] = buff;
341
            func->numNames = 1;
342
        }
343
    }
344
    for (u32 i = 0; i < i_module->numGlobals; ++i)
345
    {
346
        IM3Global global = & i_module->globals [i];
347
348
        if (global->name == NULL)
349
        {
350
            char* buff = m3_AllocArray(char, 16);
351
            snprintf(buff, 16, "$global%d", i);
352
            global->name = buff;
353
        }
354
    }
355
}
356
#endif
357
358
IM3Function  Module_GetFunction  (IM3Module i_module, u32 i_functionIndex)
359
11.6k
{
360
11.6k
    IM3Function func = NULL;
361
362
11.6k
    if (i_functionIndex < i_module->numFunctions)
363
11.6k
    {
364
11.6k
        func = & i_module->functions [i_functionIndex];
365
        //func->module = i_module;
366
11.6k
    }
367
368
11.6k
    return func;
369
11.6k
}
370
371
372
const char*  m3_GetModuleName  (IM3Module i_module)
373
0
{
374
0
    if (!i_module || !i_module->name)
375
0
        return ".unnamed";
376
377
0
    return i_module->name;
378
0
}
379
380
void  m3_SetModuleName  (IM3Module i_module, const char* name)
381
0
{
382
0
    if (i_module) i_module->name = name;
383
0
}
384
385
IM3Runtime  m3_GetModuleRuntime  (IM3Module i_module)
386
0
{
387
0
    return i_module ? i_module->runtime : NULL;
388
0
}
389