Skip to content

Commit 371941d

Browse files
committed
refactor: Allocate module dynamically
1 parent 8c4315f commit 371941d

19 files changed

+526
-512
lines changed

lib/fizzy/execute.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -468,13 +468,13 @@ ExecutionResult execute(
468468
if (depth > CallStackLimit)
469469
return Trap;
470470

471-
assert(args.size() == instance.module.get_function_type(func_idx).inputs.size());
471+
assert(args.size() == instance.module->get_function_type(func_idx).inputs.size());
472472

473-
assert(instance.module.imported_function_types.size() == instance.imported_functions.size());
473+
assert(instance.module->imported_function_types.size() == instance.imported_functions.size());
474474
if (func_idx < instance.imported_functions.size())
475475
return instance.imported_functions[func_idx].function(instance, args, depth);
476476

477-
const auto& code = instance.module.get_code(func_idx);
477+
const auto& code = instance.module->get_code(func_idx);
478478
auto* const memory = instance.memory.get();
479479

480480
OperandStack stack(args, code.local_count, static_cast<size_t>(code.max_stack_height));
@@ -560,7 +560,7 @@ ExecutionResult execute(
560560
case Instr::call:
561561
{
562562
const auto called_func_idx = read<uint32_t>(immediates);
563-
const auto& called_func_type = instance.module.get_function_type(called_func_idx);
563+
const auto& called_func_type = instance.module->get_function_type(called_func_idx);
564564

565565
if (!invoke_function(called_func_type, called_func_idx, instance, stack, depth))
566566
goto trap;
@@ -571,7 +571,7 @@ ExecutionResult execute(
571571
assert(instance.table != nullptr);
572572

573573
const auto expected_type_idx = read<uint32_t>(immediates);
574-
assert(expected_type_idx < instance.module.typesec.size());
574+
assert(expected_type_idx < instance.module->typesec.size());
575575

576576
const auto elem_idx = stack.pop().as<uint32_t>();
577577
if (elem_idx >= instance.table->size())
@@ -583,7 +583,7 @@ ExecutionResult execute(
583583

584584
// check actual type against expected type
585585
const auto& actual_type = called_func->type;
586-
const auto& expected_type = instance.module.typesec[expected_type_idx];
586+
const auto& expected_type = instance.module->typesec[expected_type_idx];
587587
if (expected_type != actual_type)
588588
goto trap;
589589

@@ -637,7 +637,7 @@ ExecutionResult execute(
637637
else
638638
{
639639
const auto module_global_idx = idx - instance.imported_globals.size();
640-
assert(module_global_idx < instance.module.globalsec.size());
640+
assert(module_global_idx < instance.module->globalsec.size());
641641
stack.push(instance.globals[module_global_idx]);
642642
}
643643
break;
@@ -653,8 +653,8 @@ ExecutionResult execute(
653653
else
654654
{
655655
const auto module_global_idx = idx - instance.imported_globals.size();
656-
assert(module_global_idx < instance.module.globalsec.size());
657-
assert(instance.module.globalsec[module_global_idx].type.is_mutable);
656+
assert(module_global_idx < instance.module->globalsec.size());
657+
assert(instance.module->globalsec[module_global_idx].type.is_mutable);
658658
instance.globals[module_global_idx] = stack.pop();
659659
}
660660
break;
@@ -1517,7 +1517,7 @@ ExecutionResult execute(
15171517

15181518
end:
15191519
assert(pc == &code.instructions[code.instructions.size()]); // End of code must be reached.
1520-
assert(stack.size() == instance.module.get_function_type(func_idx).outputs.size());
1520+
assert(stack.size() == instance.module->get_function_type(func_idx).outputs.size());
15211521

15221522
return stack.size() != 0 ? ExecutionResult{stack.pop()} : Void;
15231523

lib/fizzy/instantiate.cpp

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -237,22 +237,22 @@ std::optional<uint32_t> find_export(const Module& module, ExternalKind kind, std
237237

238238
} // namespace
239239

240-
std::unique_ptr<Instance> instantiate(Module module,
240+
std::unique_ptr<Instance> instantiate(std::unique_ptr<Module>&& module,
241241
std::vector<ExternalFunction> imported_functions, std::vector<ExternalTable> imported_tables,
242242
std::vector<ExternalMemory> imported_memories, std::vector<ExternalGlobal> imported_globals,
243243
uint32_t memory_pages_limit /*= DefaultMemoryPagesLimit*/)
244244
{
245-
assert(module.funcsec.size() == module.codesec.size());
245+
assert(module->funcsec.size() == module->codesec.size());
246246

247-
match_imported_functions(module.imported_function_types, imported_functions);
248-
match_imported_tables(module.imported_table_types, imported_tables);
249-
match_imported_memories(module.imported_memory_types, imported_memories);
250-
match_imported_globals(module.imported_global_types, imported_globals);
247+
match_imported_functions(module->imported_function_types, imported_functions);
248+
match_imported_tables(module->imported_table_types, imported_tables);
249+
match_imported_memories(module->imported_memory_types, imported_memories);
250+
match_imported_globals(module->imported_global_types, imported_globals);
251251

252252
// Init globals
253253
std::vector<Value> globals;
254-
globals.reserve(module.globalsec.size());
255-
for (auto const& global : module.globalsec)
254+
globals.reserve(module->globalsec.size());
255+
for (auto const& global : module->globalsec)
256256
{
257257
// Constraint to use global.get only with imported globals is checked at validation.
258258
assert(global.expression.kind != ConstantExpression::Kind::GlobalGet ||
@@ -262,10 +262,10 @@ std::unique_ptr<Instance> instantiate(Module module,
262262
globals.emplace_back(value);
263263
}
264264

265-
auto [table, table_limits] = allocate_table(module.tablesec, imported_tables);
265+
auto [table, table_limits] = allocate_table(module->tablesec, imported_tables);
266266

267267
auto [memory, memory_limits] =
268-
allocate_memory(module.memorysec, imported_memories, memory_pages_limit);
268+
allocate_memory(module->memorysec, imported_memories, memory_pages_limit);
269269
// In case upper limit for local/imported memory is defined,
270270
// we adjust the hard memory limit, to ensure memory.grow will fail when exceeding it.
271271
// Note: allocate_memory ensures memory's max limit is always below memory_pages_limit.
@@ -278,8 +278,8 @@ std::unique_ptr<Instance> instantiate(Module module,
278278
// Before starting to fill memory and table,
279279
// check that data and element segments are within bounds.
280280
std::vector<uint64_t> datasec_offsets;
281-
datasec_offsets.reserve(module.datasec.size());
282-
for (const auto& data : module.datasec)
281+
datasec_offsets.reserve(module->datasec.size());
282+
for (const auto& data : module->datasec)
283283
{
284284
// Offset is validated to be i32, but it's used in 64-bit calculation below.
285285
const uint64_t offset =
@@ -291,10 +291,10 @@ std::unique_ptr<Instance> instantiate(Module module,
291291
datasec_offsets.emplace_back(offset);
292292
}
293293

294-
assert(module.elementsec.empty() || table != nullptr);
294+
assert(module->elementsec.empty() || table != nullptr);
295295
std::vector<ptrdiff_t> elementsec_offsets;
296-
elementsec_offsets.reserve(module.elementsec.size());
297-
for (const auto& element : module.elementsec)
296+
elementsec_offsets.reserve(module->elementsec.size());
297+
for (const auto& element : module->elementsec)
298298
{
299299
// Offset is validated to be i32, but it's used in 64-bit calculation below.
300300
const uint64_t offset =
@@ -307,10 +307,10 @@ std::unique_ptr<Instance> instantiate(Module module,
307307
}
308308

309309
// Fill out memory based on data segments
310-
for (size_t i = 0; i < module.datasec.size(); ++i)
310+
for (size_t i = 0; i < module->datasec.size(); ++i)
311311
{
312312
// NOTE: these instructions can overlap
313-
std::copy(module.datasec[i].init.begin(), module.datasec[i].init.end(),
313+
std::copy(module->datasec[i].init.begin(), module->datasec[i].init.end(),
314314
memory->data() + datasec_offsets[i]);
315315
}
316316

@@ -321,41 +321,41 @@ std::unique_ptr<Instance> instantiate(Module module,
321321
std::move(imported_functions), std::move(imported_globals));
322322

323323
// Fill the table based on elements segment
324-
for (size_t i = 0; i < instance->module.elementsec.size(); ++i)
324+
for (size_t i = 0; i < instance->module->elementsec.size(); ++i)
325325
{
326326
// Overwrite table[offset..] with element.init
327327
auto it_table = instance->table->begin() + elementsec_offsets[i];
328-
for (const auto idx : instance->module.elementsec[i].init)
328+
for (const auto idx : instance->module->elementsec[i].init)
329329
{
330330
auto func = [idx, &instance_ref = *instance](fizzy::Instance&, span<const Value> args,
331331
int depth) { return execute(instance_ref, idx, args, depth); };
332332

333333
*it_table++ =
334-
ExternalFunction{std::move(func), instance->module.get_function_type(idx)};
334+
ExternalFunction{std::move(func), instance->module->get_function_type(idx)};
335335
}
336336
}
337337

338338
// Run start function if present
339-
if (instance->module.startfunc)
339+
if (instance->module->startfunc)
340340
{
341-
const auto funcidx = *instance->module.startfunc;
342-
assert(funcidx < instance->imported_functions.size() + instance->module.funcsec.size());
341+
const auto funcidx = *instance->module->startfunc;
342+
assert(funcidx < instance->imported_functions.size() + instance->module->funcsec.size());
343343
if (execute(*instance, funcidx, {}).trapped)
344344
{
345345
// When element section modified imported table, and then start function trapped,
346346
// modifications to the table are not rolled back.
347347
// Instance in this case is not being returned to the user, so it needs to be kept alive
348348
// as long as functions using it are alive in the table.
349-
if (!imported_tables.empty() && !instance->module.elementsec.empty())
349+
if (!imported_tables.empty() && !instance->module->elementsec.empty())
350350
{
351351
// Instance may be used by several functions added to the table,
352352
// so we need a shared ownership here.
353353
std::shared_ptr<Instance> shared_instance = std::move(instance);
354354

355-
for (size_t i = 0; i < shared_instance->module.elementsec.size(); ++i)
355+
for (size_t i = 0; i < shared_instance->module->elementsec.size(); ++i)
356356
{
357357
auto it_table = shared_instance->table->begin() + elementsec_offsets[i];
358-
for ([[maybe_unused]] auto _ : shared_instance->module.elementsec[i].init)
358+
for ([[maybe_unused]] auto _ : shared_instance->module->elementsec[i].init)
359359
{
360360
// Wrap the function with the lambda capturing shared instance
361361
auto& table_function = (*it_table)->function;
@@ -373,6 +373,16 @@ std::unique_ptr<Instance> instantiate(Module module,
373373
return instance;
374374
}
375375

376+
std::unique_ptr<Instance> instantiate(const std::unique_ptr<Module>& module,
377+
std::vector<ExternalFunction> imported_functions, std::vector<ExternalTable> imported_tables,
378+
std::vector<ExternalMemory> imported_memories, std::vector<ExternalGlobal> imported_globals,
379+
uint32_t memory_pages_limit)
380+
{
381+
return instantiate(std::make_unique<Module>(*module), std::move(imported_functions),
382+
std::move(imported_tables), std::move(imported_memories), std::move(imported_globals),
383+
memory_pages_limit);
384+
}
385+
376386
std::vector<ExternalFunction> resolve_imported_functions(
377387
const Module& module, std::vector<ImportedFunction> imported_functions)
378388
{
@@ -427,7 +437,7 @@ std::optional<FuncIdx> find_exported_function(const Module& module, std::string_
427437

428438
std::optional<ExternalFunction> find_exported_function(Instance& instance, std::string_view name)
429439
{
430-
const auto opt_index = find_export(instance.module, ExternalKind::Function, name);
440+
const auto opt_index = find_export(*instance.module, ExternalKind::Function, name);
431441
if (!opt_index.has_value())
432442
return std::nullopt;
433443

@@ -436,12 +446,12 @@ std::optional<ExternalFunction> find_exported_function(Instance& instance, std::
436446
return execute(instance, idx, args, depth);
437447
};
438448

439-
return ExternalFunction{std::move(func), instance.module.get_function_type(idx)};
449+
return ExternalFunction{std::move(func), instance.module->get_function_type(idx)};
440450
}
441451

442452
std::optional<ExternalGlobal> find_exported_global(Instance& instance, std::string_view name)
443453
{
444-
const auto opt_index = find_export(instance.module, ExternalKind::Global, name);
454+
const auto opt_index = find_export(*instance.module, ExternalKind::Global, name);
445455
if (!opt_index.has_value())
446456
return std::nullopt;
447457

@@ -457,27 +467,23 @@ std::optional<ExternalGlobal> find_exported_global(Instance& instance, std::stri
457467
// global owned by instance
458468
const auto module_global_idx = global_idx - instance.imported_globals.size();
459469
return ExternalGlobal{&instance.globals[module_global_idx],
460-
instance.module.globalsec[module_global_idx].type};
470+
instance.module->globalsec[module_global_idx].type};
461471
}
462472
}
463473

464474
std::optional<ExternalTable> find_exported_table(Instance& instance, std::string_view name)
465475
{
466-
const auto& module = instance.module;
467-
468476
// Index returned from find_export is discarded, because there's no more than 1 table
469-
if (!find_export(module, ExternalKind::Table, name))
477+
if (!find_export(*instance.module, ExternalKind::Table, name))
470478
return std::nullopt;
471479

472480
return ExternalTable{instance.table.get(), instance.table_limits};
473481
}
474482

475483
std::optional<ExternalMemory> find_exported_memory(Instance& instance, std::string_view name)
476484
{
477-
const auto& module = instance.module;
478-
479485
// Index returned from find_export is discarded, because there's no more than 1 memory
480-
if (!find_export(module, ExternalKind::Memory, name))
486+
if (!find_export(*instance.module, ExternalKind::Memory, name))
481487
return std::nullopt;
482488

483489
return ExternalMemory{instance.memory.get(), instance.memory_limits};

lib/fizzy/instantiate.hpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ using bytes_ptr = std::unique_ptr<bytes, void (*)(bytes*)>;
5454
// The module instance.
5555
struct Instance
5656
{
57-
Module module;
57+
std::unique_ptr<Module> module;
5858
// Memory is either allocated and owned by the instance or imported as already allocated bytes
5959
// and owned externally.
6060
// For these cases unique_ptr would either have a normal deleter or noop deleter respectively
@@ -70,9 +70,9 @@ struct Instance
7070
std::vector<ExternalFunction> imported_functions;
7171
std::vector<ExternalGlobal> imported_globals;
7272

73-
Instance(Module _module, bytes_ptr _memory, Limits _memory_limits, uint32_t _memory_pages_limit,
74-
table_ptr _table, Limits _table_limits, std::vector<Value> _globals,
75-
std::vector<ExternalFunction> _imported_functions,
73+
Instance(std::unique_ptr<Module> _module, bytes_ptr _memory, Limits _memory_limits,
74+
uint32_t _memory_pages_limit, table_ptr _table, Limits _table_limits,
75+
std::vector<Value> _globals, std::vector<ExternalFunction> _imported_functions,
7676
std::vector<ExternalGlobal> _imported_globals)
7777
: module(std::move(_module)),
7878
memory(std::move(_memory)),
@@ -87,13 +87,19 @@ struct Instance
8787
};
8888

8989
// Instantiate a module.
90-
std::unique_ptr<Instance> instantiate(Module module,
90+
std::unique_ptr<Instance> instantiate(std::unique_ptr<Module>&& module,
9191
std::vector<ExternalFunction> imported_functions = {},
9292
std::vector<ExternalTable> imported_tables = {},
9393
std::vector<ExternalMemory> imported_memories = {},
9494
std::vector<ExternalGlobal> imported_globals = {},
9595
uint32_t memory_pages_limit = DefaultMemoryPagesLimit);
9696

97+
std::unique_ptr<Instance> instantiate(const std::unique_ptr<Module>& module,
98+
std::vector<ExternalFunction> imported_functions = {},
99+
std::vector<ExternalTable> imported_tables = {},
100+
std::vector<ExternalMemory> imported_memories = {},
101+
std::vector<ExternalGlobal> imported_globals = {},
102+
uint32_t memory_pages_limit = DefaultMemoryPagesLimit);
97103

98104
// Function that should be used by instantiate as imports, identified by module and function name.
99105
struct ImportedFunction

0 commit comments

Comments
 (0)