}
-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
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"
}
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);
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);
// 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);
}
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;
}
*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.
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));
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);
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);
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);
}
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;
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;
.funcs = NULL,
.next_func_idx = 0,
+ .next_foreign_func_idx = 0,
.exports = NULL,
.export_count = 0,
.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,
.closure_base_idx = 0,
- .foreign_function_count = 0,
-
.null_proc_func_idx = -1,
.libraries = NULL,
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);
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);
}
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;
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;
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);
}
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);
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, "<imported function>", 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;
// 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);
}