From: Brendan Hansen Date: Wed, 10 Jan 2024 03:43:26 +0000 (-0600) Subject: added: basics of tree shaking functions X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=c5f2a25616dad09fd5c8e364a9378ca44c7031d4;p=onyx.git added: basics of tree shaking functions --- diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index be565f6a..08290445 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -313,6 +313,8 @@ typedef enum AstFlags { Ast_Flag_Function_Is_Lambda_Inside_PolyProc = BH_BIT(27), Ast_Flag_Constraint_Is_Expression = BH_BIT(28), + + Ast_Flag_Has_Been_Scheduled_For_Emit = BH_BIT(29) } AstFlags; typedef enum UnaryOp { @@ -1721,6 +1723,7 @@ Entity* entity_heap_top(EntityHeap* entities); void entity_heap_change_top(EntityHeap* entities, Entity* new_top); void entity_heap_remove_top(EntityHeap* entities); void entity_change_type(EntityHeap* entities, Entity *ent, EntityType new_type); +void entity_change_state(EntityHeap* entities, Entity *ent, EntityState new_state); void entity_heap_add_job(EntityHeap *entities, enum TypeMatch (*func)(void *), void *job_data); // If target_arr is null, the entities will be placed directly in the heap. diff --git a/compiler/include/wasm_emit.h b/compiler/include/wasm_emit.h index 81c4ada8..b16f7bee 100644 --- a/compiler/include/wasm_emit.h +++ b/compiler/include/wasm_emit.h @@ -589,6 +589,12 @@ typedef enum DatumPatchInfoKind { Datum_Patch_Relative, } DatumPatchInfoKind; +typedef enum CodePatchInfoKind { + Code_Patch_Callee, + Code_Patch_Element, + Code_Patch_Export, +} CodePatchInfoKind; + // // This represents a pointer that should be filled in // later when the corresponding data element is placed. @@ -632,6 +638,15 @@ typedef struct DatumPatchInfo { AstNode *node_to_use_if_data_id_is_null; } DatumPatchInfo; +typedef struct CodePatchInfo { + CodePatchInfoKind kind; + u32 func_idx; + u32 instr; + + AstNode *node_related_to_patch; + OnyxToken *token_related_to_patch; +} CodePatchInfo; + // Context used when building a constexpr buffer typedef struct ConstExprContext { struct OnyxWasmModule *module; @@ -703,6 +718,7 @@ typedef struct OnyxWasmModule { bh_arr(PatchInfo) stack_leave_patches; bh_arr(DatumPatchInfo) data_patches; + bh_arr(CodePatchInfo) code_patches; bh_arr(ForRemoveInfo) for_remove_info; @@ -740,10 +756,9 @@ typedef struct OnyxWasmModule { u32 export_count; u32 next_type_idx; u32 next_func_idx; + u32 next_foreign_func_idx; u32 next_global_idx; u32 next_tls_offset; - u32 next_elem_idx; - u32 foreign_function_count; i32 *stack_top_ptr; i32 *tls_size_ptr; diff --git a/compiler/src/checker.c b/compiler/src/checker.c index 5fac8aa5..d16ad373 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -2902,7 +2902,13 @@ CheckStatus check_function(AstFunction* func) { } func->flags |= Ast_Flag_Has_Been_Checked; - return Check_Success; + + if (bh_arr_length(func->tags) > 0 || (func->flags & Ast_Flag_Proc_Is_Null) != 0) { + func->flags |= Ast_Flag_Has_Been_Scheduled_For_Emit; + return Check_Success; + } + + return Check_Complete; } CheckStatus check_overloaded_function(AstOverloadedFunction* ofunc) { @@ -3330,7 +3336,12 @@ CheckStatus check_function_header(AstFunction* func) { CHECK(expression, &func->foreign.import_name); } - return Check_Success; + if (bh_arr_length(func->tags) > 0 || (func->flags & Ast_Flag_Proc_Is_Null) != 0) { + func->flags |= Ast_Flag_Has_Been_Scheduled_For_Emit; + return Check_Success; + } + + return Check_Complete; } CheckStatus check_memres_type(AstMemRes* memres) { diff --git a/compiler/src/entities.c b/compiler/src/entities.c index dc5e3ef8..79396279 100644 --- a/compiler/src/entities.c +++ b/compiler/src/entities.c @@ -166,6 +166,12 @@ void entity_change_type(EntityHeap* entities, Entity *ent, EntityType new_type) ent->type = new_type; } +void entity_change_state(EntityHeap* entities, Entity *ent, EntityState new_state) { + entities->state_count[ent->state]--; + entities->state_count[new_state]++; + ent->state = new_state; +} + void entity_heap_add_job(EntityHeap *entities, TypeMatch (*func)(void *), void *job_data) { EntityJobData *job = bh_alloc(global_heap_allocator, sizeof(*job)); job->func = func; diff --git a/compiler/src/wasm_emit.c b/compiler/src/wasm_emit.c index c1a1fd0b..9624bfd1 100644 --- a/compiler/src/wasm_emit.c +++ b/compiler/src/wasm_emit.c @@ -203,23 +203,6 @@ static u64 local_lookup_idx(LocalAllocator* la, u64 value) { } -static inline b32 should_emit_function(AstFunction* fd) { - // NOTE: Don't output intrinsic functions - if (fd->is_intrinsic) return 0; - - // NOTE: Don't output functions that are not used, only if - // they are also not exported. - if ((fd->flags & Ast_Flag_Function_Used) == 0) { - if (fd->is_exported || (bh_arr_length(fd->tags) > 0 && !fd->is_foreign)) { - return 1; - } else { - return 0; - } - } - - return 1; -} - // // Debug Info Generation @@ -562,6 +545,36 @@ static void emit_raw_string(OnyxWasmModule* mod, char *data, i32 len, u64 *out_d static void emit_constexpr(ConstExprContext *ctx, AstTyped *node, u32 offset); static b32 emit_constexpr_(ConstExprContext *ctx, AstTyped *node, u32 offset); +static void ensure_node_has_been_submitted_for_emission(AstNode *node) { + assert(node->entity); + + if (node->flags & Ast_Flag_Has_Been_Scheduled_For_Emit) return; + node->flags |= Ast_Flag_Has_Been_Scheduled_For_Emit; + + // Node should be finalized at this point. + // Actually no, it could have been entered by something else. + // assert(node->entity->state == Entity_State_Finalized); + + if (node->kind == Ast_Kind_Function) { + // Need to add header and body for functions + AstFunction *func = (AstFunction *) node; + if (func->is_foreign) goto submit_normal_node; + + func->entity_header->macro_attempts = 0; + func->entity_body->macro_attempts = 0; + + entity_change_state(&context.entities, func->entity_header, Entity_State_Code_Gen); + entity_change_state(&context.entities, func->entity_body, Entity_State_Code_Gen); + entity_heap_insert_existing(&context.entities, func->entity_header); + entity_heap_insert_existing(&context.entities, func->entity_body); + return; + } + + submit_normal_node: + entity_change_state(&context.entities, node->entity, Entity_State_Code_Gen); + entity_heap_insert_existing(&context.entities, node->entity); +} + #include "wasm_intrinsics.h" #include "wasm_type_table.h" @@ -2285,8 +2298,16 @@ EMIT_FUNC(call, AstCall* call) { } if (call->callee->kind == Ast_Kind_Function) { - i32 func_idx = (i32) bh_imap_get(&mod->index_map, (u64) call->callee); - WIL(NULL, WI_CALL, func_idx); + CodePatchInfo code_patch; + code_patch.kind = Code_Patch_Callee; + code_patch.func_idx = mod->current_func_idx; + code_patch.instr = bh_arr_length(code); + code_patch.node_related_to_patch = (AstNode *) call->callee; + bh_arr_push(mod->code_patches, code_patch); + + WIL(NULL, WI_CALL, 0); // This will be patched later. + + ensure_node_has_been_submitted_for_emission((AstNode *) call->callee); } else { emit_expression(mod, &code, call->callee); @@ -3575,6 +3596,8 @@ EMIT_FUNC(expression, AstTyped* expr) { AstFunction *func = (AstFunction *) expr; i32 elemidx = get_element_idx(mod, func); + // This is not patched because it refers to the element index, which + // requires the function be submitted and part of the binary already. WID(NULL, WI_I32_CONST, elemidx); if (!func->captures) { WIL(NULL, WI_PTR_CONST, 0); @@ -3584,8 +3607,16 @@ EMIT_FUNC(expression, AstTyped* expr) { // Allocate the block WIL(NULL, WI_I32_CONST, func->captures->total_size_in_bytes); - i32 func_idx = (i32) bh_imap_get(&mod->index_map, (u64) builtin_closure_block_allocate); - WIL(NULL, WI_CALL, func_idx); + + CodePatchInfo code_patch; + code_patch.kind = Code_Patch_Callee; + code_patch.func_idx = mod->current_func_idx; + code_patch.instr = bh_arr_length(code); + code_patch.node_related_to_patch = (AstNode *) builtin_closure_block_allocate; + bh_arr_push(mod->code_patches, code_patch); + WIL(NULL, WI_CALL, 0); + + ensure_node_has_been_submitted_for_emission((AstNode *) builtin_closure_block_allocate); u64 capture_block_ptr = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR); WIL(NULL, WI_LOCAL_TEE, capture_block_ptr); @@ -4325,16 +4356,24 @@ static i32 generate_type_idx(OnyxWasmModule* mod, Type* ft) { } static i32 get_element_idx(OnyxWasmModule* mod, AstFunction* func) { + ensure_node_has_been_submitted_for_emission((AstNode *) func); + if (bh_imap_has(&mod->elem_map, (u64) func)) { return bh_imap_get(&mod->elem_map, (u64) func); + } else { - i32 idx = mod->next_elem_idx; - bh_imap_put(&mod->elem_map, (u64) func, idx); + i32 idx = bh_arr_length(mod->elems); - i32 func_idx = bh_imap_get(&mod->index_map, (u64) func); - bh_arr_push(mod->elems, func_idx); + // Cache which function goes to which element slot. + bh_imap_put(&mod->elem_map, (u64) func, idx); - mod->next_elem_idx++; + // Submit a patch to fill this out later in linking. + CodePatchInfo code_patch; + code_patch.kind = Code_Patch_Element; + code_patch.instr = bh_arr_length(mod->elems); + code_patch.node_related_to_patch = (AstNode *) func; + bh_arr_push(mod->code_patches, code_patch); + bh_arr_push(mod->elems, 0); return idx; } @@ -4389,8 +4428,27 @@ EMIT_FUNC(stack_trace_blob, AstFunction *fd) { *pcode = code; } +static i32 assign_function_index(OnyxWasmModule *mod, AstFunction *fd) { + if (!bh_imap_has(&mod->index_map, (u64) fd)) { + i32 func_idx = (i32) mod->next_func_idx++; + bh_imap_put(&mod->index_map, (u64) fd, (u64) func_idx); + + if (context.options->print_function_mappings) { + bh_printf("%d -> %s:%d:%d\n", + func_idx, + fd->token->pos.filename, + fd->token->pos.line, + fd->token->pos.column); + } + + return func_idx; + } + + return (i32) bh_imap_get(&mod->index_map, (u64) fd); +} + static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { - if (!should_emit_function(fd)) return; + i32 func_idx = assign_function_index(mod, fd); if (fd == builtin_initialize_data_segments && !mod->doing_linking) { // This is a large hack, but is necessary. @@ -4410,7 +4468,6 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { bh_arr_new(mod->allocator, wasm_func.code, 16); - i32 func_idx = (i32) bh_imap_get(&mod->index_map, (u64) fd); mod->current_func_idx = func_idx; debug_begin_function(mod, func_idx, fd->token, get_function_name(fd)); @@ -4421,7 +4478,7 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { debug_emit_instruction(mod, NULL); bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_BLOCK_END, 0x00 })); - bh_arr_set_at(mod->funcs, func_idx - mod->foreign_function_count, wasm_func); + bh_arr_set_at(mod->funcs, func_idx, wasm_func); mod->current_func_idx = -1; debug_end_function(mod); @@ -4434,7 +4491,7 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { debug_emit_instruction(mod, NULL); bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_BLOCK_END, 0x00 })); - bh_arr_set_at(mod->funcs, func_idx - mod->foreign_function_count, wasm_func); + bh_arr_set_at(mod->funcs, func_idx, wasm_func); mod->current_func_idx = -1; debug_end_function(mod); @@ -4532,7 +4589,7 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { bh_imap_clear(&mod->local_map); - bh_arr_set_at(mod->funcs, func_idx - mod->foreign_function_count, wasm_func); + bh_arr_set_at(mod->funcs, func_idx, wasm_func); mod->current_func_idx = -1; debug_end_function(mod); @@ -4572,8 +4629,6 @@ static void encode_type_as_dyncall_symbol(char *out, Type *t) { } static void emit_foreign_function(OnyxWasmModule* mod, AstFunction* fd) { - if (!should_emit_function(fd)) return; - i32 type_idx = generate_type_idx(mod, fd->type); char *module, *name; @@ -4624,10 +4679,16 @@ static void emit_export_directive(OnyxWasmModule* mod, AstDirectiveExport* expor AstTyped *the_export = (AstTyped *) strip_aliases((AstNode *) export->export); assert(the_export); - i64 idx = bh_imap_get(&mod->index_map, (u64) the_export); + ensure_node_has_been_submitted_for_emission((AstNode *) the_export); + + CodePatchInfo code_patch; + code_patch.kind = Code_Patch_Export; + code_patch.node_related_to_patch = (AstNode *) the_export; + code_patch.token_related_to_patch = export->export_name; + bh_arr_push(mod->code_patches, code_patch); WasmExport wasm_export; - wasm_export.idx = (i32) idx; + wasm_export.idx = 0; // This will be patched later switch (the_export->kind) { case Ast_Kind_Function: wasm_export.kind = WASM_FOREIGN_FUNCTION; @@ -5072,6 +5133,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { .funcs = NULL, .next_func_idx = 0, + .next_foreign_func_idx = 0, .exports = NULL, .export_count = 0, @@ -5083,12 +5145,12 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { .data = NULL, .data_patches = NULL, + .code_patches = NULL, .next_tls_offset = 0, .tls_size_ptr = NULL, .elems = NULL, - .next_elem_idx = 0, .needs_memory_section = 0, .memory_min_size = 0, @@ -5107,8 +5169,6 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { .closure_base_idx = 0, - .foreign_function_count = 0, - .null_proc_func_idx = -1, .libraries = NULL, @@ -5155,6 +5215,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { bh_arr_new(global_heap_allocator, module.procedures_with_tags, 4); bh_arr_new(global_heap_allocator, module.globals_with_tags, 4); bh_arr_new(global_heap_allocator, module.data_patches, 4); + bh_arr_new(global_heap_allocator, module.code_patches, 4); #ifdef ENABLE_DEBUG_INFO module.debug_context = bh_alloc_item(context.ast_alloc, DebugContext); @@ -5183,25 +5244,15 @@ void emit_entity(Entity* ent) { switch (ent->type) { case Entity_Type_Foreign_Function_Header: - if (!should_emit_function(ent->function)) break; - - module->foreign_function_count++; emit_foreign_function(module, ent->function); - // fallthrough + bh_imap_put(&module->index_map, (u64) ent->function, module->next_foreign_func_idx++); - case Entity_Type_Function_Header: - if (!should_emit_function(ent->function)) break; - - if (context.options->print_function_mappings) { - bh_printf("%d -> %s:%d:%d\n", - module->next_func_idx, - ent->expr->token->pos.filename, - ent->expr->token->pos.line, - ent->expr->token->pos.column); + if (ent->function->tags != NULL) { + bh_arr_push(module->procedures_with_tags, ent->function); } + break; - bh_imap_put(&module->index_map, (u64) ent->function, module->next_func_idx++); - + case Entity_Type_Function_Header: if (ent->function->flags & Ast_Flag_Proc_Is_Null) { if (module->null_proc_func_idx == -1) module->null_proc_func_idx = get_element_idx(module, ent->function); } @@ -5270,6 +5321,52 @@ void onyx_wasm_module_link(OnyxWasmModule *module, OnyxWasmLinkOptions *options) module->doing_linking = 1; + bh_arr_each(CodePatchInfo, patch, module->code_patches) { + AstFunction *func = (AstFunction *) patch->node_related_to_patch; + + switch (patch->kind) { + case Code_Patch_Callee: { + assert(bh_imap_has(&module->index_map, (u64) patch->node_related_to_patch)); + + // This patches direct calls to functions that could not be deduced earlier + // because the function had not been emitted yet. + u64 func_idx = (u64) bh_imap_get(&module->index_map, (u64) patch->node_related_to_patch); + if (!func->is_foreign) { + func_idx += module->next_foreign_func_idx; + } + + module->funcs[patch->func_idx].code[patch->instr].data.l = func_idx; + break; + } + + case Code_Patch_Element: { + assert(bh_imap_has(&module->index_map, (u64) patch->node_related_to_patch)); + u64 func_idx = (u64) bh_imap_get(&module->index_map, (u64) patch->node_related_to_patch); + if (!func->is_foreign) { + func_idx += module->next_foreign_func_idx; + } + + module->elems[patch->instr] = func_idx; + break; + } + + case Code_Patch_Export: { + assert(bh_imap_has(&module->index_map, (u64) patch->node_related_to_patch)); + u64 func_idx = (u64) bh_imap_get(&module->index_map, (u64) patch->node_related_to_patch); + if (!func->is_foreign) { + func_idx += module->next_foreign_func_idx; + } + + token_toggle_end(patch->token_related_to_patch); + i32 export_idx = shgeti(module->exports, patch->token_related_to_patch->text); + token_toggle_end(patch->token_related_to_patch); + + module->exports[export_idx].value.idx = (i32) func_idx; + break; + } + } + } + module->memory_min_size = options->memory_min_size; module->memory_max_size = options->memory_max_size; @@ -5343,7 +5440,7 @@ void onyx_wasm_module_link(OnyxWasmModule *module, OnyxWasmLinkOptions *options) switch (patch->kind) { case Datum_Patch_Instruction: { - WasmFunc *func = &module->funcs[patch->index - module->foreign_function_count]; + WasmFunc *func = &module->funcs[patch->index]; assert(func->code[patch->location].type == WI_PTR_CONST); func->code[patch->location].data.l = (u64) datum->offset_ + patch->offset; diff --git a/compiler/src/wasm_intrinsics.h b/compiler/src/wasm_intrinsics.h index 8e107f16..55e221f3 100644 --- a/compiler/src/wasm_intrinsics.h +++ b/compiler/src/wasm_intrinsics.h @@ -525,9 +525,17 @@ EMIT_FUNC_NO_ARGS(run_init_procedures) { bh_arr(WasmInstruction) code = *pcode; bh_arr_each(AstFunction *, func, init_procedures) { - i32 func_idx = (i32) bh_imap_get(&mod->index_map, (u64) *func); + CodePatchInfo code_patch; + code_patch.kind = Code_Patch_Callee; + code_patch.func_idx = mod->current_func_idx; + code_patch.instr = bh_arr_length(code); + code_patch.node_related_to_patch = (AstNode *) *func; + bh_arr_push(mod->code_patches, code_patch); + + ensure_node_has_been_submitted_for_emission((AstNode *) *func); + debug_emit_instruction(mod, NULL); - bh_arr_push(code, ((WasmInstruction){ WI_CALL, func_idx })); + bh_arr_push(code, ((WasmInstruction){ WI_CALL, 0 })); } *pcode = code; diff --git a/compiler/src/wasm_output.h b/compiler/src/wasm_output.h index c44ffe09..8320ad78 100644 --- a/compiler/src/wasm_output.h +++ b/compiler/src/wasm_output.h @@ -140,6 +140,8 @@ static i32 output_funcsection(OnyxWasmModule* module, bh_buffer* buff) { bh_buffer_append(&vec_buff, leb, leb_len); bh_arr_each(WasmFunc, func, module->funcs) { + assert(func->code); + leb = uint_to_uleb128((u64) (func->type_idx), &leb_len); bh_buffer_append(&vec_buff, leb, leb_len); } @@ -601,7 +603,10 @@ static i32 output_codesection(OnyxWasmModule* module, bh_buffer* buff) { u8* leb = uint_to_uleb128((u64) bh_arr_length(module->funcs), &leb_len); bh_buffer_append(&vec_buff, leb, leb_len); - bh_arr_each(WasmFunc, func, module->funcs) output_code(func, &vec_buff); + bh_arr_each(WasmFunc, func, module->funcs) { + assert(func->code); + output_code(func, &vec_buff); + } leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len); bh_buffer_append(buff, leb, leb_len); @@ -720,49 +725,6 @@ static i32 output_onyx_libraries_section(OnyxWasmModule* module, bh_buffer* buff return buff->length - prev_len; } -/* -static i32 output_onyx_func_offset_section(OnyxWasmModule* module, bh_buffer* buff) { - i32 prev_len = buff->length; - - bh_buffer_write_byte(buff, WASM_SECTION_ID_CUSTOM); - - bh_buffer section_buff; - bh_buffer_init(§ion_buff, buff->allocator, 128); - - output_custom_section_name("_onyx_func_offsets", §ion_buff); - - i32 func_count = bh_arr_length(module->funcs) + module->foreign_function_count; - - bh_buffer name_buff; - bh_buffer_init(&name_buff, buff->allocator, 1024); - u32 str_cursor = func_count * 4; - fori (i, 0, func_count) { - bh_buffer_write_u32(§ion_buff, str_cursor); - - if (i < module->foreign_function_count) { - bh_buffer_append(&name_buff, "", 20); - str_cursor += 20; - } else { - WasmFunc *func = &module->funcs[i - module->foreign_function_count]; - assert(func->location); - char *str = bh_bprintf("%s:%d,%d\0", func->location->pos.filename, func->location->pos.line, func->location->pos.column); - i32 len = strlen(str); - bh_buffer_append(&name_buff, str, len + 1); - str_cursor += len + 1; - } - } - - bh_buffer_concat(§ion_buff, name_buff); - - output_unsigned_integer(section_buff.length, buff); - - bh_buffer_concat(buff, section_buff); - bh_buffer_free(§ion_buff); - - return buff->length - prev_len; -} -*/ - #ifdef ENABLE_DEBUG_INFO static i32 output_ovm_debug_sections(OnyxWasmModule* module, bh_buffer* buff) { if (!module->debug_context || !context.options->debug_info_enabled) return 0; @@ -839,7 +801,7 @@ static i32 output_ovm_debug_sections(OnyxWasmModule* module, bh_buffer* buff) { // that this has been implemented right now. assert(ctx->sym_info[patch->sym_id].location_type == DSL_REGISTER); - LocalAllocator *locals = &module->funcs[patch->func_idx - module->foreign_function_count].locals; + LocalAllocator *locals = &module->funcs[patch->func_idx].locals; ctx->sym_info[patch->sym_id].location_num = local_lookup_idx(locals, patch->local_idx); } diff --git a/compiler/src/wasm_type_table.h b/compiler/src/wasm_type_table.h index 630c6132..e63de964 100644 --- a/compiler/src/wasm_type_table.h +++ b/compiler/src/wasm_type_table.h @@ -1083,10 +1083,6 @@ static u64 build_tagged_procedures(OnyxWasmModule *module) { u32 index = 0; bh_arr_each(AstFunction *, pfunc, module->procedures_with_tags) { AstFunction *func = *pfunc; - if (!should_emit_function(func)) { - proc_count--; - continue; - } u32 tag_count = bh_arr_length(func->tags); u32 *tag_data_offsets = bh_alloc_array(global_scratch_allocator, u32, tag_count); @@ -1127,7 +1123,7 @@ static u64 build_tagged_procedures(OnyxWasmModule *module) { bh_buffer_write_u32(&tag_proc_buffer, func->type->id); WRITE_SLICE(tag_array_base, tag_count); bh_buffer_write_u32(&tag_proc_buffer, func->entity->package->id); - } + } if (context.options->verbose_output == 1) { bh_printf("Tagged procedure size: %d bytes.\n", tag_proc_buffer.length);